@emmett-community/emmett-google-pubsub 0.1.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/README.md +438 -0
- package/dist/index.d.mts +413 -0
- package/dist/index.d.ts +413 -0
- package/dist/index.js +802 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +778 -0
- package/dist/index.mjs.map +1 -0
- package/dist/testing/index.d.mts +2 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +4 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/testing/index.mjs +3 -0
- package/dist/testing/index.mjs.map +1 -0
- package/package.json +94 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,413 @@
|
|
|
1
|
+
import { PubSub, Topic, Subscription, Message as Message$1 } from '@google-cloud/pubsub';
|
|
2
|
+
import { Message, SingleMessageHandler, Command, Event, SingleRawMessageHandlerWithoutContext, AnyMessage, MessageBus, EventSubscription, CommandProcessor, ScheduledMessageProcessor } from '@event-driven-io/emmett';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Configuration for PubSub MessageBus
|
|
6
|
+
*/
|
|
7
|
+
interface PubSubMessageBusConfig {
|
|
8
|
+
/**
|
|
9
|
+
* Google Cloud PubSub client instance
|
|
10
|
+
*/
|
|
11
|
+
pubsub: PubSub;
|
|
12
|
+
/**
|
|
13
|
+
* Instance identifier for subscriptions (auto-generated if not provided)
|
|
14
|
+
*/
|
|
15
|
+
instanceId?: string;
|
|
16
|
+
/**
|
|
17
|
+
* Topic/subscription name prefix
|
|
18
|
+
* @default "emmett"
|
|
19
|
+
*/
|
|
20
|
+
topicPrefix?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Enable emulator mode (disables Cloud Scheduler features)
|
|
23
|
+
* @default false
|
|
24
|
+
*/
|
|
25
|
+
useEmulator?: boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Subscription configuration options
|
|
28
|
+
*/
|
|
29
|
+
subscriptionOptions?: SubscriptionOptions;
|
|
30
|
+
/**
|
|
31
|
+
* Auto-create topics/subscriptions
|
|
32
|
+
* @default true
|
|
33
|
+
*/
|
|
34
|
+
autoCreateResources?: boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Cleanup subscriptions on close
|
|
37
|
+
* @default false
|
|
38
|
+
*/
|
|
39
|
+
cleanupOnClose?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Close the PubSub client on close
|
|
42
|
+
* Set to false if you want to reuse the client (e.g., in tests)
|
|
43
|
+
* @default true
|
|
44
|
+
*/
|
|
45
|
+
closePubSubClient?: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Subscription configuration options
|
|
49
|
+
*/
|
|
50
|
+
interface SubscriptionOptions {
|
|
51
|
+
/**
|
|
52
|
+
* Acknowledgment deadline in seconds
|
|
53
|
+
* @default 60
|
|
54
|
+
*/
|
|
55
|
+
ackDeadlineSeconds?: number;
|
|
56
|
+
/**
|
|
57
|
+
* Retry policy for failed messages
|
|
58
|
+
*/
|
|
59
|
+
retryPolicy?: {
|
|
60
|
+
minimumBackoff?: {
|
|
61
|
+
seconds: number;
|
|
62
|
+
};
|
|
63
|
+
maximumBackoff?: {
|
|
64
|
+
seconds: number;
|
|
65
|
+
};
|
|
66
|
+
};
|
|
67
|
+
/**
|
|
68
|
+
* Dead letter policy
|
|
69
|
+
*/
|
|
70
|
+
deadLetterPolicy?: {
|
|
71
|
+
deadLetterTopic?: string;
|
|
72
|
+
maxDeliveryAttempts?: number;
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Message envelope for PubSub transport
|
|
77
|
+
*/
|
|
78
|
+
interface PubSubMessageEnvelope {
|
|
79
|
+
/**
|
|
80
|
+
* Message type (e.g., "AddProductItem")
|
|
81
|
+
*/
|
|
82
|
+
type: string;
|
|
83
|
+
/**
|
|
84
|
+
* Message kind (command or event)
|
|
85
|
+
*/
|
|
86
|
+
kind: 'command' | 'event';
|
|
87
|
+
/**
|
|
88
|
+
* Serialized message data
|
|
89
|
+
*/
|
|
90
|
+
data: unknown;
|
|
91
|
+
/**
|
|
92
|
+
* Serialized message metadata
|
|
93
|
+
*/
|
|
94
|
+
metadata?: unknown;
|
|
95
|
+
/**
|
|
96
|
+
* ISO 8601 timestamp
|
|
97
|
+
*/
|
|
98
|
+
timestamp: string;
|
|
99
|
+
/**
|
|
100
|
+
* UUID for idempotency
|
|
101
|
+
*/
|
|
102
|
+
messageId: string;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Internal handler registration
|
|
106
|
+
*/
|
|
107
|
+
interface HandlerRegistration<T extends Message = Message> {
|
|
108
|
+
id: string;
|
|
109
|
+
handler: SingleMessageHandler<T>;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Subscription information
|
|
113
|
+
*/
|
|
114
|
+
interface SubscriptionInfo {
|
|
115
|
+
topic: Topic;
|
|
116
|
+
subscription: Subscription;
|
|
117
|
+
messageType: string;
|
|
118
|
+
kind: 'command' | 'event';
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Scheduled message with timing information
|
|
122
|
+
*/
|
|
123
|
+
interface ScheduledMessageInfo {
|
|
124
|
+
message: Message;
|
|
125
|
+
options?: {
|
|
126
|
+
afterInMs: number;
|
|
127
|
+
} | {
|
|
128
|
+
at: Date;
|
|
129
|
+
};
|
|
130
|
+
scheduledAt: Date;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* PubSub message bus lifecycle
|
|
134
|
+
*/
|
|
135
|
+
interface PubSubMessageBusLifecycle {
|
|
136
|
+
/**
|
|
137
|
+
* Start the message bus (create topics/subscriptions and start listening)
|
|
138
|
+
*/
|
|
139
|
+
start(): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Close the message bus gracefully
|
|
142
|
+
*/
|
|
143
|
+
close(): Promise<void>;
|
|
144
|
+
/**
|
|
145
|
+
* Check if the message bus is started
|
|
146
|
+
*/
|
|
147
|
+
isStarted(): boolean;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Serialize a Command or Event to a Buffer for PubSub transport
|
|
152
|
+
*
|
|
153
|
+
* @param message - The message to serialize
|
|
154
|
+
* @returns Buffer containing the serialized message envelope
|
|
155
|
+
*/
|
|
156
|
+
declare function serialize(message: Command | Event): Buffer;
|
|
157
|
+
/**
|
|
158
|
+
* Deserialize a Buffer from PubSub into a Command or Event
|
|
159
|
+
*
|
|
160
|
+
* @param buffer - The buffer containing the serialized message
|
|
161
|
+
* @returns The deserialized message
|
|
162
|
+
* @throws Error if the buffer cannot be deserialized
|
|
163
|
+
*/
|
|
164
|
+
declare function deserialize<T extends Command | Event>(buffer: Buffer): T;
|
|
165
|
+
/**
|
|
166
|
+
* Attach a message ID to a message for idempotency tracking
|
|
167
|
+
*
|
|
168
|
+
* @param message - The message to attach ID to
|
|
169
|
+
* @param messageId - The message ID
|
|
170
|
+
* @returns The message with the ID attached
|
|
171
|
+
*/
|
|
172
|
+
declare function attachMessageId<T extends Message>(message: T, messageId: string): T & {
|
|
173
|
+
__messageId: string;
|
|
174
|
+
};
|
|
175
|
+
/**
|
|
176
|
+
* Extract message ID from a message
|
|
177
|
+
*
|
|
178
|
+
* @param message - The message to extract ID from
|
|
179
|
+
* @returns The message ID if present, undefined otherwise
|
|
180
|
+
*/
|
|
181
|
+
declare function extractMessageId(message: Message): string | undefined;
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* Get command topic name
|
|
185
|
+
*/
|
|
186
|
+
declare function getCommandTopicName(commandType: string, prefix?: string): string;
|
|
187
|
+
/**
|
|
188
|
+
* Get event topic name
|
|
189
|
+
*/
|
|
190
|
+
declare function getEventTopicName(eventType: string, prefix?: string): string;
|
|
191
|
+
/**
|
|
192
|
+
* Get command subscription name
|
|
193
|
+
*/
|
|
194
|
+
declare function getCommandSubscriptionName(commandType: string, instanceId: string, prefix?: string): string;
|
|
195
|
+
/**
|
|
196
|
+
* Get event subscription name
|
|
197
|
+
*/
|
|
198
|
+
declare function getEventSubscriptionName(eventType: string, subscriptionId: string, prefix?: string): string;
|
|
199
|
+
/**
|
|
200
|
+
* Get or create a topic
|
|
201
|
+
*
|
|
202
|
+
* @param pubsub - PubSub client
|
|
203
|
+
* @param topicName - Name of the topic
|
|
204
|
+
* @returns The topic instance
|
|
205
|
+
*/
|
|
206
|
+
declare function getOrCreateTopic(pubsub: PubSub, topicName: string): Promise<Topic>;
|
|
207
|
+
/**
|
|
208
|
+
* Get or create a subscription
|
|
209
|
+
*
|
|
210
|
+
* @param topic - The topic to subscribe to
|
|
211
|
+
* @param subscriptionName - Name of the subscription
|
|
212
|
+
* @param options - Subscription options
|
|
213
|
+
* @returns The subscription instance
|
|
214
|
+
*/
|
|
215
|
+
declare function getOrCreateSubscription(topic: Topic, subscriptionName: string, options?: SubscriptionOptions): Promise<Subscription>;
|
|
216
|
+
/**
|
|
217
|
+
* Delete a subscription
|
|
218
|
+
*
|
|
219
|
+
* @param subscription - The subscription to delete
|
|
220
|
+
*/
|
|
221
|
+
declare function deleteSubscription(subscription: Subscription): Promise<void>;
|
|
222
|
+
/**
|
|
223
|
+
* Delete multiple subscriptions
|
|
224
|
+
*
|
|
225
|
+
* @param subscriptions - Array of subscriptions to delete
|
|
226
|
+
*/
|
|
227
|
+
declare function deleteSubscriptions(subscriptions: Subscription[]): Promise<void>;
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Generate a random UUID
|
|
231
|
+
*/
|
|
232
|
+
declare function generateUUID(): string;
|
|
233
|
+
/**
|
|
234
|
+
* Validate that a string is not empty
|
|
235
|
+
*/
|
|
236
|
+
declare function assertNotEmptyString(value: unknown, name: string): asserts value is string;
|
|
237
|
+
/**
|
|
238
|
+
* Validate that a number is positive
|
|
239
|
+
*/
|
|
240
|
+
declare function assertPositiveNumber(value: unknown, name: string): asserts value is number;
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Schedule options for messages
|
|
244
|
+
*/
|
|
245
|
+
type ScheduleOptions = {
|
|
246
|
+
afterInMs: number;
|
|
247
|
+
} | {
|
|
248
|
+
at: Date;
|
|
249
|
+
};
|
|
250
|
+
/**
|
|
251
|
+
* Scheduled message returned from dequeue
|
|
252
|
+
*/
|
|
253
|
+
interface ScheduledMessage {
|
|
254
|
+
message: Message;
|
|
255
|
+
options?: ScheduleOptions;
|
|
256
|
+
}
|
|
257
|
+
/**
|
|
258
|
+
* Scheduler configuration
|
|
259
|
+
*/
|
|
260
|
+
interface SchedulerConfig {
|
|
261
|
+
/**
|
|
262
|
+
* Whether running in emulator mode
|
|
263
|
+
*/
|
|
264
|
+
useEmulator: boolean;
|
|
265
|
+
/**
|
|
266
|
+
* PubSub client instance
|
|
267
|
+
*/
|
|
268
|
+
pubsub: PubSub;
|
|
269
|
+
/**
|
|
270
|
+
* Topic for scheduled messages (optional, created if needed)
|
|
271
|
+
*/
|
|
272
|
+
scheduledTopic?: Topic;
|
|
273
|
+
/**
|
|
274
|
+
* Topic prefix for naming
|
|
275
|
+
* @default "emmett"
|
|
276
|
+
*/
|
|
277
|
+
topicPrefix?: string;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
* Calculate scheduled time from options
|
|
281
|
+
*
|
|
282
|
+
* @param options - Schedule options (afterInMs or at)
|
|
283
|
+
* @returns The calculated scheduled time
|
|
284
|
+
*/
|
|
285
|
+
declare function calculateScheduledTime(options?: ScheduleOptions): Date;
|
|
286
|
+
/**
|
|
287
|
+
* Filter messages that are ready for delivery
|
|
288
|
+
*
|
|
289
|
+
* @param pending - Array of pending scheduled messages
|
|
290
|
+
* @param now - Current time
|
|
291
|
+
* @returns Messages ready for delivery
|
|
292
|
+
*/
|
|
293
|
+
declare function filterReadyMessages(pending: ScheduledMessageInfo[], now: Date): ScheduledMessageInfo[];
|
|
294
|
+
/**
|
|
295
|
+
* Message scheduler with dual mode support (production/emulator)
|
|
296
|
+
*/
|
|
297
|
+
declare class MessageScheduler {
|
|
298
|
+
private pendingMessages;
|
|
299
|
+
private readonly useEmulator;
|
|
300
|
+
private readonly pubsub;
|
|
301
|
+
private readonly topicPrefix;
|
|
302
|
+
private scheduledTopic?;
|
|
303
|
+
constructor(config: SchedulerConfig);
|
|
304
|
+
/**
|
|
305
|
+
* Schedule a message for future delivery
|
|
306
|
+
*
|
|
307
|
+
* In production mode: Publishes to PubSub with publishTime attribute
|
|
308
|
+
* In emulator mode: Stores in memory for later dequeue (emulator doesn't support scheduling)
|
|
309
|
+
*
|
|
310
|
+
* @param message - The message to schedule
|
|
311
|
+
* @param options - When to deliver the message
|
|
312
|
+
*/
|
|
313
|
+
schedule(message: Message, options?: ScheduleOptions): Promise<void>;
|
|
314
|
+
/**
|
|
315
|
+
* Dequeue ready scheduled messages (emulator mode only)
|
|
316
|
+
*
|
|
317
|
+
* Returns messages whose scheduled time has passed and removes them from pending queue
|
|
318
|
+
*
|
|
319
|
+
* @returns Array of scheduled messages ready for delivery
|
|
320
|
+
*/
|
|
321
|
+
dequeue(): ScheduledMessage[];
|
|
322
|
+
/**
|
|
323
|
+
* Publish a scheduled message to PubSub (production mode)
|
|
324
|
+
*
|
|
325
|
+
* @param message - The message to publish
|
|
326
|
+
* @param scheduledAt - When the message should be delivered
|
|
327
|
+
*/
|
|
328
|
+
private publishScheduledMessage;
|
|
329
|
+
/**
|
|
330
|
+
* Get count of pending scheduled messages (emulator mode only)
|
|
331
|
+
*
|
|
332
|
+
* @returns Number of pending scheduled messages
|
|
333
|
+
*/
|
|
334
|
+
getPendingCount(): number;
|
|
335
|
+
/**
|
|
336
|
+
* Clear all pending scheduled messages (emulator mode only, useful for testing)
|
|
337
|
+
*/
|
|
338
|
+
clearPending(): void;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Determine if an error should trigger a retry (nack) or be considered permanent (ack)
|
|
343
|
+
*
|
|
344
|
+
* @param error - The error to classify
|
|
345
|
+
* @returns true if the error is retriable (should nack), false if permanent (should ack)
|
|
346
|
+
*/
|
|
347
|
+
declare function shouldRetry(error: unknown): boolean;
|
|
348
|
+
/**
|
|
349
|
+
* Process an incoming command message from PubSub
|
|
350
|
+
*
|
|
351
|
+
* @param message - The PubSub message
|
|
352
|
+
* @param handlers - Map of message type to handlers
|
|
353
|
+
* @param commandType - The command type being processed
|
|
354
|
+
* @returns 'ack' if successful or permanent failure, 'nack' if retriable failure
|
|
355
|
+
*/
|
|
356
|
+
declare function handleCommandMessage(message: Message$1, handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>, commandType: string): Promise<'ack' | 'nack'>;
|
|
357
|
+
/**
|
|
358
|
+
* Process an incoming event message from PubSub
|
|
359
|
+
*
|
|
360
|
+
* @param message - The PubSub message
|
|
361
|
+
* @param handlers - Map of message type to handlers
|
|
362
|
+
* @param eventType - The event type being processed
|
|
363
|
+
* @returns 'ack' if all handlers successful or permanent failure, 'nack' if retriable failure
|
|
364
|
+
*/
|
|
365
|
+
declare function handleEventMessage(message: Message$1, handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>, eventType: string): Promise<'ack' | 'nack'>;
|
|
366
|
+
/**
|
|
367
|
+
* Create a message listener for a PubSub subscription
|
|
368
|
+
*
|
|
369
|
+
* @param subscription - The PubSub subscription to listen on
|
|
370
|
+
* @param messageType - The message type (command or event type)
|
|
371
|
+
* @param kind - Whether this is a command or event
|
|
372
|
+
* @param handlers - Map of message type to handlers
|
|
373
|
+
*/
|
|
374
|
+
declare function createMessageListener(subscription: Subscription, messageType: string, kind: 'command' | 'event', handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>): void;
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Create a Google Cloud Pub/Sub based message bus for Emmett
|
|
378
|
+
*
|
|
379
|
+
* @param config - Configuration for the PubSub message bus
|
|
380
|
+
* @returns A message bus implementation using Google Cloud Pub/Sub
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* ```typescript
|
|
384
|
+
* import { PubSub } from '@google-cloud/pubsub';
|
|
385
|
+
* import { getPubSubMessageBus } from '@emmett-community/emmett-google-pubsub';
|
|
386
|
+
*
|
|
387
|
+
* const pubsub = new PubSub({ projectId: 'my-project' });
|
|
388
|
+
* const messageBus = getPubSubMessageBus({ pubsub });
|
|
389
|
+
*
|
|
390
|
+
* // Register handlers
|
|
391
|
+
* messageBus.handle(async (command) => {
|
|
392
|
+
* // Handle command
|
|
393
|
+
* }, 'MyCommand');
|
|
394
|
+
*
|
|
395
|
+
* // Subscribe to events
|
|
396
|
+
* messageBus.subscribe(async (event) => {
|
|
397
|
+
* // Handle event
|
|
398
|
+
* }, 'MyEvent');
|
|
399
|
+
*
|
|
400
|
+
* // Start the message bus
|
|
401
|
+
* await messageBus.start();
|
|
402
|
+
*
|
|
403
|
+
* // Send commands and publish events
|
|
404
|
+
* await messageBus.send({ type: 'MyCommand', data: { ... } });
|
|
405
|
+
* await messageBus.publish({ type: 'MyEvent', data: { ... } });
|
|
406
|
+
*
|
|
407
|
+
* // Close gracefully
|
|
408
|
+
* await messageBus.close();
|
|
409
|
+
* ```
|
|
410
|
+
*/
|
|
411
|
+
declare function getPubSubMessageBus(config: PubSubMessageBusConfig): MessageBus & EventSubscription & CommandProcessor & ScheduledMessageProcessor & PubSubMessageBusLifecycle;
|
|
412
|
+
|
|
413
|
+
export { type HandlerRegistration, MessageScheduler, type PubSubMessageBusConfig, type PubSubMessageBusLifecycle, type PubSubMessageEnvelope, type ScheduleOptions, type ScheduledMessage, type ScheduledMessageInfo, type SchedulerConfig, type SubscriptionInfo, type SubscriptionOptions, assertNotEmptyString, assertPositiveNumber, attachMessageId, calculateScheduledTime, createMessageListener, deleteSubscription, deleteSubscriptions, deserialize, extractMessageId, filterReadyMessages, generateUUID, getCommandSubscriptionName, getCommandTopicName, getEventSubscriptionName, getEventTopicName, getOrCreateSubscription, getOrCreateTopic, getPubSubMessageBus, handleCommandMessage, handleEventMessage, serialize, shouldRetry };
|