@thoughtspot/visual-embed-sdk
Version:
ThoughtSpot Embed SDK
185 lines • 7.6 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.processLegacyInterceptResponse = exports.processApiInterceptResponse = exports.handleInterceptEvent = exports.getInterceptInitData = void 0;
const config_1 = require("./config");
const embedConfig_1 = require("./embed/embedConfig");
const errors_1 = require("./errors");
const types_1 = require("./types");
const utils_1 = require("./utils");
const logger_1 = require("./utils/logger");
const DefaultInterceptUrlsMap = {
[types_1.InterceptedApiType.AnswerData]: [
'/prism/?op=GetChartWithData',
'/prism/?op=GetTableWithHeadlineData',
'/prism/?op=GetTableWithData',
],
[types_1.InterceptedApiType.LiveboardData]: [
'/prism/?op=LoadContextBook'
],
};
const formatInterceptUrl = (url) => {
const host = (0, config_1.getThoughtSpotHost)((0, embedConfig_1.getEmbedConfig)());
if (url.startsWith('/'))
return `${host}${url}`;
return url;
};
/**
* Converts user passed url values to proper urls
* [ANSER_DATA] => ['https://host/pris/op?=op']
* @param interceptUrls
* @returns
*/
const processInterceptUrls = (interceptUrls) => {
let processedUrls = [...interceptUrls];
Object.entries(DefaultInterceptUrlsMap).forEach(([apiType, apiTypeUrls]) => {
if (!processedUrls.includes(apiType))
return;
processedUrls = processedUrls.filter(url => url !== apiType);
processedUrls = [...processedUrls, ...apiTypeUrls];
});
return processedUrls.map(url => formatInterceptUrl(url));
};
/**
* Returns the data to be sent to embed to setup intercepts
* the urls to intercept, timeout etc
* @param viewConfig
* @returns
*/
const getInterceptInitData = (viewConfig) => {
const combinedUrls = [...(viewConfig.interceptUrls || [])];
if (viewConfig.isOnBeforeGetVizDataInterceptEnabled) {
combinedUrls.push(types_1.InterceptedApiType.AnswerData);
}
const shouldInterceptAll = combinedUrls.includes(types_1.InterceptedApiType.ALL);
const interceptUrls = shouldInterceptAll ? [types_1.InterceptedApiType.ALL] : processInterceptUrls(combinedUrls);
const interceptTimeout = viewConfig.interceptTimeout;
return {
interceptUrls,
interceptTimeout,
};
};
exports.getInterceptInitData = getInterceptInitData;
const parseJson = (jsonString) => {
try {
const json = JSON.parse(jsonString);
return [json, null];
}
catch (error) {
return [null, error];
}
};
/**
* Parse the api intercept data and return the parsed data and error if any
* Embed returns the input and init from the fetch call
*/
const parseInterceptData = (eventDataString) => {
try {
const [parsedData, error] = parseJson(eventDataString);
if (error) {
return [null, error];
}
const { input, init } = parsedData;
const [parsedBody, bodyParseError] = parseJson(init.body);
if (!bodyParseError) {
init.body = parsedBody;
}
const parsedInit = { input, init };
return [parsedInit, null];
}
catch (error) {
return [null, error];
}
};
const getUrlType = (url) => {
for (const [apiType, apiTypeUrls] of Object.entries(DefaultInterceptUrlsMap)) {
if (apiTypeUrls.includes(url))
return apiType;
}
// TODO: have a unknown type maybe ??
return types_1.InterceptedApiType.ALL;
};
/**
* Handle Api intercept event and simulate legacy onBeforeGetVizDataIntercept event
*
* embed sends -> ApiIntercept -> we send
* ApiIntercept
* OnBeforeGetVizDataIntercept (if url is part of DefaultUrlMap.AnswerData)
*
* @param params
* @returns
*/
const handleInterceptEvent = async (params) => {
var _a, _b, _c, _d, _e;
const { eventData, executeEvent, viewConfig, getUnsavedAnswerTml } = params;
const [interceptData, bodyParseError] = parseInterceptData(eventData.data);
if (bodyParseError) {
const errorDetails = {
errorType: types_1.ErrorDetailsTypes.API,
message: errors_1.ERROR_MESSAGE.ERROR_PARSING_API_INTERCEPT_BODY,
code: types_1.EmbedErrorCodes.PARSING_API_INTERCEPT_BODY_ERROR,
error: errors_1.ERROR_MESSAGE.ERROR_PARSING_API_INTERCEPT_BODY,
};
executeEvent(types_1.EmbedEvent.Error, errorDetails);
logger_1.logger.error('Error parsing request body', bodyParseError);
return;
}
const { input: requestUrl, init } = interceptData;
const sessionId = (_c = (_b = (_a = init === null || init === void 0 ? void 0 : init.body) === null || _a === void 0 ? void 0 : _a.variables) === null || _b === void 0 ? void 0 : _b.session) === null || _c === void 0 ? void 0 : _c.sessionId;
const vizId = (_e = (_d = init === null || init === void 0 ? void 0 : init.body) === null || _d === void 0 ? void 0 : _d.variables) === null || _e === void 0 ? void 0 : _e.contextBookId;
const answerDataUrls = DefaultInterceptUrlsMap[types_1.InterceptedApiType.AnswerData];
const legacyInterceptEnabled = viewConfig.isOnBeforeGetVizDataInterceptEnabled;
const isAnswerDataUrl = answerDataUrls.includes(requestUrl);
const sendLegacyIntercept = isAnswerDataUrl && legacyInterceptEnabled;
if (sendLegacyIntercept) {
const answerTml = await getUnsavedAnswerTml({ sessionId, vizId });
// Build the legacy payload for backwards compatibility
const legacyPayload = {
data: {
data: answerTml,
status: utils_1.embedEventStatus.END,
type: types_1.EmbedEvent.OnBeforeGetVizDataIntercept
}
};
executeEvent(types_1.EmbedEvent.OnBeforeGetVizDataIntercept, legacyPayload);
}
const urlType = getUrlType(requestUrl);
executeEvent(types_1.EmbedEvent.ApiIntercept, { ...interceptData, urlType });
};
exports.handleInterceptEvent = handleInterceptEvent;
/**
* Support both the legacy and new format of the api intercept response
* @param payload
* @returns
*/
const processApiInterceptResponse = (payload) => {
var _a;
const isLegacyFormat = (_a = payload === null || payload === void 0 ? void 0 : payload.data) === null || _a === void 0 ? void 0 : _a.error;
if (isLegacyFormat) {
return (0, exports.processLegacyInterceptResponse)(payload);
}
return payload;
};
exports.processApiInterceptResponse = processApiInterceptResponse;
const processLegacyInterceptResponse = (payload) => {
var _a, _b, _c, _d, _e;
const errorText = (_b = (_a = payload === null || payload === void 0 ? void 0 : payload.data) === null || _a === void 0 ? void 0 : _a.error) === null || _b === void 0 ? void 0 : _b.errorText;
const errorDescription = (_d = (_c = payload === null || payload === void 0 ? void 0 : payload.data) === null || _c === void 0 ? void 0 : _c.error) === null || _d === void 0 ? void 0 : _d.errorDescription;
const payloadToSend = {
execute: (_e = payload === null || payload === void 0 ? void 0 : payload.data) === null || _e === void 0 ? void 0 : _e.execute,
response: {
body: {
errors: [
{
title: errorText,
description: errorDescription,
isUserError: true,
},
],
data: {},
},
},
};
return { data: payloadToSend };
};
exports.processLegacyInterceptResponse = processLegacyInterceptResponse;
//# sourceMappingURL=api-intercept.js.map