UNPKG

@tableau/taco-toolkit

Version:
652 lines 57 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); var cors_1 = __importDefault(require("cors")); var express_1 = __importDefault(require("express")); var http_status_codes_1 = require("http-status-codes"); var node_http_1 = __importDefault(require("node:http")); var auth_credentials_1 = require("../../../shared/auth-credentials"); var auth_type_1 = require("../../../shared/enums/auth-type"); var caller_type_1 = require("../../../shared/enums/caller-type"); var connector_launch_status_1 = require("../../../shared/enums/connector-launch-status"); var eps_http_header_1 = require("../../../shared/enums/eps-http-header"); var error_codes_1 = require("../../../shared/errors/error-codes"); var error_source_1 = require("../../../shared/errors/error-source"); var status_code_1 = require("../../../shared/errors/status-code"); var log_entry_1 = require("../../../shared/logger/log-entry"); var log_highlight_1 = __importDefault(require("../../../shared/logger/log-highlight")); var log_level_1 = require("../../../shared/logger/log-level"); var utils_1 = require("../../../shared/logger/utils"); var eps_logger_1 = require("../../logging/eps-logger"); var network_adapter_1 = require("../../modules/network-adapter"); var eps_error_1 = require("../../types/eps-error"); var eps_error_info_1 = require("../../types/eps-error-info"); var position_size_1 = require("../../types/position-size"); var api_utils_1 = require("../../utils/api-utils"); var server_utils_1 = require("../../utils/server-utils"); var app_global_1 = __importDefault(require("../core/app-global")); var eps_api_utils_1 = require("./eps-api-utils"); var app_url_1 = require("./eps-handlers/app-url"); var close_connection_1 = require("./eps-handlers/close-connection"); var extract_handler_1 = require("./eps-handlers/extract-handler"); var forward_request_1 = require("./eps-handlers/forward-request"); var handler_utils_1 = require("./eps-handlers/handler-utils"); var launch_1 = require("./eps-handlers/launch"); var permission_1 = require("./eps-handlers/permission"); var EpsApi = /** @class */ (function () { function EpsApi(extractorLaunchedEvent, options) { this.app = (0, express_1.default)(); this.port = options.epsApiPort; this.apiOptions = options; this.extractorLaunchedEvent = extractorLaunchedEvent; this.extractHandler = new extract_handler_1.ExtractHandler(); this.initApiSettings(); this.initApiRoutes(); // register default error handlers this.app.use(api_utils_1.notFoundHandler); this.app.use(api_utils_1.errorHandler); } EpsApi.prototype.initApiSettings = function () { this.createCorsRules(); this.interceptRequests(); this.app.use(express_1.default.json()); }; EpsApi.prototype.initApiRoutes = function () { // ***** required routes for main service ***** this.createRoutePermission(); this.createRouteExtract(); this.createRouteLog(); this.createRouteExtractor(); this.createRouteClose(); this.createRouteStatus(); // ***** optional routes based on config ***** var _a = this.apiOptions, browserWatcherPort = _a.browserWatcherPort, staticServerOptions = _a.staticServerOptions, epsApiPort = _a.epsApiPort; if (staticServerOptions) { // root route is only needed when EPS needs to serve UI var networkAdapter = new network_adapter_1.NetworkAdapter(this.apiOptions.networkOptions); this.createRootRoute(networkAdapter); // route launch requires both browserWatcher and static server if (browserWatcherPort) { this.createRouteLaunch({ epsApiPort: epsApiPort, browserWatcherPort: browserWatcherPort, staticServerOptions: staticServerOptions, }); } else { this.createRouteAppUrl({ staticServerOptions: staticServerOptions, }); } } }; EpsApi.prototype.createCorsRules = function () { // TODO: Restrict to specific URL's this.app.use((0, cors_1.default)()); }; EpsApi.prototype.interceptRequests = function () { var _this = this; this.app.use((0, api_utils_1.getRequestLogger)(this.constructor.name, eps_api_utils_1.requestLogReplacer)); this.app.use(function (req, res, next) { if (_this.apiOptions.callerType === caller_type_1.CallerType.vizQLServer) { // Skip url checking for web authoring return next(); } // Request headers validation var callerIdHeader = req.headers[eps_http_header_1.EpsHttpHeader.CallerId]; if (callerIdHeader !== _this.apiOptions.callerId && callerIdHeader !== '0') { return (0, api_utils_1.sendBadRequest)(res, 'Missing or invalid caller-id in header'); } var epsInstanceIdHeader = req.headers[eps_http_header_1.EpsHttpHeader.EpsInstanceId]; if (epsInstanceIdHeader !== _this.apiOptions.epsInstanceId && epsInstanceIdHeader !== '0') { return (0, api_utils_1.sendBadRequest)(res, 'Missing eps-instance-id in header'); } next(); }); }; EpsApi.prototype.createRootRoute = function (networkAdapter) { var _this = this; /** * Route to forward client request to bypass CORS on the browsers. * It only support forwarding requests with method GET OR POST. * Request body must satisfy type ForwardedRequest. */ this.app.post('/', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var forwardedRequest, distinctConnectorName, apiPermission, forwardedResponse, statusCode_1, error, statusCode, response, e_1; return __generator(this, function (_a) { switch (_a.label) { case 0: forwardedRequest = req.body; if (!(0, forward_request_1.isValidForwardedRequest)(forwardedRequest)) { (0, api_utils_1.sendBadRequest)(res, "Invalid forwarded request: ".concat(forwardedRequest)); return [2 /*return*/]; } (0, forward_request_1.logForwardedRequest)(forwardedRequest); _a.label = 1; case 1: _a.trys.push([1, 4, , 5]); return [4 /*yield*/, this.getOrInitDistinctConnectorName(req)]; case 2: distinctConnectorName = _a.sent(); apiPermission = app_global_1.default.tacoInitializer.getConnectorConfig(distinctConnectorName).permission.api; return [4 /*yield*/, (0, forward_request_1.handleRequestForward)(networkAdapter, forwardedRequest, apiPermission)]; case 3: forwardedResponse = _a.sent(); if (forwardedResponse.state === 'error') { statusCode_1 = forwardedResponse.statusCode, error = forwardedResponse.error; res.status(statusCode_1).json({ error: error }); return [2 /*return*/]; } statusCode = forwardedResponse.statusCode, response = forwardedResponse.response; // note: the 'response' is a plain object typed as AjaxResponse which // is safe to be serialized res.status(statusCode).send(response); return [3 /*break*/, 5]; case 4: e_1 = _a.sent(); (0, api_utils_1.sendInternalServerError)(res, e_1); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }); /** * DEPRECATED! (since 2023.3, 246) * The latest sdk will hit the above route to forward requests. * This route still need to stay for now to support existing tacos in prod, * will be removed once all prod tacos are re-packed with the new SDK. */ this.app.get('/', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var _a, requestUrl, headersString, distinctConnectorName, apiPermission, forwardedRequest, forwardedResponse, statusCode_2, error, statusCode, response, headers, content, e_2; var _b; return __generator(this, function (_c) { switch (_c.label) { case 0: _a = req.query, requestUrl = _a.url, headersString = _a.headers; if (typeof requestUrl !== 'string') { (0, api_utils_1.sendBadRequest)(res, "Query param 'url' is required. ".concat(requestUrl)); return [2 /*return*/]; } if (headersString !== undefined && typeof headersString !== 'string') { (0, api_utils_1.sendBadRequest)(res, "Query param 'headers' must be a JSON string. ".concat(headersString)); return [2 /*return*/]; } _c.label = 1; case 1: _c.trys.push([1, 4, , 5]); return [4 /*yield*/, this.getOrInitDistinctConnectorName(req)]; case 2: distinctConnectorName = _c.sent(); apiPermission = app_global_1.default.tacoInitializer.getConnectorConfig(distinctConnectorName).permission.api; forwardedRequest = { method: 'GET', url: requestUrl, headers: headersString ? JSON.parse(headersString) : {}, }; return [4 /*yield*/, (0, forward_request_1.handleRequestForward)(networkAdapter, forwardedRequest, apiPermission)]; case 3: forwardedResponse = _c.sent(); if (forwardedResponse.state === 'error') { statusCode_2 = forwardedResponse.statusCode, error = forwardedResponse.error; res.status(statusCode_2).json({ error: error }); return [2 /*return*/]; } statusCode = forwardedResponse.statusCode, response = forwardedResponse.response; headers = __assign({}, response.headers); delete headers['content-encoding']; content = (_b = response.body) !== null && _b !== void 0 ? _b : response.text; res.status(statusCode).set(headers).send(content); return [3 /*break*/, 5]; case 4: e_2 = _c.sent(); (0, api_utils_1.sendInternalServerError)(res, e_2); return [3 /*break*/, 5]; case 5: return [2 /*return*/]; } }); }); }); }; EpsApi.prototype.createRoutePermission = function () { var _this = this; this.app.get('/permission', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var connectorClass, connectionId, tacoPath, permission, error_1; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); connectorClass = req.params.connectorClass; connectionId = req.headers[eps_http_header_1.EpsHttpHeader.ConnectionId]; tacoPath = (0, api_utils_1.getOptionalTacoPathHeader)(req); return [4 /*yield*/, (0, permission_1.handleGetPermission)({ connectorClass: connectorClass, connectionId: connectionId, tacoPath: tacoPath, })]; case 1: permission = _a.sent(); res.send(permission); return [3 /*break*/, 3]; case 2: error_1 = _a.sent(); handleError(error_1, req, res); return [3 /*break*/, 3]; case 3: return [2 /*return*/]; } }); }); }); }; EpsApi.prototype.createRouteLaunch = function (routeConfig) { var _this = this; this.app.post('/launch/:connectorClass', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var connectionData, connectorClass, connectionId, extractorMode, tacoPath, secrets, size, language, locale, launchResult, error_2; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); connectionData = (0, api_utils_1.getOptionalConnectionData)(req); connectorClass = req.params.connectorClass; connectionId = (0, api_utils_1.getRequiredStringHeader)(req, eps_http_header_1.EpsHttpHeader.ConnectionId, { allowEmpty: false, }); extractorMode = req.query.extractorMode; tacoPath = (0, api_utils_1.getRequiredTacoPathHeader)(req); return [4 /*yield*/, this.getSecrets(req)]; case 1: secrets = _a.sent(); size = (0, position_size_1.parsePositionSize)(req.query); language = (0, api_utils_1.getLocalizationHeader)(req, 'language', this.apiOptions.i18n.language); locale = (0, api_utils_1.getLocalizationHeader)(req, 'locale', this.apiOptions.i18n.locale); return [4 /*yield*/, (0, launch_1.handleLaunch)(this.extractorLaunchedEvent, { epsServiceInfo: { callerId: this.apiOptions.callerId, epsInstanceId: this.apiOptions.epsInstanceId, epsApiPort: this.port, staticServerId: routeConfig.staticServerOptions.staticServerId, staticServerPort: routeConfig.staticServerOptions.staticServerPort, browserWatcherPort: routeConfig.browserWatcherPort, }, launchUIOptions: { connectorClass: connectorClass, connectionId: connectionId, tacoPath: tacoPath, parentPositionSize: size, secrets: secrets, extractorMode: extractorMode, connectionData: connectionData, i18n: { language: language, locale: locale, }, }, })]; case 2: launchResult = _a.sent(); if (!launchResult) { return [2 /*return*/, res.status(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR).json(new eps_error_1.EPSError("Unknown error!", // possibly timeout new eps_error_info_1.EPSErrorInfo(handler_utils_1.ERROR_CODE_GENERAL_EXTRACTOR), connector_launch_status_1.ConnectorLaunchStatus.Error))]; } return [2 /*return*/, res.status(launchResult.httpStatusCode).json(launchResult.response)]; case 3: error_2 = _a.sent(); eps_logger_1.Logger.error(error_2); return [2 /*return*/, res .status(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR) .json(new eps_error_1.EPSError(error_2.toString(), new eps_error_info_1.EPSErrorInfo(handler_utils_1.ERROR_CODE_GENERAL_EXTRACTOR), connector_launch_status_1.ConnectorLaunchStatus.Error))]; case 4: return [2 /*return*/]; } }); }); }); }; EpsApi.prototype.createRouteAppUrl = function (routeConfig) { var _this = this; this.app.get('/web-authoring/app-url/:connectorClass', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var connectorClass, language, locale, pluginPath, connectionId, resp, error_3, statusCode; return __generator(this, function (_a) { switch (_a.label) { case 0: connectorClass = req.params.connectorClass; language = (0, api_utils_1.getLocalizationHeader)(req, 'language', this.apiOptions.i18n.language); locale = (0, api_utils_1.getLocalizationHeader)(req, 'locale', this.apiOptions.i18n.locale); pluginPath = (0, api_utils_1.getOptionalTacoPathHeader)(req); connectionId = req.headers[eps_http_header_1.EpsHttpHeader.ConnectionId]; _a.label = 1; case 1: _a.trys.push([1, 3, , 4]); return [4 /*yield*/, (0, app_url_1.getWebAuthoringAppUrl)({ connectionId: connectionId, connectorClass: connectorClass, pluginPath: pluginPath, staticServerOptions: routeConfig.staticServerOptions, i18n: { language: language, locale: locale, }, })]; case 2: resp = _a.sent(); eps_logger_1.Logger.info("Web Authoring Static Server Url: ".concat((0, api_utils_1.maskURL)(resp.connectorAppUrl))); // TODO: do we pass size? // const size = ConnectorConfig.windowSize(distinctConnectorName, connectorJsonFile) // const position = centerOnParent(size, options.parentPositionSize) return [2 /*return*/, res.status(http_status_codes_1.StatusCodes.OK).json(resp)]; case 3: error_3 = _a.sent(); statusCode = http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR; if (error_3 instanceof handler_utils_1.EpsHandlerError && error_3.httpStatusCode) { statusCode = error_3.httpStatusCode; } return [2 /*return*/, res.status(statusCode).json({ connectorName: connectorClass, status: connector_launch_status_1.ConnectorLaunchStatus.Error, error: "".concat(error_3), })]; case 4: return [2 /*return*/]; } }); }); }); }; /** * Usage: * * DELETE /extractor/{extractor IDs separated by comma} * * DELETE /extractor/ */ EpsApi.prototype.createRouteExtractor = function () { var _this = this; this.app.delete('/extractor/:extractorIds?', function (req, res) { var _a; try { var connectionId = (0, api_utils_1.getRequiredStringHeader)(req, eps_http_header_1.EpsHttpHeader.ConnectionId, { allowEmpty: false, }); var extractorIds = (_a = req.params.extractorIds) === null || _a === void 0 ? void 0 : _a.split(','); var resp = _this.extractHandler.handleTerminationRequest({ connectionId: connectionId, extractorIds: extractorIds }); return res.status(http_status_codes_1.StatusCodes.OK).json(resp); } catch (error) { handleError(error, req, res); } }); }; EpsApi.prototype.createRouteClose = function () { this.app.post('/close', function (req, res) { var connectionId = (0, api_utils_1.getRequiredStringHeader)(req, eps_http_header_1.EpsHttpHeader.ConnectionId, { allowEmpty: false, }); var reason = req.body.reason; var resp = (0, close_connection_1.closeConnection)({ connectionId: connectionId, reason: reason }); return res.status(http_status_codes_1.StatusCodes.OK).json(resp); }); }; EpsApi.prototype.createRouteExtract = function () { var _this = this; this.app.post('/extract/:connectorClass', function (req, res) { return __awaiter(_this, void 0, void 0, function () { var connectionId, tacoPath, connectionData, connectorClass, secrets, extractResonse, error_4; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 3, , 4]); connectionId = (0, api_utils_1.getRequiredStringHeader)(req, eps_http_header_1.EpsHttpHeader.ConnectionId, { allowEmpty: false }); tacoPath = (0, api_utils_1.getRequiredTacoPathHeader)(req); connectionData = (0, api_utils_1.getConnectionData)(req); connectorClass = req.params.connectorClass; return [4 /*yield*/, this.getSecrets(req)]; case 1: secrets = _a.sent(); return [4 /*yield*/, this.extractHandler.handleExtractRequest(this.extractorLaunchedEvent, { connectorClass: connectorClass, connectionId: connectionId, tacoPath: tacoPath, secrets: secrets, connectionData: connectionData, })]; case 2: extractResonse = _a.sent(); return [2 /*return*/, res.status(extractResonse.httpStatusCode).json(extractResonse.response)]; case 3: error_4 = _a.sent(); return [2 /*return*/, res .status(http_status_codes_1.StatusCodes.INTERNAL_SERVER_ERROR) .json(new eps_error_1.EPSError("".concat(error_4), new eps_error_info_1.EPSErrorInfo(handler_utils_1.ERROR_CODE_GENERAL_EXTRACTOR), connector_launch_status_1.ConnectorLaunchStatus.Error))]; case 4: return [2 /*return*/]; } }); }); }); }; /* * Content-Type needs to be application/json. * The body is a JSON array. Each element contains `severity`, `time`, and `message`. */ EpsApi.prototype.createRouteLog = function () { this.app.post('/log', function (req, res) { var body = req.body; if (!Array.isArray(body)) { (0, api_utils_1.sendBadRequest)(res, 'Input must be an array of log entries.'); return; } var now = Date.now(); var logEntries = []; body.forEach(function (entry) { if (!(0, log_entry_1.isLogMessage)(entry)) { eps_logger_1.Logger.warn("'/log' received a log entry in an invalid shape: ".concat((0, utils_1.getLogMessageString)(entry))); return; } logEntries.push({ message: entry.message, timestamp: entry.timestamp || now, level: entry.level || log_level_1.LogLevel.INFO, }); }); logEntries .sort(function (a, b) { return a.timestamp - b.timestamp; }) .forEach(function (entry) { var message = entry.message, timestamp = entry.timestamp, level = entry.level; switch (level) { case log_level_1.LogLevel.DEBUG: eps_logger_1.Logger.debug(message, { timestamp: timestamp, }); break; case log_level_1.LogLevel.ERROR: eps_logger_1.Logger.logEPSError(status_code_1.StatusCode.Cancelled, error_source_1.ErrorSources.Client, error_codes_1.ErrorCodes.MDDL9LNB, message, { timestamp: timestamp, }); break; case log_level_1.LogLevel.INFO: eps_logger_1.Logger.info(message, { timestamp: timestamp }); break; case log_level_1.LogLevel.WARNING: eps_logger_1.Logger.warn(message, { timestamp: timestamp }); break; } }); return res.status(http_status_codes_1.StatusCodes.OK).send(); }); }; /** * The route for EPS health check. */ EpsApi.prototype.createRouteStatus = function () { this.app.get('/status', function (req, res) { res.send(true); }); }; EpsApi.prototype.getSecrets = function (req) { return __awaiter(this, void 0, void 0, function () { var distinctConnectorName, authConfig, secrets; return __generator(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, this.getOrInitDistinctConnectorName(req)]; case 1: distinctConnectorName = _a.sent(); authConfig = app_global_1.default.tacoInitializer.getConnectorConfig(distinctConnectorName).auth; if (!authConfig) { eps_logger_1.Logger.error("Invalid auth config for ".concat(req.params.connectorClass, ": ").concat(authConfig)); } secrets = extractSecrets(req, authConfig); return [2 /*return*/, secrets]; } }); }); }; EpsApi.prototype.start = function () { return __awaiter(this, void 0, void 0, function () { var server, error_5; return __generator(this, function (_a) { switch (_a.label) { case 0: _a.trys.push([0, 2, , 3]); server = node_http_1.default.createServer(this.app); return [4 /*yield*/, (0, server_utils_1.startHttpServer)(server, this.port)]; case 1: _a.sent(); eps_logger_1.Logger.info("EPS Api is listening on port ".concat(this.port, "..."), { highlight: log_highlight_1.default.RED_ON_YELLOW, }); return [3 /*break*/, 3]; case 2: error_5 = _a.sent(); error_5.message = "Failed to start EPS API on port ".concat(this.port, ". ").concat(error_5); throw error_5; case 3: return [2 /*return*/]; } }); }); }; EpsApi.prototype.getOrInitDistinctConnectorName = function (req) { return __awaiter(this, void 0, void 0, function () { var connectionId, connectorClass, tacoPath, distinctConnectorName, _a, appLanguage, appLocale, language, locale; return __generator(this, function (_b) { switch (_b.label) { case 0: connectionId = req.headers[eps_http_header_1.EpsHttpHeader.ConnectionId]; connectorClass = req.params.connectorClass; tacoPath = (0, api_utils_1.getOptionalTacoPathHeader)(req); return [4 /*yield*/, (0, handler_utils_1.getOrInitializeDistinctConnectorName)({ connectionId: connectionId, tacoPath: tacoPath, connectorClass: connectorClass, })]; case 1: distinctConnectorName = _b.sent(); if ((0, api_utils_1.hasLocalizationHeader)(req)) { _a = this.apiOptions.i18n, appLanguage = _a.language, appLocale = _a.locale; language = (0, api_utils_1.getLocalizationHeader)(req, 'language', appLanguage); locale = (0, api_utils_1.getLocalizationHeader)(req, 'locale', appLocale); app_global_1.default.tacoInitializer.adaptLocalizedConnector(distinctConnectorName, { language: language, locale: locale }); } return [2 /*return*/, distinctConnectorName]; } }); }); }; return EpsApi; }()); exports.default = EpsApi; function handleError(error, req, res) { if (error instanceof handler_utils_1.EpsHandlerError) { var status_1 = error.httpStatusCode; if (status_1 === http_status_codes_1.StatusCodes.BAD_REQUEST) { (0, api_utils_1.sendBadRequest)(res, error); return; } if (status_1 === http_status_codes_1.StatusCodes.NOT_FOUND) { (0, api_utils_1.sendNotFound)(res, error.message); return; } } if (error instanceof Error) { (0, api_utils_1.sendInternalServerError)(res, error); return; } (0, api_utils_1.sendInternalServerError)(res, "".concat(error)); } function extractSecrets(req, auth) { if ((auth === null || auth === void 0 ? void 0 : auth.type) === auth_type_1.AuthType.oauth2) { var secrets = (0, auth_credentials_1.extractOAuthSecretsFromHeader)(req.headers); //TODO (W-14199268): for quickbooks need realm id in secrets, will be removed once we support arbitrary oauth tokens var realmid = req.headers['realmid']; if (typeof realmid === 'string') { ; secrets['realmid'] = realmid; } // for oauth check oauth tokens in the headers first and if not exist then check secrets object if (secrets !== undefined && secrets['access-token']) { eps_logger_1.Logger.info("".concat(req.path, " Secrets exists in the request header for Oauth")); return secrets; } else { eps_logger_1.Logger.info("Secrets not found the in the request header for OAuth, checking secrets object"); return parseSecrets(req); } } return parseSecrets(req); } function parseSecrets(req) { // Warning: In this context, secrets is not checked to be a SecretsType. It only needs to be compatible with the connector. // We could add '| object' to SecretsType. var hasSecrets = false; var requestSecretsRaw = req.header('secrets'); var secrets; if (requestSecretsRaw) { try { secrets = JSON.parse(requestSecretsRaw); hasSecrets = secrets !== undefined && Object.keys(secrets).length > 0; } catch (err) { // Don't dump the secrets or the err message! eps_logger_1.Logger.logEPSError(status_code_1.StatusCode.Cancelled, error_source_1.ErrorSources.Configuration, error_codes_1.ErrorCodes.TR48H3Q3, 'Could not parse secrets. Optional "secrets" header should be valid JSON.'); } } eps_logger_1.Logger.info("".concat(req.path, " Found secrets in the request header.secrets: ").concat(hasSecrets)); return hasSecrets ? secrets : undefined; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXBzLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9lcHMvbWFpbi9hcGkvZXBzLWFwaS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUEsOENBQXVCO0FBQ3ZCLG9EQUE2QjtBQUM3Qix1REFBK0M7QUFFL0Msd0RBQTRCO0FBRTVCLHFFQUFnRjtBQUNoRiw2REFBMEQ7QUFDMUQsaUVBQThEO0FBQzlELHlGQUFxRjtBQUNyRix5RUFBcUU7QUFDckUsa0VBQStEO0FBQy9ELG9FQUFrRTtBQUNsRSxrRUFBK0Q7QUFDL0QsOERBQXlFO0FBQ3pFLHVGQUFnRTtBQUNoRSw4REFBMkQ7QUFDM0Qsc0RBQWtFO0FBSWxFLHVEQUFpRDtBQUNqRCxpRUFBOEQ7QUFFOUQsbURBQWdEO0FBQ2hELDZEQUF5RDtBQUV6RCwyREFBNkQ7QUFDN0QsbURBZThCO0FBQzlCLHlEQUEwRDtBQUMxRCxrRUFBMEM7QUFDMUMsaURBQW9EO0FBQ3BELGtEQUFvRztBQUNwRyxvRUFBaUU7QUFDakUsa0VBQStEO0FBQy9ELGtFQUFtSDtBQUNuSCw4REFJcUM7QUFDckMsZ0RBQXVFO0FBQ3ZFLHdEQUErRDtBQUUvRDtJQU9FLGdCQUFZLHNCQUFvQyxFQUFFLE9BQXNCO1FBQ3RFLElBQUksQ0FBQyxHQUFHLEdBQUcsSUFBQSxpQkFBTyxHQUFFLENBQUE7UUFDcEIsSUFBSSxDQUFDLElBQUksR0FBRyxPQUFPLENBQUMsVUFBVSxDQUFBO1FBQzlCLElBQUksQ0FBQyxVQUFVLEdBQUcsT0FBTyxDQUFBO1FBQ3pCLElBQUksQ0FBQyxzQkFBc0IsR0FBRyxzQkFBc0IsQ0FBQTtRQUNwRCxJQUFJLENBQUMsY0FBYyxHQUFHLElBQUksZ0NBQWMsRUFBRSxDQUFBO1FBRTFDLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQTtRQUN0QixJQUFJLENBQUMsYUFBYSxFQUFF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