UNPKG

@sprucelabs/mercury-event-emitter

Version:
199 lines (198 loc) • 8.14 kB
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; import AbstractSpruceError from '@sprucelabs/error'; import { validateSchemaValues } from '@sprucelabs/schema'; import { eventContractUtil, eventResponseUtil, } from '@sprucelabs/spruce-event-utils'; import SpruceError from './errors/SpruceError.js'; export default class AbstractEventEmitter { constructor(contract, options) { var _a; this.listenersByEvent = {}; this.eventContract = contract; this.shouldEmitSequentally = (_a = options === null || options === void 0 ? void 0 : options.shouldEmitSequentally) !== null && _a !== void 0 ? _a : false; } emit(eventName, payload, cb) { return __awaiter(this, void 0, void 0, function* () { const { actualPayload, actualCallback } = this.normalizePayloadAndCallback(payload, cb); const eventSignature = 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 = (listenerCb, idx) => __awaiter(this, void 0, void 0, function* () { var _a; let response = yield this.emitOne({ idx, listenerCb, payload: actualPayload, totalContracts: listeners.length, actualCallback, }); if (responseSchema && !response.errors) { try { this.validateResponsePayload(responseSchema, (_a = response.payload) !== null && _a !== void 0 ? _a : {}, 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 = yield emitOneAndValidate(listener, idx); responses.push(response); idx++; } } else { responses = yield Promise.all(listeners.map((listenerCb, idx) => __awaiter(this, void 0, void 0, function* () { return emitOneAndValidate(listenerCb, idx); }))); } return { totalContracts: listeners.length, totalResponses: listeners.length, totalErrors, responses, }; }); } emitAndFlattenResponses(eventName, payload, cb) { return __awaiter(this, void 0, void 0, function* () { const results = yield this.emit(eventName, payload, cb); if (results.totalResponses === 0) { return []; } const { payloads, errors } = eventResponseUtil.getAllResponsePayloadsAndErrors(results, SpruceError); if (errors === null || errors === void 0 ? void 0 : errors[0]) { throw errors[0]; } return payloads; }); } emitOne(options) { return __awaiter(this, void 0, void 0, function* () { let responsePayload; let error; try { responsePayload = yield options.listenerCb(options.payload); } catch (err) { if (err instanceof AbstractSpruceError) { error = err; } else { error = new SpruceError({ 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]; } yield 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 = eventContractUtil.unifyContracts([ this.eventContract, contract, ]); } validateEmitPayload(schema, actualPayload, eventName) { if (schema) { try { validateSchemaValues(schema, actualPayload !== null && actualPayload !== void 0 ? actualPayload : {}); } catch (err) { throw new SpruceError({ code: 'INVALID_PAYLOAD', originalError: err, eventName, }); } } } validateResponsePayload(schema, actualPayload, eventName) { if (schema) { try { validateSchemaValues(schema, actualPayload !== null && actualPayload !== void 0 ? actualPayload : {}); } catch (err) { throw new SpruceError({ 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 }; } on(eventName, cb) { return __awaiter(this, void 0, void 0, function* () { eventContractUtil.getSignatureByName(this.eventContract, eventName); if (!this.listenersByEvent[eventName]) { this.listenersByEvent[eventName] = []; } this.listenersByEvent[eventName].push(cb); }); } off(eventName, cb) { return __awaiter(this, void 0, void 0, function* () { var _a; if (cb) { let numForgotten = 0; this.listenersByEvent[eventName] = (_a = this.listenersByEvent[eventName]) === null || _a === void 0 ? void 0 : _a.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; } }); } }