UNPKG

@message-in-the-middle/core

Version:

Framework-agnostic middleware pattern for message queue processing. Core package with all middlewares.

109 lines 3.93 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SchemaRegistryMiddleware = exports.SchemaRegistry = void 0; class SchemaRegistry { schemas = new Map(); options; constructor(options = {}) { this.options = { identifierField: options.identifierField ?? 'type', strict: options.strict ?? true, errorFormatter: options.errorFormatter ?? this.defaultErrorFormatter, }; } register(messageType, validator) { if (typeof messageType !== 'string' || messageType.length === 0) { throw new Error('Message type must be a non-empty string'); } if (messageType.length > 256) { throw new Error('Message type too long (max 256 characters)'); } const forbidden = ['__proto__', 'constructor', 'prototype']; if (forbidden.includes(messageType)) { throw new Error(`Forbidden message type: ${messageType}`); } if (this.schemas.has(messageType)) { throw new Error(`Schema already registered for message type: ${messageType}`); } const wrappedValidator = this.wrapValidator(validator); this.schemas.set(messageType, wrappedValidator); return this; } registerMany(schemas) { for (const [messageType, validator] of Object.entries(schemas)) { this.register(messageType, validator); } return this; } get(messageType) { return this.schemas.get(messageType); } has(messageType) { return this.schemas.has(messageType); } unregister(messageType) { return this.schemas.delete(messageType); } getRegisteredTypes() { return Array.from(this.schemas.keys()); } clear() { this.schemas.clear(); } getIdentifierField() { return this.options.identifierField; } async validate(message) { const messageType = message?.[this.options.identifierField]; if (!messageType) { if (this.options.strict) { throw new Error(`Message missing identifier field '${this.options.identifierField}'`); } return message; } const validator = this.schemas.get(messageType); if (!validator) { if (this.options.strict) { throw new Error(`No schema registered for message type '${messageType}'. ` + `Registered types: ${this.getRegisteredTypes().join(', ')}`); } return message; } try { const validatedMessage = await validator(message); return validatedMessage; } catch (error) { const formattedError = this.options.errorFormatter(error, messageType); throw formattedError; } } wrapValidator(validator) { if (typeof validator === 'object' && validator !== null && 'parse' in validator) { const schema = validator; return (message) => { return schema.parse(message); }; } return validator; } defaultErrorFormatter(error, messageType) { return new Error(`Schema validation failed for message type '${messageType}': ${error.message}`); } } exports.SchemaRegistry = SchemaRegistry; class SchemaRegistryMiddleware { registry; constructor(registry) { this.registry = registry; } async process(context, next) { const messageType = context.message?.[this.registry.getIdentifierField()]; context.message = await this.registry.validate(context.message); context.metadata.schemaValidated = true; context.metadata.schemaMessageType = messageType; await next(); } } exports.SchemaRegistryMiddleware = SchemaRegistryMiddleware; //# sourceMappingURL=schema-registry.middleware.js.map