@thoughtspot/visual-embed-sdk 1.31.1 → 1.32.0-alpha.1

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 (234) hide show
  1. package/cjs/package.json +2 -2
  2. package/cjs/src/auth.d.ts +14 -16
  3. package/cjs/src/auth.d.ts.map +1 -1
  4. package/cjs/src/auth.js +57 -66
  5. package/cjs/src/auth.js.map +1 -1
  6. package/cjs/src/auth.spec.d.ts +12 -0
  7. package/cjs/src/auth.spec.d.ts.map +1 -1
  8. package/cjs/src/auth.spec.js +89 -67
  9. package/cjs/src/auth.spec.js.map +1 -1
  10. package/cjs/src/authToken.d.ts +1 -1
  11. package/cjs/src/authToken.d.ts.map +1 -1
  12. package/cjs/src/authToken.js +10 -4
  13. package/cjs/src/authToken.js.map +1 -1
  14. package/cjs/src/embed/app.spec.js +4 -2
  15. package/cjs/src/embed/app.spec.js.map +1 -1
  16. package/cjs/src/embed/base.d.ts.map +1 -1
  17. package/cjs/src/embed/base.js +2 -0
  18. package/cjs/src/embed/base.js.map +1 -1
  19. package/cjs/src/embed/base.spec.js +1 -0
  20. package/cjs/src/embed/base.spec.js.map +1 -1
  21. package/cjs/src/embed/embed.spec.js +3 -0
  22. package/cjs/src/embed/embed.spec.js.map +1 -1
  23. package/cjs/src/embed/events.spec.js +3 -0
  24. package/cjs/src/embed/events.spec.js.map +1 -1
  25. package/cjs/src/embed/liveboard.spec.js +2 -0
  26. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  27. package/cjs/src/embed/pinboard.spec.js +3 -0
  28. package/cjs/src/embed/pinboard.spec.js.map +1 -1
  29. package/cjs/src/embed/sage.spec.js +3 -0
  30. package/cjs/src/embed/sage.spec.js.map +1 -1
  31. package/cjs/src/embed/search.spec.js +1 -0
  32. package/cjs/src/embed/search.spec.js.map +1 -1
  33. package/cjs/src/embed/ts-embed-trigger.spec.js +3 -0
  34. package/cjs/src/embed/ts-embed-trigger.spec.js.map +1 -1
  35. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  36. package/cjs/src/embed/ts-embed.js +1 -0
  37. package/cjs/src/embed/ts-embed.js.map +1 -1
  38. package/cjs/src/embed/ts-embed.spec.js +7 -0
  39. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  40. package/cjs/src/index.d.ts +2 -1
  41. package/cjs/src/index.d.ts.map +1 -1
  42. package/cjs/src/index.js +2 -1
  43. package/cjs/src/index.js.map +1 -1
  44. package/cjs/src/mixpanel-service.d.ts +2 -1
  45. package/cjs/src/mixpanel-service.d.ts.map +1 -1
  46. package/cjs/src/mixpanel-service.js +1 -0
  47. package/cjs/src/mixpanel-service.js.map +1 -1
  48. package/cjs/src/mixpanel-service.spec.js +7 -0
  49. package/cjs/src/mixpanel-service.spec.js.map +1 -1
  50. package/cjs/src/react/index.d.ts +1 -1
  51. package/cjs/src/react/index.d.ts.map +1 -1
  52. package/cjs/src/react/index.js +2 -1
  53. package/cjs/src/react/index.js.map +1 -1
  54. package/cjs/src/react/index.spec.js +6 -0
  55. package/cjs/src/react/index.spec.js.map +1 -1
  56. package/cjs/src/tokenizedFetch.d.ts +8 -0
  57. package/cjs/src/tokenizedFetch.d.ts.map +1 -1
  58. package/cjs/src/tokenizedFetch.js +8 -0
  59. package/cjs/src/tokenizedFetch.js.map +1 -1
  60. package/cjs/src/types.d.ts +12 -12
  61. package/cjs/src/types.d.ts.map +1 -1
  62. package/cjs/src/types.js +12 -12
  63. package/cjs/src/types.js.map +1 -1
  64. package/cjs/src/utils/authService/authService.d.ts +1 -0
  65. package/cjs/src/utils/authService/authService.d.ts.map +1 -1
  66. package/cjs/src/utils/authService/authService.js +1 -0
  67. package/cjs/src/utils/authService/authService.js.map +1 -1
  68. package/cjs/src/utils/authService/authService.spec.js +18 -5
  69. package/cjs/src/utils/authService/authService.spec.js.map +1 -1
  70. package/cjs/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  71. package/cjs/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  72. package/cjs/src/utils/authService/tokenizedAuthService.js +39 -9
  73. package/cjs/src/utils/authService/tokenizedAuthService.js.map +1 -1
  74. package/cjs/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  75. package/cjs/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  76. package/cjs/src/utils/authService/tokenizedAuthService.spec.js +32 -0
  77. package/cjs/src/utils/authService/tokenizedAuthService.spec.js.map +1 -0
  78. package/cjs/src/utils/processData.js +2 -2
  79. package/cjs/src/utils/processData.js.map +1 -1
  80. package/cjs/src/utils/processData.spec.js +3 -2
  81. package/cjs/src/utils/processData.spec.js.map +1 -1
  82. package/cjs/src/utils/sessionInfoService.d.ts +66 -0
  83. package/cjs/src/utils/sessionInfoService.d.ts.map +1 -0
  84. package/cjs/src/utils/sessionInfoService.js +92 -0
  85. package/cjs/src/utils/sessionInfoService.js.map +1 -0
  86. package/dist/src/auth.d.ts +14 -16
  87. package/dist/src/auth.d.ts.map +1 -1
  88. package/dist/src/auth.spec.d.ts +12 -0
  89. package/dist/src/auth.spec.d.ts.map +1 -1
  90. package/dist/src/authToken.d.ts +1 -1
  91. package/dist/src/authToken.d.ts.map +1 -1
  92. package/dist/src/embed/base.d.ts.map +1 -1
  93. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  94. package/dist/src/index.d.ts +2 -1
  95. package/dist/src/index.d.ts.map +1 -1
  96. package/dist/src/mixpanel-service.d.ts +2 -1
  97. package/dist/src/mixpanel-service.d.ts.map +1 -1
  98. package/dist/src/react/index.d.ts +1 -1
  99. package/dist/src/react/index.d.ts.map +1 -1
  100. package/dist/src/tokenizedFetch.d.ts +8 -0
  101. package/dist/src/tokenizedFetch.d.ts.map +1 -1
  102. package/dist/src/types.d.ts +12 -12
  103. package/dist/src/types.d.ts.map +1 -1
  104. package/dist/src/utils/authService/authService.d.ts +1 -0
  105. package/dist/src/utils/authService/authService.d.ts.map +1 -1
  106. package/dist/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  107. package/dist/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  108. package/dist/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  109. package/dist/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  110. package/dist/src/utils/sessionInfoService.d.ts +66 -0
  111. package/dist/src/utils/sessionInfoService.d.ts.map +1 -0
  112. package/dist/tsembed-react.es.js +169 -77
  113. package/dist/tsembed-react.js +169 -76
  114. package/dist/tsembed.es.js +177 -87
  115. package/dist/tsembed.js +177 -87
  116. package/dist/visual-embed-sdk-react-full.d.ts +102 -30
  117. package/dist/visual-embed-sdk-react.d.ts +102 -30
  118. package/dist/visual-embed-sdk.d.ts +102 -30
  119. package/lib/package.json +2 -2
  120. package/lib/src/auth.d.ts +14 -16
  121. package/lib/src/auth.d.ts.map +1 -1
  122. package/lib/src/auth.js +56 -63
  123. package/lib/src/auth.js.map +1 -1
  124. package/lib/src/auth.spec.d.ts +12 -0
  125. package/lib/src/auth.spec.d.ts.map +1 -1
  126. package/lib/src/auth.spec.js +88 -66
  127. package/lib/src/auth.spec.js.map +1 -1
  128. package/lib/src/authToken.d.ts +1 -1
  129. package/lib/src/authToken.d.ts.map +1 -1
  130. package/lib/src/authToken.js +10 -4
  131. package/lib/src/authToken.js.map +1 -1
  132. package/lib/src/embed/app.spec.js +4 -2
  133. package/lib/src/embed/app.spec.js.map +1 -1
  134. package/lib/src/embed/base.d.ts.map +1 -1
  135. package/lib/src/embed/base.js +3 -1
  136. package/lib/src/embed/base.js.map +1 -1
  137. package/lib/src/embed/base.spec.js +1 -0
  138. package/lib/src/embed/base.spec.js.map +1 -1
  139. package/lib/src/embed/embed.spec.js +2 -0
  140. package/lib/src/embed/embed.spec.js.map +1 -1
  141. package/lib/src/embed/events.spec.js +2 -0
  142. package/lib/src/embed/events.spec.js.map +1 -1
  143. package/lib/src/embed/liveboard.spec.js +2 -0
  144. package/lib/src/embed/liveboard.spec.js.map +1 -1
  145. package/lib/src/embed/pinboard.spec.js +2 -0
  146. package/lib/src/embed/pinboard.spec.js.map +1 -1
  147. package/lib/src/embed/sage.spec.js +2 -0
  148. package/lib/src/embed/sage.spec.js.map +1 -1
  149. package/lib/src/embed/search.spec.js +1 -0
  150. package/lib/src/embed/search.spec.js.map +1 -1
  151. package/lib/src/embed/ts-embed-trigger.spec.js +2 -0
  152. package/lib/src/embed/ts-embed-trigger.spec.js.map +1 -1
  153. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  154. package/lib/src/embed/ts-embed.js +1 -0
  155. package/lib/src/embed/ts-embed.js.map +1 -1
  156. package/lib/src/embed/ts-embed.spec.js +7 -0
  157. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  158. package/lib/src/index.d.ts +2 -1
  159. package/lib/src/index.d.ts.map +1 -1
  160. package/lib/src/index.js +2 -1
  161. package/lib/src/index.js.map +1 -1
  162. package/lib/src/mixpanel-service.d.ts +2 -1
  163. package/lib/src/mixpanel-service.d.ts.map +1 -1
  164. package/lib/src/mixpanel-service.js +1 -0
  165. package/lib/src/mixpanel-service.js.map +1 -1
  166. package/lib/src/mixpanel-service.spec.js +7 -0
  167. package/lib/src/mixpanel-service.spec.js.map +1 -1
  168. package/lib/src/react/index.d.ts +1 -1
  169. package/lib/src/react/index.d.ts.map +1 -1
  170. package/lib/src/react/index.js +1 -1
  171. package/lib/src/react/index.js.map +1 -1
  172. package/lib/src/react/index.spec.js +6 -0
  173. package/lib/src/react/index.spec.js.map +1 -1
  174. package/lib/src/tokenizedFetch.d.ts +8 -0
  175. package/lib/src/tokenizedFetch.d.ts.map +1 -1
  176. package/lib/src/tokenizedFetch.js +8 -0
  177. package/lib/src/tokenizedFetch.js.map +1 -1
  178. package/lib/src/types.d.ts +12 -12
  179. package/lib/src/types.d.ts.map +1 -1
  180. package/lib/src/types.js +12 -12
  181. package/lib/src/types.js.map +1 -1
  182. package/lib/src/utils/authService/authService.d.ts +1 -0
  183. package/lib/src/utils/authService/authService.d.ts.map +1 -1
  184. package/lib/src/utils/authService/authService.js +1 -0
  185. package/lib/src/utils/authService/authService.js.map +1 -1
  186. package/lib/src/utils/authService/authService.spec.js +18 -5
  187. package/lib/src/utils/authService/authService.spec.js.map +1 -1
  188. package/lib/src/utils/authService/tokenizedAuthService.d.ts +15 -2
  189. package/lib/src/utils/authService/tokenizedAuthService.d.ts.map +1 -1
  190. package/lib/src/utils/authService/tokenizedAuthService.js +37 -8
  191. package/lib/src/utils/authService/tokenizedAuthService.js.map +1 -1
  192. package/lib/src/utils/authService/tokenizedAuthService.spec.d.ts +2 -0
  193. package/lib/src/utils/authService/tokenizedAuthService.spec.d.ts.map +1 -0
  194. package/lib/src/utils/authService/tokenizedAuthService.spec.js +29 -0
  195. package/lib/src/utils/authService/tokenizedAuthService.spec.js.map +1 -0
  196. package/lib/src/utils/processData.js +3 -3
  197. package/lib/src/utils/processData.js.map +1 -1
  198. package/lib/src/utils/processData.spec.js +3 -2
  199. package/lib/src/utils/processData.spec.js.map +1 -1
  200. package/lib/src/utils/sessionInfoService.d.ts +66 -0
  201. package/lib/src/utils/sessionInfoService.d.ts.map +1 -0
  202. package/lib/src/utils/sessionInfoService.js +85 -0
  203. package/lib/src/utils/sessionInfoService.js.map +1 -0
  204. package/lib/src/visual-embed-sdk.d.ts +107 -31
  205. package/package.json +2 -2
  206. package/src/auth.spec.ts +92 -72
  207. package/src/auth.ts +57 -75
  208. package/src/authToken.ts +9 -4
  209. package/src/embed/app.spec.ts +4 -2
  210. package/src/embed/base.spec.ts +1 -0
  211. package/src/embed/base.ts +3 -0
  212. package/src/embed/embed.spec.ts +2 -0
  213. package/src/embed/events.spec.ts +2 -0
  214. package/src/embed/liveboard.spec.ts +2 -0
  215. package/src/embed/pinboard.spec.ts +2 -0
  216. package/src/embed/sage.spec.ts +3 -0
  217. package/src/embed/search.spec.ts +1 -0
  218. package/src/embed/ts-embed-trigger.spec.ts +3 -0
  219. package/src/embed/ts-embed.spec.ts +8 -0
  220. package/src/embed/ts-embed.ts +1 -0
  221. package/src/index.ts +2 -1
  222. package/src/mixpanel-service.spec.ts +12 -3
  223. package/src/mixpanel-service.ts +3 -1
  224. package/src/react/index.spec.tsx +7 -0
  225. package/src/react/index.tsx +1 -0
  226. package/src/tokenizedFetch.ts +8 -0
  227. package/src/types.ts +13 -12
  228. package/src/utils/authService/authService.spec.ts +18 -5
  229. package/src/utils/authService/authService.ts +1 -0
  230. package/src/utils/authService/tokenizedAuthService.spec.ts +36 -0
  231. package/src/utils/authService/tokenizedAuthService.ts +38 -8
  232. package/src/utils/processData.spec.ts +3 -2
  233. package/src/utils/processData.ts +3 -3
  234. package/src/utils/sessionInfoService.ts +101 -0
@@ -9,6 +9,7 @@ import {
9
9
  getIFrameEl,
10
10
  getRootEl,
11
11
  } from '../test/test-utils';
12
+ import * as authInstance from '../auth';
12
13
 
13
14
  const thoughtSpotHost = 'tshost';
14
15
  const defaultViewConfig = {
@@ -24,6 +25,7 @@ beforeAll(() => {
24
25
  authType: AuthType.None,
25
26
  });
26
27
  spyOn(window, 'alert');
28
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
27
29
  });
28
30
 
29
31
  describe('test view config', () => {
@@ -20,6 +20,7 @@ import {
20
20
  postMessageToParent,
21
21
  } from '../test/test-utils';
22
22
  import { LiveboardViewConfig } from './liveboard';
23
+ import * as authInstance from '../auth';
23
24
 
24
25
  const thoughtSpotHost = 'tshost';
25
26
  const defaultViewConfig = {
@@ -36,6 +37,7 @@ beforeAll(() => {
36
37
  authType: AuthType.None,
37
38
  });
38
39
  spyOn(window, 'alert');
40
+ jest.spyOn(authInstance, 'postLoginService').mockReturnValue(true);
39
41
  });
40
42
 
41
43
  describe('test communication between host app and ThoughtSpot', () => {
@@ -23,6 +23,7 @@ import {
23
23
  } from '../test/test-utils';
24
24
  import * as tsEmbed from './ts-embed';
25
25
  import * as processTriggerInstance from '../utils/processTrigger';
26
+ import * as auth from '../auth';
26
27
 
27
28
  const defaultViewConfig = {
28
29
  frameParams: {
@@ -43,6 +44,7 @@ beforeAll(() => {
43
44
  thoughtSpotHost,
44
45
  authType: AuthType.None,
45
46
  });
47
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
46
48
  });
47
49
 
48
50
  describe('Liveboard/viz embed tests', () => {
@@ -13,6 +13,7 @@ import {
13
13
  expectUrlMatchesWithParams,
14
14
  } from '../test/test-utils';
15
15
  import { version } from '../../package.json';
16
+ import * as auth from '../auth';
16
17
 
17
18
  const defaultViewConfig = {
18
19
  frameParams: {
@@ -30,6 +31,7 @@ beforeAll(() => {
30
31
  thoughtSpotHost,
31
32
  authType: AuthType.None,
32
33
  });
34
+ jest.spyOn(auth, 'postLoginService').mockReturnValue(true);
33
35
  });
34
36
 
35
37
  describe('Pinboard/viz embed tests', () => {
@@ -9,6 +9,8 @@ import {
9
9
  getRootEl,
10
10
  } from '../test/test-utils';
11
11
 
12
+ import * as authInstance from '../auth';
13
+
12
14
  const defaultConfig: SageViewConfig = {
13
15
  disableWorksheetChange: false,
14
16
  hideWorksheetSelector: false,
@@ -26,6 +28,7 @@ beforeAll(() => {
26
28
  authType: AuthType.None,
27
29
  });
28
30
  spyOn(window, 'alert');
31
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
29
32
  });
30
33
 
31
34
  describe('Sage embed tests', () => {
@@ -36,6 +36,7 @@ beforeAll(() => {
36
36
  thoughtSpotHost,
37
37
  authType: AuthType.None,
38
38
  });
39
+ jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
39
40
  spyOn(window, 'alert');
40
41
  });
41
42
 
@@ -8,9 +8,12 @@ import {
8
8
  getRootEl,
9
9
  } from '../test/test-utils';
10
10
 
11
+ import * as authInstance from '../auth';
12
+
11
13
  describe('Trigger', () => {
12
14
  beforeEach(() => {
13
15
  document.body.innerHTML = getDocumentBody();
16
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
14
17
  });
15
18
  test('should trigger the event', async (done) => {
16
19
  init({
@@ -84,6 +84,10 @@ describe('Unit test case for ts embed', () => {
84
84
  resetCachedAuthToken();
85
85
  });
86
86
 
87
+ beforeAll(() => {
88
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
89
+ });
90
+
87
91
  describe('AuthExpire embedEvent in cookieless authentication authType', () => {
88
92
  beforeAll(() => {
89
93
  jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
@@ -730,6 +734,7 @@ describe('Unit test case for ts embed', () => {
730
734
  const mockPort: any = {
731
735
  postMessage: jest.fn(),
732
736
  };
737
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
733
738
  await executeAfterWait(() => {
734
739
  const iframe = getIFrameEl();
735
740
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
@@ -739,6 +744,7 @@ describe('Unit test case for ts embed', () => {
739
744
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
740
745
  authInstance.AuthFailureType.EXPIRY,
741
746
  );
747
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
742
748
  });
743
749
 
744
750
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -757,6 +763,7 @@ describe('Unit test case for ts embed', () => {
757
763
  const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test' });
758
764
  jest.spyOn(baseInstance, 'notifyAuthFailure');
759
765
  searchEmbed.preRender();
766
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
760
767
  const mockPort: any = {
761
768
  postMessage: jest.fn(),
762
769
  };
@@ -770,6 +777,7 @@ describe('Unit test case for ts embed', () => {
770
777
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
771
778
  authInstance.AuthFailureType.EXPIRY,
772
779
  );
780
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
773
781
  });
774
782
 
775
783
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -347,6 +347,7 @@ export class TsEmbed {
347
347
  data: { authToken },
348
348
  });
349
349
  } catch (e) {
350
+ logger.error(`Received invalid token. Error : ${e?.message}`);
350
351
  processAuthFailure(e, this.isPreRendered ? this.preRenderWrapper : this.el);
351
352
  }
352
353
  } else if (autoLogin) {
package/src/index.ts CHANGED
@@ -20,8 +20,9 @@ import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/live
20
20
  import { SearchEmbed, SearchViewConfig } from './embed/search';
21
21
  import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
22
22
  import {
23
- AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter, getSessionInfo,
23
+ AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
24
24
  } from './auth';
25
+ import { getSessionInfo } from './utils/sessionInfoService';
25
26
  import {
26
27
  AuthType,
27
28
  RuntimeFilter,
@@ -6,6 +6,8 @@ import {
6
6
  testResetMixpanel,
7
7
  } from './mixpanel-service';
8
8
  import { AuthType } from './types';
9
+ import { SessionInfo } from './utils/sessionInfoService';
10
+ import { logger } from './utils/logger';
9
11
 
10
12
  const config = {
11
13
  thoughtSpotHost: 'https://10.87.89.232',
@@ -29,7 +31,7 @@ describe('Unit test for mixpanel', () => {
29
31
  mixpanelToken: 'abc123',
30
32
  userGUID: '12345',
31
33
  isPublicUser: false,
32
- };
34
+ } as SessionInfo;
33
35
  initMixpanel(sessionInfo);
34
36
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
35
37
  expect(mixpanel.identify).toHaveBeenCalledWith(sessionInfo.userGUID);
@@ -49,7 +51,7 @@ describe('Unit test for mixpanel', () => {
49
51
  clusterId: 'newClusterId',
50
52
  clusterName: 'newClusterName',
51
53
  releaseVersion: 'newReleaseVersion',
52
- };
54
+ } as SessionInfo;
53
55
  initMixpanel(sessionInfo);
54
56
 
55
57
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
@@ -74,8 +76,15 @@ describe('Unit test for mixpanel', () => {
74
76
  mixpanelToken: 'abc123',
75
77
  userGUID: '12345',
76
78
  isPublicUser: false,
77
- };
79
+ } as SessionInfo;
78
80
  initMixpanel(sessionInfo);
79
81
  expect(mixpanel.track).toHaveBeenCalledTimes(2);
80
82
  });
83
+
84
+ test('init mixpanel with no mixpanel token', () => {
85
+ jest.spyOn(logger, 'error').mockReturnValueOnce(true);
86
+ initMixpanel({ test: 'dummy' } as any);
87
+ expect(logger.error).toHaveBeenCalled();
88
+ expect(mixpanel.register_once).not.toHaveBeenCalled();
89
+ });
81
90
  });
@@ -1,5 +1,6 @@
1
1
  import * as mixpanel from 'mixpanel-browser';
2
2
  import { logger } from './utils/logger';
3
+ import { SessionInfo } from './utils/sessionInfoService';
3
4
 
4
5
  export const EndPoints = {
5
6
  CONFIG: '/callosum/v1/system/config',
@@ -54,8 +55,9 @@ function emptyQueue() {
54
55
  *
55
56
  * @param sessionInfo
56
57
  */
57
- export function initMixpanel(sessionInfo: any): void {
58
+ export function initMixpanel(sessionInfo: SessionInfo): void {
58
59
  if (!sessionInfo || !sessionInfo.mixpanelToken) {
60
+ logger.error('Mixpanel token not found in session info');
59
61
  return;
60
62
  }
61
63
  // On a public cluster the user is anonymous, so don't set the identify to
@@ -24,6 +24,9 @@ import {
24
24
 
25
25
  import { version } from '../../package.json';
26
26
 
27
+ import * as auth from '../auth';
28
+ import * as sessionService from '../utils/sessionInfoService';
29
+
27
30
  const thoughtSpotHost = 'localhost';
28
31
 
29
32
  beforeAll(() => {
@@ -31,6 +34,10 @@ beforeAll(() => {
31
34
  thoughtSpotHost,
32
35
  authType: AuthType.None,
33
36
  });
37
+ jest.spyOn(auth, 'postLoginService').mockReturnValue(true);
38
+ jest.spyOn(sessionService, 'getSessionInfo').mockReturnValue({
39
+ userGUID: 'abcd',
40
+ });
34
41
  spyOn(window, 'alert');
35
42
  });
36
43
 
@@ -370,4 +370,5 @@ export {
370
370
  HomeLeftNavItem,
371
371
  HomepageModule,
372
372
  LogLevel,
373
+ getSessionInfo,
373
374
  } from '../index';
@@ -6,8 +6,16 @@ import { AuthType } from './types';
6
6
  /**
7
7
  * Fetch wrapper that adds the authentication token to the request.
8
8
  * Use this to call the ThoughtSpot APIs when using the visual embed sdk.
9
+ * The interface for this method is the same as Web `Fetch`.
10
+ *
9
11
  * @param input
10
12
  * @param init
13
+ * @example
14
+ * ```js
15
+ * tokenizedFetch("<TS_ORIGIN>/api/rest/2.0/auth/session/user", {
16
+ * // .. fetch options ..
17
+ * });
18
+ *```
11
19
  * @version SDK: 1.28.0
12
20
  * @group Global methods
13
21
  */
package/src/types.ts CHANGED
@@ -2105,13 +2105,12 @@ export enum EmbedEvent {
2105
2105
  * Emitted when parameter changes in an answer
2106
2106
  * or liveboard
2107
2107
  *
2108
- * @version SDK : 1.29.0 | Thoughtspot : 10.2.0.cl
2109
- * @example
2110
2108
  * ```js
2111
2109
  * liveboardEmbed.on(EmbedEvent.ParameterChanged, (payload) => {
2112
2110
  * console.log('payload', payload);
2113
2111
  * })
2114
2112
  *```
2113
+ * @version SDK : 1.29.0 | Thoughtspot : 10.2.0.cl
2115
2114
  */
2116
2115
  ParameterChanged = 'parameterChanged'
2117
2116
  }
@@ -2333,7 +2332,7 @@ export enum HostEvent {
2333
2332
  * sorting, toggling of legends, and data drill down.
2334
2333
  * @example
2335
2334
  * ```js
2336
- * liveboardEmbed.trigger(HostEvent.getexportrequestforcurrentpinboard).then(
2335
+ * liveboardEmbed.trigger(HostEvent.getExportRequestForCurrentPinboard).then(
2337
2336
  * data=>console.log(data))
2338
2337
  * ```
2339
2338
  * @version SDK: 1.13.0 | ThoughtSpot: 8.5.0.cl, 8.8.1.sw
@@ -2943,15 +2942,6 @@ export enum HostEvent {
2943
2942
  * @version SDK: 1.29.0 | Thoughtspot: 10.1.0.cl
2944
2943
  */
2945
2944
  ResetLiveboardPersonalisedView = 'ResetLiveboardPersonalisedView',
2946
- /**
2947
- * Trigger CreateLiveboard for liveboard list page & Pin Modal
2948
- * @example
2949
- * ```js
2950
- * liveboardEmbed.trigger(HostEvent.CreateLiveboard);
2951
- *
2952
- * @version SDK: 1.29.0 | Thoughtspot: 10.1.0.cl
2953
- */
2954
- CreateLiveboard = 'CreateLiveboard',
2955
2945
  /**
2956
2946
  * Triggers Update RuntimeParameters for answers and liveboard
2957
2947
  * @example
@@ -3947,6 +3937,17 @@ export enum Action {
3947
3937
  */
3948
3938
  TML = 'tml',
3949
3939
 
3940
+ /**
3941
+ * Action Id for CreateLiveboard for liveboard list page & Pin Modal
3942
+ * @example
3943
+ * ```js
3944
+ * hiddenAction: [Action.CreateLiveboard]
3945
+ * disabledActions: [Action.CreateLiveboard]
3946
+ *
3947
+ * @version SDK: 1.31.1 | Thoughtspot: 10.1.0.cl
3948
+ */
3949
+ CreateLiveboard = 'CreateLiveboard',
3950
+
3950
3951
  /**
3951
3952
  * Action ID for to hide Verified Liveboard Banner
3952
3953
  * @example
@@ -26,9 +26,10 @@ describe('Unit test for authService', () => {
26
26
  status: 200,
27
27
  ok: true,
28
28
  }));
29
- const response = await fetchSessionInfoService(authVerificationUrl);
30
- expect(response.status).toBe(200);
29
+ const response = await fetchSessionInfoService(thoughtSpotHost);
30
+ expect(response.success).toBe(true);
31
31
  expect(fetch).toHaveBeenCalledTimes(1);
32
+ expect(fetch).toBeCalledWith(`${thoughtSpotHost}${EndPoints.SESSION_INFO}`, {});
32
33
  });
33
34
 
34
35
  test('fetchAuthTokenService', async () => {
@@ -108,11 +109,15 @@ describe('Unit test for authService', () => {
108
109
  status: 500,
109
110
  ok: false,
110
111
  }));
111
- await fetchSessionInfoService(authVerificationUrl);
112
- expect(logger.error).toHaveBeenCalledWith('Failure', 'error');
112
+ try {
113
+ await fetchSessionInfoService(authVerificationUrl);
114
+ } catch (e) {
115
+ expect(e.message).toContain('Failed to fetch session info');
116
+ }
117
+ expect(logger.error).toHaveBeenCalledWith('Failed to fetch http://localhost:3000/callosum/v1/session/info', 'error');
113
118
  });
114
119
 
115
- test('verifyTokenService', async () => {
120
+ test('verifyTokenService if token api works', async () => {
116
121
  global.fetch = jest.fn(() => Promise.resolve({ success: true, ok: true }));
117
122
  await verifyTokenService(thoughtSpotHost, authToken);
118
123
  expect(fetch).toBeCalledWith(`${thoughtSpotHost}${EndPoints.IS_ACTIVE}`, {
@@ -123,4 +128,12 @@ describe('Unit test for authService', () => {
123
128
  },
124
129
  });
125
130
  });
131
+
132
+ test('verifyTokenService if token api fails', async () => {
133
+ global.fetch = jest.fn(() => Promise.reject(new Error('error')));
134
+ jest.spyOn(logger, 'warn');
135
+ const status = await verifyTokenService(thoughtSpotHost, authToken);
136
+ expect(status).toBe(false);
137
+ expect(logger.warn).toHaveBeenCalledWith('Token Verification Service failed : error');
138
+ });
126
139
  });
@@ -2,6 +2,7 @@ import { logger } from '../logger';
2
2
 
3
3
  export const EndPoints = {
4
4
  AUTH_VERIFICATION: '/callosum/v1/session/info',
5
+ SESSION_INFO: '/callosum/v1/session/info',
5
6
  SAML_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/saml/login?targetURLPath=${targetUrl}`,
6
7
  OIDC_LOGIN_TEMPLATE: (targetUrl: string) => `/callosum/v1/oidc/login?targetURLPath=${targetUrl}`,
7
8
  TOKEN_LOGIN: '/callosum/v1/session/login/token',
@@ -0,0 +1,36 @@
1
+ import * as tokenizedFetchModule from '../../tokenizedFetch';
2
+ import { isActiveService } from './tokenizedAuthService';
3
+ import { logger } from '../logger';
4
+
5
+ describe('tokenizedAuthService', () => {
6
+ test('isActiveService is fetch returns ok', async () => {
7
+ jest.spyOn(tokenizedFetchModule, 'tokenizedFetch').mockResolvedValueOnce({
8
+ ok: true,
9
+ });
10
+
11
+ const isActiveResp = await isActiveService('http://thoughtspotHost');
12
+
13
+ expect(isActiveResp).toEqual(true);
14
+ });
15
+ test('isActiveService if fetch returns not ok', async () => {
16
+ jest.spyOn(tokenizedFetchModule, 'tokenizedFetch').mockResolvedValueOnce({
17
+ ok: false,
18
+ });
19
+
20
+ const isActiveResp = await isActiveService('http://thoughtspotHost');
21
+
22
+ expect(isActiveResp).toEqual(false);
23
+ });
24
+
25
+ test('isActiveService if fetch fails', async () => {
26
+ jest.spyOn(tokenizedFetchModule, 'tokenizedFetch').mockRejectedValueOnce({
27
+ ok: false,
28
+ });
29
+ jest.spyOn(logger, 'warn');
30
+
31
+ const isActiveResp = await isActiveService('http://thoughtspotHost');
32
+
33
+ expect(isActiveResp).toEqual(false);
34
+ expect(logger.warn).toHaveBeenCalled();
35
+ });
36
+ });
@@ -7,23 +7,33 @@ import { EndPoints } from './authService';
7
7
  * @param url
8
8
  * @param options
9
9
  */
10
- function tokenisedFailureLoggedFetch(url: string, options: RequestInit = {}): Promise<Response> {
10
+ function tokenizedFailureLoggedFetch(url: string, options: RequestInit = {}): Promise<Response> {
11
11
  return tokenizedFetch(url, options).then(async (r) => {
12
12
  if (!r.ok && r.type !== 'opaqueredirect' && r.type !== 'opaque') {
13
- logger.error('Failure', await r.text?.());
13
+ logger.error(`Failed to fetch ${url}`, await r.text?.());
14
14
  }
15
15
  return r;
16
16
  });
17
17
  }
18
18
 
19
19
  /**
20
+ * Fetches the session info from the ThoughtSpot server.
20
21
  *
21
- * @param authVerificationUrl
22
+ * @param thoughtspotHost
23
+ * @returns {Promise<any>}
24
+ * @example
25
+ * ```js
26
+ * const response = await sessionInfoService();
27
+ * ```
22
28
  */
23
- export function fetchSessionInfoService(authVerificationUrl: string): Promise<any> {
24
- return tokenisedFailureLoggedFetch(authVerificationUrl, {
25
- credentials: 'include',
26
- });
29
+ export async function fetchSessionInfoService(thoughtspotHost: string): Promise<any> {
30
+ const sessionInfoPath = `${thoughtspotHost}${EndPoints.SESSION_INFO}`;
31
+ const response = await tokenizedFailureLoggedFetch(sessionInfoPath);
32
+ if (!response.ok) {
33
+ throw new Error(`Failed to fetch session info: ${response.statusText}`);
34
+ }
35
+ const data = await response.json();
36
+ return data;
27
37
  }
28
38
 
29
39
  /**
@@ -31,7 +41,7 @@ export function fetchSessionInfoService(authVerificationUrl: string): Promise<an
31
41
  * @param thoughtSpotHost
32
42
  */
33
43
  export async function fetchLogoutService(thoughtSpotHost: string): Promise<any> {
34
- return tokenisedFailureLoggedFetch(`${thoughtSpotHost}${EndPoints.LOGOUT}`, {
44
+ return tokenizedFailureLoggedFetch(`${thoughtSpotHost}${EndPoints.LOGOUT}`, {
35
45
  credentials: 'include',
36
46
  method: 'POST',
37
47
  headers: {
@@ -39,3 +49,23 @@ export async function fetchLogoutService(thoughtSpotHost: string): Promise<any>
39
49
  },
40
50
  });
41
51
  }
52
+
53
+ /**
54
+ * Is active service to check if the user is logged in.
55
+ *
56
+ * @param thoughtSpotHost
57
+ * @version SDK: 1.28.4 | ThoughtSpot: *
58
+ */
59
+ export async function isActiveService(thoughtSpotHost: string): Promise<boolean> {
60
+ const isActiveUrl = `${thoughtSpotHost}${EndPoints.IS_ACTIVE}`;
61
+ try {
62
+ const res = await tokenizedFetch(isActiveUrl, {
63
+ credentials: 'include',
64
+ });
65
+ return res.ok;
66
+ } catch (e) {
67
+ logger.warn(`Is Logged In Service failed : ${e.message}`);
68
+ }
69
+
70
+ return false;
71
+ }
@@ -4,9 +4,11 @@ import * as auth from '../auth';
4
4
  import * as base from '../embed/base';
5
5
  import * as embedConfigInstance from '../embed/embedConfig';
6
6
  import { EmbedEvent, AuthType } from '../types';
7
+ import * as sessionInfoService from './sessionInfoService';
7
8
 
8
9
  describe('Unit test for process data', () => {
9
10
  beforeAll(() => {
11
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
10
12
  base.init({
11
13
  thoughtSpotHost: 'https://tshost',
12
14
  authType: AuthType.None,
@@ -58,15 +60,14 @@ describe('Unit test for process data', () => {
58
60
  isPublicUser: false,
59
61
  };
60
62
  const e = { type: EmbedEvent.AuthInit, data: sessionInfo };
61
- jest.spyOn(auth, 'initSession').mockReturnValue(null);
62
63
  jest.spyOn(base, 'notifyAuthSuccess');
64
+ jest.spyOn(sessionInfoService, 'getSessionInfo').mockReturnValue(sessionInfo);
63
65
  expect(processDataInstance.processEventData(e.type, e, '', null)).toEqual({
64
66
  type: e.type,
65
67
  data: {
66
68
  userGUID: sessionInfo.userGUID,
67
69
  },
68
70
  });
69
- expect(auth.initSession).toBeCalledWith(sessionInfo);
70
71
  expect(base.notifyAuthSuccess).toBeCalled();
71
72
  });
72
73
 
@@ -5,7 +5,7 @@ import {
5
5
  notifyAuthSuccess,
6
6
  notifyLogout,
7
7
  } from '../embed/base';
8
- import { AuthFailureType, initSession } from '../auth';
8
+ import { AuthFailureType } from '../auth';
9
9
  import { AuthType, CustomActionPayload, EmbedEvent } from '../types';
10
10
  import { AnswerService } from './graphql/answerService/answerService';
11
11
  import { resetCachedAuthToken } from '../authToken';
@@ -30,12 +30,12 @@ export function processCustomAction(e: any, thoughtSpotHost: string) {
30
30
  }
31
31
 
32
32
  /**
33
+ * Responds to AuthInit sent from host signifying successful authentication in host.
33
34
  *
34
35
  * @param e
36
+ * @returns {any}
35
37
  */
36
38
  function processAuthInit(e: any) {
37
- // Store user session details sent by app.
38
- initSession(e.data);
39
39
  notifyAuthSuccess();
40
40
 
41
41
  // Expose only allowed details (eg: userGUID) back to SDK users.
@@ -0,0 +1,101 @@
1
+ import { getEmbedConfig } from '../embed/embedConfig';
2
+ import { fetchSessionInfoService } from './authService';
3
+
4
+ export type SessionInfo = {
5
+ releaseVersion: string;
6
+ userGUID: string;
7
+ currentOrgId: number;
8
+ privileges: string[];
9
+ mixpanelToken: string;
10
+ isPublicUser: boolean;
11
+ clusterId: string;
12
+ clusterName: string;
13
+ [key: string]: any;
14
+ };
15
+
16
+ let sessionInfo: null | SessionInfo = null;
17
+
18
+ /**
19
+ * Returns the session info object and caches it for future use.
20
+ * Once fetched the session info object is cached and returned from the cache on
21
+ * subsequent calls.
22
+ *
23
+ * @example ```js
24
+ * const sessionInfo = await getSessionInfo();
25
+ * console.log(sessionInfo);
26
+ * ```
27
+ * @version SDK: 1.28.3 | ThoughtSpot: *
28
+ * @returns {Promise<SessionInfo>} The session info object.
29
+ */
30
+ export async function getSessionInfo(): Promise<SessionInfo> {
31
+ if (!sessionInfo) {
32
+ const host = getEmbedConfig().thoughtSpotHost;
33
+ const sessionResponse = await fetchSessionInfoService(host);
34
+ const processedSessionInfo = getSessionDetails(sessionResponse);
35
+ sessionInfo = processedSessionInfo;
36
+ }
37
+ return sessionInfo;
38
+ }
39
+
40
+ /**
41
+ * Returns the cached session info object. If the client is not authenticated the
42
+ * function will return null.
43
+ *
44
+ * @example ```js
45
+ * const sessionInfo = getCachedSessionInfo();
46
+ * if (sessionInfo) {
47
+ * console.log(sessionInfo);
48
+ * } else {
49
+ * console.log('Not authenticated');
50
+ * }
51
+ * ```
52
+ * @returns {SessionInfo | null} The session info object.
53
+ * @version SDK: 1.28.3 | ThoughtSpot: *
54
+ */
55
+ export function getCachedSessionInfo(): SessionInfo | null {
56
+ return sessionInfo;
57
+ }
58
+
59
+ /**
60
+ * Processes the session info response and returns the session info object.
61
+ *
62
+ * @param sessionInfoResp {any} Response from the session info API.
63
+ * @returns {SessionInfo} The session info object.
64
+ * @example ```js
65
+ * const sessionInfoResp = await fetch(sessionInfoPath);
66
+ * const sessionInfo = getSessionDetails(sessionInfoResp);
67
+ * console.log(sessionInfo);
68
+ * ```
69
+ * @version SDK: 1.28.3 | ThoughtSpot: *
70
+ */
71
+ export const getSessionDetails = (sessionInfoResp: any): SessionInfo => {
72
+ const devMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.devSdkKey;
73
+ const prodMixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.prodSdkKey;
74
+ const mixpanelToken = sessionInfoResp.configInfo.mixpanelConfig.production
75
+ ? prodMixpanelToken
76
+ : devMixpanelToken;
77
+ return {
78
+ userGUID: sessionInfoResp.userGUID,
79
+ mixpanelToken,
80
+ isPublicUser: sessionInfoResp.configInfo.isPublicUser,
81
+ releaseVersion: sessionInfoResp.releaseVersion,
82
+ clusterId: sessionInfoResp.configInfo.selfClusterId,
83
+ clusterName: sessionInfoResp.configInfo.selfClusterName,
84
+ ...sessionInfoResp,
85
+ };
86
+ };
87
+
88
+ /**
89
+ * Resets the cached session info object and forces a new fetch on the next call.
90
+ *
91
+ * @example ```js
92
+ * resetCachedSessionInfo();
93
+ * const sessionInfo = await getSessionInfo();
94
+ * console.log(sessionInfo);
95
+ * ```
96
+ * @version SDK: 1.28.3 | ThoughtSpot ts7.april.cl, 7.2.1
97
+ * @returns {void}
98
+ */
99
+ export function resetCachedSessionInfo(): void {
100
+ sessionInfo = null;
101
+ }