File size: 2,582 Bytes
ec8acdf
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import {StrictMode} from 'react';
import {createRoot} from 'react-dom/client';
import App, { renderTurnstileWidgets } from './App.tsx';
import { ensureTurnstileScript } from './turnstile';
import { initI18n } from './i18n';
import { initSentry } from './sentry';
import { initDebugBearRum } from './debugbear-rum';
import './index.css';

initSentry();
initDebugBearRum();

initI18n().then(() => {
  createRoot(document.getElementById('root')!).render(
    <StrictMode>
      <App />
    </StrictMode>,
  );

  // Turnstile is only consumed by the enterprise contact form, so the
  // challenge script is injected on demand — when the form approaches the
  // viewport — instead of shipping ~100KB of challenge JS to every visitor.
  const renderWhenReady = () => {
    if (window.turnstile && renderTurnstileWidgets() > 0) return;
    let attempts = 0;
    const retryInterval = window.setInterval(() => {
      if ((window.turnstile && renderTurnstileWidgets() > 0) || ++attempts >= 20) {
        window.clearInterval(retryInterval);
      }
    }, 250);
  };

  const ensureTurnstile = () => {
    void ensureTurnstileScript().then((loaded) => {
      if (loaded) renderWhenReady();
    });
  };

  // The form lives on the enterprise page, which mounts only while the hash
  // starts with #enterprise — on the home page the container doesn't exist,
  // so the trigger is (re-)armed on every enterprise hash entry. The poll
  // covers createRoot().render() not committing synchronously.
  const isEnterpriseHash = () => window.location.hash.startsWith('#enterprise');
  const armViewportTrigger = (findAttempts = 0) => {
    const widget = document.querySelector<HTMLElement>('.cf-turnstile');
    if (!widget) {
      if (findAttempts < 20) window.setTimeout(() => armViewportTrigger(findAttempts + 1), 250);
      return;
    }
    if (widget.dataset.wmObserved) return;
    widget.dataset.wmObserved = 'true';
    if (!('IntersectionObserver' in window)) {
      ensureTurnstile();
      return;
    }
    const observer = new IntersectionObserver((entries) => {
      if (entries.some((entry) => entry.isIntersecting)) {
        observer.disconnect();
        ensureTurnstile();
      }
    }, { rootMargin: '600px 0px' });
    observer.observe(widget);
  };

  if (isEnterpriseHash()) armViewportTrigger();
  window.addEventListener('hashchange', () => {
    // Ordinary anchors (#pricing, logo resets to '') must not pull in the
    // challenge script — only enterprise entries, where the form mounts.
    if (isEnterpriseHash()) armViewportTrigger();
  });
});