@thoughtspot/visual-embed-sdk 1.29.0-alpha.2 → 1.29.0-alpha.authRefactor

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 (45) hide show
  1. package/cjs/package.json +1 -1
  2. package/cjs/src/embed/liveboard.js +1 -1
  3. package/cjs/src/embed/liveboard.js.map +1 -1
  4. package/cjs/src/utils/sessionInfoService.d.ts +66 -0
  5. package/cjs/src/utils/sessionInfoService.d.ts.map +1 -0
  6. package/cjs/src/utils/sessionInfoService.js +92 -0
  7. package/cjs/src/utils/sessionInfoService.js.map +1 -0
  8. package/dist/tsembed-react.es.js +2 -2
  9. package/dist/tsembed-react.js +2 -2
  10. package/dist/tsembed.es.js +2 -2
  11. package/dist/tsembed.js +2 -2
  12. package/lib/package.json +1 -1
  13. package/lib/src/embed/liveboard.js +1 -1
  14. package/lib/src/embed/liveboard.js.map +1 -1
  15. package/lib/src/utils/sessionInfoService.d.ts +66 -0
  16. package/lib/src/utils/sessionInfoService.d.ts.map +1 -0
  17. package/lib/src/utils/sessionInfoService.js +85 -0
  18. package/lib/src/utils/sessionInfoService.js.map +1 -0
  19. package/package.json +1 -2
  20. package/src/auth.spec.ts +66 -72
  21. package/src/auth.ts +43 -59
  22. package/src/authToken.ts +10 -4
  23. package/src/embed/app.spec.ts +4 -2
  24. package/src/embed/base.spec.ts +1 -0
  25. package/src/embed/base.ts +3 -0
  26. package/src/embed/embed.spec.ts +2 -0
  27. package/src/embed/events.spec.ts +2 -0
  28. package/src/embed/liveboard.spec.ts +2 -0
  29. package/src/embed/pinboard.spec.ts +2 -0
  30. package/src/embed/sage.spec.ts +3 -0
  31. package/src/embed/search.spec.ts +1 -0
  32. package/src/embed/ts-embed-trigger.spec.ts +3 -0
  33. package/src/embed/ts-embed.spec.ts +8 -0
  34. package/src/embed/ts-embed.ts +1 -0
  35. package/src/index.ts +2 -1
  36. package/src/mixpanel-service.spec.ts +4 -3
  37. package/src/mixpanel-service.ts +3 -1
  38. package/src/react/index.spec.tsx +7 -0
  39. package/src/react/index.tsx +1 -0
  40. package/src/utils/authService/authService.spec.ts +9 -4
  41. package/src/utils/authService/authService.ts +1 -0
  42. package/src/utils/authService/tokenizedAuthService.ts +38 -8
  43. package/src/utils/processData.spec.ts +3 -2
  44. package/src/utils/processData.ts +1 -3
  45. package/src/utils/sessionInfoService.ts +101 -0
@@ -19,6 +19,7 @@ import { version } from '../../package.json';
19
19
  import * as config from '../config';
20
20
  import { TsEmbed, V1Embed } from './ts-embed';
21
21
  import { logger } from '../utils/logger';
22
+ import * as auth from '../auth';
22
23
 
23
24
  const defaultViewConfig = {
24
25
  frameParams: {
@@ -35,6 +36,7 @@ beforeAll(() => {
35
36
  thoughtSpotHost,
36
37
  authType: AuthType.None,
37
38
  });
39
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
38
40
  (window as any).ResizeObserver = window.ResizeObserver
39
41
  || jest.fn().mockImplementation(() => ({
40
42
  disconnect: jest.fn(),
@@ -67,13 +69,13 @@ describe('App embed tests', () => {
67
69
  test('should hide the primary nav bar', async () => {
68
70
  const appEmbed = new AppEmbed(getRootEl(), {
69
71
  ...defaultViewConfig,
70
- showPrimaryNavbar: true,
72
+ showPrimaryNavbar: false,
71
73
  } as AppViewConfig);
72
74
  appEmbed.render();
73
75
  await executeAfterWait(() => {
74
76
  expectUrlMatchesWithParams(
75
77
  getIFrameSrc(),
76
- `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=false&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
78
+ `http://${thoughtSpotHost}/?embedApp=true&primaryNavHidden=true&profileAndHelpInNavBarHidden=false${defaultParams}${defaultParamsPost}#/home`,
77
79
  );
78
80
  });
79
81
  });
@@ -28,6 +28,7 @@ describe('Base TS Embed', () => {
28
28
  thoughtSpotHost,
29
29
  authType: index.AuthType.None,
30
30
  }) as EventEmitter;
31
+ jest.spyOn(auth, 'postLoginService').mockImplementation(() => Promise.resolve({}));
31
32
  });
32
33
 
33
34
  beforeEach(() => {
package/src/embed/base.ts CHANGED
@@ -30,6 +30,7 @@ import {
30
30
  notifyLogout,
31
31
  setAuthEE,
32
32
  AuthEventEmitter,
33
+ postLoginService,
33
34
  } from '../auth';
34
35
  import { uploadMixpanelEvent, MIXPANEL_EVENT } from '../mixpanel-service';
35
36
  import { getEmbedConfig, setEmbedConfig } from './embedConfig';
@@ -75,6 +76,8 @@ export const handleAuth = (): Promise<boolean> => {
75
76
  if (!isLoggedIn) {
76
77
  notifyAuthFailure(AuthFailureType.SDK);
77
78
  } else {
79
+ // Post login service is called after successful login.
80
+ postLoginService();
78
81
  notifyAuthSDKSuccess();
79
82
  }
80
83
  },
@@ -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,
@@ -27,6 +29,7 @@ beforeAll(() => {
27
29
  authType: AuthType.None,
28
30
  });
29
31
  spyOn(window, 'alert');
32
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
30
33
  });
31
34
 
32
35
  describe('Sage embed tests', () => {
@@ -32,6 +32,7 @@ beforeAll(() => {
32
32
  thoughtSpotHost,
33
33
  authType: AuthType.None,
34
34
  });
35
+ jest.spyOn(authInstance, 'postLoginService').mockImplementation(() => Promise.resolve({}));
35
36
  spyOn(window, 'alert');
36
37
  });
37
38
 
@@ -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({
@@ -83,6 +83,10 @@ describe('Unit test case for ts embed', () => {
83
83
  resetCachedAuthToken();
84
84
  });
85
85
 
86
+ beforeAll(() => {
87
+ jest.spyOn(authInstance, 'postLoginService').mockResolvedValue(true);
88
+ });
89
+
86
90
  describe('AuthExpire embedEvent in cookieless authentication authType', () => {
87
91
  beforeAll(() => {
88
92
  jest.spyOn(authInstance, 'doCookielessTokenAuth').mockResolvedValueOnce(true);
@@ -680,6 +684,7 @@ describe('Unit test case for ts embed', () => {
680
684
  const mockPort: any = {
681
685
  postMessage: jest.fn(),
682
686
  };
687
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
683
688
  await executeAfterWait(() => {
684
689
  const iframe = getIFrameEl();
685
690
  postMessageToParent(iframe.contentWindow, mockEmbedEventPayload, mockPort);
@@ -689,6 +694,7 @@ describe('Unit test case for ts embed', () => {
689
694
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
690
695
  authInstance.AuthFailureType.EXPIRY,
691
696
  );
697
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
692
698
  });
693
699
 
694
700
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -707,6 +713,7 @@ describe('Unit test case for ts embed', () => {
707
713
  const searchEmbed = new SearchEmbed(getRootEl(), { ...defaultViewConfig, preRenderId: 'test' });
708
714
  jest.spyOn(baseInstance, 'notifyAuthFailure');
709
715
  searchEmbed.preRender();
716
+ const loggerSpy = jest.spyOn(logger, 'error').mockResolvedValueOnce(true);
710
717
  const mockPort: any = {
711
718
  postMessage: jest.fn(),
712
719
  };
@@ -720,6 +727,7 @@ describe('Unit test case for ts embed', () => {
720
727
  expect(baseInstance.notifyAuthFailure).toBeCalledWith(
721
728
  authInstance.AuthFailureType.EXPIRY,
722
729
  );
730
+ expect(loggerSpy).toHaveBeenCalledTimes(1);
723
731
  });
724
732
 
725
733
  jest.spyOn(authService, 'verifyTokenService').mockClear();
@@ -349,6 +349,7 @@ export class TsEmbed {
349
349
  data: { authToken },
350
350
  });
351
351
  } catch (e) {
352
+ logger.error(`Received invalid token. Error : ${e?.message}`);
352
353
  processAuthFailure(e, this.isPreRendered ? this.preRenderWrapper : this.el);
353
354
  }
354
355
  } else if (autoLogin) {
package/src/index.ts CHANGED
@@ -21,8 +21,9 @@ import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/live
21
21
  import { SearchEmbed, SearchViewConfig } from './embed/search';
22
22
  import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
23
23
  import {
24
- AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter, getSessionInfo,
24
+ AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
25
25
  } from './auth';
26
+ import { getSessionInfo } from './utils/sessionInfoService';
26
27
  import {
27
28
  AuthType,
28
29
  RuntimeFilter,
@@ -6,6 +6,7 @@ import {
6
6
  testResetMixpanel,
7
7
  } from './mixpanel-service';
8
8
  import { AuthType } from './types';
9
+ import { SessionInfo } from './utils/sessionInfoService';
9
10
 
10
11
  const config = {
11
12
  thoughtSpotHost: 'https://10.87.89.232',
@@ -29,7 +30,7 @@ describe('Unit test for mixpanel', () => {
29
30
  mixpanelToken: 'abc123',
30
31
  userGUID: '12345',
31
32
  isPublicUser: false,
32
- };
33
+ } as SessionInfo;
33
34
  initMixpanel(sessionInfo);
34
35
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
35
36
  expect(mixpanel.identify).toHaveBeenCalledWith(sessionInfo.userGUID);
@@ -49,7 +50,7 @@ describe('Unit test for mixpanel', () => {
49
50
  clusterId: 'newClusterId',
50
51
  clusterName: 'newClusterName',
51
52
  releaseVersion: 'newReleaseVersion',
52
- };
53
+ } as SessionInfo;
53
54
  initMixpanel(sessionInfo);
54
55
 
55
56
  expect(mixpanel.init).toHaveBeenCalledWith(sessionInfo.mixpanelToken, undefined, 'tsEmbed');
@@ -74,7 +75,7 @@ describe('Unit test for mixpanel', () => {
74
75
  mixpanelToken: 'abc123',
75
76
  userGUID: '12345',
76
77
  isPublicUser: false,
77
- };
78
+ } as SessionInfo;
78
79
  initMixpanel(sessionInfo);
79
80
  expect(mixpanel.track).toHaveBeenCalledTimes(2);
80
81
  });
@@ -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',
@@ -55,8 +56,9 @@ function emptyQueue() {
55
56
  *
56
57
  * @param sessionInfo
57
58
  */
58
- export function initMixpanel(sessionInfo: any): void {
59
+ export function initMixpanel(sessionInfo: SessionInfo): void {
59
60
  if (!sessionInfo || !sessionInfo.mixpanelToken) {
61
+ logger.error('Mixpanel token not found in session info');
60
62
  return;
61
63
  }
62
64
  // 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, 'getSessionInfoSync').mockReturnValue({
39
+ userGUID: 'abcd',
40
+ });
34
41
  spyOn(window, 'alert');
35
42
  });
36
43
 
@@ -381,4 +381,5 @@ export {
381
381
  HomeLeftNavItem,
382
382
  HomepageModule,
383
383
  LogLevel,
384
+ getSessionInfo,
384
385
  } from '../index';
@@ -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,8 +109,12 @@ 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
120
  test('verifyTokenService', async () => {
@@ -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',
@@ -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, 'getSessionInfoSync').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';
@@ -34,8 +34,6 @@ export function processCustomAction(e: any, thoughtSpotHost: string) {
34
34
  * @param e
35
35
  */
36
36
  function processAuthInit(e: any) {
37
- // Store user session details sent by app.
38
- initSession(e.data);
39
37
  notifyAuthSuccess();
40
38
 
41
39
  // 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 = getSessionInfoSync();
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 getSessionInfoSync(): 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
+ }