@senguoyun/dsh-arkme 0.1.33 → 0.1.34

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 (29) hide show
  1. package/lib/client.js +3747 -2608
  2. package/lib/client.js.map +1 -1
  3. package/lib/index.js +117 -13
  4. package/lib/persistent-extension.js +1 -1
  5. package/lib/{persistent-runtime-DUqdJv8K.js → persistent-runtime-CZQTfyC1.js} +1349 -746
  6. package/lib/types/arkme-service.d.ts +9 -1
  7. package/lib/types/arkme-service.d.ts.map +1 -1
  8. package/lib/types/client/ArkmeMessageSnapshotDialog.d.ts +17 -0
  9. package/lib/types/client/ArkmeMessageSnapshotDialog.d.ts.map +1 -0
  10. package/lib/types/client/ArkmeRichComposerInput.d.ts +3 -1
  11. package/lib/types/client/ArkmeRichComposerInput.d.ts.map +1 -1
  12. package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
  13. package/lib/types/client/ArkmeSidebar.d.ts +1 -1
  14. package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
  15. package/lib/types/client/record-capture-location.d.ts +8 -0
  16. package/lib/types/client/record-capture-location.d.ts.map +1 -0
  17. package/lib/types/host-api.d.ts.map +1 -1
  18. package/lib/types/local-database.d.ts +1 -0
  19. package/lib/types/local-database.d.ts.map +1 -1
  20. package/lib/types/services/chat-service.d.ts +14 -1
  21. package/lib/types/services/chat-service.d.ts.map +1 -1
  22. package/lib/types/services/group-ai-polish-service.d.ts +3 -1
  23. package/lib/types/services/group-ai-polish-service.d.ts.map +1 -1
  24. package/lib/types/services/record-service.d.ts +10 -3
  25. package/lib/types/services/record-service.d.ts.map +1 -1
  26. package/lib/types/state-store.d.ts.map +1 -1
  27. package/lib/types/types.d.ts +50 -1
  28. package/lib/types/types.d.ts.map +1 -1
  29. package/package.json +5 -5
@@ -5949,14 +5949,14 @@ function firstNumber(source, keys) {
5949
5949
  }
5950
5950
  return 0;
5951
5951
  }
5952
- function epochMillis(value) {
5952
+ function epochMillis$1(value) {
5953
5953
  const raw = numberValue$17(value);
5954
5954
  if (raw <= 0) return 0;
5955
5955
  return raw < 1e10 ? Math.trunc(raw * 1e3) : Math.trunc(raw);
5956
5956
  }
5957
5957
  function firstEpochMillis(source, keys) {
5958
5958
  for (const key of keys) {
5959
- const value = epochMillis(source[key]);
5959
+ const value = epochMillis$1(source[key]);
5960
5960
  if (value > 0) return value;
5961
5961
  }
5962
5962
  return 0;
@@ -7601,17 +7601,792 @@ const ARKME_VOICEPRINT_ENROLLMENT_MAX_AUDIO_BYTES = 10 * 1024 * 1024;
7601
7601
  const ARKME_WORLD_PUBLISH_MAX_IMAGES = 27;
7602
7602
  const ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES = 20 * 1024 * 1024;
7603
7603
  //#endregion
7604
+ //#region src/services/record-service.ts
7605
+ function numberValue$16(value) {
7606
+ return typeof value === "number" && Number.isFinite(value) ? value : 0;
7607
+ }
7608
+ function listValue$16(value) {
7609
+ return Array.isArray(value) ? value : [];
7610
+ }
7611
+ const DSH_AGENT_INPUT_CREATION_SOURCE = 3;
7612
+ const MAX_DEFAULT_CATEGORY_FILTER_BACKFILL_PAGES = 5;
7613
+ function integerLikeValue$1(value) {
7614
+ if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
7615
+ if (typeof value === "string" && value.trim() !== "") {
7616
+ const parsed = Number(value.trim());
7617
+ if (Number.isFinite(parsed)) return Math.trunc(parsed);
7618
+ }
7619
+ return 0;
7620
+ }
7621
+ function recordCreationSource(raw) {
7622
+ const item = objectValue$1(raw);
7623
+ const core = objectValue$1(item.record_core);
7624
+ return integerLikeValue$1(item.creation_source ?? item.creationSource ?? core.creation_source ?? core.creationSource);
7625
+ }
7626
+ function isDSHAgentInputRecord(raw) {
7627
+ return recordCreationSource(raw) === DSH_AGENT_INPUT_CREATION_SOURCE;
7628
+ }
7629
+ function safeFailureMessage$4(error) {
7630
+ if (error instanceof ArkmePluginError) return error.message;
7631
+ if (error instanceof Error && error.message.trim() !== "") return error.message;
7632
+ return "未知错误";
7633
+ }
7634
+ function arkmeRecordCaptureContextPayload(input) {
7635
+ const clientName = input.clientName?.trim().slice(0, 120) ?? "";
7636
+ const networkName = input.networkName?.trim().slice(0, 120) ?? "";
7637
+ const electric = input.electric === void 0 ? void 0 : Math.trunc(input.electric);
7638
+ const charge = Math.trunc(input.charge ?? 0);
7639
+ return {
7640
+ ...clientName === "" ? {} : { client_name: clientName },
7641
+ ...networkName === "" ? {} : { network_name: networkName },
7642
+ ...electric === void 0 || electric < 0 || electric > 100 ? {} : { electric },
7643
+ ...charge < 1 || charge > 3 ? {} : { charge }
7644
+ };
7645
+ }
7646
+ function normalizedRecordCaptureContext(input) {
7647
+ if (input === void 0) return void 0;
7648
+ const payload = arkmeRecordCaptureContextPayload(input);
7649
+ const clientName = stringValue$1(payload.client_name);
7650
+ const networkName = stringValue$1(payload.network_name);
7651
+ const electric = numberValue$16(payload.electric);
7652
+ const charge = numberValue$16(payload.charge);
7653
+ const normalized = {
7654
+ ...clientName === "" ? {} : { clientName },
7655
+ ...networkName === "" ? {} : { networkName },
7656
+ ...payload.electric === void 0 ? {} : { electric },
7657
+ ...charge === 0 ? {} : { charge }
7658
+ };
7659
+ return Object.keys(normalized).length === 0 ? void 0 : normalized;
7660
+ }
7661
+ var RecordService = class {
7662
+ runtime;
7663
+ media;
7664
+ source;
7665
+ privacy;
7666
+ constructor(runtime, media, source, privacy = new ArkmePrivacyVisibilityService(runtime)) {
7667
+ this.runtime = runtime;
7668
+ this.media = media;
7669
+ this.source = source;
7670
+ this.privacy = privacy;
7671
+ }
7672
+ async longArticleDetail(sourceRef, itemUid, signal) {
7673
+ const session = await this.runtime.requireSession();
7674
+ const source = await this.source.openSourceRef(sourceRef, session.userId);
7675
+ const uid = itemUid.trim();
7676
+ if (uid === "") throw new ArkmePluginError("long-article-item-invalid", "长文记录标识无效", false);
7677
+ const data = await this.runtime.authenticatedPost("/api/v1/records/detail", { record_uid: uid }, session, signal);
7678
+ const core = objectValue$1(data.record_core);
7679
+ const recordUid = stringValue$1(core.record_uid).trim();
7680
+ const templateKind = numberValue$16(core.template_kind);
7681
+ const displayKind = numberValue$16(core.display_kind);
7682
+ if (recordUid !== uid || templateKind !== 8 && displayKind !== 1) throw new ArkmePluginError("long-article-not-found", "未找到可用的长文详情", false, 404);
7683
+ const originContainerRef = stringValue$1(core.origin_container_ref).trim();
7684
+ if (source.kind === "topic") {
7685
+ if (stringValue$1(objectValue$1(data.topic_core).topic_uid).trim() !== source.ownerRef) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
7686
+ } else if (source.kind === "private_chat" || source.kind === "group_chat") {
7687
+ if (originContainerRef !== source.ownerRef) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
7688
+ } else if (numberValue$16(core.owner_user_id) !== session.userId) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
7689
+ const recordDurationMillis = Math.max(0, Math.trunc(numberValue$16(core.record_duration_millis)));
7690
+ const editDurationMillis = Math.max(0, Math.trunc(numberValue$16(core.edit_duration_millis)));
7691
+ return {
7692
+ sourceRef,
7693
+ itemUid: recordUid,
7694
+ title: stringValue$1(core.title),
7695
+ textContent: stringValue$1(core.text_content),
7696
+ sendAtMillis: Math.trunc(numberValue$16(core.send_at)),
7697
+ updateAtMillis: Math.trunc(numberValue$16(core.update_at)),
7698
+ recordDurationMillis,
7699
+ editDurationMillis,
7700
+ thinkingDurationMillis: recordDurationMillis + editDurationMillis,
7701
+ version: Math.trunc(numberValue$16(core.version)),
7702
+ editable: numberValue$16(core.owner_user_id) === session.userId && numberValue$16(core.creator_user_id) === session.userId
7703
+ };
7704
+ }
7705
+ async updateLongArticle(sourceRef, itemUid, input) {
7706
+ if (this.runtime.config.richMediaSendEnabled === false) throw new ArkmePluginError("rich-content-disabled", "长文编辑已被插件配置关闭", false, 403);
7707
+ const session = await this.runtime.requireSession();
7708
+ const detail = await this.longArticleDetail(sourceRef, itemUid);
7709
+ const title = input.title.trim();
7710
+ const textContent = input.textContent.trim();
7711
+ const editDurationMillis = Math.max(0, Math.trunc(input.editDurationMillis));
7712
+ if (!detail.editable) throw new ArkmePluginError("long-article-not-editable", "只能编辑自己发布的长文", false, 403);
7713
+ if (title === "" || title.length > 100 || textContent === "" || textContent.length > 4e4 || !Number.isSafeInteger(input.version) || input.version <= 0 || input.version !== detail.version) throw new ArkmePluginError("long-article-update-invalid", "长文内容或版本无效,请刷新后重试", false, 409);
7714
+ await this.runtime.authenticatedPost("/api/v1/records/update", {
7715
+ record_uid: detail.itemUid,
7716
+ template_kind: 1,
7717
+ display_kind: 1,
7718
+ title,
7719
+ text_content: textContent,
7720
+ record_duration_millis: detail.recordDurationMillis,
7721
+ edit_duration_millis: editDurationMillis,
7722
+ version: detail.version
7723
+ }, session);
7724
+ return await this.longArticleDetail(sourceRef, itemUid);
7725
+ }
7726
+ async getLongArticleDraft(sourceRef, itemUid) {
7727
+ const session = await this.runtime.requireSession();
7728
+ await this.source.openSourceRef(sourceRef, session.userId);
7729
+ return await this.runtime.stateStore.getLongArticleDraft(session.userId, sourceRef, itemUid?.trim() || void 0);
7730
+ }
7731
+ async putLongArticleDraft(draft) {
7732
+ const session = await this.runtime.requireSession();
7733
+ await this.source.openSourceRef(draft.sourceRef, session.userId);
7734
+ const itemUid = draft.itemUid?.trim() || void 0;
7735
+ if (draft.title.length > 100 || draft.textContent.length > 4e4 || draft.durationMillis < 0) throw new ArkmePluginError("long-article-draft-invalid", "长文草稿内容无效", false);
7736
+ await this.runtime.stateStore.putLongArticleDraft(session.userId, {
7737
+ sourceRef: draft.sourceRef,
7738
+ ...itemUid === void 0 ? {} : { itemUid },
7739
+ title: draft.title,
7740
+ textContent: draft.textContent,
7741
+ durationMillis: Math.max(0, Math.trunc(draft.durationMillis)),
7742
+ updatedAtMillis: Date.now()
7743
+ });
7744
+ }
7745
+ async removeLongArticleDraft(sourceRef, itemUid) {
7746
+ const session = await this.runtime.requireSession();
7747
+ await this.source.openSourceRef(sourceRef, session.userId);
7748
+ await this.runtime.stateStore.removeLongArticleDraft(session.userId, sourceRef, itemUid?.trim() || void 0);
7749
+ }
7750
+ async cachedSnapshot() {
7751
+ const session = await this.runtime.requireSession();
7752
+ return await this.runtime.stateStore.cachedSnapshot(session.userId);
7753
+ }
7754
+ async queryCached(options) {
7755
+ const session = await this.runtime.requireSession();
7756
+ return await this.runtime.stateStore.queryCached(session.userId, options);
7757
+ }
7758
+ async refreshLatest() {
7759
+ await Promise.all([this.summary(), this.list(50)]);
7760
+ }
7761
+ async refreshSnapshot() {
7762
+ await this.refreshLatest();
7763
+ return await this.cachedSnapshot();
7764
+ }
7765
+ async summary() {
7766
+ const session = await this.runtime.requireSession();
7767
+ const data = await this.runtime.authenticatedPost("/api/v1/records/uncategorized/summary", {}, session);
7768
+ const summary = {
7769
+ recordCount: numberValue$16(data.record_count),
7770
+ wordsCount: numberValue$16(data.words_count ?? data.available_text_rune_count),
7771
+ totalSec: numberValue$16(data.total_sec ?? data.available_voice_duration_sec)
7772
+ };
7773
+ await this.runtime.stateStore.cacheSummary(session.userId, summary);
7774
+ return summary;
7775
+ }
7776
+ async list(limit, cursor) {
7777
+ const session = await this.runtime.requireSession();
7778
+ const lockedRecordUids = await this.privacy.lockedRecordUids(session);
7779
+ const normalizedLimit = Math.min(50, Math.max(1, Math.trunc(limit || 30)));
7780
+ let requestCursor = cursor;
7781
+ let hasMore = false;
7782
+ let backendNextCursor;
7783
+ const visibleRawItems = [];
7784
+ for (let pageIndex = 0; pageIndex < MAX_DEFAULT_CATEGORY_FILTER_BACKFILL_PAGES; pageIndex += 1) {
7785
+ const data = await this.runtime.authenticatedPost("/api/v1/records/uncategorized/query", {
7786
+ limit: normalizedLimit,
7787
+ ...requestCursor === void 0 ? {} : {
7788
+ cursor_send_at: requestCursor.sendAtMillis,
7789
+ cursor_record_uid: requestCursor.recordUid
7790
+ }
7791
+ }, session);
7792
+ const rawPageItems = listValue$16(data.items);
7793
+ const visiblePageItems = rawPageItems.filter((raw) => !isDSHAgentInputRecord(raw) && !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.recordUid(raw)));
7794
+ visibleRawItems.push(...visiblePageItems);
7795
+ hasMore = data.has_more === true;
7796
+ const nextSendAt = numberValue$16(data.next_cursor_send_at);
7797
+ const nextUid = stringValue$1(data.next_cursor_record_uid);
7798
+ backendNextCursor = nextSendAt > 0 && nextUid !== "" ? {
7799
+ sendAtMillis: nextSendAt,
7800
+ recordUid: nextUid
7801
+ } : void 0;
7802
+ const filteredCount = rawPageItems.length - visiblePageItems.length;
7803
+ if (visibleRawItems.length >= normalizedLimit || !hasMore || backendNextCursor === void 0 || filteredCount === 0) break;
7804
+ requestCursor = backendNextCursor;
7805
+ }
7806
+ const visibleOverflow = visibleRawItems.length > normalizedLimit;
7807
+ const rawItems = visibleRawItems.slice(0, normalizedLimit);
7808
+ const media = await this.media.hydrateRecordMediaPage(rawItems, session);
7809
+ const items = rawItems.map((raw) => {
7810
+ const recordUid = this.recordUid(raw);
7811
+ const displayItems = media.displayItemsByRecordUid.get(recordUid);
7812
+ return this.recordItem(raw, session.userId, {
7813
+ ...displayItems === void 0 ? {} : { displayItems },
7814
+ mediaUnavailable: media.unavailableRecordUids.has(recordUid)
7815
+ });
7816
+ }).filter((item) => item !== void 0);
7817
+ const lastVisibleRaw = rawItems.at(-1);
7818
+ const lastVisibleCursor = lastVisibleRaw === void 0 ? void 0 : {
7819
+ sendAtMillis: numberValue$16(objectValue$1(lastVisibleRaw).send_at ?? objectValue$1(objectValue$1(lastVisibleRaw).record_core).send_at),
7820
+ recordUid: this.recordUid(lastVisibleRaw)
7821
+ };
7822
+ const filledRequestedPage = rawItems.length >= normalizedLimit;
7823
+ const nextCursor = lastVisibleCursor !== void 0 && lastVisibleCursor.sendAtMillis > 0 && lastVisibleCursor.recordUid !== "" && (visibleOverflow || filledRequestedPage && hasMore) ? lastVisibleCursor : backendNextCursor;
7824
+ const page = {
7825
+ items,
7826
+ hasMore: hasMore || visibleOverflow,
7827
+ ...nextCursor === void 0 ? {} : { nextCursor }
7828
+ };
7829
+ await this.runtime.stateStore.cachePage(session.userId, page, cursor);
7830
+ return page;
7831
+ }
7832
+ async createText(recordUid, textContent, options = {}) {
7833
+ const session = await this.runtime.requireSession();
7834
+ const normalizedUid = recordUid.trim();
7835
+ const normalizedText = textContent.trim();
7836
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
7837
+ if (normalizedText === "") throw new ArkmePluginError("record-text-empty", "请输入要发给自己的内容", false);
7838
+ if (normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-text-too-long", `内容不能超过 ${this.runtime.config.maxTextLength} 个字符`, false);
7839
+ const now = Date.now();
7840
+ const recordDurationMillis = Math.max(0, Math.trunc(options.recordDurationMillis ?? 0));
7841
+ const captureContext = normalizedRecordCaptureContext(options.captureContext);
7842
+ const pending = {
7843
+ recordUid: normalizedUid,
7844
+ textContent: normalizedText,
7845
+ createdAtMillis: now,
7846
+ sendAtMillis: now,
7847
+ attempts: 0,
7848
+ ...recordDurationMillis === 0 ? {} : { recordDurationMillis },
7849
+ ...captureContext === void 0 ? {} : { captureContext }
7850
+ };
7851
+ await this.runtime.stateStore.putPending(session.userId, pending);
7852
+ return await this.sendPending(session, pending);
7853
+ }
7854
+ async createTextForConversation(recordUid, textContent, options = {}) {
7855
+ try {
7856
+ return {
7857
+ ...await this.createText(recordUid, textContent, options),
7858
+ localState: "synced"
7859
+ };
7860
+ } catch (error) {
7861
+ const session = await this.runtime.requireSession();
7862
+ const pending = (await this.runtime.stateStore.listPending(session.userId)).find((item) => item.recordUid === recordUid);
7863
+ if (pending === void 0) throw error;
7864
+ return {
7865
+ recordUid,
7866
+ status: 0,
7867
+ localState: "failed",
7868
+ error: pending.lastError ?? safeFailureMessage$4(error)
7869
+ };
7870
+ }
7871
+ }
7872
+ async createDSHAgentInputText(recordUid, textContent, sendAtMillis) {
7873
+ const session = await this.runtime.requireSession();
7874
+ const normalizedUid = recordUid.trim();
7875
+ const normalizedText = textContent.trim();
7876
+ const normalizedSendAt = Math.max(0, Math.trunc(sendAtMillis));
7877
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
7878
+ if (normalizedText === "") throw new ArkmePluginError("record-text-empty", "请输入要发给自己的内容", false);
7879
+ if (normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-text-too-long", `内容不能超过 ${this.runtime.config.maxTextLength} 个字符`, false);
7880
+ const data = await this.runtime.authenticatedPost("/api/v1/records/dsh-agent-input/create", {
7881
+ record_uid: normalizedUid,
7882
+ template_kind: 1,
7883
+ title: "",
7884
+ text_content: normalizedText,
7885
+ send_at: normalizedSendAt > 0 ? normalizedSendAt : Date.now()
7886
+ }, session, void 0, {
7887
+ scope: this.runtime.requestScope(session.userId),
7888
+ key: `dsh-agent-input:${normalizedUid}`
7889
+ });
7890
+ this.runtime.invalidateScope(this.runtime.requestScope(session.userId));
7891
+ return {
7892
+ recordUid: stringValue$1(data.record_uid) || normalizedUid,
7893
+ status: numberValue$16(data.status)
7894
+ };
7895
+ }
7896
+ async createFileAssetsForConversation(recordUid, textContent, assets) {
7897
+ const session = await this.runtime.requireSession();
7898
+ const normalizedUid = recordUid.trim();
7899
+ const normalizedText = textContent.trim();
7900
+ if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
7901
+ if (assets.length === 0 || assets.length > 20 || normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-file-assets-invalid", "附件内容为空、过长或数量超限", false);
7902
+ for (const asset of assets) if (!/^[A-Za-z0-9._:-]{8,256}$/.test(asset.fileAssetUid) || asset.fileName.trim() === "" || asset.fileName.length > 255 || !Number.isSafeInteger(asset.size) || asset.size <= 0 || ![
7903
+ 1,
7904
+ 2,
7905
+ 3,
7906
+ 4
7907
+ ].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
7908
+ const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
7909
+ record_uid: normalizedUid,
7910
+ template_kind: 2,
7911
+ display_kind: 0,
7912
+ title: "",
7913
+ text_content: normalizedText,
7914
+ content_payload: {
7915
+ payload_kind: 2,
7916
+ schema_version: 1,
7917
+ text_state: normalizedText === "" ? 3 : 1,
7918
+ media_refs: assets.map((asset, index) => ({
7919
+ file_asset_uid: asset.fileAssetUid,
7920
+ content_file_role: 1,
7921
+ render_role: 1,
7922
+ sort_order: index,
7923
+ file_name: asset.fileName
7924
+ }))
7925
+ },
7926
+ send_at: Date.now()
7927
+ }, session);
7928
+ return {
7929
+ recordUid: stringValue$1(data.record_uid).trim() || normalizedUid,
7930
+ status: numberValue$16(data.status)
7931
+ };
7932
+ }
7933
+ async pendingWrites() {
7934
+ const session = await this.runtime.requireSession();
7935
+ return await this.runtime.stateStore.listPending(session.userId);
7936
+ }
7937
+ async retryPending(recordUid) {
7938
+ const session = await this.runtime.requireSession();
7939
+ const pending = (await this.runtime.stateStore.listPending(session.userId)).find((item) => item.recordUid === recordUid);
7940
+ if (pending === void 0) throw new ArkmePluginError("outbox-entry-not-found", "待重试内容不存在", false, 404);
7941
+ return await this.sendPending(session, pending);
7942
+ }
7943
+ async sendPending(session, pending) {
7944
+ try {
7945
+ const captureContext = pending.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(pending.captureContext);
7946
+ const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
7947
+ record_uid: pending.recordUid,
7948
+ template_kind: 1,
7949
+ title: "",
7950
+ text_content: pending.textContent,
7951
+ ...Math.max(0, Math.trunc(pending.recordDurationMillis ?? 0)) === 0 ? {} : { record_duration_millis: Math.max(0, Math.trunc(pending.recordDurationMillis ?? 0)) },
7952
+ ...captureContext === void 0 || Object.keys(captureContext).length === 0 ? {} : { capture_context: captureContext },
7953
+ send_at: pending.sendAtMillis
7954
+ }, session);
7955
+ const result = {
7956
+ recordUid: stringValue$1(data.record_uid) || pending.recordUid,
7957
+ status: numberValue$16(data.status)
7958
+ };
7959
+ await this.runtime.stateStore.markSynced(session.userId, pending.recordUid, result.status);
7960
+ return result;
7961
+ } catch (error) {
7962
+ await this.runtime.stateStore.markAttempt(session.userId, pending.recordUid, safeFailureMessage$4(error));
7963
+ throw error;
7964
+ }
7965
+ }
7966
+ recordUid(raw) {
7967
+ const item = objectValue$1(raw);
7968
+ return stringValue$1(item.record_uid ?? objectValue$1(item.record_core).record_uid).trim();
7969
+ }
7970
+ recordTimelineItem(item) {
7971
+ return {
7972
+ itemUid: item.recordUid,
7973
+ senderName: "我",
7974
+ isMe: true,
7975
+ sendAtMillis: item.sendAtMillis,
7976
+ title: item.title,
7977
+ textContent: item.textContent,
7978
+ status: item.status,
7979
+ templateKind: item.templateKind,
7980
+ version: item.version,
7981
+ ...item.displayKind === void 0 ? {} : { displayKind: item.displayKind },
7982
+ ...item.contentBlocks === void 0 ? {} : { contentBlocks: item.contentBlocks },
7983
+ ...item.mediaUnavailable === true ? { mediaUnavailable: true } : {}
7984
+ };
7985
+ }
7986
+ recordTimelineItemFromRaw(raw, userId, options = {}) {
7987
+ const item = objectValue$1(raw);
7988
+ const core = objectValue$1(item.record_core);
7989
+ return {
7990
+ itemUid: stringValue$1(item.record_uid ?? core.record_uid).trim(),
7991
+ senderName: stringValue$1(item.nickname).trim() || "我",
7992
+ isMe: options.isMe ?? numberValue$16(item.creator_user_id ?? item.owner_user_id ?? core.creator_user_id ?? core.owner_user_id) === userId,
7993
+ sendAtMillis: numberValue$16(item.send_at ?? core.send_at),
7994
+ title: stringValue$1(item.title ?? core.title),
7995
+ textContent: stringValue$1(item.text_content ?? core.text_content),
7996
+ status: numberValue$16(item.status ?? core.status),
7997
+ templateKind: numberValue$16(item.template_kind ?? core.template_kind),
7998
+ displayKind: numberValue$16(item.display_kind ?? core.display_kind),
7999
+ version: numberValue$16(item.version ?? core.version),
8000
+ updateAtMillis: numberValue$16(item.update_at ?? core.update_at),
8001
+ recordDurationMillis: numberValue$16(item.record_duration_millis ?? core.record_duration_millis),
8002
+ editDurationMillis: numberValue$16(item.edit_duration_millis ?? core.edit_duration_millis),
8003
+ contentBlocks: this.media.richContentBlocks(raw, userId, options.displayItems),
8004
+ ...options.selfTopic === void 0 ? {} : { selfTopic: options.selfTopic },
8005
+ ...options.mediaUnavailable === true ? { mediaUnavailable: true } : {}
8006
+ };
8007
+ }
8008
+ recordItem(raw, userId, options = {}) {
8009
+ const item = objectValue$1(raw);
8010
+ const core = objectValue$1(item.record_core);
8011
+ const recordUid = stringValue$1(item.record_uid ?? core.record_uid).trim();
8012
+ if (recordUid === "") return void 0;
8013
+ return {
8014
+ recordUid,
8015
+ sendAtMillis: numberValue$16(item.send_at ?? core.send_at),
8016
+ title: stringValue$1(core.title),
8017
+ textContent: stringValue$1(core.text_content),
8018
+ templateKind: numberValue$16(core.template_kind),
8019
+ status: numberValue$16(core.status),
8020
+ version: numberValue$16(core.version),
8021
+ creationSource: recordCreationSource(raw),
8022
+ displayKind: numberValue$16(item.display_kind ?? core.display_kind),
8023
+ ...userId === void 0 ? {} : { contentBlocks: this.media.richContentBlocks(raw, userId, options.displayItems) },
8024
+ ...options.mediaUnavailable === true ? { mediaUnavailable: true } : {}
8025
+ };
8026
+ }
8027
+ isDSHAgentInput(raw) {
8028
+ return isDSHAgentInputRecord(raw);
8029
+ }
8030
+ isPrivacyLocked(raw) {
8031
+ return arkmePrivacyLockedRecord(raw);
8032
+ }
8033
+ async syncHistory(maxPages = 20, signal) {
8034
+ const pageCap = Math.min(20, Math.max(1, Math.trunc(maxPages)));
8035
+ await this.refreshLatest();
8036
+ let snapshot = await this.cachedSnapshot();
8037
+ let pages = 0;
8038
+ while (snapshot.hasMore && snapshot.nextCursor !== void 0 && pages < pageCap) {
8039
+ if (signal?.aborted === true) throw new Error("Arkme历史同步已取消");
8040
+ await this.list(50, snapshot.nextCursor);
8041
+ pages += 1;
8042
+ snapshot = await this.cachedSnapshot();
8043
+ }
8044
+ return {
8045
+ pages,
8046
+ complete: !snapshot.hasMore
8047
+ };
8048
+ }
8049
+ };
8050
+ //#endregion
7604
8051
  //#region src/services/chat-service.ts
7605
8052
  const OFFICIAL_AUTHOR_USER_ID = 11;
7606
8053
  const OFFICIAL_AUTHOR_FALLBACK_DISPLAY_NAME = "即我作者";
7607
8054
  const MAX_MESSAGE_COPY_LINK_ITEMS = 100;
7608
8055
  const RECORD_UID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
7609
- function numberValue$16(value) {
8056
+ function numberValue$15(value) {
7610
8057
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
7611
8058
  }
8059
+ function finiteNumberValue(value) {
8060
+ if (typeof value === "number" && Number.isFinite(value)) return value;
8061
+ if (typeof value === "string" && value.trim() !== "") {
8062
+ const parsed = Number(value);
8063
+ if (Number.isFinite(parsed)) return parsed;
8064
+ }
8065
+ }
8066
+ function positiveNumberValue$1(...values) {
8067
+ for (const value of values) {
8068
+ const parsed = finiteNumberValue(value);
8069
+ if (parsed !== void 0 && parsed > 0) return parsed;
8070
+ }
8071
+ }
8072
+ function nonNegativeNumberValue(...values) {
8073
+ for (const value of values) {
8074
+ const parsed = finiteNumberValue(value);
8075
+ if (parsed !== void 0 && parsed >= 0) return parsed;
8076
+ }
8077
+ }
7612
8078
  function booleanValue$8(value) {
7613
8079
  return value === true;
7614
8080
  }
8081
+ function timelineCaptureContext(payload) {
8082
+ const raw = objectValue$1(payload.capture_context ?? payload.captureContext);
8083
+ const clientName = stringValue$1(raw.client_name ?? raw.clientName ?? payload.client_name ?? payload.clientName ?? payload.device_name ?? payload.deviceName).trim();
8084
+ const networkName = stringValue$1(raw.network_name ?? raw.networkName ?? payload.network_name ?? payload.networkName ?? payload.network).trim();
8085
+ const electricity = objectValue$1(payload.electricity);
8086
+ const electricValue = finiteNumberValue(raw.electric ?? payload.electric ?? electricity.electric);
8087
+ const electric = electricValue === void 0 ? void 0 : Math.trunc(electricValue);
8088
+ const charge = Math.trunc(numberValue$15(raw.charge ?? payload.charge ?? electricity.charge));
8089
+ const context = {
8090
+ ...clientName === "" ? {} : { clientName },
8091
+ ...networkName === "" ? {} : { networkName },
8092
+ ...electric === void 0 || electric < 0 || electric > 100 ? {} : { electric },
8093
+ ...charge < 1 || charge > 3 ? {} : { charge }
8094
+ };
8095
+ return Object.keys(context).length === 0 ? void 0 : context;
8096
+ }
8097
+ function epochMillis(value) {
8098
+ const parsed = finiteNumberValue(value);
8099
+ if (parsed === void 0 || parsed <= 0) return void 0;
8100
+ return Math.trunc(parsed < 1e11 ? parsed * 1e3 : parsed);
8101
+ }
8102
+ /**
8103
+ * Record lifecycle timestamps are canonical fields of the record itself.
8104
+ * Payload and extra metadata may carry stale (or zero) copies, so they can
8105
+ * only be used as a final fallback. This matches the Flutter record parser,
8106
+ * which creates the Record timestamp model from record_core first.
8107
+ */
8108
+ function firstRecordEpochMillis(sources, keys) {
8109
+ for (const source of sources) for (const key of keys) {
8110
+ const value = epochMillis(source[key]);
8111
+ if (value !== void 0) return value;
8112
+ }
8113
+ }
8114
+ function firstSnapshotText(...values) {
8115
+ for (const value of values) {
8116
+ const text = stringValue$1(value).trim();
8117
+ if (text !== "") return text;
8118
+ }
8119
+ }
8120
+ function snapshotDateLabel(value) {
8121
+ if (value === void 0) return void 0;
8122
+ const date = new Date(value);
8123
+ if (Number.isNaN(date.getTime())) return void 0;
8124
+ return new Intl.DateTimeFormat("zh-CN", {
8125
+ year: "numeric",
8126
+ month: "2-digit",
8127
+ day: "2-digit"
8128
+ }).format(date);
8129
+ }
8130
+ function snapshotMovement(value) {
8131
+ const rawSpeed = value.speed ?? value.speed_mps ?? value.speedMetersPerSecond;
8132
+ const speed = numberValue$15(rawSpeed);
8133
+ if (typeof rawSpeed === "number" && Number.isFinite(rawSpeed)) {
8134
+ const kmh = Math.round(speed * 3.6);
8135
+ return kmh <= 2 ? "静止" : kmh <= 5 ? `缓慢移动(${String(kmh)}km/h)` : kmh <= 60 ? `移动(${String(kmh)}km/h)` : `高速移动(${String(kmh)}km/h)`;
8136
+ }
8137
+ if (typeof value.activity !== "number" || !Number.isFinite(value.activity)) return void 0;
8138
+ const activity = Math.trunc(value.activity);
8139
+ return activity === 0 ? "静止" : activity === 1 ? "步行" : activity === 2 ? "跑步" : activity === 3 ? "骑行" : activity === 4 ? "驾车" : void 0;
8140
+ }
8141
+ function snapshotLocationCapture(value) {
8142
+ const latitude = finiteNumberValue(value.lat ?? value.latitude);
8143
+ const longitude = finiteNumberValue(value.lon ?? value.lng ?? value.longitude);
8144
+ if (latitude === void 0 || longitude === void 0 || latitude === 0 && longitude === 0) return void 0;
8145
+ const altitudeMeters = nonNegativeNumberValue(value.alt ?? value.altitude ?? value.altitude_meters);
8146
+ const accuracyMeters = nonNegativeNumberValue(value.accuracy ?? value.accuracy_meters ?? value.accuracyMeters);
8147
+ const speedMetersPerSecond = nonNegativeNumberValue(value.speed ?? value.speed_mps ?? value.speedMetersPerSecond);
8148
+ return {
8149
+ latitude,
8150
+ longitude,
8151
+ capturedAtMillis: epochMillis(value.captured_at ?? value.capturedAt) ?? Date.now(),
8152
+ ...accuracyMeters === void 0 ? {} : { accuracyMeters },
8153
+ ...altitudeMeters === void 0 ? {} : { altitudeMeters },
8154
+ ...speedMetersPerSecond === void 0 ? {} : { speedMetersPerSecond }
8155
+ };
8156
+ }
8157
+ function snapshotWeatherText(...values) {
8158
+ for (const value of values) {
8159
+ const direct = stringValue$1(value).trim();
8160
+ if (direct !== "") return direct;
8161
+ const weather = objectValue$1(value);
8162
+ if (Object.keys(weather).length === 0) continue;
8163
+ const temperature = finiteNumberValue(weather.temp ?? weather.temperature);
8164
+ const condition = firstSnapshotText(weather.weather, weather.weatherText, weather.weather_text, weather.condition_ch, weather.conditionCh, weather.condition);
8165
+ if (temperature !== void 0 || condition !== void 0) return `${temperature === void 0 ? "" : `${String(Math.round(temperature))}°`}${temperature === void 0 || condition === void 0 ? "" : " "}${condition ?? ""}`.trim();
8166
+ }
8167
+ }
8168
+ function snapshotLocationContext(value) {
8169
+ const root = objectValue$1(value);
8170
+ const nested = objectValue$1(root.data);
8171
+ const hasContext = (candidate) => [
8172
+ candidate.location,
8173
+ candidate.position_detail,
8174
+ candidate.positionDetail,
8175
+ candidate.weather
8176
+ ].some((entry) => Object.keys(parsedObject(entry)).length > 0 || stringValue$1(entry).trim() !== "");
8177
+ return hasContext(root) || !hasContext(nested) ? root : nested;
8178
+ }
8179
+ /**
8180
+ * `/records/detail` and `/records/location/context/get` intentionally split
8181
+ * their metadata. Flutter overlays the latter onto the former, retaining
8182
+ * every existing location field while allowing its resolved weather and
8183
+ * address to win. Keep that same shape before projecting the dialog detail.
8184
+ */
8185
+ function mergeSnapshotLocationContext(raw, contextValue) {
8186
+ const context = snapshotLocationContext(contextValue);
8187
+ if (Object.keys(context).length === 0) return raw;
8188
+ const location = {
8189
+ ...parsedObject(raw.location),
8190
+ ...parsedObject(raw.location_detail),
8191
+ ...parsedObject(context.location),
8192
+ ...parsedObject(context.location_detail)
8193
+ };
8194
+ const position = {
8195
+ ...parsedObject(raw.position_detail),
8196
+ ...parsedObject(raw.positionDetail),
8197
+ ...parsedObject(context.position_detail),
8198
+ ...parsedObject(context.positionDetail)
8199
+ };
8200
+ const weather = context.weather ?? context.weather_text ?? context.weatherText ?? raw.weather;
8201
+ return {
8202
+ ...raw,
8203
+ ...Object.keys(location).length === 0 ? {} : { location },
8204
+ ...Object.keys(position).length === 0 ? {} : { position_detail: position },
8205
+ ...weather === void 0 ? {} : { weather }
8206
+ };
8207
+ }
8208
+ function snapshotDetailFromChatRaw(raw, fallback) {
8209
+ const relation = objectValue$1(raw.relation);
8210
+ const recordCore = objectValue$1(raw.record_core ?? raw.recordCore ?? raw.record ?? raw);
8211
+ const nestedRecord = objectValue$1(raw.record);
8212
+ const record = {
8213
+ ...recordCore,
8214
+ ...nestedRecord
8215
+ };
8216
+ const rootPayload = {
8217
+ ...parsedObject(raw.payload),
8218
+ ...parsedObject(raw.content_payload),
8219
+ ...parsedObject(raw.contentPayload),
8220
+ ...parsedObject(raw.record_payload),
8221
+ ...parsedObject(raw.recordPayload)
8222
+ };
8223
+ const recordPayload = {
8224
+ ...parsedObject(record.payload),
8225
+ ...parsedObject(record.content_payload),
8226
+ ...parsedObject(record.contentPayload),
8227
+ ...parsedObject(record.record_payload),
8228
+ ...parsedObject(record.recordPayload)
8229
+ };
8230
+ const extra = {
8231
+ ...parsedObject(raw.extra),
8232
+ ...parsedObject(raw.record_extra),
8233
+ ...parsedObject(raw.recordExtra),
8234
+ ...parsedObject(raw.e),
8235
+ ...parsedObject(raw.i)
8236
+ };
8237
+ const recordExtra = {
8238
+ ...parsedObject(record.extra),
8239
+ ...parsedObject(record.record_extra),
8240
+ ...parsedObject(record.recordExtra),
8241
+ ...parsedObject(record.e),
8242
+ ...parsedObject(record.i)
8243
+ };
8244
+ const payload = {
8245
+ ...extra,
8246
+ ...recordExtra,
8247
+ ...rootPayload,
8248
+ ...recordPayload
8249
+ };
8250
+ const position = {
8251
+ ...parsedObject(payload.position_detail),
8252
+ ...parsedObject(payload.positionDetail),
8253
+ ...parsedObject(record.position_detail),
8254
+ ...parsedObject(record.positionDetail),
8255
+ ...parsedObject(raw.position_detail),
8256
+ ...parsedObject(raw.positionDetail)
8257
+ };
8258
+ const location = {
8259
+ ...parsedObject(payload.location),
8260
+ ...parsedObject(record.location),
8261
+ ...parsedObject(raw.location)
8262
+ };
8263
+ const values = {
8264
+ ...raw,
8265
+ ...record,
8266
+ ...payload
8267
+ };
8268
+ const recordDurationMillis = positiveNumberValue$1(values.record_duration_millis, values.recordDurationMillis, values.cost_mill_sec, values.costMillSec);
8269
+ const editDurationMillis = positiveNumberValue$1(values.edit_duration_millis, values.editDurationMillis, values.incr_cost_mill_sec, values.incrCostMillSec);
8270
+ const lifecycleSources = [
8271
+ recordCore,
8272
+ nestedRecord,
8273
+ raw,
8274
+ payload
8275
+ ];
8276
+ const startAtMillis = firstRecordEpochMillis(lifecycleSources, [
8277
+ "create_at",
8278
+ "created_at",
8279
+ "createAt",
8280
+ "createdAt",
8281
+ "create_time",
8282
+ "createTime",
8283
+ "create_time_stamp",
8284
+ "createTimeStamp",
8285
+ "create_timestamp",
8286
+ "createTimestamp",
8287
+ "create_at_ms",
8288
+ "createAtMillis",
8289
+ "created_at_ms",
8290
+ "createdAtMillis",
8291
+ "send_at",
8292
+ "sendAt",
8293
+ "send_time",
8294
+ "sendTime",
8295
+ "send_time_stamp",
8296
+ "sendTimeStamp",
8297
+ "send_timestamp",
8298
+ "sendTimestamp",
8299
+ "send_at_ms",
8300
+ "sendAtMillis"
8301
+ ]) ?? epochMillis(relation.attach_at ?? relation.attachAt);
8302
+ const sendAtMillis = firstRecordEpochMillis(lifecycleSources, [
8303
+ "send_at",
8304
+ "sendAt",
8305
+ "send_time",
8306
+ "sendTime",
8307
+ "send_time_stamp",
8308
+ "sendTimeStamp",
8309
+ "send_timestamp",
8310
+ "sendTimestamp",
8311
+ "send_at_ms",
8312
+ "sendAtMillis"
8313
+ ]) ?? epochMillis(relation.attach_at ?? relation.attachAt) ?? epochMillis(fallback.sendAtMillis);
8314
+ const updatedAtMillis = firstRecordEpochMillis(lifecycleSources, [
8315
+ "update_at",
8316
+ "updated_at",
8317
+ "updateAt",
8318
+ "updatedAt",
8319
+ "update_time_stamp",
8320
+ "updateTimeStamp",
8321
+ "update_timestamp",
8322
+ "updateTimestamp",
8323
+ "update_at_ms",
8324
+ "updateAtMillis"
8325
+ ]);
8326
+ const completeAtMillis = updatedAtMillis !== void 0 && updatedAtMillis > (sendAtMillis ?? 0) ? updatedAtMillis : sendAtMillis;
8327
+ const syncedAtMillis = firstRecordEpochMillis(lifecycleSources, [
8328
+ "upload_at",
8329
+ "uploadAt",
8330
+ "upload_timestamp",
8331
+ "uploadTimeStamp",
8332
+ "upload_time_stamp_v2",
8333
+ "uploadTimeStampV2",
8334
+ "upload_at_v2",
8335
+ "uploadAtV2",
8336
+ "upload_at_ms",
8337
+ "uploadAtMillis"
8338
+ ]);
8339
+ const captureContext = timelineCaptureContext(values);
8340
+ const locationCapture = snapshotLocationCapture({
8341
+ ...location,
8342
+ ...position,
8343
+ ...objectValue$1(values.position)
8344
+ });
8345
+ const locationLabel = firstSnapshotText(position.poi, position.poi_name, position.poiName, position.address, position.road, location.poi_name, location.poiName, location.address, location.name);
8346
+ const weather = snapshotWeatherText(position.weather, position.weatherText, location.weather, values.weather);
8347
+ const altitudeMeters = nonNegativeNumberValue(location.altitude, location.alt, position.altitude, position.alt);
8348
+ const movement = snapshotMovement({
8349
+ ...values,
8350
+ ...location,
8351
+ ...position
8352
+ });
8353
+ const backgroundFiles = [
8354
+ ...listValue$15(values.file_assets),
8355
+ ...listValue$15(values.fileAssets),
8356
+ ...listValue$15(values.media_items),
8357
+ ...listValue$15(values.mediaItems),
8358
+ ...listValue$15(values.media_refs),
8359
+ ...listValue$15(values.mediaRefs),
8360
+ ...listValue$15(values.media_display_items),
8361
+ ...listValue$15(values.mediaDisplayItems),
8362
+ ...listValue$15(values.files),
8363
+ ...listValue$15(values.attachments)
8364
+ ].map(objectValue$1);
8365
+ const backgroundSound = backgroundFiles.some((file) => Math.trunc(numberValue$15(file.content_file_role ?? file.contentFileRole)) === 4) || backgroundFiles.some((file) => Math.trunc(numberValue$15(file.binding_type ?? file.bindingType)) === 4) || listValue$15(values.background_sound_amplitudes ?? values.backgroundSoundAmplitudes).length > 0 || listValue$15(parsedObject(values.background_sound ?? values.backgroundSound).amplitudes).length > 0 ? "available" : values.background_sound_enabled === false || values.backgroundSoundEnabled === false ? "disabled" : "not-recorded";
8366
+ const status = numberValue$15(values.status);
8367
+ const syncState = status === 2 ? "syncing" : status < 0 ? "failed" : syncedAtMillis !== void 0 || status === 1 ? "synced" : "not-synced";
8368
+ const belongDate = snapshotDateLabel(startAtMillis ?? completeAtMillis);
8369
+ return {
8370
+ itemUid: firstSnapshotText(relation.record_uid, values.record_uid, raw.record_uid) ?? fallback.itemUid,
8371
+ textContent: firstSnapshotText(record.text_content, record.textContent, values.text_content, values.textContent) ?? fallback.textContent,
8372
+ ...recordDurationMillis === void 0 ? {} : { recordDurationMillis },
8373
+ ...editDurationMillis === void 0 ? {} : { editDurationMillis },
8374
+ ...numberValue$15(values.view_times ?? values.viewTimes) > 0 ? { viewTimes: Math.trunc(numberValue$15(values.view_times ?? values.viewTimes)) } : {},
8375
+ ...numberValue$15(values.share_times ?? values.shareTimes) > 0 ? { shareTimes: Math.trunc(numberValue$15(values.share_times ?? values.shareTimes)) } : {},
8376
+ ...captureContext === void 0 ? {} : { captureContext },
8377
+ backgroundSound,
8378
+ ...locationLabel === void 0 ? {} : { locationLabel },
8379
+ ...weather === void 0 ? {} : { weather },
8380
+ ...altitudeMeters === void 0 ? {} : { altitudeMeters },
8381
+ ...movement === void 0 ? {} : { movement },
8382
+ ...belongDate === void 0 ? {} : { belongDate },
8383
+ ...startAtMillis === void 0 ? {} : { startAtMillis },
8384
+ ...completeAtMillis === void 0 ? {} : { completeAtMillis },
8385
+ ...syncedAtMillis === void 0 ? {} : { syncedAtMillis },
8386
+ syncState,
8387
+ ...locationCapture === void 0 ? {} : { locationCapture }
8388
+ };
8389
+ }
7615
8390
  function favoriteStickerPersistenceItem(item) {
7616
8391
  return {
7617
8392
  file_asset_uid: stringValue$1(item.file_asset_uid).trim(),
@@ -7619,15 +8394,15 @@ function favoriteStickerPersistenceItem(item) {
7619
8394
  file_hash: stringValue$1(item.file_hash).trim(),
7620
8395
  file_name: stringValue$1(item.file_name).trim(),
7621
8396
  mime_type: stringValue$1(item.mime_type).trim(),
7622
- file_kind: Math.trunc(numberValue$16(item.file_kind)),
7623
- file_type: Math.trunc(numberValue$16(item.file_type)),
8397
+ file_kind: Math.trunc(numberValue$15(item.file_kind)),
8398
+ file_type: Math.trunc(numberValue$15(item.file_type)),
7624
8399
  is_animated: booleanValue$8(item.is_animated),
7625
- file_size: Math.max(0, Math.trunc(numberValue$16(item.file_size))),
7626
- file_create_at: Math.max(0, Math.trunc(numberValue$16(item.file_create_at))),
7627
- file_push_at: Math.max(0, Math.trunc(numberValue$16(item.file_push_at)))
8400
+ file_size: Math.max(0, Math.trunc(numberValue$15(item.file_size))),
8401
+ file_create_at: Math.max(0, Math.trunc(numberValue$15(item.file_create_at))),
8402
+ file_push_at: Math.max(0, Math.trunc(numberValue$15(item.file_push_at)))
7628
8403
  };
7629
8404
  }
7630
- function listValue$16(value) {
8405
+ function listValue$15(value) {
7631
8406
  return Array.isArray(value) ? value : [];
7632
8407
  }
7633
8408
  function chatMemberRole$1(value) {
@@ -7642,7 +8417,7 @@ function chatMemberStatus$1(value) {
7642
8417
  if (value === "removed" || value === 3) return "removed";
7643
8418
  return "unknown";
7644
8419
  }
7645
- function integerLikeValue$1(value) {
8420
+ function integerLikeValue(value) {
7646
8421
  if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
7647
8422
  if (typeof value === "string" && value.trim() !== "") {
7648
8423
  const parsed = Number(value.trim());
@@ -7650,24 +8425,50 @@ function integerLikeValue$1(value) {
7650
8425
  }
7651
8426
  return 0;
7652
8427
  }
8428
+ function chatRecordOwnerUserId(relation, record, payload, senderUserId) {
8429
+ const candidates = [
8430
+ relation.record_owner_user_id,
8431
+ relation.recordOwnerUserId,
8432
+ relation.owner_user_id,
8433
+ relation.ownerUserId,
8434
+ record.record_owner_user_id,
8435
+ record.recordOwnerUserId,
8436
+ record.owner_user_id,
8437
+ record.ownerUserId,
8438
+ record.user_id,
8439
+ record.userId,
8440
+ payload.record_owner_user_id,
8441
+ payload.recordOwnerUserId,
8442
+ payload.owner_user_id,
8443
+ payload.ownerUserId,
8444
+ payload.user_id,
8445
+ payload.userId,
8446
+ senderUserId
8447
+ ];
8448
+ for (const candidate of candidates) {
8449
+ const userId = integerLikeValue(candidate);
8450
+ if (userId > 0) return userId;
8451
+ }
8452
+ return 0;
8453
+ }
7653
8454
  function epochMillisValue(value) {
7654
- const timestamp = integerLikeValue$1(value);
8455
+ const timestamp = integerLikeValue(value);
7655
8456
  return timestamp > 0 && timestamp < 1e11 ? timestamp * 1e3 : timestamp;
7656
8457
  }
7657
8458
  function messageCopyLinkMediaItemFromData(value) {
7658
8459
  const data = objectValue$1(value);
7659
8460
  return {
7660
- fileKind: integerLikeValue$1(data.file_kind),
8461
+ fileKind: integerLikeValue(data.file_kind),
7661
8462
  fileName: stringValue$1(data.file_name),
7662
- size: Math.max(0, integerLikeValue$1(data.size))
8463
+ size: Math.max(0, integerLikeValue(data.size))
7663
8464
  };
7664
8465
  }
7665
8466
  function messageCopyLinkStructuredContentFromData(value) {
7666
8467
  const data = objectValue$1(value);
7667
8468
  if (Object.keys(data).length === 0) return void 0;
7668
8469
  return {
7669
- structuredKind: integerLikeValue$1(data.structured_kind),
7670
- durationMillis: Math.max(0, integerLikeValue$1(data.duration_millis))
8470
+ structuredKind: integerLikeValue(data.structured_kind),
8471
+ durationMillis: Math.max(0, integerLikeValue(data.duration_millis))
7671
8472
  };
7672
8473
  }
7673
8474
  function messageCopyLinkSnapshotItemFromData(value) {
@@ -7682,10 +8483,10 @@ function messageCopyLinkSnapshotItemFromData(value) {
7682
8483
  title: stringValue$1(data.title),
7683
8484
  textContent: stringValue$1(data.text_content),
7684
8485
  sendAtMillis: epochMillisValue(data.send_at),
7685
- templateKind: integerLikeValue$1(data.template_kind),
7686
- displayKind: integerLikeValue$1(data.display_kind),
7687
- officialMark: integerLikeValue$1(data.official_mark),
7688
- mediaItems: listValue$16(data.media_items).map(messageCopyLinkMediaItemFromData),
8486
+ templateKind: integerLikeValue(data.template_kind),
8487
+ displayKind: integerLikeValue(data.display_kind),
8488
+ officialMark: integerLikeValue(data.official_mark),
8489
+ mediaItems: listValue$15(data.media_items).map(messageCopyLinkMediaItemFromData),
7689
8490
  ...structuredContent === void 0 ? {} : { structuredContent }
7690
8491
  };
7691
8492
  if (item.sendAtMillis <= 0 || item.senderDisplayName.trim() === "" && item.sourceKind !== "agent_message") throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
@@ -7693,14 +8494,14 @@ function messageCopyLinkSnapshotItemFromData(value) {
7693
8494
  return item;
7694
8495
  }
7695
8496
  function messageCopyLinkPresentationNodesFromData(value, itemCount, depth = 1, seenItemIndexes = /* @__PURE__ */ new Set()) {
7696
- const rawNodes = listValue$16(value);
8497
+ const rawNodes = listValue$15(value);
7697
8498
  if (rawNodes.length === 0) return [];
7698
8499
  if (depth > 8) throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
7699
8500
  return rawNodes.map((rawNode) => {
7700
8501
  const data = objectValue$1(rawNode);
7701
8502
  const kind = stringValue$1(data.kind);
7702
8503
  if (kind === "item") {
7703
- const itemIndex = integerLikeValue$1(data.item_index);
8504
+ const itemIndex = integerLikeValue(data.item_index);
7704
8505
  if (itemIndex < 0 || itemIndex >= itemCount || seenItemIndexes.has(itemIndex)) throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
7705
8506
  seenItemIndexes.add(itemIndex);
7706
8507
  return {
@@ -7712,7 +8513,7 @@ function messageCopyLinkPresentationNodesFromData(value, itemCount, depth = 1, s
7712
8513
  kind: "forward_bundle",
7713
8514
  title: stringValue$1(data.title),
7714
8515
  commentText: stringValue$1(data.comment_text),
7715
- createdAtMillis: integerLikeValue$1(data.created_at),
8516
+ createdAtMillis: integerLikeValue(data.created_at),
7716
8517
  senderDisplayName: stringValue$1(data.sender_display_name),
7717
8518
  children: messageCopyLinkPresentationNodesFromData(data.children, itemCount, depth + 1, seenItemIndexes)
7718
8519
  };
@@ -7724,8 +8525,8 @@ function messageCopyLinkSourceAnchorFromData(value) {
7724
8525
  return {
7725
8526
  relationUid: stringValue$1(data.rel_uid),
7726
8527
  recordUid: stringValue$1(data.record_uid),
7727
- recordOwnerUserId: integerLikeValue$1(data.record_owner_user_id),
7728
- sequence: integerLikeValue$1(data.seq)
8528
+ recordOwnerUserId: integerLikeValue(data.record_owner_user_id),
8529
+ sequence: integerLikeValue(data.seq)
7729
8530
  };
7730
8531
  }
7731
8532
  function firstTextValue(source, keys) {
@@ -7767,12 +8568,12 @@ function messageCopyLinkExtensionItemFromData(value) {
7767
8568
  const sendAtMillis = epochMillisValue(data.send_at ?? data.sendAt ?? data.created_at ?? data.createdAt ?? data.published_at ?? data.publishedAt ?? core.send_at ?? core.sendAt ?? core.created_at ?? core.createdAt ?? core.published_at ?? core.publishedAt);
7768
8569
  const title = stringValue$1(data.title ?? core.title);
7769
8570
  const textContent = stringValue$1(data.text_content ?? data.textContent ?? data.content ?? core.text_content ?? core.textContent ?? core.content);
7770
- const mediaItems = listValue$16(data.media_items ?? data.mediaItems ?? core.media_items ?? core.mediaItems).map(messageCopyLinkMediaItemFromData);
8571
+ const mediaItems = listValue$15(data.media_items ?? data.mediaItems ?? core.media_items ?? core.mediaItems).map(messageCopyLinkMediaItemFromData);
7771
8572
  const structuredContent = messageCopyLinkStructuredContentFromData(data.structured_content ?? data.structuredContent ?? core.structured_content ?? core.structuredContent);
7772
8573
  if (recordUid === "" || sendAtMillis <= 0 || title.trim() === "" && textContent.trim() === "" && mediaItems.length === 0 && structuredContent === void 0) return;
7773
8574
  return {
7774
8575
  recordUid,
7775
- level: Math.max(2, integerLikeValue$1(data.level) || 2),
8576
+ level: Math.max(2, integerLikeValue(data.level) || 2),
7776
8577
  sourceKind: stringValue$1(data.source_kind ?? data.sourceKind) || "record_extension",
7777
8578
  senderDisplayName,
7778
8579
  senderAvatarUrl: firstTextValue(data, [
@@ -7787,17 +8588,17 @@ function messageCopyLinkExtensionItemFromData(value) {
7787
8588
  title,
7788
8589
  textContent,
7789
8590
  sendAtMillis,
7790
- templateKind: integerLikeValue$1(data.template_kind ?? data.templateKind ?? core.template_kind ?? core.templateKind) || 1,
7791
- displayKind: integerLikeValue$1(data.display_kind ?? data.displayKind ?? core.display_kind ?? core.displayKind),
7792
- officialMark: integerLikeValue$1(data.official_mark ?? data.officialMark ?? core.official_mark ?? core.officialMark),
8591
+ templateKind: integerLikeValue(data.template_kind ?? data.templateKind ?? core.template_kind ?? core.templateKind) || 1,
8592
+ displayKind: integerLikeValue(data.display_kind ?? data.displayKind ?? core.display_kind ?? core.displayKind),
8593
+ officialMark: integerLikeValue(data.official_mark ?? data.officialMark ?? core.official_mark ?? core.officialMark),
7793
8594
  mediaItems,
7794
8595
  ...structuredContent === void 0 ? {} : { structuredContent }
7795
8596
  };
7796
8597
  }
7797
8598
  function messageCopyLinkRecordContextFromData(data) {
7798
8599
  const context = objectValue$1(data.record_context ?? data.recordContext);
7799
- const extensions = listValue$16(context.extensions ?? context.extend_records ?? context.extendRecords ?? context.list ?? data.extensions ?? data.extend_records ?? data.extendRecords ?? data.list).map(messageCopyLinkExtensionItemFromData).filter((item) => item !== void 0);
7800
- const extensionCount = Math.max(integerLikeValue$1(context.extension_count ?? context.extensionCount ?? context.total ?? data.extension_count ?? data.extensionCount ?? data.total), extensions.length);
8600
+ const extensions = listValue$15(context.extensions ?? context.extend_records ?? context.extendRecords ?? context.list ?? data.extensions ?? data.extend_records ?? data.extendRecords ?? data.list).map(messageCopyLinkExtensionItemFromData).filter((item) => item !== void 0);
8601
+ const extensionCount = Math.max(integerLikeValue(context.extension_count ?? context.extensionCount ?? context.total ?? data.extension_count ?? data.extensionCount ?? data.total), extensions.length);
7801
8602
  if (extensionCount <= 0 && extensions.length === 0) return void 0;
7802
8603
  extensions.sort((left, right) => right.sendAtMillis - left.sendAtMillis);
7803
8604
  return {
@@ -7845,7 +8646,7 @@ function parsedObject(value) {
7845
8646
  }
7846
8647
  function firstInteger(source, keys) {
7847
8648
  for (const key of keys) {
7848
- const value = integerLikeValue$1(source[key]);
8649
+ const value = integerLikeValue(source[key]);
7849
8650
  if (value > 0) return value;
7850
8651
  }
7851
8652
  return 0;
@@ -7883,7 +8684,7 @@ function resolveChatMemberDisplayNames(input) {
7883
8684
  };
7884
8685
  }
7885
8686
  function normalizedJoinTimestamp(value) {
7886
- const raw = integerLikeValue$1(value);
8687
+ const raw = integerLikeValue(value);
7887
8688
  if (raw <= 0) return 0;
7888
8689
  return raw < 1e11 ? raw * 1e3 : raw;
7889
8690
  }
@@ -7900,12 +8701,12 @@ function rawMemberDisplayName(item) {
7900
8701
  async function projectArkmeConversationMemberJoinEvents(rawItems, options) {
7901
8702
  const membersByUserId = /* @__PURE__ */ new Map();
7902
8703
  for (const item of rawItems) {
7903
- const userId = integerLikeValue$1(item.user_id ?? item.userId);
8704
+ const userId = integerLikeValue(item.user_id ?? item.userId);
7904
8705
  if (userId > 0) membersByUserId.set(userId, item);
7905
8706
  }
7906
8707
  const groups = /* @__PURE__ */ new Map();
7907
8708
  for (const item of rawItems) {
7908
- const inviteeUserId = integerLikeValue$1(item.user_id ?? item.userId);
8709
+ const inviteeUserId = integerLikeValue(item.user_id ?? item.userId);
7909
8710
  if (inviteeUserId <= 0) continue;
7910
8711
  const extra = parsedObject(item.extra);
7911
8712
  if (Object.keys(extra).length === 0) continue;
@@ -8011,7 +8812,7 @@ function agentSourceLabel(displayName) {
8011
8812
  function isAgentCreationSource(relation, record, payload) {
8012
8813
  const relationMetadata = objectValue$1(relation.metadata);
8013
8814
  const recordMetadata = objectValue$1(record.metadata);
8014
- return integerLikeValue$1(payload.creation_source ?? payload.creationSource) === 1 || integerLikeValue$1(record.creation_source ?? record.creationSource) === 1 || integerLikeValue$1(relation.creation_source ?? relation.creationSource) === 1 || integerLikeValue$1(recordMetadata.creation_source ?? recordMetadata.creationSource) === 1 || integerLikeValue$1(relationMetadata.creation_source ?? relationMetadata.creationSource) === 1;
8815
+ return integerLikeValue(payload.creation_source ?? payload.creationSource) === 1 || integerLikeValue(record.creation_source ?? record.creationSource) === 1 || integerLikeValue(relation.creation_source ?? relation.creationSource) === 1 || integerLikeValue(recordMetadata.creation_source ?? recordMetadata.creationSource) === 1 || integerLikeValue(relationMetadata.creation_source ?? relationMetadata.creationSource) === 1;
8015
8816
  }
8016
8817
  function agentDisplayNameFromTimeline(relation, record, payload) {
8017
8818
  const relationMetadata = objectValue$1(relation.metadata);
@@ -8090,7 +8891,7 @@ var ChatService = class {
8090
8891
  if (stringValue$1(data.chat_session_uid).trim() !== normalizedSessionUid) throw new ArkmePluginError("bot-chat-timeline-contract-invalid", "Bot Chat 时间线返回了不匹配的会话", true, 502);
8091
8892
  const projected = [];
8092
8893
  let latestSequence = 0;
8093
- for (const raw of listValue$16(data.items)) {
8894
+ for (const raw of listValue$15(data.items)) {
8094
8895
  const item = objectValue$1(raw);
8095
8896
  const relation = objectValue$1(item.relation);
8096
8897
  const record = objectValue$1(item.record);
@@ -8098,15 +8899,15 @@ var ChatService = class {
8098
8899
  const relationUid = stringValue$1(relation.rel_uid).trim();
8099
8900
  const recordUid = stringValue$1(relation.record_uid).trim();
8100
8901
  const hydratedRecordUid = stringValue$1(payload.record_uid).trim();
8101
- const sequence = Math.trunc(numberValue$16(relation.seq));
8102
- const actorKind = Math.trunc(numberValue$16(relation.sender_actor_kind));
8103
- const senderUserId = Math.trunc(numberValue$16(relation.sender_user_id));
8902
+ const sequence = Math.trunc(numberValue$15(relation.seq));
8903
+ const actorKind = Math.trunc(numberValue$15(relation.sender_actor_kind));
8904
+ const senderUserId = Math.trunc(numberValue$15(relation.sender_user_id));
8104
8905
  const senderBotUid = stringValue$1(relation.sender_bot_uid).trim();
8105
8906
  const userActor = actorKind === 1 && senderUserId === session.userId && senderBotUid === "";
8106
8907
  const botActor = actorKind === 2 && senderBotUid === normalizedBotId;
8107
8908
  if (relationUid === "" || recordUid === "" || hydratedRecordUid !== "" && hydratedRecordUid !== recordUid || !Number.isSafeInteger(sequence) || sequence <= 0 || !userActor && !botActor) throw new ArkmePluginError("bot-chat-timeline-contract-invalid", "Bot Chat 时间线包含无效消息身份", true, 502);
8108
8909
  latestSequence = Math.max(latestSequence, sequence);
8109
- if (numberValue$16(record.status) !== 1) continue;
8910
+ if (numberValue$15(record.status) !== 1) continue;
8110
8911
  const contentBlocks = this.media.richContentBlocks(item, session.userId);
8111
8912
  projected.push({
8112
8913
  messageId: relationUid,
@@ -8114,7 +8915,7 @@ var ChatService = class {
8114
8915
  role: userActor ? "user" : "assistant",
8115
8916
  content: stringValue$1(payload.text_content),
8116
8917
  status: "sent",
8117
- createdAtMillis: Math.max(0, Math.trunc(numberValue$16(relation.attach_at ?? payload.send_at))),
8918
+ createdAtMillis: Math.max(0, Math.trunc(numberValue$15(relation.attach_at ?? payload.send_at))),
8118
8919
  attachments: contentBlocks.map((block) => ({
8119
8920
  kind: block.kind,
8120
8921
  fileName: block.fileName,
@@ -8164,7 +8965,7 @@ var ChatService = class {
8164
8965
  const responseSessionUid = stringValue$1(result.chat_session_uid).trim();
8165
8966
  const responseRecordUid = stringValue$1(result.record_uid).trim();
8166
8967
  const responseRelationUid = stringValue$1(result.rel_uid).trim();
8167
- const sequence = Math.trunc(numberValue$16(result.seq));
8968
+ const sequence = Math.trunc(numberValue$15(result.seq));
8168
8969
  if (responseSessionUid !== chatSessionUidValue || responseRecordUid !== recordUid || responseRelationUid !== relationUid || !Number.isSafeInteger(sequence) || sequence <= 0) throw new ArkmePluginError("bot-conversation-send-outcome-unknown", "消息可能已发送,但服务端确认不完整;请刷新会话确认", false, 409);
8169
8970
  this.realtime.scheduleChatSessionProjection(chatSessionUidValue, sequence);
8170
8971
  return {
@@ -8183,22 +8984,22 @@ var ChatService = class {
8183
8984
  }
8184
8985
  async directBotNotificationPreference(chatSessionUid, options = {}) {
8185
8986
  const { policy } = await this.directBotPolicy(chatSessionUid, options.signal);
8186
- return { muted: numberValue$16(policy.mute_state) === 2 || numberValue$16(policy.notify_state) === 2 };
8987
+ return { muted: numberValue$15(policy.mute_state) === 2 || numberValue$15(policy.notify_state) === 2 };
8187
8988
  }
8188
8989
  async updateDirectBotNotificationPreference(chatSessionUid, muted, options = {}) {
8189
8990
  const { session, sessionUid, policy } = await this.directBotPolicy(chatSessionUid, options.signal);
8190
- const updateAt = Math.max(Date.now(), numberValue$16(policy.update_at) + 1);
8991
+ const updateAt = Math.max(Date.now(), numberValue$15(policy.update_at) + 1);
8191
8992
  const updated = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/update", {
8192
8993
  chat_session_uid: sessionUid,
8193
- show_in_home_state: numberValue$16(policy.show_in_home_state),
8194
- privacy_state: numberValue$16(policy.privacy_state),
8994
+ show_in_home_state: numberValue$15(policy.show_in_home_state),
8995
+ privacy_state: numberValue$15(policy.privacy_state),
8195
8996
  mute_state: muted ? 2 : 1,
8196
- pin_state: numberValue$16(policy.pin_state),
8997
+ pin_state: numberValue$15(policy.pin_state),
8197
8998
  notify_state: muted ? 2 : 1,
8198
- status: numberValue$16(policy.status),
8999
+ status: numberValue$15(policy.status),
8199
9000
  update_at: updateAt
8200
9001
  }, session, options.signal);
8201
- if (stringValue$1(updated.chat_session_uid).trim() !== sessionUid || numberValue$16(updated.user_id) !== session.userId || numberValue$16(updated.show_in_home_state) !== numberValue$16(policy.show_in_home_state) || numberValue$16(updated.privacy_state) !== numberValue$16(policy.privacy_state) || numberValue$16(updated.mute_state) !== (muted ? 2 : 1) || numberValue$16(updated.pin_state) !== numberValue$16(policy.pin_state) || numberValue$16(updated.notify_state) !== (muted ? 2 : 1) || numberValue$16(updated.status) !== numberValue$16(policy.status) || !Number.isSafeInteger(numberValue$16(updated.update_at)) || numberValue$16(updated.update_at) < updateAt) throw new ArkmePluginError("bot-chat-policy-contract-invalid", "Bot Chat 通知策略更新确认不完整", true, 502);
9002
+ if (stringValue$1(updated.chat_session_uid).trim() !== sessionUid || numberValue$15(updated.user_id) !== session.userId || numberValue$15(updated.show_in_home_state) !== numberValue$15(policy.show_in_home_state) || numberValue$15(updated.privacy_state) !== numberValue$15(policy.privacy_state) || numberValue$15(updated.mute_state) !== (muted ? 2 : 1) || numberValue$15(updated.pin_state) !== numberValue$15(policy.pin_state) || numberValue$15(updated.notify_state) !== (muted ? 2 : 1) || numberValue$15(updated.status) !== numberValue$15(policy.status) || !Number.isSafeInteger(numberValue$15(updated.update_at)) || numberValue$15(updated.update_at) < updateAt) throw new ArkmePluginError("bot-chat-policy-contract-invalid", "Bot Chat 通知策略更新确认不完整", true, 502);
8202
9003
  const cacheKey = `${String(session.userId)}:${sessionUid}`;
8203
9004
  const cached = this.source.cachedChatSourceByKey(cacheKey);
8204
9005
  if (cached !== void 0) this.source.setChatSourceByKey(cacheKey, {
@@ -8223,15 +9024,15 @@ var ChatService = class {
8223
9024
  if (sessionUid === "") throw new ArkmePluginError("bot-chat-target-invalid", "Bot Chat 会话目标无效", false, 400);
8224
9025
  const session = await this.runtime.requireSession();
8225
9026
  const policy = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: sessionUid }, session, signal);
8226
- const updateAt = numberValue$16(policy.update_at);
8227
- if (stringValue$1(policy.chat_session_uid).trim() !== sessionUid || numberValue$16(policy.user_id) !== session.userId || ![
9027
+ const updateAt = numberValue$15(policy.update_at);
9028
+ if (stringValue$1(policy.chat_session_uid).trim() !== sessionUid || numberValue$15(policy.user_id) !== session.userId || ![
8228
9029
  "show_in_home_state",
8229
9030
  "privacy_state",
8230
9031
  "mute_state",
8231
9032
  "pin_state",
8232
9033
  "notify_state",
8233
9034
  "status"
8234
- ].every((key) => Number.isSafeInteger(numberValue$16(policy[key])) && numberValue$16(policy[key]) > 0) || !Number.isSafeInteger(updateAt) || updateAt <= 0 || updateAt >= Number.MAX_SAFE_INTEGER) throw new ArkmePluginError("bot-chat-policy-contract-invalid", "Bot Chat 通知策略响应不完整", true, 502);
9035
+ ].every((key) => Number.isSafeInteger(numberValue$15(policy[key])) && numberValue$15(policy[key]) > 0) || !Number.isSafeInteger(updateAt) || updateAt <= 0 || updateAt >= Number.MAX_SAFE_INTEGER) throw new ArkmePluginError("bot-chat-policy-contract-invalid", "Bot Chat 通知策略响应不完整", true, 502);
8235
9036
  return {
8236
9037
  session,
8237
9038
  sessionUid,
@@ -8287,8 +9088,8 @@ var ChatService = class {
8287
9088
  key: `member-records:${source.ownerRef}:${String(reference.targetUserId)}:${mode}:${String(Math.max(0, Math.trunc(options.beforeSequence ?? 0)))}`,
8288
9089
  failureCooldownMs: 2e3
8289
9090
  });
8290
- const items = await this.projectChatTimelineItems(listValue$16(data.items), source, session, options.signal);
8291
- const nextBeforeSequence = Math.max(0, Math.trunc(numberValue$16(data.next_before_seq)));
9091
+ const items = await this.projectChatTimelineItems(listValue$15(data.items), source, session, options.signal);
9092
+ const nextBeforeSequence = Math.max(0, Math.trunc(numberValue$15(data.next_before_seq)));
8292
9093
  return {
8293
9094
  source: await this.source.sourceItem(source),
8294
9095
  member,
@@ -8304,7 +9105,7 @@ var ChatService = class {
8304
9105
  if (source.kind !== "group_chat" && source.kind !== "private_chat") throw new ArkmePluginError("chat-members-source-invalid", "仅支持从聊天成员发起私聊", false);
8305
9106
  const reference = await this.openChatMemberRef(memberRef, session.userId, source.ownerRef);
8306
9107
  if (reference.targetUserId === session.userId) throw new ArkmePluginError("private-chat-self-invalid", "不能给自己发起私聊", false, 409);
8307
- const rawMember = (await this.rawChatMembers(source.ownerRef, true, session, options.signal)).find((item) => Math.trunc(numberValue$16(item.user_id)) === reference.targetUserId);
9108
+ const rawMember = (await this.rawChatMembers(source.ownerRef, true, session, options.signal)).find((item) => Math.trunc(numberValue$15(item.user_id)) === reference.targetUserId);
8308
9109
  if (rawMember === void 0) throw new ArkmePluginError("chat-member-ref-stale", "该成员已不属于当前会话,请刷新后重试", false, 409);
8309
9110
  const displayName = stringValue$1(rawMember.remark).trim() || stringValue$1(rawMember.display_name_snapshot).trim() || "群成员";
8310
9111
  return await this.openPrivateChatFromUser(reference.targetUserId, {
@@ -8335,7 +9136,7 @@ var ChatService = class {
8335
9136
  const uid = stringValue$1(chatSession.chat_session_uid).trim();
8336
9137
  if (uid === "") throw new ArkmePluginError("private-chat-contract-invalid", "私聊会话响应不完整", true, 502);
8337
9138
  const unread = objectValue$1(data.unread_snapshot);
8338
- const latestSequence = numberValue$16(unread.session_last_seq ?? chatSession.last_seq);
9139
+ const latestSequence = numberValue$15(unread.session_last_seq ?? chatSession.last_seq);
8339
9140
  const source = {
8340
9141
  sourceRef: await this.source.sealSourceRef(session.userId, "private_chat", uid, displayName),
8341
9142
  sourceKey: await this.source.chatDirectorySourceKey(session.userId, uid),
@@ -8343,8 +9144,8 @@ var ChatService = class {
8343
9144
  kind: "private_chat",
8344
9145
  displayName,
8345
9146
  ...profile?.avatarUrl === void 0 ? {} : { avatarRef: await this.profile.sealProfileImageRef(session.userId, peerUserId) },
8346
- activeAtMillis: numberValue$16(chatSession.last_active_at) || Date.now(),
8347
- unreadCount: numberValue$16(unread.unread_count),
9147
+ activeAtMillis: numberValue$15(chatSession.last_active_at) || Date.now(),
9148
+ unreadCount: numberValue$15(unread.unread_count),
8348
9149
  ...latestSequence > 0 ? { latestSequence } : {}
8349
9150
  };
8350
9151
  this.source.setChatSourceByKey(`${String(session.userId)}:${uid}`, source);
@@ -8360,14 +9161,14 @@ var ChatService = class {
8360
9161
  client_name: "DSH",
8361
9162
  locs: []
8362
9163
  }, session, options.signal);
8363
- const rmSubjectId = Math.trunc(numberValue$16(created.rm_subject_id));
9164
+ const rmSubjectId = Math.trunc(numberValue$15(created.rm_subject_id));
8364
9165
  if (!Number.isSafeInteger(rmSubjectId) || rmSubjectId <= 0) {
8365
9166
  if (booleanValue$8(created.already_exist)) throw new ArkmePluginError("private-chat-self-invalid", "不能给自己发起私聊", false, 409);
8366
9167
  throw new ArkmePluginError("official-author-chat-contract-invalid", "联系作者私聊响应不完整", true, 502);
8367
9168
  }
8368
- const partner = listValue$16((await this.runtime.authenticatedSubjectPost("/api/v1/private/get-partner-info-v2", { rm_subject_ids: [rmSubjectId] }, session, options.signal)).item_ls).map((item) => objectValue$1(item)).find((item) => Math.trunc(numberValue$16(item.rm_subject_id)) === rmSubjectId);
9169
+ const partner = listValue$15((await this.runtime.authenticatedSubjectPost("/api/v1/private/get-partner-info-v2", { rm_subject_ids: [rmSubjectId] }, session, options.signal)).item_ls).map((item) => objectValue$1(item)).find((item) => Math.trunc(numberValue$15(item.rm_subject_id)) === rmSubjectId);
8369
9170
  if (partner === void 0) throw new ArkmePluginError("official-author-chat-contract-invalid", "联系作者私聊资料缺失,请稍后重试", true, 502);
8370
- const peerUserId = Math.trunc(numberValue$16(partner.user_id));
9171
+ const peerUserId = Math.trunc(numberValue$15(partner.user_id));
8371
9172
  if (!Number.isSafeInteger(peerUserId) || peerUserId <= 0) throw new ArkmePluginError("official-author-chat-contract-invalid", "联系作者账号资料缺失,请稍后重试", true, 502);
8372
9173
  const displayName = stringValue$1(partner.mark).trim() || stringValue$1(partner.nick_name).trim() || "作者";
8373
9174
  return await this.openPrivateChatFromUser(peerUserId, {
@@ -8420,8 +9221,9 @@ var ChatService = class {
8420
9221
  ...options.cursor?.sendAtMillis === void 0 ? {} : { cursor_send_at: options.cursor.sendAtMillis },
8421
9222
  ...options.cursor?.itemUid === void 0 ? {} : { cursor_record_uid: options.cursor.itemUid }
8422
9223
  }, session, options.signal);
8423
- const rawRecords = listValue$16(data.items).filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
9224
+ const rawRecords = listValue$15(data.items).filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
8424
9225
  const media = await this.media.hydrateRecordMediaPage(rawRecords, session, options.signal);
9226
+ const signingKey = await this.runtime.stateStore.uniqueCode();
8425
9227
  const items = (await Promise.all(rawRecords.map(async (raw) => {
8426
9228
  const recordUid = this.record.recordUid(raw);
8427
9229
  const displayItems = media.displayItemsByRecordUid.get(recordUid);
@@ -8438,8 +9240,8 @@ var ChatService = class {
8438
9240
  } },
8439
9241
  mediaUnavailable: media.unavailableRecordUids.has(recordUid)
8440
9242
  });
8441
- }))).filter((item) => item.itemUid !== "");
8442
- const nextSendAt = numberValue$16(data.next_cursor_send_at);
9243
+ }))).filter((item) => item.itemUid !== "").map((item) => this.withRecordMessageActionRef(source, item, session.userId, signingKey));
9244
+ const nextSendAt = numberValue$15(data.next_cursor_send_at);
8443
9245
  const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
8444
9246
  return {
8445
9247
  source: await this.source.sourceItem(source),
@@ -8476,8 +9278,9 @@ var ChatService = class {
8476
9278
  ...options.cursor?.itemUid === void 0 ? {} : { cursor_record_uid: options.cursor.itemUid }
8477
9279
  }, session, options.signal);
8478
9280
  if (arkmePrivacyLockedTopic(data.topic_core)) throw new ArkmePluginError("topic-privacy-locked", "隐私锁主题不能在 Arkme 插件中查看", false, 403);
8479
- const rawRecords = listValue$16(data.records).filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
9281
+ const rawRecords = listValue$15(data.records).filter((raw) => !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.record.recordUid(raw)));
8480
9282
  const media = await this.media.hydrateRecordMediaPage(rawRecords, session, options.signal);
9283
+ const signingKey = await this.runtime.stateStore.uniqueCode();
8481
9284
  const records = rawRecords.map((raw) => {
8482
9285
  const recordUid = this.record.recordUid(raw);
8483
9286
  const displayItems = media.displayItemsByRecordUid.get(recordUid);
@@ -8486,11 +9289,11 @@ var ChatService = class {
8486
9289
  mediaUnavailable: media.unavailableRecordUids.has(recordUid)
8487
9290
  });
8488
9291
  });
8489
- const nextSendAt = numberValue$16(data.next_cursor_send_at);
9292
+ const nextSendAt = numberValue$15(data.next_cursor_send_at);
8490
9293
  const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
8491
9294
  return {
8492
9295
  source: await this.source.sourceItem(source),
8493
- items: records,
9296
+ items: records.map((item) => this.withRecordMessageActionRef(source, item, session.userId, signingKey)),
8494
9297
  hasMore: data.has_more === true,
8495
9298
  ...nextSendAt > 0 && nextUid !== "" ? { nextCursor: {
8496
9299
  sendAtMillis: nextSendAt,
@@ -8508,8 +9311,8 @@ var ChatService = class {
8508
9311
  key: `timeline:${source.ownerRef}:${String(Math.max(0, Math.trunc(options.cursor?.beforeSequence ?? 0)))}:${String(limit)}`,
8509
9312
  failureCooldownMs: 2e3
8510
9313
  });
8511
- const items = await this.projectChatTimelineItems(listValue$16(data.items), source, session, options.signal);
8512
- const beforeSequence = numberValue$16(data.next_before_seq);
9314
+ const items = await this.projectChatTimelineItems(listValue$15(data.items), source, session, options.signal);
9315
+ const beforeSequence = numberValue$15(data.next_before_seq);
8513
9316
  let aiPolishSettings;
8514
9317
  let aiPolishNotices;
8515
9318
  if (aiPolishDecorations !== void 0) {
@@ -8548,7 +9351,7 @@ var ChatService = class {
8548
9351
  return {
8549
9352
  messageRef,
8550
9353
  reportUid,
8551
- status: numberValue$16(report.status)
9354
+ status: numberValue$15(report.status)
8552
9355
  };
8553
9356
  }
8554
9357
  async messageReadReceiptSummaries(sourceRef, rawItems, options = {}) {
@@ -8565,15 +9368,15 @@ var ChatService = class {
8565
9368
  if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef) throw new ArkmePluginError("message-read-receipt-invalid-response", "消息已读状态服务返回了不匹配的会话", true, 502);
8566
9369
  const requestedKeys = new Set(items.map((item) => this.readReceiptItemKey(item.itemUid, item.sequence)));
8567
9370
  const summaries = /* @__PURE__ */ new Map();
8568
- for (const raw of listValue$16(data.items)) {
9371
+ for (const raw of listValue$15(data.items)) {
8569
9372
  const item = objectValue$1(raw);
8570
9373
  const itemUid = stringValue$1(item.record_uid).trim();
8571
- const sequence = Math.trunc(numberValue$16(item.seq));
9374
+ const sequence = Math.trunc(numberValue$15(item.seq));
8572
9375
  const key = this.readReceiptItemKey(itemUid, sequence);
8573
9376
  const rowSessionUid = stringValue$1(item.chat_session_uid).trim();
8574
- const readCount = Math.trunc(numberValue$16(item.read_count));
8575
- const unreadCount = Math.trunc(numberValue$16(item.unread_count));
8576
- const totalMemberCount = Math.trunc(numberValue$16(item.total_member_count));
9377
+ const readCount = Math.trunc(numberValue$15(item.read_count));
9378
+ const unreadCount = Math.trunc(numberValue$15(item.unread_count));
9379
+ const totalMemberCount = Math.trunc(numberValue$15(item.total_member_count));
8577
9380
  if (!requestedKeys.has(key) || summaries.has(key) || rowSessionUid !== source.ownerRef || typeof item.seq !== "number" || !Number.isSafeInteger(item.seq) || typeof item.read_count !== "number" || !Number.isSafeInteger(item.read_count) || typeof item.unread_count !== "number" || !Number.isSafeInteger(item.unread_count) || typeof item.total_member_count !== "number" || !Number.isSafeInteger(item.total_member_count) || readCount < 0 || unreadCount < 0 || totalMemberCount < 0 || readCount + unreadCount !== totalMemberCount) throw new ArkmePluginError("message-read-receipt-invalid-response", "消息已读状态服务返回无效", true, 502);
8578
9381
  summaries.set(key, {
8579
9382
  itemUid,
@@ -8604,13 +9407,13 @@ var ChatService = class {
8604
9407
  record_uid: message.itemUid,
8605
9408
  seq: message.sequence
8606
9409
  }, session, options.signal);
8607
- if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef || stringValue$1(data.record_uid).trim() !== message.itemUid || typeof data.seq !== "number" || !Number.isSafeInteger(data.seq) || Math.trunc(numberValue$16(data.seq)) !== message.sequence) throw new ArkmePluginError("message-read-receipt-invalid-response", "成员已读详情服务返回了不匹配的消息", true, 502);
8608
- const rawMembers = listValue$16(data.items).map(objectValue$1);
9410
+ if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef || stringValue$1(data.record_uid).trim() !== message.itemUid || typeof data.seq !== "number" || !Number.isSafeInteger(data.seq) || Math.trunc(numberValue$15(data.seq)) !== message.sequence) throw new ArkmePluginError("message-read-receipt-invalid-response", "成员已读详情服务返回了不匹配的消息", true, 502);
9411
+ const rawMembers = listValue$15(data.items).map(objectValue$1);
8609
9412
  const seenUserIds = /* @__PURE__ */ new Set();
8610
9413
  const receiptMembers = rawMembers.map((item) => {
8611
- const userId = Math.trunc(numberValue$16(item.user_id));
9414
+ const userId = Math.trunc(numberValue$15(item.user_id));
8612
9415
  const readStatus = stringValue$1(item.read_status).trim();
8613
- const readAtMillis = Math.trunc(numberValue$16(item.read_at));
9416
+ const readAtMillis = Math.trunc(numberValue$15(item.read_at));
8614
9417
  if (typeof item.user_id !== "number" || !Number.isSafeInteger(item.user_id) || typeof item.read_at !== "number" || !Number.isSafeInteger(item.read_at) || !Number.isSafeInteger(userId) || userId <= 0 || userId === session.userId || seenUserIds.has(userId) || readStatus !== "read" && readStatus !== "unread" || readAtMillis < 0 || readStatus === "unread" && readAtMillis !== 0) throw new ArkmePluginError("message-read-receipt-invalid-response", "成员已读详情服务返回无效", true, 502);
8615
9418
  seenUserIds.add(userId);
8616
9419
  return {
@@ -8724,7 +9527,7 @@ var ChatService = class {
8724
9527
  if (!/^[0-9A-Za-z]{16}$/.test(normalizedSid)) throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
8725
9528
  const session = await this.runtime.requireSession();
8726
9529
  const data = await this.runtime.authenticatedChatPost("/api/v1/chats/messages/copy-link/resolve", { sid: normalizedSid }, session, options.signal);
8727
- const rawItems = listValue$16(data.items);
9530
+ const rawItems = listValue$15(data.items);
8728
9531
  if (rawItems.length === 0 && stringValue$1(data.audit_status) === "auditing") throw new ArkmePluginError("message-copy-link-auditing", "审核中", true, 409);
8729
9532
  const items = rawItems.map(messageCopyLinkSnapshotItemFromData);
8730
9533
  if (items.length === 0 || items.length > MAX_MESSAGE_COPY_LINK_ITEMS) throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
@@ -8732,7 +9535,7 @@ var ChatService = class {
8732
9535
  const sourceContext = objectValue$1(data.source_context);
8733
9536
  const accessMode = stringValue$1(data.access_mode);
8734
9537
  if (accessMode !== "normal" && accessMode !== "link_read_only") throw new ArkmePluginError("message-copy-link-unavailable", "链接暂不可用", false, 404);
8735
- const anchors = accessMode === "normal" ? listValue$16(sourceContext.anchors).map(messageCopyLinkSourceAnchorFromData).filter((anchor) => anchor.relationUid.trim() !== "" && anchor.recordUid.trim() !== "" && anchor.recordOwnerUserId > 0) : [];
9538
+ const anchors = accessMode === "normal" ? listValue$15(sourceContext.anchors).map(messageCopyLinkSourceAnchorFromData).filter((anchor) => anchor.relationUid.trim() !== "" && anchor.recordUid.trim() !== "" && anchor.recordOwnerUserId > 0) : [];
8736
9539
  const recordContext = mergeMessageCopyLinkRecordContexts(messageCopyLinkRecordContextFromData(data), accessMode === "normal" ? await this.loadMessageCopyLinkPublicExtensions(messageCopyLinkRecordUidCandidates(items, anchors), session, options.signal) : void 0);
8737
9540
  const result = {
8738
9541
  sid: stringValue$1(data.sid),
@@ -8769,8 +9572,8 @@ var ChatService = class {
8769
9572
  lane: "interactive-read",
8770
9573
  bypassCache: true
8771
9574
  });
8772
- const rawItems = listValue$16(data.list ?? data.items);
8773
- if (offset === 0) total = Math.max(0, integerLikeValue$1(data.total));
9575
+ const rawItems = listValue$15(data.list ?? data.items);
9576
+ if (offset === 0) total = Math.max(0, integerLikeValue(data.total));
8774
9577
  const pageItems = rawItems.map((raw) => messageCopyLinkExtensionItemFromData(raw)).filter((item) => item !== void 0);
8775
9578
  extensions.push(...pageItems);
8776
9579
  if (rawItems.length === 0) break;
@@ -8839,7 +9642,7 @@ var ChatService = class {
8839
9642
  sid: detail.sid,
8840
9643
  recordUid: publishedRecordUid,
8841
9644
  parentRecordUid,
8842
- status: numberValue$16(data.status ?? data.check_status ?? recordResult.status),
9645
+ status: numberValue$15(data.status ?? data.check_status ?? recordResult.status),
8843
9646
  localState: "synced",
8844
9647
  extension: {
8845
9648
  recordUid: publishedRecordUid,
@@ -8909,12 +9712,12 @@ var ChatService = class {
8909
9712
  ...commentText === "" ? {} : { comment_text: commentText },
8910
9713
  send_at: sendAtMillis
8911
9714
  }, session, options.signal);
8912
- const sequence = numberValue$16(data.seq ?? data.sequence);
9715
+ const sequence = numberValue$15(data.seq ?? data.sequence);
8913
9716
  this.realtime.scheduleChatSessionProjection(targetSource.ownerRef, sequence);
8914
9717
  return {
8915
9718
  sourceRef: targetSourceRef,
8916
9719
  itemUid: stringValue$1(data.record_uid).trim() || recordUid,
8917
- status: numberValue$16(data.audit_status ?? data.status) || 1,
9720
+ status: numberValue$15(data.audit_status ?? data.status) || 1,
8918
9721
  ...sequence > 0 ? { sequence } : {},
8919
9722
  localState: "synced"
8920
9723
  };
@@ -8933,7 +9736,7 @@ var ChatService = class {
8933
9736
  return await appendCommentWarning({
8934
9737
  sourceRef: targetSourceRef,
8935
9738
  itemUid: stringValue$1(data.record_uid).trim() || recordUid,
8936
- status: numberValue$16(data.status),
9739
+ status: numberValue$15(data.status),
8937
9740
  localState: "synced"
8938
9741
  });
8939
9742
  }
@@ -8949,7 +9752,7 @@ var ChatService = class {
8949
9752
  return await appendCommentWarning({
8950
9753
  sourceRef: targetSourceRef,
8951
9754
  itemUid: stringValue$1(data.record_uid).trim() || recordUid,
8952
- status: numberValue$16(data.status),
9755
+ status: numberValue$15(data.status),
8953
9756
  localState: "synced"
8954
9757
  });
8955
9758
  }
@@ -8960,7 +9763,10 @@ var ChatService = class {
8960
9763
  if (text === "" || text.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("source-text-invalid", "发送内容为空或超过长度限制", false);
8961
9764
  const recordUid = options.recordUid?.trim() || randomUUID();
8962
9765
  if (source.kind === "send_to_self" || source.kind === "default_category") {
8963
- const result = await this.record.createTextForConversation(recordUid, text);
9766
+ const result = await this.record.createTextForConversation(recordUid, text, {
9767
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9768
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
9769
+ });
8964
9770
  if (result.localState !== "failed") this.source.invalidateSourceListCache(session.userId, "send_to_self");
8965
9771
  return {
8966
9772
  sourceRef,
@@ -8971,19 +9777,22 @@ var ChatService = class {
8971
9777
  };
8972
9778
  }
8973
9779
  if (source.kind === "topic") {
9780
+ const captureContext = options.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(options.captureContext);
8974
9781
  const result = await this.runtime.authenticatedPost("/api/v1/topics/records/create", {
8975
9782
  topic_uid: source.ownerRef,
8976
9783
  record_uid: recordUid,
8977
9784
  template_kind: 1,
8978
9785
  title: "",
8979
9786
  text_content: text,
9787
+ ...Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) === 0 ? {} : { record_duration_millis: Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) },
9788
+ ...captureContext === void 0 || Object.keys(captureContext).length === 0 ? {} : { capture_context: captureContext },
8980
9789
  send_at: Date.now()
8981
9790
  }, session);
8982
9791
  this.source.invalidateSourceListCache(session.userId, "send_to_self");
8983
9792
  return {
8984
9793
  sourceRef,
8985
9794
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
8986
- status: numberValue$16(result.status),
9795
+ status: numberValue$15(result.status),
8987
9796
  localState: "synced"
8988
9797
  };
8989
9798
  }
@@ -8992,20 +9801,38 @@ var ChatService = class {
8992
9801
  let sent;
8993
9802
  if (source.kind === "group_chat") {
8994
9803
  if ((options.botRefs?.length ?? 0) > 0 && ((options.humanMentions?.length ?? 0) > 0 || (options.botMentions?.length ?? 0) > 0)) throw new ArkmePluginError("mention-kind-conflict", "bot_refs 不能和结构化 mention 同时使用", false);
8995
- if (options.botRefs !== void 0 && options.botRefs.length > 0) sent = await this.groupBotMentionSend(sourceRef, source, text, options.botRefs, recordUid, relationUid, session, options.signal, { agentAuthored });
9804
+ if (options.botRefs !== void 0 && options.botRefs.length > 0) sent = await this.groupBotMentionSend(sourceRef, source, text, options.botRefs, recordUid, relationUid, session, options.signal, {
9805
+ agentAuthored,
9806
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9807
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
9808
+ });
8996
9809
  else if ((options.humanMentions?.length ?? 0) > 0 || (options.botMentions?.length ?? 0) > 0) {
8997
9810
  const contentPayload = await this.humanMentionContentPayload(source, textContent, text, options.humanMentions ?? [], session, options.signal, options.botMentions ?? []);
8998
- sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, contentPayload, options.signal, { agentAuthored });
9811
+ sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, contentPayload, options.signal, {
9812
+ agentAuthored,
9813
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9814
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
9815
+ });
8999
9816
  } else sent = await this.aiPolish.sendGroupSourceTextWithAiPolish(sourceRef, source.ownerRef, text, recordUid, relationUid, session, {
9000
9817
  agentAuthored,
9818
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9819
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext },
9001
9820
  ...options.signal === void 0 ? {} : { signal: options.signal }
9002
9821
  });
9003
9822
  } else if ((options.humanMentions?.length ?? 0) > 0) throw new ArkmePluginError("mention-group-required", "真人 mention 只能发送到群聊", false);
9004
9823
  else if ((options.botRefs?.length ?? 0) > 0) throw new ArkmePluginError("mention-group-required", "bot_refs 只能发送到群聊", false);
9005
9824
  else if ((options.botMentions?.length ?? 0) > 0) {
9006
9825
  const contentPayload = await this.humanMentionContentPayload(source, textContent, text, [], session, options.signal, options.botMentions ?? []);
9007
- sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, contentPayload, options.signal, { agentAuthored });
9008
- } else sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, void 0, options.signal, { agentAuthored });
9826
+ sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, contentPayload, options.signal, {
9827
+ agentAuthored,
9828
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9829
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
9830
+ });
9831
+ } else sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, void 0, options.signal, {
9832
+ agentAuthored,
9833
+ ...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
9834
+ ...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
9835
+ });
9009
9836
  if (agentAuthored && sent.localState === "synced") this.arko.agentSourceDisplayName(session);
9010
9837
  return sent;
9011
9838
  }
@@ -9014,7 +9841,7 @@ var ChatService = class {
9014
9841
  if (botInputs.length > 50) throw new ArkmePluginError("bot-mention-invalid", "单条消息 Bot mention 数量过多", false);
9015
9842
  const leadingTrim = rawText.length - rawText.trimStart().length;
9016
9843
  const rawMembers = inputs.length === 0 ? [] : await this.rawChatMembers(source.ownerRef, true, session, signal);
9017
- const membersByUserId = new Map(rawMembers.map((item) => [Math.trunc(numberValue$16(item.user_id)), item]));
9844
+ const membersByUserId = new Map(rawMembers.map((item) => [Math.trunc(numberValue$15(item.user_id)), item]));
9018
9845
  const mentions = [];
9019
9846
  for (const input of [...inputs].sort((left, right) => left.startIndex - right.startIndex)) {
9020
9847
  const memberRef = input.memberRef?.trim() ?? "";
@@ -9190,12 +10017,12 @@ var ChatService = class {
9190
10017
  ...initialAiPolish === void 0 ? {} : { initialAiPolish },
9191
10018
  ...contentPayload === void 0 ? {} : { contentPayload }
9192
10019
  });
9193
- const sequence = numberValue$16(result.seq);
10020
+ const sequence = numberValue$15(result.seq);
9194
10021
  this.realtime.scheduleChatSessionProjection(chatSessionUid, sequence);
9195
10022
  return {
9196
10023
  sourceRef,
9197
10024
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
9198
- status: numberValue$16(result.audit_status),
10025
+ status: numberValue$15(result.audit_status),
9199
10026
  sequence,
9200
10027
  localState: "synced"
9201
10028
  };
@@ -9207,6 +10034,8 @@ var ChatService = class {
9207
10034
  rel_uid: relationUid,
9208
10035
  template_kind: 1,
9209
10036
  text_content: text,
10037
+ ...Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) === 0 ? {} : { record_duration_millis: Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) },
10038
+ ...options.captureContext === void 0 ? {} : { capture_context: arkmeRecordCaptureContextPayload(options.captureContext) },
9210
10039
  ...options.agentAuthored === true ? { creation_source: 1 } : {},
9211
10040
  ...options.initialAiPolish === void 0 ? {} : { initial_ai_polish: options.initialAiPolish },
9212
10041
  ...options.contentPayload === void 0 ? {} : { content_payload: options.contentPayload },
@@ -9226,6 +10055,8 @@ var ChatService = class {
9226
10055
  const longArticle = displayKind === 1;
9227
10056
  const maxContentLength = longArticle ? 4e4 : this.runtime.config.maxTextLength;
9228
10057
  const thinkingDurationMillis = Math.max(0, Math.trunc(input.thinkingDurationMillis ?? 0));
10058
+ const recordDurationMillis = Math.max(0, Math.trunc(input.recordDurationMillis ?? (longArticle ? thinkingDurationMillis : 0)));
10059
+ const captureContext = input.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(input.captureContext);
9229
10060
  if (title.length > (longArticle ? 100 : 500) || textContent.length > maxContentLength || assets.length > 20 || textContent === "" && title === "" && assets.length === 0) throw new ArkmePluginError("rich-content-invalid", "富内容为空、过长或附件数量超限", false);
9230
10061
  if (longArticle && (title === "" || textContent === "")) throw new ArkmePluginError("long-article-invalid", "长文标题和正文不能为空", false);
9231
10062
  for (const asset of assets) if (!/^[A-Za-z0-9._:-]{8,256}$/.test(asset.fileAssetUid) || asset.size < 0 || ![
@@ -9269,7 +10100,8 @@ var ChatService = class {
9269
10100
  display_kind: displayKind,
9270
10101
  title,
9271
10102
  text_content: textContent,
9272
- ...longArticle ? { record_duration_millis: thinkingDurationMillis } : {},
10103
+ ...recordDurationMillis === 0 ? {} : { record_duration_millis: recordDurationMillis },
10104
+ ...captureContext === void 0 || Object.keys(captureContext).length === 0 ? {} : { capture_context: captureContext },
9273
10105
  ...contentPayload === void 0 ? {} : { content_payload: contentPayload },
9274
10106
  send_at: Date.now()
9275
10107
  };
@@ -9279,7 +10111,7 @@ var ChatService = class {
9279
10111
  return {
9280
10112
  sourceRef,
9281
10113
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
9282
- status: numberValue$16(result.status),
10114
+ status: numberValue$15(result.status),
9283
10115
  localState: "synced"
9284
10116
  };
9285
10117
  }
@@ -9292,7 +10124,7 @@ var ChatService = class {
9292
10124
  return {
9293
10125
  sourceRef,
9294
10126
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
9295
- status: numberValue$16(result.status),
10127
+ status: numberValue$15(result.status),
9296
10128
  localState: "synced"
9297
10129
  };
9298
10130
  }
@@ -9301,12 +10133,12 @@ var ChatService = class {
9301
10133
  rel_uid: relationUid,
9302
10134
  ...commonBody
9303
10135
  }, session, options.signal);
9304
- const sequence = numberValue$16(result.seq);
10136
+ const sequence = numberValue$15(result.seq);
9305
10137
  this.realtime.scheduleChatSessionProjection(source.ownerRef, sequence);
9306
10138
  return {
9307
10139
  sourceRef,
9308
10140
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
9309
- status: numberValue$16(result.audit_status ?? result.status),
10141
+ status: numberValue$15(result.audit_status ?? result.status),
9310
10142
  sequence,
9311
10143
  localState: "synced"
9312
10144
  };
@@ -9315,7 +10147,7 @@ var ChatService = class {
9315
10147
  const root = await this.runtime.authenticatedChatPost("/api/v1/chats/favorite-stickers/get", {}, session, signal);
9316
10148
  return {
9317
10149
  root,
9318
- items: listValue$16(root.items).map(objectValue$1)
10150
+ items: listValue$15(root.items).map(objectValue$1)
9319
10151
  };
9320
10152
  }
9321
10153
  favoriteStickerView(raw, viewerUserId) {
@@ -9329,7 +10161,7 @@ var ChatService = class {
9329
10161
  fileAssetUid,
9330
10162
  fileName,
9331
10163
  mimeType,
9332
- size: Math.max(0, Math.trunc(numberValue$16(raw.file_size ?? raw.size))),
10164
+ size: Math.max(0, Math.trunc(numberValue$15(raw.file_size ?? raw.size))),
9333
10165
  fileKind: 1,
9334
10166
  isAnimated: booleanValue$8(raw.is_animated) || mimeType.toLowerCase() === "image/gif",
9335
10167
  isAvailable: serverAvailable && mediaRef !== void 0,
@@ -9347,7 +10179,7 @@ var ChatService = class {
9347
10179
  return {
9348
10180
  items: projected,
9349
10181
  itemCount: projected.length,
9350
- updatedAtMillis: Math.max(0, Math.trunc(numberValue$16(root.updated_at_millis ?? root.updated_at)))
10182
+ updatedAtMillis: Math.max(0, Math.trunc(numberValue$15(root.updated_at_millis ?? root.updated_at)))
9351
10183
  };
9352
10184
  }
9353
10185
  async addFavoriteSticker(item, signal) {
@@ -9411,7 +10243,7 @@ var ChatService = class {
9411
10243
  render_role: 3,
9412
10244
  sort_order: 0,
9413
10245
  file_kind: 1,
9414
- file_type: Math.trunc(numberValue$16(sticker.file_type)),
10246
+ file_type: Math.trunc(numberValue$15(sticker.file_type)),
9415
10247
  mime_type: stringValue$1(sticker.mime_type).trim(),
9416
10248
  file_name: stringValue$1(sticker.file_name).trim()
9417
10249
  }]
@@ -9421,8 +10253,8 @@ var ChatService = class {
9421
10253
  return {
9422
10254
  sourceRef,
9423
10255
  itemUid: stringValue$1(result.record_uid).trim() || recordUid,
9424
- status: numberValue$16(result.audit_status ?? result.status),
9425
- sequence: numberValue$16(result.seq),
10256
+ status: numberValue$15(result.audit_status ?? result.status),
10257
+ sequence: numberValue$15(result.seq),
9426
10258
  localState: "synced"
9427
10259
  };
9428
10260
  }
@@ -9466,7 +10298,7 @@ var ChatService = class {
9466
10298
  send_at: sendAtMillis
9467
10299
  }, session, options.signal);
9468
10300
  const chatSessionUid = stringValue$1(result.chat_session_uid).trim();
9469
- const sequence = numberValue$16(result.seq);
10301
+ const sequence = numberValue$15(result.seq);
9470
10302
  const targetKind = stringValue$1(result.target_kind).trim();
9471
10303
  if (chatSessionUid === "" || !Number.isSafeInteger(sequence) || sequence <= 0 || targetKind !== "direct") throw new ArkmePluginError("direct-send-response-invalid", "Chat Agent 发送返回了无效响应", true, 502);
9472
10304
  const responseRecordUid = stringValue$1(result.record_uid).trim() || recordUid;
@@ -9498,11 +10330,11 @@ var ChatService = class {
9498
10330
  reason: "arkme_dsh_open_chat"
9499
10331
  }, session, signal);
9500
10332
  const responseSessionUid = stringValue$1(data.chat_session_uid).trim();
9501
- const responseUserId = numberValue$16(data.user_id);
9502
- const effectiveReadSequence = numberValue$16(data.effective_read_seq);
9503
- const readAt = numberValue$16(data.read_at);
9504
- const sessionLastSequence = numberValue$16(data.session_last_seq);
9505
- const unreadCount = numberValue$16(data.unread_count);
10333
+ const responseUserId = numberValue$15(data.user_id);
10334
+ const effectiveReadSequence = numberValue$15(data.effective_read_seq);
10335
+ const readAt = numberValue$15(data.read_at);
10336
+ const sessionLastSequence = numberValue$15(data.session_last_seq);
10337
+ const unreadCount = numberValue$15(data.unread_count);
9506
10338
  if (responseSessionUid !== chatSessionUid || responseUserId !== session.userId || !Number.isSafeInteger(effectiveReadSequence) || effectiveReadSequence < readSequence || !Number.isSafeInteger(readAt) || readAt <= 0 || !Number.isSafeInteger(sessionLastSequence) || sessionLastSequence < effectiveReadSequence || !Number.isSafeInteger(unreadCount) || unreadCount < 0) throw new ArkmePluginError("source-read-ack-invalid", "聊天已读响应不完整", true, 502);
9507
10339
  const cacheKey = `${String(session.userId)}:${chatSessionUid}`;
9508
10340
  const cached = this.source.cachedChatSourceByKey(cacheKey);
@@ -9532,36 +10364,56 @@ var ChatService = class {
9532
10364
  async chatTimelineItems(data, session, chatSessionUid) {
9533
10365
  const items = [];
9534
10366
  const signingKey = await this.runtime.stateStore.uniqueCode();
9535
- for (const raw of listValue$16(data.items)) {
10367
+ for (const raw of listValue$15(data.items)) {
9536
10368
  const item = objectValue$1(raw);
9537
10369
  const relation = objectValue$1(item.relation);
9538
10370
  const record = objectValue$1(item.record);
9539
10371
  const payload = objectValue$1(record.payload);
9540
10372
  const uid = stringValue$1(relation.record_uid ?? payload.record_uid).trim();
9541
10373
  if (uid === "") continue;
9542
- const senderUserId = numberValue$16(relation.sender_user_id);
10374
+ const senderUserId = integerLikeValue(relation.sender_user_id);
9543
10375
  const relationUid = stringValue$1(relation.rel_uid ?? relation.relUid).trim();
10376
+ const recordOwnerUserId = chatRecordOwnerUserId(relation, record, payload, senderUserId);
9544
10377
  const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
9545
- const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
10378
+ const sendAtMillis = numberValue$15(relation.attach_at ?? payload.send_at);
9546
10379
  const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
9547
10380
  const sharedRecording = this.withSharedRecordingDetailRef(this.chatSharedRecordingPreview(item), {
9548
10381
  viewerUserId: session.userId,
9549
10382
  chatSessionUid,
9550
10383
  relationUid,
9551
- recordOwnerUserId: integerLikeValue$1(record.record_owner_user_id ?? record.recordOwnerUserId ?? payload.record_owner_user_id ?? payload.recordOwnerUserId ?? relation.record_owner_user_id ?? relation.recordOwnerUserId),
10384
+ recordOwnerUserId,
9552
10385
  recordUid: uid,
9553
- senderUserId: integerLikeValue$1(relation.sender_user_id),
9554
- sequence: integerLikeValue$1(relation.seq),
10386
+ senderUserId: integerLikeValue(relation.sender_user_id),
10387
+ sequence: integerLikeValue(relation.seq),
9555
10388
  signingKey
9556
10389
  });
9557
10390
  const rawAgentSource = timelineAgentSource(relation, record, payload);
9558
10391
  const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
9559
10392
  const contentBlocks = this.media.richContentBlocks(item, session.userId);
10393
+ const senderName = stringValue$1(relation.display_name_snapshot).trim() || "Arkme用户";
9560
10394
  const mentionsViewer = senderUserId !== session.userId && arkmeMentionMetadataMentionsViewer(record, payload, session.userId);
9561
10395
  items.push({
9562
10396
  itemUid: uid,
10397
+ ...relationUid === "" ? {} : { messageActionRef: this.sealMessageActionRef(this.messageActionRefPayload({
10398
+ sourceKind: "chat_relation",
10399
+ userId: session.userId,
10400
+ sourceOwnerRef: chatSessionUid,
10401
+ chatSessionUid,
10402
+ relationUid,
10403
+ recordOwnerUserId,
10404
+ recordUid: uid,
10405
+ senderUserId,
10406
+ senderName,
10407
+ title: stringValue$1(payload.title),
10408
+ textContent: stringValue$1(payload.text_content),
10409
+ sendAtMillis,
10410
+ sourceSequence: numberValue$15(relation.seq),
10411
+ templateKind: numberValue$15(payload.template_kind),
10412
+ displayKind: numberValue$15(payload.display_kind),
10413
+ contentBlocks
10414
+ }), signingKey) },
9563
10415
  ...senderUserId > 0 ? { memberRef: await this.sealChatMemberRef(session.userId, chatSessionUid, senderUserId) } : {},
9564
- senderName: stringValue$1(relation.display_name_snapshot).trim() || "Arkme用户",
10416
+ senderName,
9565
10417
  ...agentSource === void 0 ? {} : { agentSource },
9566
10418
  ...senderUserId > 0 ? { avatarRef: await this.profile.sealProfileImageRef(session.userId, senderUserId) } : {},
9567
10419
  isMe: senderUserId === session.userId,
@@ -9569,13 +10421,13 @@ var ChatService = class {
9569
10421
  sendAtMillis,
9570
10422
  title: stringValue$1(payload.title),
9571
10423
  textContent: stringValue$1(payload.text_content),
9572
- status: numberValue$16(record.status),
9573
- sequence: numberValue$16(relation.seq),
9574
- ...numberValue$16(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$16(record.version ?? payload.version) } : {},
10424
+ status: numberValue$15(record.status),
10425
+ sequence: numberValue$15(relation.seq),
10426
+ ...numberValue$15(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$15(record.version ?? payload.version) } : {},
9575
10427
  ...aiPolish === void 0 ? {} : { aiPolish },
9576
10428
  ...forwardRecords === void 0 ? {} : { forwardRecords },
9577
10429
  ...sharedRecording === void 0 ? {} : { sharedRecording },
9578
- displayKind: numberValue$16(payload.display_kind),
10430
+ displayKind: numberValue$15(payload.display_kind),
9579
10431
  contentBlocks
9580
10432
  });
9581
10433
  }
@@ -9590,7 +10442,7 @@ var ChatService = class {
9590
10442
  let truncated = false;
9591
10443
  let remainingSegments = 2e3;
9592
10444
  const epochMillis = (value) => {
9593
- const time = numberValue$16(value);
10445
+ const time = numberValue$15(value);
9594
10446
  return Number.isFinite(time) && time > 0 && time < 864e13 ? Math.trunc(time < 0xe8d4a51000 ? time * 1e3 : time) : 0;
9595
10447
  };
9596
10448
  const appendItems = async (values, depth) => {
@@ -9598,7 +10450,7 @@ var ChatService = class {
9598
10450
  const sorted = values.slice(0, 100).map((value, index) => ({
9599
10451
  value,
9600
10452
  index,
9601
- order: numberValue$16(objectValue$1(value).item_order)
10453
+ order: numberValue$15(objectValue$1(value).item_order)
9602
10454
  })).sort((left, right) => (left.order || left.index) - (right.order || right.index));
9603
10455
  for (const entry of sorted) {
9604
10456
  if (projectedItems.length >= 100) {
@@ -9608,26 +10460,26 @@ var ChatService = class {
9608
10460
  const item = objectValue$1(entry.value);
9609
10461
  const nestedForward = objectValue$1(item.forward_records ?? item.forwardRecords);
9610
10462
  if (depth < 4 && stringValue$1(nestedForward.render_kind ?? nestedForward.renderKind).trim() === "forward_records") {
9611
- await appendItems(listValue$16(nestedForward.items), depth + 1);
10463
+ await appendItems(listValue$15(nestedForward.items), depth + 1);
9612
10464
  continue;
9613
10465
  }
9614
10466
  if (depth >= 4 && Object.keys(nestedForward).length > 0) truncated = true;
9615
- const senderUserId = numberValue$16(item.source_sender_user_id ?? item.sourceSenderUserId ?? item.owner_id ?? item.ownerId);
10467
+ const senderUserId = numberValue$15(item.source_sender_user_id ?? item.sourceSenderUserId ?? item.owner_id ?? item.ownerId);
9616
10468
  const senderName = stringValue$1(item.owner_name ?? item.ownerName ?? item.source_display_name ?? item.sourceDisplayName).trim() || "Arkme用户";
9617
10469
  const textContent = stringValue$1(item.text ?? item.text_preview ?? item.textPreview).trim();
9618
10470
  const title = stringValue$1(item.title).trim();
9619
10471
  const rawType = stringValue$1(item.source_type ?? item.sourceType ?? payload.source_type ?? payload.sourceType);
9620
10472
  const sourceType = rawType === "record" || rawType === "chat_record" || rawType === "long_recording_segments" || rawType === "agent" || rawType === "ai_letter" ? rawType : "unknown";
9621
- const files = listValue$16(item.files);
10473
+ const files = listValue$15(item.files);
9622
10474
  const contentBlocks = this.media.forwardContentBlocks(files, viewerUserId);
9623
10475
  const call = objectValue$1(item.call_record_snapshot ?? item.callRecordSnapshot);
9624
- const recordingSegments = listValue$16(item.long_recording_segments ?? item.longRecordingSegments);
9625
- const rawSegments = recordingSegments.length > 0 ? recordingSegments : listValue$16(call.transcript_segments ?? call.transcriptSegments);
10476
+ const recordingSegments = listValue$15(item.long_recording_segments ?? item.longRecordingSegments);
10477
+ const rawSegments = recordingSegments.length > 0 ? recordingSegments : listValue$15(call.transcript_segments ?? call.transcriptSegments);
9626
10478
  const segmentValues = rawSegments.slice(0, Math.min(500, remainingSegments));
9627
10479
  remainingSegments -= segmentValues.length;
9628
10480
  const segments = segmentValues.map((value) => {
9629
10481
  const segment = objectValue$1(value);
9630
- const offset = (value) => Math.max(0, Math.trunc(numberValue$16(value)));
10482
+ const offset = (value) => Math.max(0, Math.trunc(numberValue$15(value)));
9631
10483
  const startMillis = offset(segment.start_millis ?? segment.startMillis ?? segment.start_ms ?? segment.startMs);
9632
10484
  const endMillis = Math.max(startMillis, offset(segment.end_millis ?? segment.endMillis ?? segment.end_ms ?? segment.endMs));
9633
10485
  const speakerNumber = offset(segment.speaker_number ?? segment.speakerNumber);
@@ -9649,10 +10501,10 @@ var ChatService = class {
9649
10501
  ...audioUrl !== "" && segmentMedia.length === 0 ? { mediaUnavailable: true } : {}
9650
10502
  };
9651
10503
  });
9652
- const imageCount = Math.max(0, Math.trunc(numberValue$16(item.image_count ?? item.imageCount)));
9653
- const voiceCount = Math.max(0, Math.trunc(numberValue$16(item.voice_count ?? item.voiceCount)));
9654
- const fileCount = Math.max(0, Math.trunc(numberValue$16(item.file_count ?? item.fileCount)));
9655
- const fileName = listValue$16(item.file_names ?? item.fileNames).map((value) => stringValue$1(value).trim()).find((value) => value !== "");
10504
+ const imageCount = Math.max(0, Math.trunc(numberValue$15(item.image_count ?? item.imageCount)));
10505
+ const voiceCount = Math.max(0, Math.trunc(numberValue$15(item.voice_count ?? item.voiceCount)));
10506
+ const fileCount = Math.max(0, Math.trunc(numberValue$15(item.file_count ?? item.fileCount)));
10507
+ const fileName = listValue$15(item.file_names ?? item.fileNames).map((value) => stringValue$1(value).trim()).find((value) => value !== "");
9656
10508
  const contentLabel = imageCount > 0 ? imageCount > 1 ? `[${String(imageCount)}张图片]` : "[图片]" : voiceCount > 0 ? "[语音]" : fileCount > 0 ? fileName === void 0 ? "[文件]" : `[文件] ${fileName}` : stringValue$1(item.availability).trim() !== "" ? "原快记暂不可查看" : void 0;
9657
10509
  projectedItems.push({
9658
10510
  senderName,
@@ -9669,8 +10521,8 @@ var ChatService = class {
9669
10521
  });
9670
10522
  }
9671
10523
  };
9672
- await appendItems(listValue$16(payload.items), 0);
9673
- const summaryLines = listValue$16(payload.summary_lines ?? payload.summaryLines).map((value) => stringValue$1(value).trim()).filter((value) => value !== "");
10524
+ await appendItems(listValue$15(payload.items), 0);
10525
+ const summaryLines = listValue$15(payload.summary_lines ?? payload.summaryLines).map((value) => stringValue$1(value).trim()).filter((value) => value !== "");
9674
10526
  const createdAtMillis = epochMillis(payload.created_at ?? payload.createdAt) || epochMillis(fallbackCreatedAtMillis);
9675
10527
  return {
9676
10528
  title: stringValue$1(payload.title).trim() || "转发快记",
@@ -9713,9 +10565,9 @@ var ChatService = class {
9713
10565
  }
9714
10566
  }
9715
10567
  sharedRecordingParticipantsFromPayload(payload) {
9716
- const participants = listValue$16(payload.participants);
9717
- const mobileParticipants = listValue$16(payload.participant_ls ?? payload.participantLs);
9718
- const speakers = listValue$16(payload.speaker_ls ?? payload.speakerLs ?? payload.speakers);
10568
+ const participants = listValue$15(payload.participants);
10569
+ const mobileParticipants = listValue$15(payload.participant_ls ?? payload.participantLs);
10570
+ const speakers = listValue$15(payload.speaker_ls ?? payload.speakerLs ?? payload.speakers);
9719
10571
  return (participants.length > 0 ? participants : mobileParticipants.length > 0 ? mobileParticipants : speakers).flatMap((value) => {
9720
10572
  if (typeof value === "string") {
9721
10573
  const displayName = value.trim();
@@ -9727,11 +10579,11 @@ var ChatService = class {
9727
10579
  const participant = objectValue$1(value);
9728
10580
  const displayName = stringValue$1(participant.display_name ?? participant.displayName ?? participant.nick_name ?? participant.nickName ?? participant.speaker_name ?? participant.speakerName ?? participant.name).trim();
9729
10581
  if (displayName === "") return [];
9730
- const refUserId = integerLikeValue$1(participant.ref_user_id ?? participant.refUserId ?? participant.ref_usr_id ?? participant.refUsrId);
10582
+ const refUserId = integerLikeValue(participant.ref_user_id ?? participant.refUserId ?? participant.ref_usr_id ?? participant.refUsrId);
9731
10583
  return [{
9732
10584
  ...refUserId > 0 ? { refUserId } : {},
9733
10585
  displayName,
9734
- role: Math.max(0, integerLikeValue$1(participant.role))
10586
+ role: Math.max(0, integerLikeValue(participant.role))
9735
10587
  }];
9736
10588
  });
9737
10589
  }
@@ -9746,7 +10598,7 @@ var ChatService = class {
9746
10598
  "asr_ls",
9747
10599
  "asrLs"
9748
10600
  ]) {
9749
- const lines = listValue$16(payload[key]).flatMap((value) => {
10601
+ const lines = listValue$15(payload[key]).flatMap((value) => {
9750
10602
  if (typeof value === "string") {
9751
10603
  const line = value.trim();
9752
10604
  return line === "" ? [] : [line];
@@ -9767,15 +10619,15 @@ var ChatService = class {
9767
10619
  const sourceDigest = stringValue$1(payload.source_digest ?? payload.sourceDigest).trim();
9768
10620
  const title = stringValue$1(payload.title ?? payload.orig_name ?? payload.origName).trim();
9769
10621
  const summary = stringValue$1(payload.summary ?? payload.summary_text ?? payload.summaryText ?? payload.content_summary ?? payload.contentSummary).trim();
9770
- const displayAtMillis = integerLikeValue$1(payload.display_at ?? payload.displayAt);
10622
+ const displayAtMillis = integerLikeValue(payload.display_at ?? payload.displayAt);
9771
10623
  if (sourceDigest === "" || title === "" || summary === "" || displayAtMillis <= 0) return void 0;
9772
10624
  const transcript = this.sharedRecordingTranscriptFromPayload(payload);
9773
10625
  return {
9774
10626
  sourceDigest,
9775
- sharedByUserId: Math.max(0, integerLikeValue$1(payload.shared_by_user_id ?? payload.sharedByUserId)),
9776
- sharedAtMillis: Math.max(0, integerLikeValue$1(payload.shared_at ?? payload.sharedAt)),
10627
+ sharedByUserId: Math.max(0, integerLikeValue(payload.shared_by_user_id ?? payload.sharedByUserId)),
10628
+ sharedAtMillis: Math.max(0, integerLikeValue(payload.shared_at ?? payload.sharedAt)),
9777
10629
  displayAtMillis,
9778
- endAtMillis: Math.max(0, integerLikeValue$1(payload.end_at ?? payload.endAt)),
10630
+ endAtMillis: Math.max(0, integerLikeValue(payload.end_at ?? payload.endAt)),
9779
10631
  timeRangeText: stringValue$1(payload.time_range_text ?? payload.timeRangeText).trim(),
9780
10632
  title,
9781
10633
  summary,
@@ -9846,12 +10698,12 @@ var ChatService = class {
9846
10698
  }
9847
10699
  const result = {
9848
10700
  version: 1,
9849
- viewerUserId: integerLikeValue$1(parsed.viewerUserId),
10701
+ viewerUserId: integerLikeValue(parsed.viewerUserId),
9850
10702
  chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
9851
10703
  relationUid: stringValue$1(parsed.relationUid).trim(),
9852
- recordOwnerUserId: integerLikeValue$1(parsed.recordOwnerUserId),
10704
+ recordOwnerUserId: integerLikeValue(parsed.recordOwnerUserId),
9853
10705
  recordUid: stringValue$1(parsed.recordUid).trim(),
9854
- sequence: Math.max(0, integerLikeValue$1(parsed.sequence))
10706
+ sequence: Math.max(0, integerLikeValue(parsed.sequence))
9855
10707
  };
9856
10708
  if (parsed.version !== 1 || result.viewerUserId !== expectedViewerUserId || result.chatSessionUid === "" || result.recordUid === "" || result.recordOwnerUserId <= 0) throw new ArkmePluginError("shared-recording-detail-ref-invalid", "共享录音详情引用与当前账号不匹配,请刷新后重试", false, 403);
9857
10709
  return result;
@@ -9877,18 +10729,168 @@ var ChatService = class {
9877
10729
  detailRef
9878
10730
  };
9879
10731
  }
10732
+ async messageSnapshotDetail(sourceRef, actionRef, options = {}) {
10733
+ const session = await this.runtime.requireSession();
10734
+ const source = await this.source.openSourceRef(sourceRef, session.userId);
10735
+ const isChatSource = source.kind === "private_chat" || source.kind === "group_chat";
10736
+ const isRecordSource = source.kind === "send_to_self" || source.kind === "default_category" || source.kind === "topic";
10737
+ if (!isChatSource && !isRecordSource) throw new ArkmePluginError("message-snapshot-source-unsupported", "当前对话暂不支持读取完整快记详情", false, 400);
10738
+ const reference = await this.openMessageActionRef(actionRef, session.userId, source);
10739
+ if (reference.recordUid === "") throw new ArkmePluginError("message-snapshot-record-invalid", "快记记录身份无效,请刷新后重试", false, 400);
10740
+ if (reference.senderUserId !== session.userId) throw new ArkmePluginError("message-snapshot-not-owned", "只能查看自己发送的快记详情", false, 403);
10741
+ const recordOwnerUserId = reference.recordOwnerUserId > 0 ? reference.recordOwnerUserId : reference.senderUserId;
10742
+ if (recordOwnerUserId <= 0) throw new ArkmePluginError("message-snapshot-owner-missing", "快记记录归属暂时无法确认,请刷新后重试", true, 502);
10743
+ if (reference.sourceKind === "record") {
10744
+ if (!isRecordSource) throw new ArkmePluginError("message-snapshot-record-invalid", "快记记录身份与当前来源不匹配,请刷新后重试", false, 400);
10745
+ return this.hydratedMessageSnapshotDetail(reference, session, options);
10746
+ }
10747
+ if (!isChatSource || reference.relationUid === "") throw new ArkmePluginError("message-snapshot-record-invalid", "快记记录身份无效,请刷新后重试", false, 400);
10748
+ const chatRaw = objectValue$1((await this.runtime.authenticatedChatPost("/api/v1/chats/records/detail", {
10749
+ chat_session_uid: reference.chatSessionUid,
10750
+ record_uid: reference.recordUid,
10751
+ record_owner_user_id: recordOwnerUserId,
10752
+ rel_uid: reference.relationUid,
10753
+ ...reference.sourceSequence <= 0 ? {} : { seq: reference.sourceSequence }
10754
+ }, session, options.signal, {
10755
+ lane: "interactive-read",
10756
+ key: `message-snapshot-detail:${reference.chatSessionUid}:${reference.relationUid}:${reference.recordUid}:${String(reference.sourceSequence)}`,
10757
+ failureCooldownMs: 1e3
10758
+ })).item);
10759
+ if (Object.keys(chatRaw).length === 0) throw new ArkmePluginError("message-snapshot-detail-unavailable", "完整快记详情暂时无法读取,请稍后重试", true, 502);
10760
+ return this.hydratedMessageSnapshotDetail(reference, session, options, chatRaw);
10761
+ }
10762
+ async hydratedMessageSnapshotDetail(reference, session, options, chatRaw = {}) {
10763
+ const recordRaw = objectValue$1(await this.runtime.authenticatedPost("/api/v1/records/detail", { record_uid: reference.recordUid }, session, options.signal, {
10764
+ lane: "interactive-read",
10765
+ key: `message-snapshot-record-core:${reference.recordUid}`,
10766
+ failureCooldownMs: 1e3
10767
+ }));
10768
+ const chatRecord = objectValue$1(chatRaw.record);
10769
+ const recordCore = objectValue$1(recordRaw.record_core ?? recordRaw.recordCore ?? recordRaw.record ?? recordRaw);
10770
+ const detailRecordUid = firstSnapshotText(recordCore.record_uid, recordCore.recordUid, recordCore.uid, recordRaw.record_uid, recordRaw.recordUid, recordRaw.uid);
10771
+ const hasDetailPayload = [
10772
+ recordRaw.payload,
10773
+ recordRaw.content_payload,
10774
+ recordRaw.contentPayload,
10775
+ recordRaw.record_payload,
10776
+ recordRaw.recordPayload,
10777
+ recordRaw.location,
10778
+ recordRaw.position_detail,
10779
+ recordRaw.positionDetail,
10780
+ recordRaw.extra,
10781
+ recordRaw.record_extra,
10782
+ recordRaw.recordExtra,
10783
+ recordRaw.weather,
10784
+ recordRaw.capture_context,
10785
+ recordRaw.captureContext,
10786
+ recordRaw.background_sound,
10787
+ recordRaw.backgroundSound
10788
+ ].some((value) => Object.keys(parsedObject(value)).length > 0 || listValue$15(value).length > 0);
10789
+ if (!Object.keys(recordCore).some((key) => ![
10790
+ "record_uid",
10791
+ "recordUid",
10792
+ "uid"
10793
+ ].includes(key)) && !hasDetailPayload) throw new ArkmePluginError("message-snapshot-detail-unavailable", "完整快记详情暂时无法读取,请稍后重试", true, 502);
10794
+ if (detailRecordUid !== reference.recordUid) throw new ArkmePluginError("message-snapshot-detail-mismatch", "完整快记详情与当前消息不匹配,请刷新后重试", true, 502);
10795
+ const chatRecordPayload = {
10796
+ ...parsedObject(chatRecord.payload),
10797
+ ...parsedObject(chatRecord.content_payload),
10798
+ ...parsedObject(chatRecord.contentPayload),
10799
+ ...parsedObject(chatRecord.record_payload),
10800
+ ...parsedObject(chatRecord.recordPayload)
10801
+ };
10802
+ const detailPayload = {
10803
+ ...parsedObject(recordRaw.payload),
10804
+ ...parsedObject(recordRaw.content_payload),
10805
+ ...parsedObject(recordRaw.contentPayload),
10806
+ ...parsedObject(recordRaw.record_payload),
10807
+ ...parsedObject(recordRaw.recordPayload),
10808
+ ...parsedObject(recordCore.payload),
10809
+ ...parsedObject(recordCore.content_payload),
10810
+ ...parsedObject(recordCore.contentPayload),
10811
+ ...parsedObject(recordCore.record_payload),
10812
+ ...parsedObject(recordCore.recordPayload)
10813
+ };
10814
+ let raw = {
10815
+ ...chatRaw,
10816
+ ...recordRaw,
10817
+ relation: Object.keys(chatRaw).length === 0 ? {
10818
+ record_uid: reference.recordUid,
10819
+ record_owner_user_id: reference.recordOwnerUserId
10820
+ } : objectValue$1(chatRaw.relation),
10821
+ record: {
10822
+ ...chatRecord,
10823
+ ...recordCore,
10824
+ payload: {
10825
+ ...chatRecordPayload,
10826
+ ...detailPayload
10827
+ }
10828
+ }
10829
+ };
10830
+ const locationContext = await this.runtime.authenticatedPost("/api/v1/records/location/context/get", { record_uid: reference.recordUid }, session, options.signal, {
10831
+ lane: "interactive-read",
10832
+ key: `message-snapshot-location-context:${reference.recordUid}`,
10833
+ failureCooldownMs: 1e4
10834
+ }).catch(() => void 0);
10835
+ if (locationContext !== void 0) {
10836
+ const context = snapshotLocationContext(locationContext);
10837
+ const contextEnvelope = objectValue$1(locationContext);
10838
+ const contextData = objectValue$1(contextEnvelope.data);
10839
+ const contextRecordUid = firstSnapshotText(contextEnvelope.record_uid, contextEnvelope.recordUid, contextEnvelope.uid, contextData.record_uid, contextData.recordUid, contextData.uid, context.record_uid, context.recordUid, context.uid);
10840
+ if (contextRecordUid !== void 0 && contextRecordUid !== reference.recordUid) throw new ArkmePluginError("message-snapshot-detail-mismatch", "快记地点上下文与当前消息不匹配,请刷新后重试", true, 502);
10841
+ raw = mergeSnapshotLocationContext(raw, context);
10842
+ }
10843
+ const detail = snapshotDetailFromChatRaw(raw, {
10844
+ itemUid: reference.recordUid,
10845
+ textContent: reference.textContent,
10846
+ sendAtMillis: reference.sendAtMillis
10847
+ });
10848
+ if (detail.itemUid !== reference.recordUid) throw new ArkmePluginError("message-snapshot-detail-mismatch", "快记详情与当前消息不匹配,请刷新后重试", true, 502);
10849
+ return detail;
10850
+ }
10851
+ async saveMessageLocation(sourceRef, itemUid, location, recordVersion, options = {}) {
10852
+ const session = await this.runtime.requireSession();
10853
+ const source = await this.source.openSourceRef(sourceRef, session.userId);
10854
+ const recordUid = itemUid.trim();
10855
+ if (recordUid === "" || ![
10856
+ "private_chat",
10857
+ "group_chat",
10858
+ "send_to_self",
10859
+ "default_category",
10860
+ "topic"
10861
+ ].includes(source.kind)) throw new ArkmePluginError("message-location-target-invalid", "当前消息不能写入位置快照", false, 400);
10862
+ const latitude = location.latitude;
10863
+ const longitude = location.longitude;
10864
+ if (!Number.isFinite(latitude) || latitude < -90 || latitude > 90 || !Number.isFinite(longitude) || longitude < -180 || longitude > 180) throw new ArkmePluginError("message-location-invalid", "位置坐标无效", false, 400);
10865
+ const altitude = location.altitudeMeters;
10866
+ const speed = location.speedMetersPerSecond;
10867
+ const accuracy = location.accuracyMeters;
10868
+ await this.runtime.authenticatedPost("/api/v1/records/location/set", {
10869
+ record_uid: recordUid,
10870
+ ...recordVersion === void 0 || recordVersion <= 0 ? {} : { expected_record_version: Math.trunc(recordVersion) },
10871
+ location: {
10872
+ source_kind: 1,
10873
+ lat: latitude,
10874
+ lon: longitude,
10875
+ ...altitude === void 0 || !Number.isFinite(altitude) ? {} : { alt: altitude },
10876
+ ...speed === void 0 || !Number.isFinite(speed) || speed < 0 ? {} : { speed },
10877
+ ...accuracy === void 0 || !Number.isFinite(accuracy) || accuracy < 0 ? {} : { accuracy },
10878
+ captured_at: Math.max(1, Math.trunc(location.capturedAtMillis))
10879
+ }
10880
+ }, session, options.signal);
10881
+ }
9880
10882
  async rawChatMembers(chatSessionUid, activeOnly, session, signal) {
9881
- return listValue$16((await this.runtime.authenticatedChatPost("/api/v1/chats/members/list", {
10883
+ return listValue$15((await this.runtime.authenticatedChatPost("/api/v1/chats/members/list", {
9882
10884
  chat_session_uid: chatSessionUid,
9883
10885
  active_only: activeOnly
9884
10886
  }, session, signal)).items).map(objectValue$1);
9885
10887
  }
9886
10888
  async projectChatMembers(chatSessionUid, rawItems, session, includeViewerLabels, signal) {
9887
- const userIds = rawItems.map((item) => Math.trunc(numberValue$16(item.user_id))).filter((userId) => Number.isSafeInteger(userId) && userId > 0);
10889
+ const userIds = rawItems.map((item) => Math.trunc(numberValue$15(item.user_id))).filter((userId) => Number.isSafeInteger(userId) && userId > 0);
9888
10890
  const [profiles, viewerLabels] = await Promise.all([this.profile.publicProfileSummariesByUserIds(userIds, session, signal).catch(() => /* @__PURE__ */ new Map()), includeViewerLabels ? this.source.privateDisplayNamesByUserIds(userIds, { ...signal === void 0 ? {} : { signal } }).catch(() => /* @__PURE__ */ new Map()) : Promise.resolve(/* @__PURE__ */ new Map())]);
9889
10891
  const members = [];
9890
10892
  for (const item of rawItems) {
9891
- const userId = Math.trunc(numberValue$16(item.user_id));
10893
+ const userId = Math.trunc(numberValue$15(item.user_id));
9892
10894
  if (!Number.isSafeInteger(userId) || userId <= 0) continue;
9893
10895
  const profile = profiles.get(userId);
9894
10896
  const { displayName, memberName, secondaryName } = resolveChatMemberDisplayNames({
@@ -9914,9 +10916,9 @@ var ChatService = class {
9914
10916
  status,
9915
10917
  isSelf: userId === session.userId,
9916
10918
  isOwner: role === "owner",
9917
- joinedAtMillis: Math.max(0, Math.trunc(numberValue$16(item.join_at))),
9918
- recordCount: Math.max(0, Math.trunc(numberValue$16(extra.record_count))),
9919
- mentionCount: Math.max(0, Math.trunc(numberValue$16(extra.mention_count)))
10919
+ joinedAtMillis: Math.max(0, Math.trunc(numberValue$15(item.join_at))),
10920
+ recordCount: Math.max(0, Math.trunc(numberValue$15(extra.record_count))),
10921
+ mentionCount: Math.max(0, Math.trunc(numberValue$15(extra.mention_count)))
9920
10922
  });
9921
10923
  }
9922
10924
  const roleRank = (role) => role === "owner" ? 0 : role === "admin" ? 1 : role === "member" ? 2 : 3;
@@ -9932,29 +10934,36 @@ var ChatService = class {
9932
10934
  const relation = objectValue$1(item.relation);
9933
10935
  const record = objectValue$1(item.record);
9934
10936
  const payload = objectValue$1(record.payload);
9935
- const recordStatus = numberValue$16(record.status);
10937
+ const recordStatus = numberValue$15(record.status);
9936
10938
  if (recordStatus !== 1) continue;
9937
10939
  const uid = stringValue$1(relation.record_uid ?? payload.record_uid).trim();
9938
10940
  if (uid === "") continue;
9939
10941
  const relationUid = stringValue$1(relation.rel_uid).trim();
9940
- const senderUserId = Math.trunc(numberValue$16(relation.sender_user_id));
10942
+ const senderUserId = Math.trunc(numberValue$15(relation.sender_user_id));
10943
+ const recordOwnerUserId = chatRecordOwnerUserId(relation, record, payload, senderUserId);
9941
10944
  const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
9942
- const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
10945
+ const sendAtMillis = numberValue$15(relation.attach_at ?? payload.send_at);
9943
10946
  const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
9944
10947
  const sharedRecording = this.withSharedRecordingDetailRef(this.chatSharedRecordingPreview(item), {
9945
10948
  viewerUserId: session.userId,
9946
10949
  chatSessionUid: source.ownerRef,
9947
10950
  relationUid,
9948
- recordOwnerUserId: integerLikeValue$1(record.record_owner_user_id ?? record.recordOwnerUserId ?? payload.record_owner_user_id ?? payload.recordOwnerUserId ?? relation.record_owner_user_id ?? relation.recordOwnerUserId),
10951
+ recordOwnerUserId,
9949
10952
  recordUid: uid,
9950
10953
  senderUserId,
9951
- sequence: integerLikeValue$1(relation.seq),
10954
+ sequence: integerLikeValue(relation.seq),
9952
10955
  signingKey
9953
10956
  });
9954
10957
  const rawAgentSource = timelineAgentSource(relation, record, payload);
9955
10958
  const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
9956
10959
  const contentBlocks = this.media.richContentBlocks(item, session.userId);
9957
10960
  const senderName = stringValue$1(relation.display_name_snapshot).trim() || "Arkme用户";
10961
+ const captureContext = timelineCaptureContext({
10962
+ ...record,
10963
+ ...payload
10964
+ });
10965
+ const recordDurationMillis = positiveNumberValue$1(payload.record_duration_millis, record.record_duration_millis, payload.recordDurationMillis, record.recordDurationMillis, payload.cost_mill_sec, record.cost_mill_sec, payload.costMillSec, record.costMillSec);
10966
+ const editDurationMillis = positiveNumberValue$1(payload.edit_duration_millis, record.edit_duration_millis, payload.editDurationMillis, record.editDurationMillis, payload.incr_cost_mill_sec, record.incr_cost_mill_sec, payload.incrCostMillSec, record.incrCostMillSec);
9958
10967
  const itemIndex = items.push({
9959
10968
  itemUid: uid,
9960
10969
  ...source.kind !== "group_chat" || relationUid === "" || senderUserId === session.userId ? {} : { messageRef: this.sealMessageRef(session.userId, source.ownerRef, relationUid, signingKey) },
@@ -9964,16 +10973,16 @@ var ChatService = class {
9964
10973
  sourceOwnerRef: source.ownerRef,
9965
10974
  chatSessionUid: source.ownerRef,
9966
10975
  relationUid,
9967
- recordOwnerUserId: 0,
10976
+ recordOwnerUserId,
9968
10977
  recordUid: uid,
9969
10978
  senderUserId,
9970
10979
  senderName,
9971
10980
  title: stringValue$1(payload.title),
9972
10981
  textContent: stringValue$1(payload.text_content),
9973
10982
  sendAtMillis,
9974
- sourceSequence: numberValue$16(relation.seq),
9975
- templateKind: numberValue$16(payload.template_kind),
9976
- displayKind: numberValue$16(payload.display_kind),
10983
+ sourceSequence: numberValue$15(relation.seq),
10984
+ templateKind: numberValue$15(payload.template_kind),
10985
+ displayKind: numberValue$15(payload.display_kind),
9977
10986
  contentBlocks
9978
10987
  }), signingKey) },
9979
10988
  ...senderUserId > 0 ? { memberRef: await this.sealChatMemberRef(session.userId, source.ownerRef, senderUserId) } : {},
@@ -9984,15 +10993,16 @@ var ChatService = class {
9984
10993
  title: stringValue$1(payload.title),
9985
10994
  textContent: stringValue$1(payload.text_content),
9986
10995
  status: recordStatus,
9987
- sequence: numberValue$16(relation.seq),
9988
- ...numberValue$16(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$16(record.version ?? payload.version) } : {},
10996
+ sequence: numberValue$15(relation.seq),
10997
+ ...numberValue$15(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$15(record.version ?? payload.version) } : {},
9989
10998
  ...aiPolish === void 0 ? {} : { aiPolish },
9990
- templateKind: numberValue$16(payload.template_kind),
9991
- displayKind: numberValue$16(payload.display_kind),
9992
- version: numberValue$16(payload.version ?? record.version),
9993
- updateAtMillis: numberValue$16(payload.update_at ?? record.update_at),
9994
- recordDurationMillis: numberValue$16(payload.record_duration_millis),
9995
- editDurationMillis: numberValue$16(payload.edit_duration_millis),
10999
+ templateKind: numberValue$15(payload.template_kind),
11000
+ displayKind: numberValue$15(payload.display_kind),
11001
+ version: numberValue$15(payload.version ?? record.version),
11002
+ updateAtMillis: numberValue$15(payload.update_at ?? record.update_at),
11003
+ ...recordDurationMillis === void 0 ? {} : { recordDurationMillis },
11004
+ ...editDurationMillis === void 0 ? {} : { editDurationMillis },
11005
+ ...captureContext === void 0 ? {} : { captureContext },
9996
11006
  contentBlocks,
9997
11007
  ...forwardRecords === void 0 ? {} : { forwardRecords },
9998
11008
  ...sharedRecording === void 0 ? {} : { sharedRecording }
@@ -10032,9 +11042,9 @@ var ChatService = class {
10032
11042
  }
10033
11043
  const result = {
10034
11044
  version: 1,
10035
- viewerUserId: Math.trunc(numberValue$16(raw.viewerUserId)),
11045
+ viewerUserId: Math.trunc(numberValue$15(raw.viewerUserId)),
10036
11046
  chatSessionUid: stringValue$1(raw.chatSessionUid).trim(),
10037
- targetUserId: Math.trunc(numberValue$16(raw.targetUserId))
11047
+ targetUserId: Math.trunc(numberValue$15(raw.targetUserId))
10038
11048
  };
10039
11049
  if (raw.version !== 1 || result.viewerUserId !== expectedViewerUserId || result.chatSessionUid !== expectedChatSessionUid || !Number.isSafeInteger(result.targetUserId) || result.targetUserId <= 0) throw new ArkmePluginError("chat-member-ref-invalid", "聊天成员引用与当前账号或会话不匹配", false, 403);
10040
11050
  return result;
@@ -10056,7 +11066,7 @@ var ChatService = class {
10056
11066
  title: input.title.slice(0, 500),
10057
11067
  textContent: input.textContent.slice(0, this.runtime.config.maxTextLength),
10058
11068
  sendAtMillis: Math.trunc(input.sendAtMillis),
10059
- sourceSequence: Math.max(0, Math.trunc(numberValue$16(input.sourceSequence))),
11069
+ sourceSequence: Math.max(0, Math.trunc(numberValue$15(input.sourceSequence))),
10060
11070
  templateKind: Math.trunc(input.templateKind),
10061
11071
  displayKind: Math.trunc(input.displayKind),
10062
11072
  imageCount: contentBlocks.filter((block) => block.kind === "image").length,
@@ -10119,27 +11129,27 @@ var ChatService = class {
10119
11129
  } catch (error) {
10120
11130
  throw new ArkmePluginError("message-action-ref-invalid", "消息操作引用无效,请刷新后重试", false, 400, { cause: error });
10121
11131
  }
10122
- const fileNames = listValue$16(parsed.fileNames).map((value) => stringValue$1(value).trim()).filter((value) => value !== "").slice(0, 5);
11132
+ const fileNames = listValue$15(parsed.fileNames).map((value) => stringValue$1(value).trim()).filter((value) => value !== "").slice(0, 5);
10123
11133
  const result = {
10124
11134
  version: 1,
10125
11135
  sourceKind: stringValue$1(parsed.sourceKind).trim() === "record" ? "record" : "chat_relation",
10126
- userId: Math.trunc(numberValue$16(parsed.userId)),
11136
+ userId: Math.trunc(numberValue$15(parsed.userId)),
10127
11137
  sourceOwnerRef: stringValue$1(parsed.sourceOwnerRef).trim(),
10128
11138
  chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
10129
11139
  relationUid: stringValue$1(parsed.relationUid).trim(),
10130
- recordOwnerUserId: Math.trunc(numberValue$16(parsed.recordOwnerUserId)),
11140
+ recordOwnerUserId: Math.trunc(numberValue$15(parsed.recordOwnerUserId)),
10131
11141
  recordUid: stringValue$1(parsed.recordUid).trim(),
10132
- senderUserId: Math.trunc(numberValue$16(parsed.senderUserId)),
11142
+ senderUserId: Math.trunc(numberValue$15(parsed.senderUserId)),
10133
11143
  senderName: stringValue$1(parsed.senderName).trim() || "Arkme用户",
10134
11144
  title: stringValue$1(parsed.title),
10135
11145
  textContent: stringValue$1(parsed.textContent),
10136
- sendAtMillis: Math.trunc(numberValue$16(parsed.sendAtMillis)),
10137
- sourceSequence: Math.max(0, Math.trunc(numberValue$16(parsed.sourceSequence))),
10138
- templateKind: Math.trunc(numberValue$16(parsed.templateKind)),
10139
- displayKind: Math.trunc(numberValue$16(parsed.displayKind)),
10140
- imageCount: Math.max(0, Math.trunc(numberValue$16(parsed.imageCount))),
10141
- voiceCount: Math.max(0, Math.trunc(numberValue$16(parsed.voiceCount))),
10142
- fileCount: Math.max(0, Math.trunc(numberValue$16(parsed.fileCount))),
11146
+ sendAtMillis: Math.trunc(numberValue$15(parsed.sendAtMillis)),
11147
+ sourceSequence: Math.max(0, Math.trunc(numberValue$15(parsed.sourceSequence))),
11148
+ templateKind: Math.trunc(numberValue$15(parsed.templateKind)),
11149
+ displayKind: Math.trunc(numberValue$15(parsed.displayKind)),
11150
+ imageCount: Math.max(0, Math.trunc(numberValue$15(parsed.imageCount))),
11151
+ voiceCount: Math.max(0, Math.trunc(numberValue$15(parsed.voiceCount))),
11152
+ fileCount: Math.max(0, Math.trunc(numberValue$15(parsed.fileCount))),
10143
11153
  fileNames
10144
11154
  };
10145
11155
  const matchesChatSource = result.sourceKind === "chat_relation" && (source.kind === "private_chat" || source.kind === "group_chat") && result.sourceOwnerRef === source.ownerRef && result.chatSessionUid === source.ownerRef && result.relationUid !== "" && result.recordUid !== "";
@@ -10233,7 +11243,7 @@ var ChatService = class {
10233
11243
  }
10234
11244
  const result = {
10235
11245
  version: 1,
10236
- userId: numberValue$16(parsed.userId),
11246
+ userId: numberValue$15(parsed.userId),
10237
11247
  chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
10238
11248
  relationUid: stringValue$1(parsed.relationUid).trim()
10239
11249
  };
@@ -10246,7 +11256,7 @@ var ChatService = class {
10246
11256
  const CONTACT_REF_TTL_MS = 10 * 6e4;
10247
11257
  const MAX_CONTACT_REFS = 512;
10248
11258
  const CONTACT_REF_PATTERN = /^arkme-contact-v1\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
10249
- function numberValue$15(value) {
11259
+ function numberValue$14(value) {
10250
11260
  const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
10251
11261
  return Number.isFinite(parsed) ? parsed : 0;
10252
11262
  }
@@ -10380,7 +11390,7 @@ var ContactService = class {
10380
11390
  key: `contact:search:${normalized.identifierType}:${normalized.identifier}`,
10381
11391
  bypassCache: true
10382
11392
  });
10383
- const targetUserId = Math.trunc(numberValue$15(data.user_id));
11393
+ const targetUserId = Math.trunc(numberValue$14(data.user_id));
10384
11394
  const registered = booleanValue$7(data.is_registered) && targetUserId > 0;
10385
11395
  const isSelf = booleanValue$7(data.is_self);
10386
11396
  const canAdd = booleanValue$7(data.can_add) && !isSelf && (normalized.kind === "phone" || registered);
@@ -38950,7 +39960,7 @@ const CONTACT_DIRECTORY_PAGE_LIMIT = 50;
38950
39960
  const CONTACT_DIRECTORY_MAX_SOURCE_PAGES = 20;
38951
39961
  const CONTACT_DIRECTORY_REF_PATTERN = /^arkme-directory-contact-v1\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
38952
39962
  const OFFSET_CURSOR_PATTERN = /^arkme-directory-offset-v1\.(bots|teams|contacts)\.([0-9]+)\.([A-Za-z0-9_-]+)$/;
38953
- function numberValue$14(value) {
39963
+ function numberValue$13(value) {
38954
39964
  if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
38955
39965
  if (typeof value === "string" && value.trim() !== "") {
38956
39966
  const parsed = Number(value);
@@ -38958,7 +39968,7 @@ function numberValue$14(value) {
38958
39968
  }
38959
39969
  return 0;
38960
39970
  }
38961
- function listValue$15(value) {
39971
+ function listValue$14(value) {
38962
39972
  return Array.isArray(value) ? value : [];
38963
39973
  }
38964
39974
  function boundedLimit$1(value, fallback = 30) {
@@ -39016,7 +40026,7 @@ var ContactDirectoryService = class {
39016
40026
  key: "directory:teams:count",
39017
40027
  failureCooldownMs: 2e3
39018
40028
  });
39019
- total = Math.max(0, numberValue$14(data.total ?? data.total_count));
40029
+ total = Math.max(0, numberValue$13(data.total ?? data.total_count));
39020
40030
  break;
39021
40031
  }
39022
40032
  case "contacts":
@@ -39116,9 +40126,9 @@ var ContactDirectoryService = class {
39116
40126
  bypassCache: options.refresh === true
39117
40127
  });
39118
40128
  const projected = [];
39119
- for (const value of listValue$15(data.teams ?? data.items ?? data.list)) {
40129
+ for (const value of listValue$14(data.teams ?? data.items ?? data.list)) {
39120
40130
  const raw = objectValue$1(value);
39121
- const teamId = numberValue$14(raw.team_id ?? raw.teamId ?? raw.id);
40131
+ const teamId = numberValue$13(raw.team_id ?? raw.teamId ?? raw.id);
39122
40132
  const displayName = stringValue$1(raw.name ?? raw.team_name ?? raw.teamName).trim();
39123
40133
  if (teamId <= 0 || displayName === "") continue;
39124
40134
  const publicId = stringValue$1(raw.jotmo_id ?? raw.jotmoId).trim();
@@ -39197,10 +40207,10 @@ var ContactDirectoryService = class {
39197
40207
  failureCooldownMs: 2e3,
39198
40208
  bypassCache: options.refresh === true
39199
40209
  });
39200
- const rawItems = listValue$15(data.items);
40210
+ const rawItems = listValue$14(data.items);
39201
40211
  for (const value of rawItems) {
39202
40212
  const raw = objectValue$1(value);
39203
- const targetUserId = numberValue$14(raw.user_id);
40213
+ const targetUserId = numberValue$13(raw.user_id);
39204
40214
  if (targetUserId <= 0 || !Number.isSafeInteger(targetUserId) || descriptorsByUserId.has(targetUserId)) continue;
39205
40215
  const chatSessionUid = stringValue$1(raw.chat_session_uid).trim();
39206
40216
  descriptorsByUserId.set(targetUserId, {
@@ -39231,12 +40241,12 @@ var ContactDirectoryService = class {
39231
40241
  failureCooldownMs: 2e3,
39232
40242
  bypassCache: options.refresh === true
39233
40243
  });
39234
- for (const value of listValue$15(data.items)) {
40244
+ for (const value of listValue$14(data.items)) {
39235
40245
  const bundle = objectValue$1(value);
39236
40246
  const chatSession = objectValue$1(bundle.session);
39237
- if (numberValue$14(chatSession.session_kind) !== 1 || listValue$15(bundle.bot_participants).length > 0) continue;
40247
+ if (numberValue$13(chatSession.session_kind) !== 1 || listValue$14(bundle.bot_participants).length > 0) continue;
39238
40248
  const counterpart = objectValue$1(bundle.private_counterpart);
39239
- const targetUserId = numberValue$14(counterpart.user_id);
40249
+ const targetUserId = numberValue$13(counterpart.user_id);
39240
40250
  if (targetUserId <= 0 || !Number.isSafeInteger(targetUserId)) continue;
39241
40251
  const chatSessionUid = stringValue$1(chatSession.chat_session_uid).trim();
39242
40252
  const existing = descriptorsByUserId.get(targetUserId);
@@ -39318,7 +40328,7 @@ var ContactDirectoryService = class {
39318
40328
  if (normalized === "") return 0;
39319
40329
  const match = OFFSET_CURSOR_PATTERN.exec(normalized);
39320
40330
  if (match === null || match[1] !== section) throw new ArkmePluginError("directory-cursor-invalid", "联系人目录分页游标无效", false);
39321
- const offset = numberValue$14(match[2]);
40331
+ const offset = numberValue$13(match[2]);
39322
40332
  if (offset < 0 || !Number.isSafeInteger(offset)) throw new ArkmePluginError("directory-cursor-invalid", "联系人目录分页游标无效", false);
39323
40333
  const payload = `${section}:${String(viewerUserId)}:${String(offset)}`;
39324
40334
  const supplied = Buffer.from(match[3] ?? "", "base64url");
@@ -39329,13 +40339,13 @@ var ContactDirectoryService = class {
39329
40339
  };
39330
40340
  //#endregion
39331
40341
  //#region src/services/community-service.ts
39332
- function numberValue$13(value) {
40342
+ function numberValue$12(value) {
39333
40343
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
39334
40344
  }
39335
40345
  function booleanValue$6(value) {
39336
40346
  return value === true;
39337
40347
  }
39338
- function listValue$14(value) {
40348
+ function listValue$13(value) {
39339
40349
  return Array.isArray(value) ? value : [];
39340
40350
  }
39341
40351
  var CommunityService = class {
@@ -39354,8 +40364,8 @@ var CommunityService = class {
39354
40364
  const visible = booleanValue$6(data.visible);
39355
40365
  const groupTitle = stringValue$1(data.group_title).trim();
39356
40366
  const snapshot = objectValue$1(data.group_avatar_snapshot);
39357
- const memberCount = Math.max(0, Math.trunc(numberValue$13(snapshot.member_count)));
39358
- const memberIds = listValue$14(snapshot.members).map((member) => numberValue$13(objectValue$1(member).user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0).slice(0, 5);
40367
+ const memberCount = Math.max(0, Math.trunc(numberValue$12(snapshot.member_count)));
40368
+ const memberIds = listValue$13(snapshot.members).map((member) => numberValue$12(objectValue$1(member).user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0).slice(0, 5);
39359
40369
  let avatarRefs = [];
39360
40370
  let groupAvatar;
39361
40371
  if (visible && status === "ready" && memberIds.length > 0) try {
@@ -39363,7 +40373,7 @@ var CommunityService = class {
39363
40373
  groupAvatar = await this.source.groupAvatarPresentation({
39364
40374
  memberCount,
39365
40375
  strategy: stringValue$1(snapshot.strategy).trim(),
39366
- computedAtMillis: numberValue$13(snapshot.computed_at),
40376
+ computedAtMillis: numberValue$12(snapshot.computed_at),
39367
40377
  memberIds
39368
40378
  }, profiles, session.userId);
39369
40379
  avatarRefs = groupAvatar.slots.flatMap((slot) => slot.avatarRef === void 0 ? [] : [slot.avatarRef]);
@@ -39386,7 +40396,7 @@ var CommunityService = class {
39386
40396
  let groupTitle = stringValue$1(data.group_title).trim();
39387
40397
  if (groupTitle === "") try {
39388
40398
  const chatSession = objectValue$1((await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: chatSessionUid }, session, signal)).session);
39389
- if (stringValue$1(chatSession.chat_session_uid).trim() === chatSessionUid && numberValue$13(chatSession.session_kind) === 2) groupTitle = stringValue$1(chatSession.title).trim();
40399
+ if (stringValue$1(chatSession.chat_session_uid).trim() === chatSessionUid && numberValue$12(chatSession.session_kind) === 2) groupTitle = stringValue$1(chatSession.title).trim();
39390
40400
  } catch {}
39391
40401
  if (groupTitle === "") groupTitle = "DSH 内测群";
39392
40402
  this.source.invalidateGroupAvatar(session.userId, chatSessionUid);
@@ -39417,7 +40427,7 @@ var CommunityService = class {
39417
40427
  //#region src/services/extension-review-service.ts
39418
40428
  const ARKME_EXTENSION_REVIEW_REF_TTL_MILLIS = 1800 * 1e3;
39419
40429
  const MAX_ARKME_EXTENSION_REVIEW_REFS = 4096;
39420
- function safeFailureMessage$4(error) {
40430
+ function safeFailureMessage$3(error) {
39421
40431
  if (error instanceof ArkmePluginError) return error.message;
39422
40432
  if (error instanceof Error && error.message.trim() !== "") return error.message;
39423
40433
  return "未知错误";
@@ -39545,7 +40555,7 @@ var ExtensionReviewService = class {
39545
40555
  await this.runtime.stateStore.removeExtensionReviewOperation(userId, operation.clientMutationId);
39546
40556
  throw new ArkmePluginError("extension-review-registry-rejected", `评论已写入首页,但市集未接受:${error.message}`, false, error.httpStatus, { cause: error });
39547
40557
  }
39548
- await this.runtime.stateStore.markExtensionReviewOperation(userId, operation.clientMutationId, "failed", safeFailureMessage$4(error));
40558
+ await this.runtime.stateStore.markExtensionReviewOperation(userId, operation.clientMutationId, "failed", safeFailureMessage$3(error));
39549
40559
  throw new ArkmePluginError("extension-review-registry-pending", "评论已写入首页,但同步到扩展详情失败;请保留当前内容并重试", true, 503, { cause: error });
39550
40560
  }
39551
40561
  const authors = await this.extensionAuthors([result.review.user_id], signal);
@@ -39643,19 +40653,19 @@ var ExtensionReviewService = class {
39643
40653
  };
39644
40654
  //#endregion
39645
40655
  //#region src/services/group-ai-polish-service.ts
39646
- function numberValue$12(value) {
40656
+ function numberValue$11(value) {
39647
40657
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
39648
40658
  }
39649
40659
  function booleanValue$5(value) {
39650
40660
  return value === true;
39651
40661
  }
39652
- function listValue$13(value) {
40662
+ function listValue$12(value) {
39653
40663
  return Array.isArray(value) ? value : [];
39654
40664
  }
39655
40665
  function aiPolishThreadMessages(value) {
39656
40666
  let totalCharacters = 0;
39657
40667
  const messages = [];
39658
- for (const raw of listValue$13(value).slice(-40)) {
40668
+ for (const raw of listValue$12(value).slice(-40)) {
39659
40669
  const item = objectValue$1(raw);
39660
40670
  const id = stringValue$1(item.id).trim();
39661
40671
  const role = stringValue$1(item.role).trim();
@@ -39689,7 +40699,7 @@ function compactAiPolishActorLabel(value) {
39689
40699
  const characters = [...new Intl.Segmenter("zh-CN", { granularity: "grapheme" }).segment(normalized)].map((segment) => segment.segment);
39690
40700
  return characters.length <= 4 ? normalized : characters.slice(0, 4).join("") + "…";
39691
40701
  }
39692
- function safeFailureMessage$3(error) {
40702
+ function safeFailureMessage$2(error) {
39693
40703
  if (error instanceof ArkmePluginError) return error.message;
39694
40704
  if (error instanceof Error && error.message.trim() !== "") return error.message;
39695
40705
  return "未知错误";
@@ -40044,7 +41054,7 @@ var GroupAiPolishService = class {
40044
41054
  polished = this.aiPolishTextResult(data);
40045
41055
  } catch (error) {
40046
41056
  const sent = await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0, void 0, options.signal, options);
40047
- return this.withFailedAiPolishRetry(sent, sourceRef, chatSessionUid, relationUid, recordUid, originalText, 1, session.userId, safeFailureMessage$3(error));
41057
+ return this.withFailedAiPolishRetry(sent, sourceRef, chatSessionUid, relationUid, recordUid, originalText, 1, session.userId, safeFailureMessage$2(error));
40048
41058
  }
40049
41059
  if (polished.state === 1 && polished.action === 1 && polished.polishedText !== "") {
40050
41060
  const activeRule = config.rules.find((rule) => rule.ruleUid === polished.ruleUid);
@@ -40120,23 +41130,23 @@ var GroupAiPolishService = class {
40120
41130
  });
40121
41131
  const config = objectValue$1(data.config ?? data.setting ?? data.settings ?? data);
40122
41132
  const activeRuleUid = stringValue$1(config.active_rule_uid).trim();
40123
- const rules = listValue$13(data.rules).map((raw) => objectValue$1(raw)).map((rule) => {
41133
+ const rules = listValue$12(data.rules).map((raw) => objectValue$1(raw)).map((rule) => {
40124
41134
  const extra = objectValue$1(rule.extra);
40125
41135
  return {
40126
41136
  ruleUid: stringValue$1(rule.rule_uid).trim(),
40127
41137
  name: stringValue$1(rule.name).trim() || "未命名规则",
40128
41138
  ruleText: stringValue$1(rule.rule_text).trim(),
40129
- ruleVersion: numberValue$12(rule.rule_version),
41139
+ ruleVersion: numberValue$11(rule.rule_version),
40130
41140
  threadMessages: aiPolishThreadMessages(extra.rule_thread_messages)
40131
41141
  };
40132
41142
  }).filter((rule) => rule.ruleUid !== "" && rule.ruleText !== "");
40133
41143
  return {
40134
41144
  enabled: booleanValue$5(config.enabled ?? config.is_enabled),
40135
41145
  canManage: booleanValue$5(data.can_manage),
40136
- viewerRole: numberValue$12(data.viewer_role),
41146
+ viewerRole: numberValue$11(data.viewer_role),
40137
41147
  activeRuleUid,
40138
41148
  activeRuleName: rules.find((rule) => rule.ruleUid === activeRuleUid)?.name ?? "",
40139
- updatedAtMillis: numberValue$12(config.update_at),
41149
+ updatedAtMillis: numberValue$11(config.update_at),
40140
41150
  rules
40141
41151
  };
40142
41152
  }
@@ -40159,7 +41169,7 @@ var GroupAiPolishService = class {
40159
41169
  };
40160
41170
  }
40161
41171
  async queryGroupAiPolishNotices(chatSessionUid, session, signal) {
40162
- return listValue$13((await this.runtime.authenticatedChatPost("/api/v1/chats/ai-polish/notices/query", {
41172
+ return listValue$12((await this.runtime.authenticatedChatPost("/api/v1/chats/ai-polish/notices/query", {
40163
41173
  chat_session_uid: chatSessionUid,
40164
41174
  limit: 100
40165
41175
  }, session, signal, {
@@ -40168,15 +41178,15 @@ var GroupAiPolishService = class {
40168
41178
  cacheMs: 15e3,
40169
41179
  failureCooldownMs: 5e3
40170
41180
  })).notices).map((raw) => objectValue$1(raw)).map((notice) => {
40171
- const kind = numberValue$12(notice.notice_kind);
41181
+ const kind = numberValue$11(notice.notice_kind);
40172
41182
  const rule = stringValue$1(notice.rule_name).trim() || stringValue$1(notice.rule_text).trim();
40173
41183
  const actor = compactAiPolishActorLabel(notice.actor_display_name_snapshot);
40174
41184
  return {
40175
41185
  noticeUid: stringValue$1(notice.notice_uid).trim(),
40176
41186
  sourceKey: stringValue$1(notice.source_key).trim(),
40177
41187
  message: kind === 1 ? actor === "" ? `AI润色已开启:${rule}` : `${actor}开启了 AI 润色:${rule}` : kind === 2 ? actor === "" ? `AI润色规则已修改:${rule}` : `${actor}修改了 AI 润色规则:${rule}` : "",
40178
- createdAtMillis: numberValue$12(notice.created_at),
40179
- status: numberValue$12(notice.status)
41188
+ createdAtMillis: numberValue$11(notice.created_at),
41189
+ status: numberValue$11(notice.status)
40180
41190
  };
40181
41191
  }).filter((notice) => notice.noticeUid !== "" && notice.message !== "" && notice.createdAtMillis > 0 && (notice.status === 0 || notice.status === 1)).map(({ status: _status, ...notice }) => notice);
40182
41192
  }
@@ -40217,9 +41227,9 @@ var GroupAiPolishService = class {
40217
41227
  aiPolishTextResult(data) {
40218
41228
  return {
40219
41229
  taskUid: stringValue$1(data.task_uid).trim(),
40220
- attempt: numberValue$12(data.attempt),
40221
- state: numberValue$12(data.state),
40222
- action: numberValue$12(data.action),
41230
+ attempt: numberValue$11(data.attempt),
41231
+ state: numberValue$11(data.state),
41232
+ action: numberValue$11(data.action),
40223
41233
  polishedText: stringValue$1(data.polished_text),
40224
41234
  recordUid: stringValue$1(data.record_uid ?? data.recordUid).trim(),
40225
41235
  revisionUid: stringValue$1(data.revision_uid ?? data.revisionUid).trim(),
@@ -40234,10 +41244,10 @@ var GroupAiPolishService = class {
40234
41244
  //#endregion
40235
41245
  //#region src/services/group-service.ts
40236
41246
  const UUID$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
40237
- function numberValue$11(value) {
41247
+ function numberValue$10(value) {
40238
41248
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
40239
41249
  }
40240
- function listValue$12(value) {
41250
+ function listValue$11(value) {
40241
41251
  return Array.isArray(value) ? value : [];
40242
41252
  }
40243
41253
  function encodeOpaqueJson$5(value) {
@@ -40249,7 +41259,7 @@ function decodeOpaqueJson$4(value) {
40249
41259
  function chatMessageDnd(value) {
40250
41260
  if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
40251
41261
  const policy = value;
40252
- return numberValue$11(policy.mute_state) === 2 || numberValue$11(policy.notify_state) === 2;
41262
+ return numberValue$10(policy.mute_state) === 2 || numberValue$10(policy.notify_state) === 2;
40253
41263
  }
40254
41264
  function chatMemberRole(value) {
40255
41265
  if (value === "owner" || value === 1) return "owner";
@@ -40286,8 +41296,8 @@ var GroupService = class {
40286
41296
  title: stringValue$1(preview.title).trim() || source.displayName,
40287
41297
  inviterDisplayName: stringValue$1(preview.creator_display_name).trim() || "Arkme",
40288
41298
  inviteLink,
40289
- expireAtMillis: numberValue$11(preview.expire_at),
40290
- mode: numberValue$11(preview.join_mode) === 2 ? "approval_invite" : "direct_add"
41299
+ expireAtMillis: numberValue$10(preview.expire_at),
41300
+ mode: numberValue$10(preview.join_mode) === 2 ? "approval_invite" : "direct_add"
40291
41301
  };
40292
41302
  }
40293
41303
  async listGroupMemberCandidates(sourceRef, options = {}) {
@@ -40305,35 +41315,35 @@ var GroupService = class {
40305
41315
  this.runtime.authenticatedChatPost("/api/v1/chats/list", { limit: 50 }, session, options.signal),
40306
41316
  this.runtime.authenticatedChatPost("/api/v1/chats/governance/invite-preview", { chat_session_uid: source.ownerRef }, session, options.signal).catch(() => ({}))
40307
41317
  ]);
40308
- const directoryBundles = listValue$12(directoryData.items);
41318
+ const directoryBundles = listValue$11(directoryData.items);
40309
41319
  const privateBundles = directoryBundles.filter((raw) => {
40310
- const kind = numberValue$11(objectValue$1(objectValue$1(raw).session).session_kind);
41320
+ const kind = numberValue$10(objectValue$1(objectValue$1(raw).session).session_kind);
40311
41321
  return kind === 1 || kind === 3;
40312
41322
  });
40313
41323
  const privateTopicIds = privateBundles.map((raw) => {
40314
41324
  const chatSession = objectValue$1(objectValue$1(raw).session);
40315
- return numberValue$11(chatSession.shared_topic_id ?? chatSession.subject_id);
41325
+ return numberValue$10(chatSession.shared_topic_id ?? chatSession.subject_id);
40316
41326
  }).filter((value) => Number.isSafeInteger(value) && value > 0);
40317
41327
  const partnerData = privateTopicIds.length === 0 ? {} : await this.runtime.authenticatedSubjectPost("/api/v1/private/get-partner-info-v2", { rm_subject_ids: [...new Set(privateTopicIds)] }, session, options.signal).catch(() => ({}));
40318
41328
  const contactByTopicId = /* @__PURE__ */ new Map();
40319
- for (const raw of listValue$12(partnerData.item_ls)) {
41329
+ for (const raw of listValue$11(partnerData.item_ls)) {
40320
41330
  const item = objectValue$1(raw);
40321
- const topicId = numberValue$11(item.rm_subject_id ?? item.shared_topic_id);
41331
+ const topicId = numberValue$10(item.rm_subject_id ?? item.shared_topic_id);
40322
41332
  if (topicId > 0 && typeof item.is_contact === "boolean") contactByTopicId.set(topicId, item.is_contact);
40323
41333
  }
40324
- const existingMemberUserIds = new Set(listValue$12(objectValue$1(membersData).items).map((item) => numberValue$11(objectValue$1(item).user_id)));
41334
+ const existingMemberUserIds = new Set(listValue$11(objectValue$1(membersData).items).map((item) => numberValue$10(objectValue$1(item).user_id)));
40325
41335
  const rawCandidates = /* @__PURE__ */ new Map();
40326
41336
  for (const raw of privateBundles) {
40327
41337
  const bundle = objectValue$1(raw);
40328
41338
  const chatSession = objectValue$1(bundle.session);
40329
- if (numberValue$11(chatSession.session_kind) !== 1 && numberValue$11(chatSession.session_kind) !== 3) continue;
41339
+ if (numberValue$10(chatSession.session_kind) !== 1 && numberValue$10(chatSession.session_kind) !== 3) continue;
40330
41340
  const counterpart = objectValue$1(bundle.private_counterpart);
40331
41341
  const supplement = objectValue$1(bundle.private_supplement);
40332
- const targetUserId = numberValue$11(counterpart.user_id);
41342
+ const targetUserId = numberValue$10(counterpart.user_id);
40333
41343
  const privateChatSessionUid = stringValue$1(chatSession.chat_session_uid).trim();
40334
41344
  const displayName = stringValue$1(supplement.remark ?? supplement.counterpart_name_snapshot ?? counterpart.display_name_snapshot ?? supplement.pending_name ?? counterpart.visible_phone).trim();
40335
- const privateTopicId = numberValue$11(chatSession.shared_topic_id ?? chatSession.subject_id);
40336
- const contactState = numberValue$11(supplement.contact_state);
41345
+ const privateTopicId = numberValue$10(chatSession.shared_topic_id ?? chatSession.subject_id);
41346
+ const contactState = numberValue$10(supplement.contact_state);
40337
41347
  const relation = contactByTopicId.get(privateTopicId) === true || contactState === 1 || contactState === 3 ? "contact" : "stranger";
40338
41348
  if (!Number.isSafeInteger(targetUserId) || targetUserId <= 0 || targetUserId === session.userId || privateChatSessionUid === "" || displayName === "" || query !== "" && !displayName.toLocaleLowerCase().includes(query)) continue;
40339
41349
  rawCandidates.set(targetUserId, {
@@ -40351,7 +41361,7 @@ var GroupService = class {
40351
41361
  for (const raw of directoryBundles) {
40352
41362
  const bundle = objectValue$1(raw);
40353
41363
  const chatSession = objectValue$1(bundle.session);
40354
- if (numberValue$11(chatSession.session_kind) !== 2) continue;
41364
+ if (numberValue$10(chatSession.session_kind) !== 2) continue;
40355
41365
  const groupSessionUid = stringValue$1(chatSession.chat_session_uid).trim();
40356
41366
  if (groupSessionUid === "" || groupSessionUid === source.ownerRef) continue;
40357
41367
  const displayName = stringValue$1(chatSession.title ?? chatSession.subject_title ?? objectValue$1(bundle.participant_summary).display_name).trim();
@@ -40360,7 +41370,7 @@ var GroupService = class {
40360
41370
  sourceKey: await this.source.chatDirectorySourceKey(session.userId, groupSessionUid),
40361
41371
  kind: "group_chat",
40362
41372
  displayName: displayName || "群聊",
40363
- activeAtMillis: numberValue$11(chatSession.updated_at),
41373
+ activeAtMillis: numberValue$10(chatSession.updated_at),
40364
41374
  unreadCount: 0
40365
41375
  };
40366
41376
  const groupIndex = groups.push(groupItem) - 1;
@@ -40388,9 +41398,9 @@ var GroupService = class {
40388
41398
  }, session, options.signal);
40389
41399
  const raws = [];
40390
41400
  const seenUserIds = /* @__PURE__ */ new Set();
40391
- for (const rawMember of listValue$12(groupMembersData.items)) {
41401
+ for (const rawMember of listValue$11(groupMembersData.items)) {
40392
41402
  const member = objectValue$1(rawMember);
40393
- const targetUserId = numberValue$11(member.user_id);
41403
+ const targetUserId = numberValue$10(member.user_id);
40394
41404
  if (!Number.isSafeInteger(targetUserId) || targetUserId <= 0 || targetUserId === session.userId || seenUserIds.has(targetUserId)) continue;
40395
41405
  if (chatMemberStatus(member.status) !== "active") continue;
40396
41406
  const privateCandidate = rawCandidates.get(targetUserId);
@@ -40436,7 +41446,7 @@ var GroupService = class {
40436
41446
  }
40437
41447
  const profiles = await this.profile.publicProfileSummariesByUserIds([.../* @__PURE__ */ new Set([...selected.map(([userId]) => userId), ...groupTargetUserIds])], session, options.signal).catch(() => /* @__PURE__ */ new Map());
40438
41448
  const preview = objectValue$1(objectValue$1(inviteData).preview);
40439
- const approvalRequired = numberValue$11(preview.join_mode) === 2;
41449
+ const approvalRequired = numberValue$10(preview.join_mode) === 2;
40440
41450
  const candidateItem = async (targetUserId, candidate) => {
40441
41451
  const alreadyMember = existingMemberUserIds.has(targetUserId);
40442
41452
  const cannotInvite = approvalRequired && candidate.privateChatSessionUid === void 0;
@@ -40476,7 +41486,7 @@ var GroupService = class {
40476
41486
  items,
40477
41487
  total: rawCandidates.size,
40478
41488
  hasMore: rawCandidates.size > items.length,
40479
- mode: numberValue$11(preview.join_mode) === 2 ? "approval_invite" : "direct_add",
41489
+ mode: numberValue$10(preview.join_mode) === 2 ? "approval_invite" : "direct_add",
40480
41490
  groups,
40481
41491
  groupCandidates,
40482
41492
  contactCount: [...rawCandidates.values()].filter((item) => item.relation === "contact").length,
@@ -40490,7 +41500,7 @@ var GroupService = class {
40490
41500
  const refs = candidateRefs.map((value) => value.trim());
40491
41501
  if (refs.length === 0 || refs.length > 20 || refs.some((value) => value === "") || new Set(refs).size !== refs.length) throw new ArkmePluginError("group-member-candidates-invalid", "请选择 1-20 个不重复的成员候选项", false);
40492
41502
  const preview = objectValue$1(objectValue$1(await this.runtime.authenticatedChatPost("/api/v1/chats/governance/invite-preview", { chat_session_uid: source.ownerRef }, session, signal)).preview);
40493
- const approvalRequired = numberValue$11(preview.join_mode) === 2;
41503
+ const approvalRequired = numberValue$10(preview.join_mode) === 2;
40494
41504
  const inviteLink = stringValue$1(preview.invite_link).trim();
40495
41505
  const results = [];
40496
41506
  for (const candidateRef of refs) {
@@ -40556,9 +41566,9 @@ var GroupService = class {
40556
41566
  }
40557
41567
  const result = {
40558
41568
  version: 1,
40559
- userId: numberValue$11(raw.userId),
41569
+ userId: numberValue$10(raw.userId),
40560
41570
  groupChatSessionUid: stringValue$1(raw.groupChatSessionUid).trim(),
40561
- targetUserId: numberValue$11(raw.targetUserId),
41571
+ targetUserId: numberValue$10(raw.targetUserId),
40562
41572
  displayName: stringValue$1(raw.displayName).trim(),
40563
41573
  ...stringValue$1(raw.privateChatSessionUid).trim() === "" ? {} : { privateChatSessionUid: stringValue$1(raw.privateChatSessionUid).trim() },
40564
41574
  origin: raw.origin === "group_chat" ? "group_chat" : "private_chat"
@@ -40591,15 +41601,15 @@ var GroupService = class {
40591
41601
  const session = await this.runtime.requireSession();
40592
41602
  const source = await this.source.openSourceRef(sourceRef, session.userId);
40593
41603
  if (source.kind !== "group_chat") throw new ArkmePluginError("group-source-invalid", "仅支持查看群聊成员", false);
40594
- const rawItems = listValue$12((await this.runtime.authenticatedChatPost("/api/v1/chats/members/list", {
41604
+ const rawItems = listValue$11((await this.runtime.authenticatedChatPost("/api/v1/chats/members/list", {
40595
41605
  chat_session_uid: source.ownerRef,
40596
41606
  active_only: options.activeOnly !== false
40597
41607
  }, session, options.signal)).items).map(objectValue$1);
40598
- const userIds = rawItems.map((item) => numberValue$11(item.user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0);
41608
+ const userIds = rawItems.map((item) => numberValue$10(item.user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0);
40599
41609
  const profiles = await this.profile.publicProfileSummariesByUserIds(userIds, session, options.signal).catch(() => /* @__PURE__ */ new Map());
40600
41610
  const members = [];
40601
41611
  for (const item of rawItems) {
40602
- const userId = numberValue$11(item.user_id);
41612
+ const userId = numberValue$10(item.user_id);
40603
41613
  if (!Number.isSafeInteger(userId) || userId <= 0) continue;
40604
41614
  const profile = profiles.get(userId);
40605
41615
  const remarkName = stringValue$1(item.remark).trim();
@@ -40628,9 +41638,9 @@ var GroupService = class {
40628
41638
  status,
40629
41639
  isSelf: userId === session.userId,
40630
41640
  isOwner: role === "owner",
40631
- joinedAtMillis: numberValue$11(item.join_at),
40632
- recordCount: Math.max(0, Math.trunc(numberValue$11(objectValue$1(item.extra).record_count))),
40633
- mentionCount: Math.max(0, Math.trunc(numberValue$11(objectValue$1(item.extra).mention_count)))
41641
+ joinedAtMillis: numberValue$10(item.join_at),
41642
+ recordCount: Math.max(0, Math.trunc(numberValue$10(objectValue$1(item.extra).record_count))),
41643
+ mentionCount: Math.max(0, Math.trunc(numberValue$10(objectValue$1(item.extra).mention_count)))
40634
41644
  });
40635
41645
  }
40636
41646
  const roleRank = (role) => role === "owner" ? 0 : role === "admin" ? 1 : role === "member" ? 2 : 3;
@@ -40661,10 +41671,10 @@ var GroupService = class {
40661
41671
  sourceKey: await this.source.chatDirectorySourceKey(session.userId, source.ownerRef),
40662
41672
  kind: "group_chat",
40663
41673
  displayName: title,
40664
- activeAtMillis: numberValue$11(chatSession.last_active_at),
40665
- unreadCount: numberValue$11(objectValue$1(data.unread_snapshot).unread_count),
41674
+ activeAtMillis: numberValue$10(chatSession.last_active_at),
41675
+ unreadCount: numberValue$10(objectValue$1(data.unread_snapshot).unread_count),
40666
41676
  isMuted: messageDnd,
40667
- ...numberValue$11(chatSession.last_seq) > 0 ? { latestSequence: numberValue$11(chatSession.last_seq) } : {}
41677
+ ...numberValue$10(chatSession.last_seq) > 0 ? { latestSequence: numberValue$10(chatSession.last_seq) } : {}
40668
41678
  };
40669
41679
  try {
40670
41680
  await this.source.hydrateSourceAvatars([nextSource], /* @__PURE__ */ new Map(), /* @__PURE__ */ new Map([[0, source.ownerRef]]), session, signal);
@@ -40690,12 +41700,12 @@ var GroupService = class {
40690
41700
  const current = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: source.ownerRef }, session, signal);
40691
41701
  await this.runtime.authenticatedChatPost("/api/v1/chats/policy/update", {
40692
41702
  chat_session_uid: source.ownerRef,
40693
- show_in_home_state: numberValue$11(current.show_in_home_state) || 1,
40694
- privacy_state: numberValue$11(current.privacy_state) || 1,
41703
+ show_in_home_state: numberValue$10(current.show_in_home_state) || 1,
41704
+ privacy_state: numberValue$10(current.privacy_state) || 1,
40695
41705
  mute_state: enabled ? 2 : 1,
40696
- pin_state: numberValue$11(current.pin_state) || 1,
41706
+ pin_state: numberValue$10(current.pin_state) || 1,
40697
41707
  notify_state: enabled ? 2 : 1,
40698
- status: numberValue$11(current.status) || 1,
41708
+ status: numberValue$10(current.status) || 1,
40699
41709
  update_at: Date.now()
40700
41710
  }, session, signal);
40701
41711
  const cacheKey = `${String(session.userId)}:${source.ownerRef}`;
@@ -40777,13 +41787,13 @@ var GroupService = class {
40777
41787
  };
40778
41788
  //#endregion
40779
41789
  //#region src/services/interwoven-service.ts
40780
- function numberValue$10(value) {
41790
+ function numberValue$9(value) {
40781
41791
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
40782
41792
  }
40783
41793
  function booleanValue$4(value) {
40784
41794
  return value === true;
40785
41795
  }
40786
- function listValue$11(value) {
41796
+ function listValue$10(value) {
40787
41797
  return Array.isArray(value) ? value : [];
40788
41798
  }
40789
41799
  var InterwovenService = class {
@@ -40829,27 +41839,27 @@ var InterwovenService = class {
40829
41839
  rm_subject_id: legacyRmSubjectId,
40830
41840
  limit: 100
40831
41841
  }, session, signal);
40832
- const preparedAtMillis = Math.max(0, Math.trunc(numberValue$10(data.prepared_at))) || Date.now();
41842
+ const preparedAtMillis = Math.max(0, Math.trunc(numberValue$9(data.prepared_at))) || Date.now();
40833
41843
  const descriptors = [];
40834
41844
  let invalidItemCount = 0;
40835
- for (const rawGroup of listValue$11(data.groups)) {
41845
+ for (const rawGroup of listValue$10(data.groups)) {
40836
41846
  const group = objectValue$1(rawGroup);
40837
- if (numberValue$10(group.moment_type) !== 1) continue;
41847
+ if (numberValue$9(group.moment_type) !== 1) continue;
40838
41848
  const groupTitle = stringValue$1(group.group_title).trim() || "群聊";
40839
- for (const rawItem of listValue$11(group.group_preview_items)) {
41849
+ for (const rawItem of listValue$10(group.group_preview_items)) {
40840
41850
  const item = objectValue$1(rawItem);
40841
- if (numberValue$10(item.moment_type) !== 1) continue;
41851
+ if (numberValue$9(item.moment_type) !== 1) continue;
40842
41852
  const jumpTarget = objectValue$1(item.jump_target);
40843
41853
  const renderPayload = objectValue$1(item.render_payload);
40844
41854
  const groupName = stringValue$1(renderPayload.group_name ?? item.title).trim() || groupTitle;
40845
41855
  const rawMomentId = stringValue$1(item.moment_id).trim();
40846
- const occurredAtMillis = Math.trunc(numberValue$10(item.occurred_at));
41856
+ const occurredAtMillis = Math.trunc(numberValue$9(item.occurred_at));
40847
41857
  const sourceChatSessionUid = stringValue$1(jumpTarget.chat_session_uid).trim();
40848
- const recordOwnerUserId = Math.trunc(numberValue$10(jumpTarget.record_owner_user_id ?? renderPayload.record_owner_user_id ?? renderPayload.sender_user_id));
41858
+ const recordOwnerUserId = Math.trunc(numberValue$9(jumpTarget.record_owner_user_id ?? renderPayload.record_owner_user_id ?? renderPayload.sender_user_id));
40849
41859
  const recordUid = stringValue$1(jumpTarget.record_uid ?? renderPayload.record_uid).trim();
40850
41860
  const relationUid = stringValue$1(jumpTarget.rel_uid).trim();
40851
- const sequence = Math.trunc(numberValue$10(jumpTarget.seq));
40852
- const senderUserId = Math.trunc(numberValue$10(renderPayload.sender_user_id));
41861
+ const sequence = Math.trunc(numberValue$9(jumpTarget.seq));
41862
+ const senderUserId = Math.trunc(numberValue$9(renderPayload.sender_user_id));
40853
41863
  const hasChatDetailLocator = sourceChatSessionUid !== "" && recordOwnerUserId > 0 && recordUid !== "" && relationUid !== "" && sequence > 0;
40854
41864
  const fallbackTextContent = stringValue$1(renderPayload.content ?? renderPayload.mention_text ?? item.summary).trim().slice(0, 2e4);
40855
41865
  const fallbackTitle = stringValue$1(item.title ?? renderPayload.group_name).trim().slice(0, 500);
@@ -40916,9 +41926,9 @@ var InterwovenService = class {
40916
41926
  });
40917
41927
  }
40918
41928
  moments.sort((left, right) => left.occurredAtMillis - right.occurredAtMillis || left.momentId.localeCompare(right.momentId));
40919
- const sourceStatusPartial = listValue$11(data.source_status).some((raw) => {
41929
+ const sourceStatusPartial = listValue$10(data.source_status).some((raw) => {
40920
41930
  const status = objectValue$1(raw);
40921
- return numberValue$10(status.moment_type) === 1 && numberValue$10(status.status) !== 1;
41931
+ return numberValue$9(status.moment_type) === 1 && numberValue$9(status.status) !== 1;
40922
41932
  });
40923
41933
  if (moments.length === 0 && invalidItemCount === 0 && !sourceStatusPartial) return {
40924
41934
  state: "empty",
@@ -40964,8 +41974,8 @@ var InterwovenService = class {
40964
41974
  const relation = objectValue$1(item.relation);
40965
41975
  const record = objectValue$1(item.record);
40966
41976
  const payload = objectValue$1(record.payload);
40967
- if (stringValue$1(data.chat_session_uid).trim() !== reference.sourceChatSessionUid || stringValue$1(relation.chat_session_uid).trim() !== reference.sourceChatSessionUid || numberValue$10(relation.record_owner_user_id) !== reference.recordOwnerUserId || stringValue$1(relation.record_uid).trim() !== reference.recordUid || stringValue$1(relation.rel_uid).trim() !== reference.relationUid || numberValue$10(relation.seq) !== reference.sequence) throw new ArkmePluginError("interwoven-detail-contract-invalid", "快记详情响应与所选交织瞬间不一致", true, 502);
40968
- const status = Math.trunc(numberValue$10(record.status));
41977
+ if (stringValue$1(data.chat_session_uid).trim() !== reference.sourceChatSessionUid || stringValue$1(relation.chat_session_uid).trim() !== reference.sourceChatSessionUid || numberValue$9(relation.record_owner_user_id) !== reference.recordOwnerUserId || stringValue$1(relation.record_uid).trim() !== reference.recordUid || stringValue$1(relation.rel_uid).trim() !== reference.relationUid || numberValue$9(relation.seq) !== reference.sequence) throw new ArkmePluginError("interwoven-detail-contract-invalid", "快记详情响应与所选交织瞬间不一致", true, 502);
41978
+ const status = Math.trunc(numberValue$9(record.status));
40969
41979
  const title = stringValue$1(payload.title).trim() || reference.groupName;
40970
41980
  const textContent = stringValue$1(payload.text_content).trim();
40971
41981
  return {
@@ -40985,14 +41995,14 @@ var InterwovenService = class {
40985
41995
  const detail = await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: source.ownerRef }, session, signal);
40986
41996
  const chatSession = objectValue$1(detail.session);
40987
41997
  const counterpart = objectValue$1(detail.private_counterpart);
40988
- const counterpartUserId = Math.trunc(numberValue$10(counterpart.user_id));
40989
- if (stringValue$1(chatSession.chat_session_uid).trim() !== source.ownerRef || numberValue$10(chatSession.session_kind) !== 1 || !Number.isSafeInteger(counterpartUserId) || counterpartUserId <= 0 || counterpartUserId === session.userId) throw new ArkmePluginError("interwoven-source-invalid", "交织瞬间仅支持有效的双人私聊", false, 409);
41998
+ const counterpartUserId = Math.trunc(numberValue$9(counterpart.user_id));
41999
+ if (stringValue$1(chatSession.chat_session_uid).trim() !== source.ownerRef || numberValue$9(chatSession.session_kind) !== 1 || !Number.isSafeInteger(counterpartUserId) || counterpartUserId <= 0 || counterpartUserId === session.userId) throw new ArkmePluginError("interwoven-source-invalid", "交织瞬间仅支持有效的双人私聊", false, 409);
40990
42000
  return counterpartUserId;
40991
42001
  }
40992
42002
  async resolveLegacyPrivateSubjectId(counterpartUserId, session, signal) {
40993
42003
  const data = await this.runtime.authenticatedSubjectPost("/api/v1/private/check-contact-chat", { target_user_id: counterpartUserId }, session, signal);
40994
42004
  if (!booleanValue$4(data.exist)) return 0;
40995
- const rmSubjectId = Math.trunc(numberValue$10(data.rm_subject_id));
42005
+ const rmSubjectId = Math.trunc(numberValue$9(data.rm_subject_id));
40996
42006
  if (!Number.isSafeInteger(rmSubjectId) || rmSubjectId <= 0) throw new ArkmePluginError("interwoven-subject-contract-invalid", "私聊交织主题定位响应不完整", true, 502);
40997
42007
  return rmSubjectId;
40998
42008
  }
@@ -41402,10 +42412,10 @@ const IMAGE_CACHE_MAX_BYTES = 32 * 1024 * 1024;
41402
42412
  const IMAGE_CACHE_MAX_ENTRIES = 64;
41403
42413
  const IMAGE_DOWNLOAD_CONCURRENCY = 4;
41404
42414
  const RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND = 4;
41405
- function numberValue$9(value) {
42415
+ function numberValue$8(value) {
41406
42416
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
41407
42417
  }
41408
- function listValue$10(value) {
42418
+ function listValue$9(value) {
41409
42419
  return Array.isArray(value) ? value : [];
41410
42420
  }
41411
42421
  function jsonObjectValue(value) {
@@ -41570,7 +42580,7 @@ var MediaService = class {
41570
42580
  const unique = [...new Set(fileAssetUids.map((uid) => uid.trim()).filter((uid) => uid !== ""))].slice(0, 50);
41571
42581
  if (unique.length === 0) return [];
41572
42582
  const session = await this.runtime.requireSession();
41573
- return listValue$10((await this.runtime.authenticatedPost("/api/v1/files/assets/query", { file_asset_uids: unique }, session, signal)).items).map((raw) => {
42583
+ return listValue$9((await this.runtime.authenticatedPost("/api/v1/files/assets/query", { file_asset_uids: unique }, session, signal)).items).map((raw) => {
41574
42584
  const item = objectValue$1(raw);
41575
42585
  const previewUrl = safeHttpsUrl(item.preview_url);
41576
42586
  const downloadUrl = safeHttpsUrl(item.download_url);
@@ -41635,14 +42645,14 @@ var MediaService = class {
41635
42645
  if (!response.ok) throw new ArkmePluginError("upload-storage-failed", `对象存储上传失败(${String(response.status)})`, true, 502);
41636
42646
  storageETag = response.headers.get("etag") ?? "";
41637
42647
  } else {
41638
- const partSize = Math.trunc(numberValue$9(prepared.multipart_part_size));
41639
- const parts = listValue$10(prepared.multipart_parts).map(objectValue$1);
42648
+ const partSize = Math.trunc(numberValue$8(prepared.multipart_part_size));
42649
+ const parts = listValue$9(prepared.multipart_parts).map(objectValue$1);
41640
42650
  if (partSize <= 0 || parts.length === 0) throw new ArkmePluginError("upload-parts-missing", "分片上传参数缺失", true, 502);
41641
42651
  const handle = await open(filePath, "r");
41642
42652
  try {
41643
42653
  for (const part of parts) {
41644
42654
  options.signal?.throwIfAborted();
41645
- const partNumber = Math.trunc(numberValue$9(part.part_number));
42655
+ const partNumber = Math.trunc(numberValue$8(part.part_number));
41646
42656
  const uploadUrl = stringValue$1(part.upload_url).trim();
41647
42657
  const offset = (partNumber - 1) * partSize;
41648
42658
  const length = Math.min(partSize, metadata.size - offset);
@@ -41681,7 +42691,7 @@ var MediaService = class {
41681
42691
  fileAssetUid,
41682
42692
  fileName: metadata.fileName,
41683
42693
  mimeType: stringValue$1(completed.mime_type).trim() || metadata.mimeType,
41684
- size: numberValue$9(completed.size) || metadata.size,
42694
+ size: numberValue$8(completed.size) || metadata.size,
41685
42695
  fileKind: metadata.fileKind
41686
42696
  };
41687
42697
  } catch (error) {
@@ -41990,8 +43000,8 @@ var MediaService = class {
41990
43000
  voice.uid
41991
43001
  ].map((value) => stringValue$1(value).trim()).find((value) => value !== "");
41992
43002
  if (fileAssetUid === void 0) continue;
41993
- const durationSeconds = numberValue$9(voice.duration_sec ?? voice.durationSec ?? voice.duration);
41994
- const durationMillis = numberValue$9(voice.duration_millis ?? voice.durationMillis ?? voice.duration_ms);
43003
+ const durationSeconds = numberValue$8(voice.duration_sec ?? voice.durationSec ?? voice.duration);
43004
+ const durationMillis = numberValue$8(voice.duration_millis ?? voice.durationMillis ?? voice.duration_ms);
41995
43005
  return {
41996
43006
  ...voice,
41997
43007
  file_asset_uid: fileAssetUid,
@@ -42004,7 +43014,7 @@ var MediaService = class {
42004
43014
  recordMediaRefs(raw) {
42005
43015
  const contentPayload = this.recordContentPayload(raw);
42006
43016
  const voiceRef = this.recordVoiceMediaRef(raw);
42007
- const refs = [...listValue$10(contentPayload.media_refs ?? contentPayload.mediaRefs).map(objectValue$1), ...voiceRef === void 0 ? [] : [voiceRef]].filter((item) => Math.trunc(numberValue$9(item.content_file_role)) !== RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND && stringValue$1(item.file_asset_uid).trim() !== "");
43017
+ const refs = [...listValue$9(contentPayload.media_refs ?? contentPayload.mediaRefs).map(objectValue$1), ...voiceRef === void 0 ? [] : [voiceRef]].filter((item) => Math.trunc(numberValue$8(item.content_file_role)) !== RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND && stringValue$1(item.file_asset_uid).trim() !== "");
42008
43018
  return [...new Map(refs.map((item) => [stringValue$1(item.file_asset_uid).trim(), item])).values()];
42009
43019
  }
42010
43020
  async queryRecordMediaDisplayItems(recordUids, session, signal) {
@@ -42017,11 +43027,11 @@ var MediaService = class {
42017
43027
  key: expectedRecordUids.join(","),
42018
43028
  cacheMs: 1e3
42019
43029
  });
42020
- for (const rawResult of listValue$10(data.items ?? data.results)) {
43030
+ for (const rawResult of listValue$9(data.items ?? data.results)) {
42021
43031
  const result = objectValue$1(rawResult);
42022
43032
  const recordUid = stringValue$1(result.record_uid).trim();
42023
43033
  if (recordUid === "" || !expectedRecordUids.includes(recordUid)) continue;
42024
- displayItemsByRecordUid.set(recordUid, listValue$10(result.items));
43034
+ displayItemsByRecordUid.set(recordUid, listValue$9(result.items));
42025
43035
  }
42026
43036
  return displayItemsByRecordUid;
42027
43037
  }
@@ -42052,7 +43062,7 @@ var MediaService = class {
42052
43062
  remoteUrl,
42053
43063
  mimeType,
42054
43064
  fileName: stringValue$1(item.file_name).trim() || "语音",
42055
- size: Math.max(0, numberValue$9(item.size))
43065
+ size: Math.max(0, numberValue$8(item.size))
42056
43066
  }, `search-audio\0${key}`));
42057
43067
  }
42058
43068
  return mediaRefs;
@@ -42075,7 +43085,7 @@ var MediaService = class {
42075
43085
  purpose: "original",
42076
43086
  mimeType: stringValue$1(item.mime_type) || "application/octet-stream",
42077
43087
  fileName: stringValue$1(item.file_name) || "文件",
42078
- size: Math.max(0, numberValue$9(item.size))
43088
+ size: Math.max(0, numberValue$8(item.size))
42079
43089
  }, `search-file\0${key}`));
42080
43090
  }
42081
43091
  return refs;
@@ -42114,7 +43124,7 @@ var MediaService = class {
42114
43124
  forwardContentBlocks(files, viewerUserId) {
42115
43125
  if (this.runtime.config.richMediaRenderEnabled === false) return [];
42116
43126
  const displayItems = files.slice(0, 32).map(objectValue$1).flatMap((file, index) => {
42117
- if (numberValue$9(file.content_file_role) === RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND) return [];
43127
+ if (numberValue$8(file.content_file_role) === RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND) return [];
42118
43128
  const trustedUrl = (raw) => {
42119
43129
  const value = safeHttpsUrl(raw);
42120
43130
  if (value === void 0) return void 0;
@@ -42125,11 +43135,11 @@ var MediaService = class {
42125
43135
  const previewUrl = trustedUrl(file.preview_url ?? file.previewUrl);
42126
43136
  return [{
42127
43137
  file_name: stringValue$1(file.name ?? file.file_name ?? file.fileName),
42128
- file_kind: numberValue$9(file.type ?? file.file_kind ?? file.fileKind),
43138
+ file_kind: numberValue$8(file.type ?? file.file_kind ?? file.fileKind),
42129
43139
  mime_type: stringValue$1(file.mime_type ?? file.mimeType),
42130
- size: numberValue$9(file.size),
42131
- sort_order: numberValue$9(file.order ?? file.sort_order ?? index),
42132
- duration_sec: numberValue$9(file.duration_sec ?? file.durationSec),
43140
+ size: numberValue$8(file.size),
43141
+ sort_order: numberValue$8(file.order ?? file.sort_order ?? index),
43142
+ duration_sec: numberValue$8(file.duration_sec ?? file.durationSec),
42133
43143
  ...downloadUrl === void 0 ? {} : { download_url: downloadUrl },
42134
43144
  ...previewUrl === void 0 ? {} : { preview_url: previewUrl }
42135
43145
  }];
@@ -42150,7 +43160,7 @@ var MediaService = class {
42150
43160
  remoteUrl,
42151
43161
  mimeType,
42152
43162
  fileName,
42153
- size: Math.max(0, Math.trunc(numberValue$9(item.file_size ?? item.size)))
43163
+ size: Math.max(0, Math.trunc(numberValue$8(item.file_size ?? item.size)))
42154
43164
  }, fileAssetUid === "" ? void 0 : `favorite-sticker:${fileAssetUid}`);
42155
43165
  }
42156
43166
  issueMediaRef(viewerUserId, descriptor, stableIdentity, lifetimeMillis) {
@@ -42187,10 +43197,10 @@ var MediaService = class {
42187
43197
  const core = objectValue$1(root.record_core);
42188
43198
  this.recordContentPayload(raw);
42189
43199
  const displayItems = [
42190
- ...listValue$10(root.media_display_items),
42191
- ...listValue$10(record.media_display_items),
42192
- ...listValue$10(payload.media_display_items),
42193
- ...listValue$10(core.media_display_items),
43200
+ ...listValue$9(root.media_display_items),
43201
+ ...listValue$9(record.media_display_items),
43202
+ ...listValue$9(payload.media_display_items),
43203
+ ...listValue$9(core.media_display_items),
42194
43204
  ...hydratedDisplayItems
42195
43205
  ].map(objectValue$1);
42196
43206
  const displayByAsset = /* @__PURE__ */ new Map();
@@ -42203,11 +43213,11 @@ var MediaService = class {
42203
43213
  ...displayByAsset.get(stringValue$1(ref.file_asset_uid).trim()) ?? {},
42204
43214
  ...ref
42205
43215
  })) : displayItems).filter((item) => {
42206
- return Math.trunc(numberValue$9(item.content_file_role)) !== RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND;
43216
+ return Math.trunc(numberValue$8(item.content_file_role)) !== RECORD_CONTENT_FILE_ROLE_BACKGROUND_SOUND;
42207
43217
  }).flatMap((item, index) => {
42208
43218
  const fileAssetUid = stringValue$1(item.file_asset_uid).trim();
42209
43219
  const fileName = stringValue$1(item.file_name).trim() || `附件-${String(index + 1)}`;
42210
- const fileKind = Math.trunc(numberValue$9(item.file_kind));
43220
+ const fileKind = Math.trunc(numberValue$8(item.file_kind));
42211
43221
  const mimeType = arkmeNormalizedFileMimeType(stringValue$1(item.mime_type).trim().toLowerCase(), fileName);
42212
43222
  const kind = this.mediaKind(fileKind, mimeType, fileName);
42213
43223
  const remoteUrl = stringValue$1(kind === "image" ? item.preview_url ?? item.download_url : item.download_url).trim();
@@ -42218,7 +43228,7 @@ var MediaService = class {
42218
43228
  purpose: "original",
42219
43229
  mimeType,
42220
43230
  fileName,
42221
- size: Math.max(0, Math.trunc(numberValue$9(item.size)))
43231
+ size: Math.max(0, Math.trunc(numberValue$8(item.size)))
42222
43232
  }, fileAssetUid === "" ? void 0 : `original\0${fileAssetUid}`);
42223
43233
  return [{
42224
43234
  kind,
@@ -42227,15 +43237,15 @@ var MediaService = class {
42227
43237
  remoteUrl,
42228
43238
  mimeType,
42229
43239
  fileName,
42230
- size: Math.max(0, Math.trunc(numberValue$9(item.size)))
43240
+ size: Math.max(0, Math.trunc(numberValue$8(item.size)))
42231
43241
  }, kind === "image" && fileAssetUid !== "" ? fileAssetUid : void 0),
42232
43242
  ...fileAssetUid === "" ? {} : { fileAssetUid },
42233
43243
  fileName,
42234
43244
  mimeType,
42235
- size: Math.max(0, Math.trunc(numberValue$9(item.size))),
42236
- ...numberValue$9(item.duration_sec) > 0 ? { durationSec: numberValue$9(item.duration_sec) } : {},
42237
- sortOrder: Math.trunc(numberValue$9(item.sort_order ?? index)),
42238
- ...[1, 3].includes(Math.trunc(numberValue$9(item.render_role))) ? { renderRole: Math.trunc(numberValue$9(item.render_role)) } : {}
43245
+ size: Math.max(0, Math.trunc(numberValue$8(item.size))),
43246
+ ...numberValue$8(item.duration_sec) > 0 ? { durationSec: numberValue$8(item.duration_sec) } : {},
43247
+ sortOrder: Math.trunc(numberValue$8(item.sort_order ?? index)),
43248
+ ...[1, 3].includes(Math.trunc(numberValue$8(item.render_role))) ? { renderRole: Math.trunc(numberValue$8(item.render_role)) } : {}
42239
43249
  }];
42240
43250
  }).sort((left, right) => left.sortOrder - right.sortOrder);
42241
43251
  }
@@ -42332,10 +43342,10 @@ var MediaService = class {
42332
43342
  };
42333
43343
  //#endregion
42334
43344
  //#region src/services/outgoing-call-service.ts
42335
- function numberValue$8(value) {
43345
+ function numberValue$7(value) {
42336
43346
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
42337
43347
  }
42338
- function listValue$9(value) {
43348
+ function listValue$8(value) {
42339
43349
  return Array.isArray(value) ? value : [];
42340
43350
  }
42341
43351
  function callDiag(label, detail) {
@@ -42425,11 +43435,11 @@ var OutgoingCallService = class {
42425
43435
  const detail = await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: source.ownerRef }, session, input.signal);
42426
43436
  const chatSession = objectValue$1(detail.session);
42427
43437
  const sessionUid = stringValue$1(chatSession.chat_session_uid).trim();
42428
- const sessionKind = numberValue$8(chatSession.session_kind);
43438
+ const sessionKind = numberValue$7(chatSession.session_kind);
42429
43439
  if (sessionUid !== source.ownerRef || sessionKind !== 1 && sessionKind !== 3) throw new ArkmePluginError("call-source-invalid", "当前私聊会话不可用,请刷新后重试", false, 409);
42430
43440
  const counterpart = objectValue$1(detail.private_counterpart);
42431
43441
  const supplement = objectValue$1(detail.private_supplement);
42432
- const counterpartUserId = numberValue$8(counterpart.user_id);
43442
+ const counterpartUserId = numberValue$7(counterpart.user_id);
42433
43443
  if (!Number.isSafeInteger(counterpartUserId) || counterpartUserId <= 0 || counterpartUserId === session.userId) throw new ArkmePluginError("call-peer-unavailable", "当前私聊用户不可用,请刷新后重试", false, 409);
42434
43444
  callDiag("prepare_peer_resolved", {
42435
43445
  userId: session.userId,
@@ -42443,7 +43453,7 @@ var OutgoingCallService = class {
42443
43453
  const peerProfile = (await this.profile.publicProfilesByUserIds([counterpartUserId], session, input.signal)).get(counterpartUserId);
42444
43454
  const displayName = detailDisplayName || peerProfile?.displayName || source.displayName || "Arkme 用户";
42445
43455
  const credentials = await this.runtime.authenticatedWebrtcPost("/api/v1/trtc/credentials", {}, session, input.signal);
42446
- const sdkAppId = numberValue$8(credentials.sdk_app_id);
43456
+ const sdkAppId = numberValue$7(credentials.sdk_app_id);
42447
43457
  const trtcUserId = stringValue$1(credentials.user_id).trim();
42448
43458
  const userSig = stringValue$1(credentials.user_sig).trim();
42449
43459
  if (!Number.isSafeInteger(sdkAppId) || sdkAppId <= 0 || trtcUserId === "" || userSig === "") throw new ArkmePluginError("call-credentials-invalid", "桌面通话初始化失败", true, 502);
@@ -42461,7 +43471,7 @@ var OutgoingCallService = class {
42461
43471
  }
42462
43472
  }, session, input.signal);
42463
43473
  const roomId = stringValue$1(room.room_id).trim();
42464
- const calleeAccounts = [...new Set(listValue$9(room.callee_accounts).map((value) => stringValue$1(value).trim()).filter((value) => value !== ""))];
43474
+ const calleeAccounts = [...new Set(listValue$8(room.callee_accounts).map((value) => stringValue$1(value).trim()).filter((value) => value !== ""))];
42465
43475
  if (roomId === "") throw new ArkmePluginError("call-room-invalid", "呼叫房间创建失败,请重试", true, 502);
42466
43476
  if (calleeAccounts.length === 0) throw new ArkmePluginError("call-peer-unavailable", "对方未开通通话,请对方先登录后再试", false, 409);
42467
43477
  callDiag("prepare_room_created", {
@@ -42471,7 +43481,7 @@ var OutgoingCallService = class {
42471
43481
  mediaType: input.mediaType,
42472
43482
  calleeCount: calleeAccounts.length
42473
43483
  });
42474
- const sharedTopicId = numberValue$8(room.shared_topic_id);
43484
+ const sharedTopicId = numberValue$7(room.shared_topic_id);
42475
43485
  const userData = JSON.stringify({
42476
43486
  sharedTopicId: sharedTopicId > 0 ? sharedTopicId : 0,
42477
43487
  sourceTag: "arkme-private-chat-header",
@@ -42550,7 +43560,7 @@ const ARKME_ID_MIN_LENGTH_DEFAULT = 6;
42550
43560
  const ARKME_ID_MIN_LENGTH_STAFF = 5;
42551
43561
  const ARKME_ID_MAX_LENGTH = 20;
42552
43562
  const ARKME_STAFF_ACCOUNT_TYPE = 2;
42553
- function numberValue$7(value) {
43563
+ function numberValue$6(value) {
42554
43564
  return typeof value === "number" && Number.isFinite(value) ? value : 0;
42555
43565
  }
42556
43566
  function booleanValue$3(value) {
@@ -42559,7 +43569,7 @@ function booleanValue$3(value) {
42559
43569
  function optionalBooleanValue(value) {
42560
43570
  return typeof value === "boolean" ? value : void 0;
42561
43571
  }
42562
- function listValue$8(value) {
43572
+ function listValue$7(value) {
42563
43573
  return Array.isArray(value) ? value : [];
42564
43574
  }
42565
43575
  function chunksOf(values, size) {
@@ -42779,7 +43789,7 @@ var ProfileService = class {
42779
43789
  key: "profile:self",
42780
43790
  failureCooldownMs: 2e3
42781
43791
  });
42782
- const userId = numberValue$7(data.user_id);
43792
+ const userId = numberValue$6(data.user_id);
42783
43793
  if (userId <= 0 || userId !== session.userId) throw new ArkmePluginError("profile-contract-invalid", "Arkme 个人资料响应缺少有效用户标识", false, 502);
42784
43794
  const nickname = stringValue$1(data.nick_name).trim();
42785
43795
  const displayName = nickname || stringValue$1(data.apple_nick_name).trim() || stringValue$1(data.wechat_nick_name).trim() || stringValue$1(data.google_given_name).trim() || stringValue$1(data.name_slug).trim() || "Arkme用户";
@@ -42800,8 +43810,8 @@ var ProfileService = class {
42800
43810
  ...avatarUrl === void 0 ? {} : { avatarUrl },
42801
43811
  arkmeId: stringValue$1(data.jotmo_id).trim() || stringValue$1(data.name_slug).trim(),
42802
43812
  ...canUpdateArkmeId === void 0 ? {} : { canUpdateArkmeId },
42803
- accountType: numberValue$7(data.type),
42804
- createdAt: numberValue$7(data.create_at),
43813
+ accountType: numberValue$6(data.type),
43814
+ createdAt: numberValue$6(data.create_at),
42805
43815
  bindings: {
42806
43816
  apple: booleanValue$3(data.has_bind_apple),
42807
43817
  wechat: booleanValue$3(data.has_bind_wechat),
@@ -42854,9 +43864,9 @@ var ProfileService = class {
42854
43864
  key: `public-profiles:${batch.join("|")}`,
42855
43865
  failureCooldownMs: 5e3
42856
43866
  });
42857
- for (const raw of listValue$8(data.items)) {
43867
+ for (const raw of listValue$7(data.items)) {
42858
43868
  const item = objectValue$1(raw);
42859
- const userId = numberValue$7(item.user_id);
43869
+ const userId = numberValue$6(item.user_id);
42860
43870
  if (!batch.includes(userId)) continue;
42861
43871
  const displayName = stringValue$1(item.nick_name ?? item.display_name ?? item.name_slug).trim();
42862
43872
  const nickname = stringValue$1(item.nick_name ?? item.nickname).trim();
@@ -42917,9 +43927,9 @@ var ProfileService = class {
42917
43927
  for (const batch of chunksOf(normalized, 100)) {
42918
43928
  if (batch.length === 0) continue;
42919
43929
  const data = await this.runtime.authenticatedAuthPost("/api/v1/auth/get-public-users-by-ids", { user_ids: batch }, session, signal);
42920
- for (const raw of listValue$8(data.items)) {
43930
+ for (const raw of listValue$7(data.items)) {
42921
43931
  const item = objectValue$1(raw);
42922
- const userId = Math.trunc(numberValue$7(item.user_id));
43932
+ const userId = Math.trunc(numberValue$6(item.user_id));
42923
43933
  if (!batch.includes(userId)) continue;
42924
43934
  let hasAvatar = false;
42925
43935
  const avatarUrl = stringValue$1(item.head_img).trim();
@@ -42958,8 +43968,8 @@ var ProfileService = class {
42958
43968
  }
42959
43969
  const result = {
42960
43970
  version: 1,
42961
- viewerUserId: numberValue$7(parsed.viewerUserId),
42962
- targetUserId: numberValue$7(parsed.targetUserId)
43971
+ viewerUserId: numberValue$6(parsed.viewerUserId),
43972
+ targetUserId: numberValue$6(parsed.targetUserId)
42963
43973
  };
42964
43974
  if (parsed.version !== 1 || result.viewerUserId !== expectedViewerUserId || !Number.isSafeInteger(result.targetUserId) || result.targetUserId <= 0) throw new ArkmePluginError("image-ref-invalid", "Arkme头像引用与当前账号不匹配", false, 403);
42965
43975
  return result;
@@ -42994,419 +44004,6 @@ var ProfileService = class {
42994
44004
  }
42995
44005
  };
42996
44006
  //#endregion
42997
- //#region src/services/record-service.ts
42998
- function numberValue$6(value) {
42999
- return typeof value === "number" && Number.isFinite(value) ? value : 0;
43000
- }
43001
- function listValue$7(value) {
43002
- return Array.isArray(value) ? value : [];
43003
- }
43004
- const DSH_AGENT_INPUT_CREATION_SOURCE = 3;
43005
- const MAX_DEFAULT_CATEGORY_FILTER_BACKFILL_PAGES = 5;
43006
- function integerLikeValue(value) {
43007
- if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
43008
- if (typeof value === "string" && value.trim() !== "") {
43009
- const parsed = Number(value.trim());
43010
- if (Number.isFinite(parsed)) return Math.trunc(parsed);
43011
- }
43012
- return 0;
43013
- }
43014
- function recordCreationSource(raw) {
43015
- const item = objectValue$1(raw);
43016
- const core = objectValue$1(item.record_core);
43017
- return integerLikeValue(item.creation_source ?? item.creationSource ?? core.creation_source ?? core.creationSource);
43018
- }
43019
- function isDSHAgentInputRecord(raw) {
43020
- return recordCreationSource(raw) === DSH_AGENT_INPUT_CREATION_SOURCE;
43021
- }
43022
- function safeFailureMessage$2(error) {
43023
- if (error instanceof ArkmePluginError) return error.message;
43024
- if (error instanceof Error && error.message.trim() !== "") return error.message;
43025
- return "未知错误";
43026
- }
43027
- var RecordService = class {
43028
- runtime;
43029
- media;
43030
- source;
43031
- privacy;
43032
- constructor(runtime, media, source, privacy = new ArkmePrivacyVisibilityService(runtime)) {
43033
- this.runtime = runtime;
43034
- this.media = media;
43035
- this.source = source;
43036
- this.privacy = privacy;
43037
- }
43038
- async longArticleDetail(sourceRef, itemUid, signal) {
43039
- const session = await this.runtime.requireSession();
43040
- const source = await this.source.openSourceRef(sourceRef, session.userId);
43041
- const uid = itemUid.trim();
43042
- if (uid === "") throw new ArkmePluginError("long-article-item-invalid", "长文记录标识无效", false);
43043
- const data = await this.runtime.authenticatedPost("/api/v1/records/detail", { record_uid: uid }, session, signal);
43044
- const core = objectValue$1(data.record_core);
43045
- const recordUid = stringValue$1(core.record_uid).trim();
43046
- const templateKind = numberValue$6(core.template_kind);
43047
- const displayKind = numberValue$6(core.display_kind);
43048
- if (recordUid !== uid || templateKind !== 8 && displayKind !== 1) throw new ArkmePluginError("long-article-not-found", "未找到可用的长文详情", false, 404);
43049
- const originContainerRef = stringValue$1(core.origin_container_ref).trim();
43050
- if (source.kind === "topic") {
43051
- if (stringValue$1(objectValue$1(data.topic_core).topic_uid).trim() !== source.ownerRef) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
43052
- } else if (source.kind === "private_chat" || source.kind === "group_chat") {
43053
- if (originContainerRef !== source.ownerRef) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
43054
- } else if (numberValue$6(core.owner_user_id) !== session.userId) throw new ArkmePluginError("long-article-source-mismatch", "长文不属于当前会话", false, 403);
43055
- const recordDurationMillis = Math.max(0, Math.trunc(numberValue$6(core.record_duration_millis)));
43056
- const editDurationMillis = Math.max(0, Math.trunc(numberValue$6(core.edit_duration_millis)));
43057
- return {
43058
- sourceRef,
43059
- itemUid: recordUid,
43060
- title: stringValue$1(core.title),
43061
- textContent: stringValue$1(core.text_content),
43062
- sendAtMillis: Math.trunc(numberValue$6(core.send_at)),
43063
- updateAtMillis: Math.trunc(numberValue$6(core.update_at)),
43064
- recordDurationMillis,
43065
- editDurationMillis,
43066
- thinkingDurationMillis: recordDurationMillis + editDurationMillis,
43067
- version: Math.trunc(numberValue$6(core.version)),
43068
- editable: numberValue$6(core.owner_user_id) === session.userId && numberValue$6(core.creator_user_id) === session.userId
43069
- };
43070
- }
43071
- async updateLongArticle(sourceRef, itemUid, input) {
43072
- if (this.runtime.config.richMediaSendEnabled === false) throw new ArkmePluginError("rich-content-disabled", "长文编辑已被插件配置关闭", false, 403);
43073
- const session = await this.runtime.requireSession();
43074
- const detail = await this.longArticleDetail(sourceRef, itemUid);
43075
- const title = input.title.trim();
43076
- const textContent = input.textContent.trim();
43077
- const editDurationMillis = Math.max(0, Math.trunc(input.editDurationMillis));
43078
- if (!detail.editable) throw new ArkmePluginError("long-article-not-editable", "只能编辑自己发布的长文", false, 403);
43079
- if (title === "" || title.length > 100 || textContent === "" || textContent.length > 4e4 || !Number.isSafeInteger(input.version) || input.version <= 0 || input.version !== detail.version) throw new ArkmePluginError("long-article-update-invalid", "长文内容或版本无效,请刷新后重试", false, 409);
43080
- await this.runtime.authenticatedPost("/api/v1/records/update", {
43081
- record_uid: detail.itemUid,
43082
- template_kind: 1,
43083
- display_kind: 1,
43084
- title,
43085
- text_content: textContent,
43086
- record_duration_millis: detail.recordDurationMillis,
43087
- edit_duration_millis: editDurationMillis,
43088
- version: detail.version
43089
- }, session);
43090
- return await this.longArticleDetail(sourceRef, itemUid);
43091
- }
43092
- async getLongArticleDraft(sourceRef, itemUid) {
43093
- const session = await this.runtime.requireSession();
43094
- await this.source.openSourceRef(sourceRef, session.userId);
43095
- return await this.runtime.stateStore.getLongArticleDraft(session.userId, sourceRef, itemUid?.trim() || void 0);
43096
- }
43097
- async putLongArticleDraft(draft) {
43098
- const session = await this.runtime.requireSession();
43099
- await this.source.openSourceRef(draft.sourceRef, session.userId);
43100
- const itemUid = draft.itemUid?.trim() || void 0;
43101
- if (draft.title.length > 100 || draft.textContent.length > 4e4 || draft.durationMillis < 0) throw new ArkmePluginError("long-article-draft-invalid", "长文草稿内容无效", false);
43102
- await this.runtime.stateStore.putLongArticleDraft(session.userId, {
43103
- sourceRef: draft.sourceRef,
43104
- ...itemUid === void 0 ? {} : { itemUid },
43105
- title: draft.title,
43106
- textContent: draft.textContent,
43107
- durationMillis: Math.max(0, Math.trunc(draft.durationMillis)),
43108
- updatedAtMillis: Date.now()
43109
- });
43110
- }
43111
- async removeLongArticleDraft(sourceRef, itemUid) {
43112
- const session = await this.runtime.requireSession();
43113
- await this.source.openSourceRef(sourceRef, session.userId);
43114
- await this.runtime.stateStore.removeLongArticleDraft(session.userId, sourceRef, itemUid?.trim() || void 0);
43115
- }
43116
- async cachedSnapshot() {
43117
- const session = await this.runtime.requireSession();
43118
- return await this.runtime.stateStore.cachedSnapshot(session.userId);
43119
- }
43120
- async queryCached(options) {
43121
- const session = await this.runtime.requireSession();
43122
- return await this.runtime.stateStore.queryCached(session.userId, options);
43123
- }
43124
- async refreshLatest() {
43125
- await Promise.all([this.summary(), this.list(50)]);
43126
- }
43127
- async refreshSnapshot() {
43128
- await this.refreshLatest();
43129
- return await this.cachedSnapshot();
43130
- }
43131
- async summary() {
43132
- const session = await this.runtime.requireSession();
43133
- const data = await this.runtime.authenticatedPost("/api/v1/records/uncategorized/summary", {}, session);
43134
- const summary = {
43135
- recordCount: numberValue$6(data.record_count),
43136
- wordsCount: numberValue$6(data.words_count ?? data.available_text_rune_count),
43137
- totalSec: numberValue$6(data.total_sec ?? data.available_voice_duration_sec)
43138
- };
43139
- await this.runtime.stateStore.cacheSummary(session.userId, summary);
43140
- return summary;
43141
- }
43142
- async list(limit, cursor) {
43143
- const session = await this.runtime.requireSession();
43144
- const lockedRecordUids = await this.privacy.lockedRecordUids(session);
43145
- const normalizedLimit = Math.min(50, Math.max(1, Math.trunc(limit || 30)));
43146
- let requestCursor = cursor;
43147
- let hasMore = false;
43148
- let backendNextCursor;
43149
- const visibleRawItems = [];
43150
- for (let pageIndex = 0; pageIndex < MAX_DEFAULT_CATEGORY_FILTER_BACKFILL_PAGES; pageIndex += 1) {
43151
- const data = await this.runtime.authenticatedPost("/api/v1/records/uncategorized/query", {
43152
- limit: normalizedLimit,
43153
- ...requestCursor === void 0 ? {} : {
43154
- cursor_send_at: requestCursor.sendAtMillis,
43155
- cursor_record_uid: requestCursor.recordUid
43156
- }
43157
- }, session);
43158
- const rawPageItems = listValue$7(data.items);
43159
- const visiblePageItems = rawPageItems.filter((raw) => !isDSHAgentInputRecord(raw) && !arkmePrivacyLockedRecord(raw) && !lockedRecordUids.has(this.recordUid(raw)));
43160
- visibleRawItems.push(...visiblePageItems);
43161
- hasMore = data.has_more === true;
43162
- const nextSendAt = numberValue$6(data.next_cursor_send_at);
43163
- const nextUid = stringValue$1(data.next_cursor_record_uid);
43164
- backendNextCursor = nextSendAt > 0 && nextUid !== "" ? {
43165
- sendAtMillis: nextSendAt,
43166
- recordUid: nextUid
43167
- } : void 0;
43168
- const filteredCount = rawPageItems.length - visiblePageItems.length;
43169
- if (visibleRawItems.length >= normalizedLimit || !hasMore || backendNextCursor === void 0 || filteredCount === 0) break;
43170
- requestCursor = backendNextCursor;
43171
- }
43172
- const visibleOverflow = visibleRawItems.length > normalizedLimit;
43173
- const rawItems = visibleRawItems.slice(0, normalizedLimit);
43174
- const media = await this.media.hydrateRecordMediaPage(rawItems, session);
43175
- const items = rawItems.map((raw) => {
43176
- const recordUid = this.recordUid(raw);
43177
- const displayItems = media.displayItemsByRecordUid.get(recordUid);
43178
- return this.recordItem(raw, session.userId, {
43179
- ...displayItems === void 0 ? {} : { displayItems },
43180
- mediaUnavailable: media.unavailableRecordUids.has(recordUid)
43181
- });
43182
- }).filter((item) => item !== void 0);
43183
- const lastVisibleRaw = rawItems.at(-1);
43184
- const lastVisibleCursor = lastVisibleRaw === void 0 ? void 0 : {
43185
- sendAtMillis: numberValue$6(objectValue$1(lastVisibleRaw).send_at ?? objectValue$1(objectValue$1(lastVisibleRaw).record_core).send_at),
43186
- recordUid: this.recordUid(lastVisibleRaw)
43187
- };
43188
- const filledRequestedPage = rawItems.length >= normalizedLimit;
43189
- const nextCursor = lastVisibleCursor !== void 0 && lastVisibleCursor.sendAtMillis > 0 && lastVisibleCursor.recordUid !== "" && (visibleOverflow || filledRequestedPage && hasMore) ? lastVisibleCursor : backendNextCursor;
43190
- const page = {
43191
- items,
43192
- hasMore: hasMore || visibleOverflow,
43193
- ...nextCursor === void 0 ? {} : { nextCursor }
43194
- };
43195
- await this.runtime.stateStore.cachePage(session.userId, page, cursor);
43196
- return page;
43197
- }
43198
- async createText(recordUid, textContent) {
43199
- const session = await this.runtime.requireSession();
43200
- const normalizedUid = recordUid.trim();
43201
- const normalizedText = textContent.trim();
43202
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
43203
- if (normalizedText === "") throw new ArkmePluginError("record-text-empty", "请输入要发给自己的内容", false);
43204
- if (normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-text-too-long", `内容不能超过 ${this.runtime.config.maxTextLength} 个字符`, false);
43205
- const now = Date.now();
43206
- const pending = {
43207
- recordUid: normalizedUid,
43208
- textContent: normalizedText,
43209
- createdAtMillis: now,
43210
- sendAtMillis: now,
43211
- attempts: 0
43212
- };
43213
- await this.runtime.stateStore.putPending(session.userId, pending);
43214
- return await this.sendPending(session, pending);
43215
- }
43216
- async createTextForConversation(recordUid, textContent) {
43217
- try {
43218
- return {
43219
- ...await this.createText(recordUid, textContent),
43220
- localState: "synced"
43221
- };
43222
- } catch (error) {
43223
- const session = await this.runtime.requireSession();
43224
- const pending = (await this.runtime.stateStore.listPending(session.userId)).find((item) => item.recordUid === recordUid);
43225
- if (pending === void 0) throw error;
43226
- return {
43227
- recordUid,
43228
- status: 0,
43229
- localState: "failed",
43230
- error: pending.lastError ?? safeFailureMessage$2(error)
43231
- };
43232
- }
43233
- }
43234
- async createDSHAgentInputText(recordUid, textContent, sendAtMillis) {
43235
- const session = await this.runtime.requireSession();
43236
- const normalizedUid = recordUid.trim();
43237
- const normalizedText = textContent.trim();
43238
- const normalizedSendAt = Math.max(0, Math.trunc(sendAtMillis));
43239
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
43240
- if (normalizedText === "") throw new ArkmePluginError("record-text-empty", "请输入要发给自己的内容", false);
43241
- if (normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-text-too-long", `内容不能超过 ${this.runtime.config.maxTextLength} 个字符`, false);
43242
- const data = await this.runtime.authenticatedPost("/api/v1/records/dsh-agent-input/create", {
43243
- record_uid: normalizedUid,
43244
- template_kind: 1,
43245
- title: "",
43246
- text_content: normalizedText,
43247
- send_at: normalizedSendAt > 0 ? normalizedSendAt : Date.now()
43248
- }, session, void 0, {
43249
- scope: this.runtime.requestScope(session.userId),
43250
- key: `dsh-agent-input:${normalizedUid}`
43251
- });
43252
- this.runtime.invalidateScope(this.runtime.requestScope(session.userId));
43253
- return {
43254
- recordUid: stringValue$1(data.record_uid) || normalizedUid,
43255
- status: numberValue$6(data.status)
43256
- };
43257
- }
43258
- async createFileAssetsForConversation(recordUid, textContent, assets) {
43259
- const session = await this.runtime.requireSession();
43260
- const normalizedUid = recordUid.trim();
43261
- const normalizedText = textContent.trim();
43262
- if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(normalizedUid)) throw new ArkmePluginError("record-uid-invalid", "写入标识无效,请重试", false);
43263
- if (assets.length === 0 || assets.length > 20 || normalizedText.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("record-file-assets-invalid", "附件内容为空、过长或数量超限", false);
43264
- for (const asset of assets) if (!/^[A-Za-z0-9._:-]{8,256}$/.test(asset.fileAssetUid) || asset.fileName.trim() === "" || asset.fileName.length > 255 || !Number.isSafeInteger(asset.size) || asset.size <= 0 || ![
43265
- 1,
43266
- 2,
43267
- 3,
43268
- 4
43269
- ].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
43270
- const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
43271
- record_uid: normalizedUid,
43272
- template_kind: 2,
43273
- display_kind: 0,
43274
- title: "",
43275
- text_content: normalizedText,
43276
- content_payload: {
43277
- payload_kind: 2,
43278
- schema_version: 1,
43279
- text_state: normalizedText === "" ? 3 : 1,
43280
- media_refs: assets.map((asset, index) => ({
43281
- file_asset_uid: asset.fileAssetUid,
43282
- content_file_role: 1,
43283
- render_role: 1,
43284
- sort_order: index,
43285
- file_name: asset.fileName
43286
- }))
43287
- },
43288
- send_at: Date.now()
43289
- }, session);
43290
- return {
43291
- recordUid: stringValue$1(data.record_uid).trim() || normalizedUid,
43292
- status: numberValue$6(data.status)
43293
- };
43294
- }
43295
- async pendingWrites() {
43296
- const session = await this.runtime.requireSession();
43297
- return await this.runtime.stateStore.listPending(session.userId);
43298
- }
43299
- async retryPending(recordUid) {
43300
- const session = await this.runtime.requireSession();
43301
- const pending = (await this.runtime.stateStore.listPending(session.userId)).find((item) => item.recordUid === recordUid);
43302
- if (pending === void 0) throw new ArkmePluginError("outbox-entry-not-found", "待重试内容不存在", false, 404);
43303
- return await this.sendPending(session, pending);
43304
- }
43305
- async sendPending(session, pending) {
43306
- try {
43307
- const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
43308
- record_uid: pending.recordUid,
43309
- template_kind: 1,
43310
- title: "",
43311
- text_content: pending.textContent,
43312
- send_at: pending.sendAtMillis
43313
- }, session);
43314
- const result = {
43315
- recordUid: stringValue$1(data.record_uid) || pending.recordUid,
43316
- status: numberValue$6(data.status)
43317
- };
43318
- await this.runtime.stateStore.markSynced(session.userId, pending.recordUid, result.status);
43319
- return result;
43320
- } catch (error) {
43321
- await this.runtime.stateStore.markAttempt(session.userId, pending.recordUid, safeFailureMessage$2(error));
43322
- throw error;
43323
- }
43324
- }
43325
- recordUid(raw) {
43326
- const item = objectValue$1(raw);
43327
- return stringValue$1(item.record_uid ?? objectValue$1(item.record_core).record_uid).trim();
43328
- }
43329
- recordTimelineItem(item) {
43330
- return {
43331
- itemUid: item.recordUid,
43332
- senderName: "我",
43333
- isMe: true,
43334
- sendAtMillis: item.sendAtMillis,
43335
- title: item.title,
43336
- textContent: item.textContent,
43337
- status: item.status,
43338
- templateKind: item.templateKind,
43339
- version: item.version,
43340
- ...item.displayKind === void 0 ? {} : { displayKind: item.displayKind },
43341
- ...item.contentBlocks === void 0 ? {} : { contentBlocks: item.contentBlocks },
43342
- ...item.mediaUnavailable === true ? { mediaUnavailable: true } : {}
43343
- };
43344
- }
43345
- recordTimelineItemFromRaw(raw, userId, options = {}) {
43346
- const item = objectValue$1(raw);
43347
- const core = objectValue$1(item.record_core);
43348
- return {
43349
- itemUid: stringValue$1(item.record_uid ?? core.record_uid).trim(),
43350
- senderName: stringValue$1(item.nickname).trim() || "我",
43351
- isMe: options.isMe ?? numberValue$6(item.creator_user_id ?? item.owner_user_id ?? core.creator_user_id ?? core.owner_user_id) === userId,
43352
- sendAtMillis: numberValue$6(item.send_at ?? core.send_at),
43353
- title: stringValue$1(item.title ?? core.title),
43354
- textContent: stringValue$1(item.text_content ?? core.text_content),
43355
- status: numberValue$6(item.status ?? core.status),
43356
- templateKind: numberValue$6(item.template_kind ?? core.template_kind),
43357
- displayKind: numberValue$6(item.display_kind ?? core.display_kind),
43358
- version: numberValue$6(item.version ?? core.version),
43359
- updateAtMillis: numberValue$6(item.update_at ?? core.update_at),
43360
- recordDurationMillis: numberValue$6(item.record_duration_millis ?? core.record_duration_millis),
43361
- editDurationMillis: numberValue$6(item.edit_duration_millis ?? core.edit_duration_millis),
43362
- contentBlocks: this.media.richContentBlocks(raw, userId, options.displayItems),
43363
- ...options.selfTopic === void 0 ? {} : { selfTopic: options.selfTopic },
43364
- ...options.mediaUnavailable === true ? { mediaUnavailable: true } : {}
43365
- };
43366
- }
43367
- recordItem(raw, userId, options = {}) {
43368
- const item = objectValue$1(raw);
43369
- const core = objectValue$1(item.record_core);
43370
- const recordUid = stringValue$1(item.record_uid ?? core.record_uid).trim();
43371
- if (recordUid === "") return void 0;
43372
- return {
43373
- recordUid,
43374
- sendAtMillis: numberValue$6(item.send_at ?? core.send_at),
43375
- title: stringValue$1(core.title),
43376
- textContent: stringValue$1(core.text_content),
43377
- templateKind: numberValue$6(core.template_kind),
43378
- status: numberValue$6(core.status),
43379
- version: numberValue$6(core.version),
43380
- creationSource: recordCreationSource(raw),
43381
- displayKind: numberValue$6(item.display_kind ?? core.display_kind),
43382
- ...userId === void 0 ? {} : { contentBlocks: this.media.richContentBlocks(raw, userId, options.displayItems) },
43383
- ...options.mediaUnavailable === true ? { mediaUnavailable: true } : {}
43384
- };
43385
- }
43386
- isDSHAgentInput(raw) {
43387
- return isDSHAgentInputRecord(raw);
43388
- }
43389
- isPrivacyLocked(raw) {
43390
- return arkmePrivacyLockedRecord(raw);
43391
- }
43392
- async syncHistory(maxPages = 20, signal) {
43393
- const pageCap = Math.min(20, Math.max(1, Math.trunc(maxPages)));
43394
- await this.refreshLatest();
43395
- let snapshot = await this.cachedSnapshot();
43396
- let pages = 0;
43397
- while (snapshot.hasMore && snapshot.nextCursor !== void 0 && pages < pageCap) {
43398
- if (signal?.aborted === true) throw new Error("Arkme历史同步已取消");
43399
- await this.list(50, snapshot.nextCursor);
43400
- pages += 1;
43401
- snapshot = await this.cachedSnapshot();
43402
- }
43403
- return {
43404
- pages,
43405
- complete: !snapshot.hasMore
43406
- };
43407
- }
43408
- };
43409
- //#endregion
43410
44007
  //#region src/recording-presentation.ts
43411
44008
  function objectValue(value) {
43412
44009
  return value !== null && typeof value === "object" && !Array.isArray(value) ? value : {};
@@ -48519,6 +49116,12 @@ var ArkmeService = class {
48519
49116
  async sharedRecordingDetail(detailRef, options = {}) {
48520
49117
  return await this.chat.sharedRecordingDetail(detailRef, options);
48521
49118
  }
49119
+ async messageSnapshotDetail(sourceRef, actionRef, options = {}) {
49120
+ return await this.chat.messageSnapshotDetail(sourceRef, actionRef, options);
49121
+ }
49122
+ async saveMessageLocation(sourceRef, itemUid, location, recordVersion, options = {}) {
49123
+ await this.chat.saveMessageLocation(sourceRef, itemUid, location, recordVersion, options);
49124
+ }
48522
49125
  async messageReadReceiptSummaries(sourceRef, items, options = {}) {
48523
49126
  return await this.chat.messageReadReceiptSummaries(sourceRef, items, options);
48524
49127
  }