UNPKG

@sprucelabs/mercury-event-emitter

Version:
183 lines (182 loc) • 6.59 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const error_1 = __importDefault(require("@sprucelabs/error")); const schema_1 = require("@sprucelabs/schema"); const spruce_event_utils_1 = require("@sprucelabs/spruce-event-utils"); const SpruceError_1 = __importDefault(require("./errors/SpruceError")); class AbstractEventEmitter { constructor(contract, options) { this.listenersByEvent = {}; this.eventContract = contract; this.shouldEmitSequentally = options?.shouldEmitSequentally ?? false; } async emit(eventName, payload, cb) { const { actualPayload, actualCallback } = this.normalizePayloadAndCallback(payload, cb); const eventSignature = spruce_event_utils_1.eventContractUtil.getSignatureByName(this.eventContract, eventName); const emitSchema = eventSignature.emitPayloadSchema; const responseSchema = eventSignature.responsePayloadSchema; this.validateEmitPayload(emitSchema, actualPayload, eventName); const listeners = this.listenersByEvent[eventName] || []; let totalErrors = 0; const emitOneAndValidate = async (listenerCb, idx) => { let response = await this.emitOne({ idx, listenerCb, payload: actualPayload, totalContracts: listeners.length, actualCallback, }); if (responseSchema && !response.errors) { try { this.validateResponsePayload(responseSchema, response.payload ?? {}, eventName); } catch (err) { response = { errors: [err], }; } } if (response.errors) { totalErrors += response.errors.length; } return response; }; let responses; if (this.shouldEmitSequentally) { responses = []; let idx = 0; for (const listener of listeners) { const response = await emitOneAndValidate(listener, idx); responses.push(response); idx++; } } else { responses = await Promise.all(listeners.map(async (listenerCb, idx) => emitOneAndValidate(listenerCb, idx))); } return { totalContracts: listeners.length, totalResponses: listeners.length, totalErrors, responses, }; } async emitAndFlattenResponses(eventName, payload, cb) { const results = await this.emit(eventName, payload, cb); if (results.totalResponses === 0) { return []; } const { payloads, errors } = spruce_event_utils_1.eventResponseUtil.getAllResponsePayloadsAndErrors(results, SpruceError_1.default); if (errors?.[0]) { throw errors[0]; } return payloads; } async emitOne(options) { let responsePayload; let error; try { responsePayload = await options.listenerCb(options.payload); } catch (err) { if (err instanceof error_1.default) { error = err; } else { error = new SpruceError_1.default({ code: 'LISTENER_ERROR', originalError: err, listenerIdx: options.idx, }); } } if (typeof options.actualCallback === 'function') { const emitCallbackPayload = {}; if (responsePayload) { emitCallbackPayload.payload = responsePayload; } if (error) { emitCallbackPayload.errors = [error]; } await options.actualCallback(emitCallbackPayload); } const response = { payload: responsePayload, }; if (error) { response.errors = [error]; } return response; } listenCount(eventName) { return (this.listenersByEvent[eventName] || []).length; } mixinContract(contract) { this.eventContract = spruce_event_utils_1.eventContractUtil.unifyContracts([ this.eventContract, contract, ]); } validateEmitPayload(schema, actualPayload, eventName) { if (schema) { try { (0, schema_1.validateSchemaValues)(schema, actualPayload ?? {}); } catch (err) { throw new SpruceError_1.default({ code: 'INVALID_PAYLOAD', originalError: err, eventName, }); } } } validateResponsePayload(schema, actualPayload, eventName) { if (schema) { try { (0, schema_1.validateSchemaValues)(schema, actualPayload ?? {}); } catch (err) { throw new SpruceError_1.default({ code: 'INVALID_RESPONSE_PAYLOAD', originalError: err, eventName, }); } } } normalizePayloadAndCallback(payload, cb) { const actualPayload = typeof payload !== 'function' ? payload : undefined; const actualCallback = typeof payload === 'function' ? payload : cb; return { actualPayload, actualCallback }; } async on(eventName, cb) { spruce_event_utils_1.eventContractUtil.getSignatureByName(this.eventContract, eventName); if (!this.listenersByEvent[eventName]) { this.listenersByEvent[eventName] = []; } this.listenersByEvent[eventName].push(cb); } async off(eventName, cb) { if (cb) { let numForgotten = 0; this.listenersByEvent[eventName] = this.listenersByEvent[eventName]?.filter((listener) => { if (listener === cb) { numForgotten++; return false; } return true; }); return numForgotten; } else { const total = (this.listenersByEvent[eventName] || []).length; delete this.listenersByEvent[eventName]; return total; } } } exports.default = AbstractEventEmitter;