/** * BrokersService - Main Message Broker Service Class * * Provides a unified interface for message broker operations including * publish and subscribe functionality. * * Supported providers: RabbitMQ, Kafka, AWS SQS, Redis, Google Pub/Sub */ import { IBrokerServiceConfig, IPublishOptions, ISubscribeOptions, IPublishResult, ISubscribeResult, IGetBrokerEventsOptions, IGetBrokerEventsResult, IGetBrokerEventOptions, IBrokerEvent, IReplayEventOptions, IReplayEventResult, IReprocessDLQOptions, IReprocessDLQResult, IBrokerEventStats, IIdempotentPublishOptions } from './types'; import { IProductMessageBroker, IProductMessageBrokerTopic } from '../types'; /** * Error class for broker operations */ export declare class BrokerError extends Error { code: string; details?: unknown; constructor(message: string, code: string, details?: unknown); } /** * BrokersService * * Unified API for all message broker operations. * * @example * ```ts * import { BrokersService } from '@ductape/sdk'; * * const brokers = new BrokersService({ * workspace_id: 'your-workspace-id', * public_key: 'your-public-key', * user_id: 'your-user-id', * token: 'your-token', * env_type: 'prd', * }); * * // Publish a message * await brokers.publish({ * product: 'my-product', * env: 'production', * event: 'orders-broker:new-order', * message: { orderId: '123', amount: 99.99 }, * }); * * // Subscribe to messages * await brokers.subscribe({ * product: 'my-product', * env: 'production', * event: 'orders-broker:new-order', * callback: async (message) => { * console.log('Received:', message); * }, * }); * ``` */ export declare class BrokersService { private config; private productBuilderService; private processorApiService; private logService; private productId; private productTag; private privateKey; /** Cache manager for 3-tier caching */ private cacheManager; /** Private keys per product for cache encryption */ private privateKeys; /** Connection pool for broker services - keyed by broker type + config hash */ private brokerServicePool; /** When using shared registry, track poolKey -> sharedKey so disconnectAll can remove from shared */ private poolKeyToSharedKey; /** Cache for initialized broker configs - keyed by "productTag:brokerTag:envSlug" */ private initializedBrokerCache; /** Cache for initialized products - keyed by productTag */ private initializedProducts; /** Cache for registered broker consumers - keyed by consumerTag to track which consumers have been registered */ private registeredConsumers; /** Local cache for cache configurations to avoid repeated API calls */ private cacheConfigCache; /** Dedupe "Publish to broker - success" when same event is published twice in quick succession (e.g. feature step run twice) */ private lastPublishSuccessLogKey; private lastPublishSuccessLogTime; private static readonly PUBLISH_SUCCESS_LOG_DEDUPE_MS; constructor(config: IBrokerServiceConfig); /** * Get user access credentials */ private getUserAccess; /** * Initialize product and get broker configuration (with caching) */ private initializeBroker; private assertSqsQueueIsUnique; /** * Initialize logging service */ private initializeLogService; /** * Validate cache tag exists in product and return cache configuration * Uses local in-memory cache to avoid repeated API calls (5 minute TTL) */ private validateCache; /** * Generate a cache key for the broker service pool */ private getBrokerPoolKey; /** * Get or create broker service instance (with connection pooling). * When scope.workspaceId and scope.product are provided, uses shared registry so connections are reused across instances. */ private getBrokerService; /** * Disconnect all pooled broker connections (e.g. at end of feature run). Safe if pool is empty. */ disconnectAll(): Promise; /** * Pre-warm broker connections for the given product/env and broker tags. * Call before step execution so the first produce step reuses connections. Same auth and secrets as publish. */ warmBrokerConnections(options: { product: string; env: string; brokerTags: string[]; }): Promise; /** * Auto-register a topic in the background (fire-and-forget) * This is intentionally lightweight - no pre-check, no post-fetch */ private ensureTopicRegistered; /** * Auto-register a producer if it doesn't exist */ private ensureProducerRegistered; /** * Auto-register a consumer if it doesn't exist */ private ensureConsumerRegistered; /** * Publish a message to a broker topic */ publish(options: IPublishOptions): Promise; /** * Subscribe to a broker topic */ subscribe(options: ISubscribeOptions): Promise; /** * Get all message brokers for a product */ getBrokers(productTag: string): Promise; /** * Get a specific message broker by tag */ getBroker(productTag: string, brokerTag: string): Promise; /** * Get all topics for a message broker */ getTopics(productTag: string, brokerTag: string): Promise; /** * Get a specific topic by event string (broker_tag:topic_tag) */ getTopic(productTag: string, event: string): Promise; /** * Test connection to a message broker * * Validates broker configuration and attempts to establish a connection. * * @example * ```ts * const result = await brokers.testConnection({ * product: 'my-product', * env: 'prd', * broker: 'orders-broker', * }); * console.log(result.connected); // true or false * ``` */ testConnection(options: { product: string; env: string; broker: string; }): Promise<{ connected: boolean; latency?: number; error?: string; }>; /** * Initialize product for event operations (without broker/topic lookup) */ private initializeProductForEvents; /** * Encrypt payload data using the product's private key */ private encryptPayload; /** * Decrypt payload data using the product's private key */ private decryptPayload; /** * Get broker events with filtering and pagination * * @example * ```ts * const result = await brokers.getEvents({ * product: 'my-product', * env: 'production', * brokerTag: 'order-events', * status: 'failed', * page: 1, * limit: 20, * }); * * for (const event of result.events) { * console.log('Event:', event.id, event.status); * } * ``` */ getEvents(options: IGetBrokerEventsOptions): Promise; /** * Get a single broker event by ID * * @example * ```ts * const event = await brokers.getEvent({ * product: 'my-product', * eventId: 'event-123', * }); * * if (event) { * console.log('Event status:', event.status); * console.log('Request data:', event.request_data); * } * ``` */ getEvent(options: IGetBrokerEventOptions): Promise; /** * Replay a broker event (reprocess a failed or successful event) * * @example * ```ts * const result = await brokers.replayEvent({ * product: 'my-product', * env: 'production', * eventId: 'event-123', * force: true, // Replay even if already successful * }); * * if (result.success) { * console.log('New event ID:', result.new_event_id); * } * ``` */ replayEvent(options: IReplayEventOptions): Promise; /** * Get broker event statistics * * @example * ```ts * const stats = await brokers.getEventStats({ * product: 'my-product', * env: 'production', * brokerTag: 'order-events', * }); * * console.log('Total events:', stats.total_events); * console.log('Failed:', stats.failed_count); * console.log('Success:', stats.success_count); * ``` */ getEventStats(options: { product: string; env: string; brokerTag: string; }): Promise; /** * Reprocess messages from the Dead Letter Queue * * @example * ```ts * const result = await brokers.reprocessDLQ({ * product: 'my-product', * env: 'production', * brokerTag: 'order-events', * limit: 100, * }); * * console.log('Reprocessed:', result.reprocessed_count); * console.log('Failed:', result.failed_count); * ``` */ reprocessDLQ(options: IReprocessDLQOptions): Promise; /** * Check if an idempotency key has already been processed * * @example * ```ts * const result = await brokers.checkIdempotency({ * product: 'my-product', * env: 'production', * idempotencyKey: 'order-123-payment', * }); * * if (result.exists) { * console.log('Already processed, event ID:', result.event_id); * } * ``` */ checkIdempotency(options: { product: string; env: string; idempotencyKey: string; }): Promise<{ exists: boolean; event_id?: string; }>; /** * Publish a message with idempotency guarantee * * This ensures the message is only processed once, even if published multiple times * with the same idempotency key. * * @example * ```ts * const result = await brokers.publishIdempotent({ * product: 'my-product', * env: 'production', * event: 'order-events:new-orders', * message: { orderId: '123', amount: 99.99 }, * idempotencyKey: 'order-123-created', * idempotencyTtl: 86400, // 24 hours * }); * * if (result.success) { * console.log('Published with process ID:', result.process_id); * } * ``` */ publishIdempotent(options: IIdempotentPublishOptions): Promise; /** * Messages namespace for workbench broker message queries * All methods decrypt message content before returning */ messages: { /** * Query broker messages with filtering and pagination * Decrypts message content before returning */ query: (options: { product: string; env: string; brokerTag: string; topicTag?: string; producerTag?: string; consumerTag?: string; status?: string; startDate?: string; endDate?: string; page?: number; limit?: number; }) => Promise<{ messages: any[]; total: number; page: number; limit: number; hasMore: boolean; }>; /** * Get broker producers with pagination */ getProducers: (options: { product: string; env: string; brokerTag: string; topicTag?: string; page?: number; limit?: number; }) => Promise<{ producers: any[]; total: number; page: number; limit: number; hasMore: boolean; }>; /** * Get broker consumers with pagination */ getConsumers: (options: { product: string; env: string; brokerTag: string; topicTag?: string; page?: number; limit?: number; }) => Promise<{ consumers: any[]; total: number; page: number; limit: number; hasMore: boolean; }>; /** * Get broker dead letters with pagination * Decrypts message content before returning */ getDeadLetters: (options: { product: string; env: string; brokerTag: string; topicTag?: string; consumerTag?: string; startDate?: string; endDate?: string; page?: number; limit?: number; }) => Promise<{ deadLetters: any[]; total: number; page: number; limit: number; hasMore: boolean; }>; /** * Get comprehensive broker message statistics */ getStats: (options: { product: string; env: string; brokerTag: string; }) => Promise; /** * Get broker dashboard overview data * Decrypts message content for recent messages */ getDashboard: (options: { product: string; env: string; brokerTag: string; }) => Promise; }; } export default BrokersService;