@tableau/taco-toolkit
Version:
Tableau Connector Toolkit
652 lines • 57 kB
JavaScript
"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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