UNPKG

@thoughtspot/visual-embed-sdk

Version:
178 lines 7.05 kB
import { getThoughtSpotHost } from "./config"; import { getEmbedConfig } from "./embed/embedConfig"; import { ERROR_MESSAGE } from "./errors"; import { InterceptedApiType, EmbedEvent, EmbedErrorCodes, ErrorDetailsTypes } from "./types"; import { embedEventStatus } from "./utils"; import { logger } from "./utils/logger"; const DefaultInterceptUrlsMap = { [InterceptedApiType.AnswerData]: [ '/prism/?op=GetChartWithData', '/prism/?op=GetTableWithHeadlineData', '/prism/?op=GetTableWithData', ], [InterceptedApiType.LiveboardData]: [ '/prism/?op=LoadContextBook' ], }; const formatInterceptUrl = (url) => { const host = getThoughtSpotHost(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 */ export const getInterceptInitData = (viewConfig) => { const combinedUrls = [...(viewConfig.interceptUrls || [])]; if (viewConfig.isOnBeforeGetVizDataInterceptEnabled) { combinedUrls.push(InterceptedApiType.AnswerData); } const shouldInterceptAll = combinedUrls.includes(InterceptedApiType.ALL); const interceptUrls = shouldInterceptAll ? [InterceptedApiType.ALL] : processInterceptUrls(combinedUrls); const interceptTimeout = viewConfig.interceptTimeout; return { interceptUrls, interceptTimeout, }; }; 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 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 */ export 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: ErrorDetailsTypes.API, message: ERROR_MESSAGE.ERROR_PARSING_API_INTERCEPT_BODY, code: EmbedErrorCodes.PARSING_API_INTERCEPT_BODY_ERROR, error: ERROR_MESSAGE.ERROR_PARSING_API_INTERCEPT_BODY, }; executeEvent(EmbedEvent.Error, errorDetails); 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[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: embedEventStatus.END, type: EmbedEvent.OnBeforeGetVizDataIntercept } }; executeEvent(EmbedEvent.OnBeforeGetVizDataIntercept, legacyPayload); } const urlType = getUrlType(requestUrl); executeEvent(EmbedEvent.ApiIntercept, { ...interceptData, urlType }); }; /** * Support both the legacy and new format of the api intercept response * @param payload * @returns */ export 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 processLegacyInterceptResponse(payload); } return payload; }; export 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 }; }; //# sourceMappingURL=api-intercept.js.map