@fbsm/saga-core 0.0.1-beta.0 → 0.1.0-beta.2
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 +66 -56
- package/dist/index.cjs +104 -45
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +104 -45
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,20 +10,20 @@ npm install @fbsm/saga-core
|
|
|
10
10
|
|
|
11
11
|
## Overview
|
|
12
12
|
|
|
13
|
-
| Export
|
|
14
|
-
|
|
15
|
-
| `SagaPublisher` | Creates sagas and publishes events
|
|
16
|
-
| `SagaRunner`
|
|
17
|
-
| `SagaRegistry`
|
|
18
|
-
| `SagaParser`
|
|
19
|
-
| `SagaContext`
|
|
13
|
+
| Export | Description |
|
|
14
|
+
| --------------- | -------------------------------------------------------- |
|
|
15
|
+
| `SagaPublisher` | Creates sagas and publishes events |
|
|
16
|
+
| `SagaRunner` | Consumes events, dispatches to handlers with retry logic |
|
|
17
|
+
| `SagaRegistry` | Stores participant and handler mappings |
|
|
18
|
+
| `SagaParser` | Parses inbound messages (3-layer fallback) |
|
|
19
|
+
| `SagaContext` | AsyncLocalStorage-based context propagation |
|
|
20
20
|
|
|
21
21
|
## SagaContext
|
|
22
22
|
|
|
23
23
|
Uses `AsyncLocalStorage` to propagate saga metadata through async call chains.
|
|
24
24
|
|
|
25
25
|
```typescript
|
|
26
|
-
import { SagaContext } from
|
|
26
|
+
import { SagaContext } from "@fbsm/saga-core";
|
|
27
27
|
|
|
28
28
|
// Read current context (or undefined)
|
|
29
29
|
const ctx = SagaContext.current();
|
|
@@ -34,6 +34,7 @@ const ctx = SagaContext.require();
|
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
**`SagaContextData`**:
|
|
37
|
+
|
|
37
38
|
```typescript
|
|
38
39
|
interface SagaContextData {
|
|
39
40
|
sagaId: string;
|
|
@@ -47,6 +48,7 @@ interface SagaContextData {
|
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
Context is set automatically by:
|
|
51
|
+
|
|
50
52
|
1. **`SagaRunner`** — wraps every handler execution with `SagaContext.run()`
|
|
51
53
|
2. **`SagaPublisher.start(fn)` / `startChild(fn)` / `emitToParent(fn)`** — wraps callbacks with `SagaContext.run()`
|
|
52
54
|
|
|
@@ -55,20 +57,21 @@ Context is set automatically by:
|
|
|
55
57
|
Creates sagas and publishes events. See [Core Functions](../doc/core-functions.md) for detailed usage of each method.
|
|
56
58
|
|
|
57
59
|
```typescript
|
|
58
|
-
import { SagaPublisher } from
|
|
60
|
+
import { SagaPublisher } from "@fbsm/saga-core";
|
|
59
61
|
|
|
60
62
|
const publisher = new SagaPublisher(transport, otelContext, topicPrefix);
|
|
61
63
|
```
|
|
62
64
|
|
|
63
|
-
| Method
|
|
64
|
-
|
|
65
|
-
| `start(fn, opts?)`
|
|
66
|
-
| `startChild(fn, opts?)`
|
|
67
|
-
| `emit(params)`
|
|
68
|
-
| `emitToParent(params \| fn)`
|
|
69
|
-
| `forSaga(sagaId, parentCtx?, causationId?, key?)` | Get bound `Emit` function (no ALS)
|
|
65
|
+
| Method | Description |
|
|
66
|
+
| ------------------------------------------------- | ------------------------------------- |
|
|
67
|
+
| `start(fn, opts?)` | Create a root saga with ALS context |
|
|
68
|
+
| `startChild(fn, opts?)` | Create a child saga linked to current |
|
|
69
|
+
| `emit(params)` | Publish event in current context |
|
|
70
|
+
| `emitToParent(params \| fn)` | Emit to parent saga |
|
|
71
|
+
| `forSaga(sagaId, parentCtx?, causationId?, key?)` | Get bound `Emit` function (no ALS) |
|
|
70
72
|
|
|
71
73
|
**`SagaStartOptions`**:
|
|
74
|
+
|
|
72
75
|
```typescript
|
|
73
76
|
interface SagaStartOptions {
|
|
74
77
|
sagaName?: string;
|
|
@@ -82,36 +85,38 @@ interface SagaStartOptions {
|
|
|
82
85
|
Consumes events from transport, routes to handlers, and applies retry logic.
|
|
83
86
|
|
|
84
87
|
```typescript
|
|
85
|
-
import { SagaRunner } from
|
|
88
|
+
import { SagaRunner } from "@fbsm/saga-core";
|
|
86
89
|
|
|
87
90
|
const runner = new SagaRunner(
|
|
88
|
-
registry,
|
|
89
|
-
transport,
|
|
90
|
-
publisher,
|
|
91
|
-
parser,
|
|
92
|
-
options,
|
|
93
|
-
otelContext,
|
|
94
|
-
logger,
|
|
91
|
+
registry, // SagaRegistry
|
|
92
|
+
transport, // SagaTransport
|
|
93
|
+
publisher, // SagaPublisher
|
|
94
|
+
parser, // SagaParser
|
|
95
|
+
options, // RunnerOptions
|
|
96
|
+
otelContext, // OtelContext (optional)
|
|
97
|
+
logger, // SagaLogger (optional)
|
|
95
98
|
);
|
|
96
99
|
|
|
97
100
|
await runner.start(); // Subscribe and begin consuming
|
|
98
|
-
await runner.stop();
|
|
101
|
+
await runner.stop(); // Disconnect
|
|
99
102
|
```
|
|
100
103
|
|
|
101
104
|
**`RunnerOptions`**:
|
|
105
|
+
|
|
102
106
|
```typescript
|
|
103
107
|
interface RunnerOptions {
|
|
104
|
-
|
|
108
|
+
groupId: string;
|
|
105
109
|
fromBeginning?: boolean;
|
|
106
110
|
topicPrefix?: string;
|
|
107
111
|
retryPolicy?: {
|
|
108
|
-
maxRetries?: number;
|
|
109
|
-
initialDelayMs?: number;
|
|
112
|
+
maxRetries?: number; // default: 3
|
|
113
|
+
initialDelayMs?: number; // default: 200
|
|
110
114
|
};
|
|
111
115
|
}
|
|
112
116
|
```
|
|
113
117
|
|
|
114
118
|
**Handler execution flow**:
|
|
119
|
+
|
|
115
120
|
1. Parse inbound message via `SagaParser`
|
|
116
121
|
2. Look up handler in route map
|
|
117
122
|
3. Wrap emit with `final` hint (if `{ final: true }`)
|
|
@@ -132,51 +137,56 @@ Parses inbound messages using a 3-layer fallback strategy:
|
|
|
132
137
|
|
|
133
138
|
When using the header-based format (default with `@fbsm/saga-transport-kafka`):
|
|
134
139
|
|
|
135
|
-
| Header
|
|
136
|
-
|
|
137
|
-
| `saga-id`
|
|
138
|
-
| `saga-event-id`
|
|
139
|
-
| `saga-causation-id`
|
|
140
|
-
| `saga-step-name`
|
|
141
|
-
| `saga-published-at`
|
|
142
|
-
| `saga-schema-version`
|
|
143
|
-
| `saga-root-id`
|
|
144
|
-
| `saga-parent-id`
|
|
145
|
-
| `saga-event-hint`
|
|
146
|
-
| `saga-name`
|
|
147
|
-
| `saga-description`
|
|
148
|
-
| `saga-step-description` | Step description (optional)
|
|
149
|
-
| `saga-key`
|
|
140
|
+
| Header | Description |
|
|
141
|
+
| ----------------------- | ------------------------------------------------------ |
|
|
142
|
+
| `saga-id` | Saga instance ID |
|
|
143
|
+
| `saga-event-id` | Unique event ID |
|
|
144
|
+
| `saga-causation-id` | ID of the event that caused this one |
|
|
145
|
+
| `saga-step-name` | Logical step name |
|
|
146
|
+
| `saga-published-at` | ISO timestamp of publication |
|
|
147
|
+
| `saga-schema-version` | Schema version (currently `1`) |
|
|
148
|
+
| `saga-root-id` | Root saga ID (top-level ancestor) |
|
|
149
|
+
| `saga-parent-id` | Parent saga ID (for sub-sagas, optional) |
|
|
150
|
+
| `saga-event-hint` | Event hint: `compensation`, `final`, `fork` (optional) |
|
|
151
|
+
| `saga-name` | Saga name (optional) |
|
|
152
|
+
| `saga-description` | Saga description (optional) |
|
|
153
|
+
| `saga-step-description` | Step description (optional) |
|
|
154
|
+
| `saga-key` | Partition key (optional) |
|
|
150
155
|
|
|
151
156
|
## Errors
|
|
152
157
|
|
|
153
|
-
| Error
|
|
154
|
-
|
|
155
|
-
| `SagaError`
|
|
156
|
-
| `SagaRetryableError`
|
|
157
|
-
| `SagaDuplicateHandlerError`
|
|
158
|
-
| `SagaParseError`
|
|
159
|
-
| `SagaTransportNotConnectedError` | Publishing to a disconnected transport
|
|
160
|
-
| `SagaContextNotFoundError`
|
|
161
|
-
| `SagaNoParentError`
|
|
162
|
-
| `SagaInvalidHandlerConfigError`
|
|
158
|
+
| Error | Description |
|
|
159
|
+
| -------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
160
|
+
| `SagaError` | Base error class for all saga errors |
|
|
161
|
+
| `SagaRetryableError` | Throw in handlers to trigger retry with exponential backoff. `new SagaRetryableError(message, maxRetries?)` |
|
|
162
|
+
| `SagaDuplicateHandlerError` | Two handlers registered for the same event type |
|
|
163
|
+
| `SagaParseError` | Message parsing failed |
|
|
164
|
+
| `SagaTransportNotConnectedError` | Publishing to a disconnected transport |
|
|
165
|
+
| `SagaContextNotFoundError` | `emit()`/`startChild()`/`emitToParent()` called outside a saga context |
|
|
166
|
+
| `SagaNoParentError` | `emitToParent()` called in a saga without `parentSagaId` |
|
|
167
|
+
| `SagaInvalidHandlerConfigError` | Handler has conflicting options (e.g., both `final` and `fork`) |
|
|
163
168
|
|
|
164
169
|
**Retry behavior**: `SagaRetryableError` triggers exponential backoff: `initialDelayMs * 2^attempt`. After `maxRetries` attempts, `onRetryExhausted()` is called if defined. Non-retryable errors are logged and skipped.
|
|
165
170
|
|
|
166
171
|
## OTel Integration
|
|
167
172
|
|
|
168
173
|
```typescript
|
|
169
|
-
import {
|
|
174
|
+
import {
|
|
175
|
+
createOtelContext,
|
|
176
|
+
W3cOtelContext,
|
|
177
|
+
NoopOtelContext,
|
|
178
|
+
} from "@fbsm/saga-core";
|
|
170
179
|
|
|
171
180
|
// Auto-detect: uses W3cOtelContext if @opentelemetry/api is available, NoopOtelContext otherwise
|
|
172
181
|
const otelCtx = createOtelContext();
|
|
173
182
|
|
|
174
183
|
// Or explicitly:
|
|
175
|
-
const otelCtx = new W3cOtelContext();
|
|
176
|
-
const otelCtx = new NoopOtelContext();
|
|
184
|
+
const otelCtx = new W3cOtelContext(); // requires @opentelemetry/api
|
|
185
|
+
const otelCtx = new NoopOtelContext(); // no-op (no tracing)
|
|
177
186
|
```
|
|
178
187
|
|
|
179
188
|
The OTel context:
|
|
189
|
+
|
|
180
190
|
- Injects W3C baggage with saga context into outgoing messages
|
|
181
191
|
- Extracts trace context from incoming message headers
|
|
182
192
|
- Creates spans for publish and handle operations
|
package/dist/index.cjs
CHANGED
|
@@ -118,21 +118,27 @@ var SagaRunner = class {
|
|
|
118
118
|
async start() {
|
|
119
119
|
this.routeMap = this.registry.buildRouteMap();
|
|
120
120
|
const prefix = this.options.topicPrefix ?? "";
|
|
121
|
-
const topics = Array.from(this.routeMap.keys()).map(
|
|
121
|
+
const topics = Array.from(this.routeMap.keys()).map(
|
|
122
|
+
(et) => `${prefix}${et}`
|
|
123
|
+
);
|
|
122
124
|
await this.transport.connect();
|
|
123
125
|
if (topics.length > 0) {
|
|
124
|
-
this.logger.info(
|
|
126
|
+
this.logger.info(
|
|
127
|
+
`[SagaRunner] Subscribing to ${topics.length} topic(s): [${topics.join(", ")}]`
|
|
128
|
+
);
|
|
125
129
|
await this.transport.subscribe(
|
|
126
130
|
topics,
|
|
127
131
|
(message) => this.handleMessage(message),
|
|
128
132
|
{
|
|
129
133
|
fromBeginning: this.options.fromBeginning,
|
|
130
|
-
groupId:
|
|
134
|
+
groupId: this.options.groupId
|
|
131
135
|
}
|
|
132
136
|
);
|
|
133
137
|
this.logger.info("[SagaRunner] Consumer running");
|
|
134
138
|
} else {
|
|
135
|
-
this.logger.warn(
|
|
139
|
+
this.logger.warn(
|
|
140
|
+
"[SagaRunner] No handlers registered \u2014 nothing to subscribe"
|
|
141
|
+
);
|
|
136
142
|
}
|
|
137
143
|
}
|
|
138
144
|
async stop() {
|
|
@@ -159,10 +165,15 @@ var SagaRunner = class {
|
|
|
159
165
|
sagaName: event.sagaName,
|
|
160
166
|
sagaDescription: event.sagaDescription
|
|
161
167
|
};
|
|
162
|
-
const emit = this.publisher.forSaga(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
168
|
+
const emit = this.publisher.forSaga(
|
|
169
|
+
event.sagaId,
|
|
170
|
+
{
|
|
171
|
+
parentSagaId: event.parentSagaId,
|
|
172
|
+
rootSagaId: event.rootSagaId
|
|
173
|
+
},
|
|
174
|
+
event.eventId,
|
|
175
|
+
event.key
|
|
176
|
+
);
|
|
166
177
|
const wrappedEmit = async (params) => {
|
|
167
178
|
const finalParams = isFinalHandler ? { ...params, hint: "final" } : params;
|
|
168
179
|
return emit(finalParams);
|
|
@@ -170,10 +181,15 @@ var SagaRunner = class {
|
|
|
170
181
|
const forkConfig = route.options?.fork;
|
|
171
182
|
const finalEmit = forkConfig ? async (params) => {
|
|
172
183
|
const subSagaId = (0, import_uuid.v7)();
|
|
173
|
-
const subEmit = this.publisher.forSaga(
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
184
|
+
const subEmit = this.publisher.forSaga(
|
|
185
|
+
subSagaId,
|
|
186
|
+
{
|
|
187
|
+
parentSagaId: event.sagaId,
|
|
188
|
+
rootSagaId: event.rootSagaId
|
|
189
|
+
},
|
|
190
|
+
event.eventId,
|
|
191
|
+
event.key
|
|
192
|
+
);
|
|
177
193
|
const forkMeta = typeof forkConfig === "object" ? forkConfig : {};
|
|
178
194
|
const forkCtx = {
|
|
179
195
|
sagaId: subSagaId,
|
|
@@ -184,7 +200,10 @@ var SagaRunner = class {
|
|
|
184
200
|
sagaName: forkMeta.sagaName,
|
|
185
201
|
sagaDescription: forkMeta.sagaDescription
|
|
186
202
|
};
|
|
187
|
-
await SagaContext.run(
|
|
203
|
+
await SagaContext.run(
|
|
204
|
+
forkCtx,
|
|
205
|
+
() => subEmit({ ...params, hint: "fork" })
|
|
206
|
+
);
|
|
188
207
|
} : wrappedEmit;
|
|
189
208
|
const spanAttrs = {
|
|
190
209
|
"saga.id": event.sagaId,
|
|
@@ -195,8 +214,10 @@ var SagaRunner = class {
|
|
|
195
214
|
"saga.handler.service": route.participant.serviceId
|
|
196
215
|
};
|
|
197
216
|
if (event.sagaName) spanAttrs["saga.name"] = event.sagaName;
|
|
198
|
-
if (event.sagaDescription)
|
|
199
|
-
|
|
217
|
+
if (event.sagaDescription)
|
|
218
|
+
spanAttrs["saga.description"] = event.sagaDescription;
|
|
219
|
+
if (event.stepDescription)
|
|
220
|
+
spanAttrs["saga.step.description"] = event.stepDescription;
|
|
200
221
|
if (event.parentSagaId) spanAttrs["saga.parent.id"] = event.parentSagaId;
|
|
201
222
|
const sagaCtxData = {
|
|
202
223
|
sagaId: event.sagaId,
|
|
@@ -209,10 +230,20 @@ var SagaRunner = class {
|
|
|
209
230
|
};
|
|
210
231
|
const runHandler = () => SagaContext.run(
|
|
211
232
|
sagaCtxData,
|
|
212
|
-
() => this.runWithRetry(
|
|
233
|
+
() => this.runWithRetry(
|
|
234
|
+
route.handler,
|
|
235
|
+
route.participant,
|
|
236
|
+
incoming,
|
|
237
|
+
finalEmit
|
|
238
|
+
)
|
|
213
239
|
);
|
|
214
240
|
if (this.otelCtx) {
|
|
215
|
-
await this.otelCtx.withExtractedSpan(
|
|
241
|
+
await this.otelCtx.withExtractedSpan(
|
|
242
|
+
`saga.handle ${event.eventType}`,
|
|
243
|
+
spanAttrs,
|
|
244
|
+
message.headers,
|
|
245
|
+
runHandler
|
|
246
|
+
);
|
|
216
247
|
} else {
|
|
217
248
|
await runHandler();
|
|
218
249
|
}
|
|
@@ -321,10 +352,15 @@ var SagaPublisher = class {
|
|
|
321
352
|
}
|
|
322
353
|
async emit(params) {
|
|
323
354
|
const ctx = SagaContext.require();
|
|
324
|
-
const boundEmit = this.forSaga(
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
355
|
+
const boundEmit = this.forSaga(
|
|
356
|
+
ctx.sagaId,
|
|
357
|
+
{
|
|
358
|
+
parentSagaId: ctx.parentSagaId,
|
|
359
|
+
rootSagaId: ctx.rootSagaId
|
|
360
|
+
},
|
|
361
|
+
ctx.causationId,
|
|
362
|
+
ctx.key
|
|
363
|
+
);
|
|
328
364
|
return boundEmit(params);
|
|
329
365
|
}
|
|
330
366
|
async startChild(fn, opts) {
|
|
@@ -358,10 +394,15 @@ var SagaPublisher = class {
|
|
|
358
394
|
await SagaContext.run(parentCtx, paramsOrFn);
|
|
359
395
|
return;
|
|
360
396
|
}
|
|
361
|
-
const parentEmit = this.forSaga(
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
397
|
+
const parentEmit = this.forSaga(
|
|
398
|
+
ctx.parentSagaId,
|
|
399
|
+
{
|
|
400
|
+
parentSagaId: ctx.parentSagaId,
|
|
401
|
+
rootSagaId: ctx.rootSagaId
|
|
402
|
+
},
|
|
403
|
+
ctx.causationId,
|
|
404
|
+
ctx.key
|
|
405
|
+
);
|
|
365
406
|
return parentEmit(paramsOrFn);
|
|
366
407
|
}
|
|
367
408
|
forSaga(sagaId, parentCtx, causationId, baseKey) {
|
|
@@ -401,7 +442,11 @@ var SagaPublisher = class {
|
|
|
401
442
|
};
|
|
402
443
|
}
|
|
403
444
|
async publish(event) {
|
|
404
|
-
this.otelCtx.injectBaggage(
|
|
445
|
+
this.otelCtx.injectBaggage(
|
|
446
|
+
event.sagaId,
|
|
447
|
+
event.rootSagaId,
|
|
448
|
+
event.parentSagaId
|
|
449
|
+
);
|
|
405
450
|
const attrs = {
|
|
406
451
|
"saga.id": event.sagaId,
|
|
407
452
|
"saga.event.type": event.eventType,
|
|
@@ -627,7 +672,10 @@ var W3cOtelContext = class {
|
|
|
627
672
|
entries["saga.parent.id"] = { value: parentSagaId };
|
|
628
673
|
}
|
|
629
674
|
const baggage = this.api.propagation.createBaggage(entries);
|
|
630
|
-
const ctx = this.api.propagation.setBaggage(
|
|
675
|
+
const ctx = this.api.propagation.setBaggage(
|
|
676
|
+
this.api.context.active(),
|
|
677
|
+
baggage
|
|
678
|
+
);
|
|
631
679
|
this.api.context.with(ctx, () => {
|
|
632
680
|
});
|
|
633
681
|
}
|
|
@@ -659,7 +707,9 @@ var W3cOtelContext = class {
|
|
|
659
707
|
code: this.api.SpanStatusCode.ERROR,
|
|
660
708
|
message: error instanceof Error ? error.message : String(error)
|
|
661
709
|
});
|
|
662
|
-
span.recordException(
|
|
710
|
+
span.recordException(
|
|
711
|
+
error instanceof Error ? error : new Error(String(error))
|
|
712
|
+
);
|
|
663
713
|
throw error;
|
|
664
714
|
} finally {
|
|
665
715
|
span.end();
|
|
@@ -670,27 +720,36 @@ var W3cOtelContext = class {
|
|
|
670
720
|
this.api.propagation.inject(this.api.context.active(), headers);
|
|
671
721
|
}
|
|
672
722
|
async withExtractedSpan(name, attrs, headers, fn) {
|
|
673
|
-
const parentCtx = this.api.propagation.extract(
|
|
723
|
+
const parentCtx = this.api.propagation.extract(
|
|
724
|
+
this.api.ROOT_CONTEXT,
|
|
725
|
+
headers
|
|
726
|
+
);
|
|
674
727
|
const tracer = this.api.trace.getTracer("@fbsm/saga-core");
|
|
675
728
|
return this.api.context.with(
|
|
676
729
|
parentCtx,
|
|
677
|
-
() => tracer.startActiveSpan(
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
span.
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
730
|
+
() => tracer.startActiveSpan(
|
|
731
|
+
name,
|
|
732
|
+
{ kind: this.api.SpanKind.CONSUMER },
|
|
733
|
+
async (span) => {
|
|
734
|
+
span.setAttributes(attrs);
|
|
735
|
+
try {
|
|
736
|
+
const result = await fn();
|
|
737
|
+
span.setStatus({ code: this.api.SpanStatusCode.OK });
|
|
738
|
+
return result;
|
|
739
|
+
} catch (error) {
|
|
740
|
+
span.setStatus({
|
|
741
|
+
code: this.api.SpanStatusCode.ERROR,
|
|
742
|
+
message: error instanceof Error ? error.message : String(error)
|
|
743
|
+
});
|
|
744
|
+
span.recordException(
|
|
745
|
+
error instanceof Error ? error : new Error(String(error))
|
|
746
|
+
);
|
|
747
|
+
throw error;
|
|
748
|
+
} finally {
|
|
749
|
+
span.end();
|
|
750
|
+
}
|
|
692
751
|
}
|
|
693
|
-
|
|
752
|
+
)
|
|
694
753
|
);
|
|
695
754
|
}
|
|
696
755
|
};
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +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"]}
|
|
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 {\n NoopOtelContext,\n W3cOtelContext,\n createOtelContext,\n} 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 {\n SagaParticipant,\n HandlerConfig,\n ForkConfig,\n} 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 {\n SagaTransport,\n InboundMessage,\n} 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(\n (et) => `${prefix}${et}`,\n );\n\n await this.transport.connect();\n\n if (topics.length > 0) {\n this.logger.info(\n `[SagaRunner] Subscribing to ${topics.length} topic(s): [${topics.join(\", \")}]`,\n );\n await this.transport.subscribe(\n topics,\n (message) => this.handleMessage(message),\n {\n fromBeginning: this.options.fromBeginning,\n groupId: this.options.groupId,\n },\n );\n this.logger.info(\"[SagaRunner] Consumer running\");\n } else {\n this.logger.warn(\n \"[SagaRunner] No handlers registered — nothing to subscribe\",\n );\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(\n event.sagaId,\n {\n parentSagaId: event.parentSagaId,\n rootSagaId: event.rootSagaId,\n },\n event.eventId,\n event.key,\n );\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(\n subSagaId,\n {\n parentSagaId: event.sagaId,\n rootSagaId: event.rootSagaId,\n },\n event.eventId,\n event.key,\n );\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, () =>\n subEmit({ ...params, hint: \"fork\" }),\n );\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)\n spanAttrs[\"saga.description\"] = event.sagaDescription;\n if (event.stepDescription)\n 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(\n route.handler,\n route.participant,\n incoming,\n finalEmit,\n ),\n );\n\n if (this.otelCtx) {\n await this.otelCtx.withExtractedSpan(\n `saga.handle ${event.eventType}`,\n spanAttrs,\n message.headers,\n runHandler,\n );\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>(\n fn: () => R | Promise<R>,\n opts?: SagaStartOptions,\n ): Promise<{ sagaId: string; result: Awaited<R> }> {\n const sagaId = uuidv7();\n const ctxData = {\n sagaId,\n rootSagaId: sagaId,\n causationId: sagaId,\n key: opts?.key,\n sagaName: opts?.sagaName,\n 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(\n ctx.sagaId,\n {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n },\n ctx.causationId,\n ctx.key,\n );\n return boundEmit(params);\n }\n\n async startChild<R>(\n fn: () => R | Promise<R>,\n opts?: SagaStartOptions,\n ): 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>(\n paramsOrFn: EmitParams<T> | (() => void | Promise<void>),\n ): 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(\n ctx.parentSagaId,\n {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n },\n ctx.causationId,\n ctx.key,\n );\n return parentEmit(paramsOrFn);\n }\n\n forSaga(\n sagaId: string,\n parentCtx?: ParentSagaContext,\n causationId?: string,\n baseKey?: string,\n ): 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(\n event.sagaId,\n event.rootSagaId,\n event.parentSagaId,\n );\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>(\n event: SagaEvent<T>,\n topicPrefix = \"\",\n): 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(\n eventType: string,\n existingServiceId: string,\n newServiceId: string,\n ) {\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 {\n SagaParticipant,\n HandlerConfig,\n} 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(\n sagaId: string,\n rootSagaId: string,\n parentSagaId?: string,\n ): void;\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n };\n enrichSpan(attrs: Record<string, string>): void;\n withSpan<T>(\n name: string,\n attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T>;\n injectTraceContext(headers: Record<string, string>): void;\n withExtractedSpan<T>(\n name: string,\n attrs: Record<string, string>,\n headers: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T>;\n}\n\nexport class NoopOtelContext implements OtelContext {\n injectBaggage(): void {}\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n } {\n return {};\n }\n enrichSpan(): void {}\n async withSpan<T>(\n _name: string,\n _attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T> {\n return fn();\n }\n injectTraceContext(): void {}\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 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(\n sagaId: string,\n rootSagaId: string,\n parentSagaId?: string,\n ): 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(\n this.api.context.active(),\n baggage,\n );\n this.api.context.with(ctx, () => {});\n }\n\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n } {\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>(\n name: string,\n attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): 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(\n error instanceof Error ? error : new Error(String(error)),\n );\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(\n this.api.ROOT_CONTEXT,\n headers,\n );\n const tracer = this.api.trace.getTracer(\"@fbsm/saga-core\");\n\n return this.api.context.with(parentCtx, () =>\n tracer.startActiveSpan(\n name,\n { kind: this.api.SpanKind.CONSUMER },\n 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(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\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
CHANGED
|
@@ -24,7 +24,7 @@ interface TransportSubscribeOptions {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
interface RunnerOptions {
|
|
27
|
-
|
|
27
|
+
groupId: string;
|
|
28
28
|
fromBeginning?: boolean;
|
|
29
29
|
/** Prefix prepended to eventType to form Kafka topic names. Default: '' (no prefix). */
|
|
30
30
|
topicPrefix?: string;
|
|
@@ -50,7 +50,7 @@ interface IncomingEvent<T = Record<string, unknown>> {
|
|
|
50
50
|
key?: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
type EventHint =
|
|
53
|
+
type EventHint = "compensation" | "final" | "fork";
|
|
54
54
|
interface EmitParams<T extends object = Record<string, unknown>> {
|
|
55
55
|
eventType: string;
|
|
56
56
|
stepName: string;
|
package/dist/index.d.ts
CHANGED
|
@@ -24,7 +24,7 @@ interface TransportSubscribeOptions {
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
interface RunnerOptions {
|
|
27
|
-
|
|
27
|
+
groupId: string;
|
|
28
28
|
fromBeginning?: boolean;
|
|
29
29
|
/** Prefix prepended to eventType to form Kafka topic names. Default: '' (no prefix). */
|
|
30
30
|
topicPrefix?: string;
|
|
@@ -50,7 +50,7 @@ interface IncomingEvent<T = Record<string, unknown>> {
|
|
|
50
50
|
key?: string;
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
type EventHint =
|
|
53
|
+
type EventHint = "compensation" | "final" | "fork";
|
|
54
54
|
interface EmitParams<T extends object = Record<string, unknown>> {
|
|
55
55
|
eventType: string;
|
|
56
56
|
stepName: string;
|
package/dist/index.js
CHANGED
|
@@ -83,21 +83,27 @@ var SagaRunner = class {
|
|
|
83
83
|
async start() {
|
|
84
84
|
this.routeMap = this.registry.buildRouteMap();
|
|
85
85
|
const prefix = this.options.topicPrefix ?? "";
|
|
86
|
-
const topics = Array.from(this.routeMap.keys()).map(
|
|
86
|
+
const topics = Array.from(this.routeMap.keys()).map(
|
|
87
|
+
(et) => `${prefix}${et}`
|
|
88
|
+
);
|
|
87
89
|
await this.transport.connect();
|
|
88
90
|
if (topics.length > 0) {
|
|
89
|
-
this.logger.info(
|
|
91
|
+
this.logger.info(
|
|
92
|
+
`[SagaRunner] Subscribing to ${topics.length} topic(s): [${topics.join(", ")}]`
|
|
93
|
+
);
|
|
90
94
|
await this.transport.subscribe(
|
|
91
95
|
topics,
|
|
92
96
|
(message) => this.handleMessage(message),
|
|
93
97
|
{
|
|
94
98
|
fromBeginning: this.options.fromBeginning,
|
|
95
|
-
groupId:
|
|
99
|
+
groupId: this.options.groupId
|
|
96
100
|
}
|
|
97
101
|
);
|
|
98
102
|
this.logger.info("[SagaRunner] Consumer running");
|
|
99
103
|
} else {
|
|
100
|
-
this.logger.warn(
|
|
104
|
+
this.logger.warn(
|
|
105
|
+
"[SagaRunner] No handlers registered \u2014 nothing to subscribe"
|
|
106
|
+
);
|
|
101
107
|
}
|
|
102
108
|
}
|
|
103
109
|
async stop() {
|
|
@@ -124,10 +130,15 @@ var SagaRunner = class {
|
|
|
124
130
|
sagaName: event.sagaName,
|
|
125
131
|
sagaDescription: event.sagaDescription
|
|
126
132
|
};
|
|
127
|
-
const emit = this.publisher.forSaga(
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
const emit = this.publisher.forSaga(
|
|
134
|
+
event.sagaId,
|
|
135
|
+
{
|
|
136
|
+
parentSagaId: event.parentSagaId,
|
|
137
|
+
rootSagaId: event.rootSagaId
|
|
138
|
+
},
|
|
139
|
+
event.eventId,
|
|
140
|
+
event.key
|
|
141
|
+
);
|
|
131
142
|
const wrappedEmit = async (params) => {
|
|
132
143
|
const finalParams = isFinalHandler ? { ...params, hint: "final" } : params;
|
|
133
144
|
return emit(finalParams);
|
|
@@ -135,10 +146,15 @@ var SagaRunner = class {
|
|
|
135
146
|
const forkConfig = route.options?.fork;
|
|
136
147
|
const finalEmit = forkConfig ? async (params) => {
|
|
137
148
|
const subSagaId = uuidv7();
|
|
138
|
-
const subEmit = this.publisher.forSaga(
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
149
|
+
const subEmit = this.publisher.forSaga(
|
|
150
|
+
subSagaId,
|
|
151
|
+
{
|
|
152
|
+
parentSagaId: event.sagaId,
|
|
153
|
+
rootSagaId: event.rootSagaId
|
|
154
|
+
},
|
|
155
|
+
event.eventId,
|
|
156
|
+
event.key
|
|
157
|
+
);
|
|
142
158
|
const forkMeta = typeof forkConfig === "object" ? forkConfig : {};
|
|
143
159
|
const forkCtx = {
|
|
144
160
|
sagaId: subSagaId,
|
|
@@ -149,7 +165,10 @@ var SagaRunner = class {
|
|
|
149
165
|
sagaName: forkMeta.sagaName,
|
|
150
166
|
sagaDescription: forkMeta.sagaDescription
|
|
151
167
|
};
|
|
152
|
-
await SagaContext.run(
|
|
168
|
+
await SagaContext.run(
|
|
169
|
+
forkCtx,
|
|
170
|
+
() => subEmit({ ...params, hint: "fork" })
|
|
171
|
+
);
|
|
153
172
|
} : wrappedEmit;
|
|
154
173
|
const spanAttrs = {
|
|
155
174
|
"saga.id": event.sagaId,
|
|
@@ -160,8 +179,10 @@ var SagaRunner = class {
|
|
|
160
179
|
"saga.handler.service": route.participant.serviceId
|
|
161
180
|
};
|
|
162
181
|
if (event.sagaName) spanAttrs["saga.name"] = event.sagaName;
|
|
163
|
-
if (event.sagaDescription)
|
|
164
|
-
|
|
182
|
+
if (event.sagaDescription)
|
|
183
|
+
spanAttrs["saga.description"] = event.sagaDescription;
|
|
184
|
+
if (event.stepDescription)
|
|
185
|
+
spanAttrs["saga.step.description"] = event.stepDescription;
|
|
165
186
|
if (event.parentSagaId) spanAttrs["saga.parent.id"] = event.parentSagaId;
|
|
166
187
|
const sagaCtxData = {
|
|
167
188
|
sagaId: event.sagaId,
|
|
@@ -174,10 +195,20 @@ var SagaRunner = class {
|
|
|
174
195
|
};
|
|
175
196
|
const runHandler = () => SagaContext.run(
|
|
176
197
|
sagaCtxData,
|
|
177
|
-
() => this.runWithRetry(
|
|
198
|
+
() => this.runWithRetry(
|
|
199
|
+
route.handler,
|
|
200
|
+
route.participant,
|
|
201
|
+
incoming,
|
|
202
|
+
finalEmit
|
|
203
|
+
)
|
|
178
204
|
);
|
|
179
205
|
if (this.otelCtx) {
|
|
180
|
-
await this.otelCtx.withExtractedSpan(
|
|
206
|
+
await this.otelCtx.withExtractedSpan(
|
|
207
|
+
`saga.handle ${event.eventType}`,
|
|
208
|
+
spanAttrs,
|
|
209
|
+
message.headers,
|
|
210
|
+
runHandler
|
|
211
|
+
);
|
|
181
212
|
} else {
|
|
182
213
|
await runHandler();
|
|
183
214
|
}
|
|
@@ -286,10 +317,15 @@ var SagaPublisher = class {
|
|
|
286
317
|
}
|
|
287
318
|
async emit(params) {
|
|
288
319
|
const ctx = SagaContext.require();
|
|
289
|
-
const boundEmit = this.forSaga(
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
320
|
+
const boundEmit = this.forSaga(
|
|
321
|
+
ctx.sagaId,
|
|
322
|
+
{
|
|
323
|
+
parentSagaId: ctx.parentSagaId,
|
|
324
|
+
rootSagaId: ctx.rootSagaId
|
|
325
|
+
},
|
|
326
|
+
ctx.causationId,
|
|
327
|
+
ctx.key
|
|
328
|
+
);
|
|
293
329
|
return boundEmit(params);
|
|
294
330
|
}
|
|
295
331
|
async startChild(fn, opts) {
|
|
@@ -323,10 +359,15 @@ var SagaPublisher = class {
|
|
|
323
359
|
await SagaContext.run(parentCtx, paramsOrFn);
|
|
324
360
|
return;
|
|
325
361
|
}
|
|
326
|
-
const parentEmit = this.forSaga(
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
362
|
+
const parentEmit = this.forSaga(
|
|
363
|
+
ctx.parentSagaId,
|
|
364
|
+
{
|
|
365
|
+
parentSagaId: ctx.parentSagaId,
|
|
366
|
+
rootSagaId: ctx.rootSagaId
|
|
367
|
+
},
|
|
368
|
+
ctx.causationId,
|
|
369
|
+
ctx.key
|
|
370
|
+
);
|
|
330
371
|
return parentEmit(paramsOrFn);
|
|
331
372
|
}
|
|
332
373
|
forSaga(sagaId, parentCtx, causationId, baseKey) {
|
|
@@ -366,7 +407,11 @@ var SagaPublisher = class {
|
|
|
366
407
|
};
|
|
367
408
|
}
|
|
368
409
|
async publish(event) {
|
|
369
|
-
this.otelCtx.injectBaggage(
|
|
410
|
+
this.otelCtx.injectBaggage(
|
|
411
|
+
event.sagaId,
|
|
412
|
+
event.rootSagaId,
|
|
413
|
+
event.parentSagaId
|
|
414
|
+
);
|
|
370
415
|
const attrs = {
|
|
371
416
|
"saga.id": event.sagaId,
|
|
372
417
|
"saga.event.type": event.eventType,
|
|
@@ -592,7 +637,10 @@ var W3cOtelContext = class {
|
|
|
592
637
|
entries["saga.parent.id"] = { value: parentSagaId };
|
|
593
638
|
}
|
|
594
639
|
const baggage = this.api.propagation.createBaggage(entries);
|
|
595
|
-
const ctx = this.api.propagation.setBaggage(
|
|
640
|
+
const ctx = this.api.propagation.setBaggage(
|
|
641
|
+
this.api.context.active(),
|
|
642
|
+
baggage
|
|
643
|
+
);
|
|
596
644
|
this.api.context.with(ctx, () => {
|
|
597
645
|
});
|
|
598
646
|
}
|
|
@@ -624,7 +672,9 @@ var W3cOtelContext = class {
|
|
|
624
672
|
code: this.api.SpanStatusCode.ERROR,
|
|
625
673
|
message: error instanceof Error ? error.message : String(error)
|
|
626
674
|
});
|
|
627
|
-
span.recordException(
|
|
675
|
+
span.recordException(
|
|
676
|
+
error instanceof Error ? error : new Error(String(error))
|
|
677
|
+
);
|
|
628
678
|
throw error;
|
|
629
679
|
} finally {
|
|
630
680
|
span.end();
|
|
@@ -635,27 +685,36 @@ var W3cOtelContext = class {
|
|
|
635
685
|
this.api.propagation.inject(this.api.context.active(), headers);
|
|
636
686
|
}
|
|
637
687
|
async withExtractedSpan(name, attrs, headers, fn) {
|
|
638
|
-
const parentCtx = this.api.propagation.extract(
|
|
688
|
+
const parentCtx = this.api.propagation.extract(
|
|
689
|
+
this.api.ROOT_CONTEXT,
|
|
690
|
+
headers
|
|
691
|
+
);
|
|
639
692
|
const tracer = this.api.trace.getTracer("@fbsm/saga-core");
|
|
640
693
|
return this.api.context.with(
|
|
641
694
|
parentCtx,
|
|
642
|
-
() => tracer.startActiveSpan(
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
span.
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
695
|
+
() => tracer.startActiveSpan(
|
|
696
|
+
name,
|
|
697
|
+
{ kind: this.api.SpanKind.CONSUMER },
|
|
698
|
+
async (span) => {
|
|
699
|
+
span.setAttributes(attrs);
|
|
700
|
+
try {
|
|
701
|
+
const result = await fn();
|
|
702
|
+
span.setStatus({ code: this.api.SpanStatusCode.OK });
|
|
703
|
+
return result;
|
|
704
|
+
} catch (error) {
|
|
705
|
+
span.setStatus({
|
|
706
|
+
code: this.api.SpanStatusCode.ERROR,
|
|
707
|
+
message: error instanceof Error ? error.message : String(error)
|
|
708
|
+
});
|
|
709
|
+
span.recordException(
|
|
710
|
+
error instanceof Error ? error : new Error(String(error))
|
|
711
|
+
);
|
|
712
|
+
throw error;
|
|
713
|
+
} finally {
|
|
714
|
+
span.end();
|
|
715
|
+
}
|
|
657
716
|
}
|
|
658
|
-
|
|
717
|
+
)
|
|
659
718
|
);
|
|
660
719
|
}
|
|
661
720
|
};
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../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":["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","uuidv7","uuidv7"]}
|
|
1
|
+
{"version":3,"sources":["../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":["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 {\n SagaTransport,\n InboundMessage,\n} 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(\n (et) => `${prefix}${et}`,\n );\n\n await this.transport.connect();\n\n if (topics.length > 0) {\n this.logger.info(\n `[SagaRunner] Subscribing to ${topics.length} topic(s): [${topics.join(\", \")}]`,\n );\n await this.transport.subscribe(\n topics,\n (message) => this.handleMessage(message),\n {\n fromBeginning: this.options.fromBeginning,\n groupId: this.options.groupId,\n },\n );\n this.logger.info(\"[SagaRunner] Consumer running\");\n } else {\n this.logger.warn(\n \"[SagaRunner] No handlers registered — nothing to subscribe\",\n );\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(\n event.sagaId,\n {\n parentSagaId: event.parentSagaId,\n rootSagaId: event.rootSagaId,\n },\n event.eventId,\n event.key,\n );\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(\n subSagaId,\n {\n parentSagaId: event.sagaId,\n rootSagaId: event.rootSagaId,\n },\n event.eventId,\n event.key,\n );\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, () =>\n subEmit({ ...params, hint: \"fork\" }),\n );\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)\n spanAttrs[\"saga.description\"] = event.sagaDescription;\n if (event.stepDescription)\n 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(\n route.handler,\n route.participant,\n incoming,\n finalEmit,\n ),\n );\n\n if (this.otelCtx) {\n await this.otelCtx.withExtractedSpan(\n `saga.handle ${event.eventType}`,\n spanAttrs,\n message.headers,\n runHandler,\n );\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>(\n fn: () => R | Promise<R>,\n opts?: SagaStartOptions,\n ): Promise<{ sagaId: string; result: Awaited<R> }> {\n const sagaId = uuidv7();\n const ctxData = {\n sagaId,\n rootSagaId: sagaId,\n causationId: sagaId,\n key: opts?.key,\n sagaName: opts?.sagaName,\n 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(\n ctx.sagaId,\n {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n },\n ctx.causationId,\n ctx.key,\n );\n return boundEmit(params);\n }\n\n async startChild<R>(\n fn: () => R | Promise<R>,\n opts?: SagaStartOptions,\n ): 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>(\n paramsOrFn: EmitParams<T> | (() => void | Promise<void>),\n ): 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(\n ctx.parentSagaId,\n {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n },\n ctx.causationId,\n ctx.key,\n );\n return parentEmit(paramsOrFn);\n }\n\n forSaga(\n sagaId: string,\n parentCtx?: ParentSagaContext,\n causationId?: string,\n baseKey?: string,\n ): 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(\n event.sagaId,\n event.rootSagaId,\n event.parentSagaId,\n );\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>(\n event: SagaEvent<T>,\n topicPrefix = \"\",\n): 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(\n eventType: string,\n existingServiceId: string,\n newServiceId: string,\n ) {\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 {\n SagaParticipant,\n HandlerConfig,\n} 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(\n sagaId: string,\n rootSagaId: string,\n parentSagaId?: string,\n ): void;\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n };\n enrichSpan(attrs: Record<string, string>): void;\n withSpan<T>(\n name: string,\n attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T>;\n injectTraceContext(headers: Record<string, string>): void;\n withExtractedSpan<T>(\n name: string,\n attrs: Record<string, string>,\n headers: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T>;\n}\n\nexport class NoopOtelContext implements OtelContext {\n injectBaggage(): void {}\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n } {\n return {};\n }\n enrichSpan(): void {}\n async withSpan<T>(\n _name: string,\n _attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T> {\n return fn();\n }\n injectTraceContext(): void {}\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 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(\n sagaId: string,\n rootSagaId: string,\n parentSagaId?: string,\n ): 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(\n this.api.context.active(),\n baggage,\n );\n this.api.context.with(ctx, () => {});\n }\n\n extractBaggage(): {\n sagaId?: string;\n rootSagaId?: string;\n parentSagaId?: string;\n } {\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>(\n name: string,\n attrs: Record<string, string>,\n fn: () => Promise<T>,\n ): 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(\n error instanceof Error ? error : new Error(String(error)),\n );\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(\n this.api.ROOT_CONTEXT,\n headers,\n );\n const tracer = this.api.trace.getTracer(\"@fbsm/saga-core\");\n\n return this.api.context.with(parentCtx, () =>\n tracer.startActiveSpan(\n name,\n { kind: this.api.SpanKind.CONSUMER },\n 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(\n error instanceof Error ? error : new Error(String(error)),\n );\n throw error;\n } finally {\n span.end();\n }\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","uuidv7","uuidv7"]}
|