@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/messageBus/serialization.ts","../src/messageBus/topicManager.ts","../src/messageBus/utils.ts","../src/messageBus/scheduler.ts","../src/messageBus/messageHandler.ts","../src/messageBus/pubsubMessageBus.ts"],"names":["randomUUID","cryptoRandomUUID","EmmettError"],"mappings":"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","file":"index.js","sourcesContent":["import { randomUUID } from 'crypto';\nimport type { Command, Event, Message } from '@event-driven-io/emmett';\nimport type { PubSubMessageEnvelope } from './types';\n\n/**\n * Date marker for JSON serialization\n */\ninterface DateMarker {\n __type: 'Date';\n value: string;\n}\n\n/**\n * Recursively transform Dates to DateMarkers in an object\n */\nfunction transformDatesToMarkers(obj: unknown): unknown {\n if (obj instanceof Date) {\n return {\n __type: 'Date',\n value: obj.toISOString(),\n } satisfies DateMarker;\n }\n\n if (Array.isArray(obj)) {\n return obj.map(transformDatesToMarkers);\n }\n\n if (obj !== null && typeof obj === 'object') {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n result[key] = transformDatesToMarkers(value);\n }\n return result;\n }\n\n return obj;\n}\n\n/**\n * Check if a value is a Date marker\n */\nfunction isDateMarker(value: unknown): value is DateMarker {\n return (\n typeof value === 'object' &&\n value !== null &&\n '__type' in value &&\n (value as DateMarker).__type === 'Date' &&\n 'value' in value &&\n typeof (value as DateMarker).value === 'string'\n );\n}\n\n/**\n * JSON reviver that converts Date markers back to Dates\n */\nfunction dateReviver(_key: string, value: unknown): unknown {\n if (isDateMarker(value)) {\n return new Date(value.value);\n }\n return value;\n}\n\n/**\n * Determine if a message is a command or event based on its type\n */\nfunction getMessageKind(message: Message): 'command' | 'event' {\n // Simple heuristic: if the message type contains \"Command\", it's a command\n // Otherwise, it's an event\n // This can be customized based on your naming conventions\n const typeStr = message.type.toLowerCase();\n return typeStr.includes('command') ? 'command' : 'event';\n}\n\n/**\n * Serialize a Command or Event to a Buffer for PubSub transport\n *\n * @param message - The message to serialize\n * @returns Buffer containing the serialized message envelope\n */\nexport function serialize(message: Command | Event): Buffer {\n const envelope = {\n type: message.type,\n kind: getMessageKind(message),\n data: transformDatesToMarkers(message.data),\n metadata: 'metadata' in message ? transformDatesToMarkers(message.metadata) : undefined,\n timestamp: new Date().toISOString(),\n messageId: randomUUID(),\n };\n\n const json = JSON.stringify(envelope);\n return Buffer.from(json);\n}\n\n/**\n * Deserialize a Buffer from PubSub into a Command or Event\n *\n * @param buffer - The buffer containing the serialized message\n * @returns The deserialized message\n * @throws Error if the buffer cannot be deserialized\n */\nexport function deserialize<T extends Command | Event>(buffer: Buffer): T {\n try {\n const json = buffer.toString('utf-8');\n const envelope = JSON.parse(json, dateReviver) as PubSubMessageEnvelope;\n\n const message = {\n type: envelope.type,\n data: envelope.data,\n ...(envelope.metadata ? { metadata: envelope.metadata } : {}),\n } as Message;\n\n return message as T;\n } catch (error) {\n throw new Error(\n `Failed to deserialize message: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Attach a message ID to a message for idempotency tracking\n *\n * @param message - The message to attach ID to\n * @param messageId - The message ID\n * @returns The message with the ID attached\n */\nexport function attachMessageId<T extends Message>(\n message: T,\n messageId: string,\n): T & { __messageId: string } {\n return {\n ...message,\n __messageId: messageId,\n };\n}\n\n/**\n * Extract message ID from a message\n *\n * @param message - The message to extract ID from\n * @returns The message ID if present, undefined otherwise\n */\nexport function extractMessageId(message: Message): string | undefined {\n return '__messageId' in message\n ? (message as { __messageId: string }).__messageId\n : undefined;\n}\n","import type { PubSub, Subscription, Topic } from '@google-cloud/pubsub';\nimport type { SubscriptionOptions } from './types';\n\n/**\n * Get command topic name\n */\nexport function getCommandTopicName(\n commandType: string,\n prefix = 'emmett',\n): string {\n return `${prefix}-cmd-${commandType}`;\n}\n\n/**\n * Get event topic name\n */\nexport function getEventTopicName(eventType: string, prefix = 'emmett'): string {\n return `${prefix}-evt-${eventType}`;\n}\n\n/**\n * Get command subscription name\n */\nexport function getCommandSubscriptionName(\n commandType: string,\n instanceId: string,\n prefix = 'emmett',\n): string {\n return `${prefix}-cmd-${commandType}-${instanceId}`;\n}\n\n/**\n * Get event subscription name\n */\nexport function getEventSubscriptionName(\n eventType: string,\n subscriptionId: string,\n prefix = 'emmett',\n): string {\n return `${prefix}-evt-${eventType}-${subscriptionId}`;\n}\n\n/**\n * Get or create a topic\n *\n * @param pubsub - PubSub client\n * @param topicName - Name of the topic\n * @returns The topic instance\n */\nexport async function getOrCreateTopic(\n pubsub: PubSub,\n topicName: string,\n): Promise<Topic> {\n const topic = pubsub.topic(topicName);\n\n try {\n const [exists] = await topic.exists();\n\n if (!exists) {\n try {\n await topic.create();\n } catch (createError: any) {\n // Ignore ALREADY_EXISTS errors (race condition)\n if (createError.code !== 6) {\n throw createError;\n }\n }\n }\n\n return topic;\n } catch (error) {\n throw new Error(\n `Failed to get or create topic ${topicName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Get or create a subscription\n *\n * @param topic - The topic to subscribe to\n * @param subscriptionName - Name of the subscription\n * @param options - Subscription options\n * @returns The subscription instance\n */\nexport async function getOrCreateSubscription(\n topic: Topic,\n subscriptionName: string,\n options?: SubscriptionOptions,\n): Promise<Subscription> {\n const subscription = topic.subscription(subscriptionName);\n\n try {\n const [exists] = await subscription.exists();\n\n if (!exists) {\n const config = {\n ...(options?.ackDeadlineSeconds && {\n ackDeadlineSeconds: options.ackDeadlineSeconds,\n }),\n ...(options?.retryPolicy && {\n retryPolicy: {\n ...(options.retryPolicy.minimumBackoff && {\n minimumBackoff: options.retryPolicy.minimumBackoff,\n }),\n ...(options.retryPolicy.maximumBackoff && {\n maximumBackoff: options.retryPolicy.maximumBackoff,\n }),\n },\n }),\n ...(options?.deadLetterPolicy && {\n deadLetterPolicy: {\n ...(options.deadLetterPolicy.deadLetterTopic && {\n deadLetterTopic: options.deadLetterPolicy.deadLetterTopic,\n }),\n ...(options.deadLetterPolicy.maxDeliveryAttempts && {\n maxDeliveryAttempts: options.deadLetterPolicy.maxDeliveryAttempts,\n }),\n },\n }),\n };\n\n try {\n await subscription.create(config);\n } catch (createError: any) {\n // Ignore ALREADY_EXISTS errors (race condition)\n if (createError.code !== 6) {\n throw createError;\n }\n }\n }\n\n return subscription;\n } catch (error) {\n throw new Error(\n `Failed to get or create subscription ${subscriptionName}: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Delete a subscription\n *\n * @param subscription - The subscription to delete\n */\nexport async function deleteSubscription(\n subscription: Subscription,\n): Promise<void> {\n try {\n const [exists] = await subscription.exists();\n\n if (exists) {\n await subscription.delete();\n }\n } catch (error) {\n // Log but don't throw - cleanup is best effort\n console.warn(\n `Failed to delete subscription: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n}\n\n/**\n * Delete multiple subscriptions\n *\n * @param subscriptions - Array of subscriptions to delete\n */\nexport async function deleteSubscriptions(\n subscriptions: Subscription[],\n): Promise<void> {\n await Promise.all(subscriptions.map((sub) => deleteSubscription(sub)));\n}\n","import { randomUUID as cryptoRandomUUID } from 'crypto';\n\n/**\n * Generate a random UUID\n */\nexport function generateUUID(): string {\n return cryptoRandomUUID();\n}\n\n/**\n * Validate that a string is not empty\n */\nexport function assertNotEmptyString(\n value: unknown,\n name: string,\n): asserts value is string {\n if (typeof value !== 'string' || value.trim() === '') {\n throw new Error(`${name} must be a non-empty string`);\n }\n}\n\n/**\n * Validate that a number is positive\n */\nexport function assertPositiveNumber(\n value: unknown,\n name: string,\n): asserts value is number {\n if (typeof value !== 'number' || value <= 0 || Number.isNaN(value)) {\n throw new Error(`${name} must be a positive number`);\n }\n}\n","import type { PubSub, Topic } from '@google-cloud/pubsub';\nimport type { Message } from '@event-driven-io/emmett';\nimport type { ScheduledMessageInfo } from './types';\nimport { serialize } from './serialization';\n\n/**\n * Schedule options for messages\n */\nexport type ScheduleOptions = { afterInMs: number } | { at: Date };\n\n/**\n * Scheduled message returned from dequeue\n */\nexport interface ScheduledMessage {\n message: Message;\n options?: ScheduleOptions;\n}\n\n/**\n * Scheduler configuration\n */\nexport interface SchedulerConfig {\n /**\n * Whether running in emulator mode\n */\n useEmulator: boolean;\n\n /**\n * PubSub client instance\n */\n pubsub: PubSub;\n\n /**\n * Topic for scheduled messages (optional, created if needed)\n */\n scheduledTopic?: Topic;\n\n /**\n * Topic prefix for naming\n * @default \"emmett\"\n */\n topicPrefix?: string;\n}\n\n/**\n * Calculate scheduled time from options\n *\n * @param options - Schedule options (afterInMs or at)\n * @returns The calculated scheduled time\n */\nexport function calculateScheduledTime(options?: ScheduleOptions): Date {\n if (!options) {\n return new Date();\n }\n\n if ('afterInMs' in options) {\n const now = new Date();\n return new Date(now.getTime() + options.afterInMs);\n }\n\n if ('at' in options) {\n return options.at;\n }\n\n return new Date();\n}\n\n/**\n * Filter messages that are ready for delivery\n *\n * @param pending - Array of pending scheduled messages\n * @param now - Current time\n * @returns Messages ready for delivery\n */\nexport function filterReadyMessages(\n pending: ScheduledMessageInfo[],\n now: Date,\n): ScheduledMessageInfo[] {\n return pending.filter((msg) => msg.scheduledAt <= now);\n}\n\n/**\n * Message scheduler with dual mode support (production/emulator)\n */\nexport class MessageScheduler {\n private pendingMessages: ScheduledMessageInfo[] = [];\n private readonly useEmulator: boolean;\n private readonly pubsub: PubSub;\n private readonly topicPrefix: string;\n private scheduledTopic?: Topic;\n\n constructor(config: SchedulerConfig) {\n this.useEmulator = config.useEmulator;\n this.pubsub = config.pubsub;\n this.scheduledTopic = config.scheduledTopic;\n this.topicPrefix = config.topicPrefix ?? 'emmett';\n }\n\n /**\n * Schedule a message for future delivery\n *\n * In production mode: Publishes to PubSub with publishTime attribute\n * In emulator mode: Stores in memory for later dequeue (emulator doesn't support scheduling)\n *\n * @param message - The message to schedule\n * @param options - When to deliver the message\n */\n async schedule(message: Message, options?: ScheduleOptions): Promise<void> {\n const scheduledAt = calculateScheduledTime(options);\n\n if (this.useEmulator) {\n // Emulator mode: store in memory\n this.pendingMessages.push({\n message,\n options,\n scheduledAt,\n });\n } else {\n // Production mode: publish to PubSub with publishTime attribute\n await this.publishScheduledMessage(message, scheduledAt);\n }\n }\n\n /**\n * Dequeue ready scheduled messages (emulator mode only)\n *\n * Returns messages whose scheduled time has passed and removes them from pending queue\n *\n * @returns Array of scheduled messages ready for delivery\n */\n dequeue(): ScheduledMessage[] {\n if (!this.useEmulator) {\n // In production mode, PubSub handles scheduling, so dequeue returns empty\n return [];\n }\n\n const now = new Date();\n const ready = filterReadyMessages(this.pendingMessages, now);\n\n // Remove ready messages from pending queue\n this.pendingMessages = this.pendingMessages.filter(\n (msg) => msg.scheduledAt > now,\n );\n\n // Convert to ScheduledMessage format\n return ready.map((info) => ({\n message: info.message,\n options: info.options,\n }));\n }\n\n /**\n * Publish a scheduled message to PubSub (production mode)\n *\n * @param message - The message to publish\n * @param scheduledAt - When the message should be delivered\n */\n private async publishScheduledMessage(\n message: Message,\n scheduledAt: Date,\n ): Promise<void> {\n try {\n // Get or create the scheduled messages topic\n if (!this.scheduledTopic) {\n const topicName = `${this.topicPrefix}-scheduled-messages`;\n this.scheduledTopic = this.pubsub.topic(topicName);\n\n const [exists] = await this.scheduledTopic.exists();\n if (!exists) {\n await this.scheduledTopic.create();\n }\n }\n\n // Serialize the message\n const buffer = serialize(message);\n\n // Publish with custom attributes including publish time\n await this.scheduledTopic.publishMessage({\n data: buffer,\n attributes: {\n messageType: message.type,\n publishTime: scheduledAt.toISOString(),\n },\n });\n } catch (error) {\n throw new Error(\n `Failed to publish scheduled message ${message.type}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n\n /**\n * Get count of pending scheduled messages (emulator mode only)\n *\n * @returns Number of pending scheduled messages\n */\n getPendingCount(): number {\n return this.useEmulator ? this.pendingMessages.length : 0;\n }\n\n /**\n * Clear all pending scheduled messages (emulator mode only, useful for testing)\n */\n clearPending(): void {\n if (this.useEmulator) {\n this.pendingMessages = [];\n }\n }\n}\n","import type { Message as PubSubMessage, Subscription } from '@google-cloud/pubsub';\nimport type {\n AnyMessage,\n Command,\n Event,\n SingleRawMessageHandlerWithoutContext,\n} from '@event-driven-io/emmett';\nimport { EmmettError } from '@event-driven-io/emmett';\nimport { deserialize } from './serialization';\n\n/**\n * Determine if an error should trigger a retry (nack) or be considered permanent (ack)\n *\n * @param error - The error to classify\n * @returns true if the error is retriable (should nack), false if permanent (should ack)\n */\nexport function shouldRetry(error: unknown): boolean {\n if (!(error instanceof Error)) {\n // Unknown error types - retry to be safe\n return true;\n }\n\n const errorMessage = error.message.toLowerCase();\n\n // Network/timeout errors - retry\n if (\n errorMessage.includes('network') ||\n errorMessage.includes('timeout') ||\n errorMessage.includes('econnrefused') ||\n errorMessage.includes('enotfound') ||\n errorMessage.includes('unavailable')\n ) {\n return true;\n }\n\n // EmmettError and validation errors - don't retry (business logic errors)\n if (error instanceof EmmettError) {\n return false;\n }\n\n if (\n errorMessage.includes('validation') ||\n errorMessage.includes('invalid') ||\n errorMessage.includes('not found') ||\n errorMessage.includes('already exists')\n ) {\n return false;\n }\n\n // Default to retry for unknown errors\n return true;\n}\n\n/**\n * Process an incoming command message from PubSub\n *\n * @param message - The PubSub message\n * @param handlers - Map of message type to handlers\n * @param commandType - The command type being processed\n * @returns 'ack' if successful or permanent failure, 'nack' if retriable failure\n */\nexport async function handleCommandMessage(\n message: PubSubMessage,\n handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>,\n commandType: string,\n): Promise<'ack' | 'nack'> {\n try {\n // Get handlers for this command type\n const commandHandlers = handlers.get(commandType);\n\n if (!commandHandlers || commandHandlers.length === 0) {\n throw new EmmettError(\n `No handler registered for command ${commandType}!`,\n );\n }\n\n // Commands must have exactly one handler\n if (commandHandlers.length > 1) {\n throw new EmmettError(\n `Multiple handlers registered for command ${commandType}. ` +\n `Commands must have exactly one handler.`,\n );\n }\n\n // Deserialize the command\n const command = deserialize<Command>(message.data);\n\n // Execute the handler\n const handler = commandHandlers[0];\n await handler(command);\n\n return 'ack';\n } catch (error) {\n console.error(\n `Error handling command ${commandType}:`,\n error instanceof Error ? error.message : String(error),\n );\n\n // Determine if we should retry\n if (shouldRetry(error)) {\n console.info(\n `Nacking command ${commandType} for retry (delivery attempt: ${message.deliveryAttempt})`,\n );\n return 'nack';\n } else {\n console.warn(\n `Acking command ${commandType} despite error (permanent failure)`,\n );\n return 'ack';\n }\n }\n}\n\n/**\n * Process an incoming event message from PubSub\n *\n * @param message - The PubSub message\n * @param handlers - Map of message type to handlers\n * @param eventType - The event type being processed\n * @returns 'ack' if all handlers successful or permanent failure, 'nack' if retriable failure\n */\nexport async function handleEventMessage(\n message: PubSubMessage,\n handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>,\n eventType: string,\n): Promise<'ack' | 'nack'> {\n try {\n // Get handlers for this event type\n const eventHandlers = handlers.get(eventType);\n\n if (!eventHandlers || eventHandlers.length === 0) {\n // Events without handlers are silently ignored (valid scenario)\n console.debug(`No handlers registered for event ${eventType}, skipping`);\n return 'ack';\n }\n\n // Deserialize the event\n const event = deserialize<Event>(message.data);\n\n // Execute all handlers sequentially\n for (const handler of eventHandlers) {\n try {\n await handler(event);\n } catch (error) {\n console.error(\n `Error in event handler for ${eventType}:`,\n error instanceof Error ? error.message : String(error),\n );\n\n // If any handler fails with a retriable error, nack the whole message\n if (shouldRetry(error)) {\n console.info(\n `Nacking event ${eventType} for retry due to handler failure (delivery attempt: ${message.deliveryAttempt})`,\n );\n return 'nack';\n }\n // Otherwise continue to next handler\n console.warn(\n `Continuing event ${eventType} processing despite handler error (permanent failure)`,\n );\n }\n }\n\n return 'ack';\n } catch (error) {\n // Error deserializing or other unexpected error\n console.error(\n `Error handling event ${eventType}:`,\n error instanceof Error ? error.message : String(error),\n );\n\n if (shouldRetry(error)) {\n return 'nack';\n } else {\n return 'ack';\n }\n }\n}\n\n/**\n * Create a message listener for a PubSub subscription\n *\n * @param subscription - The PubSub subscription to listen on\n * @param messageType - The message type (command or event type)\n * @param kind - Whether this is a command or event\n * @param handlers - Map of message type to handlers\n */\nexport function createMessageListener(\n subscription: Subscription,\n messageType: string,\n kind: 'command' | 'event',\n handlers: Map<string, SingleRawMessageHandlerWithoutContext<AnyMessage>[]>,\n): void {\n subscription.on('message', async (message: PubSubMessage) => {\n try {\n // Route to appropriate handler based on kind\n const result =\n kind === 'command'\n ? await handleCommandMessage(message, handlers, messageType)\n : await handleEventMessage(message, handlers, messageType);\n\n // Acknowledge or nack based on result\n if (result === 'ack') {\n message.ack();\n } else {\n message.nack();\n }\n } catch (error) {\n // Unexpected error in listener itself - log and nack\n console.error(\n `Unexpected error in message listener for ${messageType}:`,\n error instanceof Error ? error.message : String(error),\n );\n message.nack();\n }\n });\n\n subscription.on('error', (error) => {\n console.error(\n `Subscription error for ${messageType}:`,\n error instanceof Error ? error.message : String(error),\n );\n });\n}\n","import type {\n AnyMessage,\n Command,\n CommandProcessor,\n Event,\n EventSubscription,\n Message,\n MessageBus,\n ScheduledMessageProcessor,\n SingleMessageHandler,\n SingleRawMessageHandlerWithoutContext,\n} from '@event-driven-io/emmett';\nimport { EmmettError } from '@event-driven-io/emmett';\nimport type {\n PubSubMessageBusConfig,\n PubSubMessageBusLifecycle,\n SubscriptionInfo,\n} from './types';\nimport type { ScheduledMessage } from './scheduler';\nimport { MessageScheduler } from './scheduler';\nimport { serialize } from './serialization';\nimport {\n getCommandSubscriptionName,\n getCommandTopicName,\n getEventSubscriptionName,\n getEventTopicName,\n getOrCreateSubscription,\n getOrCreateTopic,\n deleteSubscriptions,\n} from './topicManager';\nimport { createMessageListener } from './messageHandler';\nimport { generateUUID } from './utils';\n\n/**\n * Determine message kind based on message type naming convention (fallback)\n *\n * @param messageType - The message type string\n * @returns 'command' if type contains 'Command', otherwise 'event'\n */\nfunction determineMessageKindFallback(messageType: string): 'command' | 'event' {\n const typeStr = messageType.toLowerCase();\n return typeStr.includes('command') ? 'command' : 'event';\n}\n\n/**\n * Create a Google Cloud Pub/Sub based message bus for Emmett\n *\n * @param config - Configuration for the PubSub message bus\n * @returns A message bus implementation using Google Cloud Pub/Sub\n *\n * @example\n * ```typescript\n * import { PubSub } from '@google-cloud/pubsub';\n * import { getPubSubMessageBus } from '@emmett-community/emmett-google-pubsub';\n *\n * const pubsub = new PubSub({ projectId: 'my-project' });\n * const messageBus = getPubSubMessageBus({ pubsub });\n *\n * // Register handlers\n * messageBus.handle(async (command) => {\n * // Handle command\n * }, 'MyCommand');\n *\n * // Subscribe to events\n * messageBus.subscribe(async (event) => {\n * // Handle event\n * }, 'MyEvent');\n *\n * // Start the message bus\n * await messageBus.start();\n *\n * // Send commands and publish events\n * await messageBus.send({ type: 'MyCommand', data: { ... } });\n * await messageBus.publish({ type: 'MyEvent', data: { ... } });\n *\n * // Close gracefully\n * await messageBus.close();\n * ```\n */\nexport function getPubSubMessageBus(\n config: PubSubMessageBusConfig,\n): MessageBus &\n EventSubscription &\n CommandProcessor &\n ScheduledMessageProcessor &\n PubSubMessageBusLifecycle {\n // Internal state\n const instanceId = config.instanceId ?? generateUUID();\n const topicPrefix = config.topicPrefix ?? 'emmett';\n const autoCreateResources = config.autoCreateResources ?? true;\n const cleanupOnClose = config.cleanupOnClose ?? false;\n const closePubSubClient = config.closePubSubClient;\n\n // Map of message type to handlers\n const handlers = new Map<\n string,\n SingleRawMessageHandlerWithoutContext<AnyMessage>[]\n >();\n\n // Map of subscription ID to specific handler (for event subscriptions)\n const subscriptionHandlers = new Map<\n string,\n SingleRawMessageHandlerWithoutContext<AnyMessage>\n >();\n\n // Map of message type to subscription IDs (for events with multiple subscriptions)\n const eventSubscriptionIds = new Map<string, string[]>();\n\n // Track which message types are commands vs events\n const commandTypes = new Set<string>();\n const eventTypes = new Set<string>();\n\n // Active subscriptions\n const subscriptions: SubscriptionInfo[] = [];\n\n // Scheduler for delayed messages\n const scheduler = new MessageScheduler({\n useEmulator: config.useEmulator ?? false,\n pubsub: config.pubsub,\n topicPrefix,\n });\n\n // Lifecycle state\n let started = false;\n\n /**\n * Determine message kind based on how it was registered\n *\n * @param messageType - The message type string\n * @returns 'command' if registered with handle(), 'event' if registered with subscribe()\n */\n function determineMessageKind(messageType: string): 'command' | 'event' {\n // Check explicit registration first\n if (commandTypes.has(messageType)) {\n return 'command';\n }\n if (eventTypes.has(messageType)) {\n return 'event';\n }\n // Fallback to name-based heuristic\n return determineMessageKindFallback(messageType);\n }\n\n /**\n * Create subscription for a specific message type\n *\n * @param messageType - The message type\n * @param kind - Whether this is a command or event\n * @param subscriptionId - Optional subscription ID for events\n */\n async function createSubscriptionForType(\n messageType: string,\n kind: 'command' | 'event',\n subscriptionId?: string,\n ): Promise<void> {\n // Get topic name based on kind\n const topicName =\n kind === 'command'\n ? getCommandTopicName(messageType, topicPrefix)\n : getEventTopicName(messageType, topicPrefix);\n\n // Get or create topic\n const topic = await getOrCreateTopic(config.pubsub, topicName);\n\n // Get subscription name\n const subName =\n kind === 'command'\n ? getCommandSubscriptionName(messageType, instanceId, topicPrefix)\n : getEventSubscriptionName(\n messageType,\n subscriptionId ?? instanceId,\n topicPrefix,\n );\n\n // Create subscription\n const subscription = await getOrCreateSubscription(\n topic,\n subName,\n config.subscriptionOptions,\n );\n\n // Create message listener with appropriate handlers\n if (kind === 'event' && subscriptionId) {\n // For events, create a map with only this subscription's handler\n const handler = subscriptionHandlers.get(subscriptionId);\n if (handler) {\n const singleHandlerMap = new Map<\n string,\n SingleRawMessageHandlerWithoutContext<AnyMessage>[]\n >();\n singleHandlerMap.set(messageType, [handler]);\n createMessageListener(subscription, messageType, kind, singleHandlerMap);\n }\n } else {\n // For commands, use the handlers map as before\n createMessageListener(subscription, messageType, kind, handlers);\n }\n\n // Track subscription\n subscriptions.push({\n topic,\n subscription,\n messageType,\n kind,\n });\n }\n\n /**\n * Publish a message to a PubSub topic\n *\n * @param message - The message to publish\n * @param kind - Whether this is a command or event\n */\n async function publishMessage(\n message: Message,\n kind: 'command' | 'event',\n ): Promise<void> {\n // Publishing without start() is allowed (producer-only mode)\n // start() is only required for consumers (handlers/subscribers)\n\n // Get topic name\n const topicName =\n kind === 'command'\n ? getCommandTopicName(message.type, topicPrefix)\n : getEventTopicName(message.type, topicPrefix);\n\n try {\n // Get topic\n const topic = config.pubsub.topic(topicName);\n\n // Check if topic exists if auto-create is disabled\n if (!autoCreateResources) {\n const [exists] = await topic.exists();\n if (!exists) {\n throw new Error(\n `Topic ${topicName} does not exist and autoCreateResources is disabled`,\n );\n }\n } else {\n // Create topic if it doesn't exist\n const [exists] = await topic.exists();\n if (!exists) {\n await topic.create();\n }\n }\n\n // Serialize message\n const buffer = serialize(message);\n\n // Publish\n await topic.publishMessage({\n data: buffer,\n attributes: {\n messageType: message.type,\n messageKind: kind,\n },\n });\n } catch (error) {\n throw new Error(\n `Failed to publish ${kind} ${message.type} to topic ${topicName}: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n }\n\n // Return the message bus implementation\n return {\n // ===== MessageBus Interface =====\n\n /**\n * Send a command to the message bus\n *\n * Commands are routed to exactly one handler via PubSub topics\n *\n * @param command - The command to send\n */\n async send<CommandType extends Command>(\n command: CommandType,\n ): Promise<void> {\n await publishMessage(command, 'command');\n },\n\n /**\n * Publish an event to the message bus\n *\n * Events are delivered to all registered subscribers via PubSub topics\n *\n * @param event - The event to publish\n */\n async publish<EventType extends Event>(event: EventType): Promise<void> {\n await publishMessage(event, 'event');\n },\n\n /**\n * Schedule a message for future delivery\n *\n * In production mode: Uses PubSub native scheduling\n * In emulator mode: Stores in memory (emulator doesn't support scheduling)\n *\n * @param message - The message to schedule\n * @param when - When to deliver the message (afterInMs or at)\n */\n schedule<MessageType extends Message>(\n message: MessageType,\n when?: { afterInMs: number } | { at: Date },\n ): void {\n scheduler.schedule(message, when);\n },\n\n // ===== CommandProcessor Interface =====\n\n /**\n * Register a command handler\n *\n * Commands must have exactly one handler. Attempting to register multiple\n * handlers for the same command will throw an EmmettError.\n *\n * @param commandHandler - The handler function\n * @param commandTypes - Command types this handler processes\n * @throws EmmettError if a handler is already registered for any command type\n *\n * @example\n * ```typescript\n * messageBus.handle(\n * async (command: AddProductItemCommand) => {\n * // Handle command\n * },\n * 'AddProductItem'\n * );\n * ```\n */\n handle<CommandType extends Command>(\n commandHandler: SingleMessageHandler<CommandType>,\n ...commandTypeNames: CommandType['type'][]\n ): void {\n for (const commandType of commandTypeNames) {\n // Validate no duplicate handlers\n if (handlers.has(commandType)) {\n throw new EmmettError(\n `Handler already registered for command ${commandType}. ` +\n `Commands must have exactly one handler.`,\n );\n }\n\n // Track as command type\n commandTypes.add(commandType);\n\n // Store handler (single handler in array for consistency)\n handlers.set(commandType, [\n commandHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n\n // If already started, create subscription immediately\n if (started) {\n createSubscriptionForType(commandType, 'command').catch((error) => {\n console.error(\n `Failed to create subscription for command ${commandType}:`,\n error instanceof Error ? error.message : String(error),\n );\n });\n }\n }\n },\n\n // ===== EventSubscription Interface =====\n\n /**\n * Subscribe to events\n *\n * Events can have multiple subscribers. Each subscription gets its own\n * PubSub subscription to ensure all handlers receive all events.\n *\n * @param eventHandler - The handler function\n * @param eventTypes - Event types to subscribe to\n *\n * @example\n * ```typescript\n * messageBus.subscribe(\n * async (event: ProductItemAddedEvent) => {\n * // Handle event\n * },\n * 'ProductItemAdded'\n * );\n * ```\n */\n subscribe<EventType extends Event>(\n eventHandler: SingleMessageHandler<EventType>,\n ...eventTypeNames: EventType['type'][]\n ): void {\n for (const eventType of eventTypeNames) {\n // Track as event type\n eventTypes.add(eventType);\n\n // Generate unique subscription ID for this subscriber\n const subscriptionId = generateUUID();\n\n // Store handler associated with this subscription ID\n subscriptionHandlers.set(\n subscriptionId,\n eventHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n );\n\n // Get existing handlers or create new array\n const existing = handlers.get(eventType) ?? [];\n\n // Add handler to array (for compatibility)\n handlers.set(eventType, [\n ...existing,\n eventHandler as SingleRawMessageHandlerWithoutContext<AnyMessage>,\n ]);\n\n // Track subscription ID for this event type\n const existingIds = eventSubscriptionIds.get(eventType) ?? [];\n eventSubscriptionIds.set(eventType, [...existingIds, subscriptionId]);\n\n // If already started, create subscription immediately\n if (started) {\n createSubscriptionForType(eventType, 'event', subscriptionId).catch(\n (error) => {\n console.error(\n `Failed to create subscription for event ${eventType}:`,\n error instanceof Error ? error.message : String(error),\n );\n },\n );\n }\n }\n },\n\n // ===== ScheduledMessageProcessor Interface =====\n\n /**\n * Dequeue scheduled messages that are ready for delivery\n *\n * Only used in emulator mode. In production, PubSub handles scheduling.\n *\n * @returns Array of scheduled messages ready for delivery\n *\n * @example\n * ```typescript\n * // In emulator mode, periodically call dequeue\n * setInterval(() => {\n * const ready = messageBus.dequeue();\n * for (const { message } of ready) {\n * // Process message\n * }\n * }, 1000);\n * ```\n */\n dequeue(): ScheduledMessage[] {\n return scheduler.dequeue();\n },\n\n // ===== PubSubMessageBusLifecycle Interface =====\n\n /**\n * Start the message bus\n *\n * Creates topics and subscriptions for all registered handlers and begins\n * listening for messages.\n *\n * This method is idempotent - calling it multiple times is safe.\n *\n * @throws Error if topic/subscription creation fails\n *\n * @example\n * ```typescript\n * // Register all handlers first\n * messageBus.handle(commandHandler, 'MyCommand');\n * messageBus.subscribe(eventHandler, 'MyEvent');\n *\n * // Then start\n * await messageBus.start();\n * ```\n */\n async start(): Promise<void> {\n if (started) {\n console.debug('Message bus already started, skipping');\n return;\n }\n\n console.info('Starting PubSub message bus...');\n\n try {\n // Create subscriptions for all registered handlers\n const subscriptionPromises: Promise<void>[] = [];\n\n for (const [messageType] of handlers.entries()) {\n const kind = determineMessageKind(messageType);\n\n if (kind === 'command') {\n // Commands: one subscription per instance\n subscriptionPromises.push(\n createSubscriptionForType(messageType, 'command'),\n );\n } else {\n // Events: one subscription per handler (multiple allowed)\n const subIds = eventSubscriptionIds.get(messageType) ?? [\n instanceId,\n ];\n for (const subId of subIds) {\n subscriptionPromises.push(\n createSubscriptionForType(messageType, 'event', subId),\n );\n }\n }\n }\n\n // Wait for all subscriptions to be created\n await Promise.all(subscriptionPromises);\n\n started = true;\n\n console.info(\n `PubSub message bus started with ${subscriptions.length} subscription(s)`,\n );\n } catch (error) {\n throw new Error(\n `Failed to start message bus: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n\n /**\n * Close the message bus gracefully\n *\n * Stops accepting new messages, waits for in-flight messages to complete,\n * optionally cleans up subscriptions, and closes the PubSub client.\n *\n * @throws Error if cleanup fails\n *\n * @example\n * ```typescript\n * // Graceful shutdown\n * process.on('SIGTERM', async () => {\n * await messageBus.close();\n * process.exit(0);\n * });\n * ```\n */\n async close(): Promise<void> {\n console.info('Closing PubSub message bus...');\n\n try {\n // Only cleanup subscriptions if started\n if (started) {\n // Stop accepting new messages\n for (const { subscription } of subscriptions) {\n subscription.removeAllListeners('message');\n subscription.removeAllListeners('error');\n }\n\n // Wait for in-flight messages with timeout (30 seconds)\n const timeout = 30000;\n const waitStart = Date.now();\n\n // Close all subscriptions\n const closePromises = subscriptions.map(({ subscription }) =>\n subscription.close(),\n );\n await Promise.race([\n Promise.all(closePromises),\n new Promise((resolve) => setTimeout(resolve, timeout)),\n ]);\n\n const waitTime = Date.now() - waitStart;\n if (waitTime >= timeout) {\n console.warn(\n `Timeout waiting for in-flight messages after ${timeout}ms`,\n );\n }\n\n // Cleanup subscriptions if configured\n if (cleanupOnClose) {\n console.info('Cleaning up subscriptions...');\n await deleteSubscriptions(subscriptions.map((s) => s.subscription));\n }\n\n started = false;\n }\n\n // Always close PubSub client (even if not started, for producer-only mode)\n if (closePubSubClient !== false) {\n await config.pubsub.close();\n }\n\n console.info('PubSub message bus closed');\n } catch (error) {\n throw new Error(\n `Failed to close message bus: ${\n error instanceof Error ? error.message : String(error)\n }`,\n );\n }\n },\n\n /**\n * Check if the message bus is started\n *\n * @returns true if the message bus is started and ready to process messages\n */\n isStarted(): boolean {\n return started;\n },\n };\n}\n"]}
|