UNPKG

@logistically/events

Version:

A production-ready event-driven architecture library for NestJS with Redis Streams, comprehensive batching, reliable consumption, and enterprise-grade features.

99 lines (98 loc) 4.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Payload = exports.MessagePattern = exports.EventPublisher = void 0; const event_routing_1 = require("../event-routing"); const event_types_1 = require("../event-types"); const rxjs_1 = require("rxjs"); // Note: The 'prefix' in routing is used for legacy/compatibility purposes and is ignored for stream routing in the Redis Streams transport. function getNamespaceFromType(eventType) { return eventType.split('.')[0]; } function getStreamForEventType(eventType) { const namespace = getNamespaceFromType(eventType); return `${namespace}-events`; } class EventPublisher { constructor(transports, options, routingConfig = event_routing_1.default) { this.transports = transports; this.options = options; this.routingConfig = routingConfig; if (!options || !options.originServiceName) { throw new Error('originServiceName must be provided in EventPublisherOptions'); } if (!options.validator) { throw new Error('validator must be provided in EventPublisherOptions'); } // Initialize validator this.validator = options.validator; // Set event namespace - use provided one or derive from service name this.eventNamespace = options.eventNamespace || options.originServiceName; } getRouteForEvent(eventType) { return this.routingConfig.routes.find(route => route.pattern.test(eventType)); } getTransportForEvent(eventType) { const route = this.getRouteForEvent(eventType); if (route) { return { transport: this.transports[route.transport], prefix: route.prefix }; } return { transport: this.transports[event_routing_1.default.default] }; } async publish(eventType, body) { // Validate event body using the validator const validation = this.validator.validate(eventType, body); if (!validation.valid) { throw new Error(`Invalid event body for type ${eventType}: ${validation.error}`); } const { transport, prefix } = this.getTransportForEvent(eventType); const finalEventType = prefix ? `${prefix}${eventType}` : eventType; const stream = getStreamForEventType(eventType); // Create the envelope with proper header generation const envelope = (0, event_types_1.createEventEnvelope)(eventType, this.options.originServiceName, body, this.eventNamespace); // If the transport supports stream override, pass it if (typeof transport.dispatchEvent === 'function') { await transport.dispatchEvent({ pattern: finalEventType, data: envelope }, { stream }); } else { await (0, rxjs_1.firstValueFrom)(transport.emit(finalEventType, envelope)); } } // Convenience method for publishing with custom validator async publishWithValidator(eventType, body, validator) { const tempValidator = this.validator; this.validator = validator; try { await this.publish(eventType, body); } finally { this.validator = tempValidator; } } // Method to register schemas with the default validator registerSchema(eventType, schema) { if (this.validator instanceof event_types_1.DefaultEventValidator) { this.validator.registerSchema(eventType, schema); } else { throw new Error('Cannot register schema with custom validator'); } } // Close method for proper resource cleanup async close() { // Close all transports for (const transport of Object.values(this.transports)) { if (transport && typeof transport.close === 'function') { try { await transport.close(); } catch (error) { console.warn('Error closing transport:', error); } } } } } exports.EventPublisher = EventPublisher; var microservices_1 = require("@nestjs/microservices"); Object.defineProperty(exports, "MessagePattern", { enumerable: true, get: function () { return microservices_1.MessagePattern; } }); Object.defineProperty(exports, "Payload", { enumerable: true, get: function () { return microservices_1.Payload; } });