@authon/js 0.1.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.
package/dist/index.js ADDED
@@ -0,0 +1,496 @@
1
+ // src/modal.ts
2
+ import { DEFAULT_BRANDING } from "@authon/shared";
3
+
4
+ // src/providers.ts
5
+ import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES } from "@authon/shared";
6
+ var PROVIDER_ICONS = {
7
+ google: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="#4285F4" d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z"/><path fill="#34A853" d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"/><path fill="#FBBC05" d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"/><path fill="#EA4335" d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"/></svg>`,
8
+ apple: `<svg viewBox="0 0 24 24" width="20" height="20" fill="currentColor"><path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z"/></svg>`,
9
+ kakao: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="#191919" d="M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z"/></svg>`,
10
+ naver: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="#fff" d="M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z"/></svg>`,
11
+ facebook: `<svg viewBox="0 0 24 24" width="20" height="20"><path fill="#fff" d="M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z"/></svg>`,
12
+ github: `<svg viewBox="0 0 24 24" width="20" height="20" fill="#fff"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>`,
13
+ discord: `<svg viewBox="0 0 24 24" width="20" height="20" fill="#fff"><path d="M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z"/></svg>`,
14
+ x: `<svg viewBox="0 0 24 24" width="20" height="20" fill="#fff"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"/></svg>`,
15
+ line: `<svg viewBox="0 0 24 24" width="20" height="20" fill="#fff"><path d="M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314"/></svg>`,
16
+ microsoft: `<svg viewBox="0 0 24 24" width="20" height="20"><rect fill="#F25022" x="1" y="1" width="10" height="10"/><rect fill="#7FBA00" x="13" y="1" width="10" height="10"/><rect fill="#00A4EF" x="1" y="13" width="10" height="10"/><rect fill="#FFB900" x="13" y="13" width="10" height="10"/></svg>`
17
+ };
18
+ function getProviderButtonConfig(provider) {
19
+ const colors = PROVIDER_COLORS[provider];
20
+ return {
21
+ provider,
22
+ label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,
23
+ bgColor: colors.bg,
24
+ textColor: colors.text,
25
+ iconSvg: PROVIDER_ICONS[provider]
26
+ };
27
+ }
28
+
29
+ // src/modal.ts
30
+ var ModalRenderer = class {
31
+ shadowRoot = null;
32
+ hostElement = null;
33
+ containerElement = null;
34
+ mode;
35
+ branding;
36
+ enabledProviders = [];
37
+ onProviderClick;
38
+ onEmailSubmit;
39
+ onClose;
40
+ constructor(options) {
41
+ this.mode = options.mode;
42
+ this.branding = { ...DEFAULT_BRANDING, ...options.branding };
43
+ this.onProviderClick = options.onProviderClick;
44
+ this.onEmailSubmit = options.onEmailSubmit;
45
+ this.onClose = options.onClose;
46
+ if (options.mode === "embedded" && options.containerId) {
47
+ this.containerElement = document.getElementById(options.containerId);
48
+ }
49
+ }
50
+ setProviders(providers) {
51
+ this.enabledProviders = providers;
52
+ }
53
+ setBranding(branding) {
54
+ this.branding = { ...DEFAULT_BRANDING, ...branding };
55
+ }
56
+ open(view = "signIn") {
57
+ this.close();
58
+ this.render(view);
59
+ }
60
+ close() {
61
+ if (this.hostElement) {
62
+ this.hostElement.remove();
63
+ this.hostElement = null;
64
+ this.shadowRoot = null;
65
+ }
66
+ if (this.containerElement) {
67
+ this.containerElement.innerHTML = "";
68
+ }
69
+ }
70
+ render(view) {
71
+ const host = document.createElement("div");
72
+ host.setAttribute("data-authon-modal", "");
73
+ this.hostElement = host;
74
+ if (this.mode === "popup") {
75
+ document.body.appendChild(host);
76
+ } else if (this.containerElement) {
77
+ this.containerElement.appendChild(host);
78
+ }
79
+ this.shadowRoot = host.attachShadow({ mode: "open" });
80
+ this.shadowRoot.innerHTML = this.buildHTML(view);
81
+ this.attachEvents(view);
82
+ }
83
+ buildHTML(view) {
84
+ const b = this.branding;
85
+ const isSignUp = view === "signUp";
86
+ const title = isSignUp ? "Create your account" : "Welcome back";
87
+ const subtitle = isSignUp ? "Already have an account?" : "Don't have an account?";
88
+ const subtitleLink = isSignUp ? "Sign in" : "Sign up";
89
+ const providerButtons = this.enabledProviders.filter((p) => !b.hiddenProviders?.includes(p)).map((p) => {
90
+ const config = getProviderButtonConfig(p);
91
+ return `<button class="provider-btn" data-provider="${p}" style="background:${config.bgColor};color:${config.textColor};border:1px solid ${config.bgColor === "#ffffff" ? "#e5e7eb" : config.bgColor}">
92
+ <span class="provider-icon">${config.iconSvg}</span>
93
+ <span>${config.label}</span>
94
+ </button>`;
95
+ }).join("");
96
+ const divider = b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>or</span></div>` : "";
97
+ const emailForm = b.showEmailPassword !== false ? `<form class="email-form" id="email-form">
98
+ <input type="email" placeholder="Email address" name="email" required class="input" />
99
+ <input type="password" placeholder="Password" name="password" required class="input" />
100
+ <button type="submit" class="submit-btn">${isSignUp ? "Sign up" : "Sign in"}</button>
101
+ </form>` : "";
102
+ const footer = b.termsUrl || b.privacyUrl ? `<div class="footer">
103
+ ${b.termsUrl ? `<a href="${b.termsUrl}" target="_blank">Terms of Service</a>` : ""}
104
+ ${b.termsUrl && b.privacyUrl ? " \xB7 " : ""}
105
+ ${b.privacyUrl ? `<a href="${b.privacyUrl}" target="_blank">Privacy Policy</a>` : ""}
106
+ </div>` : "";
107
+ const popupWrapper = this.mode === "popup" ? `<div class="backdrop" id="backdrop"></div>` : "";
108
+ return `
109
+ <style>${this.buildCSS()}</style>
110
+ ${popupWrapper}
111
+ <div class="modal-container" role="dialog" aria-modal="true">
112
+ ${b.logoDataUrl ? `<img src="${b.logoDataUrl}" alt="Logo" class="logo" />` : ""}
113
+ <h2 class="title">${title}</h2>
114
+ ${b.brandName ? `<p class="brand-name">${b.brandName}</p>` : ""}
115
+ <div class="providers">${providerButtons}</div>
116
+ ${divider}
117
+ ${emailForm}
118
+ <p class="switch-view">${subtitle} <a href="#" id="switch-link">${subtitleLink}</a></p>
119
+ ${footer}
120
+ </div>
121
+ `;
122
+ }
123
+ buildCSS() {
124
+ const b = this.branding;
125
+ return `
126
+ :host {
127
+ --authon-primary-start: ${b.primaryColorStart || "#7c3aed"};
128
+ --authon-primary-end: ${b.primaryColorEnd || "#4f46e5"};
129
+ --authon-light-bg: ${b.lightBg || "#ffffff"};
130
+ --authon-light-text: ${b.lightText || "#111827"};
131
+ --authon-dark-bg: ${b.darkBg || "#0f172a"};
132
+ --authon-dark-text: ${b.darkText || "#f1f5f9"};
133
+ --authon-radius: ${b.borderRadius ?? 12}px;
134
+ --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
135
+ font-family: var(--authon-font);
136
+ color: var(--authon-light-text);
137
+ }
138
+ * { box-sizing: border-box; margin: 0; padding: 0; }
139
+ .backdrop {
140
+ position: fixed; inset: 0; z-index: 99998;
141
+ background: rgba(0,0,0,0.5); backdrop-filter: blur(4px);
142
+ animation: fadeIn 0.2s ease;
143
+ }
144
+ .modal-container {
145
+ ${this.mode === "popup" ? "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;" : ""}
146
+ background: var(--authon-light-bg);
147
+ border-radius: var(--authon-radius);
148
+ padding: 32px;
149
+ width: 400px; max-width: 100%;
150
+ ${this.mode === "popup" ? "box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); animation: slideIn 0.3s ease;" : ""}
151
+ }
152
+ .logo { display: block; margin: 0 auto 16px; max-height: 48px; }
153
+ .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; }
154
+ .brand-name { text-align: center; font-size: 14px; color: #6b7280; margin-bottom: 24px; }
155
+ .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }
156
+ .provider-btn {
157
+ display: flex; align-items: center; gap: 12px;
158
+ width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);
159
+ font-size: 14px; font-weight: 500; cursor: pointer;
160
+ transition: opacity 0.15s, transform 0.1s;
161
+ font-family: var(--authon-font);
162
+ }
163
+ .provider-btn:hover { opacity: 0.9; }
164
+ .provider-btn:active { transform: scale(0.98); }
165
+ .provider-icon { display: flex; align-items: center; flex-shrink: 0; }
166
+ .divider {
167
+ display: flex; align-items: center; gap: 12px;
168
+ margin: 16px 0; color: #9ca3af; font-size: 13px;
169
+ }
170
+ .divider::before, .divider::after {
171
+ content: ''; flex: 1; height: 1px; background: #e5e7eb;
172
+ }
173
+ .email-form { display: flex; flex-direction: column; gap: 10px; }
174
+ .input {
175
+ width: 100%; padding: 10px 14px;
176
+ border: 1px solid #d1d5db; border-radius: calc(var(--authon-radius) * 0.5);
177
+ font-size: 14px; font-family: var(--authon-font);
178
+ outline: none; transition: border-color 0.15s;
179
+ }
180
+ .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.1); }
181
+ .submit-btn {
182
+ width: 100%; padding: 10px;
183
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
184
+ color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);
185
+ font-size: 14px; font-weight: 600; cursor: pointer;
186
+ font-family: var(--authon-font); transition: opacity 0.15s;
187
+ }
188
+ .submit-btn:hover { opacity: 0.9; }
189
+ .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: #6b7280; }
190
+ .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }
191
+ .switch-view a:hover { text-decoration: underline; }
192
+ .footer { text-align: center; margin-top: 16px; font-size: 12px; color: #9ca3af; }
193
+ .footer a { color: #9ca3af; text-decoration: none; }
194
+ .footer a:hover { text-decoration: underline; }
195
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
196
+ @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }
197
+ ${b.customCss || ""}
198
+ `;
199
+ }
200
+ attachEvents(view) {
201
+ if (!this.shadowRoot) return;
202
+ this.shadowRoot.querySelectorAll(".provider-btn").forEach((btn) => {
203
+ btn.addEventListener("click", () => {
204
+ const provider = btn.dataset.provider;
205
+ this.onProviderClick(provider);
206
+ });
207
+ });
208
+ const form = this.shadowRoot.getElementById("email-form");
209
+ if (form) {
210
+ form.addEventListener("submit", (e) => {
211
+ e.preventDefault();
212
+ const formData = new FormData(form);
213
+ this.onEmailSubmit(
214
+ formData.get("email"),
215
+ formData.get("password"),
216
+ view === "signUp"
217
+ );
218
+ });
219
+ }
220
+ const switchLink = this.shadowRoot.getElementById("switch-link");
221
+ if (switchLink) {
222
+ switchLink.addEventListener("click", (e) => {
223
+ e.preventDefault();
224
+ this.open(view === "signIn" ? "signUp" : "signIn");
225
+ });
226
+ }
227
+ const backdrop = this.shadowRoot.getElementById("backdrop");
228
+ if (backdrop) {
229
+ backdrop.addEventListener("click", () => this.onClose());
230
+ }
231
+ if (this.mode === "popup") {
232
+ const handler = (e) => {
233
+ if (e.key === "Escape") {
234
+ this.onClose();
235
+ document.removeEventListener("keydown", handler);
236
+ }
237
+ };
238
+ document.addEventListener("keydown", handler);
239
+ }
240
+ }
241
+ };
242
+
243
+ // src/session.ts
244
+ var SessionManager = class {
245
+ accessToken = null;
246
+ user = null;
247
+ refreshTimer = null;
248
+ apiUrl;
249
+ publishableKey;
250
+ constructor(publishableKey, apiUrl) {
251
+ this.publishableKey = publishableKey;
252
+ this.apiUrl = apiUrl;
253
+ }
254
+ getToken() {
255
+ return this.accessToken;
256
+ }
257
+ getUser() {
258
+ return this.user;
259
+ }
260
+ setSession(tokens) {
261
+ this.accessToken = tokens.accessToken;
262
+ this.user = tokens.user;
263
+ this.scheduleRefresh(tokens.expiresIn);
264
+ }
265
+ clearSession() {
266
+ this.accessToken = null;
267
+ this.user = null;
268
+ if (this.refreshTimer) {
269
+ clearTimeout(this.refreshTimer);
270
+ this.refreshTimer = null;
271
+ }
272
+ }
273
+ scheduleRefresh(expiresIn) {
274
+ if (this.refreshTimer) clearTimeout(this.refreshTimer);
275
+ const refreshIn = Math.max((expiresIn - 60) * 1e3, 5e3);
276
+ this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);
277
+ }
278
+ async refresh() {
279
+ try {
280
+ const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {
281
+ method: "POST",
282
+ headers: {
283
+ "Content-Type": "application/json",
284
+ "x-api-key": this.publishableKey
285
+ },
286
+ credentials: "include"
287
+ });
288
+ if (!res.ok) {
289
+ this.clearSession();
290
+ return null;
291
+ }
292
+ const tokens = await res.json();
293
+ this.setSession(tokens);
294
+ return tokens;
295
+ } catch {
296
+ this.clearSession();
297
+ return null;
298
+ }
299
+ }
300
+ async signOut() {
301
+ try {
302
+ await fetch(`${this.apiUrl}/v1/auth/signout`, {
303
+ method: "POST",
304
+ headers: {
305
+ "Content-Type": "application/json",
306
+ "x-api-key": this.publishableKey,
307
+ ...this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}
308
+ },
309
+ credentials: "include"
310
+ });
311
+ } catch {
312
+ }
313
+ this.clearSession();
314
+ }
315
+ destroy() {
316
+ this.clearSession();
317
+ }
318
+ };
319
+
320
+ // src/authon.ts
321
+ var Authon = class {
322
+ publishableKey;
323
+ config;
324
+ session;
325
+ modal = null;
326
+ listeners = /* @__PURE__ */ new Map();
327
+ branding = null;
328
+ providers = [];
329
+ initialized = false;
330
+ constructor(publishableKey, config) {
331
+ this.publishableKey = publishableKey;
332
+ this.config = {
333
+ apiUrl: config?.apiUrl || "https://api.authon.dev",
334
+ mode: config?.mode || "popup",
335
+ theme: config?.theme || "auto",
336
+ locale: config?.locale || "en",
337
+ containerId: config?.containerId,
338
+ appearance: config?.appearance
339
+ };
340
+ this.session = new SessionManager(publishableKey, this.config.apiUrl);
341
+ }
342
+ // ── Public API ──
343
+ async openSignIn() {
344
+ await this.ensureInitialized();
345
+ this.getModal().open("signIn");
346
+ }
347
+ async openSignUp() {
348
+ await this.ensureInitialized();
349
+ this.getModal().open("signUp");
350
+ }
351
+ async signInWithOAuth(provider) {
352
+ await this.ensureInitialized();
353
+ await this.startOAuthFlow(provider);
354
+ }
355
+ async signInWithEmail(email, password) {
356
+ const tokens = await this.apiPost("/v1/auth/signin", { email, password });
357
+ this.session.setSession(tokens);
358
+ this.emit("signedIn", tokens.user);
359
+ return tokens.user;
360
+ }
361
+ async signUpWithEmail(email, password, meta) {
362
+ const tokens = await this.apiPost("/v1/auth/signup", {
363
+ email,
364
+ password,
365
+ ...meta
366
+ });
367
+ this.session.setSession(tokens);
368
+ this.emit("signedIn", tokens.user);
369
+ return tokens.user;
370
+ }
371
+ async signOut() {
372
+ await this.session.signOut();
373
+ this.emit("signedOut");
374
+ }
375
+ getUser() {
376
+ return this.session.getUser();
377
+ }
378
+ getToken() {
379
+ return this.session.getToken();
380
+ }
381
+ on(event, listener) {
382
+ if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
383
+ const set = this.listeners.get(event);
384
+ set.add(listener);
385
+ return () => set.delete(listener);
386
+ }
387
+ destroy() {
388
+ this.modal?.close();
389
+ this.session.destroy();
390
+ this.listeners.clear();
391
+ }
392
+ // ── Internal ──
393
+ emit(event, ...args) {
394
+ this.listeners.get(event)?.forEach((fn) => fn(...args));
395
+ }
396
+ async ensureInitialized() {
397
+ if (this.initialized) return;
398
+ try {
399
+ const [branding, providers] = await Promise.all([
400
+ this.apiGet("/v1/auth/branding"),
401
+ this.apiGet("/v1/auth/providers")
402
+ ]);
403
+ this.branding = { ...branding, ...this.config.appearance };
404
+ this.providers = providers.providers;
405
+ this.initialized = true;
406
+ } catch (err) {
407
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
408
+ throw err;
409
+ }
410
+ }
411
+ getModal() {
412
+ if (!this.modal) {
413
+ this.modal = new ModalRenderer({
414
+ mode: this.config.mode,
415
+ containerId: this.config.containerId,
416
+ branding: this.branding || void 0,
417
+ onProviderClick: (provider) => this.startOAuthFlow(provider),
418
+ onEmailSubmit: (email, password, isSignUp) => {
419
+ if (isSignUp) {
420
+ this.signUpWithEmail(email, password).then(() => this.modal?.close());
421
+ } else {
422
+ this.signInWithEmail(email, password).then(() => this.modal?.close());
423
+ }
424
+ },
425
+ onClose: () => this.modal?.close()
426
+ });
427
+ }
428
+ if (this.branding) this.modal.setBranding(this.branding);
429
+ this.modal.setProviders(this.providers);
430
+ return this.modal;
431
+ }
432
+ async startOAuthFlow(provider) {
433
+ try {
434
+ const { url } = await this.apiGet(
435
+ `/v1/auth/oauth/${provider}/url`
436
+ );
437
+ const width = 500;
438
+ const height = 700;
439
+ const left = window.screenX + (window.outerWidth - width) / 2;
440
+ const top = window.screenY + (window.outerHeight - height) / 2;
441
+ const popup = window.open(
442
+ url,
443
+ "authon-oauth",
444
+ `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`
445
+ );
446
+ const handler = async (e) => {
447
+ if (e.data?.type === "authon-oauth-callback") {
448
+ window.removeEventListener("message", handler);
449
+ popup?.close();
450
+ try {
451
+ const tokens = await this.apiPost("/v1/auth/oauth/callback", {
452
+ code: e.data.code,
453
+ state: e.data.state,
454
+ codeVerifier: e.data.codeVerifier,
455
+ provider
456
+ });
457
+ this.session.setSession(tokens);
458
+ this.modal?.close();
459
+ this.emit("signedIn", tokens.user);
460
+ } catch (err) {
461
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
462
+ }
463
+ }
464
+ };
465
+ window.addEventListener("message", handler);
466
+ } catch (err) {
467
+ this.emit("error", err instanceof Error ? err : new Error(String(err)));
468
+ }
469
+ }
470
+ async apiGet(path) {
471
+ const res = await fetch(`${this.config.apiUrl}${path}`, {
472
+ headers: { "x-api-key": this.publishableKey },
473
+ credentials: "include"
474
+ });
475
+ if (!res.ok) throw new Error(`API ${path}: ${res.status}`);
476
+ return res.json();
477
+ }
478
+ async apiPost(path, body) {
479
+ const res = await fetch(`${this.config.apiUrl}${path}`, {
480
+ method: "POST",
481
+ headers: {
482
+ "Content-Type": "application/json",
483
+ "x-api-key": this.publishableKey
484
+ },
485
+ credentials: "include",
486
+ body: body ? JSON.stringify(body) : void 0
487
+ });
488
+ if (!res.ok) throw new Error(`API ${path}: ${res.status}`);
489
+ return res.json();
490
+ }
491
+ };
492
+ export {
493
+ Authon,
494
+ getProviderButtonConfig
495
+ };
496
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/modal.ts","../src/providers.ts","../src/session.ts","../src/authon.ts"],"sourcesContent":["import type { BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport { DEFAULT_BRANDING } from '@authon/shared';\nimport { getProviderButtonConfig } from './providers';\n\nexport class ModalRenderer {\n private shadowRoot: ShadowRoot | null = null;\n private hostElement: HTMLDivElement | null = null;\n private containerElement: HTMLElement | null = null;\n private mode: 'popup' | 'embedded';\n private branding: BrandingConfig;\n private enabledProviders: OAuthProviderType[] = [];\n private onProviderClick: (provider: OAuthProviderType) => void;\n private onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n private onClose: () => void;\n\n constructor(options: {\n mode: 'popup' | 'embedded';\n containerId?: string;\n branding?: BrandingConfig;\n onProviderClick: (provider: OAuthProviderType) => void;\n onEmailSubmit: (email: string, password: string, isSignUp: boolean) => void;\n onClose: () => void;\n }) {\n this.mode = options.mode;\n this.branding = { ...DEFAULT_BRANDING, ...options.branding };\n this.onProviderClick = options.onProviderClick;\n this.onEmailSubmit = options.onEmailSubmit;\n this.onClose = options.onClose;\n\n if (options.mode === 'embedded' && options.containerId) {\n this.containerElement = document.getElementById(options.containerId);\n }\n }\n\n setProviders(providers: OAuthProviderType[]): void {\n this.enabledProviders = providers;\n }\n\n setBranding(branding: BrandingConfig): void {\n this.branding = { ...DEFAULT_BRANDING, ...branding };\n }\n\n open(view: 'signIn' | 'signUp' = 'signIn'): void {\n this.close();\n this.render(view);\n }\n\n close(): void {\n if (this.hostElement) {\n this.hostElement.remove();\n this.hostElement = null;\n this.shadowRoot = null;\n }\n if (this.containerElement) {\n this.containerElement.innerHTML = '';\n }\n }\n\n private render(view: 'signIn' | 'signUp'): void {\n const host = document.createElement('div');\n host.setAttribute('data-authon-modal', '');\n this.hostElement = host;\n\n if (this.mode === 'popup') {\n document.body.appendChild(host);\n } else if (this.containerElement) {\n this.containerElement.appendChild(host);\n }\n\n this.shadowRoot = host.attachShadow({ mode: 'open' });\n this.shadowRoot.innerHTML = this.buildHTML(view);\n this.attachEvents(view);\n }\n\n private buildHTML(view: 'signIn' | 'signUp'): string {\n const b = this.branding;\n const isSignUp = view === 'signUp';\n const title = isSignUp ? 'Create your account' : 'Welcome back';\n const subtitle = isSignUp ? 'Already have an account?' : \"Don't have an account?\";\n const subtitleLink = isSignUp ? 'Sign in' : 'Sign up';\n\n const providerButtons = this.enabledProviders\n .filter((p) => !b.hiddenProviders?.includes(p))\n .map((p) => {\n const config = getProviderButtonConfig(p);\n return `<button class=\"provider-btn\" data-provider=\"${p}\" style=\"background:${config.bgColor};color:${config.textColor};border:1px solid ${config.bgColor === '#ffffff' ? '#e5e7eb' : config.bgColor}\">\n <span class=\"provider-icon\">${config.iconSvg}</span>\n <span>${config.label}</span>\n </button>`;\n })\n .join('');\n\n const divider =\n b.showDivider !== false && b.showEmailPassword !== false\n ? `<div class=\"divider\"><span>or</span></div>`\n : '';\n\n const emailForm =\n b.showEmailPassword !== false\n ? `<form class=\"email-form\" id=\"email-form\">\n <input type=\"email\" placeholder=\"Email address\" name=\"email\" required class=\"input\" />\n <input type=\"password\" placeholder=\"Password\" name=\"password\" required class=\"input\" />\n <button type=\"submit\" class=\"submit-btn\">${isSignUp ? 'Sign up' : 'Sign in'}</button>\n </form>`\n : '';\n\n const footer =\n b.termsUrl || b.privacyUrl\n ? `<div class=\"footer\">\n ${b.termsUrl ? `<a href=\"${b.termsUrl}\" target=\"_blank\">Terms of Service</a>` : ''}\n ${b.termsUrl && b.privacyUrl ? ' · ' : ''}\n ${b.privacyUrl ? `<a href=\"${b.privacyUrl}\" target=\"_blank\">Privacy Policy</a>` : ''}\n </div>`\n : '';\n\n const popupWrapper =\n this.mode === 'popup'\n ? `<div class=\"backdrop\" id=\"backdrop\"></div>`\n : '';\n\n return `\n <style>${this.buildCSS()}</style>\n ${popupWrapper}\n <div class=\"modal-container\" role=\"dialog\" aria-modal=\"true\">\n ${b.logoDataUrl ? `<img src=\"${b.logoDataUrl}\" alt=\"Logo\" class=\"logo\" />` : ''}\n <h2 class=\"title\">${title}</h2>\n ${b.brandName ? `<p class=\"brand-name\">${b.brandName}</p>` : ''}\n <div class=\"providers\">${providerButtons}</div>\n ${divider}\n ${emailForm}\n <p class=\"switch-view\">${subtitle} <a href=\"#\" id=\"switch-link\">${subtitleLink}</a></p>\n ${footer}\n </div>\n `;\n }\n\n private buildCSS(): string {\n const b = this.branding;\n return `\n :host {\n --authon-primary-start: ${b.primaryColorStart || '#7c3aed'};\n --authon-primary-end: ${b.primaryColorEnd || '#4f46e5'};\n --authon-light-bg: ${b.lightBg || '#ffffff'};\n --authon-light-text: ${b.lightText || '#111827'};\n --authon-dark-bg: ${b.darkBg || '#0f172a'};\n --authon-dark-text: ${b.darkText || '#f1f5f9'};\n --authon-radius: ${b.borderRadius ?? 12}px;\n --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;\n font-family: var(--authon-font);\n color: var(--authon-light-text);\n }\n * { box-sizing: border-box; margin: 0; padding: 0; }\n .backdrop {\n position: fixed; inset: 0; z-index: 99998;\n background: rgba(0,0,0,0.5); backdrop-filter: blur(4px);\n animation: fadeIn 0.2s ease;\n }\n .modal-container {\n ${this.mode === 'popup' ? 'position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;' : ''}\n background: var(--authon-light-bg);\n border-radius: var(--authon-radius);\n padding: 32px;\n width: 400px; max-width: 100%;\n ${this.mode === 'popup' ? 'box-shadow: 0 25px 50px -12px rgba(0,0,0,0.25); animation: slideIn 0.3s ease;' : ''}\n }\n .logo { display: block; margin: 0 auto 16px; max-height: 48px; }\n .title { text-align: center; font-size: 24px; font-weight: 700; margin-bottom: 8px; }\n .brand-name { text-align: center; font-size: 14px; color: #6b7280; margin-bottom: 24px; }\n .providers { display: flex; flex-direction: column; gap: 8px; margin-bottom: 16px; }\n .provider-btn {\n display: flex; align-items: center; gap: 12px;\n width: 100%; padding: 10px 16px; border-radius: calc(var(--authon-radius) * 0.67);\n font-size: 14px; font-weight: 500; cursor: pointer;\n transition: opacity 0.15s, transform 0.1s;\n font-family: var(--authon-font);\n }\n .provider-btn:hover { opacity: 0.9; }\n .provider-btn:active { transform: scale(0.98); }\n .provider-icon { display: flex; align-items: center; flex-shrink: 0; }\n .divider {\n display: flex; align-items: center; gap: 12px;\n margin: 16px 0; color: #9ca3af; font-size: 13px;\n }\n .divider::before, .divider::after {\n content: ''; flex: 1; height: 1px; background: #e5e7eb;\n }\n .email-form { display: flex; flex-direction: column; gap: 10px; }\n .input {\n width: 100%; padding: 10px 14px;\n border: 1px solid #d1d5db; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-family: var(--authon-font);\n outline: none; transition: border-color 0.15s;\n }\n .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px rgba(124,58,237,0.1); }\n .submit-btn {\n width: 100%; padding: 10px;\n background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));\n color: #fff; border: none; border-radius: calc(var(--authon-radius) * 0.5);\n font-size: 14px; font-weight: 600; cursor: pointer;\n font-family: var(--authon-font); transition: opacity 0.15s;\n }\n .submit-btn:hover { opacity: 0.9; }\n .switch-view { text-align: center; margin-top: 16px; font-size: 13px; color: #6b7280; }\n .switch-view a { color: var(--authon-primary-start); text-decoration: none; font-weight: 500; }\n .switch-view a:hover { text-decoration: underline; }\n .footer { text-align: center; margin-top: 16px; font-size: 12px; color: #9ca3af; }\n .footer a { color: #9ca3af; text-decoration: none; }\n .footer a:hover { text-decoration: underline; }\n @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }\n @keyframes slideIn { from { opacity: 0; transform: translate(-50%, -48%); } to { opacity: 1; transform: translate(-50%, -50%); } }\n ${b.customCss || ''}\n `;\n }\n\n private attachEvents(view: 'signIn' | 'signUp'): void {\n if (!this.shadowRoot) return;\n\n this.shadowRoot.querySelectorAll('.provider-btn').forEach((btn) => {\n btn.addEventListener('click', () => {\n const provider = (btn as HTMLElement).dataset.provider as OAuthProviderType;\n this.onProviderClick(provider);\n });\n });\n\n const form = this.shadowRoot.getElementById('email-form') as HTMLFormElement | null;\n if (form) {\n form.addEventListener('submit', (e) => {\n e.preventDefault();\n const formData = new FormData(form);\n this.onEmailSubmit(\n formData.get('email') as string,\n formData.get('password') as string,\n view === 'signUp',\n );\n });\n }\n\n const switchLink = this.shadowRoot.getElementById('switch-link');\n if (switchLink) {\n switchLink.addEventListener('click', (e) => {\n e.preventDefault();\n this.open(view === 'signIn' ? 'signUp' : 'signIn');\n });\n }\n\n const backdrop = this.shadowRoot.getElementById('backdrop');\n if (backdrop) {\n backdrop.addEventListener('click', () => this.onClose());\n }\n\n if (this.mode === 'popup') {\n const handler = (e: KeyboardEvent) => {\n if (e.key === 'Escape') {\n this.onClose();\n document.removeEventListener('keydown', handler);\n }\n };\n document.addEventListener('keydown', handler);\n }\n }\n}\n","import { PROVIDER_COLORS, PROVIDER_DISPLAY_NAMES, type OAuthProviderType } from '@authon/shared';\n\nexport interface ProviderButtonConfig {\n provider: OAuthProviderType;\n label: string;\n bgColor: string;\n textColor: string;\n iconSvg: string;\n}\n\nconst PROVIDER_ICONS: Record<OAuthProviderType, string> = {\n google: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#4285F4\" d=\"M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 01-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z\"/><path fill=\"#34A853\" d=\"M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z\"/><path fill=\"#FBBC05\" d=\"M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z\"/><path fill=\"#EA4335\" d=\"M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z\"/></svg>`,\n apple: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"currentColor\"><path d=\"M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.29 2.58-2.34 4.5-3.74 4.25z\"/></svg>`,\n kakao: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#191919\" d=\"M12 3C6.48 3 2 6.36 2 10.43c0 2.62 1.75 4.93 4.37 6.23l-1.12 4.14c-.1.36.31.65.62.44l4.93-3.26c.39.04.79.06 1.2.06 5.52 0 10-3.36 10-7.61C22 6.36 17.52 3 12 3z\"/></svg>`,\n naver: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M16.27 3H7.73A4.73 4.73 0 003 7.73v8.54A4.73 4.73 0 007.73 21h8.54A4.73 4.73 0 0021 16.27V7.73A4.73 4.73 0 0016.27 3zm-1.84 12.44h-2.1l-2.86-4.15v4.15H7.38V8.56h2.1l2.86 4.15V8.56h2.09v6.88z\"/></svg>`,\n facebook: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><path fill=\"#fff\" d=\"M24 12.07C24 5.41 18.63 0 12 0S0 5.4 0 12.07C0 18.1 4.39 23.1 10.13 24v-8.44H7.08v-3.49h3.04V9.41c0-3.02 1.8-4.7 4.54-4.7 1.31 0 2.68.24 2.68.24v2.97h-1.5c-1.5 0-1.96.93-1.96 1.89v2.26h3.33l-.53 3.49h-2.8V24C19.62 23.1 24 18.1 24 12.07z\"/></svg>`,\n github: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z\"/></svg>`,\n discord: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M20.32 4.37a19.8 19.8 0 00-4.89-1.52.07.07 0 00-.08.04c-.21.38-.44.87-.61 1.26a18.27 18.27 0 00-5.49 0 12.64 12.64 0 00-.62-1.26.07.07 0 00-.08-.04 19.74 19.74 0 00-4.89 1.52.07.07 0 00-.03.03C1.11 8.39.34 12.28.73 16.12a.08.08 0 00.03.06 19.9 19.9 0 005.99 3.03.08.08 0 00.08-.03c.46-.63.87-1.3 1.22-2a.08.08 0 00-.04-.11 13.1 13.1 0 01-1.87-.9.08.08 0 01-.01-.13c.13-.09.25-.19.37-.29a.07.07 0 01.08-.01c3.93 1.8 8.18 1.8 12.07 0a.07.07 0 01.08 0c.12.1.25.2.37.3a.08.08 0 01-.01.12c-.6.35-1.22.65-1.87.9a.08.08 0 00-.04.1c.36.7.77 1.37 1.22 2a.08.08 0 00.08.03 19.83 19.83 0 006-3.03.08.08 0 00.03-.05c.47-4.87-.78-9.09-3.3-12.84a.06.06 0 00-.03-.03zM8.02 13.62c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.9 2.28-2.03 2.28zm7.5 0c-1.11 0-2.03-1.02-2.03-2.28 0-1.26.9-2.28 2.03-2.28 1.14 0 2.04 1.03 2.03 2.28 0 1.26-.89 2.28-2.03 2.28z\"/></svg>`,\n x: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z\"/></svg>`,\n line: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\" fill=\"#fff\"><path d=\"M19.365 9.863c.349 0 .63.285.63.631 0 .345-.281.63-.63.63H17.61v1.125h1.755c.349 0 .63.283.63.63 0 .344-.281.629-.63.629h-2.386c-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63h2.386c.346 0 .627.285.627.63 0 .349-.281.63-.63.63H17.61v1.125h1.755zm-3.855 3.016c0 .27-.174.51-.432.596-.064.021-.133.031-.199.031-.211 0-.391-.09-.51-.25l-2.443-3.317v2.94c0 .344-.279.629-.631.629-.346 0-.626-.285-.626-.629V8.108c0-.27.173-.51.43-.595.06-.023.136-.033.194-.033.195 0 .375.104.495.254l2.462 3.33V8.108c0-.345.282-.63.63-.63.345 0 .63.285.63.63v4.771zm-5.741 0c0 .344-.282.629-.631.629-.345 0-.627-.285-.627-.629V8.108c0-.345.282-.63.63-.63.346 0 .628.285.628.63v4.771zm-2.466.629H4.917c-.345 0-.63-.285-.63-.629V8.108c0-.345.285-.63.63-.63.348 0 .63.285.63.63v4.141h1.756c.348 0 .629.283.629.63 0 .344-.282.629-.629.629M24 10.314C24 4.943 18.615.572 12 .572S0 4.943 0 10.314c0 4.811 4.27 8.842 10.035 9.608.391.082.923.258 1.058.59.12.301.079.766.038 1.08l-.164 1.02c-.045.301-.24 1.186 1.049.645 1.291-.539 6.916-4.078 9.436-6.975C23.176 14.393 24 12.458 24 10.314\"/></svg>`,\n microsoft: `<svg viewBox=\"0 0 24 24\" width=\"20\" height=\"20\"><rect fill=\"#F25022\" x=\"1\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#7FBA00\" x=\"13\" y=\"1\" width=\"10\" height=\"10\"/><rect fill=\"#00A4EF\" x=\"1\" y=\"13\" width=\"10\" height=\"10\"/><rect fill=\"#FFB900\" x=\"13\" y=\"13\" width=\"10\" height=\"10\"/></svg>`,\n};\n\nexport function getProviderButtonConfig(provider: OAuthProviderType): ProviderButtonConfig {\n const colors = PROVIDER_COLORS[provider];\n return {\n provider,\n label: `Continue with ${PROVIDER_DISPLAY_NAMES[provider]}`,\n bgColor: colors.bg,\n textColor: colors.text,\n iconSvg: PROVIDER_ICONS[provider],\n };\n}\n","import type { AuthonUser, AuthTokens } from '@authon/shared';\n\nexport class SessionManager {\n private accessToken: string | null = null;\n private user: AuthonUser | null = null;\n private refreshTimer: ReturnType<typeof setTimeout> | null = null;\n private apiUrl: string;\n private publishableKey: string;\n\n constructor(publishableKey: string, apiUrl: string) {\n this.publishableKey = publishableKey;\n this.apiUrl = apiUrl;\n }\n\n getToken(): string | null {\n return this.accessToken;\n }\n\n getUser(): AuthonUser | null {\n return this.user;\n }\n\n setSession(tokens: AuthTokens): void {\n this.accessToken = tokens.accessToken;\n this.user = tokens.user;\n this.scheduleRefresh(tokens.expiresIn);\n }\n\n clearSession(): void {\n this.accessToken = null;\n this.user = null;\n if (this.refreshTimer) {\n clearTimeout(this.refreshTimer);\n this.refreshTimer = null;\n }\n }\n\n private scheduleRefresh(expiresIn: number): void {\n if (this.refreshTimer) clearTimeout(this.refreshTimer);\n const refreshIn = Math.max((expiresIn - 60) * 1000, 5000);\n this.refreshTimer = setTimeout(() => this.refresh(), refreshIn);\n }\n\n async refresh(): Promise<AuthTokens | null> {\n try {\n const res = await fetch(`${this.apiUrl}/v1/auth/token/refresh`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n });\n if (!res.ok) {\n this.clearSession();\n return null;\n }\n const tokens: AuthTokens = await res.json();\n this.setSession(tokens);\n return tokens;\n } catch {\n this.clearSession();\n return null;\n }\n }\n\n async signOut(): Promise<void> {\n try {\n await fetch(`${this.apiUrl}/v1/auth/signout`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n ...(this.accessToken ? { Authorization: `Bearer ${this.accessToken}` } : {}),\n },\n credentials: 'include',\n });\n } catch {\n // ignore\n }\n this.clearSession();\n }\n\n destroy(): void {\n this.clearSession();\n }\n}\n","import type { AuthonUser, AuthTokens, BrandingConfig, OAuthProviderType } from '@authon/shared';\nimport type { AuthonConfig, AuthonEventType, AuthonEvents } from './types';\nimport { ModalRenderer } from './modal';\nimport { SessionManager } from './session';\n\nexport class Authon {\n private publishableKey: string;\n private config: Required<Omit<AuthonConfig, 'containerId' | 'appearance'>> & {\n containerId?: string;\n appearance?: Partial<BrandingConfig>;\n };\n private session: SessionManager;\n private modal: ModalRenderer | null = null;\n private listeners: Map<string, Set<(...args: unknown[]) => void>> = new Map();\n private branding: BrandingConfig | null = null;\n private providers: OAuthProviderType[] = [];\n private initialized = false;\n\n constructor(publishableKey: string, config?: AuthonConfig) {\n this.publishableKey = publishableKey;\n this.config = {\n apiUrl: config?.apiUrl || 'https://api.authon.dev',\n mode: config?.mode || 'popup',\n theme: config?.theme || 'auto',\n locale: config?.locale || 'en',\n containerId: config?.containerId,\n appearance: config?.appearance,\n };\n this.session = new SessionManager(publishableKey, this.config.apiUrl);\n }\n\n // ── Public API ──\n\n async openSignIn(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signIn');\n }\n\n async openSignUp(): Promise<void> {\n await this.ensureInitialized();\n this.getModal().open('signUp');\n }\n\n async signInWithOAuth(provider: OAuthProviderType): Promise<void> {\n await this.ensureInitialized();\n await this.startOAuthFlow(provider);\n }\n\n async signInWithEmail(email: string, password: string): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signin', { email, password });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signUpWithEmail(\n email: string,\n password: string,\n meta?: { displayName?: string },\n ): Promise<AuthonUser> {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/signup', {\n email,\n password,\n ...meta,\n });\n this.session.setSession(tokens);\n this.emit('signedIn', tokens.user);\n return tokens.user;\n }\n\n async signOut(): Promise<void> {\n await this.session.signOut();\n this.emit('signedOut');\n }\n\n getUser(): AuthonUser | null {\n return this.session.getUser();\n }\n\n getToken(): string | null {\n return this.session.getToken();\n }\n\n on<K extends AuthonEventType>(event: K, listener: AuthonEvents[K]): () => void {\n if (!this.listeners.has(event)) this.listeners.set(event, new Set());\n const set = this.listeners.get(event)!;\n set.add(listener as (...args: unknown[]) => void);\n return () => set.delete(listener as (...args: unknown[]) => void);\n }\n\n destroy(): void {\n this.modal?.close();\n this.session.destroy();\n this.listeners.clear();\n }\n\n // ── Internal ──\n\n private emit(event: string, ...args: unknown[]): void {\n this.listeners.get(event)?.forEach((fn) => fn(...args));\n }\n\n private async ensureInitialized(): Promise<void> {\n if (this.initialized) return;\n try {\n const [branding, providers] = await Promise.all([\n this.apiGet<BrandingConfig>('/v1/auth/branding'),\n this.apiGet<{ providers: OAuthProviderType[] }>('/v1/auth/providers'),\n ]);\n this.branding = { ...branding, ...this.config.appearance };\n this.providers = providers.providers;\n this.initialized = true;\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n throw err;\n }\n }\n\n private getModal(): ModalRenderer {\n if (!this.modal) {\n this.modal = new ModalRenderer({\n mode: this.config.mode,\n containerId: this.config.containerId,\n branding: this.branding || undefined,\n onProviderClick: (provider) => this.startOAuthFlow(provider),\n onEmailSubmit: (email, password, isSignUp) => {\n if (isSignUp) {\n this.signUpWithEmail(email, password).then(() => this.modal?.close());\n } else {\n this.signInWithEmail(email, password).then(() => this.modal?.close());\n }\n },\n onClose: () => this.modal?.close(),\n });\n }\n if (this.branding) this.modal.setBranding(this.branding);\n this.modal.setProviders(this.providers);\n return this.modal;\n }\n\n private async startOAuthFlow(provider: OAuthProviderType): Promise<void> {\n try {\n const { url } = await this.apiGet<{ url: string }>(\n `/v1/auth/oauth/${provider}/url`,\n );\n const width = 500;\n const height = 700;\n const left = window.screenX + (window.outerWidth - width) / 2;\n const top = window.screenY + (window.outerHeight - height) / 2;\n const popup = window.open(\n url,\n 'authon-oauth',\n `width=${width},height=${height},left=${left},top=${top},toolbar=no,menubar=no`,\n );\n\n const handler = async (e: MessageEvent) => {\n if (e.data?.type === 'authon-oauth-callback') {\n window.removeEventListener('message', handler);\n popup?.close();\n try {\n const tokens = await this.apiPost<AuthTokens>('/v1/auth/oauth/callback', {\n code: e.data.code,\n state: e.data.state,\n codeVerifier: e.data.codeVerifier,\n provider,\n });\n this.session.setSession(tokens);\n this.modal?.close();\n this.emit('signedIn', tokens.user);\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n };\n window.addEventListener('message', handler);\n } catch (err) {\n this.emit('error', err instanceof Error ? err : new Error(String(err)));\n }\n }\n\n private async apiGet<T>(path: string): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n headers: { 'x-api-key': this.publishableKey },\n credentials: 'include',\n });\n if (!res.ok) throw new Error(`API ${path}: ${res.status}`);\n return res.json();\n }\n\n private async apiPost<T>(path: string, body?: unknown): Promise<T> {\n const res = await fetch(`${this.config.apiUrl}${path}`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.publishableKey,\n },\n credentials: 'include',\n body: body ? JSON.stringify(body) : undefined,\n });\n if (!res.ok) throw new Error(`API ${path}: ${res.status}`);\n return res.json();\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,39 @@
1
+ {
2
+ "name": "@authon/js",
3
+ "version": "0.1.0",
4
+ "description": "Authon core browser SDK — ShadowDOM login modal, OAuth, session management",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.cjs"
14
+ }
15
+ },
16
+ "files": ["dist"],
17
+ "scripts": {
18
+ "build": "tsup",
19
+ "dev": "tsup --watch"
20
+ },
21
+ "license": "MIT",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "https://github.com/mikusnuz/authon-sdk.git",
25
+ "directory": "packages/js"
26
+ },
27
+ "homepage": "https://github.com/mikusnuz/authon-sdk/tree/main/packages/js",
28
+ "publishConfig": {
29
+ "access": "public"
30
+ },
31
+ "keywords": ["authon", "auth", "authentication", "login", "oauth", "sdk"],
32
+ "dependencies": {
33
+ "@authon/shared": "workspace:*"
34
+ },
35
+ "devDependencies": {
36
+ "tsup": "^8.0.0",
37
+ "typescript": "^5.9.3"
38
+ }
39
+ }