@getanthill/datastore
Version:
Event-Sourced Datastore
203 lines • 7.45 kB
JavaScript
;
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