@arcblock/did-connect-service 4.1.22 → 4.1.24

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.
Files changed (179) hide show
  1. package/dist/_generated/asset-bytes.js +1 -1
  2. package/dist/_generated/asset-manifest.js +4 -4
  3. package/dist/_generated/login-bundle-string.d.ts +1 -1
  4. package/dist/_generated/login-bundle-string.d.ts.map +1 -1
  5. package/dist/_generated/login-bundle-string.js +1 -1
  6. package/dist/_generated/login-bundle-string.js.map +1 -1
  7. package/dist/assets/admin-core.16704b2e.js +2065 -0
  8. package/dist/assets/admin-core.1fc3260c.js +1623 -0
  9. package/dist/assets/admin-core.5a2d69b0.js +2067 -0
  10. package/dist/assets/admin-core.9fff6042.js +2083 -0
  11. package/dist/assets/admin-core.a13c2729.js +1461 -0
  12. package/dist/assets/{admin-core.40671087.js → admin-core.a63bbc69.js} +2 -12
  13. package/dist/assets/admin-core.c0b5af61.js +1393 -0
  14. package/dist/assets/admin-core.cbbdbe6d.js +1465 -0
  15. package/dist/assets/admin-core.e83fd379.js +1397 -0
  16. package/dist/assets/admin-extra.143b5774.js +2543 -0
  17. package/dist/assets/admin-extra.35b91f98.js +2543 -0
  18. package/dist/assets/admin-extra.531b187f.js +2552 -0
  19. package/dist/assets/admin-extra.7ca9c16b.js +2529 -0
  20. package/dist/assets/admin-extra.841b2bbe.js +2530 -0
  21. package/dist/assets/admin-extra.afcb3651.js +2528 -0
  22. package/dist/assets/admin.7c5d5f04.css +2312 -0
  23. package/dist/assets/admin.c26bb17a.css +2219 -0
  24. package/dist/assets/login.0bf3d739.js +720 -0
  25. package/dist/assets/login.4404e695.js +720 -0
  26. package/dist/assets/login.bb9f8b03.js +720 -0
  27. package/dist/assets/login.d3f05790.js +720 -0
  28. package/dist/assets/login.fa25f37a.js +720 -0
  29. package/dist/assets/login.fb0bf7b4.js +720 -0
  30. package/dist/blocklet-service-rpc.d.ts.map +1 -1
  31. package/dist/blocklet-service-rpc.js +11 -8
  32. package/dist/blocklet-service-rpc.js.map +1 -1
  33. package/dist/blocklet-service.d.ts +11 -8
  34. package/dist/blocklet-service.d.ts.map +1 -1
  35. package/dist/blocklet-service.js +32 -38
  36. package/dist/blocklet-service.js.map +1 -1
  37. package/dist/embedded.d.ts +42 -1
  38. package/dist/embedded.d.ts.map +1 -1
  39. package/dist/embedded.js +60 -1
  40. package/dist/embedded.js.map +1 -1
  41. package/dist/handlers/access-key-connect-handler.d.ts.map +1 -1
  42. package/dist/handlers/access-key-connect-handler.js +12 -1
  43. package/dist/handlers/access-key-connect-handler.js.map +1 -1
  44. package/dist/handlers/account-merge-handler.d.ts +63 -0
  45. package/dist/handlers/account-merge-handler.d.ts.map +1 -0
  46. package/dist/handlers/account-merge-handler.js +263 -0
  47. package/dist/handlers/account-merge-handler.js.map +1 -0
  48. package/dist/handlers/auth-handler.d.ts +12 -5
  49. package/dist/handlers/auth-handler.d.ts.map +1 -1
  50. package/dist/handlers/auth-handler.js +54 -8
  51. package/dist/handlers/auth-handler.js.map +1 -1
  52. package/dist/handlers/blocklet-js-handler.d.ts +3 -2
  53. package/dist/handlers/blocklet-js-handler.d.ts.map +1 -1
  54. package/dist/handlers/blocklet-js-handler.js +4 -2
  55. package/dist/handlers/blocklet-js-handler.js.map +1 -1
  56. package/dist/handlers/branding-handler.d.ts +4 -0
  57. package/dist/handlers/branding-handler.d.ts.map +1 -1
  58. package/dist/handlers/branding-handler.js +12 -6
  59. package/dist/handlers/branding-handler.js.map +1 -1
  60. package/dist/handlers/did-connect-handler.d.ts +22 -0
  61. package/dist/handlers/did-connect-handler.d.ts.map +1 -1
  62. package/dist/handlers/did-connect-handler.js +191 -17
  63. package/dist/handlers/did-connect-handler.js.map +1 -1
  64. package/dist/handlers/email-login-handler.d.ts +2 -0
  65. package/dist/handlers/email-login-handler.d.ts.map +1 -1
  66. package/dist/handlers/email-login-handler.js +30 -14
  67. package/dist/handlers/email-login-handler.js.map +1 -1
  68. package/dist/handlers/oauth-handler.d.ts +15 -0
  69. package/dist/handlers/oauth-handler.d.ts.map +1 -1
  70. package/dist/handlers/oauth-handler.js +107 -43
  71. package/dist/handlers/oauth-handler.js.map +1 -1
  72. package/dist/handlers/passkey-handler.d.ts.map +1 -1
  73. package/dist/handlers/passkey-handler.js +40 -8
  74. package/dist/handlers/passkey-handler.js.map +1 -1
  75. package/dist/handlers/team-handler.d.ts +1 -1
  76. package/dist/handlers/team-handler.d.ts.map +1 -1
  77. package/dist/handlers/team-handler.js +43 -3
  78. package/dist/handlers/team-handler.js.map +1 -1
  79. package/dist/handlers/ticket-handler.d.ts.map +1 -1
  80. package/dist/handlers/ticket-handler.js +4 -2
  81. package/dist/handlers/ticket-handler.js.map +1 -1
  82. package/dist/handlers/unbind-account.d.ts +22 -0
  83. package/dist/handlers/unbind-account.d.ts.map +1 -0
  84. package/dist/handlers/unbind-account.js +20 -0
  85. package/dist/handlers/unbind-account.js.map +1 -0
  86. package/dist/http/security-headers.d.ts +38 -0
  87. package/dist/http/security-headers.d.ts.map +1 -0
  88. package/dist/http/security-headers.js +67 -0
  89. package/dist/http/security-headers.js.map +1 -0
  90. package/dist/identity/account-state.d.ts +37 -0
  91. package/dist/identity/account-state.d.ts.map +1 -0
  92. package/dist/identity/account-state.js +97 -0
  93. package/dist/identity/account-state.js.map +1 -0
  94. package/dist/identity/json-content-type.d.ts +14 -0
  95. package/dist/identity/json-content-type.d.ts.map +1 -0
  96. package/dist/identity/json-content-type.js +26 -0
  97. package/dist/identity/json-content-type.js.map +1 -0
  98. package/dist/index.d.ts +3 -1
  99. package/dist/index.d.ts.map +1 -1
  100. package/dist/index.js +2 -2
  101. package/dist/index.js.map +1 -1
  102. package/dist/oauth-adapters/apple.d.ts +1 -1
  103. package/dist/oauth-adapters/apple.d.ts.map +1 -1
  104. package/dist/oauth-adapters/apple.js +2 -0
  105. package/dist/oauth-adapters/apple.js.map +1 -1
  106. package/dist/oauth-adapters/auth0-legacy.d.ts +1 -1
  107. package/dist/oauth-adapters/auth0-legacy.d.ts.map +1 -1
  108. package/dist/oauth-adapters/auth0-legacy.js +2 -0
  109. package/dist/oauth-adapters/auth0-legacy.js.map +1 -1
  110. package/dist/oauth-adapters/auth0.d.ts +1 -1
  111. package/dist/oauth-adapters/auth0.d.ts.map +1 -1
  112. package/dist/oauth-adapters/auth0.js +2 -0
  113. package/dist/oauth-adapters/auth0.js.map +1 -1
  114. package/dist/oauth-adapters/github.d.ts.map +1 -1
  115. package/dist/oauth-adapters/github.js +19 -12
  116. package/dist/oauth-adapters/github.js.map +1 -1
  117. package/dist/oauth-adapters/google.d.ts +1 -1
  118. package/dist/oauth-adapters/google.d.ts.map +1 -1
  119. package/dist/oauth-adapters/google.js +2 -0
  120. package/dist/oauth-adapters/google.js.map +1 -1
  121. package/dist/oauth-adapters/types.d.ts +7 -0
  122. package/dist/oauth-adapters/types.d.ts.map +1 -1
  123. package/dist/oauth-adapters/types.js +4 -1
  124. package/dist/oauth-adapters/types.js.map +1 -1
  125. package/dist/package-branding.d.ts +18 -0
  126. package/dist/package-branding.d.ts.map +1 -0
  127. package/dist/package-branding.js +103 -0
  128. package/dist/package-branding.js.map +1 -0
  129. package/dist/pages/admin/i18n.d.ts.map +1 -1
  130. package/dist/pages/admin/i18n.js +86 -0
  131. package/dist/pages/admin/i18n.js.map +1 -1
  132. package/dist/pages/admin/index.d.ts +4 -0
  133. package/dist/pages/admin/index.d.ts.map +1 -1
  134. package/dist/pages/admin/index.js +10 -2
  135. package/dist/pages/admin/index.js.map +1 -1
  136. package/dist/pages/admin/merge-confirm-view.d.ts +48 -0
  137. package/dist/pages/admin/merge-confirm-view.d.ts.map +1 -0
  138. package/dist/pages/admin/merge-confirm-view.js +85 -0
  139. package/dist/pages/admin/merge-confirm-view.js.map +1 -0
  140. package/dist/pages/admin/merge-method-picker.d.ts +12 -0
  141. package/dist/pages/admin/merge-method-picker.d.ts.map +1 -0
  142. package/dist/pages/admin/merge-method-picker.js +34 -0
  143. package/dist/pages/admin/merge-method-picker.js.map +1 -0
  144. package/dist/pages/admin/oauth-popup-close.d.ts +13 -0
  145. package/dist/pages/admin/oauth-popup-close.d.ts.map +1 -0
  146. package/dist/pages/admin/oauth-popup-close.js +15 -0
  147. package/dist/pages/admin/oauth-popup-close.js.map +1 -0
  148. package/dist/pages/admin/styles.d.ts +1 -1
  149. package/dist/pages/admin/styles.d.ts.map +1 -1
  150. package/dist/pages/admin/styles.js +83 -0
  151. package/dist/pages/admin/styles.js.map +1 -1
  152. package/dist/pages/admin/tab-audit.d.ts +1 -1
  153. package/dist/pages/admin/tab-audit.d.ts.map +1 -1
  154. package/dist/pages/admin/tab-audit.js +12 -0
  155. package/dist/pages/admin/tab-audit.js.map +1 -1
  156. package/dist/pages/admin/tab-profile-accounts.d.ts.map +1 -1
  157. package/dist/pages/admin/tab-profile-accounts.js +492 -3
  158. package/dist/pages/admin/tab-profile-accounts.js.map +1 -1
  159. package/dist/pages/invite-page.d.ts +1 -0
  160. package/dist/pages/invite-page.d.ts.map +1 -1
  161. package/dist/pages/invite-page.js +13 -3
  162. package/dist/pages/invite-page.js.map +1 -1
  163. package/dist/store/account-merge.d.ts +167 -0
  164. package/dist/store/account-merge.d.ts.map +1 -0
  165. package/dist/store/account-merge.js +313 -0
  166. package/dist/store/account-merge.js.map +1 -0
  167. package/dist/store/d1-store.d.ts +104 -7
  168. package/dist/store/d1-store.d.ts.map +1 -1
  169. package/dist/store/d1-store.js +449 -23
  170. package/dist/store/d1-store.js.map +1 -1
  171. package/dist/types.d.ts +8 -0
  172. package/dist/types.d.ts.map +1 -1
  173. package/migrations/0015_connected_accounts_id_index.sql +6 -0
  174. package/migrations/0016_did_aliases.sql +11 -0
  175. package/migrations/0017_unbind_revoke_and_cascade.sql +49 -0
  176. package/migrations/0018_primary_credential_did.sql +54 -0
  177. package/migrations/0019_account_merge.sql +16 -0
  178. package/migrations/0020_dedupe_connected_accounts.sql +24 -0
  179. package/package.json +3 -3
@@ -3,6 +3,8 @@
3
3
  * Grouped chip layout: bound accounts as chips, unbound as dashed add-chips.
4
4
  */
5
5
  import { ICON_DID_WALLET, ICON_EMAIL, ICON_PASSKEY, OAUTH_ICONS, } from "@arcblock/did-connect-core/ui";
6
+ import { renderMergeConfirmBodyHtml, toMergeConfirmViewModel } from "./merge-confirm-view.js";
7
+ import { renderMergeMethodPickerHtml } from "./merge-method-picker.js";
6
8
  /** Providers hidden from the Connected Accounts UI. */
7
9
  const HIDDEN_PROVIDERS = new Set(["facebook", "auth0-legacy"]);
8
10
  /** Build a JS-safe icon map to embed in inline <script>. */
@@ -26,6 +28,7 @@ export function connectedAccountsCardHtml(t) {
26
28
  <div class="settings-card-header">
27
29
  <span class="settings-card-title">${t("profile.connectedAccounts")}</span>
28
30
  </div>
31
+ <div id="merge-candidate-prompt" class="ca-merge-prompt" style="display:none;" hidden></div>
29
32
  <div id="connected-accounts-list"></div>
30
33
  </div>
31
34
  `;
@@ -35,12 +38,18 @@ export function connectedAccountsCardHtml(t) {
35
38
  export const CONNECTED_ACCOUNTS_SCRIPT = /* @__PURE__ */ (() => /* js */ `
36
39
  var __connectedAccounts = [];
37
40
  var __oauthProviders = [];
41
+ var __accountMergeOAuthCleanup = null;
42
+ var __mergePromptDid = "";
38
43
  var __providerIcons = ${buildIconMapJSON()};
39
44
  var __hiddenProviders = ${JSON.stringify([...HIDDEN_PROVIDERS])};
45
+ ${toMergeConfirmViewModel.toString()}
46
+ ${renderMergeConfirmBodyHtml.toString()}
47
+ ${renderMergeMethodPickerHtml.toString()}
40
48
 
41
49
  async function loadConnectedAccounts() {
42
50
  var card = document.getElementById("connected-accounts-card");
43
51
  var list = document.getElementById("connected-accounts-list");
52
+ hideMergePrompt();
44
53
 
45
54
  // Show card with skeleton chips while loading
46
55
  card.style.display = "";
@@ -69,6 +78,7 @@ async function loadConnectedAccounts() {
69
78
 
70
79
  card.style.display = "";
71
80
  renderConnectedAccounts();
81
+ maybeShowMergePrompt(userObj.did);
72
82
  }
73
83
 
74
84
  function renderConnectedAccounts() {
@@ -166,6 +176,12 @@ function renderConnectedAccounts() {
166
176
  html += '</div></div>';
167
177
  }
168
178
 
179
+ html += '<div class="ca-section">';
180
+ html += '<div class="ca-section-label">' + __t("profile.mergeAccount") + '</div>';
181
+ html += '<p class="ca-merge-hint" style="margin:0 0 8px;color:var(--text-secondary);font-size:13px;">' + __t("profile.mergeAccountHint") + '</p>';
182
+ html += '<button class="btn btn-secondary" onclick="startAccountMerge()">' + __t("profile.mergeChooseMethod") + '</button>';
183
+ html += '</div>';
184
+
169
185
  list.innerHTML = html;
170
186
  }
171
187
 
@@ -200,10 +216,15 @@ function renderBoundCard(a) {
200
216
  }
201
217
  html += '</div>';
202
218
 
203
- // Action buttons at top-right
204
- if (!a.isMain && a.provider !== "wallet" && a.provider !== "did-connect") {
219
+ // Action buttons at top-right. Wallet / did-connect get a dedicated unbind
220
+ // button (Decision 2: wallet is a credential). Last-credential is enforced
221
+ // server-side; the button is shown even on the main wallet row.
222
+ var isWallet = a.provider === "wallet" || a.provider === "did-connect";
223
+ if (isWallet || !a.isMain) {
205
224
  html += '<div class="ca-bound-actions">';
206
- if (isPasskey) {
225
+ if (isWallet) {
226
+ html += '<button class="btn-text" style="color:var(--red-text)" onclick="unbindWallet(\\'' + escapeHtml(a.provider) + '\\')">' + __t("profile.remove") + '</button>';
227
+ } else if (isPasskey) {
207
228
  html += '<button class="btn-text" onclick="openRenamePasskeyDialog(\\'' + escapeHtml(a.did) + '\\', \\'' + escapeHtml(getPasskeyName(a)) + '\\')">' + __t("profile.renamePasskey") + '</button>';
208
229
  html += '<button class="btn-text" style="color:var(--red-text)" onclick="removePasskey(\\'' + escapeHtml(a.did) + '\\')">' + __t("profile.remove") + '</button>';
209
230
  } else {
@@ -328,6 +349,20 @@ async function unbindOAuth(provider) {
328
349
  }
329
350
  }
330
351
 
352
+ async function unbindWallet(provider) {
353
+ var ok = await confirmDialog({
354
+ title: __t("profile.removeConfirmTitle"),
355
+ message: __t("profile.removeConfirmMsg"),
356
+ confirmLabel: __t("profile.remove"),
357
+ });
358
+ if (!ok) return;
359
+ var data = await api("POST", "/../wallet/unbind", { provider: provider });
360
+ if (data.ok) {
361
+ showToast(__t("profile.accountRemoved"), "success");
362
+ loadConnectedAccounts();
363
+ }
364
+ }
365
+
331
366
  async function addPasskey() {
332
367
  try {
333
368
  // 1. Get registration options. The server flattens the WebAuthn options to
@@ -457,6 +492,460 @@ function __openInWallet(url, appInfo, memberAppInfo) {
457
492
  }
458
493
  }
459
494
 
495
+ function listMergeMethods() {
496
+ var auth = (typeof window !== "undefined" && window.__mergeAuth) || { wallet: true, passkey: true, email: false };
497
+ var methods = [];
498
+ if (auth.wallet !== false) methods.push({ method: "wallet" });
499
+ if (auth.passkey !== false) methods.push({ method: "passkey" });
500
+ for (var i = 0; i < __oauthProviders.length; i++) {
501
+ methods.push({ method: "oauth", provider: __oauthProviders[i] });
502
+ }
503
+ if (auth.email) methods.push({ method: "email" });
504
+ return methods;
505
+ }
506
+
507
+ function cleanupAccountMergeOAuth() {
508
+ if (__accountMergeOAuthCleanup) __accountMergeOAuthCleanup();
509
+ }
510
+
511
+ async function proveAccountMergeWithWallet(mergeChallenge) {
512
+ var tokenData;
513
+ try {
514
+ tokenData = await api("GET", "/../did/merge-proof/token");
515
+ } catch (e) {
516
+ showToast(__t("profile.mergeFailed"), "error");
517
+ return null;
518
+ }
519
+ if (!tokenData || !tokenData.token) {
520
+ showToast(__t("profile.mergeFailed"), "error");
521
+ return null;
522
+ }
523
+
524
+ var token = tokenData.token;
525
+ var connectUrl = tokenData.url || "";
526
+ var appInfo = tokenData.appInfo || {};
527
+ var memberAppInfo = tokenData.memberAppInfo || {};
528
+
529
+ return new Promise(function(resolve) {
530
+ var d = document.getElementById("wallet-merge-dialog");
531
+ if (!d) {
532
+ d = document.createElement("dialog");
533
+ d.id = "wallet-merge-dialog";
534
+ document.body.appendChild(d);
535
+ }
536
+ d.innerHTML = '<div class="dialog-content" style="text-align:center;">'
537
+ + '<h3 style="margin-bottom:4px;">' + __t("profile.mergeProveWallet") + '</h3>'
538
+ + '<div id="wallet-merge-qr" class="wallet-qr-view">'
539
+ + '<div class="wallet-qr-placeholder"><span class="wallet-qr-spinner"></span></div>'
540
+ + '</div>'
541
+ + '<button id="wallet-merge-open" class="btn btn-secondary wallet-deep-link-btn" disabled>'
542
+ + getProviderIconSvg("did-connect") + ' ' + __t("profile.openInWallet")
543
+ + '</button>'
544
+ + '<p id="wallet-merge-status" class="wallet-bind-status">' + __t("profile.scanWithWallet") + '</p>'
545
+ + '</div>'
546
+ + '<div class="dialog-actions">'
547
+ + '<button class="btn btn-secondary" id="wallet-merge-cancel">' + __t("common.cancel") + '</button>'
548
+ + '</div>';
549
+
550
+ var statusEl = document.getElementById("wallet-merge-status");
551
+ var qrEl = document.getElementById("wallet-merge-qr");
552
+ var openBtn = document.getElementById("wallet-merge-open");
553
+ if (connectUrl && typeof __QRBundle !== "undefined" && __QRBundle.renderQR) {
554
+ __QRBundle.renderQR(qrEl, connectUrl, 212);
555
+ }
556
+ openBtn.disabled = false;
557
+ openBtn.onclick = function() { __openInWallet(connectUrl, appInfo, memberAppInfo); };
558
+
559
+ var pollTimer = null;
560
+ var pollCount = 0;
561
+ var settled = false;
562
+ var polling = false;
563
+ function finish(value) {
564
+ if (settled) return;
565
+ settled = true;
566
+ if (pollTimer) clearInterval(pollTimer);
567
+ pollTimer = null;
568
+ if (d.open) d.close();
569
+ resolve(value);
570
+ }
571
+ document.getElementById("wallet-merge-cancel").onclick = function() { finish(null); };
572
+ d.onclose = function() { finish(null); };
573
+ d.showModal();
574
+
575
+ pollTimer = setInterval(async function() {
576
+ if (polling || settled) return;
577
+ polling = true;
578
+ pollCount++;
579
+ if (pollCount > 120) {
580
+ clearInterval(pollTimer);
581
+ pollTimer = null;
582
+ statusEl.textContent = __t("profile.connectTimeout");
583
+ polling = false;
584
+ return;
585
+ }
586
+ try {
587
+ var status = await api("GET", "/../did/merge-proof/status?_t_=" + encodeURIComponent(token));
588
+ if (status.status === "scanned") {
589
+ statusEl.textContent = __t("profile.confirmInWallet");
590
+ } else if (status.status === "succeed") {
591
+ clearInterval(pollTimer);
592
+ pollTimer = null;
593
+ statusEl.textContent = __t("profile.binding");
594
+ var proved = await api("POST", "/../did/connect/complete", {
595
+ token: token,
596
+ mergeChallenge: mergeChallenge,
597
+ });
598
+ if (!proved || !proved.mergeIntent) {
599
+ statusEl.textContent = (proved && proved.error) || __t("profile.mergeFailed");
600
+ polling = false;
601
+ return;
602
+ }
603
+ finish(proved);
604
+ } else if (status.status === "error") {
605
+ clearInterval(pollTimer);
606
+ pollTimer = null;
607
+ statusEl.textContent = status.error || __t("profile.mergeFailed");
608
+ }
609
+ } catch (e) { /* ignore poll errors */ }
610
+ polling = false;
611
+ }, 1500);
612
+ });
613
+ }
614
+
615
+ async function proveAccountMergeWithPasskey(mergeChallenge) {
616
+ if (typeof PublicKeyCredential === "undefined" || !navigator.credentials || !navigator.credentials.get) {
617
+ showToast(__t("profile.mergePasskeyUnavailable"), "error");
618
+ return null;
619
+ }
620
+ var opts = await api("GET", "/../passkey/auth");
621
+ var publicKey = opts.authentication || opts;
622
+ if (!opts.challengeId || !publicKey || !publicKey.challenge) {
623
+ showToast((opts && opts.error) || __t("profile.mergeFailed"), "error");
624
+ return null;
625
+ }
626
+ publicKey.challenge = base64urlToBuffer(publicKey.challenge);
627
+ if (publicKey.allowCredentials) {
628
+ for (var i = 0; i < publicKey.allowCredentials.length; i++) {
629
+ publicKey.allowCredentials[i].id = base64urlToBuffer(publicKey.allowCredentials[i].id);
630
+ }
631
+ }
632
+ var credential;
633
+ try {
634
+ credential = await navigator.credentials.get({ publicKey: publicKey });
635
+ } catch (e) {
636
+ if (!e || e.name !== "NotAllowedError") {
637
+ showToast((e && e.message) || __t("profile.mergeFailed"), "error");
638
+ }
639
+ return null;
640
+ }
641
+ if (!credential) return null;
642
+ var response = credential.response;
643
+ return api("POST", "/../passkey/auth", {
644
+ challengeId: opts.challengeId,
645
+ credential: {
646
+ id: credential.id,
647
+ rawId: bufferToBase64url(credential.rawId),
648
+ type: credential.type,
649
+ response: {
650
+ authenticatorData: bufferToBase64url(response.authenticatorData),
651
+ clientDataJSON: bufferToBase64url(response.clientDataJSON),
652
+ signature: bufferToBase64url(response.signature),
653
+ userHandle: response.userHandle ? bufferToBase64url(response.userHandle) : undefined,
654
+ },
655
+ },
656
+ mergeChallenge: mergeChallenge,
657
+ });
658
+ }
659
+
660
+ function proveAccountMergeWithOAuth(provider, mergeChallenge) {
661
+ return new Promise(function(resolve) {
662
+ if (__oauthProviders.indexOf(provider) === -1) {
663
+ resolve(null);
664
+ return;
665
+ }
666
+ cleanupAccountMergeOAuth();
667
+ var returnUrl = encodeURIComponent(window.location.href);
668
+ var url = window.__BASE_PATH + "/../oauth/" + encodeURIComponent(provider) + "/login?returnUrl=" + returnUrl;
669
+ var redirectUri = location.origin + "/.well-known/service/oauth/callback/" + encodeURIComponent(provider);
670
+ var w = 500, h = 600;
671
+ var left = (screen.width - w) / 2, top = (screen.height - h) / 2;
672
+ var popup = window.open(url, "oauth_merge", "width=" + w + ",height=" + h + ",left=" + left + ",top=" + top);
673
+ if (!popup) {
674
+ showToast(__t("common.popupBlocked"), "error");
675
+ resolve(null);
676
+ return;
677
+ }
678
+ var settled = false;
679
+ var abandonTimer = setTimeout(function() {
680
+ if (settled) return;
681
+ showToast(__t("profile.mergePopupClosed"), "error");
682
+ finish(null);
683
+ }, 5 * 60 * 1000);
684
+ function cleanup() {
685
+ window.removeEventListener("message", onMessage);
686
+ clearTimeout(abandonTimer);
687
+ if (__accountMergeOAuthCleanup === cancel) __accountMergeOAuthCleanup = null;
688
+ }
689
+ function finish(value) {
690
+ if (settled) return;
691
+ settled = true;
692
+ cleanup();
693
+ resolve(value);
694
+ }
695
+ async function onMessage(event) {
696
+ if (event.origin !== location.origin) return;
697
+ if (!event.data || event.data.type !== "authorization_response") return;
698
+ if (settled) return;
699
+ clearTimeout(abandonTimer);
700
+ try { popup.close(); } catch (e) {}
701
+ var resp = event.data.response;
702
+ if (event.data.error || !resp || !resp.code) {
703
+ finish(null);
704
+ return;
705
+ }
706
+ try {
707
+ var proved = await api("POST", "/../oauth/login", {
708
+ provider: provider,
709
+ code: resp.code,
710
+ redirectUri: redirectUri,
711
+ mergeChallenge: mergeChallenge,
712
+ });
713
+ finish(proved);
714
+ } catch (e) {
715
+ showToast((e && e.message) || __t("profile.mergeFailed"), "error");
716
+ finish(null);
717
+ }
718
+ }
719
+ window.addEventListener("message", onMessage);
720
+ function cancel() {
721
+ try { popup.close(); } catch (e) {}
722
+ finish(null);
723
+ }
724
+ __accountMergeOAuthCleanup = cancel;
725
+ });
726
+ }
727
+
728
+ async function proveAccountMergeWithEmail(mergeChallenge) {
729
+ return new Promise(function(resolve) {
730
+ var d = document.getElementById("email-merge-dialog");
731
+ if (!d) {
732
+ d = document.createElement("dialog");
733
+ d.id = "email-merge-dialog";
734
+ document.body.appendChild(d);
735
+ }
736
+ d.innerHTML = '<div class="dialog-content">'
737
+ + '<h3>' + __t("profile.mergeProveEmail") + '</h3>'
738
+ + '<div class="merge-email-fields">'
739
+ + '<input class="input" id="email-merge-address" type="email" autocomplete="email" placeholder="' + escapeHtml(__t("profile.mergeEmailPlaceholder")) + '" />'
740
+ + '<input class="input" id="email-merge-code" inputmode="numeric" autocomplete="one-time-code" placeholder="' + escapeHtml(__t("profile.mergeEmailCodePlaceholder")) + '" disabled />'
741
+ + '<p id="email-merge-status" class="dialog-desc"></p>'
742
+ + '</div></div>'
743
+ + '<div class="dialog-actions">'
744
+ + '<button type="button" class="btn btn-secondary" id="email-merge-cancel">' + __t("common.cancel") + '</button>'
745
+ + '<button type="button" class="btn btn-secondary" id="email-merge-send">' + __t("profile.mergeEmailSendCode") + '</button>'
746
+ + '<button type="button" class="btn" id="email-merge-ok" disabled>' + __t("common.confirm") + '</button>'
747
+ + '</div>';
748
+
749
+ var emailEl = document.getElementById("email-merge-address");
750
+ var codeEl = document.getElementById("email-merge-code");
751
+ var statusEl = document.getElementById("email-merge-status");
752
+ var sendBtn = document.getElementById("email-merge-send");
753
+ var okBtn = document.getElementById("email-merge-ok");
754
+ var verifyId = null;
755
+ var settled = false;
756
+ function finish(value) {
757
+ if (settled) return;
758
+ settled = true;
759
+ if (d.open) d.close();
760
+ resolve(value);
761
+ }
762
+ document.getElementById("email-merge-cancel").onclick = function() { finish(null); };
763
+ d.onclose = function() { finish(null); };
764
+ sendBtn.onclick = async function() {
765
+ var email = (emailEl.value || "").trim();
766
+ if (!email || email.indexOf("@") === -1) return;
767
+ sendBtn.disabled = true;
768
+ statusEl.textContent = __t("profile.emailSending");
769
+ var sent = await api("POST", "/../email/sendCode", { email: email });
770
+ if (!sent || sent.id == null) {
771
+ statusEl.textContent = (sent && sent.error) || __t("profile.emailSendFailed");
772
+ sendBtn.disabled = false;
773
+ return;
774
+ }
775
+ verifyId = sent.id;
776
+ codeEl.disabled = false;
777
+ okBtn.disabled = false;
778
+ codeEl.focus();
779
+ statusEl.textContent = __t("profile.emailCodeSent");
780
+ sendBtn.disabled = false;
781
+ };
782
+ okBtn.onclick = async function() {
783
+ var code = (codeEl.value || "").trim();
784
+ if (!code || verifyId == null) return;
785
+ okBtn.disabled = true;
786
+ var proved = await api("POST", "/../email/login", {
787
+ code: code,
788
+ id: verifyId,
789
+ mergeChallenge: mergeChallenge,
790
+ });
791
+ if (!proved || !proved.mergeIntent) {
792
+ statusEl.textContent = (proved && proved.error) || __t("profile.mergeFailed");
793
+ okBtn.disabled = false;
794
+ return;
795
+ }
796
+ finish(proved);
797
+ };
798
+ d.showModal();
799
+ emailEl.focus();
800
+ });
801
+ }
802
+
803
+ async function finalizeAccountMerge(proved) {
804
+ if (!proved || !proved.mergeIntent) {
805
+ showToast((proved && proved.error) || __t("profile.mergeFailed"), "error");
806
+ return false;
807
+ }
808
+ var plan = await api("POST", "/../account/merge/dry-run", { mergeIntent: proved.mergeIntent });
809
+ var ok = await confirmMergePlan(plan);
810
+ if (!ok) {
811
+ showToast(__t("profile.mergeCancelled"), "error");
812
+ return false;
813
+ }
814
+ var committed = await api("POST", "/../account/merge/commit", { mergeIntent: proved.mergeIntent });
815
+ if (committed && committed.ok) {
816
+ showToast(__t("profile.mergeSuccess"), "success");
817
+ loadConnectedAccounts();
818
+ return true;
819
+ }
820
+ showToast((committed && committed.error) || __t("profile.mergeFailed"), "error");
821
+ return false;
822
+ }
823
+
824
+ function hideMergePrompt() {
825
+ var el = document.getElementById("merge-candidate-prompt");
826
+ if (!el) return;
827
+ el.style.display = "none";
828
+ el.hidden = true;
829
+ el.innerHTML = "";
830
+ }
831
+
832
+ function dismissMergePrompt() {
833
+ var did = __mergePromptDid || "";
834
+ if (did) {
835
+ try { localStorage["connect.mergePrompt.dismissed." + did] = "1"; } catch (e) {}
836
+ }
837
+ hideMergePrompt();
838
+ }
839
+
840
+ async function maybeShowMergePrompt(did) {
841
+ hideMergePrompt();
842
+ __mergePromptDid = did || "";
843
+ if (!did) return;
844
+ try {
845
+ if (localStorage["connect.mergePrompt.dismissed." + did] === "1") return;
846
+ } catch (e) {}
847
+ var data = await api("GET", "/../account/merge/candidate", undefined, { silent: true });
848
+ if (!data || data.mergeCandidate !== true) return;
849
+ try {
850
+ if (localStorage["connect.mergePrompt.dismissed." + did] === "1") return;
851
+ } catch (e) {}
852
+ var el = document.getElementById("merge-candidate-prompt");
853
+ if (!el) return;
854
+ el.innerHTML = '<div class="ca-merge-prompt-title">' + escapeHtml(__t("profile.mergePromptTitle")) + '</div>'
855
+ + '<p class="ca-merge-prompt-body">' + escapeHtml(__t("profile.mergePromptBody")) + '</p>'
856
+ + '<div class="ca-merge-prompt-actions">'
857
+ + '<button type="button" class="btn" id="merge-candidate-prompt-action" onclick="startAccountMerge()">' + escapeHtml(__t("profile.mergePromptAction")) + '</button>'
858
+ + '<button type="button" class="btn btn-secondary" id="merge-candidate-prompt-dismiss" onclick="dismissMergePrompt()">' + escapeHtml(__t("profile.mergePromptDismiss")) + '</button>'
859
+ + '</div>';
860
+ el.hidden = false;
861
+ el.style.display = "";
862
+ }
863
+
864
+ async function startAccountMerge() {
865
+ cleanupAccountMergeOAuth();
866
+ var start;
867
+ try {
868
+ start = await api("POST", "/../account/merge/start", {});
869
+ } catch (e) {
870
+ showToast((e && e.message) || __t("profile.mergeFailed"), "error");
871
+ return;
872
+ }
873
+ if (!start || !start.challenge) {
874
+ showToast(__t("profile.mergeFailed"), "error");
875
+ return;
876
+ }
877
+
878
+ var d = document.getElementById("account-merge-method-dialog");
879
+ if (!d) {
880
+ d = document.createElement("dialog");
881
+ d.id = "account-merge-method-dialog";
882
+ document.body.appendChild(d);
883
+ }
884
+ d.innerHTML = renderMergeMethodPickerHtml(listMergeMethods(), __t, escapeHtml, getProviderIconSvg, getProviderLabel);
885
+ document.getElementById("account-merge-method-cancel").onclick = function() { d.close(); };
886
+ var buttons = d.querySelectorAll("[data-merge-method]");
887
+ for (var b = 0; b < buttons.length; b++) {
888
+ buttons[b].onclick = async function(event) {
889
+ var button = event.currentTarget;
890
+ var method = button.getAttribute("data-merge-method");
891
+ var selectedProvider = button.getAttribute("data-merge-provider");
892
+ d.close();
893
+ try {
894
+ var proved = null;
895
+ if (method === "wallet") proved = await proveAccountMergeWithWallet(start.challenge);
896
+ else if (method === "passkey") proved = await proveAccountMergeWithPasskey(start.challenge);
897
+ else if (method === "oauth") proved = await proveAccountMergeWithOAuth(selectedProvider, start.challenge);
898
+ else if (method === "email") proved = await proveAccountMergeWithEmail(start.challenge);
899
+ if (proved) await finalizeAccountMerge(proved);
900
+ } catch (e) {
901
+ if (!e || e.name !== "NotAllowedError") {
902
+ showToast((e && e.message) || __t("profile.mergeFailed"), "error");
903
+ }
904
+ }
905
+ };
906
+ }
907
+ d.showModal();
908
+ }
909
+
910
+ function confirmMergePlan(plan) {
911
+ return new Promise(function(resolve) {
912
+ var d = document.getElementById("merge-confirm-dialog");
913
+ if (!d) {
914
+ d = document.createElement("dialog");
915
+ d.id = "merge-confirm-dialog";
916
+ d.className = "merge-confirm-dialog";
917
+ document.body.appendChild(d);
918
+ }
919
+ d.innerHTML = '<div class="dialog-content">'
920
+ + '<h3>' + escapeHtml(__t("profile.mergeConfirmTitle")) + '</h3>'
921
+ + renderMergeConfirmBodyHtml(plan, __t, escapeHtml, getProviderLabel)
922
+ + '</div>'
923
+ + '<div class="dialog-actions">'
924
+ + '<button class="btn btn-secondary" id="merge-confirm-cancel">' + escapeHtml(__t("common.cancel")) + '</button>'
925
+ + '<button class="btn btn-danger" id="merge-confirm-ok">' + escapeHtml(__t("common.confirm")) + '</button>'
926
+ + '</div>';
927
+
928
+ var okBtn = document.getElementById("merge-confirm-ok");
929
+ var cancelBtn = document.getElementById("merge-confirm-cancel");
930
+ if (plan && plan.tooLarge) okBtn.disabled = true;
931
+
932
+ var settled = false;
933
+ function finish(result) {
934
+ if (settled) return;
935
+ settled = true;
936
+ okBtn.onclick = null;
937
+ cancelBtn.onclick = null;
938
+ d.onclose = null;
939
+ d.close();
940
+ resolve(result);
941
+ }
942
+ okBtn.onclick = function() { if (okBtn.disabled) return; finish(true); };
943
+ cancelBtn.onclick = function() { finish(false); };
944
+ d.onclose = function() { finish(false); };
945
+ d.showModal();
946
+ });
947
+ }
948
+
460
949
  // ─── DID Wallet Connect (bind) ──────────────────────────────────────
461
950
  async function connectWallet() {
462
951
  // 1. Create bind session
@@ -1 +1 @@
1
- {"version":3,"file":"tab-profile-accounts.js","sourceRoot":"","sources":["../../../src/pages/admin/tab-profile-accounts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,+BAA+B,CAAC;AAIvC,uDAAuD;AACvD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;AAE/D,4DAA4D;AAC5D,SAAS,gBAAgB;IACvB,MAAM,GAAG,GAA2B;QAClC,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,eAAe;QACvB,aAAa,EAAE,eAAe;QAC9B,KAAK,EAAE,UAAU;KAClB,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,CAAM;IAC9C,OAAO,UAAU,CAAC;;;0CAGsB,CAAC,CAAC,2BAA2B,CAAC;;;;CAIvE,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;;;wBAGjD,gBAAgB,EAAE;0BAChB,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0iB9D,CAAC,EAAE,CAAC"}
1
+ {"version":3,"file":"tab-profile-accounts.js","sourceRoot":"","sources":["../../../src/pages/admin/tab-profile-accounts.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,eAAe,EACf,UAAU,EACV,YAAY,EACZ,WAAW,GACZ,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAE,0BAA0B,EAAE,uBAAuB,EAAE,MAAM,yBAAyB,CAAC;AAC9F,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAIvE,uDAAuD;AACvD,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC;AAE/D,4DAA4D;AAC5D,SAAS,gBAAgB;IACvB,MAAM,GAAG,GAA2B;QAClC,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,eAAe;QACvB,aAAa,EAAE,eAAe;QAC9B,KAAK,EAAE,UAAU;KAClB,CAAC;IACF,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QACrD,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/B,GAAG,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACjB,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;AAC7B,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,CAAM;IAC9C,OAAO,UAAU,CAAC;;;0CAGsB,CAAC,CAAC,2BAA2B,CAAC;;;;;CAKvE,CAAC;AACF,CAAC;AAED,mFAAmF;AACnF,+EAA+E;AAC/E,MAAM,CAAC,MAAM,yBAAyB,GAAG,eAAe,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC;;;;;wBAKjD,gBAAgB,EAAE;0BAChB,IAAI,CAAC,SAAS,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC;EAC7D,uBAAuB,CAAC,QAAQ,EAAE;EAClC,0BAA0B,CAAC,QAAQ,EAAE;EACrC,2BAA2B,CAAC,QAAQ,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA2gCvC,CAAC,EAAE,CAAC"}
@@ -12,5 +12,6 @@
12
12
  */
13
13
  export declare function buildInvitePageHTML(apiBase: string, locale?: string, options?: {
14
14
  masterOAuthOrigin?: string;
15
+ appName?: string;
15
16
  }): string;
16
17
  //# sourceMappingURL=invite-page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"invite-page.d.ts","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2DH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,SAAO,EACb,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAAE,GACvC,MAAM,CAkPR"}
1
+ {"version":3,"file":"invite-page.d.ts","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AA2DH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,MAAM,SAAO,EACb,OAAO,CAAC,EAAE;IAAE,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GACzD,MAAM,CA4PR"}
@@ -69,6 +69,12 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
69
69
  const masterOAuthOriginJson = JSON.stringify(options?.masterOAuthOrigin ?? null);
70
70
  const lang = locale === "zh" ? "zh" : "en";
71
71
  const t = INVITE_I18N[lang];
72
+ const appName = (options?.appName ?? "App")
73
+ .replaceAll("&", "&amp;")
74
+ .replaceAll("<", "&lt;")
75
+ .replaceAll(">", "&gt;")
76
+ .replaceAll('"', "&quot;")
77
+ .replaceAll("'", "&#39;");
72
78
  const clientI18n = JSON.stringify({
73
79
  noIdTitle: t.noIdTitle,
74
80
  noIdMsg: t.noIdMsg,
@@ -87,7 +93,7 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
87
93
  <head>
88
94
  <meta charset="utf-8" />
89
95
  <meta name="viewport" content="width=device-width, initial-scale=1" />
90
- <title>${t.title}</title>
96
+ <title>${t.title} — ${appName}</title>
91
97
  <link rel="stylesheet" href="${assetUrl("login.css")}" />
92
98
  <style>
93
99
  .invite-role {
@@ -126,6 +132,7 @@ export function buildInvitePageHTML(apiBase, locale = "en", options) {
126
132
 
127
133
  <div id="valid-state" class="hidden">
128
134
  <h1>${t.title}</h1>
135
+ <p class="subtitle">${appName}</p>
129
136
  <div class="invite-info">
130
137
  <p class="subtitle">${t.invitedPrefix}<span class="invite-role" id="invite-role"></span>${t.invitedSuffix}</p>
131
138
  <p class="invite-remark hidden" id="invite-remark"></p>
@@ -217,8 +224,11 @@ async function init() {
217
224
  return;
218
225
  }
219
226
 
220
- // Persist invitationId in cookie so login methods can pick it up
221
- document.cookie = "pending_invitation=" + encodeURIComponent(invitationId) + ";path=/;max-age=3600;SameSite=Lax;Secure";
227
+ // Persist invitationId in cookie so login methods can pick it up.
228
+ // Secure is gated on https — the browser drops a Secure cookie over plain http
229
+ // (e.g. a LAN dev server), which would silently lose the invitation.
230
+ var securePart = location.protocol === "https:" ? ";Secure" : "";
231
+ document.cookie = "pending_invitation=" + encodeURIComponent(invitationId) + ";path=/;max-age=3600;SameSite=Lax" + securePart;
222
232
 
223
233
  // 1. Check invitation validity
224
234
  var invInfo;
@@ -1 +1 @@
1
- {"version":3,"file":"invite-page.js","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"invite-page.js","sourceRoot":"","sources":["../../src/pages/invite-page.ts"],"names":[],"mappings":"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"}