@yuva-devlab/events 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/index.cjs +297 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +425 -0
- package/dist/index.d.ts +425 -0
- package/dist/index.js +288 -0
- package/dist/index.js.map +1 -0
- package/package.json +50 -3
- package/README.md +0 -3
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file packages/events/src/contracts/envelope.ts
|
|
5
|
+
* @description Standard transactional outbox and event bus envelope schema for DevLab.
|
|
6
|
+
*
|
|
7
|
+
* Guarantees cross-service traceability, event ordering, and idempotency across all services.
|
|
8
|
+
*
|
|
9
|
+
* @module @yuva-devlab/events
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Standard Zod validator for RFC UUID strings.
|
|
14
|
+
*/
|
|
15
|
+
declare const UuidSchema: z.ZodString;
|
|
16
|
+
/**
|
|
17
|
+
* Zod schema defining the canonical metadata envelope wrapping all domain events.
|
|
18
|
+
*/
|
|
19
|
+
declare const DomainEventEnvelopeSchema: z.ZodObject<{
|
|
20
|
+
/** Unique event occurrence UUID for deduplication */
|
|
21
|
+
eventId: z.ZodString;
|
|
22
|
+
/** Qualified dot-notated or uppercase event type (e.g. AGENT.EXECUTION.COMPLETED) */
|
|
23
|
+
eventType: z.ZodString;
|
|
24
|
+
/** Optional execution or correlation identifier */
|
|
25
|
+
executionId: z.ZodOptional<z.ZodString>;
|
|
26
|
+
/** Optional tenant partition identifier */
|
|
27
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
28
|
+
/** Distributed trace identifier for end-to-end telemetry */
|
|
29
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
30
|
+
/** ISO-8601 string or Date object representing event generation time */
|
|
31
|
+
timestamp: z.ZodDefault<z.ZodString>;
|
|
32
|
+
/** Domain-specific event payload matching the eventType */
|
|
33
|
+
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
eventId: string;
|
|
36
|
+
eventType: string;
|
|
37
|
+
timestamp: string;
|
|
38
|
+
payload: Record<string, unknown>;
|
|
39
|
+
executionId?: string | undefined;
|
|
40
|
+
tenantId?: string | undefined;
|
|
41
|
+
traceId?: string | undefined;
|
|
42
|
+
}, {
|
|
43
|
+
eventId: string;
|
|
44
|
+
eventType: string;
|
|
45
|
+
payload: Record<string, unknown>;
|
|
46
|
+
executionId?: string | undefined;
|
|
47
|
+
tenantId?: string | undefined;
|
|
48
|
+
traceId?: string | undefined;
|
|
49
|
+
timestamp?: string | undefined;
|
|
50
|
+
}>;
|
|
51
|
+
/**
|
|
52
|
+
* Inferred type of the canonical domain event envelope.
|
|
53
|
+
*/
|
|
54
|
+
type DomainEventEnvelope<TPayload extends Record<string, unknown> = Record<string, unknown>> = Omit<z.infer<typeof DomainEventEnvelopeSchema>, "payload"> & {
|
|
55
|
+
payload: TPayload;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Factory options for generating a new DomainEventEnvelope.
|
|
59
|
+
*/
|
|
60
|
+
interface CreateEventEnvelopeOptions<TPayload extends Record<string, unknown>> {
|
|
61
|
+
eventId?: string;
|
|
62
|
+
eventType: string;
|
|
63
|
+
payload: TPayload;
|
|
64
|
+
executionId?: string;
|
|
65
|
+
tenantId?: string;
|
|
66
|
+
traceId?: string;
|
|
67
|
+
timestamp?: string;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Generates a valid domain event envelope with defaults.
|
|
71
|
+
*
|
|
72
|
+
* @param options - Factory configuration options.
|
|
73
|
+
* @returns Fully constructed DomainEventEnvelope.
|
|
74
|
+
*/
|
|
75
|
+
declare function createEventEnvelope<TPayload extends Record<string, unknown>>(options: CreateEventEnvelopeOptions<TPayload>): DomainEventEnvelope<TPayload>;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* @file packages/events/src/contracts/event-bus.interface.ts
|
|
79
|
+
* @description Master publisher, subscriber, and event bus interfaces for DevLab services.
|
|
80
|
+
* @module @yuva-devlab/events
|
|
81
|
+
*/
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Callback handler invoked when a matching domain event is received.
|
|
85
|
+
*/
|
|
86
|
+
type EventHandler<TEvent extends DomainEventEnvelope = DomainEventEnvelope> = (event: TEvent) => void | Promise<void>;
|
|
87
|
+
/**
|
|
88
|
+
* Handle returned to subscribers allowing idempotent unsubscription.
|
|
89
|
+
*/
|
|
90
|
+
interface EventSubscription {
|
|
91
|
+
/** Unregisters the subscriber from receiving further events */
|
|
92
|
+
unsubscribe: () => void;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Contract for components capable of publishing domain events.
|
|
96
|
+
*/
|
|
97
|
+
interface IEventPublisher {
|
|
98
|
+
/**
|
|
99
|
+
* Emits a single domain event envelope.
|
|
100
|
+
*
|
|
101
|
+
* @param event - The validated event envelope to emit.
|
|
102
|
+
*/
|
|
103
|
+
publish(event: DomainEventEnvelope): Promise<void>;
|
|
104
|
+
/**
|
|
105
|
+
* Emits an atomic or contiguous sequence of domain events.
|
|
106
|
+
*
|
|
107
|
+
* @param events - Array of validated event envelopes.
|
|
108
|
+
*/
|
|
109
|
+
publishBatch(events: DomainEventEnvelope[]): Promise<void>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Contract for components that subscribe to domain event topics or wildcards.
|
|
113
|
+
*/
|
|
114
|
+
interface IEventSubscriber {
|
|
115
|
+
/**
|
|
116
|
+
* Registers a listener for an exact domain event type or wildcard ("*" or "domain.*").
|
|
117
|
+
*
|
|
118
|
+
* @param eventType - Target event type or wildcard pattern.
|
|
119
|
+
* @param handler - Callback function executing on event receipt.
|
|
120
|
+
* @returns Subscription handle with an unsubscribe method.
|
|
121
|
+
*/
|
|
122
|
+
subscribe(eventType: string, handler: EventHandler): EventSubscription;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Unified bi-directional event bus uniting publisher and subscriber capabilities.
|
|
126
|
+
*/
|
|
127
|
+
interface IEventBus extends IEventPublisher, IEventSubscriber {
|
|
128
|
+
/**
|
|
129
|
+
* Removes all registered subscribers and releases memory.
|
|
130
|
+
*/
|
|
131
|
+
clear(): void;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* @file packages/events/src/bus/in-memory-event-bus.ts
|
|
136
|
+
* @description Fast, non-blocking in-memory event bus implementation supporting wildcards.
|
|
137
|
+
* @module @yuva-devlab/events
|
|
138
|
+
*/
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* In-memory event bus with pattern matching, asynchronous execution, and fault isolation.
|
|
142
|
+
*/
|
|
143
|
+
declare class InMemoryEventBus implements IEventBus {
|
|
144
|
+
/** Map of event pattern to set of subscribed callback handlers */
|
|
145
|
+
private readonly subscribers;
|
|
146
|
+
/**
|
|
147
|
+
* Emits a single domain event envelope to all matching listeners.
|
|
148
|
+
*
|
|
149
|
+
* @param event - The validated event envelope.
|
|
150
|
+
*/
|
|
151
|
+
publish(event: DomainEventEnvelope): Promise<void>;
|
|
152
|
+
/**
|
|
153
|
+
* Emits an array of domain events sequentially or concurrently.
|
|
154
|
+
*
|
|
155
|
+
* @param events - List of event envelopes to publish.
|
|
156
|
+
*/
|
|
157
|
+
publishBatch(events: DomainEventEnvelope[]): Promise<void>;
|
|
158
|
+
/**
|
|
159
|
+
* Registers a listener for an exact event type or wildcard pattern (*, domain.*).
|
|
160
|
+
*
|
|
161
|
+
* @param eventPattern - Topic pattern to subscribe to.
|
|
162
|
+
* @param handler - Asynchronous callback handler.
|
|
163
|
+
* @returns Unsubscribe handle.
|
|
164
|
+
*/
|
|
165
|
+
subscribe(eventPattern: string, handler: EventHandler): EventSubscription;
|
|
166
|
+
/**
|
|
167
|
+
* Clears all active subscribers from memory.
|
|
168
|
+
*/
|
|
169
|
+
clear(): void;
|
|
170
|
+
/**
|
|
171
|
+
* Resolves all handlers matching the given concrete event type.
|
|
172
|
+
*
|
|
173
|
+
* @param concreteType - The incoming eventType string.
|
|
174
|
+
* @returns Array of unique matching handlers.
|
|
175
|
+
*/
|
|
176
|
+
private getMatchingHandlers;
|
|
177
|
+
/**
|
|
178
|
+
* Evaluates if a concrete event type matches a subscription pattern.
|
|
179
|
+
* Supports global wildcard "*" and prefix wildcards "prefix.*".
|
|
180
|
+
*
|
|
181
|
+
* @param pattern - Registered pattern.
|
|
182
|
+
* @param target - Concrete event type.
|
|
183
|
+
* @returns True if matched.
|
|
184
|
+
*/
|
|
185
|
+
private matchesPattern;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* @file packages/events/src/outbox/outbox-record.ts
|
|
190
|
+
* @description Outbox table record model and validation schema for the Transactional Outbox pattern.
|
|
191
|
+
* @module @yuva-devlab/events
|
|
192
|
+
*/
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Lifecycle status of an outbox record awaiting dispatch.
|
|
196
|
+
*/
|
|
197
|
+
declare const OutboxStatus: {
|
|
198
|
+
readonly PENDING: "PENDING";
|
|
199
|
+
readonly PROCESSING: "PROCESSING";
|
|
200
|
+
readonly PUBLISHED: "PUBLISHED";
|
|
201
|
+
readonly FAILED: "FAILED";
|
|
202
|
+
};
|
|
203
|
+
type OutboxStatus = (typeof OutboxStatus)[keyof typeof OutboxStatus];
|
|
204
|
+
/**
|
|
205
|
+
* Zod schema validating a persisted outbox record.
|
|
206
|
+
*/
|
|
207
|
+
declare const OutboxRecordSchema: z.ZodObject<{
|
|
208
|
+
id: z.ZodString;
|
|
209
|
+
envelope: z.ZodObject<{
|
|
210
|
+
eventId: z.ZodString;
|
|
211
|
+
eventType: z.ZodString;
|
|
212
|
+
executionId: z.ZodOptional<z.ZodString>;
|
|
213
|
+
tenantId: z.ZodOptional<z.ZodString>;
|
|
214
|
+
traceId: z.ZodOptional<z.ZodString>;
|
|
215
|
+
timestamp: z.ZodDefault<z.ZodString>;
|
|
216
|
+
payload: z.ZodRecord<z.ZodString, z.ZodUnknown>;
|
|
217
|
+
}, "strip", z.ZodTypeAny, {
|
|
218
|
+
eventId: string;
|
|
219
|
+
eventType: string;
|
|
220
|
+
timestamp: string;
|
|
221
|
+
payload: Record<string, unknown>;
|
|
222
|
+
executionId?: string | undefined;
|
|
223
|
+
tenantId?: string | undefined;
|
|
224
|
+
traceId?: string | undefined;
|
|
225
|
+
}, {
|
|
226
|
+
eventId: string;
|
|
227
|
+
eventType: string;
|
|
228
|
+
payload: Record<string, unknown>;
|
|
229
|
+
executionId?: string | undefined;
|
|
230
|
+
tenantId?: string | undefined;
|
|
231
|
+
traceId?: string | undefined;
|
|
232
|
+
timestamp?: string | undefined;
|
|
233
|
+
}>;
|
|
234
|
+
status: z.ZodEnum<["PENDING", "PROCESSING", "PUBLISHED", "FAILED"]>;
|
|
235
|
+
attempts: z.ZodDefault<z.ZodNumber>;
|
|
236
|
+
maxAttempts: z.ZodDefault<z.ZodNumber>;
|
|
237
|
+
lastError: z.ZodOptional<z.ZodString>;
|
|
238
|
+
createdAt: z.ZodString;
|
|
239
|
+
updatedAt: z.ZodString;
|
|
240
|
+
publishedAt: z.ZodOptional<z.ZodString>;
|
|
241
|
+
}, "strip", z.ZodTypeAny, {
|
|
242
|
+
status: "PENDING" | "PROCESSING" | "PUBLISHED" | "FAILED";
|
|
243
|
+
id: string;
|
|
244
|
+
envelope: {
|
|
245
|
+
eventId: string;
|
|
246
|
+
eventType: string;
|
|
247
|
+
timestamp: string;
|
|
248
|
+
payload: Record<string, unknown>;
|
|
249
|
+
executionId?: string | undefined;
|
|
250
|
+
tenantId?: string | undefined;
|
|
251
|
+
traceId?: string | undefined;
|
|
252
|
+
};
|
|
253
|
+
attempts: number;
|
|
254
|
+
maxAttempts: number;
|
|
255
|
+
createdAt: string;
|
|
256
|
+
updatedAt: string;
|
|
257
|
+
lastError?: string | undefined;
|
|
258
|
+
publishedAt?: string | undefined;
|
|
259
|
+
}, {
|
|
260
|
+
status: "PENDING" | "PROCESSING" | "PUBLISHED" | "FAILED";
|
|
261
|
+
id: string;
|
|
262
|
+
envelope: {
|
|
263
|
+
eventId: string;
|
|
264
|
+
eventType: string;
|
|
265
|
+
payload: Record<string, unknown>;
|
|
266
|
+
executionId?: string | undefined;
|
|
267
|
+
tenantId?: string | undefined;
|
|
268
|
+
traceId?: string | undefined;
|
|
269
|
+
timestamp?: string | undefined;
|
|
270
|
+
};
|
|
271
|
+
createdAt: string;
|
|
272
|
+
updatedAt: string;
|
|
273
|
+
attempts?: number | undefined;
|
|
274
|
+
maxAttempts?: number | undefined;
|
|
275
|
+
lastError?: string | undefined;
|
|
276
|
+
publishedAt?: string | undefined;
|
|
277
|
+
}>;
|
|
278
|
+
type OutboxRecord = z.infer<typeof OutboxRecordSchema>;
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* @file packages/events/src/outbox/outbox-store.interface.ts
|
|
282
|
+
* @description Storage contract for transactional outbox persistence and status updates.
|
|
283
|
+
* @module @yuva-devlab/events
|
|
284
|
+
*/
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Storage contract implemented by relational or KV databases for outbox buffering.
|
|
288
|
+
*/
|
|
289
|
+
interface IOutboxStore {
|
|
290
|
+
/**
|
|
291
|
+
* Persists a domain event inside an existing database transaction or atomically.
|
|
292
|
+
*
|
|
293
|
+
* @param envelope - Domain event envelope to queue for publication.
|
|
294
|
+
* @returns Persisted outbox record.
|
|
295
|
+
*/
|
|
296
|
+
save(envelope: DomainEventEnvelope): Promise<OutboxRecord>;
|
|
297
|
+
/**
|
|
298
|
+
* Retrieves a batch of pending outbox records ready for dispatch.
|
|
299
|
+
*
|
|
300
|
+
* @param limit - Maximum number of records to retrieve in a single polling tick.
|
|
301
|
+
* @returns Array of pending outbox records.
|
|
302
|
+
*/
|
|
303
|
+
fetchPending(limit: number): Promise<OutboxRecord[]>;
|
|
304
|
+
/**
|
|
305
|
+
* Marks a record as successfully published.
|
|
306
|
+
*
|
|
307
|
+
* @param recordId - Unique identifier of the outbox entry.
|
|
308
|
+
*/
|
|
309
|
+
markPublished(recordId: string): Promise<void>;
|
|
310
|
+
/**
|
|
311
|
+
* Records a dispatch failure and increments retry attempts.
|
|
312
|
+
*
|
|
313
|
+
* @param recordId - Unique identifier of the outbox entry.
|
|
314
|
+
* @param error - Error description message.
|
|
315
|
+
*/
|
|
316
|
+
markFailed(recordId: string, error: string): Promise<void>;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
/**
|
|
320
|
+
* @file packages/events/src/outbox/outbox-relay.ts
|
|
321
|
+
* @description Background polling relay engine delivering transactional outbox events to the event bus.
|
|
322
|
+
* @module @yuva-devlab/events
|
|
323
|
+
*/
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Configuration options for the background outbox dispatch relay.
|
|
327
|
+
*/
|
|
328
|
+
interface OutboxRelayOptions {
|
|
329
|
+
/** Polling interval in milliseconds (default: 1000ms) */
|
|
330
|
+
pollIntervalMs?: number;
|
|
331
|
+
/** Max records to drain in each tick (default: 50) */
|
|
332
|
+
batchSize?: number;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Background poller ensuring guaranteed at-least-once delivery of outbox records.
|
|
336
|
+
*/
|
|
337
|
+
declare class OutboxRelay {
|
|
338
|
+
private readonly store;
|
|
339
|
+
private readonly publisher;
|
|
340
|
+
private isRunning;
|
|
341
|
+
private timer;
|
|
342
|
+
private readonly pollIntervalMs;
|
|
343
|
+
private readonly batchSize;
|
|
344
|
+
constructor(store: IOutboxStore, publisher: IEventPublisher, options?: OutboxRelayOptions);
|
|
345
|
+
/**
|
|
346
|
+
* Starts the background relay polling loop.
|
|
347
|
+
*/
|
|
348
|
+
start(): void;
|
|
349
|
+
/**
|
|
350
|
+
* Stops the background relay polling loop.
|
|
351
|
+
*/
|
|
352
|
+
stop(): void;
|
|
353
|
+
/**
|
|
354
|
+
* Executes a single polling tick, draining pending outbox records.
|
|
355
|
+
*
|
|
356
|
+
* @returns Number of events successfully processed during this tick.
|
|
357
|
+
*/
|
|
358
|
+
drainOnce(): Promise<number>;
|
|
359
|
+
/**
|
|
360
|
+
* Schedules the next execution tick with timer guard.
|
|
361
|
+
*/
|
|
362
|
+
private scheduleNextTick;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
/**
|
|
366
|
+
* @file packages/events/src/idempotency/idempotency-store.interface.ts
|
|
367
|
+
* @description Contract for distributed idempotency stores preventing duplicate event processing.
|
|
368
|
+
* @module @yuva-devlab/events
|
|
369
|
+
*/
|
|
370
|
+
/**
|
|
371
|
+
* Result returned when attempting to acquire an idempotency lock for an event key.
|
|
372
|
+
*/
|
|
373
|
+
type IdempotencyAcquireResult = {
|
|
374
|
+
state: "ACQUIRED";
|
|
375
|
+
} | {
|
|
376
|
+
state: "ALREADY_COMPLETED";
|
|
377
|
+
completedAt: string;
|
|
378
|
+
} | {
|
|
379
|
+
state: "IN_FLIGHT";
|
|
380
|
+
};
|
|
381
|
+
/**
|
|
382
|
+
* Interface implemented by Redis, memory, or database idempotency backends.
|
|
383
|
+
*/
|
|
384
|
+
interface IIdempotencyStore {
|
|
385
|
+
/**
|
|
386
|
+
* Attempts to acquire an execution lock for a given idempotency key.
|
|
387
|
+
*
|
|
388
|
+
* @param key - The unique event or transaction key.
|
|
389
|
+
* @param ttlSeconds - Lock TTL in seconds.
|
|
390
|
+
* @returns Result indicating whether the lock was acquired, in-flight, or already completed.
|
|
391
|
+
*/
|
|
392
|
+
acquire(key: string, ttlSeconds?: number): Promise<IdempotencyAcquireResult>;
|
|
393
|
+
/**
|
|
394
|
+
* Marks the operation as successfully finished with a retention TTL.
|
|
395
|
+
*
|
|
396
|
+
* @param key - The idempotency key.
|
|
397
|
+
* @param retentionSeconds - How long to retain the completed state (default: 86400s / 24h).
|
|
398
|
+
*/
|
|
399
|
+
markCompleted(key: string, retentionSeconds?: number): Promise<void>;
|
|
400
|
+
/**
|
|
401
|
+
* Releases an in-flight lock, typically on unexpected processing error to allow retry.
|
|
402
|
+
*
|
|
403
|
+
* @param key - The idempotency key to release.
|
|
404
|
+
*/
|
|
405
|
+
release(key: string): Promise<void>;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* @file packages/events/src/idempotency/in-memory-idempotency-store.ts
|
|
410
|
+
* @description In-memory TTL idempotency store implementation for testing and single-node services.
|
|
411
|
+
* @module @yuva-devlab/events
|
|
412
|
+
*/
|
|
413
|
+
|
|
414
|
+
/**
|
|
415
|
+
* Single-process in-memory idempotency store with active expiration.
|
|
416
|
+
*/
|
|
417
|
+
declare class InMemoryIdempotencyStore implements IIdempotencyStore {
|
|
418
|
+
private readonly records;
|
|
419
|
+
acquire(key: string, ttlSeconds?: number): Promise<IdempotencyAcquireResult>;
|
|
420
|
+
markCompleted(key: string, retentionSeconds?: number): Promise<void>;
|
|
421
|
+
release(key: string): Promise<void>;
|
|
422
|
+
private cleanExpired;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
export { type CreateEventEnvelopeOptions, type DomainEventEnvelope, DomainEventEnvelopeSchema, type EventHandler, type EventSubscription, type IEventBus, type IEventPublisher, type IEventSubscriber, type IIdempotencyStore, type IOutboxStore, type IdempotencyAcquireResult, InMemoryEventBus, InMemoryIdempotencyStore, type OutboxRecord, OutboxRecordSchema, OutboxRelay, type OutboxRelayOptions, OutboxStatus, UuidSchema, createEventEnvelope };
|