@senguoyun/dsh-arkme 0.1.77 → 0.1.79

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 (63) hide show
  1. package/lib/client.js +1037 -134
  2. package/lib/client.js.map +1 -1
  3. package/lib/harness-model-client.js +26 -4
  4. package/lib/harness-native-selection-client.js +26 -4
  5. package/lib/harness-session-client.js +13 -2
  6. package/lib/harness-sidebar-client.js +9 -1
  7. package/lib/index.js +32 -1
  8. package/lib/persistent-extension.js +1 -1
  9. package/lib/{persistent-runtime-eUVtjdJU.js → persistent-runtime-CB7mEj3E.js} +507 -111
  10. package/lib/sdk.js +9 -1
  11. package/lib/types/account-session-owner.d.ts +1 -1
  12. package/lib/types/account-session-owner.d.ts.map +1 -1
  13. package/lib/types/arkme-service.d.ts +16 -0
  14. package/lib/types/arkme-service.d.ts.map +1 -1
  15. package/lib/types/client/ArkmeAccountCancellation.d.ts +8 -0
  16. package/lib/types/client/ArkmeAccountCancellation.d.ts.map +1 -0
  17. package/lib/types/client/ArkmeLogin.d.ts +3 -0
  18. package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
  19. package/lib/types/client/ArkmeRecordingSurface.d.ts +2 -1
  20. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  21. package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
  22. package/lib/types/client/ArkmeSettingsSurface.d.ts +12 -1
  23. package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
  24. package/lib/types/client/arkme-auth-flow.d.ts.map +1 -1
  25. package/lib/types/client/arkme-login-locales.d.ts +6 -0
  26. package/lib/types/client/arkme-login-locales.d.ts.map +1 -1
  27. package/lib/types/client/auth-store.d.ts.map +1 -1
  28. package/lib/types/client/harness-attachment-draft.d.ts +1 -1
  29. package/lib/types/client/harness-attachment-draft.d.ts.map +1 -1
  30. package/lib/types/client/harness-session-client.d.ts.map +1 -1
  31. package/lib/types/client/locales/actions-en.d.ts.map +1 -1
  32. package/lib/types/client/locales/en.d.ts.map +1 -1
  33. package/lib/types/client/recordings/RecordingSearchRow.d.ts +5 -0
  34. package/lib/types/client/recordings/RecordingSearchRow.d.ts.map +1 -0
  35. package/lib/types/client/recordings/recording-search-target.d.ts +4 -0
  36. package/lib/types/client/recordings/recording-search-target.d.ts.map +1 -0
  37. package/lib/types/client/ui-controller.d.ts +3 -5
  38. package/lib/types/client/ui-controller.d.ts.map +1 -1
  39. package/lib/types/host-api.d.ts.map +1 -1
  40. package/lib/types/index.d.ts +1 -1
  41. package/lib/types/index.d.ts.map +1 -1
  42. package/lib/types/local-database.d.ts +2 -0
  43. package/lib/types/local-database.d.ts.map +1 -1
  44. package/lib/types/recording-presentation.d.ts +1 -0
  45. package/lib/types/recording-presentation.d.ts.map +1 -1
  46. package/lib/types/recording-search-result.d.ts +3 -0
  47. package/lib/types/recording-search-result.d.ts.map +1 -0
  48. package/lib/types/recording-search-version.d.ts +17 -0
  49. package/lib/types/recording-search-version.d.ts.map +1 -0
  50. package/lib/types/sdk/index.d.ts +7 -1
  51. package/lib/types/sdk/index.d.ts.map +1 -1
  52. package/lib/types/services/auth-service.d.ts +30 -1
  53. package/lib/types/services/auth-service.d.ts.map +1 -1
  54. package/lib/types/services/recording-service.d.ts.map +1 -1
  55. package/lib/types/services/search-service.d.ts +3 -1
  56. package/lib/types/services/search-service.d.ts.map +1 -1
  57. package/lib/types/services/service.d.ts +4 -0
  58. package/lib/types/services/service.d.ts.map +1 -1
  59. package/lib/types/state-store.d.ts +7 -0
  60. package/lib/types/state-store.d.ts.map +1 -1
  61. package/lib/types/types.d.ts +45 -2
  62. package/lib/types/types.d.ts.map +1 -1
  63. package/package.json +5 -5
package/lib/client.js CHANGED
@@ -560,7 +560,15 @@ window.__ModuleLoader__.load({
560
560
  captcha
561
561
  }, signal);
562
562
  }
563
- /** Verify a phone code and refresh the account auth/profile state. */
563
+ async checkPhoneUnbindEligibility(expectedUserId, signal) {
564
+ return await this.call("auth.phone.unbind.check", { expectedUserId }, signal);
565
+ }
566
+ async sendPhoneUnbindCode(captcha, signal) {
567
+ return await this.call("auth.phone.unbind.send", { captcha }, signal);
568
+ }
569
+ async unbindPhone(code, signal) {
570
+ return await this.call("auth.phone.unbind", { code: code.trim() }, signal);
571
+ }
564
572
  async verifyPhoneCode(phone, code, signal) {
565
573
  const normalized = phone.replace(/[\s-]/g, "");
566
574
  const normalizedCode = code.trim();
@@ -1782,7 +1790,7 @@ window.__ModuleLoader__.load({
1782
1790
  return current.revision + 1;
1783
1791
  }
1784
1792
  function sameAuth(left, right) {
1785
- return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis;
1793
+ return left?.status === right?.status && left?.environment === right?.environment && left?.userId === right?.userId && left?.attemptId === right?.attemptId && left?.expiresAtMillis === right?.expiresAtMillis && left?.restDaysCancel === right?.restDaysCancel && left?.cancellationNotice === right?.cancellationNotice;
1786
1794
  }
1787
1795
  var ArkmeAuthStore = class {
1788
1796
  state = {
@@ -1805,6 +1813,10 @@ window.__ModuleLoader__.load({
1805
1813
  };
1806
1814
  setAuth(auth) {
1807
1815
  if (sameAuth(this.state.auth, auth) && this.state.checked && !this.state.busy && this.state.error === "") return;
1816
+ if (!["authenticated", "binding-required"].includes(auth.status) && auth.cancellationNotice === void 0 && this.state.auth?.cancellationNotice !== void 0) auth = {
1817
+ ...auth,
1818
+ cancellationNotice: this.state.auth.cancellationNotice
1819
+ };
1808
1820
  this.authGeneration += 1;
1809
1821
  this.publish({
1810
1822
  ...this.state,
@@ -1835,8 +1847,12 @@ window.__ModuleLoader__.load({
1835
1847
  });
1836
1848
  const pending = Promise.all([callArkme("auth.status"), callArkme("auth.config")]).then(([auth, config]) => {
1837
1849
  const currentAuth = this.state.auth;
1838
- const preservePendingAttempt = currentAuth?.status === "pending" && (auth.status === "logged-out" || auth.status === "expired");
1839
- const effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
1850
+ const preservePendingAttempt = (currentAuth?.status === "pending" || currentAuth?.status === "cancellation-pending") && (auth.status === "logged-out" || auth.status === "expired");
1851
+ let effectiveAuth = this.authGeneration === authGeneration && !preservePendingAttempt ? auth : currentAuth ?? auth;
1852
+ if (!["authenticated", "binding-required"].includes(effectiveAuth.status) && effectiveAuth.cancellationNotice === void 0 && currentAuth?.cancellationNotice !== void 0) effectiveAuth = {
1853
+ ...effectiveAuth,
1854
+ cancellationNotice: currentAuth.cancellationNotice
1855
+ };
1840
1856
  this.publish({
1841
1857
  ...this.state,
1842
1858
  auth: effectiveAuth,
@@ -31149,7 +31165,7 @@ window.__ModuleLoader__.load({
31149
31165
  }
31150
31166
  this.showWorld();
31151
31167
  }
31152
- showRecordingTarget(dateStamp, startAtMillis) {
31168
+ showRecordingTarget(dateStamp, startAtMillis, segment) {
31153
31169
  this.leaveContacts();
31154
31170
  const { selectedSource: _selectedSource, calendarOpen: _calendarOpen, productMode: _productMode, ...rest } = this.state;
31155
31171
  this.publish({
@@ -31157,7 +31173,8 @@ window.__ModuleLoader__.load({
31157
31173
  mode: "recordings",
31158
31174
  recordingTarget: {
31159
31175
  dateStamp,
31160
- startAtMillis
31176
+ startAtMillis,
31177
+ ...segment === void 0 ? {} : { segment }
31161
31178
  }
31162
31179
  });
31163
31180
  }
@@ -31379,7 +31396,7 @@ window.__ModuleLoader__.load({
31379
31396
  const { worldInitialScope: _scope, worldNavigationRevision: _revision, ...rest } = next;
31380
31397
  next = rest;
31381
31398
  }
31382
- const sameView = next.authRevision === this.state.authRevision && next.mode === this.state.mode && next.productMode === this.state.productMode && next.calendarOpen === this.state.calendarOpen && next.notificationActivationRevision === this.state.notificationActivationRevision && next.conversationUnreadJumpRevision === this.state.conversationUnreadJumpRevision && next.conversationTarget?.revision === this.state.conversationTarget?.revision && next.conversationTarget?.itemUid === this.state.conversationTarget?.itemUid && next.conversationTarget?.sendAtMillis === this.state.conversationTarget?.sendAtMillis && next.conversationTarget?.recordOwnerUserId === this.state.conversationTarget?.recordOwnerUserId && next.recordingTarget?.dateStamp === this.state.recordingTarget?.dateStamp && next.recordingTarget?.startAtMillis === this.state.recordingTarget?.startAtMillis && next.searchTarget?.revision === this.state.searchTarget?.revision && next.searchTarget?.query === this.state.searchTarget?.query && next.extensionShareRef === this.state.extensionShareRef && next.extensionShareAction === this.state.extensionShareAction && next.extensionDetailId === this.state.extensionDetailId && next.extensionAuthorFilter?.ownerUserId === this.state.extensionAuthorFilter?.ownerUserId && next.extensionAuthorFilter?.ownerName === this.state.extensionAuthorFilter?.ownerName && next.webLoginDialogOpen === this.state.webLoginDialogOpen && sameWorldTarget(next.worldTarget, this.state.worldTarget) && next.worldInitialScope === this.state.worldInitialScope && next.worldNavigationRevision === this.state.worldNavigationRevision && sameSelectedSource(next.selectedSource, this.state.selectedSource) && sameBot(next.selectedBot, this.state.selectedBot);
31399
+ const sameView = next.authRevision === this.state.authRevision && next.mode === this.state.mode && next.productMode === this.state.productMode && next.calendarOpen === this.state.calendarOpen && next.notificationActivationRevision === this.state.notificationActivationRevision && next.conversationUnreadJumpRevision === this.state.conversationUnreadJumpRevision && next.conversationTarget?.revision === this.state.conversationTarget?.revision && next.conversationTarget?.itemUid === this.state.conversationTarget?.itemUid && next.conversationTarget?.sendAtMillis === this.state.conversationTarget?.sendAtMillis && next.conversationTarget?.recordOwnerUserId === this.state.conversationTarget?.recordOwnerUserId && next.recordingTarget?.dateStamp === this.state.recordingTarget?.dateStamp && next.recordingTarget?.startAtMillis === this.state.recordingTarget?.startAtMillis && JSON.stringify(next.recordingTarget?.segment) === JSON.stringify(this.state.recordingTarget?.segment) && next.searchTarget?.revision === this.state.searchTarget?.revision && next.searchTarget?.query === this.state.searchTarget?.query && next.extensionShareRef === this.state.extensionShareRef && next.extensionShareAction === this.state.extensionShareAction && next.extensionDetailId === this.state.extensionDetailId && next.extensionAuthorFilter?.ownerUserId === this.state.extensionAuthorFilter?.ownerUserId && next.extensionAuthorFilter?.ownerName === this.state.extensionAuthorFilter?.ownerName && next.webLoginDialogOpen === this.state.webLoginDialogOpen && sameWorldTarget(next.worldTarget, this.state.worldTarget) && next.worldInitialScope === this.state.worldInitialScope && next.worldNavigationRevision === this.state.worldNavigationRevision && sameSelectedSource(next.selectedSource, this.state.selectedSource) && sameBot(next.selectedBot, this.state.selectedBot);
31383
31400
  if (sameView && next.chatRevision === this.state.chatRevision && next.recordRevision === this.state.recordRevision && next.topicDirectoryRevision === this.state.topicDirectoryRevision) return;
31384
31401
  this.state = next;
31385
31402
  if (!sameView) this.viewState = viewStateOf(next);
@@ -33917,6 +33934,12 @@ TA 公开分享的内容|Publicly shared content
33917
33934
  微信号|WeChat
33918
33935
  绑定|Connect
33919
33936
  换绑|Change
33937
+ 解/换绑|Disconnect / change
33938
+ 解绑手机号|Disconnect phone number
33939
+ 返回更换手机号|Back to changing phone number
33940
+ 确认解绑|Confirm disconnect
33941
+ 当前仅绑定了手机号,请先绑定其他登录方式|Link another sign-in method before unlinking your phone number.
33942
+ 账号状态未确认,请重新打开账号设置|Account status could not be confirmed. Reopen account settings.
33920
33943
  绑定中…|Connecting…
33921
33944
  通用|General
33922
33945
  隐私与权限|Privacy & permissions
@@ -34822,6 +34845,27 @@ Arkme 账号|Arkme account
34822
34845
  //#endregion
34823
34846
  //#region src/client/locales/actions-en.ts
34824
34847
  const actionEnglish = {
34848
+ "绑定邮箱": "Bind email",
34849
+ "请输入邮箱地址": "Enter your email address",
34850
+ "请输入有效的邮箱地址": "Enter a valid email address",
34851
+ "请输入4位邮箱验证码": "Enter the 4-digit email code",
34852
+ "验证码已发送,请查收邮箱": "Code sent. Check your inbox.",
34853
+ "邮箱已绑定,正在刷新账号信息;刷新失败时可重试。": "Email bound. Refreshing account details; you can retry if this fails.",
34854
+ "刷新账号信息": "Refresh account details",
34855
+ "邮箱绑定成功": "Email bound successfully",
34856
+ "该邮箱已绑定其他账号": "This email is already linked to another account",
34857
+ "当前账号已绑定邮箱,请刷新账号信息": "This account already has an email. Refresh account details.",
34858
+ "邮箱或验证码错误": "Incorrect email or verification code",
34859
+ "邮箱绑定响应异常,请重试": "Unexpected email binding response. Please try again.",
34860
+ "注销账号": "Delete account",
34861
+ "正在检查…": "Checking…",
34862
+ "注销方式已变化,请重新确认": "The deletion method has changed. Please confirm again.",
34863
+ "无需等待,将立即注销。注销完成后无法恢复登录。": "Your account will be deleted immediately. You cannot sign back in after deletion.",
34864
+ "账号将在 15 天等待期结束后注销,期间继续登录可撤销注销。": "Your account will be deleted after 15 days. Signing in during this period cancels the request.",
34865
+ "申请成功、剩余 5 天及剩余 1 天时,将向绑定手机号发送短信提醒。": "We will send SMS reminders when you submit the request, with 5 days left, and with 1 day left.",
34866
+ "请输入“确认注销”": "Type “确认注销” to confirm",
34867
+ "确认注销": "Confirm deletion",
34868
+ "正在处理…": "Processing…",
34825
34869
  "共同群聊": "Shared groups",
34826
34870
  "调整共同群聊宽度": "Resize shared groups",
34827
34871
  "同步尚未完成,请继续同步": "Sync is incomplete. Continue syncing.",
@@ -141957,6 +142001,117 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
141957
142001
  });
141958
142002
  }
141959
142003
  //#endregion
142004
+ //#region src/client/recordings/RecordingTranscriptText.tsx
142005
+ function RecordingTranscriptText({ text, matches, activeIndex }) {
142006
+ const characters = Array.from(text);
142007
+ let cursor = 0;
142008
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [matches.map((match) => {
142009
+ const prefix = characters.slice(cursor, match.start).join("");
142010
+ cursor = match.start + match.length;
142011
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react$1.Fragment, { children: [prefix, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
142012
+ "data-recording-match": match.index,
142013
+ style: {
142014
+ background: arkmeTheme.warningSoft,
142015
+ color: "inherit",
142016
+ outline: match.index === activeIndex ? `1px solid ${arkmeTheme.warning}` : void 0
142017
+ },
142018
+ children: characters.slice(match.start, cursor).join("")
142019
+ })] }, match.start);
142020
+ }), characters.slice(cursor).join("")] });
142021
+ }
142022
+ //#endregion
142023
+ //#region src/client/recordings/RecordingSearchRow.tsx
142024
+ function RecordingSearchRow({ item }) {
142025
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
142026
+ type: "button",
142027
+ "data-arkme-feedback": "neutral",
142028
+ onClick: () => arkmeUi.showRecordingTarget(item.dateStamp, item.startAtMillis, item.match),
142029
+ style: {
142030
+ display: "block",
142031
+ width: "100%",
142032
+ textAlign: "left",
142033
+ border: 0,
142034
+ borderBottom: `1px solid ${arkmeTheme.border}`,
142035
+ background: "transparent",
142036
+ padding: "12px 16px",
142037
+ cursor: "pointer",
142038
+ font: "inherit"
142039
+ },
142040
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("time", {
142041
+ "data-recording-search-group-time": "true",
142042
+ style: {
142043
+ display: "block",
142044
+ marginBottom: 4,
142045
+ fontSize: 12,
142046
+ color: arkmeTheme.secondary
142047
+ },
142048
+ children: [
142049
+ tr$1("录音"),
142050
+ " · ",
142051
+ new Date(item.startAtMillis).toLocaleString()
142052
+ ]
142053
+ }), [
142054
+ item.previous,
142055
+ item.match,
142056
+ item.next
142057
+ ].map((segment, index) => segment && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
142058
+ "data-recording-search-segment": segment === item.match ? "match" : "context",
142059
+ style: {
142060
+ display: "grid",
142061
+ gridTemplateColumns: "minmax(0,min(104px,32%)) minmax(0,1fr)",
142062
+ gap: 8,
142063
+ padding: "3px 0",
142064
+ color: segment === item.match ? arkmeTheme.text : arkmeTheme.secondary
142065
+ },
142066
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
142067
+ style: {
142068
+ display: "flex",
142069
+ alignItems: "flex-start",
142070
+ gap: 6,
142071
+ fontSize: 12
142072
+ },
142073
+ children: [segment.speaker?.avatarRef === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
142074
+ "aria-hidden": "true",
142075
+ style: {
142076
+ width: 10,
142077
+ height: 10,
142078
+ borderRadius: "50%",
142079
+ marginTop: 3,
142080
+ flex: "none",
142081
+ background: recordingSpeakerColor(segment.speaker?.colorIndex ?? -1)
142082
+ }
142083
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeUserAvatar, {
142084
+ avatarRef: segment.speaker.avatarRef,
142085
+ size: 16,
142086
+ label: `${segment.speaker.label}头像`
142087
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: segment.speaker?.label || tr$1("未知说话人") })]
142088
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
142089
+ style: {
142090
+ minWidth: 0,
142091
+ lineHeight: 1.5,
142092
+ ...segment === item.match ? {
142093
+ whiteSpace: "pre-wrap",
142094
+ overflowWrap: "anywhere"
142095
+ } : {
142096
+ whiteSpace: "nowrap",
142097
+ overflow: "hidden",
142098
+ textOverflow: "ellipsis"
142099
+ }
142100
+ },
142101
+ children: segment === item.match ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordingTranscriptText, {
142102
+ text: segment.text,
142103
+ matches: item.highlightRanges.map((range, index) => ({
142104
+ ...range,
142105
+ index,
142106
+ itemId: ""
142107
+ })),
142108
+ activeIndex: -1
142109
+ }) : segment.text
142110
+ })]
142111
+ }, index))]
142112
+ });
142113
+ }
142114
+ //#endregion
141960
142115
  //#region src/harness-embed-contract.ts
141961
142116
  const ARKME_HARNESS_EMBED_PATH = "/arkme-self/harness-frame";
141962
142117
  /** Same-origin bridge owned and disposed by the embedded session client. */
@@ -144234,25 +144389,6 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144234
144389
  ]
144235
144390
  });
144236
144391
  }
144237
- function RecordingRow({ item }) {
144238
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
144239
- "data-arkme-feedback": "neutral",
144240
- type: "button",
144241
- style: styles$37.row,
144242
- onClick: () => arkmeUi.showRecordingTarget(item.dateStamp, item.startAtMillis),
144243
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
144244
- style: {
144245
- ...styles$37.text,
144246
- marginTop: 0,
144247
- color: colors$9.text
144248
- },
144249
- children: item.snippet || tr$1("暂无转写内容")
144250
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
144251
- style: styles$37.meta,
144252
- children: dateTimeLabel$1(item.startAtMillis || item.dateStamp)
144253
- })]
144254
- });
144255
- }
144256
144392
  function AudioQuickRow({ item, asset, onOpen, onTagClick }) {
144257
144393
  useArkmeLocale();
144258
144394
  const initialUrl = item.voice?.mediaRef === void 0 ? displayUrl(asset) : mediaUrl(item.voice.mediaRef);
@@ -144383,6 +144519,9 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144383
144519
  const requestId = (0, react$1.useRef)(0);
144384
144520
  const quickRef = (0, react$1.useRef)();
144385
144521
  const searchAbort = (0, react$1.useRef)();
144522
+ const recordingPageAbort = (0, react$1.useRef)();
144523
+ const recordingResultQuery = (0, react$1.useRef)("");
144524
+ const [recordingPageLoading, setRecordingPageLoading] = (0, react$1.useState)(false);
144386
144525
  const sourceSearchAbort = (0, react$1.useRef)();
144387
144526
  const sourceSearchRevision = (0, react$1.useRef)(0);
144388
144527
  const quickRequestAbort = (0, react$1.useRef)();
@@ -144439,6 +144578,9 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144439
144578
  }
144440
144579
  setRequestedQuery(keyword);
144441
144580
  const id = ++requestId.current;
144581
+ recordingPageAbort.current?.abort();
144582
+ recordingPageAbort.current = void 0;
144583
+ setRecordingPageLoading(false);
144442
144584
  searchAbort.current?.abort();
144443
144585
  sourceSearchAbort.current?.abort();
144444
144586
  sourceSearchAbort.current = void 0;
@@ -144489,7 +144631,10 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144489
144631
  query: keyword,
144490
144632
  limit: 50
144491
144633
  }, controller.signal).then((nextRecordings) => {
144492
- if (active()) setRecordings(nextRecordings);
144634
+ if (active()) {
144635
+ recordingResultQuery.current = keyword;
144636
+ setRecordings(nextRecordings);
144637
+ }
144493
144638
  }).catch((caught) => {
144494
144639
  if (active()) setRecordingError(errorMessage$9(caught));
144495
144640
  }).finally(() => {
@@ -144512,6 +144657,57 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144512
144657
  callArkme("search.history.create", { query: keyword }).catch(() => void 0);
144513
144658
  setHistory((current) => [keyword, ...current.filter((value) => value !== keyword)].slice(0, 10));
144514
144659
  }, [resetResults, searchDshMessages]);
144660
+ const loadRecordingPage = (0, react$1.useCallback)(async () => {
144661
+ if (recordingPageAbort.current || query.trim() !== requestedQuery || searchLoading.recordings) return;
144662
+ const cursor = recordingResultQuery.current === requestedQuery && recordings?.hasMore ? recordings.nextCursor : void 0;
144663
+ if (recordings !== void 0 && !cursor && recordingError === "") return;
144664
+ const controller = new AbortController();
144665
+ recordingPageAbort.current = controller;
144666
+ const revision = requestId.current;
144667
+ setRecordingPageLoading(true);
144668
+ setRecordingError("");
144669
+ try {
144670
+ const page = await callArkme("search.recordings", {
144671
+ query: requestedQuery,
144672
+ limit: 50,
144673
+ ...cursor ? { cursor } : {}
144674
+ }, controller.signal);
144675
+ if (controller.signal.aborted || requestId.current !== revision) return;
144676
+ if (page.hasMore && (!page.nextCursor || page.nextCursor === cursor)) throw new Error("录音搜索分页未前进,请重试");
144677
+ recordingResultQuery.current = requestedQuery;
144678
+ setRecordings((current) => {
144679
+ if (!cursor) return page;
144680
+ const merged = new Map((current?.items ?? []).map((item) => [`${item.sessionId}:${item.match.transcriptSource}:${item.match.childId}:${item.match.itemIndex}`, item]));
144681
+ for (const item of page.items) merged.set(`${item.sessionId}:${item.match.transcriptSource}:${item.match.childId}:${item.match.itemIndex}`, item);
144682
+ return {
144683
+ ...page,
144684
+ items: [...merged.values()]
144685
+ };
144686
+ });
144687
+ } catch (caught) {
144688
+ if (!controller.signal.aborted && requestId.current === revision) setRecordingError(errorMessage$9(caught));
144689
+ } finally {
144690
+ if (recordingPageAbort.current === controller) {
144691
+ recordingPageAbort.current = void 0;
144692
+ setRecordingPageLoading(false);
144693
+ }
144694
+ }
144695
+ }, [
144696
+ query,
144697
+ requestedQuery,
144698
+ recordings,
144699
+ recordingError,
144700
+ searchLoading.recordings
144701
+ ]);
144702
+ (0, react$1.useEffect)(() => {
144703
+ recordingPageAbort.current?.abort();
144704
+ recordingPageAbort.current = void 0;
144705
+ setRecordingPageLoading(false);
144706
+ return () => {
144707
+ recordingPageAbort.current?.abort();
144708
+ recordingPageAbort.current = void 0;
144709
+ };
144710
+ }, [query, quick]);
144515
144711
  const chooseSource = (0, react$1.useCallback)(async (sourceUid, sourceKind) => {
144516
144712
  const keyword = query.trim();
144517
144713
  if (keyword === "") return;
@@ -145264,14 +145460,38 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
145264
145460
  }),
145265
145461
  recordingError !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
145266
145462
  style: styles$37.error,
145267
- children: [tr$1("录音·转写暂不可用:"), recordingError]
145463
+ role: "alert",
145464
+ children: [
145465
+ tr$1("录音·转写暂不可用:"),
145466
+ recordingError,
145467
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
145468
+ type: "button",
145469
+ "aria-label": "重试录音转写",
145470
+ style: styles$37.retryLoadMore,
145471
+ disabled: searchLoading.recordings || recordingPageLoading,
145472
+ onClick: () => {
145473
+ loadRecordingPage();
145474
+ },
145475
+ children: tr$1("重试")
145476
+ })
145477
+ ]
145268
145478
  }),
145269
145479
  recordingItems.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
145270
145480
  style: styles$37.list,
145271
- children: recordingItems.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordingRow, { item }, `${item.sessionId}:${String(item.startAtMillis)}`))
145272
- }) : !searchLoading.recordings && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Status, {
145481
+ children: recordingItems.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordingSearchRow, { item }, `${item.sessionId}:${item.match.transcriptSource}:${item.match.childId}:${item.match.itemIndex}`))
145482
+ }) : !searchLoading.recordings && recordingError === "" && !recordings?.hasMore && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Status, {
145273
145483
  loading: false,
145274
145484
  empty: true
145485
+ }),
145486
+ recordings?.hasMore && recordingError === "" && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
145487
+ type: "button",
145488
+ "aria-label": "加载更多录音转写",
145489
+ style: styles$37.retryLoadMore,
145490
+ disabled: searchLoading.recordings || recordingPageLoading,
145491
+ onClick: () => {
145492
+ loadRecordingPage();
145493
+ },
145494
+ children: recordingPageLoading ? tr$1("正在加载…") : tr$1("加载更多")
145275
145495
  })
145276
145496
  ]
145277
145497
  })
@@ -164220,6 +164440,12 @@ html body {
164220
164440
  const ARKME_LOGIN_LOCALE_NAMESPACE = "arkme.login";
164221
164441
  const arkmeLoginZh = {
164222
164442
  "locale.id": "zh",
164443
+ "cancellation.title": "账号正在注销",
164444
+ "cancellation.days": "距离账号注销还剩 {days} 天。继续使用将撤销注销申请;继续注销将退出本次登录。",
164445
+ "cancellation.cancel": "继续注销",
164446
+ "cancellation.continue": "继续使用",
164447
+ "cancellation.done": "账号已注销",
164448
+ "cancellation.waiting": "注销申请已提交",
164223
164449
  "story.aria": "即我产品定义",
164224
164450
  "story.title.first": "即我,",
164225
164451
  "story.title.second": "你的数字自我",
@@ -164308,6 +164534,12 @@ html body {
164308
164534
  };
164309
164535
  const arkmeLoginEn = {
164310
164536
  "locale.id": "en",
164537
+ "cancellation.title": "Account deletion pending",
164538
+ "cancellation.days": "Your account will be deleted in {days} days. Keep using your account to cancel deletion, or continue deletion to exit sign-in.",
164539
+ "cancellation.cancel": "Continue deletion",
164540
+ "cancellation.continue": "Keep using account",
164541
+ "cancellation.done": "Account deleted",
164542
+ "cancellation.waiting": "Account deletion requested",
164311
164543
  "story.aria": "About Arkme",
164312
164544
  "story.title.first": "Arkme,",
164313
164545
  "story.title.second": "Digital ark, true me",
@@ -164987,6 +165219,52 @@ html body {
164987
165219
  .dsh-arkme-login-definition h1 { font-size: 40px; }
164988
165220
  .dsh-arkme-login-card { max-height: calc(100vh - 48px); overflow-y: auto; padding: 8px 4px; }
164989
165221
  }
165222
+ .dsh-arkme-login-page.dsh-arkme-cancellation-page {
165223
+ display: flex;
165224
+ align-items: center;
165225
+ justify-content: center;
165226
+ padding: 32px 20px;
165227
+ overflow-y: auto;
165228
+ }
165229
+ .dsh-arkme-cancellation-page::after { display: none; }
165230
+ .dsh-arkme-cancellation-page .dsh-arkme-login-card {
165231
+ width: 440px;
165232
+ max-width: 100%;
165233
+ max-height: none;
165234
+ margin: auto;
165235
+ padding: 32px;
165236
+ border: 1px solid var(--arkme-login-border);
165237
+ border-radius: 24px;
165238
+ background: var(--arkme-login-surface);
165239
+ }
165240
+ .dsh-arkme-cancellation-page .dsh-arkme-login-title {
165241
+ margin: 0;
165242
+ text-align: center;
165243
+ font-size: 24px;
165244
+ line-height: 32px;
165245
+ }
165246
+ .dsh-arkme-cancellation-description {
165247
+ margin: 20px 0 0;
165248
+ color: var(--arkme-login-secondary);
165249
+ font-size: 14px;
165250
+ line-height: 24px;
165251
+ }
165252
+ .dsh-arkme-cancellation-page .dsh-arkme-login-actions button {
165253
+ height: 46px;
165254
+ margin: 0;
165255
+ border-radius: 12px;
165256
+ font-size: 14px;
165257
+ font-weight: 500;
165258
+ }
165259
+ .dsh-arkme-cancellation-page button:focus-visible {
165260
+ outline: 2px solid var(--arkme-login-accent);
165261
+ outline-offset: 3px;
165262
+ }
165263
+ @media (max-width: 420px) {
165264
+ .dsh-arkme-cancellation-page .dsh-arkme-login-card { padding: 24px 20px; }
165265
+ .dsh-arkme-cancellation-page .dsh-arkme-login-actions { grid-template-columns: 1fr; }
165266
+ }
165267
+
164990
165268
  `;
164991
165269
  function ArkmeLogin(props) {
164992
165270
  const t = props.t ?? defaultArkmeLoginTranslate;
@@ -165000,6 +165278,50 @@ html body {
165000
165278
  const changeTestUserId = (event) => {
165001
165279
  props.onTestUserIdChange(event.target.value.replace(/\D/g, "").slice(0, 16));
165002
165280
  };
165281
+ if (props.cancellationDays !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165282
+ className: "dsh-arkme-login-page dsh-arkme-cancellation-page",
165283
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("style", { children: loginStyles }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
165284
+ className: "dsh-arkme-login-card",
165285
+ role: "dialog",
165286
+ "aria-modal": "true",
165287
+ "aria-label": t("cancellation.title"),
165288
+ children: [
165289
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", {
165290
+ className: "dsh-arkme-login-title",
165291
+ children: t("cancellation.title")
165292
+ }),
165293
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
165294
+ className: "dsh-arkme-cancellation-description",
165295
+ children: t("cancellation.days", { days: props.cancellationDays })
165296
+ }),
165297
+ props.error && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
165298
+ className: "dsh-arkme-login-error",
165299
+ role: "alert",
165300
+ children: props.error
165301
+ }),
165302
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165303
+ className: "dsh-arkme-login-actions",
165304
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
165305
+ type: "button",
165306
+ className: "dsh-arkme-login-cancel",
165307
+ disabled: props.busy,
165308
+ onClick: () => {
165309
+ props.onResolveCancellation?.(false);
165310
+ },
165311
+ children: t("cancellation.cancel")
165312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
165313
+ type: "button",
165314
+ className: "dsh-arkme-login-submit",
165315
+ disabled: props.busy,
165316
+ onClick: () => {
165317
+ props.onResolveCancellation?.(true);
165318
+ },
165319
+ children: t("cancellation.continue")
165320
+ })]
165321
+ })
165322
+ ]
165323
+ })]
165324
+ });
165003
165325
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165004
165326
  className: "dsh-arkme-login-page",
165005
165327
  children: [
@@ -165042,6 +165364,11 @@ html body {
165042
165364
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165043
165365
  className: "dsh-arkme-login-content",
165044
165366
  children: [
165367
+ props.cancellationNotice !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
165368
+ className: "dsh-arkme-login-notice",
165369
+ role: "status",
165370
+ children: t(props.cancellationNotice === "done" ? "cancellation.done" : "cancellation.waiting")
165371
+ }) : null,
165045
165372
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165046
165373
  className: "dsh-arkme-login-brand",
165047
165374
  children: [
@@ -170609,6 +170936,20 @@ html body {
170609
170936
  });
170610
170937
  }
170611
170938
  //#endregion
170939
+ //#region src/client/recordings/recording-search-target.ts
170940
+ /** Hash the complete selector without adding raw Audio owner ids to the day document. */
170941
+ async function resolveRecordingSearchTarget(items, target) {
170942
+ const bytes = new TextEncoder().encode(JSON.stringify([
170943
+ target.sessionId,
170944
+ target.transcriptSource,
170945
+ target.childId,
170946
+ target.itemIndex
170947
+ ]));
170948
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", bytes);
170949
+ const identityHash = Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, "0")).join("");
170950
+ return items.find((item) => item.searchIdentityHash === identityHash && item.searchVersion === target.transcriptVersion && item.transcriptSource === target.transcriptSource);
170951
+ }
170952
+ //#endregion
170612
170953
  //#region node_modules/@phosphor-icons/react/dist/defs/ClockCounterClockwise.es.js
170613
170954
  const e$45 = /* @__PURE__ */ new Map([
170614
170955
  ["bold", /* @__PURE__ */ react$1.createElement(react$1.Fragment, null, /* @__PURE__ */ react$1.createElement("path", { d: "M140,80v41.21l34.17,20.5a12,12,0,1,1-12.34,20.58l-40-24A12,12,0,0,1,116,128V80a12,12,0,0,1,24,0ZM128,28A99.38,99.38,0,0,0,57.24,57.34c-4.69,4.74-9,9.37-13.24,14V64a12,12,0,0,0-24,0v40a12,12,0,0,0,12,12H72a12,12,0,0,0,0-24H57.77C63,86,68.37,80.22,74.26,74.26a76,76,0,1,1,1.58,109,12,12,0,0,0-16.48,17.46A100,100,0,1,0,128,28Z" }))],
@@ -177450,25 +177791,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
177450
177791
  return result;
177451
177792
  }
177452
177793
  //#endregion
177453
- //#region src/client/recordings/RecordingTranscriptText.tsx
177454
- function RecordingTranscriptText({ text, matches, activeIndex }) {
177455
- const characters = Array.from(text);
177456
- let cursor = 0;
177457
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [matches.map((match) => {
177458
- const prefix = characters.slice(cursor, match.start).join("");
177459
- cursor = match.start + match.length;
177460
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react$1.Fragment, { children: [prefix, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
177461
- "data-recording-match": match.index,
177462
- style: {
177463
- background: arkmeTheme.warningSoft,
177464
- color: "inherit",
177465
- outline: match.index === activeIndex ? `1px solid ${arkmeTheme.warning}` : void 0
177466
- },
177467
- children: characters.slice(match.start, cursor).join("")
177468
- })] }, match.start);
177469
- }), characters.slice(cursor).join("")] });
177470
- }
177471
- //#endregion
177472
177794
  //#region src/client/recordings/recording-transcript-comparison.ts
177473
177795
  function recordingComparisonPlaybackTarget(item, systemItems) {
177474
177796
  if (item.transcriptSource === "system") return item;
@@ -180526,9 +180848,10 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
180526
180848
  v1: Math.floor(durationSeconds % 3600 / 60)
180527
180849
  });
180528
180850
  }
180529
- function ArkmeRecordingTranscriptRow({ item, selected, onEditSpeaker, onSelect, text, selectionControl, onToggleSelection, readOnly = false }) {
180851
+ function ArkmeRecordingTranscriptRow({ item, selected, searchHighlighted = false, onEditSpeaker, onSelect, text, selectionControl, onToggleSelection, readOnly = false }) {
180530
180852
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
180531
180853
  "data-recording-transcript-item": item.itemId,
180854
+ "data-recording-search-highlight": searchHighlighted || void 0,
180532
180855
  style: {
180533
180856
  ...styles$20.transcript,
180534
180857
  ...readOnly ? {
@@ -180536,6 +180859,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
180536
180859
  contentVisibility: "visible"
180537
180860
  } : {},
180538
180861
  ...selected ? { background: colors$4.input } : {},
180862
+ ...searchHighlighted ? { background: `color-mix(in srgb, ${colors$4.base} 88%, ${colors$4.text} 12%)` } : {},
180539
180863
  ...selectionControl ? { paddingLeft: 27 } : {}
180540
180864
  },
180541
180865
  onDoubleClick: !readOnly && onToggleSelection === void 0 ? onSelect : void 0,
@@ -181389,6 +181713,42 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181389
181713
  const selectedSummary = day?.summary.items.find((version) => version.id === summaryVersionId && version.selectable);
181390
181714
  const selectedTimeline = day?.timeline.items.find((version) => version.id === timelineVersionId && version.selectable);
181391
181715
  const transcriptItems = (0, react$1.useMemo)(() => day?.transcript.state === "ready" ? day.transcript.items : [], [day?.transcript]);
181716
+ const preciseTarget = ui.recordingTarget?.segment;
181717
+ const preciseTargetDay = ui.recordingTarget !== void 0 && dateKey(new Date(ui.recordingTarget.dateStamp)) === dateKey(selectedDate);
181718
+ const [preciseResolution, setPreciseResolution] = (0, react$1.useState)();
181719
+ (0, react$1.useEffect)(() => {
181720
+ let cancelled = false;
181721
+ if (!preciseTarget || !preciseTargetDay) {
181722
+ setPreciseResolution(void 0);
181723
+ return;
181724
+ }
181725
+ resolveRecordingSearchTarget(transcriptItems, preciseTarget).then((item) => {
181726
+ if (!cancelled) setPreciseResolution({
181727
+ target: preciseTarget,
181728
+ items: transcriptItems,
181729
+ ...item ? { item } : {}
181730
+ });
181731
+ }).catch(() => {
181732
+ if (!cancelled) setPreciseResolution({
181733
+ target: preciseTarget,
181734
+ items: transcriptItems
181735
+ });
181736
+ });
181737
+ return () => {
181738
+ cancelled = true;
181739
+ };
181740
+ }, [
181741
+ preciseTarget,
181742
+ preciseTargetDay,
181743
+ transcriptItems
181744
+ ]);
181745
+ const preciseResolved = preciseResolution?.target === preciseTarget && preciseResolution?.items === transcriptItems;
181746
+ const preciseItem = preciseTargetDay && preciseResolved ? preciseResolution?.item : void 0;
181747
+ const preciseUnavailable = preciseTarget !== void 0 && preciseTargetDay && preciseResolved && !dayLoading && day !== void 0 && day.dateStamp === selectedDate.getTime() && day.transcript.state !== "processing" && preciseItem === void 0;
181748
+ (0, react$1.useEffect)(() => {
181749
+ if (preciseItem === void 0 || activeTab !== "transcript") return;
181750
+ [...transcriptRootRef.current?.querySelectorAll("[data-recording-transcript-item]") ?? []].find((element) => element.dataset.recordingTranscriptItem === preciseItem.itemId)?.scrollIntoView({ block: "center" });
181751
+ }, [preciseItem, activeTab]);
181392
181752
  const transcriptMatches = (0, react$1.useMemo)(() => findRecordingTranscriptMatches(transcriptItems, transcriptSearch), [transcriptItems, transcriptSearch]);
181393
181753
  const matchesByItem = (0, react$1.useMemo)(() => {
181394
181754
  const grouped = /* @__PURE__ */ new Map();
@@ -181553,6 +181913,10 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181553
181913
  const renderTranscript = () => {
181554
181914
  const section = day?.transcript;
181555
181915
  if (dayLoading) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeRecordingTranscriptLoading, {});
181916
+ if (preciseUnavailable) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
181917
+ role: "alert",
181918
+ children: tr$1("该转写条目已更新或不可用,请重新搜索")
181919
+ });
181556
181920
  if (section?.state === "processing") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeRecordingTranscriptLoading, {});
181557
181921
  if (section === void 0 || section.state !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionState, {
181558
181922
  section,
@@ -181578,7 +181942,8 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181578
181942
  };
181579
181943
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeRecordingTranscriptRow, {
181580
181944
  item,
181581
- selected,
181945
+ selected: preciseItem?.itemId === item.itemId || selected,
181946
+ searchHighlighted: preciseItem?.itemId === item.itemId,
181582
181947
  selectionControl: selectionMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
181583
181948
  type: "checkbox",
181584
181949
  "aria-label": `选择录音片段 ${recordingTranscriptTimeLabel(item.startAtMillis)}`,
@@ -202678,7 +203043,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
202678
203043
  const c$3 = e$24;
202679
203044
  //#endregion
202680
203045
  //#region package.json
202681
- var version = "0.1.77";
203046
+ var version = "0.1.79";
202682
203047
  //#endregion
202683
203048
  //#region src/client/profile-change-store.ts
202684
203049
  let revision = 0;
@@ -210678,6 +211043,21 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
210678
211043
  setBusy(false);
210679
211044
  }
210680
211045
  };
211046
+ const resolveCancellationLogin = async (continueLogin) => {
211047
+ if (busy) return;
211048
+ setBusy(true);
211049
+ setError("");
211050
+ try {
211051
+ const snapshot = await callArkme("auth.cancellation.login.resolve", { continueLogin });
211052
+ setQr("");
211053
+ qrRequestStartedRef.current = false;
211054
+ acceptAuthSnapshot(snapshot, { forcePhoneCheck: true });
211055
+ } catch (caught) {
211056
+ setError(arkmeLoginErrorMessage(caught, t));
211057
+ } finally {
211058
+ setBusy(false);
211059
+ }
211060
+ };
210681
211061
  const cancelBinding = async () => {
210682
211062
  setBusy(true);
210683
211063
  setError("");
@@ -210734,6 +211114,11 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
210734
211114
  error,
210735
211115
  loginProps: {
210736
211116
  t,
211117
+ ...auth?.status === "cancellation-pending" ? { cancellationDays: auth.restDaysCancel ?? 15 } : {},
211118
+ ...auth?.cancellationNotice === void 0 ? {} : { cancellationNotice: auth.cancellationNotice },
211119
+ onResolveCancellation: (continueLogin) => {
211120
+ resolveCancellationLogin(continueLogin);
211121
+ },
210737
211122
  mode: loginMode,
210738
211123
  phoneBindingRequired,
210739
211124
  agreed,
@@ -227410,12 +227795,63 @@ button.arkme-account-info-row {
227410
227795
  gap: 16px;
227411
227796
  }
227412
227797
 
227413
- [data-arkme-settings-view="account"] .arkme-account-info-copy > small {
227798
+ [data-arkme-settings-view="account"] .arkme-account-info-copy > small, [data-arkme-settings-view="account"] .arkme-account-info-action {
227414
227799
  text-align: right;
227415
227800
  }
227416
227801
 
227417
- [data-arkme-settings-view="account"] .arkme-account-info-action {
227418
- text-align: center;
227802
+ .arkme-account-info-value {
227803
+ justify-content: flex-end;
227804
+ align-items: center;
227805
+ gap: 10px;
227806
+ min-width: 0;
227807
+ display: flex;
227808
+ }
227809
+
227810
+ .arkme-account-info-value > small {
227811
+ color: #858992;
227812
+ white-space: nowrap;
227813
+ text-overflow: ellipsis;
227814
+ font-size: 12px;
227815
+ line-height: 18px;
227816
+ overflow: hidden;
227817
+ }
227818
+
227819
+ .arkme-account-info-edit {
227820
+ grid-column: 3 / 5;
227821
+ grid-template-columns: subgrid;
227822
+ color: #8d929b;
227823
+ min-height: 36px;
227824
+ font: inherit;
227825
+ cursor: pointer;
227826
+ background: none;
227827
+ border: 0;
227828
+ align-items: center;
227829
+ gap: 10px;
227830
+ padding: 0;
227831
+ display: grid;
227832
+ }
227833
+
227834
+ .arkme-account-info-edit:disabled {
227835
+ opacity: .6;
227836
+ cursor: default;
227837
+ }
227838
+
227839
+ .arkme-account-info-edit:focus-visible, .arkme-account-profile-qr:focus-visible {
227840
+ outline-offset: 2px;
227841
+ border-radius: 4px;
227842
+ outline: 2px solid;
227843
+ }
227844
+
227845
+ [data-arkme-settings-view="account"] .arkme-account-info-row.is-status-only .arkme-account-info-copy {
227846
+ grid-column: 2 / 4;
227847
+ }
227848
+
227849
+ [data-arkme-settings-view="account"] .arkme-account-info-row.is-status-only .arkme-account-info-action {
227850
+ display: none;
227851
+ }
227852
+
227853
+ body[data-ds-dark-theme] .arkme-account-info-value > small, body[data-ds-dark-theme] .arkme-account-info-edit {
227854
+ color: var(--dsw-alias-label-secondary, #969ba5);
227419
227855
  }
227420
227856
 
227421
227857
  [data-arkme-settings-view="account"] .arkme-redesign-settings-group:has(.arkme-redesign-balance-row) {
@@ -227430,7 +227866,9 @@ button.arkme-account-info-row {
227430
227866
  }
227431
227867
 
227432
227868
  .arkme-account-logout {
227433
- justify-content: center;
227869
+ flex-direction: column;
227870
+ align-items: center;
227871
+ gap: 12px;
227434
227872
  padding-top: 32px;
227435
227873
  display: flex;
227436
227874
  }
@@ -227447,6 +227885,13 @@ button.arkme-account-info-row {
227447
227885
  padding: 8px 24px;
227448
227886
  }
227449
227887
 
227888
+ .arkme-account-logout > .arkme-account-logout-confirm {
227889
+ color: #fff;
227890
+ background-color: #dc4d43;
227891
+ border-color: #dc4d43;
227892
+ font-weight: 700;
227893
+ }
227894
+
227450
227895
  .arkme-account-logout > button:disabled {
227451
227896
  cursor: default;
227452
227897
  opacity: .6;
@@ -227802,6 +228247,21 @@ button.arkme-account-info-row {
227802
228247
  cursor: default;
227803
228248
  }
227804
228249
 
228250
+ .arkme-account-dialog-actions button.arkme-phone-mode-action, body[data-ds-dark-theme] .arkme-account-dialog-actions button.arkme-phone-mode-action {
228251
+ min-width: 0;
228252
+ color: var(--dsw-alias-label-tertiary, #858992);
228253
+ background: none;
228254
+ border: 0;
228255
+ margin-right: auto;
228256
+ padding: 0;
228257
+ font-size: 12px;
228258
+ }
228259
+
228260
+ .arkme-account-dialog-actions button.arkme-phone-mode-action:hover:not(:disabled) {
228261
+ color: var(--dsw-alias-label-primary, #343944);
228262
+ text-decoration: underline;
228263
+ }
228264
+
227805
228265
  .arkme-account-dialog-status {
227806
228266
  color: #13a85b;
227807
228267
  margin: 0;
@@ -231633,6 +232093,54 @@ body[data-ds-dark-theme] .arkme-peer-membership-disc {
231633
232093
  outline: 2px solid var(--dsw-alias-label-secondary, #68707c);
231634
232094
  outline-offset: 2px;
231635
232095
  }
232096
+
232097
+ .arkme-cancellation-form {
232098
+ gap: 18px;
232099
+ font-size: 14px;
232100
+ line-height: 1.6;
232101
+ }
232102
+
232103
+ .arkme-cancellation-description {
232104
+ overflow-wrap: anywhere;
232105
+ margin: 0;
232106
+ }
232107
+
232108
+ .arkme-cancellation-form .arkme-account-rule {
232109
+ font-size: 13px;
232110
+ line-height: 1.6;
232111
+ }
232112
+
232113
+ .arkme-cancellation-form label {
232114
+ font-size: 13px;
232115
+ }
232116
+
232117
+ .arkme-cancellation-form input {
232118
+ font-size: 14px;
232119
+ }
232120
+
232121
+ .arkme-cancellation-form .arkme-account-dialog-actions {
232122
+ flex-wrap: wrap;
232123
+ }
232124
+
232125
+ .arkme-cancellation-dialog .arkme-account-dialog-actions .arkme-cancellation-confirm, body[data-ds-dark-theme] .arkme-cancellation-dialog .arkme-account-dialog-actions .arkme-cancellation-confirm {
232126
+ color: #fff;
232127
+ background: #b54841;
232128
+ border-color: #b54841;
232129
+ }
232130
+
232131
+ .arkme-cancellation-dialog .arkme-cancellation-confirm:hover:not(:disabled) {
232132
+ filter: brightness(.92);
232133
+ }
232134
+
232135
+ .arkme-cancellation-dialog button:focus-visible {
232136
+ outline-offset: 2px;
232137
+ outline: 2px solid #9aa7c2;
232138
+ }
232139
+
232140
+ .arkme-cancellation-dialog > header button:disabled {
232141
+ opacity: .55;
232142
+ cursor: default;
232143
+ }
231636
232144
  \nbody:has([data-arkme-owned="product-navigation"]) {
231637
232145
  --arkme-control-hover-surface: #f1f2f6;
231638
232146
  }
@@ -233605,10 +234113,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
233605
234113
  min-width: 0;
233606
234114
  }
233607
234115
 
233608
- [data-arkme-settings-view="account"] .arkme-account-info-row {
233609
- grid-template-columns: 26px minmax(0, 1fr) auto 18px;
233610
- }
233611
-
233612
234116
  .arkme-profile-edit-value {
233613
234117
  align-items: center;
233614
234118
  gap: 12px;
@@ -233937,6 +234441,136 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
233937
234441
  }
233938
234442
  bindPrivateChatActionsAuth(arkmeAuthStore, privateChatActions);
233939
234443
  //#endregion
234444
+ //#region src/client/ArkmeAccountCancellation.tsx
234445
+ function ArkmeAccountCancellation({ userId, disabled, onBusyChange, onComplete }) {
234446
+ const [preview, setPreview] = (0, react$1.useState)();
234447
+ const [confirmation, setConfirmation] = (0, react$1.useState)("");
234448
+ const [busy, setBusy] = (0, react$1.useState)(false);
234449
+ const [error, setError] = (0, react$1.useState)("");
234450
+ const busyRef = (0, react$1.useRef)(false);
234451
+ const generation = (0, react$1.useRef)(0);
234452
+ (0, react$1.useEffect)(() => () => {
234453
+ generation.current += 1;
234454
+ }, []);
234455
+ const run = async (submit) => {
234456
+ if (busyRef.current || disabled || submit && confirmation !== "确认注销") return;
234457
+ const current = generation.current;
234458
+ busyRef.current = true;
234459
+ setBusy(true);
234460
+ onBusyChange(true);
234461
+ setError("");
234462
+ try {
234463
+ const result = submit ? await callArkme("auth.cancellation.submit", {
234464
+ expectedUserId: userId,
234465
+ expectedMode: preview.mode
234466
+ }) : await callArkme("auth.cancellation.preview", { expectedUserId: userId });
234467
+ if (generation.current !== current) return;
234468
+ if (submit && (result.status === "done" || result.status === "waiting")) onComplete(result);
234469
+ else {
234470
+ setPreview(result);
234471
+ setConfirmation("");
234472
+ if (result.changed) setError(tr$1("注销方式已变化,请重新确认"));
234473
+ }
234474
+ } catch (caught) {
234475
+ if (generation.current === current) setError(caught instanceof Error ? caught.message : String(caught));
234476
+ } finally {
234477
+ busyRef.current = false;
234478
+ if (generation.current === current) {
234479
+ setBusy(false);
234480
+ onBusyChange(false);
234481
+ }
234482
+ }
234483
+ };
234484
+ const close = () => {
234485
+ if (!busyRef.current) {
234486
+ setPreview(void 0);
234487
+ setError("");
234488
+ setConfirmation("");
234489
+ }
234490
+ };
234491
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
234492
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
234493
+ "data-arkme-feedback": "danger",
234494
+ type: "button",
234495
+ disabled: disabled || busy,
234496
+ onClick: () => {
234497
+ run(false);
234498
+ },
234499
+ children: busy && preview === void 0 ? tr$1("正在检查…") : tr$1("注销账号")
234500
+ }),
234501
+ error && preview === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
234502
+ className: "arkme-account-dialog-status is-error",
234503
+ role: "alert",
234504
+ children: error
234505
+ }) : null,
234506
+ preview !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
234507
+ className: "arkme-account-dialog-backdrop",
234508
+ role: "presentation",
234509
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("section", {
234510
+ className: "arkme-account-dialog arkme-cancellation-dialog",
234511
+ role: "dialog",
234512
+ "aria-modal": "true",
234513
+ "aria-label": tr$1("注销账号"),
234514
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("header", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("h3", { children: tr$1("注销账号") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
234515
+ type: "button",
234516
+ "data-arkme-feedback": "neutral",
234517
+ "aria-label": tr$1("关闭"),
234518
+ disabled: busy,
234519
+ onClick: close,
234520
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(n$13, {
234521
+ size: 20,
234522
+ "aria-hidden": true
234523
+ })
234524
+ })] }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
234525
+ className: "arkme-account-form arkme-cancellation-form",
234526
+ onSubmit: (event) => {
234527
+ event.preventDefault();
234528
+ run(true);
234529
+ },
234530
+ children: [
234531
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
234532
+ className: "arkme-cancellation-description",
234533
+ children: tr$1(preview.mode === "immediate" ? "无需等待,将立即注销。注销完成后无法恢复登录。" : "账号将在 15 天等待期结束后注销,期间继续登录可撤销注销。")
234534
+ }),
234535
+ preview.mode === "waiting" && preview.has_phone ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
234536
+ className: "arkme-account-rule",
234537
+ children: tr$1("申请成功、剩余 5 天及剩余 1 天时,将向绑定手机号发送短信提醒。")
234538
+ }) : null,
234539
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [tr$1("请输入“确认注销”"), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
234540
+ autoFocus: true,
234541
+ value: confirmation,
234542
+ disabled: busy,
234543
+ onChange: (event) => {
234544
+ setConfirmation(event.target.value);
234545
+ }
234546
+ })] }),
234547
+ error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
234548
+ className: "arkme-account-dialog-status is-error",
234549
+ role: "alert",
234550
+ children: error
234551
+ }) : null,
234552
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("footer", {
234553
+ className: "arkme-account-dialog-actions",
234554
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
234555
+ type: "button",
234556
+ disabled: busy,
234557
+ onClick: close,
234558
+ children: tr$1("取消")
234559
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
234560
+ className: "arkme-cancellation-confirm",
234561
+ type: "submit",
234562
+ "data-arkme-feedback": "danger",
234563
+ disabled: busy || confirmation !== "确认注销",
234564
+ children: tr$1(busy ? "正在处理…" : "确认注销")
234565
+ })]
234566
+ })
234567
+ ]
234568
+ })]
234569
+ })
234570
+ }) : null
234571
+ ] });
234572
+ }
234573
+ //#endregion
233940
234574
  //#region src/client/ArkmeScreenshotShortcutSetting.tsx
233941
234575
  function ArkmeScreenshotShortcutSetting() {
233942
234576
  useArkmeLocale();
@@ -234860,40 +235494,51 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
234860
235494
  children: [title !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children })]
234861
235495
  });
234862
235496
  }
234863
- function AccountInfoRow({ icon, title, value, action, disabled = false, onClick }) {
234864
- const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
234865
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234866
- className: "arkme-account-info-icon",
234867
- "aria-hidden": true,
234868
- children: icon
234869
- }),
234870
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
234871
- className: "arkme-account-info-copy",
234872
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: value })]
234873
- }),
234874
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234875
- className: "arkme-account-info-action",
234876
- children: action
234877
- }),
234878
- onClick === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234879
- className: "arkme-redesign-trailing-slot",
234880
- "aria-hidden": true
234881
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$20, {
234882
- size: 15,
234883
- "aria-hidden": true
234884
- })
234885
- ] });
234886
- if (onClick === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
234887
- className: "arkme-account-info-row",
234888
- children: content
235497
+ function AccountInfoRow({ icon, title, value, action, valueAccessory, disabled = false, onClick }) {
235498
+ const copy = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
235499
+ className: "arkme-account-info-icon",
235500
+ "aria-hidden": true,
235501
+ children: icon
235502
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
235503
+ className: "arkme-account-info-copy",
235504
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: title }), valueAccessory === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: value }) : /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
235505
+ className: "arkme-account-info-value",
235506
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: value }), valueAccessory]
235507
+ })]
235508
+ })] });
235509
+ const trailing = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
235510
+ className: "arkme-account-info-action",
235511
+ children: action
235512
+ }), onClick === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
235513
+ className: "arkme-redesign-trailing-slot",
235514
+ "aria-hidden": true
235515
+ }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$20, {
235516
+ size: 15,
235517
+ "aria-hidden": true
235518
+ })] });
235519
+ const className = `arkme-account-info-row${action === void 0 ? " is-status-only" : ""}`;
235520
+ if (valueAccessory !== void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235521
+ className,
235522
+ children: [copy, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235523
+ "data-arkme-feedback": "neutral",
235524
+ type: "button",
235525
+ className: "arkme-account-info-edit",
235526
+ disabled: disabled || onClick === void 0,
235527
+ onClick,
235528
+ children: trailing
235529
+ })]
234889
235530
  });
234890
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235531
+ if (onClick === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235532
+ className,
235533
+ children: [copy, trailing]
235534
+ });
235535
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
234891
235536
  "data-arkme-feedback": "neutral",
234892
235537
  type: "button",
234893
- className: "arkme-account-info-row",
235538
+ className,
234894
235539
  disabled,
234895
235540
  onClick,
234896
- children: content
235541
+ children: [copy, trailing]
234897
235542
  });
234898
235543
  }
234899
235544
  function WechatBindingSettingsRow({ bound, nickname, onBind, busy = false }) {
@@ -235196,16 +235841,172 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235196
235841
  })
235197
235842
  });
235198
235843
  }
235844
+ function EmailBindDialog({ profile, onClose, onUpdated }) {
235845
+ useArkmeLocale();
235846
+ const [email, setEmail] = (0, react$1.useState)("");
235847
+ const [code, setCode] = (0, react$1.useState)("");
235848
+ const [busy, setBusy] = (0, react$1.useState)(false);
235849
+ const [bound, setBound] = (0, react$1.useState)(false);
235850
+ const [status, setStatus] = (0, react$1.useState)("");
235851
+ const [failed, setFailed] = (0, react$1.useState)(false);
235852
+ const [countdown, setCountdown] = (0, react$1.useState)(0);
235853
+ const busyRef = (0, react$1.useRef)(false);
235854
+ const mounted = (0, react$1.useRef)(true);
235855
+ (0, react$1.useEffect)(() => {
235856
+ mounted.current = true;
235857
+ return () => {
235858
+ mounted.current = false;
235859
+ };
235860
+ }, []);
235861
+ (0, react$1.useEffect)(() => {
235862
+ if (countdown <= 0) return;
235863
+ const timer = window.setTimeout(() => {
235864
+ setCountdown((value) => value - 1);
235865
+ }, 1e3);
235866
+ return () => {
235867
+ window.clearTimeout(timer);
235868
+ };
235869
+ }, [countdown]);
235870
+ const valid = email.trim().length <= 254 && /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email.trim());
235871
+ const run = async (sending) => {
235872
+ if (busyRef.current || sending && (countdown > 0 || bound) || !bound && (!valid || !sending && !/^[0-9]{4}$/.test(code))) return;
235873
+ busyRef.current = true;
235874
+ setBusy(true);
235875
+ setStatus("");
235876
+ setFailed(false);
235877
+ try {
235878
+ if (sending) {
235879
+ await callArkme("auth.email.send", {
235880
+ expectedUserId: profile.userId,
235881
+ email: email.trim()
235882
+ });
235883
+ if (!mounted.current) return;
235884
+ setCountdown(60);
235885
+ setStatus("验证码已发送,请查收邮箱");
235886
+ } else {
235887
+ if (!bound) {
235888
+ await callArkme("auth.email.bind", {
235889
+ expectedUserId: profile.userId,
235890
+ email: email.trim(),
235891
+ code
235892
+ });
235893
+ if (!mounted.current) return;
235894
+ setBound(true);
235895
+ }
235896
+ const snapshot = await callArkme("user.profile.refresh");
235897
+ if (!mounted.current) return;
235898
+ if (snapshot.profile?.userId !== profile.userId) throw new Error("账号已切换,请重新打开账号设置");
235899
+ onUpdated(snapshot);
235900
+ onClose();
235901
+ }
235902
+ } catch (error) {
235903
+ if (mounted.current) {
235904
+ setFailed(true);
235905
+ setStatus(error instanceof Error ? error.message : String(error));
235906
+ }
235907
+ } finally {
235908
+ busyRef.current = false;
235909
+ if (mounted.current) setBusy(false);
235910
+ }
235911
+ };
235912
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsDialog, {
235913
+ title: tr$1("绑定邮箱"),
235914
+ onClose: () => {
235915
+ if (!busyRef.current) onClose();
235916
+ },
235917
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
235918
+ className: "arkme-account-form",
235919
+ onSubmit: (event) => {
235920
+ event.preventDefault();
235921
+ run(false);
235922
+ },
235923
+ children: [
235924
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tr$1("邮箱") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
235925
+ autoFocus: true,
235926
+ type: "email",
235927
+ autoComplete: "email",
235928
+ value: email,
235929
+ disabled: busy || bound,
235930
+ placeholder: tr$1("请输入邮箱地址"),
235931
+ onChange: (event) => {
235932
+ setEmail(event.target.value);
235933
+ setCode("");
235934
+ setStatus("");
235935
+ }
235936
+ })] }),
235937
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tr$1("验证码") }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
235938
+ className: "arkme-account-code-row",
235939
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
235940
+ inputMode: "numeric",
235941
+ autoComplete: "one-time-code",
235942
+ maxLength: 4,
235943
+ value: code,
235944
+ disabled: busy || bound,
235945
+ placeholder: tr$1("请输入4位邮箱验证码"),
235946
+ onChange: (event) => {
235947
+ setCode(event.target.value.replace(/\D/g, "").slice(0, 4));
235948
+ }
235949
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235950
+ "data-arkme-feedback": "neutral",
235951
+ type: "button",
235952
+ disabled: busy || bound || !valid || countdown > 0,
235953
+ onClick: () => {
235954
+ run(true);
235955
+ },
235956
+ children: countdown > 0 ? `${countdown}s` : tr$1("发送验证码")
235957
+ })]
235958
+ })] }),
235959
+ bound && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
235960
+ className: "arkme-account-rule",
235961
+ children: tr$1("邮箱已绑定,正在刷新账号信息;刷新失败时可重试。")
235962
+ }),
235963
+ status && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
235964
+ className: `arkme-account-dialog-status${failed ? " is-error" : ""}`,
235965
+ role: failed ? "alert" : "status",
235966
+ children: tr$1(status)
235967
+ }),
235968
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235969
+ className: "arkme-account-dialog-actions",
235970
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235971
+ "data-arkme-feedback": "neutral",
235972
+ type: "button",
235973
+ disabled: busy,
235974
+ onClick: onClose,
235975
+ children: tr$1("取消")
235976
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
235977
+ "data-arkme-feedback": "primary",
235978
+ type: "submit",
235979
+ disabled: busy || !bound && (!valid || !/^[0-9]{4}$/.test(code)),
235980
+ children: [busy && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$14, {
235981
+ className: "arkme-icon-spin",
235982
+ size: 16,
235983
+ "aria-hidden": true
235984
+ }), tr$1(bound ? "刷新账号信息" : "绑 定")]
235985
+ })]
235986
+ })
235987
+ ]
235988
+ })
235989
+ });
235990
+ }
235199
235991
  function PhoneBindDialog({ config, profile, onClose, onUpdated }) {
235992
+ const [unbind, setUnbind] = (0, react$1.useState)(false);
235993
+ const busyRef = (0, react$1.useRef)(false);
235994
+ const mountedRef = (0, react$1.useRef)(true);
235995
+ (0, react$1.useEffect)(() => {
235996
+ mountedRef.current = true;
235997
+ return () => {
235998
+ mountedRef.current = false;
235999
+ };
236000
+ }, []);
235200
236001
  useArkmeLocale();
235201
236002
  const [phone, setPhone] = (0, react$1.useState)("");
235202
236003
  const [code, setCode] = (0, react$1.useState)("");
235203
236004
  const [phoneBusy, setPhoneBusy] = (0, react$1.useState)(false);
235204
236005
  const [status, setStatus] = (0, react$1.useState)("");
235205
236006
  const [countdown, setCountdown] = (0, react$1.useState)(0);
235206
- const phoneValid = /^1[3-9][0-9]{9}$/.test(phone.replace(/[\s-]/g, ""));
236007
+ const phoneValid = unbind || /^1[3-9][0-9]{9}$/.test(phone.replace(/[\s-]/g, ""));
235207
236008
  const codeValid = /^[0-9]{6}$/.test(code.trim());
235208
- const actionLabel = profile.contact.phoneMasked === void 0 ? "绑定手机号" : "更换手机号";
236009
+ const actionLabel = tr$1(unbind ? "解绑手机号" : profile.contact.phoneMasked === void 0 ? "绑定手机号" : "更换手机号");
235209
236010
  (0, react$1.useEffect)(() => {
235210
236011
  if (countdown <= 0) return;
235211
236012
  const timer = window.setTimeout(() => {
@@ -235215,52 +236016,99 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235215
236016
  window.clearTimeout(timer);
235216
236017
  };
235217
236018
  }, [countdown]);
236019
+ const changePhoneMode = async () => {
236020
+ if (busyRef.current) return;
236021
+ if (unbind) {
236022
+ setUnbind(false);
236023
+ setCode("");
236024
+ setStatus("");
236025
+ setCountdown(0);
236026
+ return;
236027
+ }
236028
+ busyRef.current = true;
236029
+ setPhoneBusy(true);
236030
+ setStatus("");
236031
+ try {
236032
+ const result = await callArkme("auth.phone.unbind.check", { expectedUserId: profile.userId });
236033
+ if (!mountedRef.current) return;
236034
+ if (result.allowed !== true) {
236035
+ setStatus(result.allowed === false ? tr$1("当前仅绑定了手机号,请先绑定其他登录方式") : tr$1("账号状态未确认,请重新打开账号设置"));
236036
+ return;
236037
+ }
236038
+ setUnbind(true);
236039
+ setCode("");
236040
+ setCountdown(0);
236041
+ } catch (caught) {
236042
+ if (mountedRef.current) setStatus(caught instanceof Error ? caught.message : String(caught));
236043
+ } finally {
236044
+ busyRef.current = false;
236045
+ if (mountedRef.current) setPhoneBusy(false);
236046
+ }
236047
+ };
235218
236048
  const sendCode = async () => {
236049
+ if (busyRef.current || countdown > 0) return;
235219
236050
  if (!phoneValid) {
235220
236051
  setStatus("请输入正确的手机号");
235221
236052
  return;
235222
236053
  }
236054
+ busyRef.current = true;
235223
236055
  setPhoneBusy(true);
235224
236056
  setStatus("");
235225
236057
  try {
235226
236058
  const captcha = await verifyPhoneCaptcha(config?.captchaId ?? "", phone);
235227
- await callArkme("auth.phone.send", {
236059
+ await callArkme(unbind ? "auth.phone.unbind.send" : "auth.phone.send", unbind ? { captcha } : {
235228
236060
  phone,
235229
236061
  captcha
235230
236062
  });
236063
+ if (!mountedRef.current) return;
235231
236064
  setCountdown(60);
235232
236065
  setStatus("已发送验证码");
235233
236066
  } catch (caught) {
236067
+ if (!mountedRef.current) return;
235234
236068
  setStatus(caught instanceof Error ? caught.message : String(caught));
235235
236069
  } finally {
235236
- setPhoneBusy(false);
236070
+ busyRef.current = false;
236071
+ if (mountedRef.current) setPhoneBusy(false);
235237
236072
  }
235238
236073
  };
235239
236074
  const verify = async (event) => {
235240
236075
  event.preventDefault();
236076
+ if (busyRef.current) return;
235241
236077
  if (!phoneValid || !codeValid) {
235242
236078
  setStatus("请输入正确的手机号和验证码");
235243
236079
  return;
235244
236080
  }
236081
+ busyRef.current = true;
235245
236082
  setPhoneBusy(true);
235246
236083
  setStatus("");
235247
236084
  try {
235248
- const auth = await callArkme("auth.phone.verify", {
236085
+ const auth = await callArkme(unbind ? "auth.phone.unbind" : "auth.phone.verify", unbind ? { code } : {
235249
236086
  phone,
235250
236087
  code
235251
236088
  });
236089
+ if (!mountedRef.current) return;
235252
236090
  arkmeAuthStore.setAuth(auth);
235253
- onUpdated(await callArkme("user.profile.refresh"), auth);
236091
+ if (unbind && auth.status === "binding-required") {
236092
+ onClose();
236093
+ return;
236094
+ }
236095
+ const snapshot = await callArkme("user.profile.refresh");
236096
+ if (!mountedRef.current) return;
236097
+ onUpdated(snapshot, auth);
235254
236098
  onClose();
235255
236099
  } catch (caught) {
236100
+ if (!mountedRef.current) return;
235256
236101
  setStatus(caught instanceof Error ? caught.message : String(caught));
235257
236102
  } finally {
235258
- setPhoneBusy(false);
236103
+ busyRef.current = false;
236104
+ if (mountedRef.current) setPhoneBusy(false);
235259
236105
  }
235260
236106
  };
235261
236107
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SettingsDialog, {
235262
236108
  title: actionLabel,
235263
- onClose,
236109
+ onClose: () => {
236110
+ if (!busyRef.current) onClose();
236111
+ },
235264
236112
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("form", {
235265
236113
  className: "arkme-account-form",
235266
236114
  onSubmit: (event) => {
@@ -235275,7 +236123,7 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235275
236123
  profile.contact.phoneMasked
235276
236124
  ]
235277
236125
  }) : null,
235278
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tr$1("手机号") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
236126
+ !unbind && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("label", { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { children: tr$1("手机号") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
235279
236127
  value: phone,
235280
236128
  autoFocus: true,
235281
236129
  inputMode: "tel",
@@ -235311,21 +236159,35 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235311
236159
  }) : null,
235312
236160
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235313
236161
  className: "arkme-account-dialog-actions",
235314
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235315
- "data-arkme-feedback": "neutral",
235316
- type: "button",
235317
- onClick: onClose,
235318
- children: tr$1("取消")
235319
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
235320
- "data-arkme-feedback": "primary",
235321
- type: "submit",
235322
- disabled: phoneBusy || !phoneValid || !codeValid,
235323
- children: [phoneBusy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$14, {
235324
- className: "arkme-icon-spin",
235325
- size: 16,
235326
- "aria-hidden": true
235327
- }) : null, profile.contact.phoneMasked === void 0 ? tr$1("绑 定") : tr$1("更 换")]
235328
- })]
236162
+ children: [
236163
+ profile.contact.phoneMasked !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236164
+ "data-arkme-feedback": "neutral",
236165
+ className: "arkme-phone-mode-action",
236166
+ type: "button",
236167
+ disabled: phoneBusy,
236168
+ onClick: () => {
236169
+ changePhoneMode();
236170
+ },
236171
+ children: tr$1(unbind ? "返回更换手机号" : "解绑手机号")
236172
+ }),
236173
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236174
+ "data-arkme-feedback": "neutral",
236175
+ type: "button",
236176
+ disabled: phoneBusy,
236177
+ onClick: onClose,
236178
+ children: tr$1("取消")
236179
+ }),
236180
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
236181
+ "data-arkme-feedback": "primary",
236182
+ type: "submit",
236183
+ disabled: phoneBusy || !phoneValid || !codeValid,
236184
+ children: [phoneBusy ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$14, {
236185
+ className: "arkme-icon-spin",
236186
+ size: 16,
236187
+ "aria-hidden": true
236188
+ }) : null, tr$1(unbind ? "确认解绑" : profile.contact.phoneMasked === void 0 ? "绑 定" : "更 换")]
236189
+ })
236190
+ ]
235329
236191
  })
235330
236192
  ]
235331
236193
  })
@@ -235384,9 +236246,11 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235384
236246
  const [profile, setProfile] = (0, react$1.useState)();
235385
236247
  const [clientConfig, setClientConfig] = (0, react$1.useState)();
235386
236248
  const [logoutBusy, setLogoutBusy] = (0, react$1.useState)(false);
236249
+ const [cancellationBusy, setCancellationBusy] = (0, react$1.useState)(false);
235387
236250
  const [notificationBusy, setNotificationBusy] = (0, react$1.useState)(false);
235388
236251
  const [error, setError] = (0, react$1.useState)("");
235389
236252
  const [accountFeedback, setAccountFeedback] = (0, react$1.useState)("");
236253
+ const [emailBoundToast, setEmailBoundToast] = (0, react$1.useState)(false);
235390
236254
  const [activeAccountDialog, setActiveAccountDialog] = (0, react$1.useState)(null);
235391
236255
  const notificationPermission = (0, react$1.useSyncExternalStore)(arkmeDesktopNotifications.subscribePermission, arkmeDesktopNotifications.getPermissionSnapshot, arkmeDesktopNotifications.getPermissionSnapshot).permission;
235392
236256
  const [backgroundSoundBusy, setBackgroundSoundBusy] = (0, react$1.useState)(false);
@@ -235668,19 +236532,10 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235668
236532
  authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsGroup, {
235669
236533
  title: tr$1("账号信息"),
235670
236534
  children: [
235671
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235672
- className: "arkme-account-id-with-qr",
235673
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235674
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(d, { size: 18 }),
235675
- title: tr$1("即我号"),
235676
- value: currentArkmeId === "" ? tr$1("暂未获取到即我号") : currentArkmeId,
235677
- action: tr$1(profile?.canUpdateArkmeId === false ? "不可修改" : "修改"),
235678
- disabled: profile === void 0 || profile.canUpdateArkmeId === false,
235679
- onClick: profile !== void 0 && profile.canUpdateArkmeId !== false ? () => {
235680
- setActiveAccountDialog("arkme-id");
235681
- setAccountFeedback("");
235682
- } : void 0
235683
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236535
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
236536
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(d, { size: 18 }),
236537
+ title: tr$1("即我号"),
236538
+ valueAccessory: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
235684
236539
  type: "button",
235685
236540
  className: "arkme-account-profile-qr",
235686
236541
  "aria-label": tr$1("查看我的二维码"),
@@ -235689,13 +236544,20 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235689
236544
  setActiveAccountDialog("qr");
235690
236545
  },
235691
236546
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorldShareQrIcon, {})
235692
- })]
236547
+ }),
236548
+ value: currentArkmeId === "" ? tr$1("暂未获取到即我号") : currentArkmeId,
236549
+ action: tr$1(profile?.canUpdateArkmeId === false ? "不可修改" : "修改"),
236550
+ disabled: profile === void 0 || profile.canUpdateArkmeId === false,
236551
+ onClick: profile !== void 0 && profile.canUpdateArkmeId !== false ? () => {
236552
+ setActiveAccountDialog("arkme-id");
236553
+ setAccountFeedback("");
236554
+ } : void 0
235693
236555
  }),
235694
236556
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235695
236557
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$8, { size: 18 }),
235696
236558
  title: tr$1("手机号"),
235697
236559
  value: phoneMasked ?? tr$1("未绑定"),
235698
- action: tr$1(phoneMasked === void 0 ? "绑定" : "换绑"),
236560
+ action: tr$1(phoneMasked === void 0 ? "绑定" : "解/换绑"),
235699
236561
  disabled: profile === void 0,
235700
236562
  onClick: profile !== void 0 ? () => {
235701
236563
  setActiveAccountDialog("phone");
@@ -235721,10 +236583,18 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235721
236583
  title: tr$1("华为 ID"),
235722
236584
  value: tr$1("已绑定")
235723
236585
  }),
235724
- profile?.contact.emailMasked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
236586
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235725
236587
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(i, { size: 18 }),
235726
236588
  title: tr$1("邮箱"),
235727
- value: profile.contact.emailMasked
236589
+ value: profile?.contact.emailMasked || "",
236590
+ ...!profile?.contact.emailMasked ? {
236591
+ action: tr$1("绑定"),
236592
+ disabled: profile === void 0,
236593
+ onClick: () => {
236594
+ setActiveAccountDialog("email");
236595
+ setAccountFeedback("");
236596
+ }
236597
+ } : {}
235728
236598
  }),
235729
236599
  accountFeedback !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
235730
236600
  className: "arkme-account-feedback",
@@ -235736,17 +236606,31 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235736
236606
  }) : null
235737
236607
  ]
235738
236608
  }),
235739
- authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
236609
+ authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235740
236610
  className: "arkme-account-logout",
235741
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236611
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236612
+ className: "arkme-account-logout-confirm",
235742
236613
  "data-arkme-feedback": "danger",
235743
236614
  type: "button",
235744
- disabled: logoutBusy,
236615
+ disabled: logoutBusy || cancellationBusy,
235745
236616
  onClick: () => {
235746
236617
  logout();
235747
236618
  },
235748
236619
  children: logoutBusy ? tr$1("正在退出…") : tr$1("退出登录")
235749
- })
236620
+ }), authenticatedUserId !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeAccountCancellation, {
236621
+ userId: authenticatedUserId,
236622
+ disabled: logoutBusy,
236623
+ onBusyChange: setCancellationBusy,
236624
+ onComplete: (result) => {
236625
+ arkmeAuthStore.setAuth({
236626
+ status: "logged-out",
236627
+ environment: authState.auth.environment,
236628
+ cancellationNotice: result.status === "done" ? "done" : "waiting"
236629
+ });
236630
+ clearLastNavigationCache();
236631
+ arkmeUi.authChanged(false);
236632
+ }
236633
+ }, authenticatedAccountKey) : null]
235750
236634
  })
235751
236635
  ] }),
235752
236636
  view === "general" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsGroup, {
@@ -235816,6 +236700,14 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235816
236700
  })
235817
236701
  ]
235818
236702
  }),
236703
+ emailBoundToast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.Toast, {
236704
+ text: tr$1("邮箱绑定成功"),
236705
+ anchor: surfaceRef.current,
236706
+ icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_deepseek_ai_dsh_client_ui_primitives.IconCheckOutline16, {}),
236707
+ onDone: () => {
236708
+ setEmailBoundToast(false);
236709
+ }
236710
+ }),
235819
236711
  activeAccountDialog === "qr" && profile !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProfileQrDialog, {
235820
236712
  profile,
235821
236713
  shareWebsite: clientConfig?.shareWebsite,
@@ -235830,6 +236722,17 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235830
236722
  },
235831
236723
  onUpdated: applyProfileSnapshot
235832
236724
  }) : null,
236725
+ activeAccountDialog === "email" && profile !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(EmailBindDialog, {
236726
+ profile,
236727
+ onClose: () => {
236728
+ setActiveAccountDialog(null);
236729
+ },
236730
+ onUpdated: (snapshot) => {
236731
+ applyProfileSnapshot(snapshot);
236732
+ setAccountFeedback("");
236733
+ setEmailBoundToast(true);
236734
+ }
236735
+ }, profile.userId) : null,
235833
236736
  activeAccountDialog === "phone" && profile !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PhoneBindDialog, {
235834
236737
  config: clientConfig,
235835
236738
  profile,