UNPKG

@eagleeye-solutions/integration-events-common

Version:
210 lines 8.5 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.handleZodError = exports.formatZodError = exports.getConnectorConfig = void 0; exports.getConnectorConfigInternal = getConnectorConfigInternal; exports.handleEeAirOutboundRequest = handleEeAirOutboundRequest; exports.handleCdpOutboundRequest = handleCdpOutboundRequest; exports.handleInternalMessage = handleInternalMessage; exports.handleStatus = handleStatus; const http_errors_1 = __importDefault(require("http-errors")); const memoizee_1 = __importDefault(require("memoizee")); const env_1 = require("./env"); const types_1 = require("./types"); const exceptions_1 = require("./exceptions"); const platform_1 = require("./platform"); const zod_1 = require("zod"); const connector_config_1 = require("./types/connector-config"); function redact(input) { return input[0] + '*'.repeat(input.length - 2) + input.slice(-1); } async function getConnectorConfigInternal({ appConfig, connectorId, externalKey, direction, logger, }) { logger.debug(`getConnectorConfigInternal: ${JSON.stringify({ connectorId, direction })}`); if (direction !== null && appConfig.configOverride?.[direction] && connectorId === appConfig.configOverride[direction].connectorId && externalKey === appConfig.configOverride[direction].externalKey) { logger.debug(`configOverride found for direction=${direction} connectorId=${connectorId} externalKey=${redact(externalKey)}`); return appConfig.configOverride[direction].connectorConfig; } const url = `${appConfig.configUrl}/connectors/${connectorId}/config?platform=${appConfig.configPlatform}&key=${externalKey}`; const redactedUrl = `${appConfig.configUrl}/connectors/${connectorId}/config?platform=${appConfig.configPlatform}&key=${redact(externalKey)}`; try { const t0 = performance.now(); const response = await fetch(url); const t1 = performance.now(); logger.info(`GET ${redactedUrl}: ${response.status} ${response.statusText} (${t1 - t0}ms)`); if (response.ok) { const connectorConfig = connector_config_1.BaseConnectorConfigSchema.parse(await response.json()); return connectorConfig; } else { logger.error(`GET ${redactedUrl}: ${response.status} ${response.statusText}`); return null; } } catch (err) { logger.error(err, `GET ${redactedUrl} failed`); return null; } } exports.getConnectorConfig = (0, memoizee_1.default)(getConnectorConfigInternal, { maxAge: env_1.env.CONFIG_API_RESPONSE_TTL_MS, normalizer: function (args) { const { connectorId, externalKey, direction } = args[0]; return `${connectorId}-${externalKey}-${direction}`; }, }); async function handleEeAirOutboundRequest(req, res) { const appConfig = res.app.get('appConfig'); const connectorId = req.params.connectorId; const externalKey = req.get('X-Auth-Token'); req.log.info({ 'ee-air-outbound-request': req.body, connectorId, }, `ee-air-outbound-request: method=${req.method}, url=${req.originalUrl} connectorId=${connectorId}`); try { if (!externalKey) { throw http_errors_1.default.Unauthorized(); } const direction = 'out'; const eventType = 'ee-air-outbound-event'; const attributes = {}; const requestBody = req.body; attributes[appConfig.traceIdName] = `${req.id}`; const connectorConfig = await (0, exports.getConnectorConfig)({ appConfig, connectorId, externalKey, direction, logger: req.log, }); if (!connectorConfig) { throw http_errors_1.default.Forbidden(); } await (0, platform_1.sendInternalMessage)(appConfig, { type: eventType, connectorConfig, payload: requestBody, }, attributes, req.log); res.status(200).send({ status: 'OK' }); } catch (error) { req.log.error(error, 'Error in handleEeAirOutboundRequest'); throw error; } } async function handleCdpOutboundRequest(req, res) { const appConfig = res.app.get('appConfig'); const connectorId = req.params.connectorId; const externalKey = req.get('X-Auth-Token'); req.log.info({ 'cdp-outbound-request': req.body, connectorId, }, `cdp-outbound-request: method=${req.method}, url=${req.originalUrl}, connectorId=${connectorId}`); try { if (!externalKey) { throw http_errors_1.default.Unauthorized(); } // direction is relative to AIR const direction = 'in'; const attributes = {}; const requestBody = types_1.CdpOutboundRequestBodySchema.parse(req.body); attributes[appConfig.traceIdName] = `${req.id}`; const connectorConfig = await (0, exports.getConnectorConfig)({ appConfig, connectorId, externalKey, direction, logger: req.log, }); if (!connectorConfig) { throw http_errors_1.default.Forbidden(); } const cdpOutboundEvent = { type: 'cdp-outbound-event', connectorConfig, payload: requestBody, }; await (0, platform_1.sendInternalMessage)(appConfig, cdpOutboundEvent, attributes, req.log); res.status(200).send({ status: 'OK' }); } catch (error) { if (error instanceof zod_1.ZodError) { req.log.error(error, 'Invalid request from CDP'); const formattedError = (0, exports.handleZodError)(error, req.log); if (formattedError) { res.status(400).send(formattedError); return; } } req.log.error(error, 'Error in handleCdpOutboundRequest'); throw error; } } async function handleInternalMessage(req, res) { const appConfig = res.app.get('appConfig'); const { message, attributes } = appConfig.routes.internal.getInternalMessageFromRequest(appConfig, req); const handler = appConfig.routes.internal.handlers[message.type]; const connectorId = new URL(message.connectorConfig.connection_url).pathname .split('/') .at(-1); req.log.info({ 'internal-message': { type: message.type, payload: message.payload, }, connectorId, }, `internal-message: ${message.type}, connectorId: ${connectorId}`); try { await handler(res.app.get('appConfig'), message.connectorConfig, message.payload, attributes, req.log); res.status(200).send({ status: 'OK' }); } catch (error) { req.log.error(error); if (error instanceof exceptions_1.TemporaryDeliveryFailure) { throw http_errors_1.default.InternalServerError(); } else { const formattedError = await appConfig.handlePermanentMessageDeliveryFailure(res.app.get('appConfig'), message.connectorConfig, message, attributes, req.log, error); if (formattedError) { res.status(400).send(formattedError); } else { // In the case of permanent delivery failure, we do not // want the caller to retry, so we respond with a 200 OK. res.status(200).send({ status: 200 }); } } } } async function handleStatus(_req, res) { const appConfig = res.app.get('appConfig'); res.status(200).send({ api: appConfig.appMetadata.name, version: appConfig.appMetadata.version, tagline: appConfig.appMetadata.tagline, }); } const formatZodError = (error, logger) => { const formattedError = { message: 'Validation error', errors: error.errors.map(err => ({ path: err.path.join('.'), message: err.message, })), }; logger.error(formattedError); return formattedError; }; exports.formatZodError = formatZodError; const handleZodError = (error, logger) => { if (error instanceof zod_1.ZodError) { const formatted = (0, exports.formatZodError)(error, logger); return formatted; } }; exports.handleZodError = handleZodError; //# sourceMappingURL=handlers.js.map