@thoughtspot/visual-embed-sdk 1.45.0 → 1.45.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cjs/package.json +2 -2
- package/cjs/src/authToken.d.ts +1 -1
- package/cjs/src/authToken.d.ts.map +1 -1
- package/cjs/src/authToken.js +2 -2
- package/cjs/src/authToken.js.map +1 -1
- package/cjs/src/authToken.spec.js +71 -0
- package/cjs/src/authToken.spec.js.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.d.ts +3 -3
- package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts +8 -8
- package/cjs/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.js +18 -18
- package/cjs/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js +7 -7
- package/cjs/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/cjs/src/embed/liveboard.d.ts +2 -2
- package/cjs/src/embed/liveboard.d.ts.map +1 -1
- package/cjs/src/embed/liveboard.js +2 -2
- package/cjs/src/embed/liveboard.js.map +1 -1
- package/cjs/src/embed/liveboard.spec.js +1 -1
- package/cjs/src/embed/liveboard.spec.js.map +1 -1
- package/cjs/src/embed/ts-embed.d.ts +23 -2
- package/cjs/src/embed/ts-embed.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.js +64 -22
- package/cjs/src/embed/ts-embed.js.map +1 -1
- package/cjs/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/cjs/src/embed/ts-embed.spec.js +138 -19
- package/cjs/src/embed/ts-embed.spec.js.map +1 -1
- package/cjs/src/index.d.ts +2 -2
- package/cjs/src/index.d.ts.map +1 -1
- package/cjs/src/index.js +3 -2
- package/cjs/src/index.js.map +1 -1
- package/cjs/src/types.d.ts +164 -2
- package/cjs/src/types.d.ts.map +1 -1
- package/cjs/src/types.js +43 -1
- package/cjs/src/types.js.map +1 -1
- package/cjs/src/utils/processTrigger.d.ts +3 -2
- package/cjs/src/utils/processTrigger.d.ts.map +1 -1
- package/cjs/src/utils/processTrigger.js +4 -2
- package/cjs/src/utils/processTrigger.js.map +1 -1
- package/cjs/src/utils.d.ts +5 -1
- package/cjs/src/utils.d.ts.map +1 -1
- package/cjs/src/utils.js +8 -1
- package/cjs/src/utils.js.map +1 -1
- package/dist/{index-Dk-SLdNk.js → index-BdkKLLo1.js} +1 -1
- package/dist/src/authToken.d.ts +1 -1
- package/dist/src/authToken.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/contracts.d.ts +3 -3
- package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/dist/src/embed/hostEventClient/host-event-client.d.ts +8 -8
- package/dist/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/dist/src/embed/liveboard.d.ts +2 -2
- package/dist/src/embed/liveboard.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.d.ts +23 -2
- package/dist/src/embed/ts-embed.d.ts.map +1 -1
- package/dist/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/dist/src/index.d.ts +2 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/types.d.ts +164 -2
- package/dist/src/types.d.ts.map +1 -1
- package/dist/src/utils/processTrigger.d.ts +3 -2
- package/dist/src/utils/processTrigger.d.ts.map +1 -1
- package/dist/src/utils.d.ts +5 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/tsembed-react.es.js +140 -49
- package/dist/tsembed-react.js +139 -48
- package/dist/tsembed.es.js +155 -64
- package/dist/tsembed.js +29640 -29549
- package/dist/visual-embed-sdk-react-full.d.ts +196 -13
- package/dist/visual-embed-sdk-react.d.ts +196 -13
- package/dist/visual-embed-sdk.d.ts +196 -13
- package/lib/package.json +2 -2
- package/lib/src/authToken.d.ts +1 -1
- package/lib/src/authToken.d.ts.map +1 -1
- package/lib/src/authToken.js +2 -2
- package/lib/src/authToken.js.map +1 -1
- package/lib/src/authToken.spec.js +72 -1
- package/lib/src/authToken.spec.js.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.d.ts +3 -3
- package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.d.ts +8 -8
- package/lib/src/embed/hostEventClient/host-event-client.d.ts.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.js +18 -18
- package/lib/src/embed/hostEventClient/host-event-client.js.map +1 -1
- package/lib/src/embed/hostEventClient/host-event-client.spec.js +7 -7
- package/lib/src/embed/hostEventClient/host-event-client.spec.js.map +1 -1
- package/lib/src/embed/liveboard.d.ts +2 -2
- package/lib/src/embed/liveboard.d.ts.map +1 -1
- package/lib/src/embed/liveboard.js +2 -2
- package/lib/src/embed/liveboard.js.map +1 -1
- package/lib/src/embed/liveboard.spec.js +1 -1
- package/lib/src/embed/liveboard.spec.js.map +1 -1
- package/lib/src/embed/ts-embed.d.ts +23 -2
- package/lib/src/embed/ts-embed.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.js +64 -22
- package/lib/src/embed/ts-embed.js.map +1 -1
- package/lib/src/embed/ts-embed.spec.d.ts.map +1 -1
- package/lib/src/embed/ts-embed.spec.js +139 -20
- package/lib/src/embed/ts-embed.spec.js.map +1 -1
- package/lib/src/index.d.ts +2 -2
- package/lib/src/index.d.ts.map +1 -1
- package/lib/src/index.js +2 -2
- package/lib/src/index.js.map +1 -1
- package/lib/src/types.d.ts +164 -2
- package/lib/src/types.d.ts.map +1 -1
- package/lib/src/types.js +42 -0
- package/lib/src/types.js.map +1 -1
- package/lib/src/utils/processTrigger.d.ts +3 -2
- package/lib/src/utils/processTrigger.d.ts.map +1 -1
- package/lib/src/utils/processTrigger.js +4 -2
- package/lib/src/utils/processTrigger.js.map +1 -1
- package/lib/src/utils.d.ts +5 -1
- package/lib/src/utils.d.ts.map +1 -1
- package/lib/src/utils.js +6 -0
- package/lib/src/utils.js.map +1 -1
- package/package.json +2 -2
- package/src/authToken.spec.ts +91 -2
- package/src/authToken.ts +2 -2
- package/src/embed/hostEventClient/contracts.ts +4 -4
- package/src/embed/hostEventClient/host-event-client.spec.ts +7 -1
- package/src/embed/hostEventClient/host-event-client.ts +22 -11
- package/src/embed/liveboard.spec.ts +1 -1
- package/src/embed/liveboard.ts +5 -3
- package/src/embed/ts-embed.spec.ts +184 -8
- package/src/embed/ts-embed.ts +81 -24
- package/src/index.ts +2 -0
- package/src/types.ts +171 -0
- package/src/utils/processTrigger.ts +6 -3
- package/src/utils.ts +8 -0
|
@@ -15,6 +15,8 @@ import {
|
|
|
15
15
|
SageViewConfig,
|
|
16
16
|
SearchViewConfig,
|
|
17
17
|
AnswerService,
|
|
18
|
+
SpotterEmbed,
|
|
19
|
+
SpotterEmbedViewConfig,
|
|
18
20
|
} from '../index';
|
|
19
21
|
import {
|
|
20
22
|
Action,
|
|
@@ -31,6 +33,7 @@ import {
|
|
|
31
33
|
DefaultAppInitData,
|
|
32
34
|
ErrorDetailsTypes,
|
|
33
35
|
EmbedErrorCodes,
|
|
36
|
+
ContextObject,
|
|
34
37
|
} from '../types';
|
|
35
38
|
import {
|
|
36
39
|
executeAfterWait,
|
|
@@ -64,6 +67,7 @@ import { UIPassthroughEvent } from './hostEventClient/contracts';
|
|
|
64
67
|
import * as sessionInfoService from '../utils/sessionInfoService';
|
|
65
68
|
import * as authToken from '../authToken';
|
|
66
69
|
import * as apiIntercept from '../api-intercept';
|
|
70
|
+
import * as processData from '../utils/processData';
|
|
67
71
|
|
|
68
72
|
jest.mock('../utils/processTrigger');
|
|
69
73
|
|
|
@@ -204,6 +208,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
204
208
|
parameters: payload,
|
|
205
209
|
type: UIPassthroughEvent.PinAnswerToLiveboard,
|
|
206
210
|
},
|
|
211
|
+
undefined,
|
|
207
212
|
);
|
|
208
213
|
});
|
|
209
214
|
});
|
|
@@ -224,6 +229,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
224
229
|
HostEvent.Save,
|
|
225
230
|
'http://tshost',
|
|
226
231
|
{},
|
|
232
|
+
undefined,
|
|
227
233
|
);
|
|
228
234
|
});
|
|
229
235
|
});
|
|
@@ -245,6 +251,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
245
251
|
HostEvent.Save,
|
|
246
252
|
'http://tshost',
|
|
247
253
|
false,
|
|
254
|
+
undefined,
|
|
248
255
|
);
|
|
249
256
|
});
|
|
250
257
|
});
|
|
@@ -1332,6 +1339,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
1332
1339
|
HostEvent.InfoSuccess,
|
|
1333
1340
|
'http://tshost',
|
|
1334
1341
|
expect.objectContaining({ info: expect.any(Object) }),
|
|
1342
|
+
undefined,
|
|
1335
1343
|
);
|
|
1336
1344
|
});
|
|
1337
1345
|
});
|
|
@@ -1468,6 +1476,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
1468
1476
|
HostEvent.InfoSuccess,
|
|
1469
1477
|
'http://tshost',
|
|
1470
1478
|
expect.objectContaining({ info: expect.any(Object) }),
|
|
1479
|
+
undefined,
|
|
1471
1480
|
);
|
|
1472
1481
|
});
|
|
1473
1482
|
});
|
|
@@ -1482,6 +1491,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
1482
1491
|
HostEvent.InfoSuccess,
|
|
1483
1492
|
'http://tshost',
|
|
1484
1493
|
expect.objectContaining({ info: expect.any(Object) }),
|
|
1494
|
+
undefined,
|
|
1485
1495
|
);
|
|
1486
1496
|
});
|
|
1487
1497
|
});
|
|
@@ -1496,6 +1506,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
1496
1506
|
HostEvent.InfoSuccess,
|
|
1497
1507
|
'http://tshost',
|
|
1498
1508
|
expect.objectContaining({ info: expect.any(Object) }),
|
|
1509
|
+
undefined,
|
|
1499
1510
|
);
|
|
1500
1511
|
});
|
|
1501
1512
|
});
|
|
@@ -1510,6 +1521,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
1510
1521
|
HostEvent.InfoSuccess,
|
|
1511
1522
|
'http://tshost',
|
|
1512
1523
|
expect.objectContaining({ info: expect.any(Object) }),
|
|
1524
|
+
undefined,
|
|
1513
1525
|
);
|
|
1514
1526
|
});
|
|
1515
1527
|
});
|
|
@@ -2800,7 +2812,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
2800
2812
|
jest.clearAllMocks();
|
|
2801
2813
|
document.body.innerHTML = getDocumentBody();
|
|
2802
2814
|
mockPort.postMessage.mockClear();
|
|
2803
|
-
jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue('test-token');
|
|
2815
|
+
jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue('mock-test-token-placeholder');
|
|
2804
2816
|
|
|
2805
2817
|
jest.spyOn(baseInstance, 'handleAuth').mockImplementation(() => Promise.resolve(true));
|
|
2806
2818
|
jest.spyOn(baseInstance, 'notifyAuthFailure').mockImplementation(() => { });
|
|
@@ -2829,7 +2841,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
2829
2841
|
expect(baseInstance.handleAuth).toHaveBeenCalledTimes(1);
|
|
2830
2842
|
expect(mockPort.postMessage).toHaveBeenCalledWith({
|
|
2831
2843
|
type: EmbedEvent.AuthExpire,
|
|
2832
|
-
data: { authToken: 'test-token' },
|
|
2844
|
+
data: { authToken: 'mock-test-token-placeholder' },
|
|
2833
2845
|
});
|
|
2834
2846
|
});
|
|
2835
2847
|
});
|
|
@@ -2864,7 +2876,7 @@ describe('Unit test case for ts embed', () => {
|
|
|
2864
2876
|
expect(baseInstance.handleAuth).toHaveBeenCalledTimes(1);
|
|
2865
2877
|
expect(mockPort.postMessage).toHaveBeenCalledWith({
|
|
2866
2878
|
type: EmbedEvent.AuthExpire,
|
|
2867
|
-
data: { authToken: 'test-token' },
|
|
2879
|
+
data: { authToken: 'mock-test-token-placeholder' },
|
|
2868
2880
|
});
|
|
2869
2881
|
});
|
|
2870
2882
|
});
|
|
@@ -2921,6 +2933,113 @@ describe('Unit test case for ts embed', () => {
|
|
|
2921
2933
|
});
|
|
2922
2934
|
});
|
|
2923
2935
|
|
|
2936
|
+
describe('AutoLogin behavior in tokenRefresh', () => {
|
|
2937
|
+
const mockPort = { postMessage: jest.fn() };
|
|
2938
|
+
const mockEmbedEventPayload = { type: EmbedEvent.RefreshAuthToken, data: {} };
|
|
2939
|
+
|
|
2940
|
+
beforeEach(() => {
|
|
2941
|
+
jest.clearAllMocks();
|
|
2942
|
+
document.body.innerHTML = getDocumentBody();
|
|
2943
|
+
mockPort.postMessage.mockClear();
|
|
2944
|
+
jest.spyOn(authToken, 'getAuthenticationToken').mockResolvedValue('mock-test-token-placeholder');
|
|
2945
|
+
jest.spyOn(processData, 'processAuthFailure').mockImplementation(() => ({} as any));
|
|
2946
|
+
jest.spyOn(logger, 'error').mockImplementation(() => {});
|
|
2947
|
+
});
|
|
2948
|
+
|
|
2949
|
+
const renderAndTriggerRefreshAuthToken = async () => {
|
|
2950
|
+
const spotterEmbed = new SpotterEmbed(getRootEl(), {
|
|
2951
|
+
worksheetId: 'test-worksheet',
|
|
2952
|
+
searchOptions: {
|
|
2953
|
+
searchQuery: 'test query',
|
|
2954
|
+
},
|
|
2955
|
+
} as SpotterEmbedViewConfig);
|
|
2956
|
+
await spotterEmbed.render();
|
|
2957
|
+
await executeAfterWait(() => {
|
|
2958
|
+
const iframe = getIFrameEl();
|
|
2959
|
+
postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
|
|
2960
|
+
});
|
|
2961
|
+
};
|
|
2962
|
+
|
|
2963
|
+
test('Cookieless with autoLogin undefined should default to true and refresh token', async () => {
|
|
2964
|
+
init({
|
|
2965
|
+
thoughtSpotHost: 'tshost',
|
|
2966
|
+
authType: AuthType.TrustedAuthTokenCookieless,
|
|
2967
|
+
// autoLogin undefined
|
|
2968
|
+
});
|
|
2969
|
+
|
|
2970
|
+
await renderAndTriggerRefreshAuthToken();
|
|
2971
|
+
|
|
2972
|
+
await executeAfterWait(() => {
|
|
2973
|
+
expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
|
|
2974
|
+
expect.any(Object),
|
|
2975
|
+
true
|
|
2976
|
+
);
|
|
2977
|
+
});
|
|
2978
|
+
});
|
|
2979
|
+
|
|
2980
|
+
test('Cookieless with autoLogin true should refresh token', async () => {
|
|
2981
|
+
init({
|
|
2982
|
+
thoughtSpotHost: 'tshost',
|
|
2983
|
+
authType: AuthType.TrustedAuthTokenCookieless,
|
|
2984
|
+
autoLogin: true,
|
|
2985
|
+
});
|
|
2986
|
+
|
|
2987
|
+
await renderAndTriggerRefreshAuthToken();
|
|
2988
|
+
|
|
2989
|
+
await executeAfterWait(() => {
|
|
2990
|
+
expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
|
|
2991
|
+
expect.any(Object),
|
|
2992
|
+
true
|
|
2993
|
+
);
|
|
2994
|
+
});
|
|
2995
|
+
});
|
|
2996
|
+
|
|
2997
|
+
test('Cookieless with autoLogin false should not refresh token', async () => {
|
|
2998
|
+
init({
|
|
2999
|
+
thoughtSpotHost: 'tshost',
|
|
3000
|
+
authType: AuthType.TrustedAuthTokenCookieless,
|
|
3001
|
+
autoLogin: false,
|
|
3002
|
+
});
|
|
3003
|
+
|
|
3004
|
+
await renderAndTriggerRefreshAuthToken();
|
|
3005
|
+
|
|
3006
|
+
await executeAfterWait(() => {
|
|
3007
|
+
expect(authToken.getAuthenticationToken).not.toHaveBeenCalled();
|
|
3008
|
+
expect(mockPort.postMessage).not.toHaveBeenCalled();
|
|
3009
|
+
});
|
|
3010
|
+
});
|
|
3011
|
+
|
|
3012
|
+
test('Should handle error when getAuthenticationToken fails', async () => {
|
|
3013
|
+
const error = new Error('Token fetch failed');
|
|
3014
|
+
jest.spyOn(authToken, 'getAuthenticationToken').mockRejectedValue(error);
|
|
3015
|
+
|
|
3016
|
+
init({
|
|
3017
|
+
thoughtSpotHost: 'tshost',
|
|
3018
|
+
authType: AuthType.TrustedAuthTokenCookieless,
|
|
3019
|
+
autoLogin: true,
|
|
3020
|
+
});
|
|
3021
|
+
|
|
3022
|
+
await renderAndTriggerRefreshAuthToken();
|
|
3023
|
+
|
|
3024
|
+
await executeAfterWait(() => {
|
|
3025
|
+
expect(authToken.getAuthenticationToken).toHaveBeenCalledWith(
|
|
3026
|
+
expect.any(Object),
|
|
3027
|
+
true
|
|
3028
|
+
);
|
|
3029
|
+
// Check that logger.error was called with the token refresh error
|
|
3030
|
+
const errorCalls = (logger.error as jest.Mock).mock.calls.filter(
|
|
3031
|
+
(call) => call[0]?.includes(ERROR_MESSAGE.INVALID_TOKEN_ERROR) && call[0]?.includes('Token fetch failed')
|
|
3032
|
+
);
|
|
3033
|
+
expect(errorCalls.length).toBeGreaterThan(0);
|
|
3034
|
+
expect(processData.processAuthFailure).toHaveBeenCalledWith(
|
|
3035
|
+
error,
|
|
3036
|
+
expect.any(Element)
|
|
3037
|
+
);
|
|
3038
|
+
expect(mockPort.postMessage).not.toHaveBeenCalled();
|
|
3039
|
+
});
|
|
3040
|
+
});
|
|
3041
|
+
});
|
|
3042
|
+
|
|
2924
3043
|
describe('Fullscreen Change Handler', () => {
|
|
2925
3044
|
beforeEach(() => {
|
|
2926
3045
|
document.body.innerHTML = getDocumentBody();
|
|
@@ -3159,6 +3278,59 @@ describe('Unit test case for ts embed', () => {
|
|
|
3159
3278
|
expect(callback3).toHaveBeenCalledTimes(1);
|
|
3160
3279
|
});
|
|
3161
3280
|
|
|
3281
|
+
describe('getCurrentContext', () => {
|
|
3282
|
+
const mockContext: ContextObject = {
|
|
3283
|
+
stack: [
|
|
3284
|
+
{
|
|
3285
|
+
name: 'Liveboard',
|
|
3286
|
+
type: 'Liveboard' as any,
|
|
3287
|
+
objectIds: { liveboardId: 'lb-123' },
|
|
3288
|
+
},
|
|
3289
|
+
],
|
|
3290
|
+
currentContext: {
|
|
3291
|
+
name: 'Liveboard',
|
|
3292
|
+
type: 'Liveboard' as any,
|
|
3293
|
+
objectIds: { liveboardId: 'lb-123' },
|
|
3294
|
+
},
|
|
3295
|
+
};
|
|
3296
|
+
|
|
3297
|
+
test('should return context when embed container is already loaded', async () => {
|
|
3298
|
+
const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
3299
|
+
searchEmbed.isEmbedContainerLoaded = true;
|
|
3300
|
+
|
|
3301
|
+
const triggerSpy = jest.spyOn(searchEmbed, 'trigger')
|
|
3302
|
+
.mockResolvedValue(mockContext);
|
|
3303
|
+
|
|
3304
|
+
const context = await searchEmbed.getCurrentContext();
|
|
3305
|
+
|
|
3306
|
+
expect(context).toEqual(mockContext);
|
|
3307
|
+
expect(triggerSpy).toHaveBeenCalledWith(HostEvent.GetPageContext, {});
|
|
3308
|
+
});
|
|
3309
|
+
|
|
3310
|
+
test('should wait for embed container to load before returning context', async () => {
|
|
3311
|
+
const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
3312
|
+
searchEmbed.isEmbedContainerLoaded = false;
|
|
3313
|
+
|
|
3314
|
+
const triggerSpy = jest.spyOn(searchEmbed, 'trigger')
|
|
3315
|
+
.mockResolvedValue(mockContext);
|
|
3316
|
+
|
|
3317
|
+
const contextPromise = searchEmbed.getCurrentContext();
|
|
3318
|
+
|
|
3319
|
+
// Context should not be resolved yet
|
|
3320
|
+
await executeAfterWait(() => {
|
|
3321
|
+
expect(triggerSpy).not.toHaveBeenCalled();
|
|
3322
|
+
}, 10);
|
|
3323
|
+
|
|
3324
|
+
// Simulate embed container becoming ready
|
|
3325
|
+
searchEmbed['executeEmbedContainerReadyCallbacks']();
|
|
3326
|
+
|
|
3327
|
+
const context = await contextPromise;
|
|
3328
|
+
|
|
3329
|
+
expect(context).toEqual(mockContext);
|
|
3330
|
+
expect(triggerSpy).toHaveBeenCalledWith(HostEvent.GetPageContext, {});
|
|
3331
|
+
});
|
|
3332
|
+
});
|
|
3333
|
+
|
|
3162
3334
|
test('should register embed container event handlers during construction', () => {
|
|
3163
3335
|
const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
|
|
3164
3336
|
|
|
@@ -4056,7 +4228,7 @@ describe('Destroy error handling', () => {
|
|
|
4056
4228
|
}).not.toThrow();
|
|
4057
4229
|
|
|
4058
4230
|
expect(logSpy).toHaveBeenCalledWith('Error destroying TS Embed', expect.any(Error));
|
|
4059
|
-
logSpy.
|
|
4231
|
+
logSpy.mockReset();
|
|
4060
4232
|
});
|
|
4061
4233
|
});
|
|
4062
4234
|
|
|
@@ -4099,11 +4271,12 @@ describe('Fullscreen change handler behavior', () => {
|
|
|
4099
4271
|
document.dispatchEvent(event);
|
|
4100
4272
|
|
|
4101
4273
|
await executeAfterWait(() => {
|
|
4102
|
-
expect(mockProcessTrigger).
|
|
4274
|
+
expect(mockProcessTrigger).toHaveBeenLastCalledWith(
|
|
4103
4275
|
expect.any(Object),
|
|
4104
4276
|
HostEvent.ExitPresentMode,
|
|
4105
4277
|
expect.any(String),
|
|
4106
4278
|
expect.any(Object),
|
|
4279
|
+
undefined,
|
|
4107
4280
|
);
|
|
4108
4281
|
});
|
|
4109
4282
|
});
|
|
@@ -4196,13 +4369,14 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
4196
4369
|
embed2.showPreRender();
|
|
4197
4370
|
|
|
4198
4371
|
await executeAfterWait(() => {
|
|
4199
|
-
expect(mockProcessTrigger).
|
|
4372
|
+
expect(mockProcessTrigger).toHaveBeenLastCalledWith(
|
|
4200
4373
|
expect.any(Object),
|
|
4201
4374
|
HostEvent.UpdateEmbedParams,
|
|
4202
4375
|
expect.any(String),
|
|
4203
4376
|
expect.objectContaining({
|
|
4204
4377
|
liveboardId: 'updated-lb',
|
|
4205
4378
|
}),
|
|
4379
|
+
undefined,
|
|
4206
4380
|
);
|
|
4207
4381
|
});
|
|
4208
4382
|
});
|
|
@@ -4231,7 +4405,7 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
4231
4405
|
embed2.showPreRender();
|
|
4232
4406
|
|
|
4233
4407
|
await executeAfterWait(() => {
|
|
4234
|
-
expect(mockProcessTrigger).
|
|
4408
|
+
expect(mockProcessTrigger).toHaveBeenLastCalledWith(
|
|
4235
4409
|
expect.any(Object),
|
|
4236
4410
|
HostEvent.UpdateEmbedParams,
|
|
4237
4411
|
expect.any(String),
|
|
@@ -4251,6 +4425,7 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
4251
4425
|
},
|
|
4252
4426
|
],
|
|
4253
4427
|
}),
|
|
4428
|
+
undefined,
|
|
4254
4429
|
);
|
|
4255
4430
|
});
|
|
4256
4431
|
});
|
|
@@ -4283,7 +4458,7 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
4283
4458
|
embed2.showPreRender();
|
|
4284
4459
|
|
|
4285
4460
|
await executeAfterWait(() => {
|
|
4286
|
-
expect(mockProcessTrigger).
|
|
4461
|
+
expect(mockProcessTrigger).toHaveBeenLastCalledWith(
|
|
4287
4462
|
expect.any(Object),
|
|
4288
4463
|
HostEvent.UpdateEmbedParams,
|
|
4289
4464
|
expect.any(String),
|
|
@@ -4298,6 +4473,7 @@ describe('ShowPreRender with UpdateEmbedParams', () => {
|
|
|
4298
4473
|
},
|
|
4299
4474
|
],
|
|
4300
4475
|
}),
|
|
4476
|
+
undefined,
|
|
4301
4477
|
);
|
|
4302
4478
|
});
|
|
4303
4479
|
});
|
package/src/embed/ts-embed.ts
CHANGED
|
@@ -60,6 +60,9 @@ import {
|
|
|
60
60
|
EmbedErrorDetailsEvent,
|
|
61
61
|
ErrorDetailsTypes,
|
|
62
62
|
EmbedErrorCodes,
|
|
63
|
+
MessagePayload,
|
|
64
|
+
ContextType,
|
|
65
|
+
ContextObject,
|
|
63
66
|
} from '../types';
|
|
64
67
|
import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
|
|
65
68
|
import { processEventData, processAuthFailure } from '../utils/processData';
|
|
@@ -75,6 +78,7 @@ import { ERROR_MESSAGE } from '../errors';
|
|
|
75
78
|
import { getPreauthInfo } from '../utils/sessionInfoService';
|
|
76
79
|
import { HostEventClient } from './hostEventClient/host-event-client';
|
|
77
80
|
import { getInterceptInitData, handleInterceptEvent, processApiInterceptResponse, processLegacyInterceptResponse } from '../api-intercept';
|
|
81
|
+
import { getHostEventsConfig } from '../utils';
|
|
78
82
|
|
|
79
83
|
const { version } = pkgInfo;
|
|
80
84
|
|
|
@@ -479,7 +483,9 @@ export class TsEmbed {
|
|
|
479
483
|
this.embedConfig.customVariablesForThirdPartyTools || {},
|
|
480
484
|
hiddenListColumns: this.viewConfig.hiddenListColumns || [],
|
|
481
485
|
customActions: customActionsResult.actions,
|
|
486
|
+
embedExpiryInAuthToken: this.viewConfig.refreshAuthTokenOnNearExpiry,
|
|
482
487
|
...getInterceptInitData(this.viewConfig),
|
|
488
|
+
...getHostEventsConfig(this.viewConfig),
|
|
483
489
|
};
|
|
484
490
|
|
|
485
491
|
return baseInitData;
|
|
@@ -507,29 +513,65 @@ export class TsEmbed {
|
|
|
507
513
|
}
|
|
508
514
|
};
|
|
509
515
|
|
|
516
|
+
/**
|
|
517
|
+
* Helper method to refresh/update auth token for TrustedAuthTokenCookieless auth type
|
|
518
|
+
* @param responder - Function to send response back
|
|
519
|
+
* @param eventType - The embed event type to send
|
|
520
|
+
* @param forceRefresh - Whether to force refresh the token
|
|
521
|
+
* @returns Promise that resolves if token was refreshed, rejects otherwise
|
|
522
|
+
*/
|
|
523
|
+
private async refreshAuthTokenForCookieless(
|
|
524
|
+
responder: (data: any) => void,
|
|
525
|
+
eventType: EmbedEvent,
|
|
526
|
+
forceRefresh: boolean = false
|
|
527
|
+
): Promise<void> {
|
|
528
|
+
const { authType, autoLogin } = this.embedConfig;
|
|
529
|
+
const isAutoLoginTrue = autoLogin ?? (authType === AuthType.TrustedAuthTokenCookieless);
|
|
530
|
+
|
|
531
|
+
if (isAutoLoginTrue && authType === AuthType.TrustedAuthTokenCookieless) {
|
|
532
|
+
const authToken = await getAuthenticationToken(this.embedConfig, forceRefresh);
|
|
533
|
+
responder({
|
|
534
|
+
type: eventType,
|
|
535
|
+
data: { authToken },
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
private handleAuthFailure = (error: Error) => {
|
|
541
|
+
logger.error(`${ERROR_MESSAGE.INVALID_TOKEN_ERROR} Error : ${error?.message}`);
|
|
542
|
+
processAuthFailure(error, this.isPreRendered ? this.preRenderWrapper : this.el);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
/**
|
|
546
|
+
* Refresh the auth token if the autoLogin is true and the authType is TrustedAuthTokenCookieless
|
|
547
|
+
* @param _
|
|
548
|
+
* @param responder
|
|
549
|
+
*/
|
|
550
|
+
private tokenRefresh = async (_: MessagePayload, responder: (data: {type: EmbedEvent, data: {authToken: string}}) => void) => {
|
|
551
|
+
try {
|
|
552
|
+
await this.refreshAuthTokenForCookieless(responder, EmbedEvent.RefreshAuthToken, true);
|
|
553
|
+
} catch (e) {
|
|
554
|
+
this.handleAuthFailure(e);
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
510
558
|
/**
|
|
511
559
|
* Sends updated auth token to the iFrame to avoid user logout
|
|
512
560
|
* @param _
|
|
513
561
|
* @param responder
|
|
514
562
|
*/
|
|
515
|
-
private updateAuthToken = async (_:
|
|
516
|
-
const { authType } = this.embedConfig;
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
});
|
|
528
|
-
} catch (e) {
|
|
529
|
-
logger.error(`${ERROR_MESSAGE.INVALID_TOKEN_ERROR} Error : ${e?.message}`);
|
|
530
|
-
processAuthFailure(e, this.isPreRendered ? this.preRenderWrapper : this.el);
|
|
531
|
-
}
|
|
532
|
-
} else if (autoLogin) {
|
|
563
|
+
private updateAuthToken = async (_: MessagePayload, responder: any) => {
|
|
564
|
+
const { authType, autoLogin: autoLoginConfig } = this.embedConfig;
|
|
565
|
+
// Default autoLogin: true for cookieless if undefined/null, otherwise false
|
|
566
|
+
const autoLogin = autoLoginConfig ?? (authType === AuthType.TrustedAuthTokenCookieless);
|
|
567
|
+
|
|
568
|
+
try {
|
|
569
|
+
await this.refreshAuthTokenForCookieless(responder, EmbedEvent.AuthExpire, false);
|
|
570
|
+
} catch (e) {
|
|
571
|
+
this.handleAuthFailure(e);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
if (autoLogin && authType !== AuthType.TrustedAuthTokenCookieless) {
|
|
533
575
|
handleAuth();
|
|
534
576
|
}
|
|
535
577
|
notifyAuthFailure(AuthFailureType.EXPIRY);
|
|
@@ -550,8 +592,7 @@ export class TsEmbed {
|
|
|
550
592
|
data: { authToken },
|
|
551
593
|
});
|
|
552
594
|
} catch (e) {
|
|
553
|
-
|
|
554
|
-
processAuthFailure(e, this.isPreRendered ? this.preRenderWrapper : this.el);
|
|
595
|
+
this.handleAuthFailure(e);
|
|
555
596
|
}
|
|
556
597
|
}).catch((e) => {
|
|
557
598
|
logger.error(`Auto Login failed, Error : ${e?.message}`);
|
|
@@ -569,9 +610,10 @@ export class TsEmbed {
|
|
|
569
610
|
|
|
570
611
|
const embedListenerReadyHandler = this.createEmbedContainerHandler(EmbedEvent.EmbedListenerReady);
|
|
571
612
|
this.on(EmbedEvent.EmbedListenerReady, embedListenerReadyHandler, { start: false }, true);
|
|
572
|
-
|
|
613
|
+
|
|
573
614
|
const authInitHandler = this.createEmbedContainerHandler(EmbedEvent.AuthInit);
|
|
574
615
|
this.on(EmbedEvent.AuthInit, authInitHandler, { start: false }, true);
|
|
616
|
+
this.on(EmbedEvent.RefreshAuthToken, this.tokenRefresh, { start: false }, true);
|
|
575
617
|
};
|
|
576
618
|
|
|
577
619
|
/**
|
|
@@ -1347,10 +1389,11 @@ export class TsEmbed {
|
|
|
1347
1389
|
* @param {any} data The payload to send with the message
|
|
1348
1390
|
* @returns A promise that resolves with the response from the embedded app
|
|
1349
1391
|
*/
|
|
1350
|
-
public async trigger<HostEventT extends HostEvent, PayloadT>(
|
|
1392
|
+
public async trigger<HostEventT extends HostEvent, PayloadT, ContextT extends ContextType>(
|
|
1351
1393
|
messageType: HostEventT,
|
|
1352
1394
|
data: TriggerPayload<PayloadT, HostEventT> = {} as any,
|
|
1353
|
-
|
|
1395
|
+
context?: ContextT,
|
|
1396
|
+
): Promise<TriggerResponse<PayloadT, HostEventT, ContextT>> {
|
|
1354
1397
|
uploadMixpanelEvent(`${MIXPANEL_EVENT.VISUAL_SDK_TRIGGER}-${messageType}`);
|
|
1355
1398
|
|
|
1356
1399
|
if (!this.isRendered) {
|
|
@@ -1383,7 +1426,7 @@ export class TsEmbed {
|
|
|
1383
1426
|
}
|
|
1384
1427
|
|
|
1385
1428
|
// send an empty object, this is needed for liveboard default handlers
|
|
1386
|
-
return this.hostEventClient.triggerHostEvent(messageType, data);
|
|
1429
|
+
return this.hostEventClient.triggerHostEvent(messageType, data, context);
|
|
1387
1430
|
}
|
|
1388
1431
|
|
|
1389
1432
|
/**
|
|
@@ -1425,6 +1468,20 @@ export class TsEmbed {
|
|
|
1425
1468
|
return this.render();
|
|
1426
1469
|
}
|
|
1427
1470
|
|
|
1471
|
+
/**
|
|
1472
|
+
* Get the current context of the embedded TS component.
|
|
1473
|
+
* @returns The current context object containing the page type and object ids.
|
|
1474
|
+
* @version SDK: 1.45.2 | ThoughtSpot: 26.3.0.cl
|
|
1475
|
+
*/
|
|
1476
|
+
public async getCurrentContext(): Promise<ContextObject> {
|
|
1477
|
+
return new Promise((resolve) => {
|
|
1478
|
+
this.executeAfterEmbedContainerLoaded(async () => {
|
|
1479
|
+
const context = await this.trigger(HostEvent.GetPageContext, {});
|
|
1480
|
+
resolve(context);
|
|
1481
|
+
});
|
|
1482
|
+
});
|
|
1483
|
+
}
|
|
1484
|
+
|
|
1428
1485
|
/**
|
|
1429
1486
|
* Creates the preRender shell
|
|
1430
1487
|
* @param showPreRenderByDefault - Show the preRender after render, hidden by default
|
package/src/index.ts
CHANGED
|
@@ -68,6 +68,7 @@ import {
|
|
|
68
68
|
InterceptedApiType,
|
|
69
69
|
EmbedErrorCodes,
|
|
70
70
|
ErrorDetailsTypes,
|
|
71
|
+
ContextType,
|
|
71
72
|
} from './types';
|
|
72
73
|
import { CustomCssVariables } from './css-variables';
|
|
73
74
|
import { SageEmbed, SageViewConfig } from './embed/sage';
|
|
@@ -121,6 +122,7 @@ export {
|
|
|
121
122
|
RuntimeFilterOp,
|
|
122
123
|
EmbedEvent,
|
|
123
124
|
HostEvent,
|
|
125
|
+
ContextType,
|
|
124
126
|
DataSourceVisualMode,
|
|
125
127
|
Action,
|
|
126
128
|
ContextMenuTriggerOptions,
|