UNPKG

@hookflo/tern

Version:

A robust, scalable webhook verification framework supporting multiple platforms and signature algorithms

87 lines (86 loc) 3.63 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.NormalizationEngine = void 0; const registry_1 = require("../templates/registry"); const validator_1 = require("./validator"); class NormalizationEngine { constructor(storage, validator = new validator_1.SchemaValidator()) { this.storage = storage; this.validator = validator; } async transform(params) { const { rawPayload, provider, schemaId } = params; const schema = await this.storage.getSchema(schemaId); if (!schema) throw new Error(`Schema not found: ${schemaId}`); const baseTemplate = await this.storage.getBaseTemplate(schema.baseTemplateId) || registry_1.templateRegistry.getById(schema.baseTemplateId); if (!baseTemplate) throw new Error(`Base template not found: ${schema.baseTemplateId}`); const validation = this.validator.validateSchema(schema, baseTemplate); if (!validation.valid) { throw new Error(`Invalid schema: ${validation.errors.join('; ')}`); } const providerMapping = schema.providerMappings.find((m) => m.provider === provider); if (!providerMapping) throw new Error(`No mapping found for provider: ${provider}`); const normalized = {}; for (const field of schema.fields) { if (!field.enabled) continue; const mapping = providerMapping.fieldMappings.find((m) => m.schemaFieldId === field.id); if (mapping) { const value = this.extractValue(rawPayload, mapping.providerPath); const finalValue = this.applyTransform(value, mapping.transform); normalized[field.name] = finalValue ?? field.defaultValue; } else if (field.required) { if (field.defaultValue !== undefined) { normalized[field.name] = field.defaultValue; } else { throw new Error(`Required field ${field.name} has no mapping`); } } } const outValidation = this.validator.validateOutput(normalized, schema, baseTemplate); if (!outValidation.valid) { throw new Error(`Normalized output invalid: ${outValidation.errors.join('; ')}`); } return { normalized, meta: { provider, schemaId, schemaVersion: schema.baseTemplateId, transformedAt: new Date(), }, }; } extractValue(obj, path) { if (!path) return undefined; return path.split('.').reduce((acc, key) => (acc == null ? undefined : acc[key]), obj); } applyTransform(value, transform) { if (transform == null) return value; if (value == null) return value; if (transform === 'toUpperCase') return String(value).toUpperCase(); if (transform === 'toLowerCase') return String(value).toLowerCase(); if (transform === 'toNumber') return typeof value === 'number' ? value : Number(value); if (transform.startsWith('divide:')) { const denominator = Number(transform.split(':')[1]); return Number(value) / denominator; } if (transform.startsWith('multiply:')) { const factor = Number(transform.split(':')[1]); return Number(value) * factor; } return value; } } exports.NormalizationEngine = NormalizationEngine;