@senguoyun/dsh-arkme 0.1.78 → 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 (52) hide show
  1. package/lib/client.js +912 -108
  2. package/lib/client.js.map +1 -1
  3. package/lib/harness-model-client.js +11 -3
  4. package/lib/harness-native-selection-client.js +11 -3
  5. package/lib/index.js +29 -1
  6. package/lib/persistent-extension.js +1 -1
  7. package/lib/{persistent-runtime-aiHgSAmj.js → persistent-runtime-CB7mEj3E.js} +404 -107
  8. package/lib/types/arkme-service.d.ts +9 -0
  9. package/lib/types/arkme-service.d.ts.map +1 -1
  10. package/lib/types/client/ArkmeAccountCancellation.d.ts +8 -0
  11. package/lib/types/client/ArkmeAccountCancellation.d.ts.map +1 -0
  12. package/lib/types/client/ArkmeLogin.d.ts +3 -0
  13. package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
  14. package/lib/types/client/ArkmeRecordingSurface.d.ts +2 -1
  15. package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
  16. package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
  17. package/lib/types/client/ArkmeSettingsSurface.d.ts +5 -0
  18. package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
  19. package/lib/types/client/arkme-auth-flow.d.ts.map +1 -1
  20. package/lib/types/client/arkme-login-locales.d.ts +6 -0
  21. package/lib/types/client/arkme-login-locales.d.ts.map +1 -1
  22. package/lib/types/client/auth-store.d.ts.map +1 -1
  23. package/lib/types/client/locales/actions-en.d.ts.map +1 -1
  24. package/lib/types/client/recordings/RecordingSearchRow.d.ts +5 -0
  25. package/lib/types/client/recordings/RecordingSearchRow.d.ts.map +1 -0
  26. package/lib/types/client/recordings/recording-search-target.d.ts +4 -0
  27. package/lib/types/client/recordings/recording-search-target.d.ts.map +1 -0
  28. package/lib/types/client/ui-controller.d.ts +3 -5
  29. package/lib/types/client/ui-controller.d.ts.map +1 -1
  30. package/lib/types/host-api.d.ts.map +1 -1
  31. package/lib/types/index.d.ts +1 -1
  32. package/lib/types/index.d.ts.map +1 -1
  33. package/lib/types/local-database.d.ts +2 -0
  34. package/lib/types/local-database.d.ts.map +1 -1
  35. package/lib/types/recording-presentation.d.ts +1 -0
  36. package/lib/types/recording-presentation.d.ts.map +1 -1
  37. package/lib/types/recording-search-result.d.ts +3 -0
  38. package/lib/types/recording-search-result.d.ts.map +1 -0
  39. package/lib/types/recording-search-version.d.ts +17 -0
  40. package/lib/types/recording-search-version.d.ts.map +1 -0
  41. package/lib/types/services/auth-service.d.ts +20 -1
  42. package/lib/types/services/auth-service.d.ts.map +1 -1
  43. package/lib/types/services/recording-service.d.ts.map +1 -1
  44. package/lib/types/services/search-service.d.ts +3 -1
  45. package/lib/types/services/search-service.d.ts.map +1 -1
  46. package/lib/types/services/service.d.ts +3 -0
  47. package/lib/types/services/service.d.ts.map +1 -1
  48. package/lib/types/state-store.d.ts +7 -0
  49. package/lib/types/state-store.d.ts.map +1 -1
  50. package/lib/types/types.d.ts +45 -2
  51. package/lib/types/types.d.ts.map +1 -1
  52. package/package.json +5 -5
package/lib/client.js CHANGED
@@ -1790,7 +1790,7 @@ window.__ModuleLoader__.load({
1790
1790
  return current.revision + 1;
1791
1791
  }
1792
1792
  function sameAuth(left, right) {
1793
- 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;
1794
1794
  }
1795
1795
  var ArkmeAuthStore = class {
1796
1796
  state = {
@@ -1813,6 +1813,10 @@ window.__ModuleLoader__.load({
1813
1813
  };
1814
1814
  setAuth(auth) {
1815
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
+ };
1816
1820
  this.authGeneration += 1;
1817
1821
  this.publish({
1818
1822
  ...this.state,
@@ -1843,8 +1847,12 @@ window.__ModuleLoader__.load({
1843
1847
  });
1844
1848
  const pending = Promise.all([callArkme("auth.status"), callArkme("auth.config")]).then(([auth, config]) => {
1845
1849
  const currentAuth = this.state.auth;
1846
- const preservePendingAttempt = currentAuth?.status === "pending" && (auth.status === "logged-out" || auth.status === "expired");
1847
- 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
+ };
1848
1856
  this.publish({
1849
1857
  ...this.state,
1850
1858
  auth: effectiveAuth,
@@ -31157,7 +31165,7 @@ window.__ModuleLoader__.load({
31157
31165
  }
31158
31166
  this.showWorld();
31159
31167
  }
31160
- showRecordingTarget(dateStamp, startAtMillis) {
31168
+ showRecordingTarget(dateStamp, startAtMillis, segment) {
31161
31169
  this.leaveContacts();
31162
31170
  const { selectedSource: _selectedSource, calendarOpen: _calendarOpen, productMode: _productMode, ...rest } = this.state;
31163
31171
  this.publish({
@@ -31165,7 +31173,8 @@ window.__ModuleLoader__.load({
31165
31173
  mode: "recordings",
31166
31174
  recordingTarget: {
31167
31175
  dateStamp,
31168
- startAtMillis
31176
+ startAtMillis,
31177
+ ...segment === void 0 ? {} : { segment }
31169
31178
  }
31170
31179
  });
31171
31180
  }
@@ -31387,7 +31396,7 @@ window.__ModuleLoader__.load({
31387
31396
  const { worldInitialScope: _scope, worldNavigationRevision: _revision, ...rest } = next;
31388
31397
  next = rest;
31389
31398
  }
31390
- 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);
31391
31400
  if (sameView && next.chatRevision === this.state.chatRevision && next.recordRevision === this.state.recordRevision && next.topicDirectoryRevision === this.state.topicDirectoryRevision) return;
31392
31401
  this.state = next;
31393
31402
  if (!sameView) this.viewState = viewStateOf(next);
@@ -34836,6 +34845,27 @@ Arkme 账号|Arkme account
34836
34845
  //#endregion
34837
34846
  //#region src/client/locales/actions-en.ts
34838
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…",
34839
34869
  "共同群聊": "Shared groups",
34840
34870
  "调整共同群聊宽度": "Resize shared groups",
34841
34871
  "同步尚未完成,请继续同步": "Sync is incomplete. Continue syncing.",
@@ -141971,6 +142001,117 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
141971
142001
  });
141972
142002
  }
141973
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
141974
142115
  //#region src/harness-embed-contract.ts
141975
142116
  const ARKME_HARNESS_EMBED_PATH = "/arkme-self/harness-frame";
141976
142117
  /** Same-origin bridge owned and disposed by the embedded session client. */
@@ -144248,25 +144389,6 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144248
144389
  ]
144249
144390
  });
144250
144391
  }
144251
- function RecordingRow({ item }) {
144252
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
144253
- "data-arkme-feedback": "neutral",
144254
- type: "button",
144255
- style: styles$37.row,
144256
- onClick: () => arkmeUi.showRecordingTarget(item.dateStamp, item.startAtMillis),
144257
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
144258
- style: {
144259
- ...styles$37.text,
144260
- marginTop: 0,
144261
- color: colors$9.text
144262
- },
144263
- children: item.snippet || tr$1("暂无转写内容")
144264
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
144265
- style: styles$37.meta,
144266
- children: dateTimeLabel$1(item.startAtMillis || item.dateStamp)
144267
- })]
144268
- });
144269
- }
144270
144392
  function AudioQuickRow({ item, asset, onOpen, onTagClick }) {
144271
144393
  useArkmeLocale();
144272
144394
  const initialUrl = item.voice?.mediaRef === void 0 ? displayUrl(asset) : mediaUrl(item.voice.mediaRef);
@@ -144397,6 +144519,9 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144397
144519
  const requestId = (0, react$1.useRef)(0);
144398
144520
  const quickRef = (0, react$1.useRef)();
144399
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);
144400
144525
  const sourceSearchAbort = (0, react$1.useRef)();
144401
144526
  const sourceSearchRevision = (0, react$1.useRef)(0);
144402
144527
  const quickRequestAbort = (0, react$1.useRef)();
@@ -144453,6 +144578,9 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144453
144578
  }
144454
144579
  setRequestedQuery(keyword);
144455
144580
  const id = ++requestId.current;
144581
+ recordingPageAbort.current?.abort();
144582
+ recordingPageAbort.current = void 0;
144583
+ setRecordingPageLoading(false);
144456
144584
  searchAbort.current?.abort();
144457
144585
  sourceSearchAbort.current?.abort();
144458
144586
  sourceSearchAbort.current = void 0;
@@ -144503,7 +144631,10 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144503
144631
  query: keyword,
144504
144632
  limit: 50
144505
144633
  }, controller.signal).then((nextRecordings) => {
144506
- if (active()) setRecordings(nextRecordings);
144634
+ if (active()) {
144635
+ recordingResultQuery.current = keyword;
144636
+ setRecordings(nextRecordings);
144637
+ }
144507
144638
  }).catch((caught) => {
144508
144639
  if (active()) setRecordingError(errorMessage$9(caught));
144509
144640
  }).finally(() => {
@@ -144526,6 +144657,57 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
144526
144657
  callArkme("search.history.create", { query: keyword }).catch(() => void 0);
144527
144658
  setHistory((current) => [keyword, ...current.filter((value) => value !== keyword)].slice(0, 10));
144528
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]);
144529
144711
  const chooseSource = (0, react$1.useCallback)(async (sourceUid, sourceKind) => {
144530
144712
  const keyword = query.trim();
144531
144713
  if (keyword === "") return;
@@ -145278,14 +145460,38 @@ body:has([data-arkme-self-topic-menu]) > [role="menu"] { z-index: 10030; }
145278
145460
  }),
145279
145461
  recordingError !== "" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
145280
145462
  style: styles$37.error,
145281
- 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
+ ]
145282
145478
  }),
145283
145479
  recordingItems.length > 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
145284
145480
  style: styles$37.list,
145285
- children: recordingItems.map((item) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(RecordingRow, { item }, `${item.sessionId}:${String(item.startAtMillis)}`))
145286
- }) : !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, {
145287
145483
  loading: false,
145288
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("加载更多")
145289
145495
  })
145290
145496
  ]
145291
145497
  })
@@ -164234,6 +164440,12 @@ html body {
164234
164440
  const ARKME_LOGIN_LOCALE_NAMESPACE = "arkme.login";
164235
164441
  const arkmeLoginZh = {
164236
164442
  "locale.id": "zh",
164443
+ "cancellation.title": "账号正在注销",
164444
+ "cancellation.days": "距离账号注销还剩 {days} 天。继续使用将撤销注销申请;继续注销将退出本次登录。",
164445
+ "cancellation.cancel": "继续注销",
164446
+ "cancellation.continue": "继续使用",
164447
+ "cancellation.done": "账号已注销",
164448
+ "cancellation.waiting": "注销申请已提交",
164237
164449
  "story.aria": "即我产品定义",
164238
164450
  "story.title.first": "即我,",
164239
164451
  "story.title.second": "你的数字自我",
@@ -164322,6 +164534,12 @@ html body {
164322
164534
  };
164323
164535
  const arkmeLoginEn = {
164324
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",
164325
164543
  "story.aria": "About Arkme",
164326
164544
  "story.title.first": "Arkme,",
164327
164545
  "story.title.second": "Digital ark, true me",
@@ -165001,6 +165219,52 @@ html body {
165001
165219
  .dsh-arkme-login-definition h1 { font-size: 40px; }
165002
165220
  .dsh-arkme-login-card { max-height: calc(100vh - 48px); overflow-y: auto; padding: 8px 4px; }
165003
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
+
165004
165268
  `;
165005
165269
  function ArkmeLogin(props) {
165006
165270
  const t = props.t ?? defaultArkmeLoginTranslate;
@@ -165014,6 +165278,50 @@ html body {
165014
165278
  const changeTestUserId = (event) => {
165015
165279
  props.onTestUserIdChange(event.target.value.replace(/\D/g, "").slice(0, 16));
165016
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
+ });
165017
165325
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165018
165326
  className: "dsh-arkme-login-page",
165019
165327
  children: [
@@ -165056,6 +165364,11 @@ html body {
165056
165364
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165057
165365
  className: "dsh-arkme-login-content",
165058
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,
165059
165372
  /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
165060
165373
  className: "dsh-arkme-login-brand",
165061
165374
  children: [
@@ -170623,6 +170936,20 @@ html body {
170623
170936
  });
170624
170937
  }
170625
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
170626
170953
  //#region node_modules/@phosphor-icons/react/dist/defs/ClockCounterClockwise.es.js
170627
170954
  const e$45 = /* @__PURE__ */ new Map([
170628
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" }))],
@@ -177464,25 +177791,6 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
177464
177791
  return result;
177465
177792
  }
177466
177793
  //#endregion
177467
- //#region src/client/recordings/RecordingTranscriptText.tsx
177468
- function RecordingTranscriptText({ text, matches, activeIndex }) {
177469
- const characters = Array.from(text);
177470
- let cursor = 0;
177471
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [matches.map((match) => {
177472
- const prefix = characters.slice(cursor, match.start).join("");
177473
- cursor = match.start + match.length;
177474
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react$1.Fragment, { children: [prefix, /* @__PURE__ */ (0, react_jsx_runtime.jsx)("mark", {
177475
- "data-recording-match": match.index,
177476
- style: {
177477
- background: arkmeTheme.warningSoft,
177478
- color: "inherit",
177479
- outline: match.index === activeIndex ? `1px solid ${arkmeTheme.warning}` : void 0
177480
- },
177481
- children: characters.slice(match.start, cursor).join("")
177482
- })] }, match.start);
177483
- }), characters.slice(cursor).join("")] });
177484
- }
177485
- //#endregion
177486
177794
  //#region src/client/recordings/recording-transcript-comparison.ts
177487
177795
  function recordingComparisonPlaybackTarget(item, systemItems) {
177488
177796
  if (item.transcriptSource === "system") return item;
@@ -180540,9 +180848,10 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
180540
180848
  v1: Math.floor(durationSeconds % 3600 / 60)
180541
180849
  });
180542
180850
  }
180543
- 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 }) {
180544
180852
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("li", {
180545
180853
  "data-recording-transcript-item": item.itemId,
180854
+ "data-recording-search-highlight": searchHighlighted || void 0,
180546
180855
  style: {
180547
180856
  ...styles$20.transcript,
180548
180857
  ...readOnly ? {
@@ -180550,6 +180859,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
180550
180859
  contentVisibility: "visible"
180551
180860
  } : {},
180552
180861
  ...selected ? { background: colors$4.input } : {},
180862
+ ...searchHighlighted ? { background: `color-mix(in srgb, ${colors$4.base} 88%, ${colors$4.text} 12%)` } : {},
180553
180863
  ...selectionControl ? { paddingLeft: 27 } : {}
180554
180864
  },
180555
180865
  onDoubleClick: !readOnly && onToggleSelection === void 0 ? onSelect : void 0,
@@ -181403,6 +181713,42 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181403
181713
  const selectedSummary = day?.summary.items.find((version) => version.id === summaryVersionId && version.selectable);
181404
181714
  const selectedTimeline = day?.timeline.items.find((version) => version.id === timelineVersionId && version.selectable);
181405
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]);
181406
181752
  const transcriptMatches = (0, react$1.useMemo)(() => findRecordingTranscriptMatches(transcriptItems, transcriptSearch), [transcriptItems, transcriptSearch]);
181407
181753
  const matchesByItem = (0, react$1.useMemo)(() => {
181408
181754
  const grouped = /* @__PURE__ */ new Map();
@@ -181567,6 +181913,10 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181567
181913
  const renderTranscript = () => {
181568
181914
  const section = day?.transcript;
181569
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
+ });
181570
181920
  if (section?.state === "processing") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeRecordingTranscriptLoading, {});
181571
181921
  if (section === void 0 || section.state !== "ready") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SectionState, {
181572
181922
  section,
@@ -181592,7 +181942,8 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
181592
181942
  };
181593
181943
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ArkmeRecordingTranscriptRow, {
181594
181944
  item,
181595
- selected,
181945
+ selected: preciseItem?.itemId === item.itemId || selected,
181946
+ searchHighlighted: preciseItem?.itemId === item.itemId,
181596
181947
  selectionControl: selectionMode && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("input", {
181597
181948
  type: "checkbox",
181598
181949
  "aria-label": `选择录音片段 ${recordingTranscriptTimeLabel(item.startAtMillis)}`,
@@ -202692,7 +203043,7 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
202692
203043
  const c$3 = e$24;
202693
203044
  //#endregion
202694
203045
  //#region package.json
202695
- var version = "0.1.78";
203046
+ var version = "0.1.79";
202696
203047
  //#endregion
202697
203048
  //#region src/client/profile-change-store.ts
202698
203049
  let revision = 0;
@@ -210692,6 +211043,21 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
210692
211043
  setBusy(false);
210693
211044
  }
210694
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
+ };
210695
211061
  const cancelBinding = async () => {
210696
211062
  setBusy(true);
210697
211063
  setError("");
@@ -210748,6 +211114,11 @@ registerProcessor('arkme-pcm-journal', ArkmePcmJournal);
210748
211114
  error,
210749
211115
  loginProps: {
210750
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
+ },
210751
211122
  mode: loginMode,
210752
211123
  phoneBindingRequired,
210753
211124
  agreed,
@@ -227424,12 +227795,63 @@ button.arkme-account-info-row {
227424
227795
  gap: 16px;
227425
227796
  }
227426
227797
 
227427
- [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 {
227428
227799
  text-align: right;
227429
227800
  }
227430
227801
 
227431
- [data-arkme-settings-view="account"] .arkme-account-info-action {
227432
- 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);
227433
227855
  }
227434
227856
 
227435
227857
  [data-arkme-settings-view="account"] .arkme-redesign-settings-group:has(.arkme-redesign-balance-row) {
@@ -227444,7 +227866,9 @@ button.arkme-account-info-row {
227444
227866
  }
227445
227867
 
227446
227868
  .arkme-account-logout {
227447
- justify-content: center;
227869
+ flex-direction: column;
227870
+ align-items: center;
227871
+ gap: 12px;
227448
227872
  padding-top: 32px;
227449
227873
  display: flex;
227450
227874
  }
@@ -227461,6 +227885,13 @@ button.arkme-account-info-row {
227461
227885
  padding: 8px 24px;
227462
227886
  }
227463
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
+
227464
227895
  .arkme-account-logout > button:disabled {
227465
227896
  cursor: default;
227466
227897
  opacity: .6;
@@ -231662,6 +232093,54 @@ body[data-ds-dark-theme] .arkme-peer-membership-disc {
231662
232093
  outline: 2px solid var(--dsw-alias-label-secondary, #68707c);
231663
232094
  outline-offset: 2px;
231664
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
+ }
231665
232144
  \nbody:has([data-arkme-owned="product-navigation"]) {
231666
232145
  --arkme-control-hover-surface: #f1f2f6;
231667
232146
  }
@@ -233634,10 +234113,6 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
233634
234113
  min-width: 0;
233635
234114
  }
233636
234115
 
233637
- [data-arkme-settings-view="account"] .arkme-account-info-row {
233638
- grid-template-columns: 26px minmax(0, 1fr) auto 18px;
233639
- }
233640
-
233641
234116
  .arkme-profile-edit-value {
233642
234117
  align-items: center;
233643
234118
  gap: 12px;
@@ -233966,6 +234441,136 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
233966
234441
  }
233967
234442
  bindPrivateChatActionsAuth(arkmeAuthStore, privateChatActions);
233968
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
233969
234574
  //#region src/client/ArkmeScreenshotShortcutSetting.tsx
233970
234575
  function ArkmeScreenshotShortcutSetting() {
233971
234576
  useArkmeLocale();
@@ -234889,40 +235494,51 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
234889
235494
  children: [title !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("h2", { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children })]
234890
235495
  });
234891
235496
  }
234892
- function AccountInfoRow({ icon, title, value, action, disabled = false, onClick }) {
234893
- const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
234894
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234895
- className: "arkme-account-info-icon",
234896
- "aria-hidden": true,
234897
- children: icon
234898
- }),
234899
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
234900
- className: "arkme-account-info-copy",
234901
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("strong", { children: title }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("small", { children: value })]
234902
- }),
234903
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234904
- className: "arkme-account-info-action",
234905
- children: action
234906
- }),
234907
- onClick === void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
234908
- className: "arkme-redesign-trailing-slot",
234909
- "aria-hidden": true
234910
- }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$20, {
234911
- size: 15,
234912
- "aria-hidden": true
234913
- })
234914
- ] });
234915
- if (onClick === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
234916
- className: "arkme-account-info-row",
234917
- 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
+ })]
234918
235530
  });
234919
- 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", {
234920
235536
  "data-arkme-feedback": "neutral",
234921
235537
  type: "button",
234922
- className: "arkme-account-info-row",
235538
+ className,
234923
235539
  disabled,
234924
235540
  onClick,
234925
- children: content
235541
+ children: [copy, trailing]
234926
235542
  });
234927
235543
  }
234928
235544
  function WechatBindingSettingsRow({ bound, nickname, onBind, busy = false }) {
@@ -235225,6 +235841,153 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235225
235841
  })
235226
235842
  });
235227
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
+ }
235228
235991
  function PhoneBindDialog({ config, profile, onClose, onUpdated }) {
235229
235992
  const [unbind, setUnbind] = (0, react$1.useState)(false);
235230
235993
  const busyRef = (0, react$1.useRef)(false);
@@ -235483,9 +236246,11 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235483
236246
  const [profile, setProfile] = (0, react$1.useState)();
235484
236247
  const [clientConfig, setClientConfig] = (0, react$1.useState)();
235485
236248
  const [logoutBusy, setLogoutBusy] = (0, react$1.useState)(false);
236249
+ const [cancellationBusy, setCancellationBusy] = (0, react$1.useState)(false);
235486
236250
  const [notificationBusy, setNotificationBusy] = (0, react$1.useState)(false);
235487
236251
  const [error, setError] = (0, react$1.useState)("");
235488
236252
  const [accountFeedback, setAccountFeedback] = (0, react$1.useState)("");
236253
+ const [emailBoundToast, setEmailBoundToast] = (0, react$1.useState)(false);
235489
236254
  const [activeAccountDialog, setActiveAccountDialog] = (0, react$1.useState)(null);
235490
236255
  const notificationPermission = (0, react$1.useSyncExternalStore)(arkmeDesktopNotifications.subscribePermission, arkmeDesktopNotifications.getPermissionSnapshot, arkmeDesktopNotifications.getPermissionSnapshot).permission;
235491
236256
  const [backgroundSoundBusy, setBackgroundSoundBusy] = (0, react$1.useState)(false);
@@ -235767,19 +236532,10 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235767
236532
  authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsGroup, {
235768
236533
  title: tr$1("账号信息"),
235769
236534
  children: [
235770
- /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235771
- className: "arkme-account-id-with-qr",
235772
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235773
- icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(d, { size: 18 }),
235774
- title: tr$1("即我号"),
235775
- value: currentArkmeId === "" ? tr$1("暂未获取到即我号") : currentArkmeId,
235776
- action: tr$1(profile?.canUpdateArkmeId === false ? "不可修改" : "修改"),
235777
- disabled: profile === void 0 || profile.canUpdateArkmeId === false,
235778
- onClick: profile !== void 0 && profile.canUpdateArkmeId !== false ? () => {
235779
- setActiveAccountDialog("arkme-id");
235780
- setAccountFeedback("");
235781
- } : void 0
235782
- }), /* @__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", {
235783
236539
  type: "button",
235784
236540
  className: "arkme-account-profile-qr",
235785
236541
  "aria-label": tr$1("查看我的二维码"),
@@ -235788,7 +236544,14 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235788
236544
  setActiveAccountDialog("qr");
235789
236545
  },
235790
236546
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(WorldShareQrIcon, {})
235791
- })]
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
235792
236555
  }),
235793
236556
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235794
236557
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(s$8, { size: 18 }),
@@ -235820,10 +236583,18 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235820
236583
  title: tr$1("华为 ID"),
235821
236584
  value: tr$1("已绑定")
235822
236585
  }),
235823
- profile?.contact.emailMasked && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
236586
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AccountInfoRow, {
235824
236587
  icon: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(i, { size: 18 }),
235825
236588
  title: tr$1("邮箱"),
235826
- 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
+ } : {}
235827
236598
  }),
235828
236599
  accountFeedback !== "" ? /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("p", {
235829
236600
  className: "arkme-account-feedback",
@@ -235835,17 +236606,31 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235835
236606
  }) : null
235836
236607
  ]
235837
236608
  }),
235838
- authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
236609
+ authenticated && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
235839
236610
  className: "arkme-account-logout",
235840
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236611
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
236612
+ className: "arkme-account-logout-confirm",
235841
236613
  "data-arkme-feedback": "danger",
235842
236614
  type: "button",
235843
- disabled: logoutBusy,
236615
+ disabled: logoutBusy || cancellationBusy,
235844
236616
  onClick: () => {
235845
236617
  logout();
235846
236618
  },
235847
236619
  children: logoutBusy ? tr$1("正在退出…") : tr$1("退出登录")
235848
- })
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]
235849
236634
  })
235850
236635
  ] }),
235851
236636
  view === "general" && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(SettingsGroup, {
@@ -235915,6 +236700,14 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235915
236700
  })
235916
236701
  ]
235917
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
+ }),
235918
236711
  activeAccountDialog === "qr" && profile !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ProfileQrDialog, {
235919
236712
  profile,
235920
236713
  shareWebsite: clientConfig?.shareWebsite,
@@ -235929,6 +236722,17 @@ body[data-ds-dark-theme] .arkme-member-label[data-tier="2"] {
235929
236722
  },
235930
236723
  onUpdated: applyProfileSnapshot
235931
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,
235932
236736
  activeAccountDialog === "phone" && profile !== void 0 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PhoneBindDialog, {
235933
236737
  config: clientConfig,
235934
236738
  profile,