|
| 1 | +import { getThoughtSpotHost } from "./config"; |
| 2 | +import { getEmbedConfig } from "./embed/embedConfig"; |
| 3 | +import { InterceptedApiType, BaseViewConfig, EmbedConfig, InterceptV2Flags, EmbedEvent } from "./types"; |
| 4 | + |
| 5 | + |
| 6 | + |
| 7 | +const defaultUrls: Record<Exclude<InterceptedApiType, InterceptedApiType.ALL>, string[]> = { |
| 8 | + [InterceptedApiType.METADATA]: [ |
| 9 | + '/prism/?op=CreateAnswerSession', |
| 10 | + '/prism/?op=GetV2SourceDetail', |
| 11 | + ] as string[], |
| 12 | + [InterceptedApiType.DATA]: [ |
| 13 | + '/prism/?op=GetChartWithData', |
| 14 | + '/prism/?op=GetTableWithHeadlineData', |
| 15 | + '/prism/?op=LoadContextBook' |
| 16 | + ] as string[], |
| 17 | +}; |
| 18 | + |
| 19 | +const formatInterceptUrl = (url: string) => { |
| 20 | + const host = getThoughtSpotHost(getEmbedConfig()); |
| 21 | + if (url.startsWith('/')) return `${host}${url}`; |
| 22 | + return url; |
| 23 | +} |
| 24 | + |
| 25 | +export const processApiIntercept = async (eventData: any) => { |
| 26 | + |
| 27 | + return JSON.parse(eventData.data); |
| 28 | +} |
| 29 | + |
| 30 | +interface LegacyInterceptFlags { |
| 31 | + isOnBeforeGetVizDataInterceptEnabled: boolean; |
| 32 | +} |
| 33 | + |
| 34 | +const processInterceptUrls = (combinedUrls: (string | InterceptedApiType)[]) => { |
| 35 | + Object.entries(defaultUrls).forEach(([apiType, apiTypeUrls]) => { |
| 36 | + if (!combinedUrls.includes(apiType)) return; |
| 37 | + combinedUrls = combinedUrls.filter(url => url !== apiType); |
| 38 | + combinedUrls = [...combinedUrls, ...apiTypeUrls]; |
| 39 | + }) |
| 40 | + return combinedUrls.map(url => formatInterceptUrl(url)); |
| 41 | +} |
| 42 | +export const getInterceptInitData = (embedConfig: EmbedConfig, viewConfig: BaseViewConfig): InterceptV2Flags => { |
| 43 | + |
| 44 | + const enableApiIntercept = (embedConfig.enableApiIntercept || viewConfig.enableApiIntercept) && (viewConfig.enableApiIntercept !== false); |
| 45 | + |
| 46 | + if (!enableApiIntercept) return { |
| 47 | + enableApiIntercept: false, |
| 48 | + }; |
| 49 | + |
| 50 | + const combinedUrls = [...(embedConfig.interceptUrls || []), ...(viewConfig.interceptUrls || [])]; |
| 51 | + |
| 52 | + if ((viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) { |
| 53 | + combinedUrls.push(InterceptedApiType.DATA); |
| 54 | + } |
| 55 | + |
| 56 | + const shouldInterceptAll = combinedUrls.includes(InterceptedApiType.ALL); |
| 57 | + const interceptUrls = shouldInterceptAll ? [InterceptedApiType.ALL] : processInterceptUrls(combinedUrls); |
| 58 | + |
| 59 | + const interceptTimeout = embedConfig.interceptTimeout || viewConfig.interceptTimeout; |
| 60 | + |
| 61 | + return { |
| 62 | + interceptUrls, |
| 63 | + interceptTimeout, |
| 64 | + enableApiIntercept, |
| 65 | + }; |
| 66 | +} |
| 67 | + |
| 68 | +/** |
| 69 | + * |
| 70 | + * @param fetchInit |
| 71 | + */ |
| 72 | +const parseInterceptData = (eventDataString: any) => { |
| 73 | + |
| 74 | + try { |
| 75 | + const { input, init } = JSON.parse(eventDataString); |
| 76 | + |
| 77 | + init.body = JSON.parse(init.body); |
| 78 | + |
| 79 | + const parsedInit = { input, init }; |
| 80 | + return [parsedInit, null]; |
| 81 | + } catch (error) { |
| 82 | + return [null, error]; |
| 83 | + } |
| 84 | +} |
| 85 | + |
| 86 | +export const handleInterceptEvent = async (params: { eventData: any, executeEvent: (eventType: EmbedEvent, data: any) => void, embedConfig: EmbedConfig, viewConfig: BaseViewConfig, getUnsavedAnswerTml: (props: { sessionId?: string, vizId?: string }) => Promise<{ tml: string }> }) => { |
| 87 | + |
| 88 | + const { eventData, executeEvent, viewConfig, getUnsavedAnswerTml } = params; |
| 89 | + |
| 90 | + const [interceptData, bodyParseError] = parseInterceptData(eventData.data); |
| 91 | + |
| 92 | + if (bodyParseError) { |
| 93 | + executeEvent(EmbedEvent.Error, { |
| 94 | + error: 'Error parsing api intercept body', |
| 95 | + }); |
| 96 | + logger.error('Error parsing request body', bodyParseError); |
| 97 | + return; |
| 98 | + } |
| 99 | + |
| 100 | + const { input: requestUrl, init } = interceptData; |
| 101 | + |
| 102 | + const sessionId = init?.body?.variables?.session?.sessionId; |
| 103 | + const vizId = init?.body?.variables?.contextBookId; |
| 104 | + |
| 105 | + if (defaultUrls.DATA.includes(requestUrl) && (viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) { |
| 106 | + const answerTml = await getUnsavedAnswerTml({ sessionId, vizId }); |
| 107 | + executeEvent(EmbedEvent.OnBeforeGetVizDataIntercept, { data: { data: answerTml } }); |
| 108 | + } |
| 109 | + |
| 110 | + executeEvent(EmbedEvent.ApiIntercept, interceptData); |
| 111 | +} |
| 112 | + |
| 113 | +export const processLegacyInterceptResponse = (payload: any) => { |
| 114 | + |
| 115 | + const title = payload?.data?.errorText; |
| 116 | + const desc = payload?.data?.errorDescription; |
| 117 | + |
| 118 | + const payloadToSend = [{ |
| 119 | + data: {}, |
| 120 | + errors: [ |
| 121 | + { |
| 122 | + errorObj: { |
| 123 | + title, |
| 124 | + desc |
| 125 | + } |
| 126 | + } |
| 127 | + ], |
| 128 | + }]; |
| 129 | + |
| 130 | + return payloadToSend; |
| 131 | +} |
0 commit comments