• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

thoughtspot / visual-embed-sdk / #2615

15 Oct 2025 10:51AM UTC coverage: 92.334% (-1.8%) from 94.158%
#2615

Pull #328

sastaachar
SCAL-269016 : update
Pull Request #328: SCAL-269016 : Intercept v2

915 of 1098 branches covered (83.33%)

Branch coverage included in aggregate %.

34 of 72 new or added lines in 6 files covered. (47.22%)

8 existing lines in 3 files now uncovered.

2530 of 2633 relevant lines covered (96.09%)

68.85 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

13.82
/src/api-intercept.ts
1
import { getThoughtSpotHost } from "./config";
14✔
2
import { getEmbedConfig } from "./embed/embedConfig";
14✔
3
import { InterceptedApiType, BaseViewConfig, EmbedConfig, InterceptV2Flags, EmbedEvent } from "./types";
14✔
4
import { logger } from "./utils/logger";
14✔
5

6

7
const defaultUrls: Record<Exclude<InterceptedApiType, InterceptedApiType.ALL>, string[]> = {
14✔
8
    [InterceptedApiType.METADATA]: [
9
        '/prism/?op=CreateAnswerSession',
10
        '/prism/?op=GetV2SourceDetail',
11
    ] as string[],
12
    [InterceptedApiType.ANSWER_DATA]: [
13
        '/prism/?op=GetChartWithData',
14
        '/prism/?op=GetTableWithHeadlineData',
15
    ] as string[],
16
    [InterceptedApiType.LIVEBOARD_DATA]: [
17
        '/prism/?op=LoadContextBook'
18
    ] as string[],
19
};
20

21
const formatInterceptUrl = (url: string) => {
14✔
NEW
22
    const host = getThoughtSpotHost(getEmbedConfig());
×
NEW
23
    if (url.startsWith('/')) return `${host}${url}`;
×
NEW
24
    return url;
×
25
}
26

27
export const processApiIntercept = async (eventData: any) => {
14✔
28

NEW
29
    return JSON.parse(eventData.data);
×
30
}
31

32
interface LegacyInterceptFlags {
33
    isOnBeforeGetVizDataInterceptEnabled: boolean;
34
}
35

36
const processInterceptUrls = (interceptUrls: (string | InterceptedApiType)[]) => {
14✔
NEW
37
    let processedUrls = [...interceptUrls];
×
NEW
38
    Object.entries(defaultUrls).forEach(([apiType, apiTypeUrls]) => {
×
NEW
39
        if (!processedUrls.includes(apiType)) return;
×
NEW
40
        processedUrls = processedUrls.filter(url => url !== apiType);
×
NEW
41
        processedUrls = [...processedUrls, ...apiTypeUrls];
×
42
    })
NEW
43
    return processedUrls.map(url => formatInterceptUrl(url));
×
44
}
45
export const getInterceptInitData = (embedConfig: EmbedConfig, viewConfig: BaseViewConfig): InterceptV2Flags => {
14✔
46

47
    const enableApiIntercept = (embedConfig.enableApiIntercept || viewConfig.enableApiIntercept) && (viewConfig.enableApiIntercept !== false);
288!
48

49
    if (!enableApiIntercept) return {
288✔
50
        enableApiIntercept: false,
NEW
51
    };
×
52

NEW
53
    const combinedUrls = [...(embedConfig.interceptUrls || []), ...(viewConfig.interceptUrls || [])];
×
NEW
54

×
55
    if ((viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) {
56
        combinedUrls.push(InterceptedApiType.ANSWER_DATA);
NEW
57
    }
×
NEW
58

×
59
    const shouldInterceptAll = combinedUrls.includes(InterceptedApiType.ALL);
NEW
60
    const interceptUrls = shouldInterceptAll ? [InterceptedApiType.ALL] : processInterceptUrls(combinedUrls);
×
61

NEW
62
    const interceptTimeout = embedConfig.interceptTimeout || viewConfig.interceptTimeout;
×
63

64
    return {
65
        interceptUrls,
66
        interceptTimeout,
67
        enableApiIntercept,
68
    };
69
}
70

71
/**
72
 * 
73
 * @param fetchInit 
14✔
74
 */
NEW
75
const parseInterceptData = (eventDataString: any) => {
×
NEW
76

×
77
    try {
NEW
78
        const { input, init } = JSON.parse(eventDataString);
×
79

NEW
80
        init.body = JSON.parse(init.body);
×
NEW
81

×
82
        const parsedInit = { input, init };
NEW
83
        return [parsedInit, null];
×
84
    } catch (error) {
85
        return [null, error];
86
    }
87
}
14✔
88

NEW
89
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 }> }) => {
×
90

NEW
91
    const { eventData, executeEvent, viewConfig, getUnsavedAnswerTml } = params;
×
92

NEW
93
    const [interceptData, bodyParseError] = parseInterceptData(eventData.data);
×
NEW
94

×
95
    if (bodyParseError) {
96
        executeEvent(EmbedEvent.Error, {
NEW
97
            error: 'Error parsing api intercept body',
×
NEW
98
        });
×
99
        logger.error('Error parsing request body', bodyParseError);
100
        return;
NEW
101
    }
×
102

NEW
103
    const { input: requestUrl, init } = interceptData;
×
NEW
104

×
105
    const sessionId = init?.body?.variables?.session?.sessionId;
NEW
106
    const vizId = init?.body?.variables?.contextBookId;
×
NEW
107

×
NEW
108
    if (defaultUrls.ANSWER_DATA.includes(requestUrl) && (viewConfig as LegacyInterceptFlags).isOnBeforeGetVizDataInterceptEnabled) {
×
109
        const answerTml = await getUnsavedAnswerTml({ sessionId, vizId });
110
        executeEvent(EmbedEvent.OnBeforeGetVizDataIntercept, { data: { data: answerTml } });
NEW
111
    }
×
112

113
    executeEvent(EmbedEvent.ApiIntercept, interceptData);
114
}
14✔
115

NEW
116
export const processLegacyInterceptResponse = (payload: any) => {
×
117

×
118
    const payloadToSend = {
119
        execute: payload?.data?.execute,
120
        response: {
121
            body: {
122
                errors: [
×
123
                    {
×
124
                        title: payload?.data?.errorText,
125
                        message: payload?.data?.errorDescription,
126
                        isUserError: true,
127
                    },
128
                ],
129
                data: {},
130
            },
131
        },
132
    };
NEW
133

×
134

135
    return { data: payloadToSend };
136
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc