@rehers/rehers-roleplay-sdk 2.3.0 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/index.d.ts +4 -2
  2. package/package.json +1 -1
  3. package/roleplay-sdk.js +216 -137
package/index.d.ts CHANGED
@@ -82,9 +82,11 @@ export interface SeamlessRoleplaySDK {
82
82
  mount(container: HTMLElement, data?: SeamlessRoleplayOpenData): void;
83
83
  /** Open the add-to-scenario dialog for bulk contact import. */
84
84
  addToScenario(options: AddToScenarioOptions): void;
85
- /** Close the roleplay dialog or unmount. */
85
+ /** Close the active dialog. Does not affect mount. */
86
86
  close(): void;
87
- /** Destroy the SDK clears state, timers, and DOM. */
87
+ /** Unmount the mounted embed. Does not affect dialogs. */
88
+ unmount(): void;
89
+ /** Destroy the SDK — clears state, timers, and DOM (both mount and dialogs). */
88
90
  destroy(): void;
89
91
  }
90
92
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rehers/rehers-roleplay-sdk",
3
- "version": "2.3.0",
3
+ "version": "2.4.0",
4
4
  "description": "Seamless Roleplay SDK — embed roleplay call sessions via a modal + iframe",
5
5
  "main": "roleplay-sdk.js",
6
6
  "types": "index.d.ts",
package/roleplay-sdk.js CHANGED
@@ -15,7 +15,7 @@
15
15
  var SESSION_TIMEOUT_MS = 15000;
16
16
  var SDK_LOG_PREFIX = "[SeamlessRoleplay]";
17
17
 
18
- // ── State ───────────────────────────────────────────────────────────
18
+ // ── Auth state ────────────────────────────────────────────────────
19
19
  var publishableKey = null;
20
20
  var userId = null;
21
21
  var userEmail = null;
@@ -30,18 +30,25 @@
30
30
  var fetchingSession = null; // single-flight Promise
31
31
 
32
32
  var initCallbacks = { onReady: null, onError: null };
33
- var callbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
34
- var addToScenarioCallbacks = { onComplete: null, onClose: null, onError: null };
35
- var addToScenarioPendingContacts = null;
33
+ var initCalled = false;
36
34
 
37
- var overlay = null;
38
- var iframe = null;
35
+ // ── Mount state (persistent embed — survives dialog open/close) ───
36
+ var mountIframe = null;
39
37
  var mountContainer = null;
40
- var pendingContactData = null;
41
- var mode = null; // "dialog" | "mount" | "add-to-scenario"
42
- var listener = null;
43
- var initCalled = false;
44
- var closeTeardownTimer = null;
38
+ var mountContactData = null;
39
+ var mountCallbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
40
+ var mountListener = null;
41
+
42
+ // ── Dialog state (overlay — dialog or add-to-scenario) ────────────
43
+ var dialogOverlay = null;
44
+ var dialogIframe = null;
45
+ var dialogMode = null; // "dialog" | "add-to-scenario"
46
+ var dialogContactData = null;
47
+ var dialogCallbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
48
+ var dialogAddToScenarioCallbacks = { onComplete: null, onClose: null, onError: null };
49
+ var dialogAddToScenarioPendingContacts = null;
50
+ var dialogListener = null;
51
+ var dialogCloseTeardownTimer = null;
45
52
 
46
53
  // ── Safe logging ──────────────────────────────────────────────────
47
54
 
@@ -65,17 +72,17 @@
65
72
  return DEFAULT_API_ORIGIN;
66
73
  }
67
74
 
68
- function sendToIframe(msg) {
75
+ function sendMsg(iframeEl, msg) {
69
76
  try {
70
- if (iframe && iframe.contentWindow) {
71
- iframe.contentWindow.postMessage(msg, getOrigin());
77
+ if (iframeEl && iframeEl.contentWindow) {
78
+ iframeEl.contentWindow.postMessage(msg, getOrigin());
72
79
  }
73
80
  } catch (e) {
74
- logError("sendToIframe", e);
81
+ logError("sendMsg", e);
75
82
  }
76
83
  }
77
84
 
78
- // ── Session management ──────────────────────────────────────────────
85
+ // ── Session management ────────────────────────────────────────────
79
86
 
80
87
  function fetchSession() {
81
88
  if (fetchingSession) return fetchingSession;
@@ -167,80 +174,90 @@
167
174
  }, delay);
168
175
  }
169
176
 
170
- // ── Teardown ────────────────────────────────────────────────────────
177
+ // ── Teardown (dialog only — mount is independent) ─────────────────
171
178
 
172
- function teardown() {
179
+ function teardownDialog() {
173
180
  try {
174
- // Cancel any pending close→teardown timer so it can't destroy a new dialog
175
- if (closeTeardownTimer) {
176
- clearTimeout(closeTeardownTimer);
177
- closeTeardownTimer = null;
181
+ if (dialogCloseTeardownTimer) {
182
+ clearTimeout(dialogCloseTeardownTimer);
183
+ dialogCloseTeardownTimer = null;
178
184
  }
179
185
 
180
- if (mode === "dialog" || mode === "add-to-scenario") {
181
- if (overlay && overlay.parentNode) {
182
- overlay.parentNode.removeChild(overlay);
183
- }
184
- overlay = null;
185
- } else if (mode === "mount") {
186
- if (iframe && iframe.parentNode) {
187
- iframe.parentNode.removeChild(iframe);
188
- }
189
- mountContainer = null;
186
+ if (dialogOverlay && dialogOverlay.parentNode) {
187
+ dialogOverlay.parentNode.removeChild(dialogOverlay);
190
188
  }
189
+ dialogOverlay = null;
190
+
191
+ if (dialogListener) {
192
+ window.removeEventListener("message", dialogListener);
193
+ dialogListener = null;
194
+ }
195
+ } catch (e) {
196
+ logError("teardownDialog", e);
197
+ }
198
+
199
+ dialogIframe = null;
200
+ dialogContactData = null;
201
+ dialogAddToScenarioPendingContacts = null;
202
+ dialogMode = null;
203
+ dialogCallbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
204
+ dialogAddToScenarioCallbacks = { onComplete: null, onClose: null, onError: null };
205
+ }
191
206
 
192
- if (listener) {
193
- window.removeEventListener("message", listener);
194
- listener = null;
207
+ function teardownMount() {
208
+ try {
209
+ if (mountIframe && mountIframe.parentNode) {
210
+ mountIframe.parentNode.removeChild(mountIframe);
211
+ }
212
+ if (mountListener) {
213
+ window.removeEventListener("message", mountListener);
214
+ mountListener = null;
195
215
  }
196
216
  } catch (e) {
197
- logError("teardown", e);
217
+ logError("teardownMount", e);
198
218
  }
199
219
 
200
- // Always reset state even if DOM cleanup failed
201
- iframe = null;
202
- pendingContactData = null;
203
- addToScenarioPendingContacts = null;
204
- mode = null;
205
- callbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
206
- addToScenarioCallbacks = { onComplete: null, onClose: null, onError: null };
220
+ mountIframe = null;
221
+ mountContainer = null;
222
+ mountContactData = null;
223
+ mountCallbacks = { onCallStarted: null, onCallEnded: null, onClose: null, onError: null };
207
224
  }
208
225
 
209
- // ── Message handler ─────────────────────────────────────────────────
226
+ // ── Message dispatch ──────────────────────────────────────────────
210
227
 
211
- function dispatchInitToIframe(token) {
212
- if (addToScenarioPendingContacts) {
228
+ function dispatchInitToTarget(targetIframe, contactData, atsContacts) {
229
+ if (atsContacts) {
213
230
  var msg = {
214
231
  type: "seamless-add-to-scenario-init",
215
- sessionToken: token,
232
+ sessionToken: sessionToken,
216
233
  publishableKey: publishableKey,
217
234
  userId: userId,
218
- contacts: addToScenarioPendingContacts,
235
+ contacts: atsContacts,
219
236
  };
220
237
  if (paymentLink) msg.paymentLink = paymentLink;
221
- sendToIframe(msg);
222
- } else if (token) {
238
+ sendMsg(targetIframe, msg);
239
+ } else if (sessionToken) {
223
240
  var msg = {
224
241
  type: "seamless-session-init",
225
- sessionToken: token,
226
- contact: pendingContactData ? {
227
- name: pendingContactData.name,
228
- domain: pendingContactData.domain,
229
- company: pendingContactData.company,
230
- title: pendingContactData.title,
231
- companyDescription: pendingContactData.companyDescription || undefined,
232
- liUrl: pendingContactData.liUrl || undefined,
242
+ sessionToken: sessionToken,
243
+ contact: contactData ? {
244
+ name: contactData.name,
245
+ domain: contactData.domain,
246
+ company: contactData.company,
247
+ title: contactData.title,
248
+ companyDescription: contactData.companyDescription || undefined,
249
+ liUrl: contactData.liUrl || undefined,
233
250
  } : null,
234
251
  };
235
- sendToIframe(msg);
252
+ sendMsg(targetIframe, msg);
236
253
  } else if (paymentLink) {
237
- sendToIframe({
254
+ sendMsg(targetIframe, {
238
255
  type: "seamless-session-init",
239
256
  paymentLink: paymentLink,
240
257
  contact: null,
241
258
  });
242
259
  } else {
243
- sendToIframe({
260
+ sendMsg(targetIframe, {
244
261
  type: "seamless-session-init",
245
262
  paymentLink: null,
246
263
  contact: null,
@@ -248,53 +265,104 @@
248
265
  }
249
266
  }
250
267
 
251
- function handleMessage(event) {
268
+ // ── Mount message handler ─────────────────────────────────────────
269
+
270
+ function handleMountMessage(event) {
271
+ try {
272
+ if (event.origin !== getOrigin()) return;
273
+ if (!mountIframe || !event.source || event.source !== mountIframe.contentWindow) return;
274
+
275
+ var data = event.data;
276
+ if (!data || typeof data.type !== "string") return;
277
+
278
+ switch (data.type) {
279
+ case "ROLEPLAY_READY":
280
+ getSessionToken()
281
+ .then(function (token) {
282
+ dispatchInitToTarget(mountIframe, mountContactData, null);
283
+ })
284
+ .catch(function () {
285
+ dispatchInitToTarget(mountIframe, mountContactData, null);
286
+ });
287
+ break;
288
+
289
+ case "ROLEPLAY_CALL_STARTED":
290
+ if (mountCallbacks.onCallStarted) {
291
+ mountCallbacks.onCallStarted({ callId: data.callId });
292
+ }
293
+ break;
294
+
295
+ case "ROLEPLAY_CALL_ENDED":
296
+ if (mountCallbacks.onCallEnded) {
297
+ mountCallbacks.onCallEnded({ callId: data.callId, duration: data.duration });
298
+ }
299
+ break;
300
+
301
+ case "ROLEPLAY_ERROR":
302
+ if (mountCallbacks.onError) {
303
+ mountCallbacks.onError({ code: data.code, message: data.message });
304
+ }
305
+ break;
306
+
307
+ case "ROLEPLAY_CLOSED":
308
+ var onClose = mountCallbacks.onClose;
309
+ teardownMount();
310
+ if (onClose) onClose();
311
+ break;
312
+ }
313
+ } catch (e) {
314
+ logError("handleMountMessage", e);
315
+ }
316
+ }
317
+
318
+ // ── Dialog message handler ────────────────────────────────────────
319
+
320
+ function handleDialogMessage(event) {
252
321
  try {
253
322
  if (event.origin !== getOrigin()) return;
323
+ if (!dialogIframe || !event.source || event.source !== dialogIframe.contentWindow) return;
254
324
 
255
325
  var data = event.data;
256
326
  if (!data || typeof data.type !== "string") return;
257
327
 
258
328
  switch (data.type) {
259
329
  case "ROLEPLAY_READY":
260
- // Ensure we have a fresh token before sending init to iframe
261
330
  getSessionToken()
262
331
  .then(function (token) {
263
- dispatchInitToIframe(token);
332
+ dispatchInitToTarget(dialogIframe, dialogContactData, dialogAddToScenarioPendingContacts);
264
333
  })
265
334
  .catch(function () {
266
- // Token refresh failed — send whatever we have (iframe will handle auth errors)
267
- dispatchInitToIframe(sessionToken);
335
+ dispatchInitToTarget(dialogIframe, dialogContactData, dialogAddToScenarioPendingContacts);
268
336
  });
269
337
  break;
270
338
 
271
339
  case "ROLEPLAY_CALL_STARTED":
272
- if (callbacks.onCallStarted) {
273
- callbacks.onCallStarted({ callId: data.callId });
340
+ if (dialogCallbacks.onCallStarted) {
341
+ dialogCallbacks.onCallStarted({ callId: data.callId });
274
342
  }
275
343
  break;
276
344
 
277
345
  case "ROLEPLAY_CALL_ENDED":
278
- if (callbacks.onCallEnded) {
279
- callbacks.onCallEnded({ callId: data.callId, duration: data.duration });
346
+ if (dialogCallbacks.onCallEnded) {
347
+ dialogCallbacks.onCallEnded({ callId: data.callId, duration: data.duration });
280
348
  }
281
349
  break;
282
350
 
283
351
  case "ROLEPLAY_ERROR":
284
- if (callbacks.onError) {
285
- callbacks.onError({ code: data.code, message: data.message });
352
+ if (dialogCallbacks.onError) {
353
+ dialogCallbacks.onError({ code: data.code, message: data.message });
286
354
  }
287
355
  break;
288
356
 
289
357
  case "ROLEPLAY_CLOSED":
290
- var onClose = callbacks.onClose;
291
- teardown();
358
+ var onClose = dialogCallbacks.onClose;
359
+ teardownDialog();
292
360
  if (onClose) onClose();
293
361
  break;
294
362
 
295
363
  case "ADD_TO_SCENARIO_COMPLETE":
296
- var atsOnComplete = addToScenarioCallbacks.onComplete;
297
- teardown();
364
+ var atsOnComplete = dialogAddToScenarioCallbacks.onComplete;
365
+ teardownDialog();
298
366
  if (atsOnComplete) {
299
367
  atsOnComplete({
300
368
  scenarioId: data.scenarioId,
@@ -306,36 +374,36 @@
306
374
  break;
307
375
 
308
376
  case "ADD_TO_SCENARIO_ERROR":
309
- if (addToScenarioCallbacks.onError) {
310
- addToScenarioCallbacks.onError({ code: data.code, message: data.message });
377
+ if (dialogAddToScenarioCallbacks.onError) {
378
+ dialogAddToScenarioCallbacks.onError({ code: data.code, message: data.message });
311
379
  }
312
380
  break;
313
381
 
314
382
  case "ADD_TO_SCENARIO_CLOSED":
315
- var atsOnClose = addToScenarioCallbacks.onClose;
316
- teardown();
383
+ var atsOnClose = dialogAddToScenarioCallbacks.onClose;
384
+ teardownDialog();
317
385
  if (atsOnClose) atsOnClose();
318
386
  break;
319
387
  }
320
388
  } catch (e) {
321
- logError("handleMessage", e);
389
+ logError("handleDialogMessage", e);
322
390
  }
323
391
  }
324
392
 
325
- // ── Close ───────────────────────────────────────────────────────────
393
+ // ── Close (dialog only) ───────────────────────────────────────────
326
394
 
327
- function close() {
395
+ function closeDialog() {
328
396
  try {
329
- sendToIframe({ type: "roleplay-close" });
330
- if (closeTeardownTimer) clearTimeout(closeTeardownTimer);
331
- closeTeardownTimer = setTimeout(teardown, 300);
397
+ sendMsg(dialogIframe, { type: "roleplay-close" });
398
+ if (dialogCloseTeardownTimer) clearTimeout(dialogCloseTeardownTimer);
399
+ dialogCloseTeardownTimer = setTimeout(teardownDialog, 300);
332
400
  } catch (e) {
333
401
  logError("close", e);
334
- teardown();
402
+ teardownDialog();
335
403
  }
336
404
  }
337
405
 
338
- // ── Create iframe ───────────────────────────────────────────────────
406
+ // ── Create iframe ─────────────────────────────────────────────────
339
407
 
340
408
  function createIframe(path) {
341
409
  var iframeEl = document.createElement("iframe");
@@ -348,7 +416,7 @@
348
416
  return iframeEl;
349
417
  }
350
418
 
351
- // ── SDK API ─────────────────────────────────────────────────────────
419
+ // ── SDK API ───────────────────────────────────────────────────────
352
420
 
353
421
  var SeamlessRoleplay = {
354
422
  /**
@@ -416,19 +484,19 @@
416
484
  return;
417
485
  }
418
486
 
419
- // If already open, tear down first (also cancels any pending close timer)
420
- if (overlay || (iframe && mode)) teardown();
487
+ // Tear down any existing dialog (NOT the mount)
488
+ if (dialogOverlay || dialogIframe) teardownDialog();
421
489
 
422
- pendingContactData = data;
423
- callbacks.onCallStarted = data.onCallStarted || null;
424
- callbacks.onCallEnded = data.onCallEnded || null;
425
- callbacks.onClose = data.onClose || null;
426
- callbacks.onError = data.onError || null;
427
- mode = "dialog";
490
+ dialogContactData = data;
491
+ dialogCallbacks.onCallStarted = data.onCallStarted || null;
492
+ dialogCallbacks.onCallEnded = data.onCallEnded || null;
493
+ dialogCallbacks.onClose = data.onClose || null;
494
+ dialogCallbacks.onError = data.onError || null;
495
+ dialogMode = "dialog";
428
496
 
429
497
  // Listen for messages
430
- listener = handleMessage;
431
- window.addEventListener("message", listener);
498
+ dialogListener = handleDialogMessage;
499
+ window.addEventListener("message", dialogListener);
432
500
 
433
501
  // Build overlay
434
502
  var el = document.createElement("div");
@@ -478,7 +546,7 @@
478
546
  cbs.alignItems = "center";
479
547
  cbs.justifyContent = "center";
480
548
  cbs.lineHeight = "1";
481
- closeBtn.addEventListener("click", close);
549
+ closeBtn.addEventListener("click", closeDialog);
482
550
 
483
551
  var iframeEl = createIframe();
484
552
 
@@ -487,15 +555,15 @@
487
555
  el.appendChild(container);
488
556
 
489
557
  el.addEventListener("click", function (e) {
490
- if (e.target === el) close();
558
+ if (e.target === el) closeDialog();
491
559
  });
492
560
 
493
- overlay = el;
494
- iframe = iframeEl;
495
- document.body.appendChild(overlay);
561
+ dialogOverlay = el;
562
+ dialogIframe = iframeEl;
563
+ document.body.appendChild(dialogOverlay);
496
564
  } catch (e) {
497
565
  logError("open", e);
498
- teardown();
566
+ teardownDialog();
499
567
  if (data && typeof data.onError === "function") {
500
568
  try { data.onError({ code: "SDK_ERROR", message: e.message || "Unexpected error during open" }); } catch (_) {}
501
569
  }
@@ -527,28 +595,27 @@
527
595
  return;
528
596
  }
529
597
 
530
- // If already open, tear down first (also cancels any pending close timer)
531
- if (overlay || (iframe && mode)) teardown();
598
+ // Tear down any existing mount (re-mount)
599
+ if (mountIframe) teardownMount();
532
600
 
533
- pendingContactData = hasContactData ? data : null;
534
- callbacks.onCallStarted = (data && data.onCallStarted) || null;
535
- callbacks.onCallEnded = (data && data.onCallEnded) || null;
536
- callbacks.onClose = (data && data.onClose) || null;
537
- callbacks.onError = (data && data.onError) || null;
538
- mode = "mount";
601
+ mountContactData = hasContactData ? data : null;
602
+ mountCallbacks.onCallStarted = (data && data.onCallStarted) || null;
603
+ mountCallbacks.onCallEnded = (data && data.onCallEnded) || null;
604
+ mountCallbacks.onClose = (data && data.onClose) || null;
605
+ mountCallbacks.onError = (data && data.onError) || null;
539
606
  mountContainer = container;
540
607
 
541
608
  // Listen for messages
542
- listener = handleMessage;
543
- window.addEventListener("message", listener);
609
+ mountListener = handleMountMessage;
610
+ window.addEventListener("message", mountListener);
544
611
 
545
612
  // No contact data → full app embed at root; with contact → /embed/roleplay-call
546
613
  var iframeEl = createIframe(hasContactData ? "/embed/roleplay-call" : "/");
547
- iframe = iframeEl;
614
+ mountIframe = iframeEl;
548
615
  container.appendChild(iframeEl);
549
616
  } catch (e) {
550
617
  logError("mount", e);
551
- teardown();
618
+ teardownMount();
552
619
  if (data && typeof data.onError === "function") {
553
620
  try { data.onError({ code: "SDK_ERROR", message: e.message || "Unexpected error during mount" }); } catch (_) {}
554
621
  }
@@ -588,18 +655,18 @@
588
655
  }
589
656
  }
590
657
 
591
- // Tear down any existing dialog (also cancels any pending close timer)
592
- if (overlay || (iframe && mode)) teardown();
658
+ // Tear down any existing dialog (NOT the mount)
659
+ if (dialogOverlay || dialogIframe) teardownDialog();
593
660
 
594
- addToScenarioPendingContacts = opts.contacts;
595
- addToScenarioCallbacks.onComplete = opts.onComplete || null;
596
- addToScenarioCallbacks.onClose = opts.onClose || null;
597
- addToScenarioCallbacks.onError = opts.onError || null;
598
- mode = "add-to-scenario";
661
+ dialogAddToScenarioPendingContacts = opts.contacts;
662
+ dialogAddToScenarioCallbacks.onComplete = opts.onComplete || null;
663
+ dialogAddToScenarioCallbacks.onClose = opts.onClose || null;
664
+ dialogAddToScenarioCallbacks.onError = opts.onError || null;
665
+ dialogMode = "add-to-scenario";
599
666
 
600
667
  // Listen for messages
601
- listener = handleMessage;
602
- window.addEventListener("message", listener);
668
+ dialogListener = handleDialogMessage;
669
+ window.addEventListener("message", dialogListener);
603
670
 
604
671
  // Build overlay — wide, compact dialog
605
672
  var el = document.createElement("div");
@@ -663,22 +730,22 @@
663
730
  cbs.transition = "background 0.15s";
664
731
  closeBtn.addEventListener("mouseenter", function () { cbs.background = "rgba(0,0,0,0.15)"; });
665
732
  closeBtn.addEventListener("mouseleave", function () { cbs.background = "rgba(0,0,0,0.08)"; });
666
- closeBtn.addEventListener("click", close);
733
+ closeBtn.addEventListener("click", closeDialog);
667
734
 
668
735
  container.appendChild(iframeEl);
669
736
  container.appendChild(closeBtn);
670
737
  el.appendChild(container);
671
738
 
672
739
  el.addEventListener("click", function (e) {
673
- if (e.target === el) close();
740
+ if (e.target === el) closeDialog();
674
741
  });
675
742
 
676
- overlay = el;
677
- iframe = iframeEl;
678
- document.body.appendChild(overlay);
743
+ dialogOverlay = el;
744
+ dialogIframe = iframeEl;
745
+ document.body.appendChild(dialogOverlay);
679
746
  } catch (e) {
680
747
  logError("addToScenario", e);
681
- teardown();
748
+ teardownDialog();
682
749
  if (opts && typeof opts.onError === "function") {
683
750
  try { opts.onError({ code: "SDK_ERROR", message: e.message || "Unexpected error during addToScenario" }); } catch (_) {}
684
751
  }
@@ -686,19 +753,30 @@
686
753
  },
687
754
 
688
755
  /**
689
- * Close the roleplay.
756
+ * Close the active dialog. Does not affect mount.
690
757
  */
691
758
  close: function () {
692
759
  try {
693
- close();
760
+ closeDialog();
694
761
  } catch (e) {
695
762
  logError("close", e);
696
- teardown();
763
+ teardownDialog();
764
+ }
765
+ },
766
+
767
+ /**
768
+ * Unmount the mounted embed. Does not affect dialogs.
769
+ */
770
+ unmount: function () {
771
+ try {
772
+ teardownMount();
773
+ } catch (e) {
774
+ logError("unmount", e);
697
775
  }
698
776
  },
699
777
 
700
778
  /**
701
- * Destroy the SDK — clears state, timers, and DOM.
779
+ * Destroy the SDK — clears state, timers, and DOM (both mount and dialogs).
702
780
  */
703
781
  destroy: function () {
704
782
  try {
@@ -706,7 +784,8 @@
706
784
  clearTimeout(refreshTimer);
707
785
  refreshTimer = null;
708
786
  }
709
- teardown();
787
+ teardownDialog();
788
+ teardownMount();
710
789
  publishableKey = null;
711
790
  userId = null;
712
791
  userEmail = null;