@thoughtspot/visual-embed-sdk 1.25.0 → 1.26.0-token-cache.0

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.
Files changed (215) hide show
  1. package/README.md +1 -1
  2. package/cjs/package.json +1 -1
  3. package/cjs/src/auth.d.ts +0 -12
  4. package/cjs/src/auth.d.ts.map +1 -1
  5. package/cjs/src/auth.js +15 -54
  6. package/cjs/src/auth.js.map +1 -1
  7. package/cjs/src/auth.spec.d.ts.map +1 -1
  8. package/cjs/src/auth.spec.js +44 -5
  9. package/cjs/src/auth.spec.js.map +1 -1
  10. package/cjs/src/authToken.d.ts +4 -0
  11. package/cjs/src/authToken.d.ts.map +1 -0
  12. package/cjs/src/authToken.js +60 -0
  13. package/cjs/src/authToken.js.map +1 -0
  14. package/cjs/src/config.d.ts.map +1 -1
  15. package/cjs/src/config.js +3 -0
  16. package/cjs/src/config.js.map +1 -1
  17. package/cjs/src/config.spec.js +1 -1
  18. package/cjs/src/config.spec.js.map +1 -1
  19. package/cjs/src/embed/TsEmbed.d.ts +302 -0
  20. package/cjs/src/embed/TsEmbed.d.ts.map +1 -0
  21. package/cjs/src/embed/TsEmbed.js +851 -0
  22. package/cjs/src/embed/TsEmbed.js.map +1 -0
  23. package/cjs/src/embed/base.d.ts +0 -1
  24. package/cjs/src/embed/base.d.ts.map +1 -1
  25. package/cjs/src/embed/base.js +6 -5
  26. package/cjs/src/embed/base.js.map +1 -1
  27. package/cjs/src/embed/base.spec.js +7 -5
  28. package/cjs/src/embed/base.spec.js.map +1 -1
  29. package/cjs/src/embed/search.d.ts +0 -4
  30. package/cjs/src/embed/search.d.ts.map +1 -1
  31. package/cjs/src/embed/search.js +3 -2
  32. package/cjs/src/embed/search.js.map +1 -1
  33. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  34. package/cjs/src/embed/ts-embed.js +3 -2
  35. package/cjs/src/embed/ts-embed.js.map +1 -1
  36. package/cjs/src/embed/ts-embed.spec.js +48 -37
  37. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  38. package/cjs/src/react/index.spec.js +0 -12
  39. package/cjs/src/react/index.spec.js.map +1 -1
  40. package/cjs/src/tokenizedFetch.d.ts +2 -0
  41. package/cjs/src/tokenizedFetch.d.ts.map +1 -0
  42. package/cjs/src/tokenizedFetch.js +20 -0
  43. package/cjs/src/tokenizedFetch.js.map +1 -0
  44. package/cjs/src/types.d.ts +11 -1
  45. package/cjs/src/types.d.ts.map +1 -1
  46. package/cjs/src/types.js +7 -1
  47. package/cjs/src/types.js.map +1 -1
  48. package/cjs/src/utils/answerService.d.ts +10 -0
  49. package/cjs/src/utils/answerService.d.ts.map +1 -0
  50. package/cjs/src/utils/answerService.js +61 -0
  51. package/cjs/src/utils/answerService.js.map +1 -0
  52. package/cjs/src/utils/answerService.spec.d.ts +2 -0
  53. package/cjs/src/utils/answerService.spec.d.ts.map +1 -0
  54. package/cjs/src/utils/answerService.spec.js +31 -0
  55. package/cjs/src/utils/answerService.spec.js.map +1 -0
  56. package/cjs/src/utils/authService.d.ts +12 -1
  57. package/cjs/src/utils/authService.d.ts.map +1 -1
  58. package/cjs/src/utils/authService.js +32 -16
  59. package/cjs/src/utils/authService.js.map +1 -1
  60. package/cjs/src/utils/authService.spec.js +3 -4
  61. package/cjs/src/utils/authService.spec.js.map +1 -1
  62. package/cjs/src/utils/graphql/answerService/answerService.d.ts +1 -0
  63. package/cjs/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  64. package/cjs/src/utils/graphql/answerService/answerService.js +6 -2
  65. package/cjs/src/utils/graphql/answerService/answerService.js.map +1 -1
  66. package/cjs/src/utils/graphql/answerService/answerService.spec.js +18 -2
  67. package/cjs/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  68. package/cjs/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  69. package/cjs/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  70. package/cjs/src/utils/graphql/graphql-request.spec.js +39 -0
  71. package/cjs/src/utils/graphql/graphql-request.spec.js.map +1 -0
  72. package/cjs/src/utils/logger.d.ts +28 -0
  73. package/cjs/src/utils/logger.d.ts.map +1 -0
  74. package/cjs/src/utils/logger.js +82 -0
  75. package/cjs/src/utils/logger.js.map +1 -0
  76. package/cjs/src/utils/processData.d.ts.map +1 -1
  77. package/cjs/src/utils/processData.js +2 -2
  78. package/cjs/src/utils/processData.js.map +1 -1
  79. package/cjs/src/utils/processData.spec.js +2 -2
  80. package/cjs/src/utils/processData.spec.js.map +1 -1
  81. package/dist/src/auth.d.ts +0 -12
  82. package/dist/src/auth.d.ts.map +1 -1
  83. package/dist/src/auth.spec.d.ts.map +1 -1
  84. package/dist/src/authToken.d.ts +4 -0
  85. package/dist/src/authToken.d.ts.map +1 -0
  86. package/dist/src/config.d.ts.map +1 -1
  87. package/dist/src/embed/base.d.ts +0 -1
  88. package/dist/src/embed/base.d.ts.map +1 -1
  89. package/dist/src/embed/search.d.ts +0 -4
  90. package/dist/src/embed/search.d.ts.map +1 -1
  91. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  92. package/dist/src/tokenizedFetch.d.ts +2 -0
  93. package/dist/src/tokenizedFetch.d.ts.map +1 -0
  94. package/dist/src/types.d.ts +11 -1
  95. package/dist/src/types.d.ts.map +1 -1
  96. package/dist/src/utils/answerService.d.ts +10 -0
  97. package/dist/src/utils/answerService.d.ts.map +1 -0
  98. package/dist/src/utils/answerService.spec.d.ts +2 -0
  99. package/dist/src/utils/answerService.spec.d.ts.map +1 -0
  100. package/dist/src/utils/authService.d.ts +12 -1
  101. package/dist/src/utils/authService.d.ts.map +1 -1
  102. package/dist/src/utils/graphql/answerService/answerService.d.ts +1 -0
  103. package/dist/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  104. package/dist/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  105. package/dist/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  106. package/dist/src/utils/logger.d.ts +28 -0
  107. package/dist/src/utils/logger.d.ts.map +1 -0
  108. package/dist/src/utils/processData.d.ts.map +1 -1
  109. package/dist/tsembed-react.es.js +2149 -2094
  110. package/dist/tsembed-react.js +2152 -2097
  111. package/dist/tsembed.es.js +6483 -6425
  112. package/dist/tsembed.js +6483 -6425
  113. package/dist/visual-embed-sdk-react-full.d.ts +12 -18
  114. package/dist/visual-embed-sdk-react.d.ts +12 -18
  115. package/dist/visual-embed-sdk.d.ts +12 -18
  116. package/lib/package.json +1 -1
  117. package/lib/src/auth.d.ts +0 -12
  118. package/lib/src/auth.d.ts.map +1 -1
  119. package/lib/src/auth.js +10 -48
  120. package/lib/src/auth.js.map +1 -1
  121. package/lib/src/auth.spec.d.ts.map +1 -1
  122. package/lib/src/auth.spec.js +44 -5
  123. package/lib/src/auth.spec.js.map +1 -1
  124. package/lib/src/authToken.d.ts +4 -0
  125. package/lib/src/authToken.d.ts.map +1 -0
  126. package/lib/src/authToken.js +55 -0
  127. package/lib/src/authToken.js.map +1 -0
  128. package/lib/src/config.d.ts.map +1 -1
  129. package/lib/src/config.js +3 -0
  130. package/lib/src/config.js.map +1 -1
  131. package/lib/src/config.spec.js +1 -1
  132. package/lib/src/config.spec.js.map +1 -1
  133. package/lib/src/embed/TsEmbed.d.ts +302 -0
  134. package/lib/src/embed/TsEmbed.d.ts.map +1 -0
  135. package/lib/src/embed/TsEmbed.js +847 -0
  136. package/lib/src/embed/TsEmbed.js.map +1 -0
  137. package/lib/src/embed/base.d.ts +0 -1
  138. package/lib/src/embed/base.d.ts.map +1 -1
  139. package/lib/src/embed/base.js +3 -2
  140. package/lib/src/embed/base.js.map +1 -1
  141. package/lib/src/embed/base.spec.js +7 -5
  142. package/lib/src/embed/base.spec.js.map +1 -1
  143. package/lib/src/embed/search.d.ts +0 -4
  144. package/lib/src/embed/search.d.ts.map +1 -1
  145. package/lib/src/embed/search.js +3 -2
  146. package/lib/src/embed/search.js.map +1 -1
  147. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  148. package/lib/src/embed/ts-embed.js +2 -1
  149. package/lib/src/embed/ts-embed.js.map +1 -1
  150. package/lib/src/embed/ts-embed.spec.js +48 -37
  151. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  152. package/lib/src/react/index.spec.js +0 -12
  153. package/lib/src/react/index.spec.js.map +1 -1
  154. package/lib/src/tokenizedFetch.d.ts +2 -0
  155. package/lib/src/tokenizedFetch.d.ts.map +1 -0
  156. package/lib/src/tokenizedFetch.js +16 -0
  157. package/lib/src/tokenizedFetch.js.map +1 -0
  158. package/lib/src/types.d.ts +11 -1
  159. package/lib/src/types.d.ts.map +1 -1
  160. package/lib/src/types.js +7 -1
  161. package/lib/src/types.js.map +1 -1
  162. package/lib/src/utils/answerService.d.ts +10 -0
  163. package/lib/src/utils/answerService.d.ts.map +1 -0
  164. package/lib/src/utils/answerService.js +57 -0
  165. package/lib/src/utils/answerService.js.map +1 -0
  166. package/lib/src/utils/answerService.spec.d.ts +2 -0
  167. package/lib/src/utils/answerService.spec.d.ts.map +1 -0
  168. package/lib/src/utils/answerService.spec.js +29 -0
  169. package/lib/src/utils/answerService.spec.js.map +1 -0
  170. package/lib/src/utils/authService.d.ts +12 -1
  171. package/lib/src/utils/authService.d.ts.map +1 -1
  172. package/lib/src/utils/authService.js +26 -10
  173. package/lib/src/utils/authService.js.map +1 -1
  174. package/lib/src/utils/authService.spec.js +1 -2
  175. package/lib/src/utils/authService.spec.js.map +1 -1
  176. package/lib/src/utils/graphql/answerService/answerService.d.ts +1 -0
  177. package/lib/src/utils/graphql/answerService/answerService.d.ts.map +1 -1
  178. package/lib/src/utils/graphql/answerService/answerService.js +6 -2
  179. package/lib/src/utils/graphql/answerService/answerService.js.map +1 -1
  180. package/lib/src/utils/graphql/answerService/answerService.spec.js +17 -2
  181. package/lib/src/utils/graphql/answerService/answerService.spec.js.map +1 -1
  182. package/lib/src/utils/graphql/graphql-request.spec.d.ts +2 -0
  183. package/lib/src/utils/graphql/graphql-request.spec.d.ts.map +1 -0
  184. package/lib/src/utils/graphql/graphql-request.spec.js +36 -0
  185. package/lib/src/utils/graphql/graphql-request.spec.js.map +1 -0
  186. package/lib/src/utils/logger.d.ts +28 -0
  187. package/lib/src/utils/logger.d.ts.map +1 -0
  188. package/lib/src/utils/logger.js +75 -0
  189. package/lib/src/utils/logger.js.map +1 -0
  190. package/lib/src/utils/processData.d.ts.map +1 -1
  191. package/lib/src/utils/processData.js +2 -2
  192. package/lib/src/utils/processData.js.map +1 -1
  193. package/lib/src/utils/processData.spec.js +2 -2
  194. package/lib/src/utils/processData.spec.js.map +1 -1
  195. package/lib/src/visual-embed-sdk.d.ts +12 -18
  196. package/package.json +1 -1
  197. package/src/auth.spec.ts +47 -7
  198. package/src/auth.ts +9 -50
  199. package/src/authToken.ts +60 -0
  200. package/src/config.spec.ts +1 -1
  201. package/src/config.ts +3 -0
  202. package/src/embed/base.spec.ts +7 -6
  203. package/src/embed/base.ts +2 -3
  204. package/src/embed/search.ts +2 -6
  205. package/src/embed/ts-embed.spec.ts +54 -40
  206. package/src/embed/ts-embed.ts +2 -1
  207. package/src/react/index.spec.tsx +0 -29
  208. package/src/tokenizedFetch.ts +16 -0
  209. package/src/types.ts +12 -2
  210. package/src/utils/authService.spec.ts +1 -2
  211. package/src/utils/authService.ts +29 -10
  212. package/src/utils/graphql/answerService/answerService.spec.ts +27 -3
  213. package/src/utils/graphql/answerService/answerService.ts +7 -2
  214. package/src/utils/processData.spec.ts +2 -2
  215. package/src/utils/processData.ts +2 -1
package/src/auth.spec.ts CHANGED
@@ -4,6 +4,7 @@ import * as checkReleaseVersionInBetaInstance from './utils';
4
4
  import * as mixPanelService from './mixpanel-service';
5
5
  import { AuthType, EmbedEvent } from './types';
6
6
  import { executeAfterWait } from './test/test-utils';
7
+ import { resetCachedAuthToken } from './authToken';
7
8
 
8
9
  const thoughtSpotHost = 'http://localhost:3000';
9
10
  const username = 'tsuser';
@@ -88,7 +89,7 @@ export const embedConfig: any = {
88
89
  password,
89
90
  authType: AuthType.None,
90
91
  },
91
- doCookielessAuth: (token :string) => ({
92
+ doCookielessAuth: (token: string) => ({
92
93
  thoughtSpotHost,
93
94
  username,
94
95
  authType: AuthType.TrustedAuthTokenCookieless,
@@ -114,9 +115,11 @@ describe('Unit test for auth', () => {
114
115
  beforeEach(() => {
115
116
  global.fetch = window.fetch;
116
117
  });
117
-
118
+ afterEach(() => {
119
+ resetCachedAuthToken();
120
+ });
118
121
  test('endpoints, SAML_LOGIN_TEMPLATE', () => {
119
- const ssoTemplateUrl = authInstance.EndPoints.SAML_LOGIN_TEMPLATE(thoughtSpotHost);
122
+ const ssoTemplateUrl = authService.EndPoints.SAML_LOGIN_TEMPLATE(thoughtSpotHost);
120
123
  expect(ssoTemplateUrl).toBe(`/callosum/v1/saml/login?targetURLPath=${thoughtSpotHost}`);
121
124
  });
122
125
 
@@ -173,6 +176,7 @@ describe('Unit test for auth', () => {
173
176
  jest.spyOn(authService, 'fetchAuthService').mockImplementation(() => Promise.resolve({
174
177
  status: 200,
175
178
  }));
179
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
176
180
  await authInstance.doTokenAuth(embedConfig.doTokenAuthSuccess('authToken2'));
177
181
  expect(authService.fetchSessionInfoService).toBeCalled();
178
182
  expect(authService.fetchAuthService).toBeCalledWith(
@@ -189,11 +193,12 @@ describe('Unit test for auth', () => {
189
193
  status: 200,
190
194
  ok: true,
191
195
  }));
196
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
192
197
  await authInstance.doTokenAuth(embedConfig.doTokenAuthFailureWithoutGetAuthToken);
193
198
  await executeAfterWait(() => {
194
199
  expect(authInstance.loggedInStatus).toBe(true);
195
200
  expect(authService.fetchSessionInfoService).toBeCalled();
196
- expect(authService.fetchAuthService).toBeCalledWith(thoughtSpotHost, username, 'abc');
201
+ expect(authService.fetchAuthService).toBeCalledWith(thoughtSpotHost, username, 'authToken2');
197
202
  });
198
203
  });
199
204
 
@@ -208,9 +213,11 @@ describe('Unit test for auth', () => {
208
213
  status: 200,
209
214
  ok: true,
210
215
  }));
216
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
211
217
  await authInstance.doTokenAuth(embedConfig.doTokenAuthSuccess('authToken3'));
212
218
 
213
219
  try {
220
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(false);
214
221
  await authInstance.doTokenAuth(embedConfig.doTokenAuthSuccess('authToken3'));
215
222
  expect(false).toBe(true);
216
223
  } catch (e) {
@@ -236,6 +243,7 @@ describe('Unit test for auth', () => {
236
243
  status: 200,
237
244
  ok: true,
238
245
  }));
246
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
239
247
  const isLoggedIn = await authInstance.doTokenAuth(embedConfig.doTokenAuthWithCookieDetect);
240
248
  expect(authService.fetchSessionInfoService).toHaveBeenCalledTimes(2);
241
249
  expect(isLoggedIn).toBe(false);
@@ -256,6 +264,7 @@ describe('Unit test for auth', () => {
256
264
  status: 200,
257
265
  type: 'opaqueredirect',
258
266
  }));
267
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
259
268
  expect(await authInstance.doTokenAuth(embedConfig.doTokenAuthSuccess('authToken2'))).toBe(
260
269
  true,
261
270
  );
@@ -395,6 +404,7 @@ describe('Unit test for auth', () => {
395
404
 
396
405
  describe('doOIDCAuth', () => {
397
406
  afterEach(() => {
407
+ resetCachedAuthToken();
398
408
  delete global.window;
399
409
  global.window = Object.create(originalWindow);
400
410
  global.window.open = jest.fn();
@@ -463,15 +473,13 @@ describe('Unit test for auth', () => {
463
473
  });
464
474
 
465
475
  it('doCookielessTokenAuth should resolve to true if valid token is passed', async () => {
466
- jest.spyOn(authService, 'fetchAuthTokenService').mockResolvedValueOnce(new Response(JSON.stringify({ token: 'testToken' }), { status: 200 }));
467
476
  jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(new Response('', { status: 200 }));
468
477
  const isLoggedIn = await authInstance.doCookielessTokenAuth(embedConfig.doCookielessAuth('testToken'));
469
478
  expect(isLoggedIn).toBe(true);
470
479
  });
471
480
 
472
481
  it('doCookielessTokenAuth should resolve to false if valid token is not passed', async () => {
473
- jest.spyOn(authService, 'fetchAuthTokenService').mockResolvedValueOnce(new Response(JSON.stringify({ token: 'testToken' }), { status: 200 }));
474
- jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(new Response('', { status: 400 }));
482
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(false);
475
483
  const isLoggedIn = await authInstance.doCookielessTokenAuth(embedConfig.doCookielessAuth('testToken'));
476
484
  expect(isLoggedIn).toBe(false);
477
485
  });
@@ -480,4 +488,36 @@ describe('Unit test for auth', () => {
480
488
  authInstance.setAuthEE(testObject as any);
481
489
  expect(authInstance.getAuthEE()).toBe(testObject);
482
490
  });
491
+ it('getSessionDetails returns the correct details given sessionInfo', () => {
492
+ jest.clearAllMocks();
493
+ jest.restoreAllMocks();
494
+
495
+ const details = authInstance.getSessionDetails({
496
+ userGUID: '1234',
497
+ releaseVersion: '1',
498
+ configInfo: {
499
+ mixpanelConfig: {
500
+ devSdkKey: 'devKey',
501
+ prodSdkKey: 'prodKey',
502
+ production: false,
503
+ },
504
+ },
505
+ });
506
+ expect(details).toEqual(expect.objectContaining({
507
+ mixpanelToken: 'devKey',
508
+ }));
509
+
510
+ const details2 = authInstance.getSessionDetails({
511
+ configInfo: {
512
+ mixpanelConfig: {
513
+ devSdkKey: 'devKey',
514
+ prodSdkKey: 'prodKey',
515
+ production: true,
516
+ },
517
+ },
518
+ });
519
+ expect(details2).toEqual(expect.objectContaining({
520
+ mixpanelToken: 'prodKey',
521
+ }));
522
+ });
483
523
  });
package/src/auth.ts CHANGED
@@ -4,16 +4,15 @@ import {
4
4
  AuthType, DOMSelector, EmbedConfig, EmbedEvent, Param,
5
5
  } from './types';
6
6
  import { getDOMNode, getRedirectUrl } from './utils';
7
- // eslint-disable-next-line import/no-cycle
8
7
  import {
9
8
  fetchSessionInfoService,
10
- fetchAuthTokenService,
11
9
  fetchAuthService,
12
10
  fetchBasicAuthService,
13
11
  fetchLogoutService,
14
12
  fetchAuthPostService,
15
- verifyTokenService,
13
+ EndPoints,
16
14
  } from './utils/authService';
15
+ import { getAuthenticationToken, resetCachedAuthToken } from './authToken';
17
16
 
18
17
  // eslint-disable-next-line import/no-mutable-exports
19
18
  export let loggedInStatus = false;
@@ -30,18 +29,6 @@ let releaseVersion = '';
30
29
 
31
30
  export const SSO_REDIRECTION_MARKER_GUID = '5e16222e-ef02-43e9-9fbd-24226bf3ce5b';
32
31
 
33
- export const EndPoints = {
34
- AUTH_VERIFICATION: '/callosum/v1/session/info',
35
- SAML_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
36
- OIDC_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
37
- TOKEN_LOGIN: '/callosum/v1/session/login/token',
38
- BASIC_LOGIN: '/callosum/v1/session/login',
39
- LOGOUT: '/callosum/v1/session/logout',
40
- EXECUTE_TML: '/api/rest/2.0/metadata/tml/import',
41
- EXPORT_TML: '/api/rest/2.0/metadata/tml/export',
42
- IS_ACTIVE: '/callosum/v1/session/isactive',
43
- };
44
-
45
32
  interface sessionInfoInterface {
46
33
  userGUID: any;
47
34
  isPublicUser: any;
@@ -216,6 +203,7 @@ export const initSession = (sessionDetails: sessionInfoInterface) => {
216
203
  };
217
204
 
218
205
  export const getSessionDetails = (sessionInfoResp: any): sessionInfoInterface => {
206
+ console.log('helloooo');
219
207
  const devMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.devSdkKey;
220
208
  const prodMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.prodSdkKey;
221
209
  const mixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.production
@@ -270,22 +258,6 @@ export function getSessionInfo(): Promise<sessionInfoInterface> {
270
258
  return sessionInfoPromise;
271
259
  }
272
260
 
273
- const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
274
- + 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
275
- let prevAuthToken: string = null;
276
- /**
277
- *
278
- * @param authtoken
279
- */
280
- function alertForDuplicateToken(authtoken: string) {
281
- if (prevAuthToken === authtoken) {
282
- // eslint-disable-next-line no-alert
283
- alert(DUPLICATE_TOKEN_ERR);
284
- throw new Error(DUPLICATE_TOKEN_ERR);
285
- }
286
- prevAuthToken = authtoken;
287
- }
288
-
289
261
  /**
290
262
  * Check if we are stuck at the SSO redirect URL
291
263
  */
@@ -305,19 +277,6 @@ function removeSSORedirectUrlMarker(): void {
305
277
  window.location.hash = window.location.hash.replace(SSO_REDIRECTION_MARKER_GUID, '');
306
278
  }
307
279
 
308
- export const getAuthenticationToken = async (embedConfig: EmbedConfig): Promise<any> => {
309
- const { authEndpoint, getAuthToken } = embedConfig;
310
- let authToken = null;
311
- if (getAuthToken) {
312
- authToken = await getAuthToken();
313
- alertForDuplicateToken(authToken);
314
- } else {
315
- const response = await fetchAuthTokenService(authEndpoint);
316
- authToken = await response.text();
317
- }
318
- return authToken;
319
- };
320
-
321
280
  /**
322
281
  * Perform token based authentication
323
282
  *
@@ -362,13 +321,12 @@ export const doCookielessTokenAuth = async (embedConfig: EmbedConfig): Promise<b
362
321
  }
363
322
  try {
364
323
  const authToken = await getAuthenticationToken(embedConfig);
365
- const response = await verifyTokenService(embedConfig.thoughtSpotHost, authToken);
366
- if (!response.ok) return false;
367
- } catch (e) {
368
- return false;
324
+ if (authToken) return true;
325
+ } catch {
326
+ // return false if getAuthenticationToken fails
369
327
  }
370
328
 
371
- return true;
329
+ return false;
372
330
  };
373
331
 
374
332
  /**
@@ -514,7 +472,8 @@ export const doOIDCAuth = async (embedConfig: EmbedConfig) => {
514
472
 
515
473
  export const logout = async (embedConfig: EmbedConfig): Promise<boolean> => {
516
474
  const { thoughtSpotHost } = embedConfig;
517
- const response = await fetchLogoutService(thoughtSpotHost);
475
+ await fetchLogoutService(thoughtSpotHost);
476
+ resetCachedAuthToken();
518
477
  loggedInStatus = false;
519
478
  return loggedInStatus;
520
479
  };
@@ -0,0 +1,60 @@
1
+ import { EmbedConfig } from './types';
2
+ import { fetchAuthTokenService, verifyTokenService } from './utils/authService';
3
+
4
+ const DUPLICATE_TOKEN_ERR = 'Duplicate token, please issue a new token every time getAuthToken callback is called.'
5
+ + 'See https://developers.thoughtspot.com/docs/?pageid=embed-auth#trusted-auth-embed for more details.';
6
+
7
+ const INVALID_TOKEN_ERR = 'Invalid token received form token callback or authToken endpoint.';
8
+
9
+ let cachedAuthToken: string | null = null;
10
+
11
+ // This method can be used to get the authToken using the embedConfig
12
+ export const getAuthenticationToken = async (embedConfig: EmbedConfig): Promise<string> => {
13
+ if (cachedAuthToken) {
14
+ try {
15
+ const isCachedTokenStillValid = await validateAuthToken(embedConfig, cachedAuthToken);
16
+ if (isCachedTokenStillValid) return cachedAuthToken;
17
+ } catch {
18
+ // Continue to get a new token if validation fails
19
+ }
20
+ }
21
+
22
+ const { authEndpoint, getAuthToken } = embedConfig;
23
+
24
+ let authToken = null;
25
+ if (getAuthToken) {
26
+ authToken = await getAuthToken();
27
+ } else {
28
+ const response = await fetchAuthTokenService(authEndpoint);
29
+ authToken = await response.text();
30
+ }
31
+
32
+ // this will throw error if the token is not valid
33
+ await validateAuthToken(embedConfig, authToken);
34
+
35
+ cachedAuthToken = authToken;
36
+ return authToken;
37
+ };
38
+
39
+ const validateAuthToken = async (embedConfig: EmbedConfig, authToken: string): Promise<boolean> => {
40
+ try {
41
+ const isTokenValid = await verifyTokenService(embedConfig.thoughtSpotHost, authToken);
42
+ if (isTokenValid) return true;
43
+ } catch {
44
+ return false;
45
+ }
46
+
47
+ if (cachedAuthToken && cachedAuthToken === authToken) {
48
+ if (!embedConfig.suppressErrorAlerts) {
49
+ // eslint-disable-next-line no-alert
50
+ alert(DUPLICATE_TOKEN_ERR);
51
+ }
52
+ throw new Error(DUPLICATE_TOKEN_ERR);
53
+ } else {
54
+ throw new Error(INVALID_TOKEN_ERR);
55
+ }
56
+ };
57
+
58
+ export const resetCachedAuthToken = (): void => {
59
+ cachedAuthToken = null;
60
+ };
@@ -18,7 +18,7 @@ describe('getThoughtSpotHost', () => {
18
18
  });
19
19
  };
20
20
 
21
- expect(testFn).toThrow(TypeError);
21
+ expect(testFn).toThrow(Error);
22
22
  });
23
23
 
24
24
  test('IP address/hostname only', () => {
package/src/config.ts CHANGED
@@ -27,6 +27,9 @@ const urlRegex = new RegExp(
27
27
  * @param config
28
28
  */
29
29
  export const getThoughtSpotHost = (config: EmbedConfig): string => {
30
+ if (!config.thoughtSpotHost) {
31
+ throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
32
+ }
30
33
  const urlParts = config.thoughtSpotHost.match(urlRegex);
31
34
  if (!urlParts) {
32
35
  throw new Error(ERROR_MESSAGE.INVALID_THOUGHTSPOT_HOST);
@@ -3,6 +3,8 @@
3
3
  import EventEmitter from 'eventemitter3';
4
4
  import { EmbedConfig } from '../index';
5
5
  import * as auth from '../auth';
6
+ import * as authService from '../utils/authService';
7
+ import * as authTokenService from '../authToken';
6
8
  import * as index from '../index';
7
9
  import * as base from './base';
8
10
  import {
@@ -10,7 +12,6 @@ import {
10
12
  getAllIframeEl,
11
13
  getDocumentBody,
12
14
  getRootEl,
13
- getRootEl2,
14
15
  getIFrameSrc,
15
16
  } from '../test/test-utils';
16
17
 
@@ -107,7 +108,7 @@ describe('Base TS Embed', () => {
107
108
  };
108
109
  await index.executeTML(data);
109
110
  expect(window.fetch).toHaveBeenCalledWith(
110
- `http://${thoughtSpotHost}${auth.EndPoints.EXECUTE_TML}`,
111
+ `http://${thoughtSpotHost}${authService.EndPoints.EXECUTE_TML}`,
111
112
  {
112
113
  credentials: 'include',
113
114
  headers: {
@@ -132,7 +133,7 @@ describe('Base TS Embed', () => {
132
133
  autoLogin: true,
133
134
  });
134
135
  const embedConfig = base.getEmbedConfig();
135
- const authToken = await auth.getAuthenticationToken(embedConfig);
136
+ const authToken = await authTokenService.getAuthenticationToken(embedConfig);
136
137
  const data: base.executeTMLInput = {
137
138
  metadata_tmls: ['{"liveboard":{"name":"Parameters Liveboard"}}'],
138
139
  import_policy: 'PARTIAL',
@@ -140,7 +141,7 @@ describe('Base TS Embed', () => {
140
141
  };
141
142
  await index.executeTML(data);
142
143
  expect(window.fetch).toHaveBeenCalledWith(
143
- `http://${thoughtSpotHost}${auth.EndPoints.EXECUTE_TML}`,
144
+ `http://${thoughtSpotHost}${authService.EndPoints.EXECUTE_TML}`,
144
145
  {
145
146
  credentials: 'include',
146
147
  headers: expect.objectContaining({
@@ -210,7 +211,7 @@ describe('Base TS Embed', () => {
210
211
  };
211
212
  await index.exportTML(data);
212
213
  expect(window.fetch).toHaveBeenCalledWith(
213
- `http://${thoughtSpotHost}${auth.EndPoints.EXPORT_TML}`,
214
+ `http://${thoughtSpotHost}${authService.EndPoints.EXPORT_TML}`,
214
215
  {
215
216
  credentials: 'include',
216
217
  headers: {
@@ -351,7 +352,7 @@ describe('Base TS Embed', () => {
351
352
  });
352
353
  index.logout();
353
354
  expect(window.fetch).toHaveBeenCalledWith(
354
- `http://${thoughtSpotHost}${auth.EndPoints.LOGOUT}`,
355
+ `http://${thoughtSpotHost}${authService.EndPoints.LOGOUT}`,
355
356
  {
356
357
  credentials: 'include',
357
358
  headers: {
package/src/embed/base.ts CHANGED
@@ -10,6 +10,8 @@
10
10
  */
11
11
  import EventEmitter from 'eventemitter3';
12
12
  import uniq from 'lodash/uniq';
13
+ import { getAuthenticationToken } from '../authToken';
14
+ import { EndPoints } from '../utils/authService';
13
15
  import { getThoughtSpotHost } from '../config';
14
16
  import { AuthType, EmbedConfig, PrefetchFeatures } from '../types';
15
17
  import {
@@ -24,8 +26,6 @@ import {
24
26
  notifyLogout,
25
27
  setAuthEE,
26
28
  AuthEventEmitter,
27
- EndPoints,
28
- getAuthenticationToken,
29
29
  } from '../auth';
30
30
  import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
31
31
 
@@ -351,7 +351,6 @@ export const executeTML = async (data: executeTMLInput): Promise<any> => {
351
351
  console.error(error);
352
352
  });
353
353
  * ```
354
- *
355
354
  * @version SDK: 1.23.0 | ThoughtSpot: 9.4.0.cl
356
355
  * @group Global methods
357
356
  */
@@ -69,10 +69,6 @@ export interface SearchViewConfig
69
69
  * using raw answer data.
70
70
  */
71
71
  hideResults?: boolean;
72
- /**
73
- * If set to true, expands all the data sources panel.
74
- */
75
- expandAllDataSource?: boolean;
76
72
  /**
77
73
  * If set to true, the Search Assist feature is enabled.
78
74
  *
@@ -178,7 +174,6 @@ export class SearchEmbed extends TsEmbed {
178
174
  protected getEmbedParams(): string {
179
175
  const {
180
176
  hideResults,
181
- expandAllDataSource,
182
177
  enableSearchAssist,
183
178
  forceTable,
184
179
  searchOptions,
@@ -274,7 +269,8 @@ export class SearchEmbed extends TsEmbed {
274
269
  if (
275
270
  checkReleaseVersionInBeta(
276
271
  getReleaseVersion(),
277
- getEmbedConfig().suppressSearchEmbedBetaWarning,
272
+ getEmbedConfig().suppressSearchEmbedBetaWarning
273
+ || getEmbedConfig().suppressErrorAlerts,
278
274
  )
279
275
  ) {
280
276
  alert(ERROR_MESSAGE.SEARCHEMBED_BETA_WRANING_MESSAGE);
@@ -1,4 +1,5 @@
1
1
  /* eslint-disable dot-notation */
2
+ import { resetCachedAuthToken } from '../authToken';
2
3
  import {
3
4
  AuthType,
4
5
  init,
@@ -34,6 +35,7 @@ import * as mixpanelInstance from '../mixpanel-service';
34
35
  import * as authInstance from '../auth';
35
36
  import * as baseInstance from './base';
36
37
  import { MIXPANEL_EVENT } from '../mixpanel-service';
38
+ import * as authService from '../utils/authService';
37
39
 
38
40
  const defaultViewConfig = {
39
41
  frameParams: {
@@ -89,8 +91,51 @@ describe('Unit test case for ts embed', () => {
89
91
 
90
92
  afterEach(() => {
91
93
  jest.clearAllMocks();
94
+ resetCachedAuthToken();
92
95
  });
93
96
 
97
+ describe('AuthExpire embedEvent in cookieless authentication authType', () => {
98
+ beforeAll(() => {
99
+ jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
100
+ jest.spyOn(authService, 'verifyTokenService').mockResolvedValueOnce(true);
101
+ init({
102
+ thoughtSpotHost: 'tshost',
103
+ customizations: customisations,
104
+ customCssUrl: 'http://localhost:5000',
105
+ authType: AuthType.TrustedAuthTokenCookieless,
106
+ getAuthToken: () => Promise.resolve('test_auth_token2'),
107
+ });
108
+ });
109
+
110
+ test('check for new authToken based on getAuthToken function', async () => {
111
+ const mockEmbedEventPayload = {
112
+ type: EmbedEvent.AuthExpire,
113
+ data: {},
114
+ };
115
+ const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
116
+ jest.spyOn(baseInstance, 'notifyAuthFailure');
117
+ jest.spyOn(baseInstance, 'handleAuth');
118
+
119
+ searchEmbed.render();
120
+ const mockPort: any = {
121
+ postMessage: jest.fn(),
122
+ };
123
+ await executeAfterWait(() => {
124
+ const iframe = getIFrameEl();
125
+ postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
126
+ });
127
+ await executeAfterWait(() => {
128
+ expect(baseInstance.notifyAuthFailure).toBeCalledWith(
129
+ authInstance.AuthFailureType.EXPIRY,
130
+ );
131
+ expect(baseInstance.handleAuth).not.toHaveBeenCalled();
132
+ expect(mockPort.postMessage).toHaveBeenCalledWith({
133
+ type: EmbedEvent.AuthExpire,
134
+ data: { authToken: 'test_auth_token2' },
135
+ });
136
+ });
137
+ });
138
+ });
94
139
  describe('Called Embed event status for start and end', () => {
95
140
  beforeAll(() => {
96
141
  init({
@@ -483,7 +528,15 @@ describe('Unit test case for ts embed', () => {
483
528
  });
484
529
  });
485
530
 
531
+ afterEach(() => {
532
+ baseInstance.reset();
533
+ });
534
+
486
535
  test('check for authToken based on getAuthToken function', async () => {
536
+ const a = jest.spyOn(authService, 'verifyTokenService');
537
+ a.mockResolvedValue(true);
538
+
539
+ // authVerifyMock.mockResolvedValue(true);
487
540
  const mockEmbedEventPayload = {
488
541
  type: EmbedEvent.APP_INIT,
489
542
  data: {},
@@ -511,47 +564,8 @@ describe('Unit test case for ts embed', () => {
511
564
  },
512
565
  });
513
566
  });
514
- });
515
- });
516
567
 
517
- describe('AuthExpire embedEvent in cookieless authentication authType', () => {
518
- beforeAll(() => {
519
- jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
520
- init({
521
- thoughtSpotHost: 'tshost',
522
- customizations: customisations,
523
- customCssUrl: 'http://localhost:5000',
524
- authType: AuthType.TrustedAuthTokenCookieless,
525
- getAuthToken: () => Promise.resolve('test_auth_token2'),
526
- });
527
- });
528
-
529
- test('check for new authToken based on getAuthToken function', async () => {
530
- const mockEmbedEventPayload = {
531
- type: EmbedEvent.AuthExpire,
532
- data: {},
533
- };
534
- const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
535
- jest.spyOn(baseInstance, 'notifyAuthFailure');
536
- jest.spyOn(baseInstance, 'handleAuth');
537
- searchEmbed.render();
538
- const mockPort: any = {
539
- postMessage: jest.fn(),
540
- };
541
- await executeAfterWait(() => {
542
- const iframe = getIFrameEl();
543
- postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
544
- });
545
- await executeAfterWait(() => {
546
- expect(baseInstance.notifyAuthFailure).toBeCalledWith(
547
- authInstance.AuthFailureType.EXPIRY,
548
- );
549
- expect(baseInstance.handleAuth).not.toHaveBeenCalled();
550
- expect(mockPort.postMessage).toHaveBeenCalledWith({
551
- type: EmbedEvent.AuthExpire,
552
- data: { authToken: 'test_auth_token2' },
553
- });
554
- });
568
+ jest.spyOn(authService, 'verifyTokenService').mockClear();
555
569
  });
556
570
  });
557
571
 
@@ -9,6 +9,7 @@
9
9
 
10
10
  import isEqual from 'lodash/isEqual';
11
11
 
12
+ import { getAuthenticationToken } from '../authToken';
12
13
  import { AnswerService } from '../utils/graphql/answerService/answerService';
13
14
  import {
14
15
  getEncodedQueryParamsString,
@@ -61,7 +62,7 @@ import {
61
62
  handleAuth,
62
63
  notifyAuthFailure,
63
64
  } from './base';
64
- import { AuthFailureType, getAuthenticationToken } from '../auth';
65
+ import { AuthFailureType } from '../auth';
65
66
 
66
67
  const { version } = pkgInfo;
67
68
 
@@ -199,35 +199,6 @@ describe('React Components', () => {
199
199
  ).toBe(true);
200
200
  expect(containerSibling.querySelector('div')).toBe(null);
201
201
  });
202
-
203
- it('Should have the correct container element', async () => {
204
- const { container } = render(
205
- <LiveboardEmbed liveboardId="abcd" className="def" />,
206
- );
207
-
208
- await waitFor(() => getIFrameEl(container));
209
- expect(container.querySelector('div')).not.toBe(null);
210
- expect(
211
- container.querySelector('div').classList.contains('def'),
212
- ).toBe(true);
213
-
214
- const { container: containerSibling } = render(
215
- <LiveboardEmbed
216
- liveboardId="abcd"
217
- className="def"
218
- insertAsSibling={true}
219
- />,
220
- );
221
- await waitFor(() => getIFrameEl(containerSibling));
222
- expect(containerSibling.querySelector('span')).not.toBe(null);
223
- expect(containerSibling.querySelector('span').style.position).toBe(
224
- 'absolute',
225
- );
226
- expect(
227
- getIFrameEl(containerSibling).classList.contains('def'),
228
- ).toBe(true);
229
- expect(containerSibling.querySelector('div')).toBe(null);
230
- });
231
202
  });
232
203
 
233
204
  describe('SearchBarEmbed', () => {
@@ -0,0 +1,16 @@
1
+ import { getAuthenticationToken } from './authToken';
2
+ import { getEmbedConfig } from './embed/base';
3
+ import { AuthType } from './types';
4
+
5
+ export const tokenizedFetch: typeof fetch = async (input, init) : Promise<Response> => {
6
+ const req = new Request(input, init);
7
+ const embedConfig = getEmbedConfig();
8
+ if (embedConfig.authType !== AuthType.TrustedAuthTokenCookieless) {
9
+ return fetch(req);
10
+ }
11
+ const authToken = await getAuthenticationToken(embedConfig);
12
+ if (authToken) {
13
+ req.headers.append('Authorization', `Bearer ${authToken}`);
14
+ }
15
+ return fetch(req);
16
+ };