@arcblock/did-connect-core 4.1.53 → 4.1.55
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/ui/i18n.d.ts.map +1 -1
- package/dist/ui/i18n.js +32 -4
- package/dist/ui/i18n.js.map +1 -1
- package/dist/ui/index.bundle.js +321 -158
- package/dist/ui/login-dialog.d.ts.map +1 -1
- package/dist/ui/login-dialog.js +4 -0
- package/dist/ui/login-dialog.js.map +1 -1
- package/dist/ui/login-page.d.ts +4 -0
- package/dist/ui/login-page.d.ts.map +1 -1
- package/dist/ui/login-page.js +232 -147
- package/dist/ui/login-page.js.map +1 -1
- package/dist/ui/styles.d.ts.map +1 -1
- package/dist/ui/styles.js +54 -23
- package/dist/ui/styles.js.map +1 -1
- package/package.json +1 -1
package/dist/ui/index.bundle.js
CHANGED
|
@@ -381,12 +381,19 @@ var messages = {
|
|
|
381
381
|
emailExplanation: "We will send you a verification code. No password needed.",
|
|
382
382
|
otherMethods: "Other ways to sign in",
|
|
383
383
|
passkeyCreateAccount: "Create an account with Passkey",
|
|
384
|
-
lastUsed: "Last used
|
|
384
|
+
lastUsed: "Last used",
|
|
385
385
|
passkeyExplanation: "Create a new account using your fingerprint, face, or device unlock. Your device will ask you to save a Passkey. Already have an account? Go back to sign in.",
|
|
386
386
|
continueWith: "Continue with {provider}",
|
|
387
387
|
oauthWaiting: "Continue in the {provider} window",
|
|
388
388
|
oauthIncomplete: "Sign-in is not complete. Reopen the window or choose another method.",
|
|
389
389
|
oauthReopen: "Reopen window",
|
|
390
|
+
oauthUnconfirmed: "We could not confirm sign-in. Reload this page to check your session before trying again.",
|
|
391
|
+
oauthCheckSession: "Reload and check sign-in",
|
|
392
|
+
oauthCancelled: "Stopped waiting for sign-in. If the provider window is still open, close it before retrying.",
|
|
393
|
+
oauthDenied: "Authorization was declined. Try again or choose another sign-in method.",
|
|
394
|
+
oauthBlocked: "Your browser blocked the sign-in window. Reopen it or continue on this page.",
|
|
395
|
+
oauthTimedOut: "Sign-in timed out. Reopen the window to start again.",
|
|
396
|
+
oauthFailed: "We could not complete sign-in. Try again or choose another method.",
|
|
390
397
|
oauthFullPage: "Continue on this page",
|
|
391
398
|
emailEdit: "Change email",
|
|
392
399
|
emailCooldown: "Resend in {seconds}s",
|
|
@@ -447,12 +454,19 @@ var messages = {
|
|
|
447
454
|
emailExplanation: "\u6211\u4EEC\u4F1A\u53D1\u9001\u9A8C\u8BC1\u7801\uFF0C\u65E0\u9700\u5BC6\u7801\u3002",
|
|
448
455
|
otherMethods: "\u5176\u4ED6\u767B\u5F55\u65B9\u5F0F",
|
|
449
456
|
passkeyCreateAccount: "\u4F7F\u7528 Passkey \u521B\u5EFA\u8D26\u6237",
|
|
450
|
-
lastUsed: "\u4E0A\u6B21\u4F7F\u7528
|
|
457
|
+
lastUsed: "\u4E0A\u6B21\u4F7F\u7528",
|
|
451
458
|
passkeyExplanation: "\u4F7F\u7528\u6307\u7EB9\u3001\u9762\u5BB9\u6216\u8BBE\u5907\u89E3\u9501\u65B9\u5F0F\u521B\u5EFA\u65B0\u8D26\u6237\uFF0C\u65E0\u9700\u5BC6\u7801\u3002\u8BBE\u5907\u4F1A\u63D0\u793A\u4FDD\u5B58 Passkey\u3002\u5DF2\u6709\u8D26\u6237\uFF1F\u8BF7\u8FD4\u56DE\u767B\u5F55\u3002",
|
|
452
459
|
continueWith: "\u4F7F\u7528 {provider} \u7EE7\u7EED",
|
|
453
460
|
oauthWaiting: "\u8BF7\u5728 {provider} \u7A97\u53E3\u4E2D\u7EE7\u7EED",
|
|
454
461
|
oauthIncomplete: "\u767B\u5F55\u5C1A\u672A\u5B8C\u6210\u3002\u60A8\u53EF\u4EE5\u91CD\u65B0\u6253\u5F00\u7A97\u53E3\u6216\u9009\u62E9\u5176\u4ED6\u65B9\u5F0F\u3002",
|
|
455
462
|
oauthReopen: "\u91CD\u65B0\u6253\u5F00\u7A97\u53E3",
|
|
463
|
+
oauthUnconfirmed: "\u6682\u65F6\u65E0\u6CD5\u786E\u8BA4\u767B\u5F55\u7ED3\u679C\u3002\u8BF7\u5148\u91CD\u65B0\u52A0\u8F7D\u9875\u9762\u68C0\u67E5\u767B\u5F55\u72B6\u6001\uFF0C\u518D\u51B3\u5B9A\u662F\u5426\u91CD\u8BD5\u3002",
|
|
464
|
+
oauthCheckSession: "\u91CD\u65B0\u52A0\u8F7D\u5E76\u68C0\u67E5\u767B\u5F55\u72B6\u6001",
|
|
465
|
+
oauthCancelled: "\u5DF2\u505C\u6B62\u7B49\u5F85\u767B\u5F55\u3002\u82E5\u6388\u6743\u7A97\u53E3\u4ECD\u7136\u6253\u5F00\uFF0C\u8BF7\u5173\u95ED\u540E\u518D\u91CD\u8BD5\u3002",
|
|
466
|
+
oauthDenied: "\u60A8\u672A\u540C\u610F\u6388\u6743\u3002\u53EF\u4EE5\u91CD\u8BD5\u6216\u9009\u62E9\u5176\u4ED6\u767B\u5F55\u65B9\u5F0F\u3002",
|
|
467
|
+
oauthBlocked: "\u6D4F\u89C8\u5668\u62E6\u622A\u4E86\u767B\u5F55\u7A97\u53E3\u3002\u8BF7\u91CD\u65B0\u6253\u5F00\uFF0C\u6216\u5728\u5F53\u524D\u9875\u9762\u7EE7\u7EED\u3002",
|
|
468
|
+
oauthTimedOut: "\u767B\u5F55\u7B49\u5F85\u5DF2\u8D85\u65F6\u3002\u8BF7\u91CD\u65B0\u6253\u5F00\u7A97\u53E3\u518D\u8BD5\u3002",
|
|
469
|
+
oauthFailed: "\u672A\u80FD\u5B8C\u6210\u767B\u5F55\u3002\u8BF7\u91CD\u8BD5\u6216\u9009\u62E9\u5176\u4ED6\u65B9\u5F0F\u3002",
|
|
456
470
|
oauthFullPage: "\u5728\u5F53\u524D\u9875\u9762\u7EE7\u7EED",
|
|
457
471
|
emailEdit: "\u4FEE\u6539\u90AE\u7BB1",
|
|
458
472
|
emailCooldown: "{seconds} \u79D2\u540E\u91CD\u53D1",
|
|
@@ -513,12 +527,19 @@ var messages = {
|
|
|
513
527
|
emailExplanation: "\u6211\u5011\u6703\u50B3\u9001\u9A57\u8B49\u78BC\uFF0C\u7121\u9700\u5BC6\u78BC\u3002",
|
|
514
528
|
otherMethods: "\u5176\u4ED6\u767B\u5165\u65B9\u5F0F",
|
|
515
529
|
passkeyCreateAccount: "\u4F7F\u7528 Passkey \u5EFA\u7ACB\u5E33\u6236",
|
|
516
|
-
lastUsed: "\u4E0A\u6B21\u4F7F\u7528
|
|
530
|
+
lastUsed: "\u4E0A\u6B21\u4F7F\u7528",
|
|
517
531
|
passkeyExplanation: "\u4F7F\u7528\u6307\u7D0B\u3001\u9762\u5BB9\u6216\u88DD\u7F6E\u89E3\u9396\u65B9\u5F0F\u5EFA\u7ACB\u65B0\u5E33\u6236\uFF0C\u7121\u9700\u5BC6\u78BC\u3002\u88DD\u7F6E\u6703\u63D0\u793A\u5132\u5B58 Passkey\u3002\u5DF2\u6709\u5E33\u6236\uFF1F\u8ACB\u8FD4\u56DE\u767B\u5165\u3002",
|
|
518
532
|
continueWith: "\u4F7F\u7528 {provider} \u7E7C\u7E8C",
|
|
519
533
|
oauthWaiting: "\u8ACB\u5728 {provider} \u8996\u7A97\u4E2D\u7E7C\u7E8C",
|
|
520
534
|
oauthIncomplete: "\u767B\u5165\u5C1A\u672A\u5B8C\u6210\u3002\u60A8\u53EF\u4EE5\u91CD\u65B0\u958B\u555F\u8996\u7A97\u6216\u9078\u64C7\u5176\u4ED6\u65B9\u5F0F\u3002",
|
|
521
535
|
oauthReopen: "\u91CD\u65B0\u958B\u555F\u8996\u7A97",
|
|
536
|
+
oauthUnconfirmed: "\u66AB\u6642\u7121\u6CD5\u78BA\u8A8D\u767B\u5165\u7D50\u679C\u3002\u8ACB\u5148\u91CD\u65B0\u8F09\u5165\u9801\u9762\u6AA2\u67E5\u767B\u5165\u72C0\u614B\uFF0C\u518D\u6C7A\u5B9A\u662F\u5426\u91CD\u8A66\u3002",
|
|
537
|
+
oauthCheckSession: "\u91CD\u65B0\u8F09\u5165\u4E26\u6AA2\u67E5\u767B\u5165\u72C0\u614B",
|
|
538
|
+
oauthCancelled: "\u5DF2\u505C\u6B62\u7B49\u5F85\u767B\u5165\u3002\u82E5\u6388\u6B0A\u8996\u7A97\u4ECD\u7136\u958B\u555F\uFF0C\u8ACB\u95DC\u9589\u5F8C\u518D\u91CD\u8A66\u3002",
|
|
539
|
+
oauthDenied: "\u60A8\u672A\u540C\u610F\u6388\u6B0A\u3002\u53EF\u4EE5\u91CD\u8A66\u6216\u9078\u64C7\u5176\u4ED6\u767B\u5165\u65B9\u5F0F\u3002",
|
|
540
|
+
oauthBlocked: "\u700F\u89BD\u5668\u5C01\u9396\u4E86\u767B\u5165\u8996\u7A97\u3002\u8ACB\u91CD\u65B0\u958B\u555F\uFF0C\u6216\u5728\u76EE\u524D\u9801\u9762\u7E7C\u7E8C\u3002",
|
|
541
|
+
oauthTimedOut: "\u767B\u5165\u7B49\u5F85\u5DF2\u903E\u6642\u3002\u8ACB\u91CD\u65B0\u958B\u555F\u8996\u7A97\u518D\u8A66\u3002",
|
|
542
|
+
oauthFailed: "\u672A\u80FD\u5B8C\u6210\u767B\u5165\u3002\u8ACB\u91CD\u8A66\u6216\u9078\u64C7\u5176\u4ED6\u65B9\u5F0F\u3002",
|
|
522
543
|
oauthFullPage: "\u5728\u76EE\u524D\u9801\u9762\u7E7C\u7E8C",
|
|
523
544
|
emailEdit: "\u4FEE\u6539\u96FB\u5B50\u90F5\u4EF6",
|
|
524
545
|
emailCooldown: "{seconds} \u79D2\u5F8C\u91CD\u65B0\u50B3\u9001",
|
|
@@ -579,12 +600,19 @@ var messages = {
|
|
|
579
600
|
emailExplanation: "\u78BA\u8A8D\u30B3\u30FC\u30C9\u3092\u9001\u4FE1\u3057\u307E\u3059\u3002\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u4E0D\u8981\u3067\u3059\u3002",
|
|
580
601
|
otherMethods: "\u4ED6\u306E\u30ED\u30B0\u30A4\u30F3\u65B9\u6CD5",
|
|
581
602
|
passkeyCreateAccount: "Passkey \u3067\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F5C\u6210",
|
|
582
|
-
lastUsed: "\u524D\u56DE\
|
|
603
|
+
lastUsed: "\u524D\u56DE\u4F7F\u7528",
|
|
583
604
|
passkeyExplanation: "\u6307\u7D0B\u3001\u9854\u8A8D\u8A3C\u3001\u307E\u305F\u306F\u30C7\u30D0\u30A4\u30B9\u306E\u30ED\u30C3\u30AF\u89E3\u9664\u3067\u65B0\u3057\u3044\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u4F5C\u6210\u3057\u307E\u3059\u3002\u30D1\u30B9\u30EF\u30FC\u30C9\u306F\u4E0D\u8981\u3067\u3059\u3002\u30C7\u30D0\u30A4\u30B9\u304C Passkey \u306E\u4FDD\u5B58\u3092\u6C42\u3081\u307E\u3059\u3002\u30A2\u30AB\u30A6\u30F3\u30C8\u3092\u304A\u6301\u3061\u3067\u3059\u304B\uFF1F\u30ED\u30B0\u30A4\u30F3\u306B\u623B\u3063\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
584
605
|
continueWith: "{provider} \u3067\u7D9A\u3051\u308B",
|
|
585
606
|
oauthWaiting: "{provider} \u306E\u30A6\u30A3\u30F3\u30C9\u30A6\u3067\u7D9A\u3051\u3066\u304F\u3060\u3055\u3044",
|
|
586
607
|
oauthIncomplete: "\u30ED\u30B0\u30A4\u30F3\u306F\u307E\u3060\u5B8C\u4E86\u3057\u3066\u3044\u307E\u305B\u3093\u3002\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u958B\u304D\u76F4\u3059\u304B\u3001\u5225\u306E\u65B9\u6CD5\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
587
608
|
oauthReopen: "\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u958B\u304D\u76F4\u3059",
|
|
609
|
+
oauthUnconfirmed: "\u30ED\u30B0\u30A4\u30F3\u7D50\u679C\u3092\u78BA\u8A8D\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u518D\u8A66\u884C\u306E\u524D\u306B\u30DA\u30FC\u30B8\u3092\u518D\u8AAD\u307F\u8FBC\u307F\u3057\u3066\u72B6\u614B\u3092\u78BA\u8A8D\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
610
|
+
oauthCheckSession: "\u518D\u8AAD\u307F\u8FBC\u307F\u3057\u3066\u30ED\u30B0\u30A4\u30F3\u3092\u78BA\u8A8D",
|
|
611
|
+
oauthCancelled: "\u30ED\u30B0\u30A4\u30F3\u306E\u5F85\u6A5F\u3092\u7D42\u4E86\u3057\u307E\u3057\u305F\u3002\u8A8D\u8A3C\u30A6\u30A3\u30F3\u30C9\u30A6\u304C\u958B\u3044\u3066\u3044\u308B\u5834\u5408\u306F\u3001\u9589\u3058\u3066\u304B\u3089\u518D\u8A66\u884C\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
612
|
+
oauthDenied: "\u8A8D\u8A3C\u304C\u8A31\u53EF\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u518D\u8A66\u884C\u3059\u308B\u304B\u3001\u5225\u306E\u65B9\u6CD5\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
613
|
+
oauthBlocked: "\u30D6\u30E9\u30A6\u30B6\u304C\u30ED\u30B0\u30A4\u30F3\u753B\u9762\u3092\u30D6\u30ED\u30C3\u30AF\u3057\u307E\u3057\u305F\u3002\u958B\u304D\u76F4\u3059\u304B\u3001\u3053\u306E\u30DA\u30FC\u30B8\u3067\u7D9A\u3051\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
614
|
+
oauthTimedOut: "\u30ED\u30B0\u30A4\u30F3\u304C\u30BF\u30A4\u30E0\u30A2\u30A6\u30C8\u3057\u307E\u3057\u305F\u3002\u30A6\u30A3\u30F3\u30C9\u30A6\u3092\u958B\u304D\u76F4\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
|
|
615
|
+
oauthFailed: "\u30ED\u30B0\u30A4\u30F3\u3092\u5B8C\u4E86\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u518D\u8A66\u884C\u3059\u308B\u304B\u3001\u5225\u306E\u65B9\u6CD5\u3092\u9078\u3093\u3067\u304F\u3060\u3055\u3044\u3002",
|
|
588
616
|
oauthFullPage: "\u3053\u306E\u30DA\u30FC\u30B8\u3067\u7D9A\u3051\u308B",
|
|
589
617
|
emailEdit: "\u30E1\u30FC\u30EB\u30A2\u30C9\u30EC\u30B9\u3092\u5909\u66F4",
|
|
590
618
|
emailCooldown: "{seconds} \u79D2\u5F8C\u306B\u518D\u9001\u4FE1",
|
|
@@ -2612,7 +2640,9 @@ h1 {
|
|
|
2612
2640
|
}
|
|
2613
2641
|
@keyframes fadeIn { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
|
|
2614
2642
|
|
|
2615
|
-
/* QR timeout overlay
|
|
2643
|
+
/* QR timeout overlay. It sits on the code, not across the card. Dark keeps a
|
|
2644
|
+
dim scrim so the expired plate stays readable as "inactive". */
|
|
2645
|
+
.qr-plate { position: relative; }
|
|
2616
2646
|
.qr-timeout-overlay {
|
|
2617
2647
|
position: absolute;
|
|
2618
2648
|
inset: 0;
|
|
@@ -2621,14 +2651,28 @@ h1 {
|
|
|
2621
2651
|
align-items: center;
|
|
2622
2652
|
justify-content: center;
|
|
2623
2653
|
gap: 12px;
|
|
2654
|
+
padding: 16px;
|
|
2655
|
+
text-align: center;
|
|
2624
2656
|
background: rgba(0, 0, 0, 0.65);
|
|
2625
|
-
border-radius:
|
|
2657
|
+
border-radius: inherit;
|
|
2626
2658
|
backdrop-filter: blur(2px);
|
|
2627
2659
|
}
|
|
2628
2660
|
.qr-timeout-overlay .timeout-text {
|
|
2629
2661
|
font-size: 13px;
|
|
2662
|
+
line-height: 1.4;
|
|
2630
2663
|
color: #fff;
|
|
2631
2664
|
}
|
|
2665
|
+
[data-theme="light"] .qr-timeout-overlay,
|
|
2666
|
+
:host([data-theme="light"]) .qr-timeout-overlay {
|
|
2667
|
+
background: rgba(255, 255, 255, 0.94);
|
|
2668
|
+
border: 1px solid var(--border);
|
|
2669
|
+
box-shadow: var(--shadow-sm);
|
|
2670
|
+
backdrop-filter: blur(8px);
|
|
2671
|
+
}
|
|
2672
|
+
[data-theme="light"] .qr-timeout-overlay .timeout-text,
|
|
2673
|
+
:host([data-theme="light"]) .qr-timeout-overlay .timeout-text {
|
|
2674
|
+
color: var(--text-secondary);
|
|
2675
|
+
}
|
|
2632
2676
|
.qr-timeout-overlay .refresh-btn {
|
|
2633
2677
|
display: inline-flex;
|
|
2634
2678
|
align-items: center;
|
|
@@ -2980,28 +3024,41 @@ h1 {
|
|
|
2980
3024
|
border-color: var(--border-strong);
|
|
2981
3025
|
}
|
|
2982
3026
|
.locale-trigger svg { width: 14px; height: 14px; flex-shrink: 0; }
|
|
3027
|
+
/* One compact menu surface; rows are choices, not nested pill buttons. */
|
|
2983
3028
|
.locale-menu {
|
|
2984
|
-
display: none;
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
margin-top: 4px;
|
|
3029
|
+
display: none; position: absolute; top: calc(100% + 6px); right: 0; z-index: 4;
|
|
3030
|
+
min-width: 144px; width: max-content; max-width: min(240px,calc(100vw - 64px));
|
|
3031
|
+
padding: 4px; background: var(--bg-card); border: 1px solid var(--border);
|
|
3032
|
+
border-radius: 10px; box-shadow: var(--shadow-lg);
|
|
2989
3033
|
}
|
|
2990
|
-
.locale-switcher.open .locale-menu {
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
border-color: var(--border-strong);
|
|
3034
|
+
.locale-switcher.open .locale-menu { display: flex; flex-direction: column; }
|
|
3035
|
+
.locale-menu .locale-btn {
|
|
3036
|
+
width: 100%; min-height: 36px; height: auto; padding: 7px 10px; gap: 8px;
|
|
3037
|
+
border: 0; border-radius: 6px; background: transparent; text-align: left;
|
|
3038
|
+
font-size: 13px; line-height: 1.4; overflow-wrap: anywhere;
|
|
2996
3039
|
}
|
|
2997
|
-
.locale-
|
|
3040
|
+
.locale-menu .locale-btn:hover, .locale-menu .locale-btn:focus-visible { background: var(--bg-hover); color: var(--text); }
|
|
3041
|
+
.locale-menu .locale-btn[aria-checked="true"] { color: var(--text); font-weight: 600; }
|
|
3042
|
+
.locale-check { width: 14px; flex: 0 0 14px; font-size: 12px; line-height: 1; }
|
|
3043
|
+
@media (pointer: coarse) { .locale-menu .locale-btn { min-height: 44px; } }
|
|
3044
|
+
.has-last-used { flex-wrap: wrap; }
|
|
3045
|
+
.last-used { display: inline-block; font-size: 11px; font-weight: 400; line-height: 1.4;
|
|
3046
|
+
padding: 2px 6px; border: 1px solid currentColor; border-radius: 4px; opacity: .72; white-space: nowrap; }
|
|
2998
3047
|
.card { position: relative; }
|
|
2999
3048
|
|
|
3000
3049
|
/* Long localized method labels remain readable on narrow screens. */
|
|
3001
3050
|
.methods-grid { grid-template-columns: 1fr; }
|
|
3002
3051
|
.method-btn { min-height: 48px; white-space: normal; }
|
|
3003
3052
|
.passkey-alt { min-height: 44px; font-weight: 600; }
|
|
3004
|
-
.oauth-recovery { font-size: 14px; line-height: 1.5; margin: 12px 0;
|
|
3053
|
+
.oauth-recovery { font-size: 14px; line-height: 1.5; margin: 12px 0; padding: 12px;
|
|
3054
|
+
border: 1px solid var(--border); border-radius: var(--radius); color: var(--text-secondary); text-align: left; }
|
|
3055
|
+
.oauth-recovery p { margin: 0 0 8px; overflow-wrap: anywhere; }
|
|
3056
|
+
.oauth-recovery-actions { display: flex; flex-wrap: wrap; gap: 4px 12px; align-items: center; }
|
|
3057
|
+
.oauth-recovery-actions button, .oauth-recovery-actions a { font: inherit; font-size: 13px; min-height: 44px;
|
|
3058
|
+
display: inline-flex; align-items: center; padding: 4px 0; color: var(--text); border: 0; background: none; cursor: pointer; text-decoration: underline; text-underline-offset: 3px; }
|
|
3059
|
+
.oauth-recovery-actions[hidden], .oauth-recovery-actions [hidden] { display: none; }
|
|
3060
|
+
.oauth-recovery-actions :focus-visible { outline: 2px solid var(--blue); outline-offset: 3px; }
|
|
3061
|
+
|
|
3005
3062
|
@media (max-width: 480px) { .card { padding: 24px 20px; width: 100%; box-sizing: border-box; } h1 { font-size: 24px; } }
|
|
3006
3063
|
|
|
3007
3064
|
.passkey-create-entry { display: flex; justify-content: center; align-items: center; width: 100%; box-sizing: border-box; border: 1px solid var(--border); border-radius: var(--radius); background: var(--bg-surface); color: var(--text); padding: 10px 14px; }
|
|
@@ -3014,11 +3071,7 @@ h1 {
|
|
|
3014
3071
|
.card-modal .locale-switcher { min-width: 0; max-width: 100%; }
|
|
3015
3072
|
.card-modal .locale-trigger { max-width: 100%; height: 36px; }
|
|
3016
3073
|
.locale-label { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
3017
|
-
.card-modal .locale-menu {
|
|
3018
|
-
width: max-content; max-width: min(260px,calc(100vw - 80px)); padding: 6px;
|
|
3019
|
-
background: var(--bg-card); border: 1px solid var(--border-strong); border-radius: 10px; box-shadow: var(--shadow-lg); }
|
|
3020
|
-
.card-modal .locale-menu .locale-btn { min-height: 40px; height: auto; text-align: left; border-radius: 6px; }
|
|
3021
|
-
.card-modal .locale-menu .locale-btn span { overflow-wrap: anywhere; }
|
|
3074
|
+
.card-modal .locale-menu { left: 0; right: auto; }
|
|
3022
3075
|
|
|
3023
3076
|
.card { padding: 52px 24px 24px; box-sizing: border-box; }
|
|
3024
3077
|
.card-modal { width: 100%; }
|
|
@@ -3027,7 +3080,13 @@ h1 {
|
|
|
3027
3080
|
.card.card-modal, :host([data-theme="light"]) .card.card-modal { box-shadow: none; }
|
|
3028
3081
|
/* A translateY entrance expands an auto scroller by 4px until it finishes. */
|
|
3029
3082
|
.card-modal[data-view] { animation: none; }
|
|
3030
|
-
|
|
3083
|
+
/* Sub-step navigation shares the close button's center line in both modes. */
|
|
3084
|
+
.back-btn { top: 8px; left: 24px; height: 44px; max-width: calc(100% - 160px); line-height: 1.4; text-align: left; }
|
|
3085
|
+
.back-btn:focus-visible { outline: 2px solid var(--blue); outline-offset: 2px; border-radius: 4px; }
|
|
3086
|
+
.card-modal .back-btn { position: absolute; top: 8px; left: 24px; margin: 0; }
|
|
3087
|
+
.card-modal:has(.back-btn) .card-tools { left: auto; right: 64px; max-width: calc(100% - 160px); }
|
|
3088
|
+
.passkey-creating > .home-link { display: none; }
|
|
3089
|
+
@media (max-width:480px) { .back-btn, .card-modal .back-btn { left: 18px; } }
|
|
3031
3090
|
.card-modal h1 { display: block; overflow: visible; -webkit-line-clamp: unset; line-clamp: unset; line-height: 1.4; padding-block: 2px; }
|
|
3032
3091
|
.card-modal h1[tabindex="-1"]:focus { outline: none; }
|
|
3033
3092
|
.card-modal h1, .card-modal h2, .card-modal .subtitle, .card-modal .status { overflow-wrap: anywhere; }
|
|
@@ -3474,6 +3533,8 @@ var LoginPage = class {
|
|
|
3474
3533
|
}
|
|
3475
3534
|
/** Locale sits on the card's top-right row, level with Back / Cancel. */
|
|
3476
3535
|
renderCardTools(card) {
|
|
3536
|
+
if (!(this.options.showLocaleSelector ?? this.options.mode !== "dialog"))
|
|
3537
|
+
return;
|
|
3477
3538
|
const tools = document.createElement("div");
|
|
3478
3539
|
tools.className = "card-tools";
|
|
3479
3540
|
this.renderLocaleSwitcher(tools);
|
|
@@ -3531,6 +3592,8 @@ var LoginPage = class {
|
|
|
3531
3592
|
trigger.addEventListener("click", (event) => {
|
|
3532
3593
|
event.stopPropagation();
|
|
3533
3594
|
setOpen(menu.hidden);
|
|
3595
|
+
if (!menu.hidden)
|
|
3596
|
+
menu.querySelector('[aria-checked="true"]')?.focus();
|
|
3534
3597
|
});
|
|
3535
3598
|
for (const item of locales) {
|
|
3536
3599
|
const checked = item.code === current.code;
|
|
@@ -3540,12 +3603,13 @@ var LoginPage = class {
|
|
|
3540
3603
|
btn.setAttribute("role", "menuitemradio");
|
|
3541
3604
|
btn.setAttribute("aria-checked", checked ? "true" : "false");
|
|
3542
3605
|
btn.dataset.locale = item.code;
|
|
3606
|
+
btn.tabIndex = -1;
|
|
3543
3607
|
btn.title = item.label;
|
|
3544
|
-
|
|
3608
|
+
{
|
|
3545
3609
|
const mark = document.createElement("span");
|
|
3546
3610
|
mark.className = "locale-check";
|
|
3547
3611
|
mark.setAttribute("aria-hidden", "true");
|
|
3548
|
-
mark.textContent = "\u2713";
|
|
3612
|
+
mark.textContent = checked ? "\u2713" : "";
|
|
3549
3613
|
btn.appendChild(mark);
|
|
3550
3614
|
}
|
|
3551
3615
|
const label = document.createElement("span");
|
|
@@ -3557,6 +3621,24 @@ var LoginPage = class {
|
|
|
3557
3621
|
});
|
|
3558
3622
|
menu.appendChild(btn);
|
|
3559
3623
|
}
|
|
3624
|
+
wrapper.addEventListener("keydown", (event) => {
|
|
3625
|
+
const items = [...menu.querySelectorAll(".locale-btn")];
|
|
3626
|
+
const active = this.shadow?.activeElement ?? document.activeElement;
|
|
3627
|
+
const index = items.indexOf(active);
|
|
3628
|
+
if (event.key === "Escape") {
|
|
3629
|
+
event.preventDefault();
|
|
3630
|
+
event.stopPropagation();
|
|
3631
|
+
setOpen(false);
|
|
3632
|
+
trigger.focus();
|
|
3633
|
+
} else if (event.key === "Tab")
|
|
3634
|
+
setOpen(false);
|
|
3635
|
+
else if (["ArrowDown", "ArrowUp", "Home", "End"].includes(event.key)) {
|
|
3636
|
+
event.preventDefault();
|
|
3637
|
+
setOpen(true);
|
|
3638
|
+
const next = event.key === "Home" ? 0 : event.key === "End" ? items.length - 1 : index < 0 ? event.key === "ArrowUp" ? items.length - 1 : 0 : (index + (event.key === "ArrowUp" ? -1 : 1) + items.length) % items.length;
|
|
3639
|
+
items[next]?.focus();
|
|
3640
|
+
}
|
|
3641
|
+
});
|
|
3560
3642
|
const onOutsideClick = (event) => {
|
|
3561
3643
|
const path = event.composedPath();
|
|
3562
3644
|
if (path.includes(wrapper))
|
|
@@ -3607,25 +3689,25 @@ var LoginPage = class {
|
|
|
3607
3689
|
break;
|
|
3608
3690
|
}
|
|
3609
3691
|
}
|
|
3692
|
+
/** Keep recognition next to the action, without a second page subtitle. */
|
|
3693
|
+
markLastUsed(button, method, locale) {
|
|
3694
|
+
if (!this.options.preferenceKey)
|
|
3695
|
+
return;
|
|
3696
|
+
try {
|
|
3697
|
+
if (localStorage.getItem(`did-login-method:${this.options.preferenceKey}`) !== method)
|
|
3698
|
+
return;
|
|
3699
|
+
const hint = document.createElement("span");
|
|
3700
|
+
hint.className = "last-used";
|
|
3701
|
+
hint.textContent = t("lastUsed", locale);
|
|
3702
|
+
button.classList.add("has-last-used");
|
|
3703
|
+
button.appendChild(hint);
|
|
3704
|
+
} catch {
|
|
3705
|
+
}
|
|
3706
|
+
}
|
|
3610
3707
|
renderMethodsView(card, locale, methods) {
|
|
3611
3708
|
if (this.options.mode !== "dialog")
|
|
3612
3709
|
this.renderHomeLink(card, locale);
|
|
3613
3710
|
this.renderBrandHeader(card, locale);
|
|
3614
|
-
if (this.options.preferenceKey) {
|
|
3615
|
-
try {
|
|
3616
|
-
const last = localStorage.getItem(`did-login-method:${this.options.preferenceKey}`);
|
|
3617
|
-
const labels = { passkey: "Passkey", oauth: "OAuth", email: t("emailButton", locale), "did-connect": "DID Wallet" };
|
|
3618
|
-
const provider = last?.startsWith("oauth:") ? this.options.oauthProviders?.find((p) => p.enabled && `oauth:${p.id}` === last) : void 0;
|
|
3619
|
-
const label = provider?.name ?? (last ? labels[last] : void 0);
|
|
3620
|
-
if (last && label && (methods.includes(last) || provider && methods.includes("oauth"))) {
|
|
3621
|
-
const hint = document.createElement("p");
|
|
3622
|
-
hint.className = "subtitle";
|
|
3623
|
-
hint.textContent = t("lastUsed", locale, { method: label });
|
|
3624
|
-
card.appendChild(hint);
|
|
3625
|
-
}
|
|
3626
|
-
} catch {
|
|
3627
|
-
}
|
|
3628
|
-
}
|
|
3629
3711
|
const requestedPasskey = this.options.methods.includes("passkey");
|
|
3630
3712
|
if (requestedPasskey && !methods.includes("passkey")) {
|
|
3631
3713
|
const warn = document.createElement("div");
|
|
@@ -3895,11 +3977,12 @@ var LoginPage = class {
|
|
|
3895
3977
|
}
|
|
3896
3978
|
});
|
|
3897
3979
|
}
|
|
3898
|
-
renderBackButton(parent, locale) {
|
|
3980
|
+
renderBackButton(parent, locale, onBack = () => this.switchView("methods")) {
|
|
3899
3981
|
const btn = document.createElement("button");
|
|
3982
|
+
btn.type = "button";
|
|
3900
3983
|
btn.className = "back-btn";
|
|
3901
3984
|
btn.innerHTML = `${ICON_BACK_ARROW} ${escapeHtml(t("back", locale))}`;
|
|
3902
|
-
btn.addEventListener("click",
|
|
3985
|
+
btn.addEventListener("click", onBack);
|
|
3903
3986
|
parent.appendChild(btn);
|
|
3904
3987
|
}
|
|
3905
3988
|
/**
|
|
@@ -4006,12 +4089,6 @@ var LoginPage = class {
|
|
|
4006
4089
|
}
|
|
4007
4090
|
footer.appendChild(links);
|
|
4008
4091
|
}
|
|
4009
|
-
if (this.currentView !== "methods" && this.options.mode !== "dialog") {
|
|
4010
|
-
this.renderHomeLink(footer, locale);
|
|
4011
|
-
const cancel = footer.querySelector(".home-link");
|
|
4012
|
-
if (cancel)
|
|
4013
|
-
cancel.style.cssText = "position:static;display:inline-flex;margin-top:12px";
|
|
4014
|
-
}
|
|
4015
4092
|
parent.appendChild(footer);
|
|
4016
4093
|
}
|
|
4017
4094
|
renderDivider(parent, locale) {
|
|
@@ -4107,11 +4184,8 @@ var LoginPage = class {
|
|
|
4107
4184
|
createBtn.id = "passkey-btn";
|
|
4108
4185
|
createBtn.innerHTML = `${ICON_PASSKEY} ${escapeHtml(t("passkeyCreate", locale))}`;
|
|
4109
4186
|
section.appendChild(createBtn);
|
|
4110
|
-
|
|
4111
|
-
|
|
4112
|
-
backLink.className = "passkey-alt";
|
|
4113
|
-
backLink.textContent = t("passkeyBackToSignIn", locale);
|
|
4114
|
-
section.appendChild(backLink);
|
|
4187
|
+
parent.querySelector(".back-btn")?.remove();
|
|
4188
|
+
this.renderBackButton(parent, locale, () => renderSignInState());
|
|
4115
4189
|
const doCreate = async () => {
|
|
4116
4190
|
if (createBtn.disabled)
|
|
4117
4191
|
return;
|
|
@@ -4141,7 +4215,6 @@ var LoginPage = class {
|
|
|
4141
4215
|
if (e.key === "Enter")
|
|
4142
4216
|
doCreate();
|
|
4143
4217
|
});
|
|
4144
|
-
backLink.addEventListener("click", () => renderSignInState());
|
|
4145
4218
|
createBtn.focus();
|
|
4146
4219
|
};
|
|
4147
4220
|
const doSignIn = async () => {
|
|
@@ -4176,6 +4249,7 @@ var LoginPage = class {
|
|
|
4176
4249
|
};
|
|
4177
4250
|
const renderSignInState = () => {
|
|
4178
4251
|
this.cardEl?.classList.remove("passkey-creating");
|
|
4252
|
+
parent.querySelector(".back-btn")?.remove();
|
|
4179
4253
|
this.abort?.abort();
|
|
4180
4254
|
this.generation++;
|
|
4181
4255
|
const heading = this.cardEl?.querySelector("h1");
|
|
@@ -4187,6 +4261,7 @@ var LoginPage = class {
|
|
|
4187
4261
|
signInBtn.className = this.cardEl?.classList.contains("social-first") ? "btn btn-secondary" : "btn";
|
|
4188
4262
|
signInBtn.id = "passkey-btn";
|
|
4189
4263
|
signInBtn.innerHTML = `${ICON_PASSKEY} ${escapeHtml(t("passkeySignIn", locale))}`;
|
|
4264
|
+
this.markLastUsed(signInBtn, "passkey", locale);
|
|
4190
4265
|
section.appendChild(signInBtn);
|
|
4191
4266
|
signInBtn.addEventListener("click", () => doSignIn());
|
|
4192
4267
|
const createLink = document.createElement("button");
|
|
@@ -4208,159 +4283,240 @@ var LoginPage = class {
|
|
|
4208
4283
|
startOAuthPopup(providerId, btn) {
|
|
4209
4284
|
this.oauthCleanup?.();
|
|
4210
4285
|
const epoch = this.generation;
|
|
4286
|
+
const locale = this.options.locale;
|
|
4211
4287
|
const servicePrefix = this.config.servicePrefix ?? "/.well-known/service";
|
|
4212
4288
|
const oauthBase = this.options.masterOAuthOrigin ? `${this.options.masterOAuthOrigin}${servicePrefix}` : servicePrefix;
|
|
4213
4289
|
const oauthOrigin = new URL(oauthBase, window.location.href).origin;
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
return;
|
|
4290
|
+
let returnUrl = window.location.href;
|
|
4291
|
+
if (this.options.mode !== "dialog" && window.location.pathname === `${servicePrefix}/login`) {
|
|
4292
|
+
const requested = new URLSearchParams(window.location.search).get("return_to");
|
|
4293
|
+
try {
|
|
4294
|
+
const target = new URL(requested || "/", window.location.origin);
|
|
4295
|
+
returnUrl = target.origin === window.location.origin && !/^\/[/\\]/.test(target.pathname) ? target.href : `${window.location.origin}/`;
|
|
4296
|
+
} catch {
|
|
4297
|
+
returnUrl = `${window.location.origin}/`;
|
|
4298
|
+
}
|
|
4224
4299
|
}
|
|
4300
|
+
const loginUrl = `${oauthBase}/api/oauth/${encodeURIComponent(providerId)}/login?returnUrl=${encodeURIComponent(returnUrl)}`;
|
|
4301
|
+
const provider = this.options.oauthProviders?.find((p) => p.id === providerId)?.name ?? providerId;
|
|
4225
4302
|
const originalHTML = btn.innerHTML;
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4303
|
+
let popup = null;
|
|
4304
|
+
let settled = false;
|
|
4305
|
+
let exchanging = false;
|
|
4306
|
+
let probing = false;
|
|
4307
|
+
let pollTimer;
|
|
4308
|
+
let sessionTimer;
|
|
4309
|
+
let abandonTimer;
|
|
4310
|
+
const current = () => !settled && this.mounted && epoch === this.generation;
|
|
4311
|
+
const locked = [];
|
|
4312
|
+
const lockMethods = () => {
|
|
4313
|
+
for (const button of this.cardEl?.querySelectorAll(".method-btn, .passkey-create-entry, #passkey-btn, .locale-trigger, .locale-btn") ?? []) {
|
|
4314
|
+
locked.push({ button, disabled: button.disabled });
|
|
4315
|
+
button.disabled = true;
|
|
4316
|
+
}
|
|
4317
|
+
};
|
|
4229
4318
|
const recovery = document.createElement("div");
|
|
4230
4319
|
recovery.className = "oauth-recovery";
|
|
4231
4320
|
recovery.setAttribute("role", "status");
|
|
4232
4321
|
const hint = document.createElement("p");
|
|
4233
|
-
|
|
4322
|
+
const actions = document.createElement("div");
|
|
4323
|
+
actions.className = "oauth-recovery-actions";
|
|
4324
|
+
const reopen = document.createElement("button");
|
|
4325
|
+
reopen.type = "button";
|
|
4326
|
+
reopen.className = "oauth-retry";
|
|
4327
|
+
reopen.textContent = t("oauthReopen", locale);
|
|
4328
|
+
reopen.hidden = true;
|
|
4329
|
+
reopen.onclick = () => {
|
|
4330
|
+
this.select("oauth");
|
|
4331
|
+
this.activeProvider = providerId;
|
|
4332
|
+
this.startOAuthPopup(providerId, btn);
|
|
4333
|
+
};
|
|
4234
4334
|
const fullPage = document.createElement("a");
|
|
4235
4335
|
fullPage.href = loginUrl;
|
|
4236
|
-
fullPage.textContent = t("oauthFullPage",
|
|
4237
|
-
fullPage.addEventListener("click", () => {
|
|
4336
|
+
fullPage.textContent = t("oauthFullPage", locale);
|
|
4337
|
+
fullPage.addEventListener("click", (event) => {
|
|
4338
|
+
const reconcile = recovery.dataset.state === "oauthUnconfirmed";
|
|
4339
|
+
if (exchanging && !settled) {
|
|
4340
|
+
event.preventDefault();
|
|
4341
|
+
return;
|
|
4342
|
+
}
|
|
4343
|
+
if (reconcile)
|
|
4344
|
+
event.preventDefault();
|
|
4238
4345
|
this.options.onBeforeRedirect?.();
|
|
4239
4346
|
this.oauthCleanup?.();
|
|
4347
|
+
if (reconcile)
|
|
4348
|
+
window.location.reload();
|
|
4240
4349
|
});
|
|
4241
|
-
|
|
4242
|
-
|
|
4350
|
+
const cancel = document.createElement("button");
|
|
4351
|
+
cancel.type = "button";
|
|
4352
|
+
cancel.className = "oauth-cancel";
|
|
4353
|
+
cancel.textContent = t("cancel", locale);
|
|
4354
|
+
actions.append(reopen, fullPage, cancel);
|
|
4355
|
+
recovery.append(hint, actions);
|
|
4243
4356
|
btn.parentElement?.after(recovery);
|
|
4244
|
-
const
|
|
4245
|
-
recovery.hidden = false;
|
|
4246
|
-
this.emit("incomplete");
|
|
4357
|
+
const restoreButton = () => {
|
|
4247
4358
|
btn.innerHTML = originalHTML;
|
|
4248
4359
|
btn.disabled = false;
|
|
4249
4360
|
btn.classList.remove("oauth-btn-loading");
|
|
4250
4361
|
};
|
|
4251
|
-
|
|
4252
|
-
|
|
4362
|
+
const closePopup = () => {
|
|
4363
|
+
try {
|
|
4364
|
+
popup?.close();
|
|
4365
|
+
} catch {
|
|
4366
|
+
}
|
|
4367
|
+
};
|
|
4368
|
+
const cleanup = () => {
|
|
4369
|
+
settled = true;
|
|
4370
|
+
clearInterval(pollTimer);
|
|
4371
|
+
clearInterval(sessionTimer);
|
|
4372
|
+
clearTimeout(abandonTimer);
|
|
4373
|
+
window.removeEventListener("message", onMessage);
|
|
4374
|
+
for (const item of locked.splice(0))
|
|
4375
|
+
item.button.disabled = item.disabled;
|
|
4376
|
+
restoreButton();
|
|
4377
|
+
};
|
|
4378
|
+
const showRecovery = (key) => {
|
|
4379
|
+
hint.textContent = t(key, locale, { provider });
|
|
4380
|
+
recovery.dataset.state = key;
|
|
4381
|
+
actions.hidden = false;
|
|
4382
|
+
reopen.hidden = false;
|
|
4383
|
+
cancel.hidden = true;
|
|
4384
|
+
restoreButton();
|
|
4385
|
+
};
|
|
4386
|
+
const fail = (key) => {
|
|
4387
|
+
if (!current())
|
|
4388
|
+
return;
|
|
4389
|
+
cleanup();
|
|
4390
|
+
closePopup();
|
|
4391
|
+
showRecovery(key);
|
|
4392
|
+
this.emit("incomplete");
|
|
4393
|
+
};
|
|
4253
4394
|
const succeed = () => {
|
|
4254
|
-
if (
|
|
4395
|
+
if (!current())
|
|
4255
4396
|
return;
|
|
4256
|
-
settled = true;
|
|
4257
4397
|
cleanup();
|
|
4258
|
-
|
|
4398
|
+
closePopup();
|
|
4399
|
+
recovery.remove();
|
|
4400
|
+
btn.textContent = t("success", locale);
|
|
4401
|
+
btn.disabled = true;
|
|
4259
4402
|
this.handleSuccess();
|
|
4260
4403
|
};
|
|
4261
|
-
|
|
4262
|
-
if (
|
|
4404
|
+
cancel.onclick = () => {
|
|
4405
|
+
if (exchanging)
|
|
4263
4406
|
return;
|
|
4264
|
-
|
|
4407
|
+
fail("oauthCancelled");
|
|
4408
|
+
btn.focus();
|
|
4409
|
+
};
|
|
4410
|
+
const onMessage = async (event) => {
|
|
4411
|
+
if (event.origin !== oauthOrigin || event.source !== popup || !popup)
|
|
4265
4412
|
return;
|
|
4266
|
-
if (
|
|
4413
|
+
if (!event.data || event.data.type !== "authorization_response" || !current() || exchanging)
|
|
4267
4414
|
return;
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
pollTimer = void 0;
|
|
4271
|
-
}
|
|
4272
|
-
try {
|
|
4273
|
-
popup.close();
|
|
4274
|
-
} catch {
|
|
4275
|
-
}
|
|
4415
|
+
clearInterval(pollTimer);
|
|
4416
|
+
clearInterval(sessionTimer);
|
|
4276
4417
|
if (event.data.error) {
|
|
4277
|
-
|
|
4278
|
-
cleanup();
|
|
4418
|
+
fail(event.data.error === "access_denied" ? "oauthDenied" : event.data.error === "cancelled" ? "oauthCancelled" : "oauthFailed");
|
|
4279
4419
|
return;
|
|
4280
4420
|
}
|
|
4281
4421
|
const { code, state } = event.data.response ?? event.data;
|
|
4282
|
-
if (!code) {
|
|
4283
|
-
|
|
4284
|
-
cleanup();
|
|
4422
|
+
if (typeof code !== "string" || !code || typeof state !== "string" || !state) {
|
|
4423
|
+
fail("oauthFailed");
|
|
4285
4424
|
return;
|
|
4286
4425
|
}
|
|
4287
|
-
|
|
4426
|
+
exchanging = true;
|
|
4427
|
+
lockMethods();
|
|
4428
|
+
actions.hidden = true;
|
|
4429
|
+
closePopup();
|
|
4430
|
+
hint.textContent = t("verifying", locale);
|
|
4431
|
+
btn.textContent = t("verifying", locale);
|
|
4288
4432
|
btn.disabled = true;
|
|
4289
4433
|
try {
|
|
4290
4434
|
const oauthBody = { provider: providerId, code, state };
|
|
4291
4435
|
if (this.options.invitationId)
|
|
4292
4436
|
oauthBody.invitationId = this.options.invitationId;
|
|
4293
|
-
await this.http.post(`${servicePrefix}/api/oauth/login`, oauthBody);
|
|
4437
|
+
await this.http.post(`${servicePrefix}/api/oauth/login`, oauthBody, { signal: this.abort?.signal });
|
|
4294
4438
|
succeed();
|
|
4295
|
-
} catch (
|
|
4296
|
-
if (
|
|
4439
|
+
} catch (err) {
|
|
4440
|
+
if (!current())
|
|
4297
4441
|
return;
|
|
4298
|
-
const
|
|
4299
|
-
const
|
|
4300
|
-
if (
|
|
4301
|
-
settled = true;
|
|
4442
|
+
const code2 = err instanceof Error && "code" in err ? String(err.code) : "";
|
|
4443
|
+
const message = err instanceof Error ? err.message : "";
|
|
4444
|
+
if (code2 === "FORBIDDEN" || code2 === "registration_closed" || message === "registration_closed") {
|
|
4302
4445
|
cleanup();
|
|
4303
|
-
|
|
4304
|
-
|
|
4305
|
-
|
|
4306
|
-
|
|
4446
|
+
recovery.remove();
|
|
4447
|
+
this.showFullError(friendlyError(err, locale));
|
|
4448
|
+
} else
|
|
4449
|
+
fail("oauthFailed");
|
|
4450
|
+
}
|
|
4451
|
+
};
|
|
4452
|
+
this.oauthCleanup = () => {
|
|
4453
|
+
cleanup();
|
|
4454
|
+
recovery.remove();
|
|
4455
|
+
closePopup();
|
|
4456
|
+
};
|
|
4457
|
+
window.addEventListener("message", onMessage);
|
|
4458
|
+
try {
|
|
4459
|
+
popup = window.open(loginUrl, "oauth-login:popup", `left=${window.screenX + (window.innerWidth - 500) / 2},top=${window.screenY + (window.innerHeight - 620) / 2},width=500,height=620,resizable,scrollbars=yes,status=1,popup`);
|
|
4460
|
+
} catch {
|
|
4461
|
+
}
|
|
4462
|
+
if (!popup) {
|
|
4463
|
+
fail("oauthBlocked");
|
|
4464
|
+
return;
|
|
4465
|
+
}
|
|
4466
|
+
hint.textContent = t("oauthWaiting", locale, { provider });
|
|
4467
|
+
btn.textContent = t("oauthWaiting", locale, { provider });
|
|
4468
|
+
btn.disabled = true;
|
|
4469
|
+
btn.classList.add("oauth-btn-loading");
|
|
4470
|
+
const checkSession = async () => {
|
|
4471
|
+
if (!current() || exchanging || probing)
|
|
4472
|
+
return;
|
|
4473
|
+
probing = true;
|
|
4474
|
+
try {
|
|
4475
|
+
const session = await this.http.get(`${servicePrefix}/api/did/session`);
|
|
4476
|
+
if (current() && !exchanging && session?.authenticated === true)
|
|
4477
|
+
succeed();
|
|
4478
|
+
} catch {
|
|
4479
|
+
} finally {
|
|
4480
|
+
probing = false;
|
|
4307
4481
|
}
|
|
4308
4482
|
};
|
|
4309
|
-
|
|
4483
|
+
pollTimer = setInterval(() => {
|
|
4310
4484
|
let closed = false;
|
|
4311
4485
|
try {
|
|
4312
|
-
closed = popup
|
|
4486
|
+
closed = !!popup?.closed;
|
|
4313
4487
|
} catch {
|
|
4314
4488
|
return;
|
|
4315
4489
|
}
|
|
4316
|
-
if (!closed)
|
|
4490
|
+
if (!closed || !current())
|
|
4317
4491
|
return;
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
if (session?.authenticated)
|
|
4326
|
-
succeed();
|
|
4327
|
-
}).catch(() => {
|
|
4328
|
-
});
|
|
4329
|
-
};
|
|
4330
|
-
checkSession();
|
|
4331
|
-
sessionPollTimer = setInterval(checkSession, 500);
|
|
4492
|
+
clearInterval(pollTimer);
|
|
4493
|
+
showRecovery("oauthIncomplete");
|
|
4494
|
+
cancel.hidden = false;
|
|
4495
|
+
void checkSession();
|
|
4496
|
+
sessionTimer = setInterval(() => {
|
|
4497
|
+
void checkSession();
|
|
4498
|
+
}, 2e3);
|
|
4332
4499
|
}, 500);
|
|
4333
|
-
|
|
4334
|
-
if (
|
|
4500
|
+
abandonTimer = setTimeout(() => {
|
|
4501
|
+
if (!current())
|
|
4502
|
+
return;
|
|
4503
|
+
if (!exchanging) {
|
|
4504
|
+
fail("oauthTimedOut");
|
|
4335
4505
|
return;
|
|
4336
|
-
cleanup();
|
|
4337
|
-
restore();
|
|
4338
|
-
}, 5 * 60 * 1e3);
|
|
4339
|
-
const cleanup = () => {
|
|
4340
|
-
settled = true;
|
|
4341
|
-
btn.innerHTML = originalHTML;
|
|
4342
|
-
btn.disabled = false;
|
|
4343
|
-
btn.classList.remove("oauth-btn-loading");
|
|
4344
|
-
if (pollTimer !== void 0) {
|
|
4345
|
-
clearInterval(pollTimer);
|
|
4346
|
-
pollTimer = void 0;
|
|
4347
|
-
}
|
|
4348
|
-
if (sessionPollTimer !== void 0) {
|
|
4349
|
-
clearInterval(sessionPollTimer);
|
|
4350
|
-
sessionPollTimer = void 0;
|
|
4351
4506
|
}
|
|
4352
|
-
|
|
4353
|
-
window.removeEventListener("message", onMessage);
|
|
4354
|
-
};
|
|
4355
|
-
this.oauthCleanup = () => {
|
|
4507
|
+
this.abort?.abort();
|
|
4356
4508
|
cleanup();
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4509
|
+
closePopup();
|
|
4510
|
+
lockMethods();
|
|
4511
|
+
hint.textContent = t("oauthUnconfirmed", locale);
|
|
4512
|
+
recovery.dataset.state = "oauthUnconfirmed";
|
|
4513
|
+
actions.hidden = false;
|
|
4514
|
+
reopen.hidden = true;
|
|
4515
|
+
cancel.hidden = true;
|
|
4516
|
+
fullPage.href = window.location.href;
|
|
4517
|
+
fullPage.textContent = t("oauthCheckSession", locale);
|
|
4518
|
+
this.emit("incomplete");
|
|
4519
|
+
}, 5 * 60 * 1e3);
|
|
4364
4520
|
}
|
|
4365
4521
|
// (removed dead code: renderEmailButton — email now renders through renderSecondaryGrid)
|
|
4366
4522
|
/**
|
|
@@ -4383,6 +4539,7 @@ var LoginPage = class {
|
|
|
4383
4539
|
btn.dataset.provider = provider.id;
|
|
4384
4540
|
const icon = getOAuthIcon(provider.id);
|
|
4385
4541
|
btn.innerHTML = `${icon} ${escapeHtml(t("continueWith", locale, { provider: provider.name }))}`;
|
|
4542
|
+
this.markLastUsed(btn, `oauth:${provider.id}`, locale);
|
|
4386
4543
|
grid.appendChild(btn);
|
|
4387
4544
|
btn.addEventListener("click", () => {
|
|
4388
4545
|
this.select("oauth");
|
|
@@ -4396,6 +4553,7 @@ var LoginPage = class {
|
|
|
4396
4553
|
btn.className = "method-btn";
|
|
4397
4554
|
btn.id = "email-btn";
|
|
4398
4555
|
btn.innerHTML = `${ICON_EMAIL} ${escapeHtml(t("emailButton", locale))}`;
|
|
4556
|
+
this.markLastUsed(btn, "email", locale);
|
|
4399
4557
|
grid.appendChild(btn);
|
|
4400
4558
|
btn.addEventListener("click", () => {
|
|
4401
4559
|
this.select("email");
|
|
@@ -4408,6 +4566,7 @@ var LoginPage = class {
|
|
|
4408
4566
|
btn.id = "did-wallet-btn";
|
|
4409
4567
|
const walletLabel = grid.children.length > 0 ? t("didWalletButtonShort", locale) : t("didWalletButton", locale);
|
|
4410
4568
|
btn.innerHTML = `${ICON_DID_WALLET} ${escapeHtml(walletLabel)}`;
|
|
4569
|
+
this.markLastUsed(btn, "did-connect", locale);
|
|
4411
4570
|
grid.appendChild(btn);
|
|
4412
4571
|
btn.addEventListener("click", () => {
|
|
4413
4572
|
this.select("did-connect");
|
|
@@ -4444,7 +4603,7 @@ var LoginPage = class {
|
|
|
4444
4603
|
}
|
|
4445
4604
|
});
|
|
4446
4605
|
this.tokenSession.on("timeout", () => {
|
|
4447
|
-
statusEl.textContent =
|
|
4606
|
+
statusEl.textContent = "";
|
|
4448
4607
|
const overlay = document.createElement("div");
|
|
4449
4608
|
overlay.className = "qr-timeout-overlay";
|
|
4450
4609
|
overlay.innerHTML = `<span class="timeout-text">${escapeHtml(t("timeout", locale))}</span>`;
|
|
@@ -4459,7 +4618,8 @@ var LoginPage = class {
|
|
|
4459
4618
|
this.startDIDConnectInView(statusEl, qrContainer, walletBtn, locale);
|
|
4460
4619
|
});
|
|
4461
4620
|
overlay.appendChild(refreshBtn);
|
|
4462
|
-
qrContainer.
|
|
4621
|
+
const plate = qrContainer.querySelector(".qr-plate");
|
|
4622
|
+
(plate ?? qrContainer).appendChild(overlay);
|
|
4463
4623
|
});
|
|
4464
4624
|
this.tokenSession.on("error", (err) => {
|
|
4465
4625
|
this.showConnectResult(qrContainer, walletBtn, statusEl, friendlyError(err, locale), true);
|
|
@@ -4710,6 +4870,9 @@ var LoginDialog = class {
|
|
|
4710
4870
|
mount() {
|
|
4711
4871
|
if (this.dialog)
|
|
4712
4872
|
return;
|
|
4873
|
+
const hostLocale = document.documentElement.lang;
|
|
4874
|
+
if (hostLocale)
|
|
4875
|
+
this.options.locale = hostLocale;
|
|
4713
4876
|
let focused = document.activeElement;
|
|
4714
4877
|
while (focused?.shadowRoot?.activeElement)
|
|
4715
4878
|
focused = focused.shadowRoot.activeElement;
|