PluginProbe
HubSpot All-In-One Marketing – Forms, Popups, Live Chat / 11.3.75
HubSpot All-In-One Marketing – Forms, Popups, Live Chat v11.3.75
11.3.75 11.3.73 11.3.71 11.3.70 11.3.69 11.3.64 11.3.65 11.3.62 11.3.61 11.3.56 11.3.58 11.0.31 11.0.52 11.0.54 11.0.56 11.0.58 11.0.7 11.1.10 11.1.11 11.1.13 11.1.14 11.1.15 11.1.2 11.1.20 11.1.21 All 73 releases
leadin / scripts / utils / embedderReady.ts

embedderReady.ts in HubSpot All-In-One Marketing – Forms, Popups, Live Chat 11.3.75, at scripts/utils/embedderReady.ts

103 lines 3.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 import Raven from '../lib/Raven';
2
3 const POLL_INTERVAL_MS = 250;
4 const DEFAULT_TIMEOUT_MS = 15000;
5
6 const EMBEDDER_SCRIPT_SELECTOR = 'script[src*="/integrated-app-embedder/"]';
7
8 export function isEmbedderReady() {
9 const { IntegratedAppEmbedder, IntegratedAppOptions }: any = window;
10
11 return !!IntegratedAppEmbedder && typeof IntegratedAppOptions === 'function';
12 }
13
14 function getEmbedderDiagnostics() {
15 const scriptTag = document.querySelector(
16 EMBEDDER_SCRIPT_SELECTOR
17 ) as HTMLScriptElement | null;
18
19 return {
20 hasScriptTag: !!scriptTag,
21 scriptSrc: scriptTag ? scriptTag.src : null,
22 readyState: document.readyState,
23 hasEmbedder: !!(window as any).IntegratedAppEmbedder,
24 typeofOptions: typeof (window as any).IntegratedAppOptions,
25 };
26 }
27
28 /**
29 * The embedder script is a cross-origin script from js.hubspot.com, and nothing
30 * makes the widgets wait for it: they read its globals off `window` the moment a
31 * control renders. On sites where an asset pipeline defers it, or where the
32 * editor is simply slow, the widget can lose that race and fail permanently even
33 * though the script arrives seconds later.
34 *
35 * Resolves true as soon as the globals appear, or false once the wait is up.
36 */
37 export function whenEmbedderReady(
38 timeoutMs: number = DEFAULT_TIMEOUT_MS
39 ): { promise: Promise<boolean>; cancel: () => void } {
40 let intervalId: number | undefined;
41
42 const cancel = () => {
43 if (intervalId !== undefined) {
44 window.clearInterval(intervalId);
45 intervalId = undefined;
46 }
47 };
48
49 const promise = new Promise<boolean>(resolve => {
50 if (isEmbedderReady()) {
51 console.info('HubSpot plugin - embedder ready immediately');
52 resolve(true);
53 return;
54 }
55
56 const startedAt = Date.now();
57
58 console.info(
59 `HubSpot plugin - waiting up to ${timeoutMs}ms for embedder script`,
60 getEmbedderDiagnostics()
61 );
62
63 intervalId = window.setInterval(() => {
64 const waitedMs = Date.now() - startedAt;
65
66 if (isEmbedderReady()) {
67 cancel();
68 console.info(`HubSpot plugin - embedder ready after ${waitedMs}ms`);
69 resolve(true);
70 } else if (waitedMs >= timeoutMs) {
71 cancel();
72 resolve(false);
73 }
74 }, POLL_INTERVAL_MS);
75 });
76
77 return { promise, cancel };
78 }
79
80 /**
81 * Reports a give-up so these failures stop being invisible. Until now the widget
82 * rendered its error box without telling anyone, so the only signal we had for
83 * this whole class of problem came from unrelated admin pages.
84 *
85 * Uses captureException rather than captureMessage on purpose: Raven is
86 * configured with a shouldSendCallback that drops any event whose culprit does
87 * not match plugins/leadin/, and captureMessage does not attach a stack trace,
88 * so it has no culprit to match on.
89 */
90 export function reportEmbedderUnavailable(waitedMs: number) {
91 const diagnostics = getEmbedderDiagnostics();
92
93 console.error(
94 `HubSpot plugin - embedder unavailable after ${waitedMs}ms`,
95 diagnostics
96 );
97
98 Raven.captureException(new Error('Leadin embedder unavailable'), {
99 fingerprint: ['EMBEDDER_UNAVAILABLE'],
100 extra: { waitedMs, ...diagnostics },
101 });
102 }
103