@authon/js 0.1.8 → 0.1.10

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.js CHANGED
@@ -131,6 +131,22 @@ var ModalRenderer = class {
131
131
  this.containerElement.innerHTML = "";
132
132
  }
133
133
  }
134
+ showError(message) {
135
+ if (!this.shadowRoot) return;
136
+ this.clearError();
137
+ const errorEl = this.shadowRoot.getElementById("email-form");
138
+ if (errorEl) {
139
+ const errDiv = document.createElement("div");
140
+ errDiv.id = "authon-error-msg";
141
+ errDiv.className = "error-msg";
142
+ errDiv.textContent = message;
143
+ errorEl.appendChild(errDiv);
144
+ }
145
+ }
146
+ clearError() {
147
+ if (!this.shadowRoot) return;
148
+ this.shadowRoot.getElementById("authon-error-msg")?.remove();
149
+ }
134
150
  showLoading() {
135
151
  if (!this.shadowRoot) return;
136
152
  this.hideLoading();
@@ -296,6 +312,14 @@ var ModalRenderer = class {
296
312
  font-family: var(--authon-font); transition: opacity 0.15s;
297
313
  }
298
314
  .submit-btn:hover { opacity: 0.9; }
315
+ .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }
316
+ .error-msg {
317
+ margin-top: 8px; padding: 8px 12px;
318
+ background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);
319
+ border-radius: calc(var(--authon-radius) * 0.33);
320
+ font-size: 13px; color: #ef4444; text-align: center;
321
+ animation: fadeIn 0.15s ease;
322
+ }
299
323
  .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }
300
324
  .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }
301
325
  .switch-view a:hover { text-decoration: underline; }
@@ -576,11 +600,14 @@ var Authon = class {
576
600
  branding: this.branding || void 0,
577
601
  onProviderClick: (provider) => this.startOAuthFlow(provider),
578
602
  onEmailSubmit: (email, password, isSignUp) => {
579
- if (isSignUp) {
580
- this.signUpWithEmail(email, password).then(() => this.modal?.close());
581
- } else {
582
- this.signInWithEmail(email, password).then(() => this.modal?.close());
583
- }
603
+ this.modal?.clearError();
604
+ const promise = isSignUp ? this.signUpWithEmail(email, password) : this.signInWithEmail(email, password);
605
+ promise.then(() => this.modal?.close()).catch((err) => {
606
+ const msg = err instanceof Error ? err.message : String(err);
607
+ const friendlyMsg = msg.includes("401") ? "Invalid email or password" : msg.includes("409") ? "Email already in use" : msg.includes("400") ? "Please check your input" : msg || "Authentication failed";
608
+ this.modal?.showError(friendlyMsg);
609
+ this.emit("error", err instanceof Error ? err : new Error(msg));
610
+ });
584
611
  },
585
612
  onClose: () => this.modal?.close()
586
613
  });
@@ -606,24 +633,38 @@ var Authon = class {
606
633
  `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`
607
634
  );
608
635
  let callbackReceived = false;
609
- const pollTimer = setInterval(() => {
610
- if (callbackReceived) return;
611
- try {
612
- if (!popup || popup.closed) {
613
- clearInterval(pollTimer);
614
- if (!callbackReceived) {
615
- window.removeEventListener("message", handler);
616
- this.modal?.hideLoading();
617
- }
618
- }
619
- } catch {
620
- }
621
- }, 500);
636
+ let cleaned = false;
637
+ const cleanup = () => {
638
+ if (cleaned) return;
639
+ cleaned = true;
640
+ window.removeEventListener("message", handler);
641
+ window.removeEventListener("focus", focusHandler);
642
+ if (maxTimer) clearTimeout(maxTimer);
643
+ };
644
+ const focusHandler = () => {
645
+ if (callbackReceived || cleaned) return;
646
+ setTimeout(() => {
647
+ if (callbackReceived || cleaned) return;
648
+ cleanup();
649
+ this.modal?.hideLoading();
650
+ }, 1500);
651
+ };
652
+ window.addEventListener("focus", focusHandler);
653
+ const maxTimer = setTimeout(() => {
654
+ if (callbackReceived || cleaned) return;
655
+ cleanup();
656
+ this.modal?.hideLoading();
657
+ }, 18e4);
658
+ if (!popup) {
659
+ cleanup();
660
+ this.modal?.hideLoading();
661
+ this.emit("error", new Error("Popup was blocked by the browser"));
662
+ return;
663
+ }
622
664
  const handler = async (e) => {
623
665
  if (e.data?.type !== "authon-oauth-callback") return;
624
666
  callbackReceived = true;
625
- window.removeEventListener("message", handler);
626
- clearInterval(pollTimer);
667
+ cleanup();
627
668
  try {
628
669
  const tokens = await this.apiPost("/v1/auth/oauth/callback", {
629
670
  code: e.data.code,
package/dist/index.mjs CHANGED
@@ -104,6 +104,22 @@ var ModalRenderer = class {
104
104
  this.containerElement.innerHTML = "";
105
105
  }
106
106
  }
107
+ showError(message) {
108
+ if (!this.shadowRoot) return;
109
+ this.clearError();
110
+ const errorEl = this.shadowRoot.getElementById("email-form");
111
+ if (errorEl) {
112
+ const errDiv = document.createElement("div");
113
+ errDiv.id = "authon-error-msg";
114
+ errDiv.className = "error-msg";
115
+ errDiv.textContent = message;
116
+ errorEl.appendChild(errDiv);
117
+ }
118
+ }
119
+ clearError() {
120
+ if (!this.shadowRoot) return;
121
+ this.shadowRoot.getElementById("authon-error-msg")?.remove();
122
+ }
107
123
  showLoading() {
108
124
  if (!this.shadowRoot) return;
109
125
  this.hideLoading();
@@ -269,6 +285,14 @@ var ModalRenderer = class {
269
285
  font-family: var(--authon-font); transition: opacity 0.15s;
270
286
  }
271
287
  .submit-btn:hover { opacity: 0.9; }
288
+ .submit-btn:disabled { opacity: 0.6; cursor: not-allowed; }
289
+ .error-msg {
290
+ margin-top: 8px; padding: 8px 12px;
291
+ background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);
292
+ border-radius: calc(var(--authon-radius) * 0.33);
293
+ font-size: 13px; color: #ef4444; text-align: center;
294
+ animation: fadeIn 0.15s ease;
295
+ }
272
296
  .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: var(--authon-muted); }
273
297
  .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }
274
298
  .switch-view a:hover { text-decoration: underline; }
@@ -549,11 +573,14 @@ var Authon = class {
549
573
  branding: this.branding || void 0,
550
574
  onProviderClick: (provider) => this.startOAuthFlow(provider),
551
575
  onEmailSubmit: (email, password, isSignUp) => {
552
- if (isSignUp) {
553
- this.signUpWithEmail(email, password).then(() => this.modal?.close());
554
- } else {
555
- this.signInWithEmail(email, password).then(() => this.modal?.close());
556
- }
576
+ this.modal?.clearError();
577
+ const promise = isSignUp ? this.signUpWithEmail(email, password) : this.signInWithEmail(email, password);
578
+ promise.then(() => this.modal?.close()).catch((err) => {
579
+ const msg = err instanceof Error ? err.message : String(err);
580
+ const friendlyMsg = msg.includes("401") ? "Invalid email or password" : msg.includes("409") ? "Email already in use" : msg.includes("400") ? "Please check your input" : msg || "Authentication failed";
581
+ this.modal?.showError(friendlyMsg);
582
+ this.emit("error", err instanceof Error ? err : new Error(msg));
583
+ });
557
584
  },
558
585
  onClose: () => this.modal?.close()
559
586
  });
@@ -579,24 +606,38 @@ var Authon = class {
579
606
  `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`
580
607
  );
581
608
  let callbackReceived = false;
582
- const pollTimer = setInterval(() => {
583
- if (callbackReceived) return;
584
- try {
585
- if (!popup || popup.closed) {
586
- clearInterval(pollTimer);
587
- if (!callbackReceived) {
588
- window.removeEventListener("message", handler);
589
- this.modal?.hideLoading();
590
- }
591
- }
592
- } catch {
593
- }
594
- }, 500);
609
+ let cleaned = false;
610
+ const cleanup = () => {
611
+ if (cleaned) return;
612
+ cleaned = true;
613
+ window.removeEventListener("message", handler);
614
+ window.removeEventListener("focus", focusHandler);
615
+ if (maxTimer) clearTimeout(maxTimer);
616
+ };
617
+ const focusHandler = () => {
618
+ if (callbackReceived || cleaned) return;
619
+ setTimeout(() => {
620
+ if (callbackReceived || cleaned) return;
621
+ cleanup();
622
+ this.modal?.hideLoading();
623
+ }, 1500);
624
+ };
625
+ window.addEventListener("focus", focusHandler);
626
+ const maxTimer = setTimeout(() => {
627
+ if (callbackReceived || cleaned) return;
628
+ cleanup();
629
+ this.modal?.hideLoading();
630
+ }, 18e4);
631
+ if (!popup) {
632
+ cleanup();
633
+ this.modal?.hideLoading();
634
+ this.emit("error", new Error("Popup was blocked by the browser"));
635
+ return;
636
+ }
595
637
  const handler = async (e) => {
596
638
  if (e.data?.type !== "authon-oauth-callback") return;
597
639
  callbackReceived = true;
598
- window.removeEventListener("message", handler);
599
- clearInterval(pollTimer);
640
+ cleanup();
600
641
  try {
601
642
  const tokens = await this.apiPost("/v1/auth/oauth/callback", {
602
643
  code: e.data.code,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@authon/js",
3
- "version": "0.1.8",
3
+ "version": "0.1.10",
4
4
  "description": "Authon core SDK — ShadowDOM login modal for any app",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",