UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

203 lines 7.45 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.applied = exports.patched = exports.updated = exports.created = exports.wrapper = void 0; const lodash_1 = require("lodash"); const middleware_1 = require("../middleware"); const handlers = __importStar(require("./handlers")); function wrapper(services, topic, handler) { return async (event, route, headers, opts) => { try { await handler(event, route, headers); typeof opts?.ack === 'function' && (await opts.ack()); } catch (err) { services.telemetry.logger.error('[events#wrapper] Event error', { err, }); if (typeof opts?.delivery === 'number' && opts?.delivery > 0) { services.telemetry.logger.warn('[events#wrapper] Event discarded', { event, route, headers: (0, lodash_1.omit)(headers, 'authorization'), deliver: opts?.delivery, }); typeof opts?.ack === 'function' && (await opts.ack()); // Publish the message in another dedicated dead messages queue return; } if (err?.details) { await handlers.publish(services, `${topic}/error`, { event, details: err?.details, }); } typeof opts?.nack === 'function' && (await opts.nack()); } }; } exports.wrapper = wrapper; const created = (services, modelName, topic) => wrapper(services, topic, async (event, route, headers = {}) => { const entity = await handlers.created(services, { params: { model: modelName, }, headers, }, event); return entity.state; }); exports.created = created; const updated = (services, modelName, topic) => wrapper(services, topic, async (event, route, headers = {}) => { const entity = await handlers.updated(services, { params: { model: modelName, correlation_id: route.params.correlation_id, }, headers, }, event); return entity.state; }); exports.updated = updated; const patched = (services, modelName, topic) => wrapper(services, topic, async (event, route, headers) => { const entity = await handlers.patched(services, { params: { model: modelName, correlation_id: route.params.correlation_id, }, headers, }, event); return entity.state; }); exports.patched = patched; const applied = (services, modelName, topic) => wrapper(services, topic, async (event, route, headers = {}) => { const entity = await handlers.applied(services, { params: { model: modelName, correlation_id: route.params.correlation_id, event_type: route.params.event_type, }, headers, }, event); return entity.state; }); exports.applied = applied; const EVENT_HANDLERS_MAPPING = { CREATED: exports.created, UPDATED: exports.updated, ROLLBACKED: null, // Skipped RESTORED: null, // Skipped PATCHED: exports.patched, ARCHIVED: null, // Skipped DELETED: null, // Skipped }; async function registerModelEventForMQTT(services, model, topic, eventSchema, handler) { const { config, mqtt } = services; if (config.features.mqtt.isEnabled !== true) { return; } const modelConfig = model.getModelConfig(); services.telemetry.logger.debug('[events] Registering model event...', { protocol: 'mqtt', name: modelConfig.name, topic, }); mqtt.on(topic, mqtt.authenticate((0, middleware_1.getTokensByRole)(config.security.tokens, 'write'), handler(services, modelConfig.name, topic))); await mqtt.subscribe(topic, { type: 'object', properties: { body: eventSchema, }, }); } async function registerModelEventForAMQP(services, model, topic, eventSchema, handler) { const { config, amqp } = services; if (config.features.amqp.isEnabled !== true) { return; } const modelConfig = model.getModelConfig(); services.telemetry.logger.debug('[events] Registering model event...', { protocol: 'amqp', name: modelConfig.name, topic, }); amqp.on(topic, amqp.authenticate((0, middleware_1.getTokensByRole)(config.security.tokens, 'write'), handler(services, modelConfig.name, topic))); await amqp.subscribe(topic, { type: 'object', properties: { body: eventSchema, }, }); } async function registerModelEvent(services, model, eventName, handler) { if (handler === null) { return; } handler = handler || exports.applied; const modelConfig = model.getModelConfig(); const schema = model.getSchema(); services.telemetry.logger.debug('[events] Registering model...', { name: modelConfig.name, }); const event = schema.events[eventName]; let lastVersion; for (const eventVersion in event) { lastVersion = eventVersion; } if (!lastVersion) { return; } const eventSchema = event[lastVersion]; let topic = `${modelConfig.name}/${eventName}`.toLowerCase(); if (eventName !== 'CREATED') { topic += `/{${model.getCorrelationField()}}`; } await Promise.all([ registerModelEventForMQTT(services, model, topic, eventSchema, handler), registerModelEventForAMQP(services, model, topic, eventSchema, handler), ]); } async function registerModel(services, model) { const schema = model.getSchema(); const events = schema.events || {}; services.telemetry.logger.debug('[events] Registering model...', { name: model.getModelConfig().name, }); for (const eventName in events) { await registerModelEvent(services, model, eventName, /* @ts-ignore */ EVENT_HANDLERS_MAPPING[eventName]); } } async function register(services) { services.telemetry.logger.info('[events] Registering...'); for (const [modelName, model] of services.models.MODELS.entries()) { if (services.models.isInternalModel(modelName) === true) { continue; } await registerModel(services, model); } } exports.default = register; //# sourceMappingURL=index.js.map