@thoughtspot/visual-embed-sdk 1.42.1-alpha.7 → 1.42.3

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 (229) hide show
  1. package/cjs/package.json +4 -3
  2. package/cjs/src/css-variables.d.ts +0 -48
  3. package/cjs/src/css-variables.d.ts.map +1 -1
  4. package/cjs/src/embed/app.d.ts +20 -0
  5. package/cjs/src/embed/app.d.ts.map +1 -1
  6. package/cjs/src/embed/app.js +9 -4
  7. package/cjs/src/embed/app.js.map +1 -1
  8. package/cjs/src/embed/app.spec.js +62 -0
  9. package/cjs/src/embed/app.spec.js.map +1 -1
  10. package/cjs/src/embed/base.d.ts.map +1 -1
  11. package/cjs/src/embed/base.js +2 -0
  12. package/cjs/src/embed/base.js.map +1 -1
  13. package/cjs/src/embed/bodyless-conversation.d.ts +1 -1
  14. package/cjs/src/embed/conversation.d.ts +16 -0
  15. package/cjs/src/embed/conversation.d.ts.map +1 -1
  16. package/cjs/src/embed/conversation.js +5 -2
  17. package/cjs/src/embed/conversation.js.map +1 -1
  18. package/cjs/src/embed/conversation.spec.js +25 -1
  19. package/cjs/src/embed/conversation.spec.js.map +1 -1
  20. package/cjs/src/embed/hostEventClient/contracts.d.ts +1 -11
  21. package/cjs/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  22. package/cjs/src/embed/hostEventClient/contracts.js +0 -1
  23. package/cjs/src/embed/hostEventClient/contracts.js.map +1 -1
  24. package/cjs/src/embed/liveboard.d.ts.map +1 -1
  25. package/cjs/src/embed/liveboard.js +5 -1
  26. package/cjs/src/embed/liveboard.js.map +1 -1
  27. package/cjs/src/embed/liveboard.spec.js +46 -0
  28. package/cjs/src/embed/liveboard.spec.js.map +1 -1
  29. package/cjs/src/embed/sage.d.ts +4 -4
  30. package/cjs/src/embed/search.d.ts.map +1 -1
  31. package/cjs/src/embed/search.js +1 -3
  32. package/cjs/src/embed/search.js.map +1 -1
  33. package/cjs/src/embed/ts-embed.d.ts +0 -2
  34. package/cjs/src/embed/ts-embed.d.ts.map +1 -1
  35. package/cjs/src/embed/ts-embed.js +31 -44
  36. package/cjs/src/embed/ts-embed.js.map +1 -1
  37. package/cjs/src/embed/ts-embed.spec.js +134 -43
  38. package/cjs/src/embed/ts-embed.spec.js.map +1 -1
  39. package/cjs/src/errors.js +1 -1
  40. package/cjs/src/errors.js.map +1 -1
  41. package/cjs/src/index.d.ts +3 -3
  42. package/cjs/src/index.d.ts.map +1 -1
  43. package/cjs/src/index.js +1 -2
  44. package/cjs/src/index.js.map +1 -1
  45. package/cjs/src/react/all-types-export.d.ts +1 -2
  46. package/cjs/src/react/all-types-export.d.ts.map +1 -1
  47. package/cjs/src/react/all-types-export.js +5 -3
  48. package/cjs/src/react/all-types-export.js.map +1 -1
  49. package/cjs/src/react/all-types-export.spec.js +0 -8
  50. package/cjs/src/react/all-types-export.spec.js.map +1 -1
  51. package/cjs/src/react/index.d.ts +1 -2
  52. package/cjs/src/react/index.d.ts.map +1 -1
  53. package/cjs/src/react/index.js +2 -1
  54. package/cjs/src/react/index.js.map +1 -1
  55. package/cjs/src/react/util.d.ts +1 -0
  56. package/cjs/src/react/util.d.ts.map +1 -1
  57. package/cjs/src/types.d.ts +80 -94
  58. package/cjs/src/types.d.ts.map +1 -1
  59. package/cjs/src/types.js +30 -46
  60. package/cjs/src/types.js.map +1 -1
  61. package/cjs/src/utils/custom-actions.d.ts.map +1 -1
  62. package/cjs/src/utils/custom-actions.js +9 -0
  63. package/cjs/src/utils/custom-actions.js.map +1 -1
  64. package/cjs/src/utils/custom-actions.spec.js +20 -0
  65. package/cjs/src/utils/custom-actions.spec.js.map +1 -1
  66. package/cjs/src/utils/processData.d.ts +1 -1
  67. package/cjs/src/utils/processData.d.ts.map +1 -1
  68. package/cjs/src/utils/processData.js +8 -8
  69. package/cjs/src/utils/processData.js.map +1 -1
  70. package/cjs/src/utils/processData.spec.js.map +1 -1
  71. package/dist/{index-DvNA626T.js → index-SVcLgSqi.js} +1 -1
  72. package/dist/src/css-variables.d.ts +0 -48
  73. package/dist/src/css-variables.d.ts.map +1 -1
  74. package/dist/src/embed/app.d.ts +20 -0
  75. package/dist/src/embed/app.d.ts.map +1 -1
  76. package/dist/src/embed/base.d.ts.map +1 -1
  77. package/dist/src/embed/bodyless-conversation.d.ts +1 -1
  78. package/dist/src/embed/conversation.d.ts +16 -0
  79. package/dist/src/embed/conversation.d.ts.map +1 -1
  80. package/dist/src/embed/hostEventClient/contracts.d.ts +1 -11
  81. package/dist/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  82. package/dist/src/embed/liveboard.d.ts.map +1 -1
  83. package/dist/src/embed/sage.d.ts +4 -4
  84. package/dist/src/embed/search.d.ts.map +1 -1
  85. package/dist/src/embed/ts-embed.d.ts +0 -2
  86. package/dist/src/embed/ts-embed.d.ts.map +1 -1
  87. package/dist/src/index.d.ts +3 -3
  88. package/dist/src/index.d.ts.map +1 -1
  89. package/dist/src/react/all-types-export.d.ts +1 -2
  90. package/dist/src/react/all-types-export.d.ts.map +1 -1
  91. package/dist/src/react/index.d.ts +1 -2
  92. package/dist/src/react/index.d.ts.map +1 -1
  93. package/dist/src/react/util.d.ts +1 -0
  94. package/dist/src/react/util.d.ts.map +1 -1
  95. package/dist/src/types.d.ts +80 -94
  96. package/dist/src/types.d.ts.map +1 -1
  97. package/dist/src/utils/custom-actions.d.ts.map +1 -1
  98. package/dist/src/utils/processData.d.ts +1 -1
  99. package/dist/src/utils/processData.d.ts.map +1 -1
  100. package/dist/tsembed-react.es.js +114 -224
  101. package/dist/tsembed-react.js +258 -444
  102. package/dist/tsembed.es.js +113 -224
  103. package/dist/tsembed.js +256 -443
  104. package/dist/visual-embed-sdk-react-full.d.ts +126 -161
  105. package/dist/visual-embed-sdk-react.d.ts +117 -156
  106. package/dist/visual-embed-sdk.d.ts +117 -159
  107. package/lib/package.json +4 -3
  108. package/lib/src/css-variables.d.ts +0 -48
  109. package/lib/src/css-variables.d.ts.map +1 -1
  110. package/lib/src/embed/app.d.ts +20 -0
  111. package/lib/src/embed/app.d.ts.map +1 -1
  112. package/lib/src/embed/app.js +9 -4
  113. package/lib/src/embed/app.js.map +1 -1
  114. package/lib/src/embed/app.spec.js +62 -0
  115. package/lib/src/embed/app.spec.js.map +1 -1
  116. package/lib/src/embed/base.d.ts.map +1 -1
  117. package/lib/src/embed/base.js +2 -0
  118. package/lib/src/embed/base.js.map +1 -1
  119. package/lib/src/embed/bodyless-conversation.d.ts +1 -1
  120. package/lib/src/embed/conversation.d.ts +16 -0
  121. package/lib/src/embed/conversation.d.ts.map +1 -1
  122. package/lib/src/embed/conversation.js +5 -2
  123. package/lib/src/embed/conversation.js.map +1 -1
  124. package/lib/src/embed/conversation.spec.js +25 -1
  125. package/lib/src/embed/conversation.spec.js.map +1 -1
  126. package/lib/src/embed/hostEventClient/contracts.d.ts +1 -11
  127. package/lib/src/embed/hostEventClient/contracts.d.ts.map +1 -1
  128. package/lib/src/embed/hostEventClient/contracts.js +0 -1
  129. package/lib/src/embed/hostEventClient/contracts.js.map +1 -1
  130. package/lib/src/embed/liveboard.d.ts.map +1 -1
  131. package/lib/src/embed/liveboard.js +5 -1
  132. package/lib/src/embed/liveboard.js.map +1 -1
  133. package/lib/src/embed/liveboard.spec.js +47 -1
  134. package/lib/src/embed/liveboard.spec.js.map +1 -1
  135. package/lib/src/embed/sage.d.ts +4 -4
  136. package/lib/src/embed/search.d.ts.map +1 -1
  137. package/lib/src/embed/search.js +1 -3
  138. package/lib/src/embed/search.js.map +1 -1
  139. package/lib/src/embed/ts-embed.d.ts +0 -2
  140. package/lib/src/embed/ts-embed.d.ts.map +1 -1
  141. package/lib/src/embed/ts-embed.js +31 -44
  142. package/lib/src/embed/ts-embed.js.map +1 -1
  143. package/lib/src/embed/ts-embed.spec.js +134 -43
  144. package/lib/src/embed/ts-embed.spec.js.map +1 -1
  145. package/lib/src/errors.js +1 -1
  146. package/lib/src/errors.js.map +1 -1
  147. package/lib/src/index.d.ts +3 -3
  148. package/lib/src/index.d.ts.map +1 -1
  149. package/lib/src/index.js +2 -2
  150. package/lib/src/index.js.map +1 -1
  151. package/lib/src/react/all-types-export.d.ts +1 -2
  152. package/lib/src/react/all-types-export.d.ts.map +1 -1
  153. package/lib/src/react/all-types-export.js +2 -2
  154. package/lib/src/react/all-types-export.js.map +1 -1
  155. package/lib/src/react/all-types-export.spec.js +0 -8
  156. package/lib/src/react/all-types-export.spec.js.map +1 -1
  157. package/lib/src/react/index.d.ts +1 -2
  158. package/lib/src/react/index.d.ts.map +1 -1
  159. package/lib/src/react/index.js +4 -3
  160. package/lib/src/react/index.js.map +1 -1
  161. package/lib/src/react/util.d.ts +1 -0
  162. package/lib/src/react/util.d.ts.map +1 -1
  163. package/lib/src/types.d.ts +80 -94
  164. package/lib/src/types.d.ts.map +1 -1
  165. package/lib/src/types.js +29 -45
  166. package/lib/src/types.js.map +1 -1
  167. package/lib/src/utils/custom-actions.d.ts.map +1 -1
  168. package/lib/src/utils/custom-actions.js +9 -0
  169. package/lib/src/utils/custom-actions.js.map +1 -1
  170. package/lib/src/utils/custom-actions.spec.js +20 -0
  171. package/lib/src/utils/custom-actions.spec.js.map +1 -1
  172. package/lib/src/utils/processData.d.ts +1 -1
  173. package/lib/src/utils/processData.d.ts.map +1 -1
  174. package/lib/src/utils/processData.js +8 -8
  175. package/lib/src/utils/processData.js.map +1 -1
  176. package/lib/src/utils/processData.spec.js.map +1 -1
  177. package/package.json +4 -3
  178. package/src/css-variables.ts +0 -58
  179. package/src/embed/app.spec.ts +87 -0
  180. package/src/embed/app.ts +35 -4
  181. package/src/embed/base.ts +2 -0
  182. package/src/embed/bodyless-conversation.ts +1 -1
  183. package/src/embed/conversation.spec.ts +35 -1
  184. package/src/embed/conversation.ts +22 -0
  185. package/src/embed/hostEventClient/contracts.ts +0 -10
  186. package/src/embed/liveboard.spec.ts +60 -0
  187. package/src/embed/liveboard.ts +9 -0
  188. package/src/embed/sage.ts +4 -4
  189. package/src/embed/search.ts +1 -3
  190. package/src/embed/ts-embed.spec.ts +175 -53
  191. package/src/embed/ts-embed.ts +45 -68
  192. package/src/errors.ts +1 -1
  193. package/src/index.ts +3 -4
  194. package/src/react/all-types-export.spec.ts +1 -9
  195. package/src/react/all-types-export.ts +8 -10
  196. package/src/react/index.tsx +130 -155
  197. package/src/types.ts +78 -94
  198. package/src/utils/custom-actions.spec.ts +22 -0
  199. package/src/utils/custom-actions.ts +11 -0
  200. package/src/utils/processData.spec.ts +1 -0
  201. package/src/utils/processData.ts +11 -11
  202. package/cjs/src/api-intercept.d.ts +0 -31
  203. package/cjs/src/api-intercept.d.ts.map +0 -1
  204. package/cjs/src/api-intercept.js +0 -119
  205. package/cjs/src/api-intercept.js.map +0 -1
  206. package/cjs/src/api-intercept.spec.d.ts +0 -2
  207. package/cjs/src/api-intercept.spec.d.ts.map +0 -1
  208. package/cjs/src/api-intercept.spec.js +0 -122
  209. package/cjs/src/api-intercept.spec.js.map +0 -1
  210. package/dist/index-BCC3Z072.js +0 -7371
  211. package/dist/index-BEzW4MDA.js +0 -7371
  212. package/dist/index-BaESA9rq.js +0 -7371
  213. package/dist/index-CFNZIcKr.js +0 -7447
  214. package/dist/index-CqKTa1Fe.js +0 -7447
  215. package/dist/index-DFnPKcjZ.js +0 -7447
  216. package/dist/index-DhFH7b7U.js +0 -7447
  217. package/dist/src/api-intercept.d.ts +0 -31
  218. package/dist/src/api-intercept.d.ts.map +0 -1
  219. package/dist/src/api-intercept.spec.d.ts +0 -2
  220. package/dist/src/api-intercept.spec.d.ts.map +0 -1
  221. package/lib/src/api-intercept.d.ts +0 -31
  222. package/lib/src/api-intercept.d.ts.map +0 -1
  223. package/lib/src/api-intercept.js +0 -112
  224. package/lib/src/api-intercept.js.map +0 -1
  225. package/lib/src/api-intercept.spec.d.ts +0 -2
  226. package/lib/src/api-intercept.spec.d.ts.map +0 -1
  227. package/lib/src/api-intercept.spec.js +0 -119
  228. package/lib/src/api-intercept.spec.js.map +0 -1
  229. package/src/api-intercept.ts +0 -139
@@ -90,7 +90,6 @@ beforeAll(() => {
90
90
  const customisations = {
91
91
  style: {
92
92
  customCSS: {},
93
- customCSSUrl: undefined as string | undefined,
94
93
  },
95
94
  content: {},
96
95
  };
@@ -98,7 +97,6 @@ const customisations = {
98
97
  const customisationsView = {
99
98
  style: {
100
99
  customCSS: {},
101
- customCSSUrl: undefined as string | undefined,
102
100
  },
103
101
  content: {
104
102
  strings: {
@@ -1047,7 +1045,7 @@ describe('Unit test case for ts embed', () => {
1047
1045
  type: EmbedEvent.APP_INIT,
1048
1046
  data: {},
1049
1047
  };
1050
-
1048
+
1051
1049
  // Create a SearchEmbed with valid custom actions to test
1052
1050
  // CustomActionsValidationResult
1053
1051
  const searchEmbed = new SearchEmbed(getRootEl(), {
@@ -1069,7 +1067,7 @@ describe('Unit test case for ts embed', () => {
1069
1067
  }
1070
1068
  ]
1071
1069
  });
1072
-
1070
+
1073
1071
  searchEmbed.render();
1074
1072
  const mockPort: any = {
1075
1073
  postMessage: jest.fn(),
@@ -1118,7 +1116,7 @@ describe('Unit test case for ts embed', () => {
1118
1116
  customVariablesForThirdPartyTools: {},
1119
1117
  },
1120
1118
  });
1121
-
1119
+
1122
1120
  // Verify that CustomActionsValidationResult structure is
1123
1121
  // correct
1124
1122
  const appInitData = mockPort.postMessage.mock.calls[0][0].data;
@@ -1139,7 +1137,7 @@ describe('Unit test case for ts embed', () => {
1139
1137
  })
1140
1138
  ])
1141
1139
  );
1142
-
1140
+
1143
1141
  // Verify actions are sorted by name (alphabetically)
1144
1142
  expect(appInitData.customActions[0].name).toBe('Another Valid Action');
1145
1143
  expect(appInitData.customActions[1].name).toBe('Valid Action');
@@ -2430,50 +2428,6 @@ describe('Unit test case for ts embed', () => {
2430
2428
  });
2431
2429
  });
2432
2430
 
2433
- describe('When destroyed', () => {
2434
- it('should remove the iframe', async () => {
2435
- const appEmbed = new AppEmbed(getRootEl(), {
2436
- frameParams: {
2437
- width: '100%',
2438
- height: '100%',
2439
- },
2440
- });
2441
- await appEmbed.render();
2442
- expect(getIFrameEl()).toBeTruthy();
2443
- appEmbed.destroy();
2444
- expect(getIFrameEl()).toBeFalsy();
2445
- });
2446
-
2447
- it('should remove the iframe when insertAsSibling is true', async () => {
2448
- const appEmbed = new AppEmbed(getRootEl(), {
2449
- frameParams: {
2450
- width: '100%',
2451
- height: '100%',
2452
- },
2453
- insertAsSibling: true,
2454
- });
2455
- await appEmbed.render();
2456
- expect(getIFrameEl()).toBeTruthy();
2457
- appEmbed.destroy();
2458
- expect(getIFrameEl()).toBeFalsy();
2459
- });
2460
-
2461
- it("Should remove the error message on destroy if it's present", async () => {
2462
- jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(false);
2463
- const appEmbed = new AppEmbed(getRootEl(), {
2464
- frameParams: {
2465
- width: '100%',
2466
- height: '100%',
2467
- },
2468
- insertAsSibling: true,
2469
- });
2470
- await appEmbed.render();
2471
- expect(getRootEl().nextElementSibling.innerHTML).toContain('Not logged in');
2472
- appEmbed.destroy();
2473
- expect(getRootEl().nextElementSibling.innerHTML).toBe('');
2474
- });
2475
- });
2476
-
2477
2431
  describe('validate getThoughtSpotPostUrlParams', () => {
2478
2432
  const { location } = window;
2479
2433
 
@@ -2490,7 +2444,7 @@ describe('Unit test case for ts embed', () => {
2490
2444
  });
2491
2445
 
2492
2446
  afterAll((): void => {
2493
- (window.location as any) = location;
2447
+ window.location = location as any;
2494
2448
  });
2495
2449
 
2496
2450
  it('get url params for TS', () => {
@@ -3408,7 +3362,7 @@ describe('Unit test case for ts embed', () => {
3408
3362
  new Error('Auth failed'),
3409
3363
  );
3410
3364
  const searchEmbed = new SearchEmbed(getRootEl(), defaultViewConfig);
3411
- const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => { });
3365
+ const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
3412
3366
  await searchEmbed.render();
3413
3367
  await executeAfterWait(() => {
3414
3368
  expect(getRootEl().innerHTML).toContain('Not logged in');
@@ -3417,7 +3371,7 @@ describe('Unit test case for ts embed', () => {
3417
3371
  window.dispatchEvent(onlineEvent);
3418
3372
  }).not.toThrow();
3419
3373
  });
3420
-
3374
+
3421
3375
  errorSpy.mockReset();
3422
3376
  });
3423
3377
 
@@ -3458,4 +3412,172 @@ describe('Unit test case for ts embed', () => {
3458
3412
  triggerSpy.mockReset();
3459
3413
  });
3460
3414
  });
3415
+
3416
+ describe('When destroyed', () => {
3417
+ it('should remove the iframe', async () => {
3418
+ const appEmbed = new AppEmbed(getRootEl(), {
3419
+ frameParams: {
3420
+ width: '100%',
3421
+ height: '100%',
3422
+ },
3423
+ });
3424
+ await appEmbed.render();
3425
+ expect(getIFrameEl()).toBeTruthy();
3426
+ appEmbed.destroy();
3427
+ expect(getIFrameEl()).toBeFalsy();
3428
+ });
3429
+
3430
+ it('should remove the iframe when insertAsSibling is true', async () => {
3431
+ const appEmbed = new AppEmbed(getRootEl(), {
3432
+ frameParams: {
3433
+ width: '100%',
3434
+ height: '100%',
3435
+ },
3436
+ insertAsSibling: true,
3437
+ });
3438
+ await appEmbed.render();
3439
+ expect(getIFrameEl()).toBeTruthy();
3440
+ appEmbed.destroy();
3441
+ expect(getIFrameEl()).toBeFalsy();
3442
+ });
3443
+
3444
+ it("Should remove the error message on destroy if it's present", async () => {
3445
+ jest.spyOn(baseInstance, 'getAuthPromise').mockResolvedValueOnce(false);
3446
+ const appEmbed = new AppEmbed(getRootEl(), {
3447
+ frameParams: {
3448
+ width: '100%',
3449
+ height: '100%',
3450
+ },
3451
+ insertAsSibling: true,
3452
+ });
3453
+ await appEmbed.render();
3454
+ expect(getRootEl().nextElementSibling.innerHTML).toContain('Not logged in');
3455
+ appEmbed.destroy();
3456
+ expect(getRootEl().nextElementSibling.innerHTML).toBe('');
3457
+ });
3458
+
3459
+ describe('with waitForCleanupOnDestroy configuration', () => {
3460
+ let originalEmbedConfig: any;
3461
+
3462
+ beforeEach(() => {
3463
+ originalEmbedConfig = embedConfig.getEmbedConfig();
3464
+ });
3465
+
3466
+ afterEach(() => {
3467
+ embedConfig.setEmbedConfig(originalEmbedConfig);
3468
+ });
3469
+
3470
+ it('should trigger DestroyEmbed event immediately when waitForCleanupOnDestroy is false', async () => {
3471
+ embedConfig.setEmbedConfig({
3472
+ ...originalEmbedConfig,
3473
+ waitForCleanupOnDestroy: false,
3474
+ });
3475
+
3476
+ const appEmbed = new AppEmbed(getRootEl(), {
3477
+ frameParams: {
3478
+ width: '100%',
3479
+ height: '100%',
3480
+ },
3481
+ });
3482
+ await appEmbed.render();
3483
+
3484
+ const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockResolvedValue(null);
3485
+ const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3486
+
3487
+ appEmbed.destroy();
3488
+
3489
+ expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3490
+ expect(removeChildSpy).toHaveBeenCalled();
3491
+ });
3492
+
3493
+ it('should trigger DestroyEmbed event and wait for cleanup when waitForCleanupOnDestroy is true', async () => {
3494
+ embedConfig.setEmbedConfig({
3495
+ ...originalEmbedConfig,
3496
+ waitForCleanupOnDestroy: true,
3497
+ cleanupTimeout: 1000,
3498
+ });
3499
+
3500
+ const appEmbed = new AppEmbed(getRootEl(), {
3501
+ frameParams: {
3502
+ width: '100%',
3503
+ height: '100%',
3504
+ },
3505
+ });
3506
+ await appEmbed.render();
3507
+
3508
+ const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockResolvedValue(null);
3509
+ const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3510
+
3511
+ appEmbed.destroy();
3512
+
3513
+ // Should be called immediately when waitForCleanupOnDestroy is true
3514
+ expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3515
+
3516
+ // Wait for the timeout to complete
3517
+ await new Promise(resolve => setTimeout(resolve, 1100));
3518
+
3519
+ expect(removeChildSpy).toHaveBeenCalled();
3520
+ });
3521
+
3522
+ it('should handle Promise.race with successful cleanup completion', async () => {
3523
+ embedConfig.setEmbedConfig({
3524
+ ...originalEmbedConfig,
3525
+ waitForCleanupOnDestroy: true,
3526
+ cleanupTimeout: 2000,
3527
+ });
3528
+
3529
+ const appEmbed = new AppEmbed(getRootEl(), {
3530
+ frameParams: {
3531
+ width: '100%',
3532
+ height: '100%',
3533
+ },
3534
+ });
3535
+ await appEmbed.render();
3536
+
3537
+ // Mock trigger to resolve quickly (before timeout)
3538
+ const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockImplementation(() =>
3539
+ new Promise(resolve => setTimeout(() => resolve(null), 100))
3540
+ );
3541
+ const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3542
+
3543
+ appEmbed.destroy();
3544
+
3545
+ // Wait for the trigger to complete
3546
+ await new Promise(resolve => setTimeout(resolve, 200));
3547
+
3548
+ expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3549
+ expect(removeChildSpy).toHaveBeenCalled();
3550
+ });
3551
+
3552
+ it('should handle Promise.race with timeout when cleanup takes too long', async () => {
3553
+ embedConfig.setEmbedConfig({
3554
+ ...originalEmbedConfig,
3555
+ waitForCleanupOnDestroy: true,
3556
+ cleanupTimeout: 100,
3557
+ });
3558
+
3559
+ const appEmbed = new AppEmbed(getRootEl(), {
3560
+ frameParams: {
3561
+ width: '100%',
3562
+ height: '100%',
3563
+ },
3564
+ });
3565
+ await appEmbed.render();
3566
+
3567
+ // Mock trigger to take longer than timeout
3568
+ const triggerSpy = jest.spyOn(appEmbed, 'trigger').mockImplementation(() =>
3569
+ new Promise(resolve => setTimeout(() => resolve(null), 500))
3570
+ );
3571
+ const removeChildSpy = jest.spyOn(Node.prototype, 'removeChild').mockImplementation(() => getRootEl());
3572
+
3573
+ appEmbed.destroy();
3574
+
3575
+ // Wait for the timeout to complete
3576
+ await new Promise(resolve => setTimeout(resolve, 200));
3577
+
3578
+ expect(triggerSpy).toHaveBeenCalledWith(HostEvent.DestroyEmbed);
3579
+ expect(removeChildSpy).toHaveBeenCalled();
3580
+ });
3581
+ });
3582
+ });
3461
3583
  });
@@ -71,7 +71,6 @@ import { getEmbedConfig } from './embedConfig';
71
71
  import { ERROR_MESSAGE } from '../errors';
72
72
  import { getPreauthInfo } from '../utils/sessionInfoService';
73
73
  import { HostEventClient } from './hostEventClient/host-event-client';
74
- import { getInterceptInitData, handleInterceptEvent, processLegacyInterceptResponse } from '../api-intercept';
75
74
 
76
75
  const { version } = pkgInfo;
77
76
 
@@ -202,7 +201,7 @@ export class TsEmbed {
202
201
  });
203
202
  const embedConfig = getEmbedConfig();
204
203
  this.embedConfig = embedConfig;
205
-
204
+
206
205
  this.hostEventClient = new HostEventClient(this.iFrame);
207
206
  this.isReadyForRenderPromise = getInitPromise().then(async () => {
208
207
  if (!embedConfig.authTriggerContainer && !embedConfig.useEventForSAMLPopup) {
@@ -337,50 +336,33 @@ export class TsEmbed {
337
336
  this.subscribedListeners.offline = offlineEventListener;
338
337
  }
339
338
 
340
- private messageEventListener = async (event: MessageEvent<any>) => {
341
- const eventType = this.getEventType(event);
342
- const eventPort = this.getEventPort(event);
343
- const eventData = this.formatEventData(event, eventType);
344
- if (event.source === this.iFrame.contentWindow) {
345
- const processedEventData = await processEventData(
346
- eventType,
347
- eventData,
348
- this.thoughtSpotHost,
349
- this.isPreRendered ? this.preRenderWrapper : this.el,
350
- );
351
-
352
- const executeEvent = (_eventType: EmbedEvent, data: any) => {
353
- this.executeCallbacks(_eventType, data, eventPort);
354
- }
355
-
356
- if (eventType === EmbedEvent.ApiIntercept && this.viewConfig.enableApiIntercept) {
357
- const getUnsavedAnswerTml = async (props: { sessionId?: string, vizId?: string }) => {
358
- const response = await this.triggerUIPassThrough(UIPassthroughEvent.GetUnsavedAnswerTML, props);
359
- return response[0]?.value;
360
- }
361
- handleInterceptEvent({ eventData: processedEventData, executeEvent, embedConfig: this.embedConfig, viewConfig: this.viewConfig, getUnsavedAnswerTml });
362
- return;
363
- }
364
-
365
- this.executeCallbacks(
366
- eventType,
367
- processedEventData,
368
- eventPort,
369
- );
370
- }
371
- };
372
339
  /**
373
340
  * Subscribe to message events that depend on successful iframe setup
374
341
  */
375
342
  private subscribeToMessageEvents() {
376
343
  this.unsubscribeToMessageEvents();
377
344
 
378
- window.addEventListener('message', this.messageEventListener);
345
+ const messageEventListener = (event: MessageEvent<any>) => {
346
+ const eventType = this.getEventType(event);
347
+ const eventPort = this.getEventPort(event);
348
+ const eventData = this.formatEventData(event, eventType);
349
+ if (event.source === this.iFrame.contentWindow) {
350
+ this.executeCallbacks(
351
+ eventType,
352
+ processEventData(
353
+ eventType,
354
+ eventData,
355
+ this.thoughtSpotHost,
356
+ this.isPreRendered ? this.preRenderWrapper : this.el,
357
+ ),
358
+ eventPort,
359
+ );
360
+ }
361
+ };
362
+ window.addEventListener('message', messageEventListener);
379
363
 
380
- this.subscribedListeners.message = this.messageEventListener;
364
+ this.subscribedListeners.message = messageEventListener;
381
365
  }
382
-
383
-
384
366
  /**
385
367
  * Adds event listeners for both network and message events.
386
368
  * This maintains backward compatibility with the existing method.
@@ -394,7 +376,6 @@ export class TsEmbed {
394
376
  this.subscribeToMessageEvents();
395
377
  }
396
378
 
397
-
398
379
  private unsubscribeToNetworkEvents() {
399
380
  if (this.subscribedListeners.online) {
400
381
  window.removeEventListener('online', this.subscribedListeners.online);
@@ -445,7 +426,7 @@ export class TsEmbed {
445
426
  message: customActionsResult.errors,
446
427
  });
447
428
  }
448
- const baseInitData = {
429
+ return {
449
430
  customisations: getCustomisations(this.embedConfig, this.viewConfig),
450
431
  authToken,
451
432
  runtimeFilterParams: this.viewConfig.excludeRuntimeFiltersfromURL
@@ -464,10 +445,7 @@ export class TsEmbed {
464
445
  this.embedConfig.customVariablesForThirdPartyTools || {},
465
446
  hiddenListColumns: this.viewConfig.hiddenListColumns || [],
466
447
  customActions: customActionsResult.actions,
467
- ...getInterceptInitData(this.embedConfig, this.viewConfig),
468
448
  };
469
-
470
- return baseInitData;
471
449
  }
472
450
 
473
451
  protected async getAppInitData() {
@@ -1045,21 +1023,6 @@ export class TsEmbed {
1045
1023
  this.iFrame.style.height = getCssDimension(height);
1046
1024
  }
1047
1025
 
1048
- protected createEmbedEventResponder = (eventPort: MessagePort | void, eventType: EmbedEvent) => {
1049
-
1050
- const { enableApiIntercept } = getInterceptInitData(this.embedConfig, this.viewConfig);
1051
- if (eventType === EmbedEvent.OnBeforeGetVizDataIntercept && enableApiIntercept) {
1052
- return (payload: any) => {
1053
- const payloadToSend = processLegacyInterceptResponse(payload);
1054
- this.triggerEventOnPort(eventPort, payloadToSend);
1055
- }
1056
- }
1057
-
1058
- return (payload: any) => {
1059
- this.triggerEventOnPort(eventPort, payload);
1060
- }
1061
- }
1062
-
1063
1026
  /**
1064
1027
  * Executes all registered event handlers for a particular event type
1065
1028
  * @param eventType The event type
@@ -1084,8 +1047,9 @@ export class TsEmbed {
1084
1047
  // payload
1085
1048
  || (!callbackObj.options.start && dataStatus === embedEventStatus.END)
1086
1049
  ) {
1087
- const responder = this.createEmbedEventResponder(eventPort, eventType);
1088
- callbackObj.callback(data, responder);
1050
+ callbackObj.callback(data, (payload) => {
1051
+ this.triggerEventOnPort(eventPort, payload);
1052
+ });
1089
1053
  }
1090
1054
  });
1091
1055
  }
@@ -1227,12 +1191,12 @@ export class TsEmbed {
1227
1191
  }
1228
1192
  }
1229
1193
 
1230
- /**
1231
- * @hidden
1232
- * Internal state to track if the embed container is loaded.
1233
- * This is used to trigger events after the embed container is loaded.
1234
- */
1235
- public isEmbedContainerLoaded = false;
1194
+ /**
1195
+ * @hidden
1196
+ * Internal state to track if the embed container is loaded.
1197
+ * This is used to trigger events after the embed container is loaded.
1198
+ */
1199
+ public isEmbedContainerLoaded = false;
1236
1200
 
1237
1201
  /**
1238
1202
  * @hidden
@@ -1384,7 +1348,7 @@ export class TsEmbed {
1384
1348
  }
1385
1349
  this.isPreRendered = true;
1386
1350
  this.showPreRenderByDefault = showPreRenderByDefault;
1387
-
1351
+
1388
1352
  const isAlreadyRendered = this.connectPreRendered();
1389
1353
  if (isAlreadyRendered && !replaceExistingPreRender) {
1390
1354
  return this;
@@ -1432,8 +1396,21 @@ export class TsEmbed {
1432
1396
  public destroy(): void {
1433
1397
  try {
1434
1398
  this.removeFullscreenChangeHandler();
1435
- this.insertedDomEl?.parentNode.removeChild(this.insertedDomEl);
1436
1399
  this.unsubscribeToEvents();
1400
+ if (!getEmbedConfig().waitForCleanupOnDestroy) {
1401
+ this.trigger(HostEvent.DestroyEmbed)
1402
+ this.insertedDomEl?.parentNode?.removeChild(this.insertedDomEl);
1403
+ } else {
1404
+ const cleanupTimeout = getEmbedConfig().cleanupTimeout;
1405
+ Promise.race([
1406
+ this.trigger(HostEvent.DestroyEmbed),
1407
+ new Promise((resolve) => setTimeout(resolve, cleanupTimeout)),
1408
+ ]).then(() => {
1409
+ this.insertedDomEl?.parentNode?.removeChild(this.insertedDomEl);
1410
+ }).catch((e) => {
1411
+ logger.log('Error destroying TS Embed', e);
1412
+ });
1413
+ }
1437
1414
  } catch (e) {
1438
1415
  logger.log('Error destroying TS Embed', e);
1439
1416
  }
package/src/errors.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  export const ERROR_MESSAGE = {
2
2
  INVALID_THOUGHTSPOT_HOST: 'Error parsing ThoughtSpot host. Please provide a valid URL.',
3
- SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND: 'Please select a worksheet to get started',
3
+ SPOTTER_EMBED_WORKSHEED_ID_NOT_FOUND: 'Please select a Model to get started',
4
4
  LIVEBOARD_VIZ_ID_VALIDATION: 'Please select a Liveboard to embed.',
5
5
  TRIGGER_TIMED_OUT: 'Trigger timed-out in getting a response',
6
6
  SEARCHEMBED_BETA_WRANING_MESSAGE: 'SearchEmbed is in Beta in this release.',
package/src/index.ts CHANGED
@@ -30,10 +30,10 @@ import {
30
30
  import { PinboardEmbed, LiveboardViewConfig, LiveboardEmbed } from './embed/liveboard';
31
31
  import { SearchEmbed, SearchViewConfig } from './embed/search';
32
32
  import { SearchBarEmbed, SearchBarViewConfig } from './embed/search-bar';
33
- import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig, BodylessConversation, BodylessConversationViewConfig } from './embed/bodyless-conversation';
33
+ import { SpotterAgentEmbed, SpotterAgentEmbedViewConfig, BodylessConversation, BodylessConversationViewConfig} from './embed/bodyless-conversation';
34
34
  import { SpotterEmbed, SpotterEmbedViewConfig, ConversationEmbed, ConversationViewConfig } from './embed/conversation';
35
35
  import {
36
- AuthFailureType, AuthStatus, AuthEvent,
36
+ AuthFailureType, AuthStatus, AuthEvent, AuthEventEmitter,
37
37
  } from './auth';
38
38
  import { getSessionInfo } from './utils/sessionInfoService';
39
39
  import {
@@ -64,7 +64,6 @@ import {
64
64
  ListPageColumns,
65
65
  CustomActionsPosition,
66
66
  CustomActionTarget,
67
- InterceptedApiType,
68
67
  } from './types';
69
68
  import { CustomCssVariables } from './css-variables';
70
69
  import { SageEmbed, SageViewConfig } from './embed/sage';
@@ -106,6 +105,7 @@ export {
106
105
  AuthFailureType,
107
106
  AuthStatus,
108
107
  AuthEvent,
108
+ AuthEventEmitter,
109
109
  AnswerService,
110
110
  // types
111
111
  SessionInterface,
@@ -152,7 +152,6 @@ export {
152
152
  DataPanelCustomColumnGroupsAccordionState,
153
153
  CustomActionsPosition,
154
154
  CustomActionTarget,
155
- InterceptedApiType,
156
155
  };
157
156
 
158
157
  export { resetCachedAuthToken } from './authToken';
@@ -6,14 +6,6 @@ describe('Exports', () => {
6
6
  });
7
7
 
8
8
  it('should not have undefined exports', () => {
9
- const undefinedKeys = Object.entries(Exports)
10
- .filter(([, exportValue]) => !Boolean(exportValue))
11
- .map(([key]) => key);
12
- // Helpful log if the expectation fails
13
- if (undefinedKeys.length) {
14
- // eslint-disable-next-line no-console
15
- console.log('Undefined re-exports in all-types-export:', undefinedKeys);
16
- }
17
- Object.entries(Exports).forEach(([, exportValue]) => { expect(Boolean(exportValue)).toBe(true); });
9
+ Object.entries(Exports).forEach(([, exportValue]) => {expect(Boolean(exportValue)).toBe(true);});
18
10
  });
19
11
  });
@@ -29,29 +29,23 @@ export {
29
29
  AuthFailureType,
30
30
  AuthStatus,
31
31
  AuthEvent,
32
- // value exports
32
+ AuthEventEmitter,
33
+ // types
33
34
  Page,
34
35
  AuthType,
36
+ RuntimeFilter,
35
37
  RuntimeFilterOp,
36
38
  EmbedEvent,
37
39
  HostEvent,
38
40
  DataSourceVisualMode,
39
41
  Action,
40
- PrefetchFeatures,
41
- resetCachedAuthToken,
42
- DataPanelCustomColumnGroupsAccordionState,
43
- InterceptedApiType,
44
- } from '../index';
45
-
46
- export type {
47
- // type-only exports
48
- RuntimeFilter,
49
42
  EmbedConfig,
50
43
  SearchViewConfig,
51
44
  SearchBarViewConfig,
52
45
  LiveboardViewConfig,
53
46
  SageViewConfig,
54
47
  AppViewConfig,
48
+ PrefetchFeatures,
55
49
  FrameParams,
56
50
  DOMSelector,
57
51
  MessageOptions,
@@ -62,5 +56,9 @@ export type {
62
56
  customCssInterface,
63
57
  CustomCssVariables,
64
58
  RuntimeParameter,
59
+ resetCachedAuthToken,
65
60
  UIPassthroughEvent,
61
+ DataPanelCustomColumnGroupsAccordionState,
62
+ CustomActionsPosition,
63
+ CustomActionTarget,
66
64
  } from '../index';