@authon/js 0.5.0 → 0.7.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 CHANGED
@@ -89,7 +89,13 @@ var translations = {
89
89
  magicLink: "Continue with Magic Link",
90
90
  passkey: "Sign in with Passkey",
91
91
  securedBy: "Secured by",
92
- backToSignIn: "Back to sign in"
92
+ backToSignIn: "Back to sign in",
93
+ profile: "Profile",
94
+ editProfile: "Edit Profile",
95
+ displayName: "Display Name",
96
+ save: "Save",
97
+ signOut: "Sign Out",
98
+ sessions: "Active Sessions"
93
99
  },
94
100
  ko: {
95
101
  welcomeBack: "\uB2E4\uC2DC \uC624\uC2E0 \uAC78 \uD658\uC601\uD569\uB2C8\uB2E4",
@@ -107,7 +113,13 @@ var translations = {
107
113
  magicLink: "\uB9E4\uC9C1 \uB9C1\uD06C\uB85C \uACC4\uC18D\uD558\uAE30",
108
114
  passkey: "\uD328\uC2A4\uD0A4\uB85C \uB85C\uADF8\uC778",
109
115
  securedBy: "\uBCF4\uC548 \uC81C\uACF5",
110
- backToSignIn: "\uB85C\uADF8\uC778\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30"
116
+ backToSignIn: "\uB85C\uADF8\uC778\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30",
117
+ profile: "\uD504\uB85C\uD544",
118
+ editProfile: "\uD504\uB85C\uD544 \uD3B8\uC9D1",
119
+ displayName: "\uD45C\uC2DC \uC774\uB984",
120
+ save: "\uC800\uC7A5",
121
+ signOut: "\uB85C\uADF8\uC544\uC6C3",
122
+ sessions: "\uD65C\uC131 \uC138\uC158"
111
123
  },
112
124
  ja: {
113
125
  welcomeBack: "\u304A\u304B\u3048\u308A\u306A\u3055\u3044",
@@ -125,7 +137,13 @@ var translations = {
125
137
  magicLink: "\u30DE\u30B8\u30C3\u30AF\u30EA\u30F3\u30AF\u3067\u7D9A\u884C",
126
138
  passkey: "\u30D1\u30B9\u30AD\u30FC\u3067\u30ED\u30B0\u30A4\u30F3",
127
139
  securedBy: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u63D0\u4F9B",
128
- backToSignIn: "\u30ED\u30B0\u30A4\u30F3\u306B\u623B\u308B"
140
+ backToSignIn: "\u30ED\u30B0\u30A4\u30F3\u306B\u623B\u308B",
141
+ profile: "\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB",
142
+ editProfile: "\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u7DE8\u96C6",
143
+ displayName: "\u8868\u793A\u540D",
144
+ save: "\u4FDD\u5B58",
145
+ signOut: "\u30B5\u30A4\u30F3\u30A2\u30A6\u30C8",
146
+ sessions: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30BB\u30C3\u30B7\u30E7\u30F3"
129
147
  },
130
148
  "zh-CN": {
131
149
  welcomeBack: "\u6B22\u8FCE\u56DE\u6765",
@@ -143,7 +161,13 @@ var translations = {
143
161
  magicLink: "\u4F7F\u7528\u9B54\u6CD5\u94FE\u63A5\u7EE7\u7EED",
144
162
  passkey: "\u4F7F\u7528\u901A\u884C\u5BC6\u94A5\u767B\u5F55",
145
163
  securedBy: "\u5B89\u5168\u4FDD\u969C",
146
- backToSignIn: "\u8FD4\u56DE\u767B\u5F55"
164
+ backToSignIn: "\u8FD4\u56DE\u767B\u5F55",
165
+ profile: "\u4E2A\u4EBA\u8D44\u6599",
166
+ editProfile: "\u7F16\u8F91\u8D44\u6599",
167
+ displayName: "\u663E\u793A\u540D\u79F0",
168
+ save: "\u4FDD\u5B58",
169
+ signOut: "\u9000\u51FA\u767B\u5F55",
170
+ sessions: "\u6D3B\u8DC3\u4F1A\u8BDD"
147
171
  },
148
172
  "zh-TW": {
149
173
  welcomeBack: "\u6B61\u8FCE\u56DE\u4F86",
@@ -161,7 +185,13 @@ var translations = {
161
185
  magicLink: "\u4F7F\u7528\u9B54\u6CD5\u9023\u7D50\u7E7C\u7E8C",
162
186
  passkey: "\u4F7F\u7528\u901A\u884C\u91D1\u9470\u767B\u5165",
163
187
  securedBy: "\u5B89\u5168\u4FDD\u969C",
164
- backToSignIn: "\u8FD4\u56DE\u767B\u5165"
188
+ backToSignIn: "\u8FD4\u56DE\u767B\u5165",
189
+ profile: "\u500B\u4EBA\u8CC7\u6599",
190
+ editProfile: "\u7DE8\u8F2F\u8CC7\u6599",
191
+ displayName: "\u986F\u793A\u540D\u7A31",
192
+ save: "\u5132\u5B58",
193
+ signOut: "\u767B\u51FA",
194
+ sessions: "\u6D3B\u8E8D\u5DE5\u4F5C\u968E\u6BB5"
165
195
  },
166
196
  "pt-BR": {
167
197
  welcomeBack: "Bem-vindo de volta",
@@ -179,7 +209,13 @@ var translations = {
179
209
  magicLink: "Continuar com Magic Link",
180
210
  passkey: "Entrar com Passkey",
181
211
  securedBy: "Protegido por",
182
- backToSignIn: "Voltar ao login"
212
+ backToSignIn: "Voltar ao login",
213
+ profile: "Perfil",
214
+ editProfile: "Editar perfil",
215
+ displayName: "Nome de exibicao",
216
+ save: "Salvar",
217
+ signOut: "Sair",
218
+ sessions: "Sessoes ativas"
183
219
  },
184
220
  es: {
185
221
  welcomeBack: "Bienvenido de nuevo",
@@ -197,7 +233,13 @@ var translations = {
197
233
  magicLink: "Continuar con Magic Link",
198
234
  passkey: "Iniciar con Passkey",
199
235
  securedBy: "Protegido por",
200
- backToSignIn: "Volver al inicio de sesion"
236
+ backToSignIn: "Volver al inicio de sesion",
237
+ profile: "Perfil",
238
+ editProfile: "Editar perfil",
239
+ displayName: "Nombre de visualizacion",
240
+ save: "Guardar",
241
+ signOut: "Cerrar sesion",
242
+ sessions: "Sesiones activas"
201
243
  },
202
244
  de: {
203
245
  welcomeBack: "Willkommen zuruck",
@@ -215,7 +257,13 @@ var translations = {
215
257
  magicLink: "Weiter mit Magic Link",
216
258
  passkey: "Mit Passkey anmelden",
217
259
  securedBy: "Gesichert durch",
218
- backToSignIn: "Zuruck zur Anmeldung"
260
+ backToSignIn: "Zuruck zur Anmeldung",
261
+ profile: "Profil",
262
+ editProfile: "Profil bearbeiten",
263
+ displayName: "Anzeigename",
264
+ save: "Speichern",
265
+ signOut: "Abmelden",
266
+ sessions: "Aktive Sitzungen"
219
267
  },
220
268
  fr: {
221
269
  welcomeBack: "Bon retour",
@@ -233,7 +281,13 @@ var translations = {
233
281
  magicLink: "Continuer avec Magic Link",
234
282
  passkey: "Se connecter avec Passkey",
235
283
  securedBy: "Securise par",
236
- backToSignIn: "Retour a la connexion"
284
+ backToSignIn: "Retour a la connexion",
285
+ profile: "Profil",
286
+ editProfile: "Modifier le profil",
287
+ displayName: "Nom d'affichage",
288
+ save: "Enregistrer",
289
+ signOut: "Se deconnecter",
290
+ sessions: "Sessions actives"
237
291
  },
238
292
  hi: {
239
293
  welcomeBack: "\u0935\u093E\u092A\u0938\u0940 \u092A\u0930 \u0938\u094D\u0935\u093E\u0917\u0924 \u0939\u0948",
@@ -251,7 +305,13 @@ var translations = {
251
305
  magicLink: "\u092E\u0948\u091C\u093F\u0915 \u0932\u093F\u0902\u0915 \u0938\u0947 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
252
306
  passkey: "\u092A\u093E\u0938\u0915\u0940 \u0938\u0947 \u0938\u093E\u0907\u0928 \u0907\u0928",
253
307
  securedBy: "\u0938\u0941\u0930\u0915\u094D\u0937\u093E \u092A\u094D\u0930\u0926\u093E\u0924\u093E",
254
- backToSignIn: "\u0938\u093E\u0907\u0928 \u0907\u0928 \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902"
308
+ backToSignIn: "\u0938\u093E\u0907\u0928 \u0907\u0928 \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902",
309
+ profile: "\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932",
310
+ editProfile: "\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932 \u0938\u0902\u092A\u093E\u0926\u093F\u0924 \u0915\u0930\u0947\u0902",
311
+ displayName: "\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928 \u0928\u093E\u092E",
312
+ save: "\u0938\u0939\u0947\u091C\u0947\u0902",
313
+ signOut: "\u0938\u093E\u0907\u0928 \u0906\u0909\u091F",
314
+ sessions: "\u0938\u0915\u094D\u0930\u093F\u092F \u0938\u0924\u094D\u0930"
255
315
  },
256
316
  tr: {
257
317
  welcomeBack: "Tekrar hos geldiniz",
@@ -269,7 +329,13 @@ var translations = {
269
329
  magicLink: "Magic Link ile devam et",
270
330
  passkey: "Passkey ile giris yap",
271
331
  securedBy: "Guvenlik saglayici",
272
- backToSignIn: "Girise don"
332
+ backToSignIn: "Girise don",
333
+ profile: "Profil",
334
+ editProfile: "Profili duzenle",
335
+ displayName: "Goruntu adi",
336
+ save: "Kaydet",
337
+ signOut: "Cikis yap",
338
+ sessions: "Aktif oturumlar"
273
339
  },
274
340
  id: {
275
341
  welcomeBack: "Selamat datang kembali",
@@ -287,7 +353,13 @@ var translations = {
287
353
  magicLink: "Lanjutkan dengan Magic Link",
288
354
  passkey: "Masuk dengan Passkey",
289
355
  securedBy: "Diamankan oleh",
290
- backToSignIn: "Kembali ke login"
356
+ backToSignIn: "Kembali ke login",
357
+ profile: "Profil",
358
+ editProfile: "Edit profil",
359
+ displayName: "Nama tampilan",
360
+ save: "Simpan",
361
+ signOut: "Keluar",
362
+ sessions: "Sesi aktif"
291
363
  },
292
364
  vi: {
293
365
  welcomeBack: "Chao mung tro lai",
@@ -305,7 +377,13 @@ var translations = {
305
377
  magicLink: "Tiep tuc voi Magic Link",
306
378
  passkey: "Dang nhap voi Passkey",
307
379
  securedBy: "Bao mat boi",
308
- backToSignIn: "Quay lai dang nhap"
380
+ backToSignIn: "Quay lai dang nhap",
381
+ profile: "Ho so",
382
+ editProfile: "Chinh sua ho so",
383
+ displayName: "Ten hien thi",
384
+ save: "Luu",
385
+ signOut: "Dang xuat",
386
+ sessions: "Phien dang nhap hoat dong"
309
387
  },
310
388
  th: {
311
389
  welcomeBack: "\u0E22\u0E34\u0E19\u0E14\u0E35\u0E15\u0E49\u0E2D\u0E19\u0E23\u0E31\u0E1A\u0E01\u0E25\u0E31\u0E1A",
@@ -323,7 +401,13 @@ var translations = {
323
401
  magicLink: "\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E14\u0E49\u0E27\u0E22 Magic Link",
324
402
  passkey: "\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22 Passkey",
325
403
  securedBy: "\u0E23\u0E31\u0E01\u0E29\u0E32\u0E04\u0E27\u0E32\u0E21\u0E1B\u0E25\u0E2D\u0E14\u0E20\u0E31\u0E22\u0E42\u0E14\u0E22",
326
- backToSignIn: "\u0E01\u0E25\u0E31\u0E1A\u0E44\u0E1B\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A"
404
+ backToSignIn: "\u0E01\u0E25\u0E31\u0E1A\u0E44\u0E1B\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
405
+ profile: "\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C",
406
+ editProfile: "\u0E41\u0E01\u0E49\u0E44\u0E02\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C",
407
+ displayName: "\u0E0A\u0E37\u0E48\u0E2D\u0E17\u0E35\u0E48\u0E41\u0E2A\u0E14\u0E07",
408
+ save: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01",
409
+ signOut: "\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A",
410
+ sessions: "\u0E40\u0E0B\u0E2A\u0E0A\u0E31\u0E19\u0E17\u0E35\u0E48\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E2D\u0E22\u0E39\u0E48"
327
411
  },
328
412
  ru: {
329
413
  welcomeBack: "\u0421 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0438\u0435\u043C",
@@ -341,7 +425,13 @@ var translations = {
341
425
  magicLink: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441 Magic Link",
342
426
  passkey: "\u0412\u043E\u0439\u0442\u0438 \u0441 Passkey",
343
427
  securedBy: "\u0417\u0430\u0449\u0438\u0449\u0435\u043D\u043E",
344
- backToSignIn: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u0432\u0445\u043E\u0434\u0443"
428
+ backToSignIn: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u0432\u0445\u043E\u0434\u0443",
429
+ profile: "\u041F\u0440\u043E\u0444\u0438\u043B\u044C",
430
+ editProfile: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C",
431
+ displayName: "\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u0438\u043C\u044F",
432
+ save: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C",
433
+ signOut: "\u0412\u044B\u0439\u0442\u0438",
434
+ sessions: "\u0410\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0441\u0435\u0430\u043D\u0441\u044B"
345
435
  },
346
436
  it: {
347
437
  welcomeBack: "Bentornato",
@@ -359,7 +449,13 @@ var translations = {
359
449
  magicLink: "Continua con Magic Link",
360
450
  passkey: "Accedi con Passkey",
361
451
  securedBy: "Protetto da",
362
- backToSignIn: "Torna all'accesso"
452
+ backToSignIn: "Torna all'accesso",
453
+ profile: "Profilo",
454
+ editProfile: "Modifica profilo",
455
+ displayName: "Nome visualizzato",
456
+ save: "Salva",
457
+ signOut: "Esci",
458
+ sessions: "Sessioni attive"
363
459
  },
364
460
  pl: {
365
461
  welcomeBack: "Witaj ponownie",
@@ -377,7 +473,13 @@ var translations = {
377
473
  magicLink: "Kontynuuj z Magic Link",
378
474
  passkey: "Zaloguj sie z Passkey",
379
475
  securedBy: "Zabezpieczone przez",
380
- backToSignIn: "Powrot do logowania"
476
+ backToSignIn: "Powrot do logowania",
477
+ profile: "Profil",
478
+ editProfile: "Edytuj profil",
479
+ displayName: "Nazwa wyswietlana",
480
+ save: "Zapisz",
481
+ signOut: "Wyloguj sie",
482
+ sessions: "Aktywne sesje"
381
483
  },
382
484
  nl: {
383
485
  welcomeBack: "Welkom terug",
@@ -395,7 +497,13 @@ var translations = {
395
497
  magicLink: "Doorgaan met Magic Link",
396
498
  passkey: "Inloggen met Passkey",
397
499
  securedBy: "Beveiligd door",
398
- backToSignIn: "Terug naar inloggen"
500
+ backToSignIn: "Terug naar inloggen",
501
+ profile: "Profiel",
502
+ editProfile: "Profiel bewerken",
503
+ displayName: "Weergavenaam",
504
+ save: "Opslaan",
505
+ signOut: "Uitloggen",
506
+ sessions: "Actieve sessies"
399
507
  },
400
508
  ar: {
401
509
  welcomeBack: "\u0645\u0631\u062D\u0628\u064B\u0627 \u0628\u0639\u0648\u062F\u062A\u0643",
@@ -413,7 +521,13 @@ var translations = {
413
521
  magicLink: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Magic Link",
414
522
  passkey: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Passkey",
415
523
  securedBy: "\u0645\u062D\u0645\u064A \u0628\u0648\u0627\u0633\u0637\u0629",
416
- backToSignIn: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644"
524
+ backToSignIn: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644",
525
+ profile: "\u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0634\u062E\u0635\u064A",
526
+ editProfile: "\u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0634\u062E\u0635\u064A",
527
+ displayName: "\u0627\u0644\u0627\u0633\u0645 \u0627\u0644\u0645\u0639\u0631\u0648\u0636",
528
+ save: "\u062D\u0641\u0638",
529
+ signOut: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062E\u0631\u0648\u062C",
530
+ sessions: "\u0627\u0644\u062C\u0644\u0633\u0627\u062A \u0627\u0644\u0646\u0634\u0637\u0629"
417
531
  },
418
532
  sv: {
419
533
  welcomeBack: "Valkommen tillbaka",
@@ -431,7 +545,13 @@ var translations = {
431
545
  magicLink: "Fortsatt med Magic Link",
432
546
  passkey: "Logga in med Passkey",
433
547
  securedBy: "Sakrad av",
434
- backToSignIn: "Tillbaka till inloggning"
548
+ backToSignIn: "Tillbaka till inloggning",
549
+ profile: "Profil",
550
+ editProfile: "Redigera profil",
551
+ displayName: "Visningsnamn",
552
+ save: "Spara",
553
+ signOut: "Logga ut",
554
+ sessions: "Aktiva sessioner"
435
555
  },
436
556
  uk: {
437
557
  welcomeBack: "\u0417 \u043F\u043E\u0432\u0435\u0440\u043D\u0435\u043D\u043D\u044F\u043C",
@@ -449,7 +569,13 @@ var translations = {
449
569
  magicLink: "\u041F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u0437 Magic Link",
450
570
  passkey: "\u0423\u0432\u0456\u0439\u0442\u0438 \u0437 Passkey",
451
571
  securedBy: "\u0417\u0430\u0445\u0438\u0449\u0435\u043D\u043E",
452
- backToSignIn: "\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u0438\u0441\u044F \u0434\u043E \u0432\u0445\u043E\u0434\u0443"
572
+ backToSignIn: "\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u0438\u0441\u044F \u0434\u043E \u0432\u0445\u043E\u0434\u0443",
573
+ profile: "\u041F\u0440\u043E\u0444\u0456\u043B\u044C",
574
+ editProfile: "\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0444\u0456\u043B\u044C",
575
+ displayName: "\u0412\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0443\u0432\u0430\u043D\u0435 \u0456\u043C'\u044F",
576
+ save: "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
577
+ signOut: "\u0412\u0438\u0439\u0442\u0438",
578
+ sessions: "\u0410\u043A\u0442\u0438\u0432\u043D\u0456 \u0441\u0435\u0430\u043D\u0441\u0438"
453
579
  }
454
580
  };
455
581
  function getStrings(locale) {
@@ -679,6 +805,53 @@ var ModalRenderer = class {
679
805
  if (!this.shadowRoot) return;
680
806
  this.shadowRoot.getElementById("authon-error-msg")?.remove();
681
807
  }
808
+ showVerificationInput(email, onVerify, onResend) {
809
+ if (!this.shadowRoot) return;
810
+ const inner = this.shadowRoot.querySelector(".modal-inner");
811
+ if (!inner) return;
812
+ inner.innerHTML = `
813
+ <div style="text-align:center;padding:8px 0">
814
+ <div style="width:48px;height:48px;border-radius:12px;background:color-mix(in srgb, var(--authon-primary-start) 15%, transparent);display:flex;align-items:center;justify-content:center;margin:0 auto 16px">
815
+ <svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="var(--authon-primary-start)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 4h16c1.1 0 2 .9 2 2v12c0 1.1-.9 2-2 2H4c-1.1 0-2-.9-2-2V6c0-1.1.9-2 2-2z"/><polyline points="22,6 12,13 2,6"/></svg>
816
+ </div>
817
+ <h2 class="title" style="font-size:20px;margin-bottom:4px">${this.t.welcomeBack.includes("Welcome") ? "Check your email" : this.t.welcomeBack}</h2>
818
+ <p style="font-size:13px;color:var(--authon-muted);margin-bottom:20px">${email}</p>
819
+ </div>
820
+ <div class="email-form" id="verify-form">
821
+ <input type="text" id="verify-code" class="input" placeholder="000000" maxlength="6" inputmode="numeric" autocomplete="one-time-code" style="text-align:center;font-size:20px;letter-spacing:0.2em;font-family:ui-monospace,monospace" />
822
+ <button type="button" id="verify-submit" class="submit-btn">${this.t.signIn}</button>
823
+ </div>
824
+ <p style="text-align:center;margin-top:12px;font-size:12px;color:var(--authon-dim)">
825
+ <a href="#" id="resend-link" style="color:var(--authon-primary-start);text-decoration:none;font-weight:500">${this.t.backToSignIn.includes("Back") ? "Resend code" : this.t.backToSignIn}</a>
826
+ </p>
827
+ `;
828
+ const codeInput = this.shadowRoot.getElementById("verify-code");
829
+ const submitBtn = this.shadowRoot.getElementById("verify-submit");
830
+ const resendLink = this.shadowRoot.getElementById("resend-link");
831
+ codeInput?.focus();
832
+ codeInput?.addEventListener("input", () => {
833
+ codeInput.value = codeInput.value.replace(/\D/g, "").slice(0, 6);
834
+ });
835
+ submitBtn?.addEventListener("click", async () => {
836
+ const code = codeInput?.value?.trim();
837
+ if (!code || code.length < 6) return;
838
+ submitBtn.textContent = "...";
839
+ submitBtn.disabled = true;
840
+ await onVerify(code);
841
+ });
842
+ codeInput?.addEventListener("keydown", (e) => {
843
+ if (e.key === "Enter") submitBtn?.click();
844
+ });
845
+ resendLink?.addEventListener("click", async (e) => {
846
+ e.preventDefault();
847
+ resendLink.textContent = "...";
848
+ await onResend();
849
+ resendLink.textContent = "Sent!";
850
+ setTimeout(() => {
851
+ resendLink.textContent = "Resend code";
852
+ }, 2e3);
853
+ });
854
+ }
682
855
  showLoading() {
683
856
  if (!this.shadowRoot) return;
684
857
  this.hideLoading();
@@ -1573,6 +1746,676 @@ var ModalRenderer = class {
1573
1746
  }
1574
1747
  };
1575
1748
 
1749
+ // src/profile.ts
1750
+ function hexToRgba2(hex, alpha) {
1751
+ const h = hex.replace("#", "");
1752
+ const r = parseInt(h.substring(0, 2), 16);
1753
+ const g = parseInt(h.substring(2, 4), 16);
1754
+ const b = parseInt(h.substring(4, 6), 16);
1755
+ return `rgba(${r},${g},${b},${alpha})`;
1756
+ }
1757
+ function formatRelativeTime(dateStr) {
1758
+ if (!dateStr) return "\u2014";
1759
+ const diff = Date.now() - new Date(dateStr).getTime();
1760
+ const minutes = Math.floor(diff / 6e4);
1761
+ if (minutes < 1) return "just now";
1762
+ if (minutes < 60) return `${minutes}m ago`;
1763
+ const hours = Math.floor(minutes / 60);
1764
+ if (hours < 24) return `${hours}h ago`;
1765
+ const days = Math.floor(hours / 24);
1766
+ return `${days}d ago`;
1767
+ }
1768
+ function parseUserAgent(ua) {
1769
+ if (!ua) return "Unknown device";
1770
+ if (/iPhone|iPad/.test(ua)) return "iOS";
1771
+ if (/Android/.test(ua)) return "Android";
1772
+ if (/Windows/.test(ua)) return "Windows";
1773
+ if (/Macintosh|Mac OS/.test(ua)) return "macOS";
1774
+ if (/Linux/.test(ua)) return "Linux";
1775
+ return "Unknown device";
1776
+ }
1777
+ var ProfileRenderer = class {
1778
+ shadowRoot = null;
1779
+ hostElement = null;
1780
+ containerElement = null;
1781
+ containerId = null;
1782
+ mode;
1783
+ theme;
1784
+ branding;
1785
+ themeObserver = null;
1786
+ mediaQueryListener = null;
1787
+ t;
1788
+ user;
1789
+ sessions;
1790
+ isEditMode = false;
1791
+ onSave;
1792
+ onSignOut;
1793
+ onRevokeSession;
1794
+ onClose;
1795
+ escHandler = null;
1796
+ constructor(options) {
1797
+ this.mode = options.mode;
1798
+ this.theme = options.theme || "auto";
1799
+ this.branding = { ...DEFAULT_BRANDING, ...options.branding };
1800
+ this.t = getStrings(options.locale || "en");
1801
+ this.user = options.user;
1802
+ this.sessions = options.sessions || [];
1803
+ this.onSave = options.onSave;
1804
+ this.onSignOut = options.onSignOut;
1805
+ this.onRevokeSession = options.onRevokeSession;
1806
+ this.onClose = options.onClose;
1807
+ if (options.mode === "embedded" && options.containerId) {
1808
+ this.containerId = options.containerId;
1809
+ }
1810
+ }
1811
+ resolveContainerElement() {
1812
+ if (this.mode !== "embedded" || !this.containerId) return null;
1813
+ const next = document.getElementById(this.containerId);
1814
+ if (this.containerElement !== next) {
1815
+ this.hostElement?.remove();
1816
+ this.hostElement = null;
1817
+ this.shadowRoot = null;
1818
+ }
1819
+ this.containerElement = next;
1820
+ return next;
1821
+ }
1822
+ open() {
1823
+ this.resolveContainerElement();
1824
+ if (this.hostElement && !this.hostElement.isConnected) {
1825
+ this.hostElement = null;
1826
+ this.shadowRoot = null;
1827
+ }
1828
+ if (this.shadowRoot && this.hostElement) {
1829
+ this.rerender();
1830
+ } else {
1831
+ this.isEditMode = false;
1832
+ this.render();
1833
+ }
1834
+ }
1835
+ close() {
1836
+ this.stopThemeObserver();
1837
+ if (this.escHandler) {
1838
+ document.removeEventListener("keydown", this.escHandler);
1839
+ this.escHandler = null;
1840
+ }
1841
+ if (this.hostElement) {
1842
+ this.hostElement.remove();
1843
+ this.hostElement = null;
1844
+ this.shadowRoot = null;
1845
+ }
1846
+ const liveContainer = this.resolveContainerElement();
1847
+ if (liveContainer) {
1848
+ liveContainer.replaceChildren();
1849
+ }
1850
+ }
1851
+ updateUser(user) {
1852
+ this.user = user;
1853
+ if (this.shadowRoot) this.rerender();
1854
+ }
1855
+ updateSessions(sessions) {
1856
+ this.sessions = sessions;
1857
+ if (this.shadowRoot) this.rerender();
1858
+ }
1859
+ setTheme(theme) {
1860
+ this.theme = theme;
1861
+ this.updateThemeCSS();
1862
+ if (theme === "auto") {
1863
+ this.startThemeObserver();
1864
+ } else {
1865
+ this.stopThemeObserver();
1866
+ }
1867
+ }
1868
+ showSaving() {
1869
+ if (!this.shadowRoot) return;
1870
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1871
+ if (btn) {
1872
+ btn.disabled = true;
1873
+ btn.textContent = "...";
1874
+ }
1875
+ }
1876
+ showSaveError(message) {
1877
+ if (!this.shadowRoot) return;
1878
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1879
+ if (btn) {
1880
+ btn.disabled = false;
1881
+ btn.textContent = this.t.save;
1882
+ }
1883
+ this.showInlineError("profile-error", message);
1884
+ }
1885
+ showInlineError(id, message) {
1886
+ if (!this.shadowRoot) return;
1887
+ this.shadowRoot.getElementById(id)?.remove();
1888
+ const errEl = document.createElement("div");
1889
+ errEl.id = id;
1890
+ errEl.className = "error-msg";
1891
+ errEl.textContent = message;
1892
+ this.shadowRoot.querySelector(".profile-actions")?.appendChild(errEl);
1893
+ }
1894
+ updateThemeCSS() {
1895
+ if (!this.shadowRoot) return;
1896
+ const styleEl = this.shadowRoot.getElementById("authon-profile-theme-style");
1897
+ if (styleEl) styleEl.textContent = this.buildCSS();
1898
+ }
1899
+ startThemeObserver() {
1900
+ this.stopThemeObserver();
1901
+ if (typeof document === "undefined" || typeof window === "undefined") return;
1902
+ this.themeObserver = new MutationObserver(() => this.updateThemeCSS());
1903
+ this.themeObserver.observe(document.documentElement, {
1904
+ attributes: true,
1905
+ attributeFilter: ["data-theme", "class"]
1906
+ });
1907
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
1908
+ this.mediaQueryListener = () => this.updateThemeCSS();
1909
+ mq.addEventListener("change", this.mediaQueryListener);
1910
+ }
1911
+ stopThemeObserver() {
1912
+ if (this.themeObserver) {
1913
+ this.themeObserver.disconnect();
1914
+ this.themeObserver = null;
1915
+ }
1916
+ if (this.mediaQueryListener) {
1917
+ window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", this.mediaQueryListener);
1918
+ this.mediaQueryListener = null;
1919
+ }
1920
+ }
1921
+ isDark() {
1922
+ if (this.theme === "dark") return true;
1923
+ if (this.theme === "light") return false;
1924
+ if (typeof document !== "undefined") {
1925
+ const html = document.documentElement;
1926
+ if (html.classList.contains("dark") || html.getAttribute("data-theme") === "dark") return true;
1927
+ if (html.classList.contains("light") || html.getAttribute("data-theme") === "light") return false;
1928
+ }
1929
+ return typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches;
1930
+ }
1931
+ render() {
1932
+ const host = document.createElement("div");
1933
+ host.setAttribute("data-authon-profile", "");
1934
+ this.hostElement = host;
1935
+ if (this.mode === "popup") {
1936
+ document.body.appendChild(host);
1937
+ } else {
1938
+ const container = this.resolveContainerElement();
1939
+ if (!container) {
1940
+ this.hostElement = null;
1941
+ throw new Error(`Authon profile container "#${this.containerId}" not found`);
1942
+ }
1943
+ container.replaceChildren();
1944
+ container.appendChild(host);
1945
+ }
1946
+ this.shadowRoot = host.attachShadow({ mode: "open" });
1947
+ this.shadowRoot.innerHTML = this.buildShell();
1948
+ this.attachEvents();
1949
+ if (this.mode === "popup") {
1950
+ this.escHandler = (e) => {
1951
+ if (e.key === "Escape") {
1952
+ this.onClose();
1953
+ this.close();
1954
+ }
1955
+ };
1956
+ document.addEventListener("keydown", this.escHandler);
1957
+ }
1958
+ if (this.theme === "auto") this.startThemeObserver();
1959
+ }
1960
+ rerender() {
1961
+ if (!this.shadowRoot) return;
1962
+ const inner = this.shadowRoot.getElementById("profile-inner");
1963
+ if (!inner) return;
1964
+ inner.style.opacity = "0";
1965
+ inner.style.transform = "translateY(-4px)";
1966
+ setTimeout(() => {
1967
+ inner.innerHTML = this.buildInnerContent();
1968
+ this.attachInnerEvents();
1969
+ void inner.offsetHeight;
1970
+ inner.style.opacity = "1";
1971
+ inner.style.transform = "translateY(0)";
1972
+ }, 120);
1973
+ }
1974
+ buildShell() {
1975
+ const popupWrapper = this.mode === "popup" ? `<div class="backdrop" id="profile-backdrop"></div>` : "";
1976
+ return `
1977
+ <style id="authon-profile-theme-style">${this.buildCSS()}</style>
1978
+ ${popupWrapper}
1979
+ <div class="profile-container" role="dialog" aria-modal="true" aria-label="${this.t.profile}">
1980
+ <div id="profile-inner" class="profile-inner">
1981
+ ${this.buildInnerContent()}
1982
+ </div>
1983
+ </div>
1984
+ `;
1985
+ }
1986
+ buildInnerContent() {
1987
+ const u = this.user;
1988
+ const initials = (u.displayName || u.email || "?").split(/\s+/).map((w) => w[0]?.toUpperCase() ?? "").slice(0, 2).join("");
1989
+ const avatarHtml = u.avatarUrl ? `<img class="avatar-img" src="${u.avatarUrl}" alt="${u.displayName || ""}" />` : `<div class="avatar-placeholder">${initials}</div>`;
1990
+ const closeBtn = this.mode === "popup" ? `<button class="close-btn" id="profile-close-btn" aria-label="Close">
1991
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1992
+ <path d="M12 4L4 12M4 4l8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
1993
+ </svg>
1994
+ </button>` : "";
1995
+ if (this.isEditMode) {
1996
+ return this.buildEditContent(avatarHtml, closeBtn);
1997
+ }
1998
+ return this.buildViewContent(avatarHtml, closeBtn, u);
1999
+ }
2000
+ buildViewContent(avatarHtml, closeBtn, u) {
2001
+ const sessionsHtml = this.sessions.length > 0 ? `<div class="section">
2002
+ <div class="section-label">${this.t.sessions}</div>
2003
+ <div class="sessions-list">
2004
+ ${this.sessions.map((s) => `
2005
+ <div class="session-item" data-session-id="${s.id}">
2006
+ <div class="session-info">
2007
+ <span class="session-device">${parseUserAgent(s.userAgent)}</span>
2008
+ <span class="session-meta">${s.ipAddress || ""} &middot; ${formatRelativeTime(s.lastActiveAt)}</span>
2009
+ </div>
2010
+ <button class="session-revoke-btn" data-session-id="${s.id}" aria-label="Revoke session">
2011
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
2012
+ <path d="M10.5 3.5L3.5 10.5M3.5 3.5l7 7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
2013
+ </svg>
2014
+ </button>
2015
+ </div>
2016
+ `).join("")}
2017
+ </div>
2018
+ </div>` : "";
2019
+ return `
2020
+ <div class="profile-header">
2021
+ <div class="avatar-wrap">${avatarHtml}</div>
2022
+ <div class="header-text">
2023
+ <div class="display-name">${u.displayName || "\u2014"}</div>
2024
+ <div class="email">${u.email || "\u2014"}</div>
2025
+ </div>
2026
+ ${closeBtn}
2027
+ </div>
2028
+
2029
+ <div class="section">
2030
+ <div class="field-row">
2031
+ <span class="field-label">${this.t.emailAddress}</span>
2032
+ <span class="field-value readonly">${u.email || "\u2014"}</span>
2033
+ </div>
2034
+ <div class="field-row">
2035
+ <span class="field-label">${this.t.displayName}</span>
2036
+ <span class="field-value">${u.displayName || "\u2014"}</span>
2037
+ </div>
2038
+ </div>
2039
+
2040
+ ${sessionsHtml}
2041
+
2042
+ <div class="profile-actions">
2043
+ <button class="edit-btn" id="profile-edit-btn">${this.t.editProfile}</button>
2044
+ <button class="signout-btn" id="profile-signout-btn">${this.t.signOut}</button>
2045
+ </div>
2046
+ `;
2047
+ }
2048
+ buildEditContent(avatarHtml, closeBtn) {
2049
+ const u = this.user;
2050
+ return `
2051
+ <div class="profile-header">
2052
+ <div class="avatar-wrap">${avatarHtml}</div>
2053
+ <div class="header-text">
2054
+ <div class="display-name">${this.t.editProfile}</div>
2055
+ <div class="email">${u.email || "\u2014"}</div>
2056
+ </div>
2057
+ ${closeBtn}
2058
+ </div>
2059
+
2060
+ <div class="section">
2061
+ <div class="field-group">
2062
+ <label class="field-label" for="profile-displayname-input">${this.t.displayName}</label>
2063
+ <input
2064
+ id="profile-displayname-input"
2065
+ class="input"
2066
+ type="text"
2067
+ value="${u.displayName || ""}"
2068
+ placeholder="${this.t.displayName}"
2069
+ autocomplete="name"
2070
+ />
2071
+ </div>
2072
+ <div class="field-group">
2073
+ <label class="field-label" for="profile-avatar-input">Avatar URL</label>
2074
+ <input
2075
+ id="profile-avatar-input"
2076
+ class="input"
2077
+ type="url"
2078
+ value="${u.avatarUrl || ""}"
2079
+ placeholder="https://..."
2080
+ autocomplete="off"
2081
+ />
2082
+ </div>
2083
+ <div class="field-group">
2084
+ <label class="field-label">${this.t.emailAddress}</label>
2085
+ <input class="input readonly" type="email" value="${u.email || ""}" disabled />
2086
+ </div>
2087
+ </div>
2088
+
2089
+ <div class="profile-actions">
2090
+ <button class="save-btn" id="profile-save-btn">${this.t.save}</button>
2091
+ <button class="cancel-btn" id="profile-cancel-btn">Cancel</button>
2092
+ </div>
2093
+ `;
2094
+ }
2095
+ buildCSS() {
2096
+ const b = this.branding;
2097
+ const dark = this.isDark();
2098
+ const bg = dark ? b.darkBg || "#0f172a" : b.lightBg || "#ffffff";
2099
+ const text = dark ? b.darkText || "#f1f5f9" : b.lightText || "#111827";
2100
+ const mutedText = dark ? "#94a3b8" : "#6b7280";
2101
+ const dimText = dark ? "#64748b" : "#9ca3af";
2102
+ const borderColor = dark ? "#334155" : "#d1d5db";
2103
+ const dividerColor = dark ? "#334155" : "#e5e7eb";
2104
+ const inputBg = dark ? "#1e293b" : "#ffffff";
2105
+ const sectionBg = dark ? "#1e293b" : "#f9fafb";
2106
+ const sessionItemBg = dark ? "#263148" : "#f3f4f6";
2107
+ return `
2108
+ :host {
2109
+ --authon-primary-start: ${b.primaryColorStart || "#7c3aed"};
2110
+ --authon-primary-end: ${b.primaryColorEnd || "#4f46e5"};
2111
+ --authon-bg: ${bg};
2112
+ --authon-text: ${text};
2113
+ --authon-muted: ${mutedText};
2114
+ --authon-dim: ${dimText};
2115
+ --authon-border: ${borderColor};
2116
+ --authon-divider: ${dividerColor};
2117
+ --authon-input-bg: ${inputBg};
2118
+ --authon-section-bg: ${sectionBg};
2119
+ --authon-session-bg: ${sessionItemBg};
2120
+ --authon-backdrop-bg: rgba(0,0,0,${dark ? "0.7" : "0.5"});
2121
+ --authon-radius: ${b.borderRadius ?? 12}px;
2122
+ --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
2123
+ font-family: var(--authon-font);
2124
+ color: var(--authon-text);
2125
+ }
2126
+ * { box-sizing: border-box; margin: 0; padding: 0; }
2127
+
2128
+ .backdrop {
2129
+ position: fixed; inset: 0; z-index: 99998;
2130
+ background: var(--authon-backdrop-bg); backdrop-filter: blur(4px);
2131
+ animation: fadeIn 0.2s ease;
2132
+ }
2133
+
2134
+ .profile-container {
2135
+ ${this.mode === "popup" ? "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;" : ""}
2136
+ background: var(--authon-bg);
2137
+ color: var(--authon-text);
2138
+ border: 1px solid var(--authon-border);
2139
+ border-radius: var(--authon-radius);
2140
+ padding: 24px;
2141
+ width: 380px; max-width: 100%;
2142
+ ${this.mode === "popup" ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? "0.5" : "0.25"}); animation: slideIn 0.3s ease;` : ""}
2143
+ }
2144
+
2145
+ .profile-inner {
2146
+ transition: opacity 0.12s ease, transform 0.12s ease;
2147
+ }
2148
+
2149
+ .profile-header {
2150
+ display: flex;
2151
+ align-items: center;
2152
+ gap: 14px;
2153
+ margin-bottom: 20px;
2154
+ position: relative;
2155
+ }
2156
+
2157
+ .avatar-wrap { flex-shrink: 0; }
2158
+
2159
+ .avatar-img {
2160
+ width: 52px; height: 52px;
2161
+ border-radius: 50%;
2162
+ object-fit: cover;
2163
+ border: 2px solid var(--authon-border);
2164
+ }
2165
+
2166
+ .avatar-placeholder {
2167
+ width: 52px; height: 52px;
2168
+ border-radius: 50%;
2169
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2170
+ display: flex; align-items: center; justify-content: center;
2171
+ font-size: 18px; font-weight: 700; color: #fff;
2172
+ flex-shrink: 0;
2173
+ }
2174
+
2175
+ .header-text { flex: 1; min-width: 0; }
2176
+
2177
+ .display-name {
2178
+ font-size: 16px; font-weight: 600;
2179
+ color: var(--authon-text);
2180
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2181
+ }
2182
+
2183
+ .email {
2184
+ font-size: 13px; color: var(--authon-muted);
2185
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2186
+ margin-top: 2px;
2187
+ }
2188
+
2189
+ .close-btn {
2190
+ position: absolute; top: 0; right: 0;
2191
+ background: none; border: none;
2192
+ color: var(--authon-muted); cursor: pointer;
2193
+ padding: 4px; border-radius: 6px;
2194
+ display: flex; align-items: center; justify-content: center;
2195
+ transition: color 0.15s, background 0.15s;
2196
+ }
2197
+ .close-btn:hover { color: var(--authon-text); background: var(--authon-divider); }
2198
+
2199
+ .section {
2200
+ background: var(--authon-section-bg);
2201
+ border: 1px solid var(--authon-border);
2202
+ border-radius: calc(var(--authon-radius) * 0.67);
2203
+ padding: 12px 14px;
2204
+ margin-bottom: 12px;
2205
+ display: flex; flex-direction: column; gap: 10px;
2206
+ }
2207
+
2208
+ .section-label {
2209
+ font-size: 11px; font-weight: 600;
2210
+ text-transform: uppercase; letter-spacing: 0.05em;
2211
+ color: var(--authon-dim); margin-bottom: 2px;
2212
+ }
2213
+
2214
+ .field-row {
2215
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
2216
+ }
2217
+
2218
+ .field-label {
2219
+ font-size: 12px; color: var(--authon-muted); flex-shrink: 0;
2220
+ }
2221
+
2222
+ .field-value {
2223
+ font-size: 13px; color: var(--authon-text);
2224
+ text-align: right; min-width: 0;
2225
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2226
+ }
2227
+
2228
+ .field-value.readonly { color: var(--authon-dim); }
2229
+
2230
+ .field-group {
2231
+ display: flex; flex-direction: column; gap: 4px;
2232
+ }
2233
+
2234
+ .input {
2235
+ width: 100%; padding: 9px 12px;
2236
+ background: var(--authon-input-bg);
2237
+ color: var(--authon-text);
2238
+ border: 1px solid var(--authon-border);
2239
+ border-radius: calc(var(--authon-radius) * 0.5);
2240
+ font-size: 13px; font-family: var(--authon-font);
2241
+ outline: none; transition: border-color 0.15s;
2242
+ }
2243
+ .input::placeholder { color: var(--authon-dim); }
2244
+ .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px ${hexToRgba2(b.primaryColorStart || "#7c3aed", 0.15)}; }
2245
+ .input.readonly, .input:disabled { color: var(--authon-dim); cursor: not-allowed; background: var(--authon-section-bg); }
2246
+
2247
+ .sessions-list { display: flex; flex-direction: column; gap: 6px; }
2248
+
2249
+ .session-item {
2250
+ display: flex; align-items: center; justify-content: space-between;
2251
+ background: var(--authon-session-bg);
2252
+ border-radius: calc(var(--authon-radius) * 0.5);
2253
+ padding: 8px 10px; gap: 8px;
2254
+ }
2255
+
2256
+ .session-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
2257
+
2258
+ .session-device {
2259
+ font-size: 13px; font-weight: 500; color: var(--authon-text);
2260
+ }
2261
+
2262
+ .session-meta {
2263
+ font-size: 11px; color: var(--authon-dim);
2264
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2265
+ }
2266
+
2267
+ .session-revoke-btn {
2268
+ background: none; border: none;
2269
+ color: var(--authon-dim); cursor: pointer;
2270
+ padding: 4px; border-radius: 4px; flex-shrink: 0;
2271
+ display: flex; align-items: center; justify-content: center;
2272
+ transition: color 0.15s, background 0.15s;
2273
+ }
2274
+ .session-revoke-btn:hover { color: #ef4444; background: rgba(239,68,68,0.1); }
2275
+
2276
+ .profile-actions {
2277
+ display: flex; flex-direction: column; gap: 8px;
2278
+ margin-top: 4px;
2279
+ }
2280
+
2281
+ .edit-btn {
2282
+ width: 100%; padding: 10px;
2283
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2284
+ color: #fff; border: none;
2285
+ border-radius: calc(var(--authon-radius) * 0.5);
2286
+ font-size: 14px; font-weight: 600; cursor: pointer;
2287
+ font-family: var(--authon-font); transition: opacity 0.15s;
2288
+ }
2289
+ .edit-btn:hover { opacity: 0.9; }
2290
+
2291
+ .save-btn {
2292
+ width: 100%; padding: 10px;
2293
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2294
+ color: #fff; border: none;
2295
+ border-radius: calc(var(--authon-radius) * 0.5);
2296
+ font-size: 14px; font-weight: 600; cursor: pointer;
2297
+ font-family: var(--authon-font); transition: opacity 0.15s;
2298
+ }
2299
+ .save-btn:hover { opacity: 0.9; }
2300
+ .save-btn:disabled { opacity: 0.6; cursor: not-allowed; }
2301
+
2302
+ .cancel-btn {
2303
+ width: 100%; padding: 10px;
2304
+ background: none;
2305
+ color: var(--authon-muted);
2306
+ border: 1px solid var(--authon-border);
2307
+ border-radius: calc(var(--authon-radius) * 0.5);
2308
+ font-size: 14px; font-weight: 500; cursor: pointer;
2309
+ font-family: var(--authon-font); transition: background 0.15s, color 0.15s;
2310
+ }
2311
+ .cancel-btn:hover { background: var(--authon-divider); color: var(--authon-text); }
2312
+
2313
+ .signout-btn {
2314
+ width: 100%; padding: 10px;
2315
+ background: none;
2316
+ color: #ef4444;
2317
+ border: 1px solid rgba(239,68,68,0.3);
2318
+ border-radius: calc(var(--authon-radius) * 0.5);
2319
+ font-size: 14px; font-weight: 500; cursor: pointer;
2320
+ font-family: var(--authon-font); transition: background 0.15s;
2321
+ }
2322
+ .signout-btn:hover { background: rgba(239,68,68,0.08); }
2323
+
2324
+ .error-msg {
2325
+ padding: 8px 12px;
2326
+ background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);
2327
+ border-radius: calc(var(--authon-radius) * 0.33);
2328
+ font-size: 13px; color: #ef4444; text-align: center;
2329
+ animation: fadeIn 0.15s ease;
2330
+ }
2331
+
2332
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
2333
+ @keyframes slideIn { from { opacity: 0; transform: translate(-50%, calc(-50% - 8px)); } to { opacity: 1; transform: translate(-50%, -50%); } }
2334
+ `;
2335
+ }
2336
+ attachEvents() {
2337
+ this.attachBackdropEvent();
2338
+ this.attachInnerEvents();
2339
+ }
2340
+ attachBackdropEvent() {
2341
+ if (!this.shadowRoot || this.mode !== "popup") return;
2342
+ const backdrop = this.shadowRoot.getElementById("profile-backdrop");
2343
+ if (backdrop) {
2344
+ backdrop.addEventListener("click", () => {
2345
+ this.onClose();
2346
+ this.close();
2347
+ });
2348
+ }
2349
+ }
2350
+ attachInnerEvents() {
2351
+ if (!this.shadowRoot) return;
2352
+ const closeBtn = this.shadowRoot.getElementById("profile-close-btn");
2353
+ closeBtn?.addEventListener("click", () => {
2354
+ this.onClose();
2355
+ this.close();
2356
+ });
2357
+ const editBtn = this.shadowRoot.getElementById("profile-edit-btn");
2358
+ editBtn?.addEventListener("click", () => {
2359
+ this.isEditMode = true;
2360
+ this.rerender();
2361
+ });
2362
+ const cancelBtn = this.shadowRoot.getElementById("profile-cancel-btn");
2363
+ cancelBtn?.addEventListener("click", () => {
2364
+ this.isEditMode = false;
2365
+ this.rerender();
2366
+ });
2367
+ const saveBtn = this.shadowRoot.getElementById("profile-save-btn");
2368
+ saveBtn?.addEventListener("click", async () => {
2369
+ const nameInput = this.shadowRoot.getElementById("profile-displayname-input");
2370
+ const avatarInput = this.shadowRoot.getElementById("profile-avatar-input");
2371
+ const displayName = nameInput?.value.trim();
2372
+ const avatarUrl = avatarInput?.value.trim();
2373
+ this.showSaving();
2374
+ this.shadowRoot.getElementById("profile-error")?.remove();
2375
+ try {
2376
+ await this.onSave({
2377
+ displayName: displayName || void 0,
2378
+ avatarUrl: avatarUrl || void 0
2379
+ });
2380
+ this.isEditMode = false;
2381
+ this.rerender();
2382
+ } catch (err) {
2383
+ this.showSaveError(err instanceof Error ? err.message : "Save failed");
2384
+ }
2385
+ });
2386
+ const signOutBtn = this.shadowRoot.getElementById("profile-signout-btn");
2387
+ signOutBtn?.addEventListener("click", async () => {
2388
+ if (signOutBtn instanceof HTMLButtonElement) {
2389
+ signOutBtn.disabled = true;
2390
+ signOutBtn.textContent = "...";
2391
+ }
2392
+ try {
2393
+ await this.onSignOut();
2394
+ this.close();
2395
+ } catch (_) {
2396
+ if (signOutBtn instanceof HTMLButtonElement) {
2397
+ signOutBtn.disabled = false;
2398
+ signOutBtn.textContent = this.t.signOut;
2399
+ }
2400
+ }
2401
+ });
2402
+ this.shadowRoot.querySelectorAll(".session-revoke-btn").forEach((btn) => {
2403
+ btn.addEventListener("click", async () => {
2404
+ const sessionId = btn.dataset.sessionId;
2405
+ if (!sessionId) return;
2406
+ btn.disabled = true;
2407
+ try {
2408
+ await this.onRevokeSession(sessionId);
2409
+ this.sessions = this.sessions.filter((s) => s.id !== sessionId);
2410
+ this.rerender();
2411
+ } catch (_) {
2412
+ btn.disabled = false;
2413
+ }
2414
+ });
2415
+ });
2416
+ }
2417
+ };
2418
+
1576
2419
  // src/session.ts
1577
2420
  var SessionManager = class {
1578
2421
  accessToken = null;
@@ -2102,6 +2945,7 @@ var Authon = class {
2102
2945
  config;
2103
2946
  session;
2104
2947
  modal = null;
2948
+ profile = null;
2105
2949
  listeners = /* @__PURE__ */ new Map();
2106
2950
  branding = null;
2107
2951
  providers = [];
@@ -2135,9 +2979,56 @@ var Authon = class {
2135
2979
  await this.ensureInitialized();
2136
2980
  this.getModal().open("signUp");
2137
2981
  }
2982
+ async openProfile() {
2983
+ const user = this.getUser();
2984
+ if (!user) throw new Error("Must be signed in to open profile");
2985
+ const token = this.session.getToken();
2986
+ let sessions = [];
2987
+ if (token) {
2988
+ try {
2989
+ sessions = await this.listSessions();
2990
+ } catch (_) {
2991
+ }
2992
+ }
2993
+ if (!this.profile) {
2994
+ this.profile = new ProfileRenderer({
2995
+ mode: this.config.mode,
2996
+ theme: this.config.theme,
2997
+ locale: this.config.locale,
2998
+ containerId: this.config.containerId,
2999
+ branding: this.branding || void 0,
3000
+ user,
3001
+ sessions,
3002
+ onSave: async (data) => {
3003
+ const updated = await this.updateProfile(data);
3004
+ this.profile?.updateUser(updated);
3005
+ },
3006
+ onSignOut: async () => {
3007
+ await this.signOut();
3008
+ this.profile = null;
3009
+ },
3010
+ onRevokeSession: async (sessionId) => {
3011
+ await this.revokeSession(sessionId);
3012
+ },
3013
+ onClose: () => {
3014
+ this.profile?.close();
3015
+ this.profile = null;
3016
+ }
3017
+ });
3018
+ } else {
3019
+ this.profile.updateUser(user);
3020
+ this.profile.updateSessions(sessions);
3021
+ }
3022
+ this.profile.open();
3023
+ }
3024
+ closeProfile() {
3025
+ this.profile?.close();
3026
+ this.profile = null;
3027
+ }
2138
3028
  /** Update theme at runtime without destroying form state */
2139
3029
  setTheme(theme) {
2140
3030
  this.getModal().setTheme(theme);
3031
+ this.profile?.setTheme(theme);
2141
3032
  }
2142
3033
  async signInWithOAuth(provider, options) {
2143
3034
  await this.ensureInitialized();
@@ -2159,14 +3050,27 @@ var Authon = class {
2159
3050
  return res.user;
2160
3051
  }
2161
3052
  async signUpWithEmail(email, password, meta) {
2162
- const tokens = await this.apiPost("/v1/auth/signup", {
3053
+ const res = await this.apiPost("/v1/auth/signup", {
2163
3054
  email,
2164
3055
  password,
2165
3056
  ...meta
2166
3057
  });
2167
- this.session.setSession(tokens);
2168
- this.emit("signedIn", tokens.user);
2169
- return tokens.user;
3058
+ if (res.needsVerification) {
3059
+ this.emit("verificationRequired", res.email);
3060
+ return { needsVerification: true, email: res.email };
3061
+ }
3062
+ this.session.setSession(res);
3063
+ this.emit("signedIn", res.user);
3064
+ return res.user;
3065
+ }
3066
+ async verifyEmail(email, code) {
3067
+ const res = await this.apiPost("/v1/auth/verify-email", { email, code });
3068
+ this.session.setSession(res);
3069
+ this.emit("signedIn", res.user);
3070
+ return res.user;
3071
+ }
3072
+ async resendVerificationCode(email) {
3073
+ await this.apiPost("/v1/auth/resend-code", { email });
2170
3074
  }
2171
3075
  async signOut() {
2172
3076
  await this.session.signOut();
@@ -2450,6 +3354,8 @@ var Authon = class {
2450
3354
  }
2451
3355
  destroy() {
2452
3356
  this.modal?.close();
3357
+ this.profile?.close();
3358
+ this.profile = null;
2453
3359
  this.session.destroy();
2454
3360
  this.listeners.clear();
2455
3361
  }
@@ -2515,13 +3421,37 @@ var Authon = class {
2515
3421
  onEmailSubmit: (email, password, isSignUp) => {
2516
3422
  this.modal?.clearError();
2517
3423
  const turnstileToken = this.modal?.getTurnstileToken?.() || void 0;
2518
- const promise = isSignUp ? this.signUpWithEmail(email, password, { turnstileToken }) : this.signInWithEmail(email, password, turnstileToken);
2519
- promise.then(() => this.modal?.close()).catch((err) => {
2520
- this.modal?.resetTurnstile?.();
2521
- const msg = err instanceof Error ? err.message : String(err);
2522
- this.modal?.showError(msg || "Authentication failed");
2523
- this.emit("error", err instanceof Error ? err : new Error(msg));
2524
- });
3424
+ if (isSignUp) {
3425
+ this.signUpWithEmail(email, password, { turnstileToken }).then((result) => {
3426
+ if ("needsVerification" in result && result.needsVerification) {
3427
+ this.modal?.showVerificationInput(email, async (code) => {
3428
+ try {
3429
+ await this.verifyEmail(email, code);
3430
+ this.modal?.close();
3431
+ } catch (err) {
3432
+ const msg = err instanceof Error ? err.message : String(err);
3433
+ this.modal?.showError(msg || "Verification failed");
3434
+ }
3435
+ }, async () => {
3436
+ await this.resendVerificationCode(email);
3437
+ });
3438
+ } else {
3439
+ this.modal?.close();
3440
+ }
3441
+ }).catch((err) => {
3442
+ this.modal?.resetTurnstile?.();
3443
+ const msg = err instanceof Error ? err.message : String(err);
3444
+ this.modal?.showError(msg || "Authentication failed");
3445
+ this.emit("error", err instanceof Error ? err : new Error(msg));
3446
+ });
3447
+ } else {
3448
+ this.signInWithEmail(email, password, turnstileToken).then(() => this.modal?.close()).catch((err) => {
3449
+ this.modal?.resetTurnstile?.();
3450
+ const msg = err instanceof Error ? err.message : String(err);
3451
+ this.modal?.showError(msg || "Authentication failed");
3452
+ this.emit("error", err instanceof Error ? err : new Error(msg));
3453
+ });
3454
+ }
2525
3455
  },
2526
3456
  onClose: () => this.modal?.close(),
2527
3457
  onWeb3WalletSelect: async (walletId) => {
@@ -2953,6 +3883,7 @@ var Authon = class {
2953
3883
  export {
2954
3884
  Authon,
2955
3885
  AuthonMfaRequiredError,
3886
+ ProfileRenderer,
2956
3887
  generateQrSvg,
2957
3888
  getProviderButtonConfig,
2958
3889
  getStrings,