@authon/js 0.3.1 → 0.3.2

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.
package/dist/index.d.cts CHANGED
@@ -37,6 +37,8 @@ declare class Authon {
37
37
  private providers;
38
38
  private providerFlowModes;
39
39
  private initialized;
40
+ private captchaEnabled;
41
+ private turnstileSiteKey;
40
42
  constructor(publishableKey: string, config?: AuthonConfig);
41
43
  getProviders(): Promise<OAuthProviderType[]>;
42
44
  openSignIn(): Promise<void>;
@@ -44,9 +46,10 @@ declare class Authon {
44
46
  /** Update theme at runtime without destroying form state */
45
47
  setTheme(theme: 'light' | 'dark' | 'auto'): void;
46
48
  signInWithOAuth(provider: OAuthProviderType, options?: OAuthSignInOptions): Promise<void>;
47
- signInWithEmail(email: string, password: string): Promise<AuthonUser>;
49
+ signInWithEmail(email: string, password: string, turnstileToken?: string): Promise<AuthonUser>;
48
50
  signUpWithEmail(email: string, password: string, meta?: {
49
51
  displayName?: string;
52
+ turnstileToken?: string;
50
53
  }): Promise<AuthonUser>;
51
54
  signOut(): Promise<void>;
52
55
  getUser(): AuthonUser | null;
@@ -108,6 +111,7 @@ declare class Authon {
108
111
  leave: (orgId: string) => Promise<void>;
109
112
  };
110
113
  destroy(): void;
114
+ private loadTurnstileScript;
111
115
  private emit;
112
116
  private ensureInitialized;
113
117
  private getModal;
package/dist/index.d.ts CHANGED
@@ -37,6 +37,8 @@ declare class Authon {
37
37
  private providers;
38
38
  private providerFlowModes;
39
39
  private initialized;
40
+ private captchaEnabled;
41
+ private turnstileSiteKey;
40
42
  constructor(publishableKey: string, config?: AuthonConfig);
41
43
  getProviders(): Promise<OAuthProviderType[]>;
42
44
  openSignIn(): Promise<void>;
@@ -44,9 +46,10 @@ declare class Authon {
44
46
  /** Update theme at runtime without destroying form state */
45
47
  setTheme(theme: 'light' | 'dark' | 'auto'): void;
46
48
  signInWithOAuth(provider: OAuthProviderType, options?: OAuthSignInOptions): Promise<void>;
47
- signInWithEmail(email: string, password: string): Promise<AuthonUser>;
49
+ signInWithEmail(email: string, password: string, turnstileToken?: string): Promise<AuthonUser>;
48
50
  signUpWithEmail(email: string, password: string, meta?: {
49
51
  displayName?: string;
52
+ turnstileToken?: string;
50
53
  }): Promise<AuthonUser>;
51
54
  signOut(): Promise<void>;
52
55
  getUser(): AuthonUser | null;
@@ -108,6 +111,7 @@ declare class Authon {
108
111
  leave: (orgId: string) => Promise<void>;
109
112
  };
110
113
  destroy(): void;
114
+ private loadTurnstileScript;
111
115
  private emit;
112
116
  private ensureInitialized;
113
117
  private getModal;
package/dist/index.js CHANGED
@@ -120,10 +120,15 @@ var ModalRenderer = class {
120
120
  selectedWallet = "";
121
121
  overlayEmail = "";
122
122
  overlayError = "";
123
+ // Turnstile CAPTCHA
124
+ captchaSiteKey = "";
125
+ turnstileWidgetId = null;
126
+ turnstileToken = "";
123
127
  constructor(options) {
124
128
  this.mode = options.mode;
125
129
  this.theme = options.theme || "auto";
126
130
  this.branding = { ...DEFAULT_BRANDING, ...options.branding };
131
+ this.captchaSiteKey = options.captchaSiteKey || "";
127
132
  this.onProviderClick = options.onProviderClick;
128
133
  this.onEmailSubmit = options.onEmailSubmit;
129
134
  this.onClose = options.onClose;
@@ -161,6 +166,11 @@ var ModalRenderer = class {
161
166
  document.removeEventListener("keydown", this.escHandler);
162
167
  this.escHandler = null;
163
168
  }
169
+ if (this.turnstileWidgetId !== null) {
170
+ window.turnstile?.remove(this.turnstileWidgetId);
171
+ this.turnstileWidgetId = null;
172
+ this.turnstileToken = "";
173
+ }
164
174
  if (this.hostElement) {
165
175
  this.hostElement.remove();
166
176
  this.hostElement = null;
@@ -171,6 +181,15 @@ var ModalRenderer = class {
171
181
  }
172
182
  this.currentOverlay = "none";
173
183
  }
184
+ getTurnstileToken() {
185
+ return this.turnstileToken;
186
+ }
187
+ resetTurnstile() {
188
+ if (this.turnstileWidgetId !== null) {
189
+ window.turnstile?.reset(this.turnstileWidgetId);
190
+ this.turnstileToken = "";
191
+ }
192
+ }
174
193
  /** Update theme at runtime without destroying form state */
175
194
  setTheme(theme) {
176
195
  this.theme = theme;
@@ -369,10 +388,12 @@ var ModalRenderer = class {
369
388
  </button>`;
370
389
  }).join("") : "";
371
390
  const divider = showProviders && b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>or</span></div>` : "";
391
+ const captchaContainer = this.captchaSiteKey ? '<div id="turnstile-container" style="display:flex;justify-content:center;margin:4px 0"></div>' : "";
372
392
  const emailForm = b.showEmailPassword !== false ? `<form class="email-form" id="email-form">
373
393
  <input type="email" placeholder="Email address" name="email" required class="input" autocomplete="email" />
374
394
  <input type="password" placeholder="Password" name="password" required class="input" autocomplete="${isSignUp ? "new-password" : "current-password"}" />
375
395
  ${isSignUp ? '<p class="password-hint">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ""}
396
+ ${captchaContainer}
376
397
  <button type="submit" class="submit-btn">${isSignUp ? "Sign up" : "Sign in"}</button>
377
398
  </form>` : "";
378
399
  const hasMethodAbove = showProviders && this.enabledProviders.length > 0 || b.showEmailPassword !== false;
@@ -429,6 +450,45 @@ var ModalRenderer = class {
429
450
  ${b.showSecuredBy !== false ? `<div class="secured-by">Secured by <a href="https://authon.dev" target="_blank" rel="noopener noreferrer" class="secured-link">Authon</a></div>` : ""}
430
451
  `;
431
452
  }
453
+ renderTurnstile() {
454
+ if (!this.captchaSiteKey || !this.shadowRoot) return;
455
+ const container = this.shadowRoot.getElementById("turnstile-container");
456
+ if (!container) return;
457
+ const w = window;
458
+ const tryRender = () => {
459
+ if (!w.turnstile || !container.isConnected) return;
460
+ const wrapper = document.createElement("div");
461
+ wrapper.style.display = "flex";
462
+ wrapper.style.justifyContent = "center";
463
+ document.body.appendChild(wrapper);
464
+ this.turnstileWidgetId = w.turnstile.render(wrapper, {
465
+ sitekey: this.captchaSiteKey,
466
+ callback: (token) => {
467
+ this.turnstileToken = token;
468
+ },
469
+ "expired-callback": () => {
470
+ this.turnstileToken = "";
471
+ },
472
+ "error-callback": () => {
473
+ this.turnstileToken = "";
474
+ },
475
+ theme: this.isDark() ? "dark" : "light",
476
+ size: "flexible"
477
+ });
478
+ container.appendChild(wrapper);
479
+ };
480
+ if (w.turnstile) {
481
+ tryRender();
482
+ } else {
483
+ const interval = setInterval(() => {
484
+ if (w.turnstile) {
485
+ clearInterval(interval);
486
+ tryRender();
487
+ }
488
+ }, 200);
489
+ setTimeout(() => clearInterval(interval), 1e4);
490
+ }
491
+ }
432
492
  isDark() {
433
493
  if (this.theme === "dark") return true;
434
494
  if (this.theme === "light") return false;
@@ -1011,6 +1071,7 @@ var ModalRenderer = class {
1011
1071
  );
1012
1072
  });
1013
1073
  }
1074
+ this.renderTurnstile();
1014
1075
  const backBtn = this.shadowRoot.getElementById("back-btn");
1015
1076
  if (backBtn) {
1016
1077
  backBtn.addEventListener("click", () => {
@@ -1538,6 +1599,8 @@ var Authon = class {
1538
1599
  providers = [];
1539
1600
  providerFlowModes = {};
1540
1601
  initialized = false;
1602
+ captchaEnabled = false;
1603
+ turnstileSiteKey = "";
1541
1604
  constructor(publishableKey, config) {
1542
1605
  this.publishableKey = publishableKey;
1543
1606
  this.config = {
@@ -1572,10 +1635,12 @@ var Authon = class {
1572
1635
  await this.ensureInitialized();
1573
1636
  await this.startOAuthFlow(provider, options);
1574
1637
  }
1575
- async signInWithEmail(email, password) {
1638
+ async signInWithEmail(email, password, turnstileToken) {
1639
+ const body = { email, password };
1640
+ if (turnstileToken) body.turnstileToken = turnstileToken;
1576
1641
  const res = await this.apiPost(
1577
1642
  "/v1/auth/signin",
1578
- { email, password }
1643
+ body
1579
1644
  );
1580
1645
  if (res.mfaRequired && res.mfaToken) {
1581
1646
  this.emit("mfaRequired", res.mfaToken);
@@ -1869,6 +1934,14 @@ var Authon = class {
1869
1934
  this.listeners.clear();
1870
1935
  }
1871
1936
  // ── Internal ──
1937
+ loadTurnstileScript() {
1938
+ if (typeof document === "undefined") return;
1939
+ if (document.querySelector('script[src*="challenges.cloudflare.com/turnstile"]')) return;
1940
+ const script = document.createElement("script");
1941
+ script.src = "https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit";
1942
+ script.async = true;
1943
+ document.head.appendChild(script);
1944
+ }
1872
1945
  emit(event, ...args) {
1873
1946
  this.listeners.get(event)?.forEach((fn) => fn(...args));
1874
1947
  }
@@ -1880,6 +1953,11 @@ var Authon = class {
1880
1953
  this.apiGet("/v1/auth/providers")
1881
1954
  ]);
1882
1955
  this.branding = { ...branding, ...this.config.appearance };
1956
+ this.captchaEnabled = !!branding.captchaEnabled;
1957
+ this.turnstileSiteKey = branding.turnstileSiteKey || "";
1958
+ if (this.captchaEnabled && this.turnstileSiteKey) {
1959
+ this.loadTurnstileScript();
1960
+ }
1883
1961
  this.providers = providersRes.providers;
1884
1962
  this.providerFlowModes = {};
1885
1963
  for (const provider of this.providers) {
@@ -1900,11 +1978,14 @@ var Authon = class {
1900
1978
  theme: this.config.theme,
1901
1979
  containerId: this.config.containerId,
1902
1980
  branding: this.branding || void 0,
1981
+ captchaSiteKey: this.captchaEnabled ? this.turnstileSiteKey : void 0,
1903
1982
  onProviderClick: (provider) => this.startOAuthFlow(provider),
1904
1983
  onEmailSubmit: (email, password, isSignUp) => {
1905
1984
  this.modal?.clearError();
1906
- const promise = isSignUp ? this.signUpWithEmail(email, password) : this.signInWithEmail(email, password);
1985
+ const turnstileToken = this.modal?.getTurnstileToken?.() || void 0;
1986
+ const promise = isSignUp ? this.signUpWithEmail(email, password, { turnstileToken }) : this.signInWithEmail(email, password, turnstileToken);
1907
1987
  promise.then(() => this.modal?.close()).catch((err) => {
1988
+ this.modal?.resetTurnstile?.();
1908
1989
  const msg = err instanceof Error ? err.message : String(err);
1909
1990
  this.modal?.showError(msg || "Authentication failed");
1910
1991
  this.emit("error", err instanceof Error ? err : new Error(msg));