@authon/js 0.4.2 → 0.6.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.cjs CHANGED
@@ -22,8 +22,11 @@ var index_exports = {};
22
22
  __export(index_exports, {
23
23
  Authon: () => Authon,
24
24
  AuthonMfaRequiredError: () => AuthonMfaRequiredError,
25
+ ProfileRenderer: () => ProfileRenderer,
25
26
  generateQrSvg: () => generateQrSvg,
26
- getProviderButtonConfig: () => getProviderButtonConfig
27
+ getProviderButtonConfig: () => getProviderButtonConfig,
28
+ getStrings: () => getStrings,
29
+ translations: () => translations
27
30
  });
28
31
  module.exports = __toCommonJS(index_exports);
29
32
 
@@ -37,7 +40,7 @@ var AuthonMfaRequiredError = class extends Error {
37
40
  }
38
41
  };
39
42
 
40
- // ../shared/dist/index.js
43
+ // ../../node_modules/.pnpm/@authon+shared@0.3.0/node_modules/@authon/shared/dist/index.js
41
44
  var PROVIDER_DISPLAY_NAMES = {
42
45
  google: "Google",
43
46
  apple: "Apple",
@@ -100,6 +103,520 @@ function getProviderButtonConfig(provider) {
100
103
  };
101
104
  }
102
105
 
106
+ // src/i18n.ts
107
+ var translations = {
108
+ en: {
109
+ welcomeBack: "Welcome back",
110
+ createAccount: "Create your account",
111
+ alreadyHaveAccount: "Already have an account?",
112
+ dontHaveAccount: "Don't have an account?",
113
+ signIn: "Sign in",
114
+ signUp: "Sign up",
115
+ or: "or",
116
+ emailAddress: "Email address",
117
+ password: "Password",
118
+ passwordHint: "Must contain uppercase, lowercase, and a number (min 8 chars)",
119
+ continueWith: "Continue with",
120
+ connectWallet: "Connect Wallet",
121
+ magicLink: "Continue with Magic Link",
122
+ passkey: "Sign in with Passkey",
123
+ securedBy: "Secured by",
124
+ backToSignIn: "Back to sign in",
125
+ profile: "Profile",
126
+ editProfile: "Edit Profile",
127
+ displayName: "Display Name",
128
+ save: "Save",
129
+ signOut: "Sign Out",
130
+ sessions: "Active Sessions"
131
+ },
132
+ ko: {
133
+ welcomeBack: "\uB2E4\uC2DC \uC624\uC2E0 \uAC78 \uD658\uC601\uD569\uB2C8\uB2E4",
134
+ createAccount: "\uACC4\uC815 \uB9CC\uB4E4\uAE30",
135
+ alreadyHaveAccount: "\uC774\uBBF8 \uACC4\uC815\uC774 \uC788\uC73C\uC2E0\uAC00\uC694?",
136
+ dontHaveAccount: "\uACC4\uC815\uC774 \uC5C6\uC73C\uC2E0\uAC00\uC694?",
137
+ signIn: "\uB85C\uADF8\uC778",
138
+ signUp: "\uD68C\uC6D0\uAC00\uC785",
139
+ or: "\uB610\uB294",
140
+ emailAddress: "\uC774\uBA54\uC77C \uC8FC\uC18C",
141
+ password: "\uBE44\uBC00\uBC88\uD638",
142
+ passwordHint: "\uB300\uBB38\uC790, \uC18C\uBB38\uC790, \uC22B\uC790 \uD3EC\uD568 (\uCD5C\uC18C 8\uC790)",
143
+ continueWith: "(\uC73C)\uB85C \uACC4\uC18D\uD558\uAE30",
144
+ connectWallet: "\uC9C0\uAC11 \uC5F0\uACB0",
145
+ magicLink: "\uB9E4\uC9C1 \uB9C1\uD06C\uB85C \uACC4\uC18D\uD558\uAE30",
146
+ passkey: "\uD328\uC2A4\uD0A4\uB85C \uB85C\uADF8\uC778",
147
+ securedBy: "\uBCF4\uC548 \uC81C\uACF5",
148
+ backToSignIn: "\uB85C\uADF8\uC778\uC73C\uB85C \uB3CC\uC544\uAC00\uAE30",
149
+ profile: "\uD504\uB85C\uD544",
150
+ editProfile: "\uD504\uB85C\uD544 \uD3B8\uC9D1",
151
+ displayName: "\uD45C\uC2DC \uC774\uB984",
152
+ save: "\uC800\uC7A5",
153
+ signOut: "\uB85C\uADF8\uC544\uC6C3",
154
+ sessions: "\uD65C\uC131 \uC138\uC158"
155
+ },
156
+ ja: {
157
+ welcomeBack: "\u304A\u304B\u3048\u308A\u306A\u3055\u3044",
158
+ createAccount: "\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F5C\u6210",
159
+ alreadyHaveAccount: "\u3059\u3067\u306B\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u304A\u6301\u3061\u3067\u3059\u304B\uFF1F",
160
+ dontHaveAccount: "\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u304A\u6301\u3061\u3067\u306A\u3044\u3067\u3059\u304B\uFF1F",
161
+ signIn: "\u30ED\u30B0\u30A4\u30F3",
162
+ signUp: "\u65B0\u898F\u767B\u9332",
163
+ or: "\u307E\u305F\u306F",
164
+ emailAddress: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9",
165
+ password: "\u30D1\u30B9\u30EF\u30FC\u30C9",
166
+ passwordHint: "\u5927\u6587\u5B57\u3001\u5C0F\u6587\u5B57\u3001\u6570\u5B57\u3092\u542B\u3080\uFF088\u6587\u5B57\u4EE5\u4E0A\uFF09",
167
+ continueWith: "\u3067\u7D9A\u884C",
168
+ connectWallet: "\u30A6\u30A9\u30EC\u30C3\u30C8\u63A5\u7D9A",
169
+ magicLink: "\u30DE\u30B8\u30C3\u30AF\u30EA\u30F3\u30AF\u3067\u7D9A\u884C",
170
+ passkey: "\u30D1\u30B9\u30AD\u30FC\u3067\u30ED\u30B0\u30A4\u30F3",
171
+ securedBy: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u63D0\u4F9B",
172
+ backToSignIn: "\u30ED\u30B0\u30A4\u30F3\u306B\u623B\u308B",
173
+ profile: "\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB",
174
+ editProfile: "\u30D7\u30ED\u30D5\u30A3\u30FC\u30EB\u7DE8\u96C6",
175
+ displayName: "\u8868\u793A\u540D",
176
+ save: "\u4FDD\u5B58",
177
+ signOut: "\u30B5\u30A4\u30F3\u30A2\u30A6\u30C8",
178
+ sessions: "\u30A2\u30AF\u30C6\u30A3\u30D6\u30BB\u30C3\u30B7\u30E7\u30F3"
179
+ },
180
+ "zh-CN": {
181
+ welcomeBack: "\u6B22\u8FCE\u56DE\u6765",
182
+ createAccount: "\u521B\u5EFA\u8D26\u6237",
183
+ alreadyHaveAccount: "\u5DF2\u6709\u8D26\u6237\uFF1F",
184
+ dontHaveAccount: "\u6CA1\u6709\u8D26\u6237\uFF1F",
185
+ signIn: "\u767B\u5F55",
186
+ signUp: "\u6CE8\u518C",
187
+ or: "\u6216",
188
+ emailAddress: "\u90AE\u7BB1\u5730\u5740",
189
+ password: "\u5BC6\u7801",
190
+ passwordHint: "\u9700\u5305\u542B\u5927\u5199\u3001\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57\uFF08\u81F3\u5C118\u4F4D\uFF09",
191
+ continueWith: "\u7EE7\u7EED\u4F7F\u7528",
192
+ connectWallet: "\u8FDE\u63A5\u94B1\u5305",
193
+ magicLink: "\u4F7F\u7528\u9B54\u6CD5\u94FE\u63A5\u7EE7\u7EED",
194
+ passkey: "\u4F7F\u7528\u901A\u884C\u5BC6\u94A5\u767B\u5F55",
195
+ securedBy: "\u5B89\u5168\u4FDD\u969C",
196
+ backToSignIn: "\u8FD4\u56DE\u767B\u5F55",
197
+ profile: "\u4E2A\u4EBA\u8D44\u6599",
198
+ editProfile: "\u7F16\u8F91\u8D44\u6599",
199
+ displayName: "\u663E\u793A\u540D\u79F0",
200
+ save: "\u4FDD\u5B58",
201
+ signOut: "\u9000\u51FA\u767B\u5F55",
202
+ sessions: "\u6D3B\u8DC3\u4F1A\u8BDD"
203
+ },
204
+ "zh-TW": {
205
+ welcomeBack: "\u6B61\u8FCE\u56DE\u4F86",
206
+ createAccount: "\u5EFA\u7ACB\u5E33\u6236",
207
+ alreadyHaveAccount: "\u5DF2\u6709\u5E33\u6236\uFF1F",
208
+ dontHaveAccount: "\u6C92\u6709\u5E33\u6236\uFF1F",
209
+ signIn: "\u767B\u5165",
210
+ signUp: "\u8A3B\u518A",
211
+ or: "\u6216",
212
+ emailAddress: "\u96FB\u5B50\u90F5\u4EF6",
213
+ password: "\u5BC6\u78BC",
214
+ passwordHint: "\u9700\u5305\u542B\u5927\u5BEB\u3001\u5C0F\u5BEB\u5B57\u6BCD\u548C\u6578\u5B57\uFF08\u81F3\u5C118\u4F4D\uFF09",
215
+ continueWith: "\u7E7C\u7E8C\u4F7F\u7528",
216
+ connectWallet: "\u9023\u63A5\u9322\u5305",
217
+ magicLink: "\u4F7F\u7528\u9B54\u6CD5\u9023\u7D50\u7E7C\u7E8C",
218
+ passkey: "\u4F7F\u7528\u901A\u884C\u91D1\u9470\u767B\u5165",
219
+ securedBy: "\u5B89\u5168\u4FDD\u969C",
220
+ backToSignIn: "\u8FD4\u56DE\u767B\u5165",
221
+ profile: "\u500B\u4EBA\u8CC7\u6599",
222
+ editProfile: "\u7DE8\u8F2F\u8CC7\u6599",
223
+ displayName: "\u986F\u793A\u540D\u7A31",
224
+ save: "\u5132\u5B58",
225
+ signOut: "\u767B\u51FA",
226
+ sessions: "\u6D3B\u8E8D\u5DE5\u4F5C\u968E\u6BB5"
227
+ },
228
+ "pt-BR": {
229
+ welcomeBack: "Bem-vindo de volta",
230
+ createAccount: "Crie sua conta",
231
+ alreadyHaveAccount: "Ja tem uma conta?",
232
+ dontHaveAccount: "Nao tem uma conta?",
233
+ signIn: "Entrar",
234
+ signUp: "Cadastrar",
235
+ or: "ou",
236
+ emailAddress: "Endereco de e-mail",
237
+ password: "Senha",
238
+ passwordHint: "Deve conter maiusculas, minusculas e numeros (min 8 caracteres)",
239
+ continueWith: "Continuar com",
240
+ connectWallet: "Conectar carteira",
241
+ magicLink: "Continuar com Magic Link",
242
+ passkey: "Entrar com Passkey",
243
+ securedBy: "Protegido por",
244
+ backToSignIn: "Voltar ao login",
245
+ profile: "Perfil",
246
+ editProfile: "Editar perfil",
247
+ displayName: "Nome de exibicao",
248
+ save: "Salvar",
249
+ signOut: "Sair",
250
+ sessions: "Sessoes ativas"
251
+ },
252
+ es: {
253
+ welcomeBack: "Bienvenido de nuevo",
254
+ createAccount: "Crea tu cuenta",
255
+ alreadyHaveAccount: "Ya tienes una cuenta?",
256
+ dontHaveAccount: "No tienes una cuenta?",
257
+ signIn: "Iniciar sesion",
258
+ signUp: "Registrarse",
259
+ or: "o",
260
+ emailAddress: "Correo electronico",
261
+ password: "Contrasena",
262
+ passwordHint: "Debe contener mayusculas, minusculas y numeros (min 8 caracteres)",
263
+ continueWith: "Continuar con",
264
+ connectWallet: "Conectar billetera",
265
+ magicLink: "Continuar con Magic Link",
266
+ passkey: "Iniciar con Passkey",
267
+ securedBy: "Protegido por",
268
+ backToSignIn: "Volver al inicio de sesion",
269
+ profile: "Perfil",
270
+ editProfile: "Editar perfil",
271
+ displayName: "Nombre de visualizacion",
272
+ save: "Guardar",
273
+ signOut: "Cerrar sesion",
274
+ sessions: "Sesiones activas"
275
+ },
276
+ de: {
277
+ welcomeBack: "Willkommen zuruck",
278
+ createAccount: "Konto erstellen",
279
+ alreadyHaveAccount: "Bereits ein Konto?",
280
+ dontHaveAccount: "Noch kein Konto?",
281
+ signIn: "Anmelden",
282
+ signUp: "Registrieren",
283
+ or: "oder",
284
+ emailAddress: "E-Mail-Adresse",
285
+ password: "Passwort",
286
+ passwordHint: "Gross-/Kleinbuchstaben und Zahl erforderlich (mind. 8 Zeichen)",
287
+ continueWith: "Weiter mit",
288
+ connectWallet: "Wallet verbinden",
289
+ magicLink: "Weiter mit Magic Link",
290
+ passkey: "Mit Passkey anmelden",
291
+ securedBy: "Gesichert durch",
292
+ backToSignIn: "Zuruck zur Anmeldung",
293
+ profile: "Profil",
294
+ editProfile: "Profil bearbeiten",
295
+ displayName: "Anzeigename",
296
+ save: "Speichern",
297
+ signOut: "Abmelden",
298
+ sessions: "Aktive Sitzungen"
299
+ },
300
+ fr: {
301
+ welcomeBack: "Bon retour",
302
+ createAccount: "Creez votre compte",
303
+ alreadyHaveAccount: "Vous avez deja un compte ?",
304
+ dontHaveAccount: "Vous n'avez pas de compte ?",
305
+ signIn: "Se connecter",
306
+ signUp: "S'inscrire",
307
+ or: "ou",
308
+ emailAddress: "Adresse e-mail",
309
+ password: "Mot de passe",
310
+ passwordHint: "Doit contenir majuscules, minuscules et chiffres (min 8 caracteres)",
311
+ continueWith: "Continuer avec",
312
+ connectWallet: "Connecter le portefeuille",
313
+ magicLink: "Continuer avec Magic Link",
314
+ passkey: "Se connecter avec Passkey",
315
+ securedBy: "Securise par",
316
+ backToSignIn: "Retour a la connexion",
317
+ profile: "Profil",
318
+ editProfile: "Modifier le profil",
319
+ displayName: "Nom d'affichage",
320
+ save: "Enregistrer",
321
+ signOut: "Se deconnecter",
322
+ sessions: "Sessions actives"
323
+ },
324
+ hi: {
325
+ welcomeBack: "\u0935\u093E\u092A\u0938\u0940 \u092A\u0930 \u0938\u094D\u0935\u093E\u0917\u0924 \u0939\u0948",
326
+ createAccount: "\u0905\u092A\u0928\u093E \u0916\u093E\u0924\u093E \u092C\u0928\u093E\u090F\u0902",
327
+ alreadyHaveAccount: "\u092A\u0939\u0932\u0947 \u0938\u0947 \u0916\u093E\u0924\u093E \u0939\u0948?",
328
+ dontHaveAccount: "\u0916\u093E\u0924\u093E \u0928\u0939\u0940\u0902 \u0939\u0948?",
329
+ signIn: "\u0938\u093E\u0907\u0928 \u0907\u0928",
330
+ signUp: "\u0938\u093E\u0907\u0928 \u0905\u092A",
331
+ or: "\u092F\u093E",
332
+ emailAddress: "\u0908\u092E\u0947\u0932 \u092A\u0924\u093E",
333
+ password: "\u092A\u093E\u0938\u0935\u0930\u094D\u0921",
334
+ passwordHint: "\u092C\u0921\u093C\u0947, \u091B\u094B\u091F\u0947 \u0905\u0915\u094D\u0937\u0930 \u0914\u0930 \u0938\u0902\u0916\u094D\u092F\u093E \u0906\u0935\u0936\u094D\u092F\u0915 (\u0915\u092E \u0938\u0947 \u0915\u092E 8 \u0905\u0915\u094D\u0937\u0930)",
335
+ continueWith: "\u0938\u0947 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
336
+ connectWallet: "\u0935\u0949\u0932\u0947\u091F \u0915\u0928\u0947\u0915\u094D\u091F \u0915\u0930\u0947\u0902",
337
+ magicLink: "\u092E\u0948\u091C\u093F\u0915 \u0932\u093F\u0902\u0915 \u0938\u0947 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
338
+ passkey: "\u092A\u093E\u0938\u0915\u0940 \u0938\u0947 \u0938\u093E\u0907\u0928 \u0907\u0928",
339
+ securedBy: "\u0938\u0941\u0930\u0915\u094D\u0937\u093E \u092A\u094D\u0930\u0926\u093E\u0924\u093E",
340
+ backToSignIn: "\u0938\u093E\u0907\u0928 \u0907\u0928 \u092A\u0930 \u0935\u093E\u092A\u0938 \u091C\u093E\u090F\u0902",
341
+ profile: "\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932",
342
+ editProfile: "\u092A\u094D\u0930\u094B\u092B\u093C\u093E\u0907\u0932 \u0938\u0902\u092A\u093E\u0926\u093F\u0924 \u0915\u0930\u0947\u0902",
343
+ displayName: "\u092A\u094D\u0930\u0926\u0930\u094D\u0936\u0928 \u0928\u093E\u092E",
344
+ save: "\u0938\u0939\u0947\u091C\u0947\u0902",
345
+ signOut: "\u0938\u093E\u0907\u0928 \u0906\u0909\u091F",
346
+ sessions: "\u0938\u0915\u094D\u0930\u093F\u092F \u0938\u0924\u094D\u0930"
347
+ },
348
+ tr: {
349
+ welcomeBack: "Tekrar hos geldiniz",
350
+ createAccount: "Hesap olusturun",
351
+ alreadyHaveAccount: "Zaten bir hesabiniz var mi?",
352
+ dontHaveAccount: "Hesabiniz yok mu?",
353
+ signIn: "Giris yap",
354
+ signUp: "Kaydol",
355
+ or: "veya",
356
+ emailAddress: "E-posta adresi",
357
+ password: "Sifre",
358
+ passwordHint: "Buyuk, kucuk harf ve rakam icermeli (en az 8 karakter)",
359
+ continueWith: "ile devam et",
360
+ connectWallet: "Cuzdan bagla",
361
+ magicLink: "Magic Link ile devam et",
362
+ passkey: "Passkey ile giris yap",
363
+ securedBy: "Guvenlik saglayici",
364
+ backToSignIn: "Girise don",
365
+ profile: "Profil",
366
+ editProfile: "Profili duzenle",
367
+ displayName: "Goruntu adi",
368
+ save: "Kaydet",
369
+ signOut: "Cikis yap",
370
+ sessions: "Aktif oturumlar"
371
+ },
372
+ id: {
373
+ welcomeBack: "Selamat datang kembali",
374
+ createAccount: "Buat akun Anda",
375
+ alreadyHaveAccount: "Sudah punya akun?",
376
+ dontHaveAccount: "Belum punya akun?",
377
+ signIn: "Masuk",
378
+ signUp: "Daftar",
379
+ or: "atau",
380
+ emailAddress: "Alamat email",
381
+ password: "Kata sandi",
382
+ passwordHint: "Harus mengandung huruf besar, kecil, dan angka (min 8 karakter)",
383
+ continueWith: "Lanjutkan dengan",
384
+ connectWallet: "Hubungkan dompet",
385
+ magicLink: "Lanjutkan dengan Magic Link",
386
+ passkey: "Masuk dengan Passkey",
387
+ securedBy: "Diamankan oleh",
388
+ backToSignIn: "Kembali ke login",
389
+ profile: "Profil",
390
+ editProfile: "Edit profil",
391
+ displayName: "Nama tampilan",
392
+ save: "Simpan",
393
+ signOut: "Keluar",
394
+ sessions: "Sesi aktif"
395
+ },
396
+ vi: {
397
+ welcomeBack: "Chao mung tro lai",
398
+ createAccount: "Tao tai khoan",
399
+ alreadyHaveAccount: "Da co tai khoan?",
400
+ dontHaveAccount: "Chua co tai khoan?",
401
+ signIn: "Dang nhap",
402
+ signUp: "Dang ky",
403
+ or: "hoac",
404
+ emailAddress: "Dia chi email",
405
+ password: "Mat khau",
406
+ passwordHint: "Can chu hoa, chu thuong va so (toi thieu 8 ky tu)",
407
+ continueWith: "Tiep tuc voi",
408
+ connectWallet: "Ket noi vi",
409
+ magicLink: "Tiep tuc voi Magic Link",
410
+ passkey: "Dang nhap voi Passkey",
411
+ securedBy: "Bao mat boi",
412
+ backToSignIn: "Quay lai dang nhap",
413
+ profile: "Ho so",
414
+ editProfile: "Chinh sua ho so",
415
+ displayName: "Ten hien thi",
416
+ save: "Luu",
417
+ signOut: "Dang xuat",
418
+ sessions: "Phien dang nhap hoat dong"
419
+ },
420
+ th: {
421
+ welcomeBack: "\u0E22\u0E34\u0E19\u0E14\u0E35\u0E15\u0E49\u0E2D\u0E19\u0E23\u0E31\u0E1A\u0E01\u0E25\u0E31\u0E1A",
422
+ createAccount: "\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E31\u0E0D\u0E0A\u0E35",
423
+ alreadyHaveAccount: "\u0E21\u0E35\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27?",
424
+ dontHaveAccount: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E1A\u0E31\u0E0D\u0E0A\u0E35?",
425
+ signIn: "\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
426
+ signUp: "\u0E2A\u0E21\u0E31\u0E04\u0E23\u0E2A\u0E21\u0E32\u0E0A\u0E34\u0E01",
427
+ or: "\u0E2B\u0E23\u0E37\u0E2D",
428
+ emailAddress: "\u0E2D\u0E35\u0E40\u0E21\u0E25",
429
+ password: "\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19",
430
+ passwordHint: "\u0E15\u0E49\u0E2D\u0E07\u0E21\u0E35\u0E15\u0E31\u0E27\u0E1E\u0E34\u0E21\u0E1E\u0E4C\u0E43\u0E2B\u0E0D\u0E48 \u0E15\u0E31\u0E27\u0E1E\u0E34\u0E21\u0E1E\u0E4C\u0E40\u0E25\u0E47\u0E01 \u0E41\u0E25\u0E30\u0E15\u0E31\u0E27\u0E40\u0E25\u0E02 (\u0E2D\u0E22\u0E48\u0E32\u0E07\u0E19\u0E49\u0E2D\u0E22 8 \u0E15\u0E31\u0E27)",
431
+ continueWith: "\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E14\u0E49\u0E27\u0E22",
432
+ connectWallet: "\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E01\u0E23\u0E30\u0E40\u0E1B\u0E4B\u0E32",
433
+ magicLink: "\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E14\u0E49\u0E27\u0E22 Magic Link",
434
+ passkey: "\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22 Passkey",
435
+ securedBy: "\u0E23\u0E31\u0E01\u0E29\u0E32\u0E04\u0E27\u0E32\u0E21\u0E1B\u0E25\u0E2D\u0E14\u0E20\u0E31\u0E22\u0E42\u0E14\u0E22",
436
+ backToSignIn: "\u0E01\u0E25\u0E31\u0E1A\u0E44\u0E1B\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
437
+ profile: "\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C",
438
+ editProfile: "\u0E41\u0E01\u0E49\u0E44\u0E02\u0E42\u0E1B\u0E23\u0E44\u0E1F\u0E25\u0E4C",
439
+ displayName: "\u0E0A\u0E37\u0E48\u0E2D\u0E17\u0E35\u0E48\u0E41\u0E2A\u0E14\u0E07",
440
+ save: "\u0E1A\u0E31\u0E19\u0E17\u0E36\u0E01",
441
+ signOut: "\u0E2D\u0E2D\u0E01\u0E08\u0E32\u0E01\u0E23\u0E30\u0E1A\u0E1A",
442
+ sessions: "\u0E40\u0E0B\u0E2A\u0E0A\u0E31\u0E19\u0E17\u0E35\u0E48\u0E43\u0E0A\u0E49\u0E07\u0E32\u0E19\u0E2D\u0E22\u0E39\u0E48"
443
+ },
444
+ ru: {
445
+ welcomeBack: "\u0421 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0438\u0435\u043C",
446
+ createAccount: "\u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u0430\u043A\u043A\u0430\u0443\u043D\u0442",
447
+ alreadyHaveAccount: "\u0423\u0436\u0435 \u0435\u0441\u0442\u044C \u0430\u043A\u043A\u0430\u0443\u043D\u0442?",
448
+ dontHaveAccount: "\u041D\u0435\u0442 \u0430\u043A\u043A\u0430\u0443\u043D\u0442\u0430?",
449
+ signIn: "\u0412\u043E\u0439\u0442\u0438",
450
+ signUp: "\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F",
451
+ or: "\u0438\u043B\u0438",
452
+ emailAddress: "\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F \u043F\u043E\u0447\u0442\u0430",
453
+ password: "\u041F\u0430\u0440\u043E\u043B\u044C",
454
+ passwordHint: "\u0417\u0430\u0433\u043B\u0430\u0432\u043D\u044B\u0435, \u0441\u0442\u0440\u043E\u0447\u043D\u044B\u0435 \u0431\u0443\u043A\u0432\u044B \u0438 \u0446\u0438\u0444\u0440\u044B (\u043C\u0438\u043D. 8 \u0441\u0438\u043C\u0432\u043E\u043B\u043E\u0432)",
455
+ continueWith: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441",
456
+ connectWallet: "\u041F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043A\u043E\u0448\u0435\u043B\u0435\u043A",
457
+ magicLink: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441 Magic Link",
458
+ passkey: "\u0412\u043E\u0439\u0442\u0438 \u0441 Passkey",
459
+ securedBy: "\u0417\u0430\u0449\u0438\u0449\u0435\u043D\u043E",
460
+ backToSignIn: "\u0412\u0435\u0440\u043D\u0443\u0442\u044C\u0441\u044F \u043A \u0432\u0445\u043E\u0434\u0443",
461
+ profile: "\u041F\u0440\u043E\u0444\u0438\u043B\u044C",
462
+ editProfile: "\u0420\u0435\u0434\u0430\u043A\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043F\u0440\u043E\u0444\u0438\u043B\u044C",
463
+ displayName: "\u041E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u043C\u043E\u0435 \u0438\u043C\u044F",
464
+ save: "\u0421\u043E\u0445\u0440\u0430\u043D\u0438\u0442\u044C",
465
+ signOut: "\u0412\u044B\u0439\u0442\u0438",
466
+ sessions: "\u0410\u043A\u0442\u0438\u0432\u043D\u044B\u0435 \u0441\u0435\u0430\u043D\u0441\u044B"
467
+ },
468
+ it: {
469
+ welcomeBack: "Bentornato",
470
+ createAccount: "Crea il tuo account",
471
+ alreadyHaveAccount: "Hai gia un account?",
472
+ dontHaveAccount: "Non hai un account?",
473
+ signIn: "Accedi",
474
+ signUp: "Registrati",
475
+ or: "o",
476
+ emailAddress: "Indirizzo email",
477
+ password: "Password",
478
+ passwordHint: "Deve contenere maiuscole, minuscole e numeri (min 8 caratteri)",
479
+ continueWith: "Continua con",
480
+ connectWallet: "Connetti portafoglio",
481
+ magicLink: "Continua con Magic Link",
482
+ passkey: "Accedi con Passkey",
483
+ securedBy: "Protetto da",
484
+ backToSignIn: "Torna all'accesso",
485
+ profile: "Profilo",
486
+ editProfile: "Modifica profilo",
487
+ displayName: "Nome visualizzato",
488
+ save: "Salva",
489
+ signOut: "Esci",
490
+ sessions: "Sessioni attive"
491
+ },
492
+ pl: {
493
+ welcomeBack: "Witaj ponownie",
494
+ createAccount: "Utworz konto",
495
+ alreadyHaveAccount: "Masz juz konto?",
496
+ dontHaveAccount: "Nie masz konta?",
497
+ signIn: "Zaloguj sie",
498
+ signUp: "Zarejestruj sie",
499
+ or: "lub",
500
+ emailAddress: "Adres e-mail",
501
+ password: "Haslo",
502
+ passwordHint: "Wielkie, male litery i cyfry (min 8 znakow)",
503
+ continueWith: "Kontynuuj z",
504
+ connectWallet: "Polacz portfel",
505
+ magicLink: "Kontynuuj z Magic Link",
506
+ passkey: "Zaloguj sie z Passkey",
507
+ securedBy: "Zabezpieczone przez",
508
+ backToSignIn: "Powrot do logowania",
509
+ profile: "Profil",
510
+ editProfile: "Edytuj profil",
511
+ displayName: "Nazwa wyswietlana",
512
+ save: "Zapisz",
513
+ signOut: "Wyloguj sie",
514
+ sessions: "Aktywne sesje"
515
+ },
516
+ nl: {
517
+ welcomeBack: "Welkom terug",
518
+ createAccount: "Maak je account aan",
519
+ alreadyHaveAccount: "Heb je al een account?",
520
+ dontHaveAccount: "Nog geen account?",
521
+ signIn: "Inloggen",
522
+ signUp: "Registreren",
523
+ or: "of",
524
+ emailAddress: "E-mailadres",
525
+ password: "Wachtwoord",
526
+ passwordHint: "Hoofdletters, kleine letters en cijfers vereist (min 8 tekens)",
527
+ continueWith: "Doorgaan met",
528
+ connectWallet: "Portemonnee verbinden",
529
+ magicLink: "Doorgaan met Magic Link",
530
+ passkey: "Inloggen met Passkey",
531
+ securedBy: "Beveiligd door",
532
+ backToSignIn: "Terug naar inloggen",
533
+ profile: "Profiel",
534
+ editProfile: "Profiel bewerken",
535
+ displayName: "Weergavenaam",
536
+ save: "Opslaan",
537
+ signOut: "Uitloggen",
538
+ sessions: "Actieve sessies"
539
+ },
540
+ ar: {
541
+ welcomeBack: "\u0645\u0631\u062D\u0628\u064B\u0627 \u0628\u0639\u0648\u062F\u062A\u0643",
542
+ createAccount: "\u0623\u0646\u0634\u0626 \u062D\u0633\u0627\u0628\u0643",
543
+ alreadyHaveAccount: "\u0644\u062F\u064A\u0643 \u062D\u0633\u0627\u0628 \u0628\u0627\u0644\u0641\u0639\u0644\u061F",
544
+ dontHaveAccount: "\u0644\u064A\u0633 \u0644\u062F\u064A\u0643 \u062D\u0633\u0627\u0628\u061F",
545
+ signIn: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644",
546
+ signUp: "\u0625\u0646\u0634\u0627\u0621 \u062D\u0633\u0627\u0628",
547
+ or: "\u0623\u0648",
548
+ emailAddress: "\u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A",
549
+ password: "\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631",
550
+ passwordHint: "\u064A\u062C\u0628 \u0623\u0646 \u062A\u062D\u062A\u0648\u064A \u0639\u0644\u0649 \u0623\u062D\u0631\u0641 \u0643\u0628\u064A\u0631\u0629 \u0648\u0635\u063A\u064A\u0631\u0629 \u0648\u0623\u0631\u0642\u0627\u0645 (8 \u0623\u062D\u0631\u0641 \u0639\u0644\u0649 \u0627\u0644\u0623\u0642\u0644)",
551
+ continueWith: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645",
552
+ connectWallet: "\u0631\u0628\u0637 \u0627\u0644\u0645\u062D\u0641\u0638\u0629",
553
+ magicLink: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Magic Link",
554
+ passkey: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Passkey",
555
+ securedBy: "\u0645\u062D\u0645\u064A \u0628\u0648\u0627\u0633\u0637\u0629",
556
+ backToSignIn: "\u0627\u0644\u0639\u0648\u062F\u0629 \u0644\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644",
557
+ profile: "\u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0634\u062E\u0635\u064A",
558
+ editProfile: "\u062A\u0639\u062F\u064A\u0644 \u0627\u0644\u0645\u0644\u0641 \u0627\u0644\u0634\u062E\u0635\u064A",
559
+ displayName: "\u0627\u0644\u0627\u0633\u0645 \u0627\u0644\u0645\u0639\u0631\u0648\u0636",
560
+ save: "\u062D\u0641\u0638",
561
+ signOut: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062E\u0631\u0648\u062C",
562
+ sessions: "\u0627\u0644\u062C\u0644\u0633\u0627\u062A \u0627\u0644\u0646\u0634\u0637\u0629"
563
+ },
564
+ sv: {
565
+ welcomeBack: "Valkommen tillbaka",
566
+ createAccount: "Skapa ditt konto",
567
+ alreadyHaveAccount: "Har du redan ett konto?",
568
+ dontHaveAccount: "Har du inget konto?",
569
+ signIn: "Logga in",
570
+ signUp: "Registrera dig",
571
+ or: "eller",
572
+ emailAddress: "E-postadress",
573
+ password: "Losenord",
574
+ passwordHint: "Stora, sma bokstaver och siffror kravs (minst 8 tecken)",
575
+ continueWith: "Fortsatt med",
576
+ connectWallet: "Anslut planbok",
577
+ magicLink: "Fortsatt med Magic Link",
578
+ passkey: "Logga in med Passkey",
579
+ securedBy: "Sakrad av",
580
+ backToSignIn: "Tillbaka till inloggning",
581
+ profile: "Profil",
582
+ editProfile: "Redigera profil",
583
+ displayName: "Visningsnamn",
584
+ save: "Spara",
585
+ signOut: "Logga ut",
586
+ sessions: "Aktiva sessioner"
587
+ },
588
+ uk: {
589
+ welcomeBack: "\u0417 \u043F\u043E\u0432\u0435\u0440\u043D\u0435\u043D\u043D\u044F\u043C",
590
+ createAccount: "\u0421\u0442\u0432\u043E\u0440\u0456\u0442\u044C \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441",
591
+ alreadyHaveAccount: "\u0412\u0436\u0435 \u0454 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441?",
592
+ dontHaveAccount: "\u041D\u0435\u043C\u0430\u0454 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443?",
593
+ signIn: "\u0423\u0432\u0456\u0439\u0442\u0438",
594
+ signUp: "\u0417\u0430\u0440\u0435\u0454\u0441\u0442\u0440\u0443\u0432\u0430\u0442\u0438\u0441\u044F",
595
+ or: "\u0430\u0431\u043E",
596
+ emailAddress: "\u0415\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430 \u043F\u043E\u0448\u0442\u0430",
597
+ password: "\u041F\u0430\u0440\u043E\u043B\u044C",
598
+ passwordHint: "\u0412\u0435\u043B\u0438\u043A\u0456, \u043C\u0430\u043B\u0456 \u043B\u0456\u0442\u0435\u0440\u0438 \u0442\u0430 \u0446\u0438\u0444\u0440\u0438 (\u043C\u0456\u043D. 8 \u0441\u0438\u043C\u0432\u043E\u043B\u0456\u0432)",
599
+ continueWith: "\u041F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u0437",
600
+ connectWallet: "\u041F\u0456\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u0438 \u0433\u0430\u043C\u0430\u043D\u0435\u0446\u044C",
601
+ magicLink: "\u041F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u0437 Magic Link",
602
+ passkey: "\u0423\u0432\u0456\u0439\u0442\u0438 \u0437 Passkey",
603
+ securedBy: "\u0417\u0430\u0445\u0438\u0449\u0435\u043D\u043E",
604
+ backToSignIn: "\u041F\u043E\u0432\u0435\u0440\u043D\u0443\u0442\u0438\u0441\u044F \u0434\u043E \u0432\u0445\u043E\u0434\u0443",
605
+ profile: "\u041F\u0440\u043E\u0444\u0456\u043B\u044C",
606
+ editProfile: "\u0420\u0435\u0434\u0430\u0433\u0443\u0432\u0430\u0442\u0438 \u043F\u0440\u043E\u0444\u0456\u043B\u044C",
607
+ displayName: "\u0412\u0456\u0434\u043E\u0431\u0440\u0430\u0436\u0443\u0432\u0430\u043D\u0435 \u0456\u043C'\u044F",
608
+ save: "\u0417\u0431\u0435\u0440\u0435\u0433\u0442\u0438",
609
+ signOut: "\u0412\u0438\u0439\u0442\u0438",
610
+ sessions: "\u0410\u043A\u0442\u0438\u0432\u043D\u0456 \u0441\u0435\u0430\u043D\u0441\u0438"
611
+ }
612
+ };
613
+ function getStrings(locale) {
614
+ if (locale in translations) return translations[locale];
615
+ const lang = locale.split("-")[0].split("_")[0];
616
+ if (lang in translations) return translations[lang];
617
+ return translations.en;
618
+ }
619
+
103
620
  // src/modal.ts
104
621
  function hexToRgba(hex, alpha) {
105
622
  const h = hex.replace("#", "");
@@ -155,6 +672,8 @@ var ModalRenderer = class {
155
672
  turnstileWidgetId = null;
156
673
  turnstileToken = "";
157
674
  turnstileWrapper = null;
675
+ // i18n
676
+ t;
158
677
  // Dev Teleport (test mode)
159
678
  isTestMode = false;
160
679
  onDevTeleport = null;
@@ -164,6 +683,7 @@ var ModalRenderer = class {
164
683
  this.branding = { ...DEFAULT_BRANDING, ...options.branding };
165
684
  this.captchaSiteKey = options.captchaSiteKey || "";
166
685
  this.isTestMode = options.isTestMode || false;
686
+ this.t = getStrings(options.locale || "en");
167
687
  this.onDevTeleport = options.onDevTeleport || null;
168
688
  this.onProviderClick = options.onProviderClick;
169
689
  this.onEmailSubmit = options.onEmailSubmit;
@@ -435,9 +955,9 @@ var ModalRenderer = class {
435
955
  buildInnerContent(view) {
436
956
  const b = this.branding;
437
957
  const isSignUp = view === "signUp";
438
- const title = isSignUp ? "Create your account" : "Welcome back";
439
- const subtitle = isSignUp ? "Already have an account?" : "Don't have an account?";
440
- const subtitleLink = isSignUp ? "Sign in" : "Sign up";
958
+ const title = isSignUp ? this.t.createAccount : this.t.welcomeBack;
959
+ const subtitle = isSignUp ? this.t.alreadyHaveAccount : this.t.dontHaveAccount;
960
+ const subtitleLink = isSignUp ? this.t.signIn : this.t.signUp;
441
961
  const dark = this.isDark();
442
962
  const showProviders = !isSignUp;
443
963
  const providerButtons = showProviders ? this.enabledProviders.filter((p) => !b.hiddenProviders?.includes(p)).map((p) => {
@@ -451,12 +971,12 @@ var ModalRenderer = class {
451
971
  </button>`;
452
972
  }).join("") : "";
453
973
  const hasVisibleProviders = showProviders && this.enabledProviders.filter((p) => !b.hiddenProviders?.includes(p)).length > 0;
454
- const divider = hasVisibleProviders && b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>or</span></div>` : "";
974
+ const divider = hasVisibleProviders && b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>${this.t.or}</span></div>` : "";
455
975
  const emailForm = b.showEmailPassword !== false ? `<form class="email-form" id="email-form">
456
- <input type="email" placeholder="Email address" name="email" required class="input" autocomplete="email" />
457
- <input type="password" placeholder="Password" name="password" required class="input" autocomplete="${isSignUp ? "new-password" : "current-password"}" />
458
- ${isSignUp ? '<p class="password-hint">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ""}
459
- <button type="submit" class="submit-btn">${isSignUp ? "Sign up" : "Sign in"}</button>
976
+ <input type="email" placeholder="${this.t.emailAddress}" name="email" required class="input" autocomplete="email" />
977
+ <input type="password" placeholder="${this.t.password}" name="password" required class="input" autocomplete="${isSignUp ? "new-password" : "current-password"}" />
978
+ ${isSignUp ? `<p class="password-hint">${this.t.passwordHint}</p>` : ""}
979
+ <button type="submit" class="submit-btn">${isSignUp ? this.t.signUp : this.t.signIn}</button>
460
980
  </form>` : "";
461
981
  const hasMethodAbove = showProviders && this.enabledProviders.length > 0 || b.showEmailPassword !== false;
462
982
  const hasMethodBelow = b.showWeb3 || b.showPasswordless || b.showPasskey;
@@ -467,7 +987,7 @@ var ModalRenderer = class {
467
987
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
468
988
  <path d="M21 12V7H5a2 2 0 0 1 0-4h14v4"/><path d="M3 5v14a2 2 0 0 0 2 2h16v-5"/><path d="M18 12a2 2 0 0 0 0 4h4v-4h-4z"/>
469
989
  </svg>
470
- <span>Connect Wallet</span>
990
+ <span>${this.t.connectWallet}</span>
471
991
  </button>`);
472
992
  }
473
993
  if (b.showPasswordless) {
@@ -475,7 +995,7 @@ var ModalRenderer = class {
475
995
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
476
996
  <path d="M10 13a5 5 0 0 0 7.54.54l3-3a5 5 0 0 0-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 0 0-7.54-.54l-3 3a5 5 0 0 0 7.07 7.07l1.71-1.71"/>
477
997
  </svg>
478
- <span>Continue with Magic Link</span>
998
+ <span>${this.t.magicLink}</span>
479
999
  </button>`);
480
1000
  }
481
1001
  if (b.showPasskey) {
@@ -483,7 +1003,7 @@ var ModalRenderer = class {
483
1003
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
484
1004
  <circle cx="10" cy="7" r="4"/><path d="M10.3 15H7a4 4 0 0 0-4 4v2"/><path d="M21.7 13.3 19 11"/><path d="m21 15-2.5-1.5"/><path d="m17 17 2.5-1.5"/><path d="M22 9v6a1 1 0 0 1-1 1h-.5"/><circle cx="18" cy="9" r="3"/>
485
1005
  </svg>
486
- <span>Sign in with Passkey</span>
1006
+ <span>${this.t.passkey}</span>
487
1007
  </button>`);
488
1008
  }
489
1009
  const authMethods = methodButtons.length > 0 ? `<div class="auth-methods">${methodButtons.join("")}</div>` : "";
@@ -519,7 +1039,7 @@ var ModalRenderer = class {
519
1039
  <button type="button" id="dev-teleport-btn" class="dev-teleport-btn">Go</button>
520
1040
  </div>
521
1041
  </div>` : ""}
522
- ${b.showSecuredBy !== false ? `<div class="secured-by">Secured by <a href="https://authon.dev" target="_blank" rel="noopener noreferrer" class="secured-link">Authon</a></div>` : ""}
1042
+ ${b.showSecuredBy !== false ? `<div class="secured-by">${this.t.securedBy} <a href="https://authon.dev" target="_blank" rel="noopener noreferrer" class="secured-link">Authon</a></div>` : ""}
523
1043
  `;
524
1044
  }
525
1045
  renderTurnstile() {
@@ -1211,6 +1731,676 @@ var ModalRenderer = class {
1211
1731
  }
1212
1732
  };
1213
1733
 
1734
+ // src/profile.ts
1735
+ function hexToRgba2(hex, alpha) {
1736
+ const h = hex.replace("#", "");
1737
+ const r = parseInt(h.substring(0, 2), 16);
1738
+ const g = parseInt(h.substring(2, 4), 16);
1739
+ const b = parseInt(h.substring(4, 6), 16);
1740
+ return `rgba(${r},${g},${b},${alpha})`;
1741
+ }
1742
+ function formatRelativeTime(dateStr) {
1743
+ if (!dateStr) return "\u2014";
1744
+ const diff = Date.now() - new Date(dateStr).getTime();
1745
+ const minutes = Math.floor(diff / 6e4);
1746
+ if (minutes < 1) return "just now";
1747
+ if (minutes < 60) return `${minutes}m ago`;
1748
+ const hours = Math.floor(minutes / 60);
1749
+ if (hours < 24) return `${hours}h ago`;
1750
+ const days = Math.floor(hours / 24);
1751
+ return `${days}d ago`;
1752
+ }
1753
+ function parseUserAgent(ua) {
1754
+ if (!ua) return "Unknown device";
1755
+ if (/iPhone|iPad/.test(ua)) return "iOS";
1756
+ if (/Android/.test(ua)) return "Android";
1757
+ if (/Windows/.test(ua)) return "Windows";
1758
+ if (/Macintosh|Mac OS/.test(ua)) return "macOS";
1759
+ if (/Linux/.test(ua)) return "Linux";
1760
+ return "Unknown device";
1761
+ }
1762
+ var ProfileRenderer = class {
1763
+ shadowRoot = null;
1764
+ hostElement = null;
1765
+ containerElement = null;
1766
+ containerId = null;
1767
+ mode;
1768
+ theme;
1769
+ branding;
1770
+ themeObserver = null;
1771
+ mediaQueryListener = null;
1772
+ t;
1773
+ user;
1774
+ sessions;
1775
+ isEditMode = false;
1776
+ onSave;
1777
+ onSignOut;
1778
+ onRevokeSession;
1779
+ onClose;
1780
+ escHandler = null;
1781
+ constructor(options) {
1782
+ this.mode = options.mode;
1783
+ this.theme = options.theme || "auto";
1784
+ this.branding = { ...DEFAULT_BRANDING, ...options.branding };
1785
+ this.t = getStrings(options.locale || "en");
1786
+ this.user = options.user;
1787
+ this.sessions = options.sessions || [];
1788
+ this.onSave = options.onSave;
1789
+ this.onSignOut = options.onSignOut;
1790
+ this.onRevokeSession = options.onRevokeSession;
1791
+ this.onClose = options.onClose;
1792
+ if (options.mode === "embedded" && options.containerId) {
1793
+ this.containerId = options.containerId;
1794
+ }
1795
+ }
1796
+ resolveContainerElement() {
1797
+ if (this.mode !== "embedded" || !this.containerId) return null;
1798
+ const next = document.getElementById(this.containerId);
1799
+ if (this.containerElement !== next) {
1800
+ this.hostElement?.remove();
1801
+ this.hostElement = null;
1802
+ this.shadowRoot = null;
1803
+ }
1804
+ this.containerElement = next;
1805
+ return next;
1806
+ }
1807
+ open() {
1808
+ this.resolveContainerElement();
1809
+ if (this.hostElement && !this.hostElement.isConnected) {
1810
+ this.hostElement = null;
1811
+ this.shadowRoot = null;
1812
+ }
1813
+ if (this.shadowRoot && this.hostElement) {
1814
+ this.rerender();
1815
+ } else {
1816
+ this.isEditMode = false;
1817
+ this.render();
1818
+ }
1819
+ }
1820
+ close() {
1821
+ this.stopThemeObserver();
1822
+ if (this.escHandler) {
1823
+ document.removeEventListener("keydown", this.escHandler);
1824
+ this.escHandler = null;
1825
+ }
1826
+ if (this.hostElement) {
1827
+ this.hostElement.remove();
1828
+ this.hostElement = null;
1829
+ this.shadowRoot = null;
1830
+ }
1831
+ const liveContainer = this.resolveContainerElement();
1832
+ if (liveContainer) {
1833
+ liveContainer.replaceChildren();
1834
+ }
1835
+ }
1836
+ updateUser(user) {
1837
+ this.user = user;
1838
+ if (this.shadowRoot) this.rerender();
1839
+ }
1840
+ updateSessions(sessions) {
1841
+ this.sessions = sessions;
1842
+ if (this.shadowRoot) this.rerender();
1843
+ }
1844
+ setTheme(theme) {
1845
+ this.theme = theme;
1846
+ this.updateThemeCSS();
1847
+ if (theme === "auto") {
1848
+ this.startThemeObserver();
1849
+ } else {
1850
+ this.stopThemeObserver();
1851
+ }
1852
+ }
1853
+ showSaving() {
1854
+ if (!this.shadowRoot) return;
1855
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1856
+ if (btn) {
1857
+ btn.disabled = true;
1858
+ btn.textContent = "...";
1859
+ }
1860
+ }
1861
+ showSaveError(message) {
1862
+ if (!this.shadowRoot) return;
1863
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1864
+ if (btn) {
1865
+ btn.disabled = false;
1866
+ btn.textContent = this.t.save;
1867
+ }
1868
+ this.showInlineError("profile-error", message);
1869
+ }
1870
+ showInlineError(id, message) {
1871
+ if (!this.shadowRoot) return;
1872
+ this.shadowRoot.getElementById(id)?.remove();
1873
+ const errEl = document.createElement("div");
1874
+ errEl.id = id;
1875
+ errEl.className = "error-msg";
1876
+ errEl.textContent = message;
1877
+ this.shadowRoot.querySelector(".profile-actions")?.appendChild(errEl);
1878
+ }
1879
+ updateThemeCSS() {
1880
+ if (!this.shadowRoot) return;
1881
+ const styleEl = this.shadowRoot.getElementById("authon-profile-theme-style");
1882
+ if (styleEl) styleEl.textContent = this.buildCSS();
1883
+ }
1884
+ startThemeObserver() {
1885
+ this.stopThemeObserver();
1886
+ if (typeof document === "undefined" || typeof window === "undefined") return;
1887
+ this.themeObserver = new MutationObserver(() => this.updateThemeCSS());
1888
+ this.themeObserver.observe(document.documentElement, {
1889
+ attributes: true,
1890
+ attributeFilter: ["data-theme", "class"]
1891
+ });
1892
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
1893
+ this.mediaQueryListener = () => this.updateThemeCSS();
1894
+ mq.addEventListener("change", this.mediaQueryListener);
1895
+ }
1896
+ stopThemeObserver() {
1897
+ if (this.themeObserver) {
1898
+ this.themeObserver.disconnect();
1899
+ this.themeObserver = null;
1900
+ }
1901
+ if (this.mediaQueryListener) {
1902
+ window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", this.mediaQueryListener);
1903
+ this.mediaQueryListener = null;
1904
+ }
1905
+ }
1906
+ isDark() {
1907
+ if (this.theme === "dark") return true;
1908
+ if (this.theme === "light") return false;
1909
+ if (typeof document !== "undefined") {
1910
+ const html = document.documentElement;
1911
+ if (html.classList.contains("dark") || html.getAttribute("data-theme") === "dark") return true;
1912
+ if (html.classList.contains("light") || html.getAttribute("data-theme") === "light") return false;
1913
+ }
1914
+ return typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches;
1915
+ }
1916
+ render() {
1917
+ const host = document.createElement("div");
1918
+ host.setAttribute("data-authon-profile", "");
1919
+ this.hostElement = host;
1920
+ if (this.mode === "popup") {
1921
+ document.body.appendChild(host);
1922
+ } else {
1923
+ const container = this.resolveContainerElement();
1924
+ if (!container) {
1925
+ this.hostElement = null;
1926
+ throw new Error(`Authon profile container "#${this.containerId}" not found`);
1927
+ }
1928
+ container.replaceChildren();
1929
+ container.appendChild(host);
1930
+ }
1931
+ this.shadowRoot = host.attachShadow({ mode: "open" });
1932
+ this.shadowRoot.innerHTML = this.buildShell();
1933
+ this.attachEvents();
1934
+ if (this.mode === "popup") {
1935
+ this.escHandler = (e) => {
1936
+ if (e.key === "Escape") {
1937
+ this.onClose();
1938
+ this.close();
1939
+ }
1940
+ };
1941
+ document.addEventListener("keydown", this.escHandler);
1942
+ }
1943
+ if (this.theme === "auto") this.startThemeObserver();
1944
+ }
1945
+ rerender() {
1946
+ if (!this.shadowRoot) return;
1947
+ const inner = this.shadowRoot.getElementById("profile-inner");
1948
+ if (!inner) return;
1949
+ inner.style.opacity = "0";
1950
+ inner.style.transform = "translateY(-4px)";
1951
+ setTimeout(() => {
1952
+ inner.innerHTML = this.buildInnerContent();
1953
+ this.attachInnerEvents();
1954
+ void inner.offsetHeight;
1955
+ inner.style.opacity = "1";
1956
+ inner.style.transform = "translateY(0)";
1957
+ }, 120);
1958
+ }
1959
+ buildShell() {
1960
+ const popupWrapper = this.mode === "popup" ? `<div class="backdrop" id="profile-backdrop"></div>` : "";
1961
+ return `
1962
+ <style id="authon-profile-theme-style">${this.buildCSS()}</style>
1963
+ ${popupWrapper}
1964
+ <div class="profile-container" role="dialog" aria-modal="true" aria-label="${this.t.profile}">
1965
+ <div id="profile-inner" class="profile-inner">
1966
+ ${this.buildInnerContent()}
1967
+ </div>
1968
+ </div>
1969
+ `;
1970
+ }
1971
+ buildInnerContent() {
1972
+ const u = this.user;
1973
+ const initials = (u.displayName || u.email || "?").split(/\s+/).map((w) => w[0]?.toUpperCase() ?? "").slice(0, 2).join("");
1974
+ const avatarHtml = u.avatarUrl ? `<img class="avatar-img" src="${u.avatarUrl}" alt="${u.displayName || ""}" />` : `<div class="avatar-placeholder">${initials}</div>`;
1975
+ const closeBtn = this.mode === "popup" ? `<button class="close-btn" id="profile-close-btn" aria-label="Close">
1976
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1977
+ <path d="M12 4L4 12M4 4l8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
1978
+ </svg>
1979
+ </button>` : "";
1980
+ if (this.isEditMode) {
1981
+ return this.buildEditContent(avatarHtml, closeBtn);
1982
+ }
1983
+ return this.buildViewContent(avatarHtml, closeBtn, u);
1984
+ }
1985
+ buildViewContent(avatarHtml, closeBtn, u) {
1986
+ const sessionsHtml = this.sessions.length > 0 ? `<div class="section">
1987
+ <div class="section-label">${this.t.sessions}</div>
1988
+ <div class="sessions-list">
1989
+ ${this.sessions.map((s) => `
1990
+ <div class="session-item" data-session-id="${s.id}">
1991
+ <div class="session-info">
1992
+ <span class="session-device">${parseUserAgent(s.userAgent)}</span>
1993
+ <span class="session-meta">${s.ipAddress || ""} &middot; ${formatRelativeTime(s.lastActiveAt)}</span>
1994
+ </div>
1995
+ <button class="session-revoke-btn" data-session-id="${s.id}" aria-label="Revoke session">
1996
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
1997
+ <path d="M10.5 3.5L3.5 10.5M3.5 3.5l7 7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
1998
+ </svg>
1999
+ </button>
2000
+ </div>
2001
+ `).join("")}
2002
+ </div>
2003
+ </div>` : "";
2004
+ return `
2005
+ <div class="profile-header">
2006
+ <div class="avatar-wrap">${avatarHtml}</div>
2007
+ <div class="header-text">
2008
+ <div class="display-name">${u.displayName || "\u2014"}</div>
2009
+ <div class="email">${u.email || "\u2014"}</div>
2010
+ </div>
2011
+ ${closeBtn}
2012
+ </div>
2013
+
2014
+ <div class="section">
2015
+ <div class="field-row">
2016
+ <span class="field-label">${this.t.emailAddress}</span>
2017
+ <span class="field-value readonly">${u.email || "\u2014"}</span>
2018
+ </div>
2019
+ <div class="field-row">
2020
+ <span class="field-label">${this.t.displayName}</span>
2021
+ <span class="field-value">${u.displayName || "\u2014"}</span>
2022
+ </div>
2023
+ </div>
2024
+
2025
+ ${sessionsHtml}
2026
+
2027
+ <div class="profile-actions">
2028
+ <button class="edit-btn" id="profile-edit-btn">${this.t.editProfile}</button>
2029
+ <button class="signout-btn" id="profile-signout-btn">${this.t.signOut}</button>
2030
+ </div>
2031
+ `;
2032
+ }
2033
+ buildEditContent(avatarHtml, closeBtn) {
2034
+ const u = this.user;
2035
+ return `
2036
+ <div class="profile-header">
2037
+ <div class="avatar-wrap">${avatarHtml}</div>
2038
+ <div class="header-text">
2039
+ <div class="display-name">${this.t.editProfile}</div>
2040
+ <div class="email">${u.email || "\u2014"}</div>
2041
+ </div>
2042
+ ${closeBtn}
2043
+ </div>
2044
+
2045
+ <div class="section">
2046
+ <div class="field-group">
2047
+ <label class="field-label" for="profile-displayname-input">${this.t.displayName}</label>
2048
+ <input
2049
+ id="profile-displayname-input"
2050
+ class="input"
2051
+ type="text"
2052
+ value="${u.displayName || ""}"
2053
+ placeholder="${this.t.displayName}"
2054
+ autocomplete="name"
2055
+ />
2056
+ </div>
2057
+ <div class="field-group">
2058
+ <label class="field-label" for="profile-avatar-input">Avatar URL</label>
2059
+ <input
2060
+ id="profile-avatar-input"
2061
+ class="input"
2062
+ type="url"
2063
+ value="${u.avatarUrl || ""}"
2064
+ placeholder="https://..."
2065
+ autocomplete="off"
2066
+ />
2067
+ </div>
2068
+ <div class="field-group">
2069
+ <label class="field-label">${this.t.emailAddress}</label>
2070
+ <input class="input readonly" type="email" value="${u.email || ""}" disabled />
2071
+ </div>
2072
+ </div>
2073
+
2074
+ <div class="profile-actions">
2075
+ <button class="save-btn" id="profile-save-btn">${this.t.save}</button>
2076
+ <button class="cancel-btn" id="profile-cancel-btn">Cancel</button>
2077
+ </div>
2078
+ `;
2079
+ }
2080
+ buildCSS() {
2081
+ const b = this.branding;
2082
+ const dark = this.isDark();
2083
+ const bg = dark ? b.darkBg || "#0f172a" : b.lightBg || "#ffffff";
2084
+ const text = dark ? b.darkText || "#f1f5f9" : b.lightText || "#111827";
2085
+ const mutedText = dark ? "#94a3b8" : "#6b7280";
2086
+ const dimText = dark ? "#64748b" : "#9ca3af";
2087
+ const borderColor = dark ? "#334155" : "#d1d5db";
2088
+ const dividerColor = dark ? "#334155" : "#e5e7eb";
2089
+ const inputBg = dark ? "#1e293b" : "#ffffff";
2090
+ const sectionBg = dark ? "#1e293b" : "#f9fafb";
2091
+ const sessionItemBg = dark ? "#263148" : "#f3f4f6";
2092
+ return `
2093
+ :host {
2094
+ --authon-primary-start: ${b.primaryColorStart || "#7c3aed"};
2095
+ --authon-primary-end: ${b.primaryColorEnd || "#4f46e5"};
2096
+ --authon-bg: ${bg};
2097
+ --authon-text: ${text};
2098
+ --authon-muted: ${mutedText};
2099
+ --authon-dim: ${dimText};
2100
+ --authon-border: ${borderColor};
2101
+ --authon-divider: ${dividerColor};
2102
+ --authon-input-bg: ${inputBg};
2103
+ --authon-section-bg: ${sectionBg};
2104
+ --authon-session-bg: ${sessionItemBg};
2105
+ --authon-backdrop-bg: rgba(0,0,0,${dark ? "0.7" : "0.5"});
2106
+ --authon-radius: ${b.borderRadius ?? 12}px;
2107
+ --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
2108
+ font-family: var(--authon-font);
2109
+ color: var(--authon-text);
2110
+ }
2111
+ * { box-sizing: border-box; margin: 0; padding: 0; }
2112
+
2113
+ .backdrop {
2114
+ position: fixed; inset: 0; z-index: 99998;
2115
+ background: var(--authon-backdrop-bg); backdrop-filter: blur(4px);
2116
+ animation: fadeIn 0.2s ease;
2117
+ }
2118
+
2119
+ .profile-container {
2120
+ ${this.mode === "popup" ? "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;" : ""}
2121
+ background: var(--authon-bg);
2122
+ color: var(--authon-text);
2123
+ border: 1px solid var(--authon-border);
2124
+ border-radius: var(--authon-radius);
2125
+ padding: 24px;
2126
+ width: 380px; max-width: 100%;
2127
+ ${this.mode === "popup" ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? "0.5" : "0.25"}); animation: slideIn 0.3s ease;` : ""}
2128
+ }
2129
+
2130
+ .profile-inner {
2131
+ transition: opacity 0.12s ease, transform 0.12s ease;
2132
+ }
2133
+
2134
+ .profile-header {
2135
+ display: flex;
2136
+ align-items: center;
2137
+ gap: 14px;
2138
+ margin-bottom: 20px;
2139
+ position: relative;
2140
+ }
2141
+
2142
+ .avatar-wrap { flex-shrink: 0; }
2143
+
2144
+ .avatar-img {
2145
+ width: 52px; height: 52px;
2146
+ border-radius: 50%;
2147
+ object-fit: cover;
2148
+ border: 2px solid var(--authon-border);
2149
+ }
2150
+
2151
+ .avatar-placeholder {
2152
+ width: 52px; height: 52px;
2153
+ border-radius: 50%;
2154
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2155
+ display: flex; align-items: center; justify-content: center;
2156
+ font-size: 18px; font-weight: 700; color: #fff;
2157
+ flex-shrink: 0;
2158
+ }
2159
+
2160
+ .header-text { flex: 1; min-width: 0; }
2161
+
2162
+ .display-name {
2163
+ font-size: 16px; font-weight: 600;
2164
+ color: var(--authon-text);
2165
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2166
+ }
2167
+
2168
+ .email {
2169
+ font-size: 13px; color: var(--authon-muted);
2170
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2171
+ margin-top: 2px;
2172
+ }
2173
+
2174
+ .close-btn {
2175
+ position: absolute; top: 0; right: 0;
2176
+ background: none; border: none;
2177
+ color: var(--authon-muted); cursor: pointer;
2178
+ padding: 4px; border-radius: 6px;
2179
+ display: flex; align-items: center; justify-content: center;
2180
+ transition: color 0.15s, background 0.15s;
2181
+ }
2182
+ .close-btn:hover { color: var(--authon-text); background: var(--authon-divider); }
2183
+
2184
+ .section {
2185
+ background: var(--authon-section-bg);
2186
+ border: 1px solid var(--authon-border);
2187
+ border-radius: calc(var(--authon-radius) * 0.67);
2188
+ padding: 12px 14px;
2189
+ margin-bottom: 12px;
2190
+ display: flex; flex-direction: column; gap: 10px;
2191
+ }
2192
+
2193
+ .section-label {
2194
+ font-size: 11px; font-weight: 600;
2195
+ text-transform: uppercase; letter-spacing: 0.05em;
2196
+ color: var(--authon-dim); margin-bottom: 2px;
2197
+ }
2198
+
2199
+ .field-row {
2200
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
2201
+ }
2202
+
2203
+ .field-label {
2204
+ font-size: 12px; color: var(--authon-muted); flex-shrink: 0;
2205
+ }
2206
+
2207
+ .field-value {
2208
+ font-size: 13px; color: var(--authon-text);
2209
+ text-align: right; min-width: 0;
2210
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2211
+ }
2212
+
2213
+ .field-value.readonly { color: var(--authon-dim); }
2214
+
2215
+ .field-group {
2216
+ display: flex; flex-direction: column; gap: 4px;
2217
+ }
2218
+
2219
+ .input {
2220
+ width: 100%; padding: 9px 12px;
2221
+ background: var(--authon-input-bg);
2222
+ color: var(--authon-text);
2223
+ border: 1px solid var(--authon-border);
2224
+ border-radius: calc(var(--authon-radius) * 0.5);
2225
+ font-size: 13px; font-family: var(--authon-font);
2226
+ outline: none; transition: border-color 0.15s;
2227
+ }
2228
+ .input::placeholder { color: var(--authon-dim); }
2229
+ .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px ${hexToRgba2(b.primaryColorStart || "#7c3aed", 0.15)}; }
2230
+ .input.readonly, .input:disabled { color: var(--authon-dim); cursor: not-allowed; background: var(--authon-section-bg); }
2231
+
2232
+ .sessions-list { display: flex; flex-direction: column; gap: 6px; }
2233
+
2234
+ .session-item {
2235
+ display: flex; align-items: center; justify-content: space-between;
2236
+ background: var(--authon-session-bg);
2237
+ border-radius: calc(var(--authon-radius) * 0.5);
2238
+ padding: 8px 10px; gap: 8px;
2239
+ }
2240
+
2241
+ .session-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
2242
+
2243
+ .session-device {
2244
+ font-size: 13px; font-weight: 500; color: var(--authon-text);
2245
+ }
2246
+
2247
+ .session-meta {
2248
+ font-size: 11px; color: var(--authon-dim);
2249
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2250
+ }
2251
+
2252
+ .session-revoke-btn {
2253
+ background: none; border: none;
2254
+ color: var(--authon-dim); cursor: pointer;
2255
+ padding: 4px; border-radius: 4px; flex-shrink: 0;
2256
+ display: flex; align-items: center; justify-content: center;
2257
+ transition: color 0.15s, background 0.15s;
2258
+ }
2259
+ .session-revoke-btn:hover { color: #ef4444; background: rgba(239,68,68,0.1); }
2260
+
2261
+ .profile-actions {
2262
+ display: flex; flex-direction: column; gap: 8px;
2263
+ margin-top: 4px;
2264
+ }
2265
+
2266
+ .edit-btn {
2267
+ width: 100%; padding: 10px;
2268
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2269
+ color: #fff; border: none;
2270
+ border-radius: calc(var(--authon-radius) * 0.5);
2271
+ font-size: 14px; font-weight: 600; cursor: pointer;
2272
+ font-family: var(--authon-font); transition: opacity 0.15s;
2273
+ }
2274
+ .edit-btn:hover { opacity: 0.9; }
2275
+
2276
+ .save-btn {
2277
+ width: 100%; padding: 10px;
2278
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2279
+ color: #fff; border: none;
2280
+ border-radius: calc(var(--authon-radius) * 0.5);
2281
+ font-size: 14px; font-weight: 600; cursor: pointer;
2282
+ font-family: var(--authon-font); transition: opacity 0.15s;
2283
+ }
2284
+ .save-btn:hover { opacity: 0.9; }
2285
+ .save-btn:disabled { opacity: 0.6; cursor: not-allowed; }
2286
+
2287
+ .cancel-btn {
2288
+ width: 100%; padding: 10px;
2289
+ background: none;
2290
+ color: var(--authon-muted);
2291
+ border: 1px solid var(--authon-border);
2292
+ border-radius: calc(var(--authon-radius) * 0.5);
2293
+ font-size: 14px; font-weight: 500; cursor: pointer;
2294
+ font-family: var(--authon-font); transition: background 0.15s, color 0.15s;
2295
+ }
2296
+ .cancel-btn:hover { background: var(--authon-divider); color: var(--authon-text); }
2297
+
2298
+ .signout-btn {
2299
+ width: 100%; padding: 10px;
2300
+ background: none;
2301
+ color: #ef4444;
2302
+ border: 1px solid rgba(239,68,68,0.3);
2303
+ border-radius: calc(var(--authon-radius) * 0.5);
2304
+ font-size: 14px; font-weight: 500; cursor: pointer;
2305
+ font-family: var(--authon-font); transition: background 0.15s;
2306
+ }
2307
+ .signout-btn:hover { background: rgba(239,68,68,0.08); }
2308
+
2309
+ .error-msg {
2310
+ padding: 8px 12px;
2311
+ background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);
2312
+ border-radius: calc(var(--authon-radius) * 0.33);
2313
+ font-size: 13px; color: #ef4444; text-align: center;
2314
+ animation: fadeIn 0.15s ease;
2315
+ }
2316
+
2317
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
2318
+ @keyframes slideIn { from { opacity: 0; transform: translate(-50%, calc(-50% - 8px)); } to { opacity: 1; transform: translate(-50%, -50%); } }
2319
+ `;
2320
+ }
2321
+ attachEvents() {
2322
+ this.attachBackdropEvent();
2323
+ this.attachInnerEvents();
2324
+ }
2325
+ attachBackdropEvent() {
2326
+ if (!this.shadowRoot || this.mode !== "popup") return;
2327
+ const backdrop = this.shadowRoot.getElementById("profile-backdrop");
2328
+ if (backdrop) {
2329
+ backdrop.addEventListener("click", () => {
2330
+ this.onClose();
2331
+ this.close();
2332
+ });
2333
+ }
2334
+ }
2335
+ attachInnerEvents() {
2336
+ if (!this.shadowRoot) return;
2337
+ const closeBtn = this.shadowRoot.getElementById("profile-close-btn");
2338
+ closeBtn?.addEventListener("click", () => {
2339
+ this.onClose();
2340
+ this.close();
2341
+ });
2342
+ const editBtn = this.shadowRoot.getElementById("profile-edit-btn");
2343
+ editBtn?.addEventListener("click", () => {
2344
+ this.isEditMode = true;
2345
+ this.rerender();
2346
+ });
2347
+ const cancelBtn = this.shadowRoot.getElementById("profile-cancel-btn");
2348
+ cancelBtn?.addEventListener("click", () => {
2349
+ this.isEditMode = false;
2350
+ this.rerender();
2351
+ });
2352
+ const saveBtn = this.shadowRoot.getElementById("profile-save-btn");
2353
+ saveBtn?.addEventListener("click", async () => {
2354
+ const nameInput = this.shadowRoot.getElementById("profile-displayname-input");
2355
+ const avatarInput = this.shadowRoot.getElementById("profile-avatar-input");
2356
+ const displayName = nameInput?.value.trim();
2357
+ const avatarUrl = avatarInput?.value.trim();
2358
+ this.showSaving();
2359
+ this.shadowRoot.getElementById("profile-error")?.remove();
2360
+ try {
2361
+ await this.onSave({
2362
+ displayName: displayName || void 0,
2363
+ avatarUrl: avatarUrl || void 0
2364
+ });
2365
+ this.isEditMode = false;
2366
+ this.rerender();
2367
+ } catch (err) {
2368
+ this.showSaveError(err instanceof Error ? err.message : "Save failed");
2369
+ }
2370
+ });
2371
+ const signOutBtn = this.shadowRoot.getElementById("profile-signout-btn");
2372
+ signOutBtn?.addEventListener("click", async () => {
2373
+ if (signOutBtn instanceof HTMLButtonElement) {
2374
+ signOutBtn.disabled = true;
2375
+ signOutBtn.textContent = "...";
2376
+ }
2377
+ try {
2378
+ await this.onSignOut();
2379
+ this.close();
2380
+ } catch (_) {
2381
+ if (signOutBtn instanceof HTMLButtonElement) {
2382
+ signOutBtn.disabled = false;
2383
+ signOutBtn.textContent = this.t.signOut;
2384
+ }
2385
+ }
2386
+ });
2387
+ this.shadowRoot.querySelectorAll(".session-revoke-btn").forEach((btn) => {
2388
+ btn.addEventListener("click", async () => {
2389
+ const sessionId = btn.dataset.sessionId;
2390
+ if (!sessionId) return;
2391
+ btn.disabled = true;
2392
+ try {
2393
+ await this.onRevokeSession(sessionId);
2394
+ this.sessions = this.sessions.filter((s) => s.id !== sessionId);
2395
+ this.rerender();
2396
+ } catch (_) {
2397
+ btn.disabled = false;
2398
+ }
2399
+ });
2400
+ });
2401
+ }
2402
+ };
2403
+
1214
2404
  // src/session.ts
1215
2405
  var SessionManager = class {
1216
2406
  accessToken = null;
@@ -1740,6 +2930,7 @@ var Authon = class {
1740
2930
  config;
1741
2931
  session;
1742
2932
  modal = null;
2933
+ profile = null;
1743
2934
  listeners = /* @__PURE__ */ new Map();
1744
2935
  branding = null;
1745
2936
  providers = [];
@@ -1773,9 +2964,56 @@ var Authon = class {
1773
2964
  await this.ensureInitialized();
1774
2965
  this.getModal().open("signUp");
1775
2966
  }
2967
+ async openProfile() {
2968
+ const user = this.getUser();
2969
+ if (!user) throw new Error("Must be signed in to open profile");
2970
+ const token = this.session.getToken();
2971
+ let sessions = [];
2972
+ if (token) {
2973
+ try {
2974
+ sessions = await this.listSessions();
2975
+ } catch (_) {
2976
+ }
2977
+ }
2978
+ if (!this.profile) {
2979
+ this.profile = new ProfileRenderer({
2980
+ mode: this.config.mode,
2981
+ theme: this.config.theme,
2982
+ locale: this.config.locale,
2983
+ containerId: this.config.containerId,
2984
+ branding: this.branding || void 0,
2985
+ user,
2986
+ sessions,
2987
+ onSave: async (data) => {
2988
+ const updated = await this.updateProfile(data);
2989
+ this.profile?.updateUser(updated);
2990
+ },
2991
+ onSignOut: async () => {
2992
+ await this.signOut();
2993
+ this.profile = null;
2994
+ },
2995
+ onRevokeSession: async (sessionId) => {
2996
+ await this.revokeSession(sessionId);
2997
+ },
2998
+ onClose: () => {
2999
+ this.profile?.close();
3000
+ this.profile = null;
3001
+ }
3002
+ });
3003
+ } else {
3004
+ this.profile.updateUser(user);
3005
+ this.profile.updateSessions(sessions);
3006
+ }
3007
+ this.profile.open();
3008
+ }
3009
+ closeProfile() {
3010
+ this.profile?.close();
3011
+ this.profile = null;
3012
+ }
1776
3013
  /** Update theme at runtime without destroying form state */
1777
3014
  setTheme(theme) {
1778
3015
  this.getModal().setTheme(theme);
3016
+ this.profile?.setTheme(theme);
1779
3017
  }
1780
3018
  async signInWithOAuth(provider, options) {
1781
3019
  await this.ensureInitialized();
@@ -2088,6 +3326,8 @@ var Authon = class {
2088
3326
  }
2089
3327
  destroy() {
2090
3328
  this.modal?.close();
3329
+ this.profile?.close();
3330
+ this.profile = null;
2091
3331
  this.session.destroy();
2092
3332
  this.listeners.clear();
2093
3333
  }
@@ -2134,6 +3374,7 @@ var Authon = class {
2134
3374
  this.modal = new ModalRenderer({
2135
3375
  mode: this.config.mode,
2136
3376
  theme: this.config.theme,
3377
+ locale: this.config.locale,
2137
3378
  containerId: this.config.containerId,
2138
3379
  branding: this.branding || void 0,
2139
3380
  captchaSiteKey: this.captchaEnabled ? this.turnstileSiteKey : void 0,
@@ -2591,7 +3832,10 @@ var Authon = class {
2591
3832
  0 && (module.exports = {
2592
3833
  Authon,
2593
3834
  AuthonMfaRequiredError,
3835
+ ProfileRenderer,
2594
3836
  generateQrSvg,
2595
- getProviderButtonConfig
3837
+ getProviderButtonConfig,
3838
+ getStrings,
3839
+ translations
2596
3840
  });
2597
3841
  //# sourceMappingURL=index.cjs.map