@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.js CHANGED
@@ -8,7 +8,7 @@ var AuthonMfaRequiredError = class extends Error {
8
8
  }
9
9
  };
10
10
 
11
- // ../shared/dist/index.js
11
+ // ../../node_modules/.pnpm/@authon+shared@0.3.0/node_modules/@authon/shared/dist/index.js
12
12
  var PROVIDER_DISPLAY_NAMES = {
13
13
  google: "Google",
14
14
  apple: "Apple",
@@ -71,6 +71,520 @@ function getProviderButtonConfig(provider) {
71
71
  };
72
72
  }
73
73
 
74
+ // src/i18n.ts
75
+ var translations = {
76
+ en: {
77
+ welcomeBack: "Welcome back",
78
+ createAccount: "Create your account",
79
+ alreadyHaveAccount: "Already have an account?",
80
+ dontHaveAccount: "Don't have an account?",
81
+ signIn: "Sign in",
82
+ signUp: "Sign up",
83
+ or: "or",
84
+ emailAddress: "Email address",
85
+ password: "Password",
86
+ passwordHint: "Must contain uppercase, lowercase, and a number (min 8 chars)",
87
+ continueWith: "Continue with",
88
+ connectWallet: "Connect Wallet",
89
+ magicLink: "Continue with Magic Link",
90
+ passkey: "Sign in with Passkey",
91
+ securedBy: "Secured by",
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"
99
+ },
100
+ ko: {
101
+ welcomeBack: "\uB2E4\uC2DC \uC624\uC2E0 \uAC78 \uD658\uC601\uD569\uB2C8\uB2E4",
102
+ createAccount: "\uACC4\uC815 \uB9CC\uB4E4\uAE30",
103
+ alreadyHaveAccount: "\uC774\uBBF8 \uACC4\uC815\uC774 \uC788\uC73C\uC2E0\uAC00\uC694?",
104
+ dontHaveAccount: "\uACC4\uC815\uC774 \uC5C6\uC73C\uC2E0\uAC00\uC694?",
105
+ signIn: "\uB85C\uADF8\uC778",
106
+ signUp: "\uD68C\uC6D0\uAC00\uC785",
107
+ or: "\uB610\uB294",
108
+ emailAddress: "\uC774\uBA54\uC77C \uC8FC\uC18C",
109
+ password: "\uBE44\uBC00\uBC88\uD638",
110
+ passwordHint: "\uB300\uBB38\uC790, \uC18C\uBB38\uC790, \uC22B\uC790 \uD3EC\uD568 (\uCD5C\uC18C 8\uC790)",
111
+ continueWith: "(\uC73C)\uB85C \uACC4\uC18D\uD558\uAE30",
112
+ connectWallet: "\uC9C0\uAC11 \uC5F0\uACB0",
113
+ magicLink: "\uB9E4\uC9C1 \uB9C1\uD06C\uB85C \uACC4\uC18D\uD558\uAE30",
114
+ passkey: "\uD328\uC2A4\uD0A4\uB85C \uB85C\uADF8\uC778",
115
+ securedBy: "\uBCF4\uC548 \uC81C\uACF5",
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"
123
+ },
124
+ ja: {
125
+ welcomeBack: "\u304A\u304B\u3048\u308A\u306A\u3055\u3044",
126
+ createAccount: "\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F5C\u6210",
127
+ alreadyHaveAccount: "\u3059\u3067\u306B\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u304A\u6301\u3061\u3067\u3059\u304B\uFF1F",
128
+ dontHaveAccount: "\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u304A\u6301\u3061\u3067\u306A\u3044\u3067\u3059\u304B\uFF1F",
129
+ signIn: "\u30ED\u30B0\u30A4\u30F3",
130
+ signUp: "\u65B0\u898F\u767B\u9332",
131
+ or: "\u307E\u305F\u306F",
132
+ emailAddress: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9",
133
+ password: "\u30D1\u30B9\u30EF\u30FC\u30C9",
134
+ passwordHint: "\u5927\u6587\u5B57\u3001\u5C0F\u6587\u5B57\u3001\u6570\u5B57\u3092\u542B\u3080\uFF088\u6587\u5B57\u4EE5\u4E0A\uFF09",
135
+ continueWith: "\u3067\u7D9A\u884C",
136
+ connectWallet: "\u30A6\u30A9\u30EC\u30C3\u30C8\u63A5\u7D9A",
137
+ magicLink: "\u30DE\u30B8\u30C3\u30AF\u30EA\u30F3\u30AF\u3067\u7D9A\u884C",
138
+ passkey: "\u30D1\u30B9\u30AD\u30FC\u3067\u30ED\u30B0\u30A4\u30F3",
139
+ securedBy: "\u30BB\u30AD\u30E5\u30EA\u30C6\u30A3\u63D0\u4F9B",
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"
147
+ },
148
+ "zh-CN": {
149
+ welcomeBack: "\u6B22\u8FCE\u56DE\u6765",
150
+ createAccount: "\u521B\u5EFA\u8D26\u6237",
151
+ alreadyHaveAccount: "\u5DF2\u6709\u8D26\u6237\uFF1F",
152
+ dontHaveAccount: "\u6CA1\u6709\u8D26\u6237\uFF1F",
153
+ signIn: "\u767B\u5F55",
154
+ signUp: "\u6CE8\u518C",
155
+ or: "\u6216",
156
+ emailAddress: "\u90AE\u7BB1\u5730\u5740",
157
+ password: "\u5BC6\u7801",
158
+ passwordHint: "\u9700\u5305\u542B\u5927\u5199\u3001\u5C0F\u5199\u5B57\u6BCD\u548C\u6570\u5B57\uFF08\u81F3\u5C118\u4F4D\uFF09",
159
+ continueWith: "\u7EE7\u7EED\u4F7F\u7528",
160
+ connectWallet: "\u8FDE\u63A5\u94B1\u5305",
161
+ magicLink: "\u4F7F\u7528\u9B54\u6CD5\u94FE\u63A5\u7EE7\u7EED",
162
+ passkey: "\u4F7F\u7528\u901A\u884C\u5BC6\u94A5\u767B\u5F55",
163
+ securedBy: "\u5B89\u5168\u4FDD\u969C",
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"
171
+ },
172
+ "zh-TW": {
173
+ welcomeBack: "\u6B61\u8FCE\u56DE\u4F86",
174
+ createAccount: "\u5EFA\u7ACB\u5E33\u6236",
175
+ alreadyHaveAccount: "\u5DF2\u6709\u5E33\u6236\uFF1F",
176
+ dontHaveAccount: "\u6C92\u6709\u5E33\u6236\uFF1F",
177
+ signIn: "\u767B\u5165",
178
+ signUp: "\u8A3B\u518A",
179
+ or: "\u6216",
180
+ emailAddress: "\u96FB\u5B50\u90F5\u4EF6",
181
+ password: "\u5BC6\u78BC",
182
+ passwordHint: "\u9700\u5305\u542B\u5927\u5BEB\u3001\u5C0F\u5BEB\u5B57\u6BCD\u548C\u6578\u5B57\uFF08\u81F3\u5C118\u4F4D\uFF09",
183
+ continueWith: "\u7E7C\u7E8C\u4F7F\u7528",
184
+ connectWallet: "\u9023\u63A5\u9322\u5305",
185
+ magicLink: "\u4F7F\u7528\u9B54\u6CD5\u9023\u7D50\u7E7C\u7E8C",
186
+ passkey: "\u4F7F\u7528\u901A\u884C\u91D1\u9470\u767B\u5165",
187
+ securedBy: "\u5B89\u5168\u4FDD\u969C",
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"
195
+ },
196
+ "pt-BR": {
197
+ welcomeBack: "Bem-vindo de volta",
198
+ createAccount: "Crie sua conta",
199
+ alreadyHaveAccount: "Ja tem uma conta?",
200
+ dontHaveAccount: "Nao tem uma conta?",
201
+ signIn: "Entrar",
202
+ signUp: "Cadastrar",
203
+ or: "ou",
204
+ emailAddress: "Endereco de e-mail",
205
+ password: "Senha",
206
+ passwordHint: "Deve conter maiusculas, minusculas e numeros (min 8 caracteres)",
207
+ continueWith: "Continuar com",
208
+ connectWallet: "Conectar carteira",
209
+ magicLink: "Continuar com Magic Link",
210
+ passkey: "Entrar com Passkey",
211
+ securedBy: "Protegido por",
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"
219
+ },
220
+ es: {
221
+ welcomeBack: "Bienvenido de nuevo",
222
+ createAccount: "Crea tu cuenta",
223
+ alreadyHaveAccount: "Ya tienes una cuenta?",
224
+ dontHaveAccount: "No tienes una cuenta?",
225
+ signIn: "Iniciar sesion",
226
+ signUp: "Registrarse",
227
+ or: "o",
228
+ emailAddress: "Correo electronico",
229
+ password: "Contrasena",
230
+ passwordHint: "Debe contener mayusculas, minusculas y numeros (min 8 caracteres)",
231
+ continueWith: "Continuar con",
232
+ connectWallet: "Conectar billetera",
233
+ magicLink: "Continuar con Magic Link",
234
+ passkey: "Iniciar con Passkey",
235
+ securedBy: "Protegido por",
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"
243
+ },
244
+ de: {
245
+ welcomeBack: "Willkommen zuruck",
246
+ createAccount: "Konto erstellen",
247
+ alreadyHaveAccount: "Bereits ein Konto?",
248
+ dontHaveAccount: "Noch kein Konto?",
249
+ signIn: "Anmelden",
250
+ signUp: "Registrieren",
251
+ or: "oder",
252
+ emailAddress: "E-Mail-Adresse",
253
+ password: "Passwort",
254
+ passwordHint: "Gross-/Kleinbuchstaben und Zahl erforderlich (mind. 8 Zeichen)",
255
+ continueWith: "Weiter mit",
256
+ connectWallet: "Wallet verbinden",
257
+ magicLink: "Weiter mit Magic Link",
258
+ passkey: "Mit Passkey anmelden",
259
+ securedBy: "Gesichert durch",
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"
267
+ },
268
+ fr: {
269
+ welcomeBack: "Bon retour",
270
+ createAccount: "Creez votre compte",
271
+ alreadyHaveAccount: "Vous avez deja un compte ?",
272
+ dontHaveAccount: "Vous n'avez pas de compte ?",
273
+ signIn: "Se connecter",
274
+ signUp: "S'inscrire",
275
+ or: "ou",
276
+ emailAddress: "Adresse e-mail",
277
+ password: "Mot de passe",
278
+ passwordHint: "Doit contenir majuscules, minuscules et chiffres (min 8 caracteres)",
279
+ continueWith: "Continuer avec",
280
+ connectWallet: "Connecter le portefeuille",
281
+ magicLink: "Continuer avec Magic Link",
282
+ passkey: "Se connecter avec Passkey",
283
+ securedBy: "Securise par",
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"
291
+ },
292
+ hi: {
293
+ welcomeBack: "\u0935\u093E\u092A\u0938\u0940 \u092A\u0930 \u0938\u094D\u0935\u093E\u0917\u0924 \u0939\u0948",
294
+ createAccount: "\u0905\u092A\u0928\u093E \u0916\u093E\u0924\u093E \u092C\u0928\u093E\u090F\u0902",
295
+ alreadyHaveAccount: "\u092A\u0939\u0932\u0947 \u0938\u0947 \u0916\u093E\u0924\u093E \u0939\u0948?",
296
+ dontHaveAccount: "\u0916\u093E\u0924\u093E \u0928\u0939\u0940\u0902 \u0939\u0948?",
297
+ signIn: "\u0938\u093E\u0907\u0928 \u0907\u0928",
298
+ signUp: "\u0938\u093E\u0907\u0928 \u0905\u092A",
299
+ or: "\u092F\u093E",
300
+ emailAddress: "\u0908\u092E\u0947\u0932 \u092A\u0924\u093E",
301
+ password: "\u092A\u093E\u0938\u0935\u0930\u094D\u0921",
302
+ 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)",
303
+ continueWith: "\u0938\u0947 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
304
+ connectWallet: "\u0935\u0949\u0932\u0947\u091F \u0915\u0928\u0947\u0915\u094D\u091F \u0915\u0930\u0947\u0902",
305
+ magicLink: "\u092E\u0948\u091C\u093F\u0915 \u0932\u093F\u0902\u0915 \u0938\u0947 \u091C\u093E\u0930\u0940 \u0930\u0916\u0947\u0902",
306
+ passkey: "\u092A\u093E\u0938\u0915\u0940 \u0938\u0947 \u0938\u093E\u0907\u0928 \u0907\u0928",
307
+ securedBy: "\u0938\u0941\u0930\u0915\u094D\u0937\u093E \u092A\u094D\u0930\u0926\u093E\u0924\u093E",
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"
315
+ },
316
+ tr: {
317
+ welcomeBack: "Tekrar hos geldiniz",
318
+ createAccount: "Hesap olusturun",
319
+ alreadyHaveAccount: "Zaten bir hesabiniz var mi?",
320
+ dontHaveAccount: "Hesabiniz yok mu?",
321
+ signIn: "Giris yap",
322
+ signUp: "Kaydol",
323
+ or: "veya",
324
+ emailAddress: "E-posta adresi",
325
+ password: "Sifre",
326
+ passwordHint: "Buyuk, kucuk harf ve rakam icermeli (en az 8 karakter)",
327
+ continueWith: "ile devam et",
328
+ connectWallet: "Cuzdan bagla",
329
+ magicLink: "Magic Link ile devam et",
330
+ passkey: "Passkey ile giris yap",
331
+ securedBy: "Guvenlik saglayici",
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"
339
+ },
340
+ id: {
341
+ welcomeBack: "Selamat datang kembali",
342
+ createAccount: "Buat akun Anda",
343
+ alreadyHaveAccount: "Sudah punya akun?",
344
+ dontHaveAccount: "Belum punya akun?",
345
+ signIn: "Masuk",
346
+ signUp: "Daftar",
347
+ or: "atau",
348
+ emailAddress: "Alamat email",
349
+ password: "Kata sandi",
350
+ passwordHint: "Harus mengandung huruf besar, kecil, dan angka (min 8 karakter)",
351
+ continueWith: "Lanjutkan dengan",
352
+ connectWallet: "Hubungkan dompet",
353
+ magicLink: "Lanjutkan dengan Magic Link",
354
+ passkey: "Masuk dengan Passkey",
355
+ securedBy: "Diamankan oleh",
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"
363
+ },
364
+ vi: {
365
+ welcomeBack: "Chao mung tro lai",
366
+ createAccount: "Tao tai khoan",
367
+ alreadyHaveAccount: "Da co tai khoan?",
368
+ dontHaveAccount: "Chua co tai khoan?",
369
+ signIn: "Dang nhap",
370
+ signUp: "Dang ky",
371
+ or: "hoac",
372
+ emailAddress: "Dia chi email",
373
+ password: "Mat khau",
374
+ passwordHint: "Can chu hoa, chu thuong va so (toi thieu 8 ky tu)",
375
+ continueWith: "Tiep tuc voi",
376
+ connectWallet: "Ket noi vi",
377
+ magicLink: "Tiep tuc voi Magic Link",
378
+ passkey: "Dang nhap voi Passkey",
379
+ securedBy: "Bao mat boi",
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"
387
+ },
388
+ th: {
389
+ welcomeBack: "\u0E22\u0E34\u0E19\u0E14\u0E35\u0E15\u0E49\u0E2D\u0E19\u0E23\u0E31\u0E1A\u0E01\u0E25\u0E31\u0E1A",
390
+ createAccount: "\u0E2A\u0E23\u0E49\u0E32\u0E07\u0E1A\u0E31\u0E0D\u0E0A\u0E35",
391
+ alreadyHaveAccount: "\u0E21\u0E35\u0E1A\u0E31\u0E0D\u0E0A\u0E35\u0E2D\u0E22\u0E39\u0E48\u0E41\u0E25\u0E49\u0E27?",
392
+ dontHaveAccount: "\u0E22\u0E31\u0E07\u0E44\u0E21\u0E48\u0E21\u0E35\u0E1A\u0E31\u0E0D\u0E0A\u0E35?",
393
+ signIn: "\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A",
394
+ signUp: "\u0E2A\u0E21\u0E31\u0E04\u0E23\u0E2A\u0E21\u0E32\u0E0A\u0E34\u0E01",
395
+ or: "\u0E2B\u0E23\u0E37\u0E2D",
396
+ emailAddress: "\u0E2D\u0E35\u0E40\u0E21\u0E25",
397
+ password: "\u0E23\u0E2B\u0E31\u0E2A\u0E1C\u0E48\u0E32\u0E19",
398
+ 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)",
399
+ continueWith: "\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E14\u0E49\u0E27\u0E22",
400
+ connectWallet: "\u0E40\u0E0A\u0E37\u0E48\u0E2D\u0E21\u0E15\u0E48\u0E2D\u0E01\u0E23\u0E30\u0E40\u0E1B\u0E4B\u0E32",
401
+ magicLink: "\u0E14\u0E33\u0E40\u0E19\u0E34\u0E19\u0E01\u0E32\u0E23\u0E15\u0E48\u0E2D\u0E14\u0E49\u0E27\u0E22 Magic Link",
402
+ passkey: "\u0E40\u0E02\u0E49\u0E32\u0E2A\u0E39\u0E48\u0E23\u0E30\u0E1A\u0E1A\u0E14\u0E49\u0E27\u0E22 Passkey",
403
+ securedBy: "\u0E23\u0E31\u0E01\u0E29\u0E32\u0E04\u0E27\u0E32\u0E21\u0E1B\u0E25\u0E2D\u0E14\u0E20\u0E31\u0E22\u0E42\u0E14\u0E22",
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"
411
+ },
412
+ ru: {
413
+ welcomeBack: "\u0421 \u0432\u043E\u0437\u0432\u0440\u0430\u0449\u0435\u043D\u0438\u0435\u043C",
414
+ createAccount: "\u0421\u043E\u0437\u0434\u0430\u0439\u0442\u0435 \u0430\u043A\u043A\u0430\u0443\u043D\u0442",
415
+ alreadyHaveAccount: "\u0423\u0436\u0435 \u0435\u0441\u0442\u044C \u0430\u043A\u043A\u0430\u0443\u043D\u0442?",
416
+ dontHaveAccount: "\u041D\u0435\u0442 \u0430\u043A\u043A\u0430\u0443\u043D\u0442\u0430?",
417
+ signIn: "\u0412\u043E\u0439\u0442\u0438",
418
+ signUp: "\u0417\u0430\u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C\u0441\u044F",
419
+ or: "\u0438\u043B\u0438",
420
+ emailAddress: "\u042D\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430\u044F \u043F\u043E\u0447\u0442\u0430",
421
+ password: "\u041F\u0430\u0440\u043E\u043B\u044C",
422
+ 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)",
423
+ continueWith: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441",
424
+ connectWallet: "\u041F\u043E\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u044C \u043A\u043E\u0448\u0435\u043B\u0435\u043A",
425
+ magicLink: "\u041F\u0440\u043E\u0434\u043E\u043B\u0436\u0438\u0442\u044C \u0441 Magic Link",
426
+ passkey: "\u0412\u043E\u0439\u0442\u0438 \u0441 Passkey",
427
+ securedBy: "\u0417\u0430\u0449\u0438\u0449\u0435\u043D\u043E",
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"
435
+ },
436
+ it: {
437
+ welcomeBack: "Bentornato",
438
+ createAccount: "Crea il tuo account",
439
+ alreadyHaveAccount: "Hai gia un account?",
440
+ dontHaveAccount: "Non hai un account?",
441
+ signIn: "Accedi",
442
+ signUp: "Registrati",
443
+ or: "o",
444
+ emailAddress: "Indirizzo email",
445
+ password: "Password",
446
+ passwordHint: "Deve contenere maiuscole, minuscole e numeri (min 8 caratteri)",
447
+ continueWith: "Continua con",
448
+ connectWallet: "Connetti portafoglio",
449
+ magicLink: "Continua con Magic Link",
450
+ passkey: "Accedi con Passkey",
451
+ securedBy: "Protetto da",
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"
459
+ },
460
+ pl: {
461
+ welcomeBack: "Witaj ponownie",
462
+ createAccount: "Utworz konto",
463
+ alreadyHaveAccount: "Masz juz konto?",
464
+ dontHaveAccount: "Nie masz konta?",
465
+ signIn: "Zaloguj sie",
466
+ signUp: "Zarejestruj sie",
467
+ or: "lub",
468
+ emailAddress: "Adres e-mail",
469
+ password: "Haslo",
470
+ passwordHint: "Wielkie, male litery i cyfry (min 8 znakow)",
471
+ continueWith: "Kontynuuj z",
472
+ connectWallet: "Polacz portfel",
473
+ magicLink: "Kontynuuj z Magic Link",
474
+ passkey: "Zaloguj sie z Passkey",
475
+ securedBy: "Zabezpieczone przez",
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"
483
+ },
484
+ nl: {
485
+ welcomeBack: "Welkom terug",
486
+ createAccount: "Maak je account aan",
487
+ alreadyHaveAccount: "Heb je al een account?",
488
+ dontHaveAccount: "Nog geen account?",
489
+ signIn: "Inloggen",
490
+ signUp: "Registreren",
491
+ or: "of",
492
+ emailAddress: "E-mailadres",
493
+ password: "Wachtwoord",
494
+ passwordHint: "Hoofdletters, kleine letters en cijfers vereist (min 8 tekens)",
495
+ continueWith: "Doorgaan met",
496
+ connectWallet: "Portemonnee verbinden",
497
+ magicLink: "Doorgaan met Magic Link",
498
+ passkey: "Inloggen met Passkey",
499
+ securedBy: "Beveiligd door",
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"
507
+ },
508
+ ar: {
509
+ welcomeBack: "\u0645\u0631\u062D\u0628\u064B\u0627 \u0628\u0639\u0648\u062F\u062A\u0643",
510
+ createAccount: "\u0623\u0646\u0634\u0626 \u062D\u0633\u0627\u0628\u0643",
511
+ alreadyHaveAccount: "\u0644\u062F\u064A\u0643 \u062D\u0633\u0627\u0628 \u0628\u0627\u0644\u0641\u0639\u0644\u061F",
512
+ dontHaveAccount: "\u0644\u064A\u0633 \u0644\u062F\u064A\u0643 \u062D\u0633\u0627\u0628\u061F",
513
+ signIn: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644",
514
+ signUp: "\u0625\u0646\u0634\u0627\u0621 \u062D\u0633\u0627\u0628",
515
+ or: "\u0623\u0648",
516
+ emailAddress: "\u0627\u0644\u0628\u0631\u064A\u062F \u0627\u0644\u0625\u0644\u0643\u062A\u0631\u0648\u0646\u064A",
517
+ password: "\u0643\u0644\u0645\u0629 \u0627\u0644\u0645\u0631\u0648\u0631",
518
+ 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)",
519
+ continueWith: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645",
520
+ connectWallet: "\u0631\u0628\u0637 \u0627\u0644\u0645\u062D\u0641\u0638\u0629",
521
+ magicLink: "\u0627\u0644\u0645\u062A\u0627\u0628\u0639\u0629 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Magic Link",
522
+ passkey: "\u062A\u0633\u062C\u064A\u0644 \u0627\u0644\u062F\u062E\u0648\u0644 \u0628\u0627\u0633\u062A\u062E\u062F\u0627\u0645 Passkey",
523
+ securedBy: "\u0645\u062D\u0645\u064A \u0628\u0648\u0627\u0633\u0637\u0629",
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"
531
+ },
532
+ sv: {
533
+ welcomeBack: "Valkommen tillbaka",
534
+ createAccount: "Skapa ditt konto",
535
+ alreadyHaveAccount: "Har du redan ett konto?",
536
+ dontHaveAccount: "Har du inget konto?",
537
+ signIn: "Logga in",
538
+ signUp: "Registrera dig",
539
+ or: "eller",
540
+ emailAddress: "E-postadress",
541
+ password: "Losenord",
542
+ passwordHint: "Stora, sma bokstaver och siffror kravs (minst 8 tecken)",
543
+ continueWith: "Fortsatt med",
544
+ connectWallet: "Anslut planbok",
545
+ magicLink: "Fortsatt med Magic Link",
546
+ passkey: "Logga in med Passkey",
547
+ securedBy: "Sakrad av",
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"
555
+ },
556
+ uk: {
557
+ welcomeBack: "\u0417 \u043F\u043E\u0432\u0435\u0440\u043D\u0435\u043D\u043D\u044F\u043C",
558
+ createAccount: "\u0421\u0442\u0432\u043E\u0440\u0456\u0442\u044C \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441",
559
+ alreadyHaveAccount: "\u0412\u0436\u0435 \u0454 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u0438\u0439 \u0437\u0430\u043F\u0438\u0441?",
560
+ dontHaveAccount: "\u041D\u0435\u043C\u0430\u0454 \u043E\u0431\u043B\u0456\u043A\u043E\u0432\u043E\u0433\u043E \u0437\u0430\u043F\u0438\u0441\u0443?",
561
+ signIn: "\u0423\u0432\u0456\u0439\u0442\u0438",
562
+ signUp: "\u0417\u0430\u0440\u0435\u0454\u0441\u0442\u0440\u0443\u0432\u0430\u0442\u0438\u0441\u044F",
563
+ or: "\u0430\u0431\u043E",
564
+ emailAddress: "\u0415\u043B\u0435\u043A\u0442\u0440\u043E\u043D\u043D\u0430 \u043F\u043E\u0448\u0442\u0430",
565
+ password: "\u041F\u0430\u0440\u043E\u043B\u044C",
566
+ 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)",
567
+ continueWith: "\u041F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u0437",
568
+ connectWallet: "\u041F\u0456\u0434\u043A\u043B\u044E\u0447\u0438\u0442\u0438 \u0433\u0430\u043C\u0430\u043D\u0435\u0446\u044C",
569
+ magicLink: "\u041F\u0440\u043E\u0434\u043E\u0432\u0436\u0438\u0442\u0438 \u0437 Magic Link",
570
+ passkey: "\u0423\u0432\u0456\u0439\u0442\u0438 \u0437 Passkey",
571
+ securedBy: "\u0417\u0430\u0445\u0438\u0449\u0435\u043D\u043E",
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"
579
+ }
580
+ };
581
+ function getStrings(locale) {
582
+ if (locale in translations) return translations[locale];
583
+ const lang = locale.split("-")[0].split("_")[0];
584
+ if (lang in translations) return translations[lang];
585
+ return translations.en;
586
+ }
587
+
74
588
  // src/modal.ts
75
589
  function hexToRgba(hex, alpha) {
76
590
  const h = hex.replace("#", "");
@@ -126,6 +640,8 @@ var ModalRenderer = class {
126
640
  turnstileWidgetId = null;
127
641
  turnstileToken = "";
128
642
  turnstileWrapper = null;
643
+ // i18n
644
+ t;
129
645
  // Dev Teleport (test mode)
130
646
  isTestMode = false;
131
647
  onDevTeleport = null;
@@ -135,6 +651,7 @@ var ModalRenderer = class {
135
651
  this.branding = { ...DEFAULT_BRANDING, ...options.branding };
136
652
  this.captchaSiteKey = options.captchaSiteKey || "";
137
653
  this.isTestMode = options.isTestMode || false;
654
+ this.t = getStrings(options.locale || "en");
138
655
  this.onDevTeleport = options.onDevTeleport || null;
139
656
  this.onProviderClick = options.onProviderClick;
140
657
  this.onEmailSubmit = options.onEmailSubmit;
@@ -406,9 +923,9 @@ var ModalRenderer = class {
406
923
  buildInnerContent(view) {
407
924
  const b = this.branding;
408
925
  const isSignUp = view === "signUp";
409
- const title = isSignUp ? "Create your account" : "Welcome back";
410
- const subtitle = isSignUp ? "Already have an account?" : "Don't have an account?";
411
- const subtitleLink = isSignUp ? "Sign in" : "Sign up";
926
+ const title = isSignUp ? this.t.createAccount : this.t.welcomeBack;
927
+ const subtitle = isSignUp ? this.t.alreadyHaveAccount : this.t.dontHaveAccount;
928
+ const subtitleLink = isSignUp ? this.t.signIn : this.t.signUp;
412
929
  const dark = this.isDark();
413
930
  const showProviders = !isSignUp;
414
931
  const providerButtons = showProviders ? this.enabledProviders.filter((p) => !b.hiddenProviders?.includes(p)).map((p) => {
@@ -422,12 +939,12 @@ var ModalRenderer = class {
422
939
  </button>`;
423
940
  }).join("") : "";
424
941
  const hasVisibleProviders = showProviders && this.enabledProviders.filter((p) => !b.hiddenProviders?.includes(p)).length > 0;
425
- const divider = hasVisibleProviders && b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>or</span></div>` : "";
942
+ const divider = hasVisibleProviders && b.showDivider !== false && b.showEmailPassword !== false ? `<div class="divider"><span>${this.t.or}</span></div>` : "";
426
943
  const emailForm = b.showEmailPassword !== false ? `<form class="email-form" id="email-form">
427
- <input type="email" placeholder="Email address" name="email" required class="input" autocomplete="email" />
428
- <input type="password" placeholder="Password" name="password" required class="input" autocomplete="${isSignUp ? "new-password" : "current-password"}" />
429
- ${isSignUp ? '<p class="password-hint">Must contain uppercase, lowercase, and a number (min 8 chars)</p>' : ""}
430
- <button type="submit" class="submit-btn">${isSignUp ? "Sign up" : "Sign in"}</button>
944
+ <input type="email" placeholder="${this.t.emailAddress}" name="email" required class="input" autocomplete="email" />
945
+ <input type="password" placeholder="${this.t.password}" name="password" required class="input" autocomplete="${isSignUp ? "new-password" : "current-password"}" />
946
+ ${isSignUp ? `<p class="password-hint">${this.t.passwordHint}</p>` : ""}
947
+ <button type="submit" class="submit-btn">${isSignUp ? this.t.signUp : this.t.signIn}</button>
431
948
  </form>` : "";
432
949
  const hasMethodAbove = showProviders && this.enabledProviders.length > 0 || b.showEmailPassword !== false;
433
950
  const hasMethodBelow = b.showWeb3 || b.showPasswordless || b.showPasskey;
@@ -438,7 +955,7 @@ var ModalRenderer = class {
438
955
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
439
956
  <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"/>
440
957
  </svg>
441
- <span>Connect Wallet</span>
958
+ <span>${this.t.connectWallet}</span>
442
959
  </button>`);
443
960
  }
444
961
  if (b.showPasswordless) {
@@ -446,7 +963,7 @@ var ModalRenderer = class {
446
963
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
447
964
  <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"/>
448
965
  </svg>
449
- <span>Continue with Magic Link</span>
966
+ <span>${this.t.magicLink}</span>
450
967
  </button>`);
451
968
  }
452
969
  if (b.showPasskey) {
@@ -454,7 +971,7 @@ var ModalRenderer = class {
454
971
  <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
455
972
  <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"/>
456
973
  </svg>
457
- <span>Sign in with Passkey</span>
974
+ <span>${this.t.passkey}</span>
458
975
  </button>`);
459
976
  }
460
977
  const authMethods = methodButtons.length > 0 ? `<div class="auth-methods">${methodButtons.join("")}</div>` : "";
@@ -490,7 +1007,7 @@ var ModalRenderer = class {
490
1007
  <button type="button" id="dev-teleport-btn" class="dev-teleport-btn">Go</button>
491
1008
  </div>
492
1009
  </div>` : ""}
493
- ${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>` : ""}
1010
+ ${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>` : ""}
494
1011
  `;
495
1012
  }
496
1013
  renderTurnstile() {
@@ -1182,6 +1699,676 @@ var ModalRenderer = class {
1182
1699
  }
1183
1700
  };
1184
1701
 
1702
+ // src/profile.ts
1703
+ function hexToRgba2(hex, alpha) {
1704
+ const h = hex.replace("#", "");
1705
+ const r = parseInt(h.substring(0, 2), 16);
1706
+ const g = parseInt(h.substring(2, 4), 16);
1707
+ const b = parseInt(h.substring(4, 6), 16);
1708
+ return `rgba(${r},${g},${b},${alpha})`;
1709
+ }
1710
+ function formatRelativeTime(dateStr) {
1711
+ if (!dateStr) return "\u2014";
1712
+ const diff = Date.now() - new Date(dateStr).getTime();
1713
+ const minutes = Math.floor(diff / 6e4);
1714
+ if (minutes < 1) return "just now";
1715
+ if (minutes < 60) return `${minutes}m ago`;
1716
+ const hours = Math.floor(minutes / 60);
1717
+ if (hours < 24) return `${hours}h ago`;
1718
+ const days = Math.floor(hours / 24);
1719
+ return `${days}d ago`;
1720
+ }
1721
+ function parseUserAgent(ua) {
1722
+ if (!ua) return "Unknown device";
1723
+ if (/iPhone|iPad/.test(ua)) return "iOS";
1724
+ if (/Android/.test(ua)) return "Android";
1725
+ if (/Windows/.test(ua)) return "Windows";
1726
+ if (/Macintosh|Mac OS/.test(ua)) return "macOS";
1727
+ if (/Linux/.test(ua)) return "Linux";
1728
+ return "Unknown device";
1729
+ }
1730
+ var ProfileRenderer = class {
1731
+ shadowRoot = null;
1732
+ hostElement = null;
1733
+ containerElement = null;
1734
+ containerId = null;
1735
+ mode;
1736
+ theme;
1737
+ branding;
1738
+ themeObserver = null;
1739
+ mediaQueryListener = null;
1740
+ t;
1741
+ user;
1742
+ sessions;
1743
+ isEditMode = false;
1744
+ onSave;
1745
+ onSignOut;
1746
+ onRevokeSession;
1747
+ onClose;
1748
+ escHandler = null;
1749
+ constructor(options) {
1750
+ this.mode = options.mode;
1751
+ this.theme = options.theme || "auto";
1752
+ this.branding = { ...DEFAULT_BRANDING, ...options.branding };
1753
+ this.t = getStrings(options.locale || "en");
1754
+ this.user = options.user;
1755
+ this.sessions = options.sessions || [];
1756
+ this.onSave = options.onSave;
1757
+ this.onSignOut = options.onSignOut;
1758
+ this.onRevokeSession = options.onRevokeSession;
1759
+ this.onClose = options.onClose;
1760
+ if (options.mode === "embedded" && options.containerId) {
1761
+ this.containerId = options.containerId;
1762
+ }
1763
+ }
1764
+ resolveContainerElement() {
1765
+ if (this.mode !== "embedded" || !this.containerId) return null;
1766
+ const next = document.getElementById(this.containerId);
1767
+ if (this.containerElement !== next) {
1768
+ this.hostElement?.remove();
1769
+ this.hostElement = null;
1770
+ this.shadowRoot = null;
1771
+ }
1772
+ this.containerElement = next;
1773
+ return next;
1774
+ }
1775
+ open() {
1776
+ this.resolveContainerElement();
1777
+ if (this.hostElement && !this.hostElement.isConnected) {
1778
+ this.hostElement = null;
1779
+ this.shadowRoot = null;
1780
+ }
1781
+ if (this.shadowRoot && this.hostElement) {
1782
+ this.rerender();
1783
+ } else {
1784
+ this.isEditMode = false;
1785
+ this.render();
1786
+ }
1787
+ }
1788
+ close() {
1789
+ this.stopThemeObserver();
1790
+ if (this.escHandler) {
1791
+ document.removeEventListener("keydown", this.escHandler);
1792
+ this.escHandler = null;
1793
+ }
1794
+ if (this.hostElement) {
1795
+ this.hostElement.remove();
1796
+ this.hostElement = null;
1797
+ this.shadowRoot = null;
1798
+ }
1799
+ const liveContainer = this.resolveContainerElement();
1800
+ if (liveContainer) {
1801
+ liveContainer.replaceChildren();
1802
+ }
1803
+ }
1804
+ updateUser(user) {
1805
+ this.user = user;
1806
+ if (this.shadowRoot) this.rerender();
1807
+ }
1808
+ updateSessions(sessions) {
1809
+ this.sessions = sessions;
1810
+ if (this.shadowRoot) this.rerender();
1811
+ }
1812
+ setTheme(theme) {
1813
+ this.theme = theme;
1814
+ this.updateThemeCSS();
1815
+ if (theme === "auto") {
1816
+ this.startThemeObserver();
1817
+ } else {
1818
+ this.stopThemeObserver();
1819
+ }
1820
+ }
1821
+ showSaving() {
1822
+ if (!this.shadowRoot) return;
1823
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1824
+ if (btn) {
1825
+ btn.disabled = true;
1826
+ btn.textContent = "...";
1827
+ }
1828
+ }
1829
+ showSaveError(message) {
1830
+ if (!this.shadowRoot) return;
1831
+ const btn = this.shadowRoot.getElementById("profile-save-btn");
1832
+ if (btn) {
1833
+ btn.disabled = false;
1834
+ btn.textContent = this.t.save;
1835
+ }
1836
+ this.showInlineError("profile-error", message);
1837
+ }
1838
+ showInlineError(id, message) {
1839
+ if (!this.shadowRoot) return;
1840
+ this.shadowRoot.getElementById(id)?.remove();
1841
+ const errEl = document.createElement("div");
1842
+ errEl.id = id;
1843
+ errEl.className = "error-msg";
1844
+ errEl.textContent = message;
1845
+ this.shadowRoot.querySelector(".profile-actions")?.appendChild(errEl);
1846
+ }
1847
+ updateThemeCSS() {
1848
+ if (!this.shadowRoot) return;
1849
+ const styleEl = this.shadowRoot.getElementById("authon-profile-theme-style");
1850
+ if (styleEl) styleEl.textContent = this.buildCSS();
1851
+ }
1852
+ startThemeObserver() {
1853
+ this.stopThemeObserver();
1854
+ if (typeof document === "undefined" || typeof window === "undefined") return;
1855
+ this.themeObserver = new MutationObserver(() => this.updateThemeCSS());
1856
+ this.themeObserver.observe(document.documentElement, {
1857
+ attributes: true,
1858
+ attributeFilter: ["data-theme", "class"]
1859
+ });
1860
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
1861
+ this.mediaQueryListener = () => this.updateThemeCSS();
1862
+ mq.addEventListener("change", this.mediaQueryListener);
1863
+ }
1864
+ stopThemeObserver() {
1865
+ if (this.themeObserver) {
1866
+ this.themeObserver.disconnect();
1867
+ this.themeObserver = null;
1868
+ }
1869
+ if (this.mediaQueryListener) {
1870
+ window.matchMedia("(prefers-color-scheme: dark)").removeEventListener("change", this.mediaQueryListener);
1871
+ this.mediaQueryListener = null;
1872
+ }
1873
+ }
1874
+ isDark() {
1875
+ if (this.theme === "dark") return true;
1876
+ if (this.theme === "light") return false;
1877
+ if (typeof document !== "undefined") {
1878
+ const html = document.documentElement;
1879
+ if (html.classList.contains("dark") || html.getAttribute("data-theme") === "dark") return true;
1880
+ if (html.classList.contains("light") || html.getAttribute("data-theme") === "light") return false;
1881
+ }
1882
+ return typeof window !== "undefined" && window.matchMedia("(prefers-color-scheme: dark)").matches;
1883
+ }
1884
+ render() {
1885
+ const host = document.createElement("div");
1886
+ host.setAttribute("data-authon-profile", "");
1887
+ this.hostElement = host;
1888
+ if (this.mode === "popup") {
1889
+ document.body.appendChild(host);
1890
+ } else {
1891
+ const container = this.resolveContainerElement();
1892
+ if (!container) {
1893
+ this.hostElement = null;
1894
+ throw new Error(`Authon profile container "#${this.containerId}" not found`);
1895
+ }
1896
+ container.replaceChildren();
1897
+ container.appendChild(host);
1898
+ }
1899
+ this.shadowRoot = host.attachShadow({ mode: "open" });
1900
+ this.shadowRoot.innerHTML = this.buildShell();
1901
+ this.attachEvents();
1902
+ if (this.mode === "popup") {
1903
+ this.escHandler = (e) => {
1904
+ if (e.key === "Escape") {
1905
+ this.onClose();
1906
+ this.close();
1907
+ }
1908
+ };
1909
+ document.addEventListener("keydown", this.escHandler);
1910
+ }
1911
+ if (this.theme === "auto") this.startThemeObserver();
1912
+ }
1913
+ rerender() {
1914
+ if (!this.shadowRoot) return;
1915
+ const inner = this.shadowRoot.getElementById("profile-inner");
1916
+ if (!inner) return;
1917
+ inner.style.opacity = "0";
1918
+ inner.style.transform = "translateY(-4px)";
1919
+ setTimeout(() => {
1920
+ inner.innerHTML = this.buildInnerContent();
1921
+ this.attachInnerEvents();
1922
+ void inner.offsetHeight;
1923
+ inner.style.opacity = "1";
1924
+ inner.style.transform = "translateY(0)";
1925
+ }, 120);
1926
+ }
1927
+ buildShell() {
1928
+ const popupWrapper = this.mode === "popup" ? `<div class="backdrop" id="profile-backdrop"></div>` : "";
1929
+ return `
1930
+ <style id="authon-profile-theme-style">${this.buildCSS()}</style>
1931
+ ${popupWrapper}
1932
+ <div class="profile-container" role="dialog" aria-modal="true" aria-label="${this.t.profile}">
1933
+ <div id="profile-inner" class="profile-inner">
1934
+ ${this.buildInnerContent()}
1935
+ </div>
1936
+ </div>
1937
+ `;
1938
+ }
1939
+ buildInnerContent() {
1940
+ const u = this.user;
1941
+ const initials = (u.displayName || u.email || "?").split(/\s+/).map((w) => w[0]?.toUpperCase() ?? "").slice(0, 2).join("");
1942
+ const avatarHtml = u.avatarUrl ? `<img class="avatar-img" src="${u.avatarUrl}" alt="${u.displayName || ""}" />` : `<div class="avatar-placeholder">${initials}</div>`;
1943
+ const closeBtn = this.mode === "popup" ? `<button class="close-btn" id="profile-close-btn" aria-label="Close">
1944
+ <svg width="16" height="16" viewBox="0 0 16 16" fill="none">
1945
+ <path d="M12 4L4 12M4 4l8 8" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>
1946
+ </svg>
1947
+ </button>` : "";
1948
+ if (this.isEditMode) {
1949
+ return this.buildEditContent(avatarHtml, closeBtn);
1950
+ }
1951
+ return this.buildViewContent(avatarHtml, closeBtn, u);
1952
+ }
1953
+ buildViewContent(avatarHtml, closeBtn, u) {
1954
+ const sessionsHtml = this.sessions.length > 0 ? `<div class="section">
1955
+ <div class="section-label">${this.t.sessions}</div>
1956
+ <div class="sessions-list">
1957
+ ${this.sessions.map((s) => `
1958
+ <div class="session-item" data-session-id="${s.id}">
1959
+ <div class="session-info">
1960
+ <span class="session-device">${parseUserAgent(s.userAgent)}</span>
1961
+ <span class="session-meta">${s.ipAddress || ""} &middot; ${formatRelativeTime(s.lastActiveAt)}</span>
1962
+ </div>
1963
+ <button class="session-revoke-btn" data-session-id="${s.id}" aria-label="Revoke session">
1964
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none">
1965
+ <path d="M10.5 3.5L3.5 10.5M3.5 3.5l7 7" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
1966
+ </svg>
1967
+ </button>
1968
+ </div>
1969
+ `).join("")}
1970
+ </div>
1971
+ </div>` : "";
1972
+ return `
1973
+ <div class="profile-header">
1974
+ <div class="avatar-wrap">${avatarHtml}</div>
1975
+ <div class="header-text">
1976
+ <div class="display-name">${u.displayName || "\u2014"}</div>
1977
+ <div class="email">${u.email || "\u2014"}</div>
1978
+ </div>
1979
+ ${closeBtn}
1980
+ </div>
1981
+
1982
+ <div class="section">
1983
+ <div class="field-row">
1984
+ <span class="field-label">${this.t.emailAddress}</span>
1985
+ <span class="field-value readonly">${u.email || "\u2014"}</span>
1986
+ </div>
1987
+ <div class="field-row">
1988
+ <span class="field-label">${this.t.displayName}</span>
1989
+ <span class="field-value">${u.displayName || "\u2014"}</span>
1990
+ </div>
1991
+ </div>
1992
+
1993
+ ${sessionsHtml}
1994
+
1995
+ <div class="profile-actions">
1996
+ <button class="edit-btn" id="profile-edit-btn">${this.t.editProfile}</button>
1997
+ <button class="signout-btn" id="profile-signout-btn">${this.t.signOut}</button>
1998
+ </div>
1999
+ `;
2000
+ }
2001
+ buildEditContent(avatarHtml, closeBtn) {
2002
+ const u = this.user;
2003
+ return `
2004
+ <div class="profile-header">
2005
+ <div class="avatar-wrap">${avatarHtml}</div>
2006
+ <div class="header-text">
2007
+ <div class="display-name">${this.t.editProfile}</div>
2008
+ <div class="email">${u.email || "\u2014"}</div>
2009
+ </div>
2010
+ ${closeBtn}
2011
+ </div>
2012
+
2013
+ <div class="section">
2014
+ <div class="field-group">
2015
+ <label class="field-label" for="profile-displayname-input">${this.t.displayName}</label>
2016
+ <input
2017
+ id="profile-displayname-input"
2018
+ class="input"
2019
+ type="text"
2020
+ value="${u.displayName || ""}"
2021
+ placeholder="${this.t.displayName}"
2022
+ autocomplete="name"
2023
+ />
2024
+ </div>
2025
+ <div class="field-group">
2026
+ <label class="field-label" for="profile-avatar-input">Avatar URL</label>
2027
+ <input
2028
+ id="profile-avatar-input"
2029
+ class="input"
2030
+ type="url"
2031
+ value="${u.avatarUrl || ""}"
2032
+ placeholder="https://..."
2033
+ autocomplete="off"
2034
+ />
2035
+ </div>
2036
+ <div class="field-group">
2037
+ <label class="field-label">${this.t.emailAddress}</label>
2038
+ <input class="input readonly" type="email" value="${u.email || ""}" disabled />
2039
+ </div>
2040
+ </div>
2041
+
2042
+ <div class="profile-actions">
2043
+ <button class="save-btn" id="profile-save-btn">${this.t.save}</button>
2044
+ <button class="cancel-btn" id="profile-cancel-btn">Cancel</button>
2045
+ </div>
2046
+ `;
2047
+ }
2048
+ buildCSS() {
2049
+ const b = this.branding;
2050
+ const dark = this.isDark();
2051
+ const bg = dark ? b.darkBg || "#0f172a" : b.lightBg || "#ffffff";
2052
+ const text = dark ? b.darkText || "#f1f5f9" : b.lightText || "#111827";
2053
+ const mutedText = dark ? "#94a3b8" : "#6b7280";
2054
+ const dimText = dark ? "#64748b" : "#9ca3af";
2055
+ const borderColor = dark ? "#334155" : "#d1d5db";
2056
+ const dividerColor = dark ? "#334155" : "#e5e7eb";
2057
+ const inputBg = dark ? "#1e293b" : "#ffffff";
2058
+ const sectionBg = dark ? "#1e293b" : "#f9fafb";
2059
+ const sessionItemBg = dark ? "#263148" : "#f3f4f6";
2060
+ return `
2061
+ :host {
2062
+ --authon-primary-start: ${b.primaryColorStart || "#7c3aed"};
2063
+ --authon-primary-end: ${b.primaryColorEnd || "#4f46e5"};
2064
+ --authon-bg: ${bg};
2065
+ --authon-text: ${text};
2066
+ --authon-muted: ${mutedText};
2067
+ --authon-dim: ${dimText};
2068
+ --authon-border: ${borderColor};
2069
+ --authon-divider: ${dividerColor};
2070
+ --authon-input-bg: ${inputBg};
2071
+ --authon-section-bg: ${sectionBg};
2072
+ --authon-session-bg: ${sessionItemBg};
2073
+ --authon-backdrop-bg: rgba(0,0,0,${dark ? "0.7" : "0.5"});
2074
+ --authon-radius: ${b.borderRadius ?? 12}px;
2075
+ --authon-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
2076
+ font-family: var(--authon-font);
2077
+ color: var(--authon-text);
2078
+ }
2079
+ * { box-sizing: border-box; margin: 0; padding: 0; }
2080
+
2081
+ .backdrop {
2082
+ position: fixed; inset: 0; z-index: 99998;
2083
+ background: var(--authon-backdrop-bg); backdrop-filter: blur(4px);
2084
+ animation: fadeIn 0.2s ease;
2085
+ }
2086
+
2087
+ .profile-container {
2088
+ ${this.mode === "popup" ? "position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 99999; max-height: 90vh; overflow-y: auto;" : ""}
2089
+ background: var(--authon-bg);
2090
+ color: var(--authon-text);
2091
+ border: 1px solid var(--authon-border);
2092
+ border-radius: var(--authon-radius);
2093
+ padding: 24px;
2094
+ width: 380px; max-width: 100%;
2095
+ ${this.mode === "popup" ? `box-shadow: 0 25px 50px -12px rgba(0,0,0,${dark ? "0.5" : "0.25"}); animation: slideIn 0.3s ease;` : ""}
2096
+ }
2097
+
2098
+ .profile-inner {
2099
+ transition: opacity 0.12s ease, transform 0.12s ease;
2100
+ }
2101
+
2102
+ .profile-header {
2103
+ display: flex;
2104
+ align-items: center;
2105
+ gap: 14px;
2106
+ margin-bottom: 20px;
2107
+ position: relative;
2108
+ }
2109
+
2110
+ .avatar-wrap { flex-shrink: 0; }
2111
+
2112
+ .avatar-img {
2113
+ width: 52px; height: 52px;
2114
+ border-radius: 50%;
2115
+ object-fit: cover;
2116
+ border: 2px solid var(--authon-border);
2117
+ }
2118
+
2119
+ .avatar-placeholder {
2120
+ width: 52px; height: 52px;
2121
+ border-radius: 50%;
2122
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2123
+ display: flex; align-items: center; justify-content: center;
2124
+ font-size: 18px; font-weight: 700; color: #fff;
2125
+ flex-shrink: 0;
2126
+ }
2127
+
2128
+ .header-text { flex: 1; min-width: 0; }
2129
+
2130
+ .display-name {
2131
+ font-size: 16px; font-weight: 600;
2132
+ color: var(--authon-text);
2133
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2134
+ }
2135
+
2136
+ .email {
2137
+ font-size: 13px; color: var(--authon-muted);
2138
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2139
+ margin-top: 2px;
2140
+ }
2141
+
2142
+ .close-btn {
2143
+ position: absolute; top: 0; right: 0;
2144
+ background: none; border: none;
2145
+ color: var(--authon-muted); cursor: pointer;
2146
+ padding: 4px; border-radius: 6px;
2147
+ display: flex; align-items: center; justify-content: center;
2148
+ transition: color 0.15s, background 0.15s;
2149
+ }
2150
+ .close-btn:hover { color: var(--authon-text); background: var(--authon-divider); }
2151
+
2152
+ .section {
2153
+ background: var(--authon-section-bg);
2154
+ border: 1px solid var(--authon-border);
2155
+ border-radius: calc(var(--authon-radius) * 0.67);
2156
+ padding: 12px 14px;
2157
+ margin-bottom: 12px;
2158
+ display: flex; flex-direction: column; gap: 10px;
2159
+ }
2160
+
2161
+ .section-label {
2162
+ font-size: 11px; font-weight: 600;
2163
+ text-transform: uppercase; letter-spacing: 0.05em;
2164
+ color: var(--authon-dim); margin-bottom: 2px;
2165
+ }
2166
+
2167
+ .field-row {
2168
+ display: flex; align-items: center; justify-content: space-between; gap: 8px;
2169
+ }
2170
+
2171
+ .field-label {
2172
+ font-size: 12px; color: var(--authon-muted); flex-shrink: 0;
2173
+ }
2174
+
2175
+ .field-value {
2176
+ font-size: 13px; color: var(--authon-text);
2177
+ text-align: right; min-width: 0;
2178
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2179
+ }
2180
+
2181
+ .field-value.readonly { color: var(--authon-dim); }
2182
+
2183
+ .field-group {
2184
+ display: flex; flex-direction: column; gap: 4px;
2185
+ }
2186
+
2187
+ .input {
2188
+ width: 100%; padding: 9px 12px;
2189
+ background: var(--authon-input-bg);
2190
+ color: var(--authon-text);
2191
+ border: 1px solid var(--authon-border);
2192
+ border-radius: calc(var(--authon-radius) * 0.5);
2193
+ font-size: 13px; font-family: var(--authon-font);
2194
+ outline: none; transition: border-color 0.15s;
2195
+ }
2196
+ .input::placeholder { color: var(--authon-dim); }
2197
+ .input:focus { border-color: var(--authon-primary-start); box-shadow: 0 0 0 3px ${hexToRgba2(b.primaryColorStart || "#7c3aed", 0.15)}; }
2198
+ .input.readonly, .input:disabled { color: var(--authon-dim); cursor: not-allowed; background: var(--authon-section-bg); }
2199
+
2200
+ .sessions-list { display: flex; flex-direction: column; gap: 6px; }
2201
+
2202
+ .session-item {
2203
+ display: flex; align-items: center; justify-content: space-between;
2204
+ background: var(--authon-session-bg);
2205
+ border-radius: calc(var(--authon-radius) * 0.5);
2206
+ padding: 8px 10px; gap: 8px;
2207
+ }
2208
+
2209
+ .session-info { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
2210
+
2211
+ .session-device {
2212
+ font-size: 13px; font-weight: 500; color: var(--authon-text);
2213
+ }
2214
+
2215
+ .session-meta {
2216
+ font-size: 11px; color: var(--authon-dim);
2217
+ white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
2218
+ }
2219
+
2220
+ .session-revoke-btn {
2221
+ background: none; border: none;
2222
+ color: var(--authon-dim); cursor: pointer;
2223
+ padding: 4px; border-radius: 4px; flex-shrink: 0;
2224
+ display: flex; align-items: center; justify-content: center;
2225
+ transition: color 0.15s, background 0.15s;
2226
+ }
2227
+ .session-revoke-btn:hover { color: #ef4444; background: rgba(239,68,68,0.1); }
2228
+
2229
+ .profile-actions {
2230
+ display: flex; flex-direction: column; gap: 8px;
2231
+ margin-top: 4px;
2232
+ }
2233
+
2234
+ .edit-btn {
2235
+ width: 100%; padding: 10px;
2236
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2237
+ color: #fff; border: none;
2238
+ border-radius: calc(var(--authon-radius) * 0.5);
2239
+ font-size: 14px; font-weight: 600; cursor: pointer;
2240
+ font-family: var(--authon-font); transition: opacity 0.15s;
2241
+ }
2242
+ .edit-btn:hover { opacity: 0.9; }
2243
+
2244
+ .save-btn {
2245
+ width: 100%; padding: 10px;
2246
+ background: linear-gradient(135deg, var(--authon-primary-start), var(--authon-primary-end));
2247
+ color: #fff; border: none;
2248
+ border-radius: calc(var(--authon-radius) * 0.5);
2249
+ font-size: 14px; font-weight: 600; cursor: pointer;
2250
+ font-family: var(--authon-font); transition: opacity 0.15s;
2251
+ }
2252
+ .save-btn:hover { opacity: 0.9; }
2253
+ .save-btn:disabled { opacity: 0.6; cursor: not-allowed; }
2254
+
2255
+ .cancel-btn {
2256
+ width: 100%; padding: 10px;
2257
+ background: none;
2258
+ color: var(--authon-muted);
2259
+ border: 1px solid var(--authon-border);
2260
+ border-radius: calc(var(--authon-radius) * 0.5);
2261
+ font-size: 14px; font-weight: 500; cursor: pointer;
2262
+ font-family: var(--authon-font); transition: background 0.15s, color 0.15s;
2263
+ }
2264
+ .cancel-btn:hover { background: var(--authon-divider); color: var(--authon-text); }
2265
+
2266
+ .signout-btn {
2267
+ width: 100%; padding: 10px;
2268
+ background: none;
2269
+ color: #ef4444;
2270
+ border: 1px solid rgba(239,68,68,0.3);
2271
+ border-radius: calc(var(--authon-radius) * 0.5);
2272
+ font-size: 14px; font-weight: 500; cursor: pointer;
2273
+ font-family: var(--authon-font); transition: background 0.15s;
2274
+ }
2275
+ .signout-btn:hover { background: rgba(239,68,68,0.08); }
2276
+
2277
+ .error-msg {
2278
+ padding: 8px 12px;
2279
+ background: rgba(239,68,68,0.1); border: 1px solid rgba(239,68,68,0.3);
2280
+ border-radius: calc(var(--authon-radius) * 0.33);
2281
+ font-size: 13px; color: #ef4444; text-align: center;
2282
+ animation: fadeIn 0.15s ease;
2283
+ }
2284
+
2285
+ @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
2286
+ @keyframes slideIn { from { opacity: 0; transform: translate(-50%, calc(-50% - 8px)); } to { opacity: 1; transform: translate(-50%, -50%); } }
2287
+ `;
2288
+ }
2289
+ attachEvents() {
2290
+ this.attachBackdropEvent();
2291
+ this.attachInnerEvents();
2292
+ }
2293
+ attachBackdropEvent() {
2294
+ if (!this.shadowRoot || this.mode !== "popup") return;
2295
+ const backdrop = this.shadowRoot.getElementById("profile-backdrop");
2296
+ if (backdrop) {
2297
+ backdrop.addEventListener("click", () => {
2298
+ this.onClose();
2299
+ this.close();
2300
+ });
2301
+ }
2302
+ }
2303
+ attachInnerEvents() {
2304
+ if (!this.shadowRoot) return;
2305
+ const closeBtn = this.shadowRoot.getElementById("profile-close-btn");
2306
+ closeBtn?.addEventListener("click", () => {
2307
+ this.onClose();
2308
+ this.close();
2309
+ });
2310
+ const editBtn = this.shadowRoot.getElementById("profile-edit-btn");
2311
+ editBtn?.addEventListener("click", () => {
2312
+ this.isEditMode = true;
2313
+ this.rerender();
2314
+ });
2315
+ const cancelBtn = this.shadowRoot.getElementById("profile-cancel-btn");
2316
+ cancelBtn?.addEventListener("click", () => {
2317
+ this.isEditMode = false;
2318
+ this.rerender();
2319
+ });
2320
+ const saveBtn = this.shadowRoot.getElementById("profile-save-btn");
2321
+ saveBtn?.addEventListener("click", async () => {
2322
+ const nameInput = this.shadowRoot.getElementById("profile-displayname-input");
2323
+ const avatarInput = this.shadowRoot.getElementById("profile-avatar-input");
2324
+ const displayName = nameInput?.value.trim();
2325
+ const avatarUrl = avatarInput?.value.trim();
2326
+ this.showSaving();
2327
+ this.shadowRoot.getElementById("profile-error")?.remove();
2328
+ try {
2329
+ await this.onSave({
2330
+ displayName: displayName || void 0,
2331
+ avatarUrl: avatarUrl || void 0
2332
+ });
2333
+ this.isEditMode = false;
2334
+ this.rerender();
2335
+ } catch (err) {
2336
+ this.showSaveError(err instanceof Error ? err.message : "Save failed");
2337
+ }
2338
+ });
2339
+ const signOutBtn = this.shadowRoot.getElementById("profile-signout-btn");
2340
+ signOutBtn?.addEventListener("click", async () => {
2341
+ if (signOutBtn instanceof HTMLButtonElement) {
2342
+ signOutBtn.disabled = true;
2343
+ signOutBtn.textContent = "...";
2344
+ }
2345
+ try {
2346
+ await this.onSignOut();
2347
+ this.close();
2348
+ } catch (_) {
2349
+ if (signOutBtn instanceof HTMLButtonElement) {
2350
+ signOutBtn.disabled = false;
2351
+ signOutBtn.textContent = this.t.signOut;
2352
+ }
2353
+ }
2354
+ });
2355
+ this.shadowRoot.querySelectorAll(".session-revoke-btn").forEach((btn) => {
2356
+ btn.addEventListener("click", async () => {
2357
+ const sessionId = btn.dataset.sessionId;
2358
+ if (!sessionId) return;
2359
+ btn.disabled = true;
2360
+ try {
2361
+ await this.onRevokeSession(sessionId);
2362
+ this.sessions = this.sessions.filter((s) => s.id !== sessionId);
2363
+ this.rerender();
2364
+ } catch (_) {
2365
+ btn.disabled = false;
2366
+ }
2367
+ });
2368
+ });
2369
+ }
2370
+ };
2371
+
1185
2372
  // src/session.ts
1186
2373
  var SessionManager = class {
1187
2374
  accessToken = null;
@@ -1711,6 +2898,7 @@ var Authon = class {
1711
2898
  config;
1712
2899
  session;
1713
2900
  modal = null;
2901
+ profile = null;
1714
2902
  listeners = /* @__PURE__ */ new Map();
1715
2903
  branding = null;
1716
2904
  providers = [];
@@ -1744,9 +2932,56 @@ var Authon = class {
1744
2932
  await this.ensureInitialized();
1745
2933
  this.getModal().open("signUp");
1746
2934
  }
2935
+ async openProfile() {
2936
+ const user = this.getUser();
2937
+ if (!user) throw new Error("Must be signed in to open profile");
2938
+ const token = this.session.getToken();
2939
+ let sessions = [];
2940
+ if (token) {
2941
+ try {
2942
+ sessions = await this.listSessions();
2943
+ } catch (_) {
2944
+ }
2945
+ }
2946
+ if (!this.profile) {
2947
+ this.profile = new ProfileRenderer({
2948
+ mode: this.config.mode,
2949
+ theme: this.config.theme,
2950
+ locale: this.config.locale,
2951
+ containerId: this.config.containerId,
2952
+ branding: this.branding || void 0,
2953
+ user,
2954
+ sessions,
2955
+ onSave: async (data) => {
2956
+ const updated = await this.updateProfile(data);
2957
+ this.profile?.updateUser(updated);
2958
+ },
2959
+ onSignOut: async () => {
2960
+ await this.signOut();
2961
+ this.profile = null;
2962
+ },
2963
+ onRevokeSession: async (sessionId) => {
2964
+ await this.revokeSession(sessionId);
2965
+ },
2966
+ onClose: () => {
2967
+ this.profile?.close();
2968
+ this.profile = null;
2969
+ }
2970
+ });
2971
+ } else {
2972
+ this.profile.updateUser(user);
2973
+ this.profile.updateSessions(sessions);
2974
+ }
2975
+ this.profile.open();
2976
+ }
2977
+ closeProfile() {
2978
+ this.profile?.close();
2979
+ this.profile = null;
2980
+ }
1747
2981
  /** Update theme at runtime without destroying form state */
1748
2982
  setTheme(theme) {
1749
2983
  this.getModal().setTheme(theme);
2984
+ this.profile?.setTheme(theme);
1750
2985
  }
1751
2986
  async signInWithOAuth(provider, options) {
1752
2987
  await this.ensureInitialized();
@@ -2059,6 +3294,8 @@ var Authon = class {
2059
3294
  }
2060
3295
  destroy() {
2061
3296
  this.modal?.close();
3297
+ this.profile?.close();
3298
+ this.profile = null;
2062
3299
  this.session.destroy();
2063
3300
  this.listeners.clear();
2064
3301
  }
@@ -2105,6 +3342,7 @@ var Authon = class {
2105
3342
  this.modal = new ModalRenderer({
2106
3343
  mode: this.config.mode,
2107
3344
  theme: this.config.theme,
3345
+ locale: this.config.locale,
2108
3346
  containerId: this.config.containerId,
2109
3347
  branding: this.branding || void 0,
2110
3348
  captchaSiteKey: this.captchaEnabled ? this.turnstileSiteKey : void 0,
@@ -2561,7 +3799,10 @@ var Authon = class {
2561
3799
  export {
2562
3800
  Authon,
2563
3801
  AuthonMfaRequiredError,
3802
+ ProfileRenderer,
2564
3803
  generateQrSvg,
2565
- getProviderButtonConfig
3804
+ getProviderButtonConfig,
3805
+ getStrings,
3806
+ translations
2566
3807
  };
2567
3808
  //# sourceMappingURL=index.js.map