@senguoyun/dsh-arkme 0.1.31 → 0.1.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +1946 -762
- package/lib/client.js.map +1 -1
- package/lib/index.js +3693 -171
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-BJ8konXI.js → persistent-runtime-CFeIg6aw.js} +1520 -681
- package/lib/sdk.js +38 -0
- package/lib/types/arkme-service.d.ts +25 -10
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeBillingSettings.d.ts.map +1 -1
- package/lib/types/client/ArkmeBotConversationSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeBotSettingsPanel.d.ts.map +1 -1
- package/lib/types/client/ArkmeGroupChatControls.d.ts +17 -1
- package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
- package/lib/types/client/ArkmeLinkText.d.ts +13 -0
- package/lib/types/client/ArkmeLinkText.d.ts.map +1 -0
- package/lib/types/client/ArkmeLongArticleDialog.d.ts.map +1 -1
- package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeQuickAdd.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichContent.d.ts +4 -21
- package/lib/types/client/ArkmeRichContent.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichText.d.ts +12 -0
- package/lib/types/client/ArkmeRichText.d.ts.map +1 -0
- package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/bot-chat-directory-projection.d.ts +7 -0
- package/lib/types/client/bot-chat-directory-projection.d.ts.map +1 -0
- package/lib/types/client/link-metadata-client.d.ts +20 -0
- package/lib/types/client/link-metadata-client.d.ts.map +1 -0
- package/lib/types/client/realtime-client-events.d.ts +4 -1
- package/lib/types/client/realtime-client-events.d.ts.map +1 -1
- package/lib/types/client/redesign/contacts/AlphabeticalContactList.d.ts +3 -3
- package/lib/types/client/redesign/contacts/AlphabeticalContactList.d.ts.map +1 -1
- package/lib/types/client/redesign/contacts/ContactDirectorySurface.d.ts +3 -3
- package/lib/types/client/redesign/contacts/ContactDirectorySurface.d.ts.map +1 -1
- package/lib/types/client/related-recordings.d.ts +3 -0
- package/lib/types/client/related-recordings.d.ts.map +1 -1
- package/lib/types/client/text-link-parser.d.ts +10 -0
- package/lib/types/client/text-link-parser.d.ts.map +1 -0
- package/lib/types/client/text-link-tlds.d.ts +2 -0
- package/lib/types/client/text-link-tlds.d.ts.map +1 -0
- package/lib/types/client/ui-controller.d.ts.map +1 -1
- package/lib/types/dsh-host-capabilities.d.ts +10 -0
- package/lib/types/dsh-host-capabilities.d.ts.map +1 -0
- package/lib/types/dsh-remote/api-proxy-adapter.d.ts +250 -0
- package/lib/types/dsh-remote/api-proxy-adapter.d.ts.map +1 -0
- package/lib/types/dsh-remote/channel-manager.d.ts +45 -0
- package/lib/types/dsh-remote/channel-manager.d.ts.map +1 -0
- package/lib/types/dsh-remote/command-ledger.d.ts +60 -0
- package/lib/types/dsh-remote/command-ledger.d.ts.map +1 -0
- package/lib/types/dsh-remote/control-plane.d.ts +17 -0
- package/lib/types/dsh-remote/control-plane.d.ts.map +1 -0
- package/lib/types/dsh-remote/crypto.d.ts +11 -0
- package/lib/types/dsh-remote/crypto.d.ts.map +1 -0
- package/lib/types/dsh-remote/default-socket-factory.d.ts +8 -0
- package/lib/types/dsh-remote/default-socket-factory.d.ts.map +1 -0
- package/lib/types/dsh-remote/dsh-event-contract.d.ts +29 -0
- package/lib/types/dsh-remote/dsh-event-contract.d.ts.map +1 -0
- package/lib/types/dsh-remote/errors.d.ts +9 -0
- package/lib/types/dsh-remote/errors.d.ts.map +1 -0
- package/lib/types/dsh-remote/host.d.ts +85 -0
- package/lib/types/dsh-remote/host.d.ts.map +1 -0
- package/lib/types/dsh-remote/protocol-v1.d.ts +6 -0
- package/lib/types/dsh-remote/protocol-v1.d.ts.map +1 -0
- package/lib/types/dsh-remote/realtime-transport.d.ts +84 -0
- package/lib/types/dsh-remote/realtime-transport.d.ts.map +1 -0
- package/lib/types/dsh-remote/runtime-secret-broker.d.ts +28 -0
- package/lib/types/dsh-remote/runtime-secret-broker.d.ts.map +1 -0
- package/lib/types/dsh-remote/runtime-store.d.ts +39 -0
- package/lib/types/dsh-remote/runtime-store.d.ts.map +1 -0
- package/lib/types/dsh-remote/transport-fragment.d.ts +10 -0
- package/lib/types/dsh-remote/transport-fragment.d.ts.map +1 -0
- package/lib/types/dsh-remote/types.d.ts +164 -0
- package/lib/types/dsh-remote/types.d.ts.map +1 -0
- package/lib/types/harness-embed-route.d.ts +11 -1
- package/lib/types/harness-embed-route.d.ts.map +1 -1
- package/lib/types/host-api.d.ts +3 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts +14 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/keychain-store.d.ts +33 -0
- package/lib/types/keychain-store.d.ts.map +1 -1
- package/lib/types/link-metadata.d.ts +9 -0
- package/lib/types/link-metadata.d.ts.map +1 -0
- package/lib/types/managed-ai/adapter.d.ts +2 -0
- package/lib/types/managed-ai/adapter.d.ts.map +1 -1
- package/lib/types/sdk/index.d.ts +9 -2
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/bot-conversation-service.d.ts +59 -0
- package/lib/types/services/bot-conversation-service.d.ts.map +1 -0
- package/lib/types/services/bot-service.d.ts +11 -29
- package/lib/types/services/bot-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +30 -5
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/contact-directory-service.d.ts.map +1 -1
- package/lib/types/services/link-metadata-service.d.ts +73 -0
- package/lib/types/services/link-metadata-service.d.ts.map +1 -0
- package/lib/types/services/related-recording-service.d.ts +1 -0
- package/lib/types/services/related-recording-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts +4 -2
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/tools/ports/bots.d.ts +1 -1
- package/lib/types/tools/ports/bots.d.ts.map +1 -1
- package/lib/types/types.d.ts +55 -21
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +23 -23
|
@@ -4,6 +4,10 @@ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } fr
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { chmod as chmod$1, copyFile, link, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
6
6
|
import { pinyin } from "pinyin-pro";
|
|
7
|
+
import { Resolver } from "node:dns/promises";
|
|
8
|
+
import { request } from "node:http";
|
|
9
|
+
import { request as request$1 } from "node:https";
|
|
10
|
+
import { BlockList, isIP } from "node:net";
|
|
7
11
|
import OSS from "ali-oss";
|
|
8
12
|
import { Readable } from "node:stream";
|
|
9
13
|
import { gunzipSync, gzipSync } from "node:zlib";
|
|
@@ -1006,7 +1010,7 @@ var ServiceRuntime = class {
|
|
|
1006
1010
|
signal.removeEventListener("abort", abort);
|
|
1007
1011
|
}
|
|
1008
1012
|
}
|
|
1009
|
-
async get(baseUrl, path, bearer, successCodes, signal, options = {}) {
|
|
1013
|
+
async get(baseUrl, path, bearer, successCodes, signal, options = {}, preferDataError = false) {
|
|
1010
1014
|
return await this.requestCoordinator.run({
|
|
1011
1015
|
scope: options.scope ?? "public",
|
|
1012
1016
|
lane: options.lane ?? "interactive-read",
|
|
@@ -1022,10 +1026,10 @@ var ServiceRuntime = class {
|
|
|
1022
1026
|
"login-expired"
|
|
1023
1027
|
].includes(error.code),
|
|
1024
1028
|
serviceCooldownMs: (error) => this.remoteServiceCooldownMs(error),
|
|
1025
|
-
operation: async (coordinatedSignal) => await this.getDirect(baseUrl, path, bearer, successCodes, coordinatedSignal)
|
|
1029
|
+
operation: async (coordinatedSignal) => await this.getDirect(baseUrl, path, bearer, successCodes, coordinatedSignal, preferDataError)
|
|
1026
1030
|
});
|
|
1027
1031
|
}
|
|
1028
|
-
async getDirect(baseUrl, path, bearer, successCodes, signal = new AbortController().signal) {
|
|
1032
|
+
async getDirect(baseUrl, path, bearer, successCodes, signal = new AbortController().signal, preferDataError = false) {
|
|
1029
1033
|
const controller = new AbortController();
|
|
1030
1034
|
const abort = () => controller.abort(signal.reason);
|
|
1031
1035
|
if (signal.aborted) abort();
|
|
@@ -1055,7 +1059,12 @@ var ServiceRuntime = class {
|
|
|
1055
1059
|
} catch (error) {
|
|
1056
1060
|
throw new ArkmePluginError("arkme-response-invalid", "Arkme 服务返回了无效响应", true, 502, { cause: error });
|
|
1057
1061
|
}
|
|
1058
|
-
if (!successCodes.includes(envelope.code))
|
|
1062
|
+
if (!successCodes.includes(envelope.code)) {
|
|
1063
|
+
const errorData = objectValue$1(envelope.data);
|
|
1064
|
+
const serviceErrorCode = preferDataError ? stringValue$1(errorData.error_code).trim() : "";
|
|
1065
|
+
const serviceMessage = preferDataError ? stringValue$1(errorData.message).trim() : "";
|
|
1066
|
+
throw new ArkmePluginError(serviceErrorCode || `arkme-code-${envelope.code}`, serviceMessage || envelope.message?.trim() || "Arkme 服务请求失败", serviceErrorCode === "" ? envelope.code >= 500 : serviceErrorCode === "PAIRING_RATE_LIMITED", 502);
|
|
1067
|
+
}
|
|
1059
1068
|
return envelope.data ?? {};
|
|
1060
1069
|
} catch (error) {
|
|
1061
1070
|
if (error instanceof ArkmePluginError) throw error;
|
|
@@ -1085,6 +1094,17 @@ var ServiceRuntime = class {
|
|
|
1085
1094
|
return await this.get(this.config.authBaseUrl, path, session.accessToken, [200], signal, requestOptions());
|
|
1086
1095
|
}
|
|
1087
1096
|
}
|
|
1097
|
+
async authenticatedDshRemoteGet(path, signal) {
|
|
1098
|
+
let session = await this.requireSession();
|
|
1099
|
+
const requestOptions = () => this.authenticatedRequestOptions(session, "auth", "interactive-read", { bypassCache: true });
|
|
1100
|
+
try {
|
|
1101
|
+
return await this.get(this.config.authBaseUrl, path, session.accessToken, [200], signal, requestOptions(), true);
|
|
1102
|
+
} catch (error) {
|
|
1103
|
+
if (!(error instanceof ArkmePluginError) || !["auth-http-401", "auth-http-403"].includes(error.code)) throw error;
|
|
1104
|
+
session = await this.refreshAccessToken(session);
|
|
1105
|
+
return await this.get(this.config.authBaseUrl, path, session.accessToken, [200], signal, requestOptions(), true);
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1088
1108
|
async authenticatedPost(path, body, initialSession, signal, options = {}) {
|
|
1089
1109
|
let session = initialSession ?? await this.requireSession();
|
|
1090
1110
|
const requestOptions = () => this.authenticatedRequestOptions(session, "record", "write", options);
|
|
@@ -1131,6 +1151,17 @@ var ServiceRuntime = class {
|
|
|
1131
1151
|
return await this.post(this.config.authBaseUrl, path, body, session.accessToken, [200], signal, false, requestOptions());
|
|
1132
1152
|
}
|
|
1133
1153
|
}
|
|
1154
|
+
async authenticatedDshRemotePost(path, body, initialSession, signal) {
|
|
1155
|
+
let session = initialSession ?? await this.requireSession();
|
|
1156
|
+
const requestOptions = () => this.authenticatedRequestOptions(session, "auth", "write", { bypassCache: true });
|
|
1157
|
+
try {
|
|
1158
|
+
return await this.post(this.config.authBaseUrl, path, body, session.accessToken, [200], signal, true, requestOptions());
|
|
1159
|
+
} catch (error) {
|
|
1160
|
+
if (!(error instanceof ArkmePluginError) || !["auth-http-401", "auth-http-403"].includes(error.code)) throw error;
|
|
1161
|
+
session = await this.refreshAccessToken(session);
|
|
1162
|
+
return await this.post(this.config.authBaseUrl, path, body, session.accessToken, [200], signal, true, requestOptions());
|
|
1163
|
+
}
|
|
1164
|
+
}
|
|
1134
1165
|
async authenticatedSubjectPost(path, body, initialSession, signal) {
|
|
1135
1166
|
let session = initialSession ?? await this.requireSession();
|
|
1136
1167
|
try {
|
|
@@ -1813,13 +1844,13 @@ function bestMatchingCategory(text) {
|
|
|
1813
1844
|
}
|
|
1814
1845
|
//#endregion
|
|
1815
1846
|
//#region src/services/ai-video-service.ts
|
|
1816
|
-
function numberValue$
|
|
1847
|
+
function numberValue$25(value) {
|
|
1817
1848
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1818
1849
|
}
|
|
1819
|
-
function booleanValue$
|
|
1850
|
+
function booleanValue$15(value) {
|
|
1820
1851
|
return value === true;
|
|
1821
1852
|
}
|
|
1822
|
-
function listValue$
|
|
1853
|
+
function listValue$26(value) {
|
|
1823
1854
|
return Array.isArray(value) ? value : [];
|
|
1824
1855
|
}
|
|
1825
1856
|
var AiVideoService = class {
|
|
@@ -1831,12 +1862,12 @@ var AiVideoService = class {
|
|
|
1831
1862
|
const session = await this.runtime.requireSession();
|
|
1832
1863
|
const data = await this.runtime.authenticatedIntelligentPost("/api/v1/ai-comic-video/preflight", this.aiVideoSelectionBody(sessionId, segments), session, signal);
|
|
1833
1864
|
return {
|
|
1834
|
-
allowed: booleanValue$
|
|
1865
|
+
allowed: booleanValue$15(data.allowed),
|
|
1835
1866
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
1836
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1837
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
1838
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
1839
|
-
retryable: booleanValue$
|
|
1867
|
+
selectedDurationMillis: Math.max(0, numberValue$25(data.selected_duration_millis)),
|
|
1868
|
+
minimumDurationMillis: Math.max(0, numberValue$25(data.minimum_duration_millis)),
|
|
1869
|
+
selectedSegmentCount: Math.max(0, numberValue$25(data.selected_segment_count)),
|
|
1870
|
+
retryable: booleanValue$15(data.retryable),
|
|
1840
1871
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
1841
1872
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
1842
1873
|
};
|
|
@@ -1871,8 +1902,8 @@ var AiVideoService = class {
|
|
|
1871
1902
|
...options.statuses === void 0 || options.statuses.length === 0 ? {} : { statuses: options.statuses }
|
|
1872
1903
|
}, session, options.signal);
|
|
1873
1904
|
return {
|
|
1874
|
-
items: listValue$
|
|
1875
|
-
hasMore: booleanValue$
|
|
1905
|
+
items: listValue$26(data.items).map((raw) => this.aiVideoListItem(raw)).filter((item) => item !== void 0),
|
|
1906
|
+
hasMore: booleanValue$15(data.has_more),
|
|
1876
1907
|
...stringValue$1(data.next_cursor).trim() === "" ? {} : { nextCursor: stringValue$1(data.next_cursor).trim() }
|
|
1877
1908
|
};
|
|
1878
1909
|
}
|
|
@@ -1883,13 +1914,13 @@ var AiVideoService = class {
|
|
|
1883
1914
|
texts
|
|
1884
1915
|
}, session, signal);
|
|
1885
1916
|
return {
|
|
1886
|
-
allowed: booleanValue$
|
|
1917
|
+
allowed: booleanValue$15(data.allowed),
|
|
1887
1918
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
1888
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1889
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
1890
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
1891
|
-
selectedTextCount: Math.max(0, numberValue$
|
|
1892
|
-
retryable: booleanValue$
|
|
1919
|
+
selectedDurationMillis: Math.max(0, numberValue$25(data.selected_duration_millis)),
|
|
1920
|
+
minimumDurationMillis: Math.max(0, numberValue$25(data.minimum_duration_millis)),
|
|
1921
|
+
selectedSegmentCount: Math.max(0, numberValue$25(data.selected_segment_count)),
|
|
1922
|
+
selectedTextCount: Math.max(0, numberValue$25(data.selected_text_count)),
|
|
1923
|
+
retryable: booleanValue$15(data.retryable),
|
|
1893
1924
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
1894
1925
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
1895
1926
|
};
|
|
@@ -1928,19 +1959,19 @@ var AiVideoService = class {
|
|
|
1928
1959
|
"canceled"
|
|
1929
1960
|
])).has(status)) throw new ArkmePluginError("ai-video-contract-invalid", "AI 视频服务返回了无效任务信息", true, 502);
|
|
1930
1961
|
const selection = objectValue$1(data.selection);
|
|
1931
|
-
const segmentCount = listValue$
|
|
1932
|
-
const textCount = listValue$
|
|
1962
|
+
const segmentCount = listValue$26(selection.segments).length;
|
|
1963
|
+
const textCount = listValue$26(selection.texts).length;
|
|
1933
1964
|
return {
|
|
1934
1965
|
jobId,
|
|
1935
1966
|
status,
|
|
1936
1967
|
stage: stringValue$1(data.stage).trim() || status,
|
|
1937
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
1968
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$25(data.progress)))),
|
|
1938
1969
|
selectedSegmentCount: segmentCount,
|
|
1939
1970
|
...textCount === 0 ? {} : { selectedTextCount: textCount },
|
|
1940
|
-
retryable: booleanValue$
|
|
1971
|
+
retryable: booleanValue$15(data.retryable),
|
|
1941
1972
|
...stringValue$1(data.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(data.video_asset_uid).trim() },
|
|
1942
1973
|
...stringValue$1(data.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(data.cover_asset_uid).trim() },
|
|
1943
|
-
...numberValue$
|
|
1974
|
+
...numberValue$25(data.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$25(data.video_duration_millis) },
|
|
1944
1975
|
...stringValue$1(data.error_code).trim() === "" ? {} : { errorCode: stringValue$1(data.error_code).trim() },
|
|
1945
1976
|
...stringValue$1(data.error_message).trim() === "" ? {} : { errorMessage: stringValue$1(data.error_message).trim() },
|
|
1946
1977
|
...stringValue$1(data.failure_stage).trim() === "" ? {} : { failureStage: stringValue$1(data.failure_stage).trim() }
|
|
@@ -1963,17 +1994,17 @@ var AiVideoService = class {
|
|
|
1963
1994
|
sessionId: stringValue$1(item.session_id).trim(),
|
|
1964
1995
|
status,
|
|
1965
1996
|
stage: stringValue$1(item.stage).trim() || status,
|
|
1966
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
1997
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$25(item.progress)))),
|
|
1967
1998
|
title: stringValue$1(source.title).trim() || "长录音 AI 视频",
|
|
1968
|
-
sourceStartedAtMillis: numberValue$
|
|
1969
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1970
|
-
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$
|
|
1971
|
-
retryable: booleanValue$
|
|
1972
|
-
createdAtMillis: numberValue$
|
|
1973
|
-
updatedAtMillis: numberValue$
|
|
1999
|
+
sourceStartedAtMillis: numberValue$25(source.started_at),
|
|
2000
|
+
selectedDurationMillis: Math.max(0, numberValue$25(source.selected_duration_millis)),
|
|
2001
|
+
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$25(item.selected_segment_count))),
|
|
2002
|
+
retryable: booleanValue$15(item.retryable),
|
|
2003
|
+
createdAtMillis: numberValue$25(item.created_at),
|
|
2004
|
+
updatedAtMillis: numberValue$25(item.updated_at),
|
|
1974
2005
|
...stringValue$1(item.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(item.cover_asset_uid).trim() },
|
|
1975
2006
|
...stringValue$1(item.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(item.video_asset_uid).trim() },
|
|
1976
|
-
...numberValue$
|
|
2007
|
+
...numberValue$25(item.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$25(item.video_duration_millis) },
|
|
1977
2008
|
...stringValue$1(item.error_code).trim() === "" ? {} : { errorCode: stringValue$1(item.error_code).trim() },
|
|
1978
2009
|
...stringValue$1(item.error_message).trim() === "" ? {} : { errorMessage: clippedText(item.error_message, 500) }
|
|
1979
2010
|
};
|
|
@@ -1999,13 +2030,13 @@ const ARKO_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
|
1999
2030
|
"expired"
|
|
2000
2031
|
]);
|
|
2001
2032
|
const ARKO_PROFILE_DISPLAY_NAME_CACHE_TTL_MS = 10 * 6e4;
|
|
2002
|
-
function numberValue$
|
|
2033
|
+
function numberValue$24(value) {
|
|
2003
2034
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2004
2035
|
}
|
|
2005
|
-
function booleanValue$
|
|
2036
|
+
function booleanValue$14(value) {
|
|
2006
2037
|
return value === true;
|
|
2007
2038
|
}
|
|
2008
|
-
function listValue$
|
|
2039
|
+
function listValue$25(value) {
|
|
2009
2040
|
return Array.isArray(value) ? value : [];
|
|
2010
2041
|
}
|
|
2011
2042
|
function optionalString$3(value) {
|
|
@@ -2034,7 +2065,7 @@ function joinUrlWithQuery(baseUrl, path, query) {
|
|
|
2034
2065
|
}
|
|
2035
2066
|
function arkoProfileFromData(data) {
|
|
2036
2067
|
const displayName = stringValue$1(data.display_name).trim();
|
|
2037
|
-
const version = numberValue$
|
|
2068
|
+
const version = numberValue$24(data.version);
|
|
2038
2069
|
if (displayName === "" || !Number.isSafeInteger(version) || version < 0) throw new ArkmePluginError("arko-profile-contract-invalid", "Arko 资料响应不完整", true, 502);
|
|
2039
2070
|
return {
|
|
2040
2071
|
displayName,
|
|
@@ -2058,15 +2089,15 @@ function arkoModelOptionFromData(value) {
|
|
|
2058
2089
|
displayName,
|
|
2059
2090
|
provider,
|
|
2060
2091
|
description,
|
|
2061
|
-
recommended: booleanValue$
|
|
2062
|
-
selected: booleanValue$
|
|
2092
|
+
recommended: booleanValue$14(data.recommended),
|
|
2093
|
+
selected: booleanValue$14(data.selected)
|
|
2063
2094
|
};
|
|
2064
2095
|
}
|
|
2065
2096
|
function arkoModelCatalogFromData(data) {
|
|
2066
2097
|
const defaultRouteKey = arkoModelRouteKey(data.default_route_key);
|
|
2067
2098
|
const effectiveRouteKey = arkoModelRouteKey(data.effective_route_key);
|
|
2068
2099
|
const selectionSource = stringValue$1(data.selection_source);
|
|
2069
|
-
const options = listValue$
|
|
2100
|
+
const options = listValue$25(data.items).map(arkoModelOptionFromData);
|
|
2070
2101
|
const routeKeys = new Set(options.map((option) => option.routeKey));
|
|
2071
2102
|
const selected = options.filter((option) => option.selected);
|
|
2072
2103
|
if (selectionSource !== "default" && selectionSource !== "personal" || options.length === 0 || options.length > 16 || routeKeys.size !== options.length || !routeKeys.has(defaultRouteKey) || !routeKeys.has(effectiveRouteKey) || selected.length !== 1 || selected[0]?.routeKey !== effectiveRouteKey) throw new ArkmePluginError("arko-model-contract-invalid", "Arko 模型目录响应无效", true, 502);
|
|
@@ -2087,9 +2118,9 @@ function parsedJsonRecord(value) {
|
|
|
2087
2118
|
}
|
|
2088
2119
|
function arkoHistoryItemFromData(value) {
|
|
2089
2120
|
const data = objectValue$1(value);
|
|
2090
|
-
const messageId = numberValue$
|
|
2091
|
-
const sessionId = numberValue$
|
|
2092
|
-
const roleCode = numberValue$
|
|
2121
|
+
const messageId = numberValue$24(data.id ?? data.msg_id ?? data.msgId);
|
|
2122
|
+
const sessionId = numberValue$24(data.session_id ?? data.sessionId);
|
|
2123
|
+
const roleCode = numberValue$24(data.role ?? data.sender_role ?? data.senderRole);
|
|
2093
2124
|
if (!Number.isSafeInteger(messageId) || messageId <= 0 || !Number.isSafeInteger(sessionId) || sessionId <= 0 || roleCode !== 2 && roleCode !== 3) return void 0;
|
|
2094
2125
|
const extra = parsedJsonRecord(data.extra ?? data.metadata ?? data.meta);
|
|
2095
2126
|
const extraData = parsedJsonRecord(extra.data);
|
|
@@ -2110,7 +2141,7 @@ function arkoHistoryItemFromData(value) {
|
|
|
2110
2141
|
extraData.updateAt,
|
|
2111
2142
|
data.updated_at,
|
|
2112
2143
|
data.updatedAt
|
|
2113
|
-
].map(numberValue$
|
|
2144
|
+
].map(numberValue$24).find((candidate) => candidate > 0) ?? 0;
|
|
2114
2145
|
const runUid = optionalString$3(extra.agent_run_uid);
|
|
2115
2146
|
const runStatus = optionalString$3(extra.agent_run_status);
|
|
2116
2147
|
const retryable = optionalBooleanValue$1(extra.agent_run_retryable);
|
|
@@ -2123,7 +2154,7 @@ function arkoHistoryItemFromData(value) {
|
|
|
2123
2154
|
text: stringValue$1(data.content ?? data.text_content ?? data.textContent),
|
|
2124
2155
|
reasoning: stringValue$1(data.reason_content ?? data.reason_text ?? data.reasonText),
|
|
2125
2156
|
createdAtMillis: activityAt > 0 && activityAt < 1e11 ? activityAt * 1e3 : activityAt,
|
|
2126
|
-
status: numberValue$
|
|
2157
|
+
status: numberValue$24(data.status ?? data.msg_status),
|
|
2127
2158
|
...runUid === void 0 ? {} : { runUid },
|
|
2128
2159
|
...runStatus === void 0 ? {} : { runStatus },
|
|
2129
2160
|
...retryable === void 0 ? {} : { retryable },
|
|
@@ -2142,14 +2173,14 @@ function arkoRunProjectionFromData(data) {
|
|
|
2142
2173
|
return {
|
|
2143
2174
|
runUid,
|
|
2144
2175
|
status,
|
|
2145
|
-
retryable: booleanValue$
|
|
2176
|
+
retryable: booleanValue$14(data.agent_run_retryable ?? data.retryable),
|
|
2146
2177
|
...errorCode === "" ? {} : { errorCode },
|
|
2147
2178
|
...retryOfRunUid === "" ? {} : { retryOfRunUid },
|
|
2148
2179
|
...clientAction === void 0 ? {} : { clientAction }
|
|
2149
2180
|
};
|
|
2150
2181
|
}
|
|
2151
2182
|
function arkoCreatedRecordUids(value) {
|
|
2152
|
-
return listValue$
|
|
2183
|
+
return listValue$25(value).map((item) => stringValue$1(item).trim()).filter((item) => item !== "");
|
|
2153
2184
|
}
|
|
2154
2185
|
function arkoStreamFrame(raw) {
|
|
2155
2186
|
try {
|
|
@@ -2178,7 +2209,7 @@ var ArkoService = class {
|
|
|
2178
2209
|
async arkoEnsureSession(signal) {
|
|
2179
2210
|
const session = await this.runtime.requireSession();
|
|
2180
2211
|
const latest = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/latest-session", { type: ARKO_AGENT_DIRECT_SESSION_TYPE }, session, signal);
|
|
2181
|
-
const latestSessionId = numberValue$
|
|
2212
|
+
const latestSessionId = numberValue$24(latest.id);
|
|
2182
2213
|
if (Number.isSafeInteger(latestSessionId) && latestSessionId > 0) return {
|
|
2183
2214
|
sessionId: latestSessionId,
|
|
2184
2215
|
created: false,
|
|
@@ -2188,7 +2219,7 @@ var ArkoService = class {
|
|
|
2188
2219
|
}
|
|
2189
2220
|
async arkoCreateSession(signal) {
|
|
2190
2221
|
const session = await this.runtime.requireSession();
|
|
2191
|
-
const createdSessionId = numberValue$
|
|
2222
|
+
const createdSessionId = numberValue$24((await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-session", {
|
|
2192
2223
|
name: ARKO_DEFAULT_SESSION_NAME,
|
|
2193
2224
|
type: ARKO_AGENT_DIRECT_SESSION_TYPE
|
|
2194
2225
|
}, session, signal)).session_id);
|
|
@@ -2213,7 +2244,7 @@ var ArkoService = class {
|
|
|
2213
2244
|
const normalizedLimit = Math.min(ARKO_HISTORY_PAGE_LIMIT, Math.max(1, Math.trunc(limit)));
|
|
2214
2245
|
const normalizedOffset = Math.max(0, Math.trunc(offset));
|
|
2215
2246
|
const session = await this.runtime.requireSession();
|
|
2216
|
-
const rawItems = listValue$
|
|
2247
|
+
const rawItems = listValue$25((await this.runtime.authenticatedIntelligentPost("/api/v1/qa/message-list", {
|
|
2217
2248
|
limit: normalizedLimit,
|
|
2218
2249
|
offset: normalizedOffset,
|
|
2219
2250
|
session_type: ARKO_AGENT_DIRECT_SESSION_TYPE
|
|
@@ -2256,9 +2287,9 @@ var ArkoService = class {
|
|
|
2256
2287
|
};
|
|
2257
2288
|
if (modelRouteKey !== "") body.model_route_key = modelRouteKey;
|
|
2258
2289
|
const accepted = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-msg-v2", body, session, options.signal);
|
|
2259
|
-
const userMsgId = numberValue$
|
|
2260
|
-
const assistantMsgId = numberValue$
|
|
2261
|
-
const acceptedSessionId = numberValue$
|
|
2290
|
+
const userMsgId = numberValue$24(accepted.user_msg_id);
|
|
2291
|
+
const assistantMsgId = numberValue$24(accepted.assistant_msg_id);
|
|
2292
|
+
const acceptedSessionId = numberValue$24(accepted.session_id) || sessionId;
|
|
2262
2293
|
if (!Number.isSafeInteger(acceptedSessionId) || acceptedSessionId <= 0 || !Number.isSafeInteger(userMsgId) || userMsgId <= 0 || !Number.isSafeInteger(assistantMsgId) || assistantMsgId <= 0) throw new ArkmePluginError("arko-ask-contract-invalid", "Arko 消息响应不完整", true, 502);
|
|
2263
2294
|
const runUid = stringValue$1(accepted.run_uid).trim();
|
|
2264
2295
|
if (runUid === "") throw new ArkmePluginError("arko-ask-contract-invalid", "Arko 消息响应缺少运行标识", true, 502);
|
|
@@ -2294,8 +2325,8 @@ var ArkoService = class {
|
|
|
2294
2325
|
}, session, signal);
|
|
2295
2326
|
const status = stringValue$1(data.status).trim();
|
|
2296
2327
|
const normalizedRunUid = stringValue$1(data.run_uid).trim() || runUid.trim();
|
|
2297
|
-
const sequence = numberValue$
|
|
2298
|
-
const surfaceAssistantMsgId = numberValue$
|
|
2328
|
+
const sequence = numberValue$24(data.sequence);
|
|
2329
|
+
const surfaceAssistantMsgId = numberValue$24(data.surface_assistant_msg_id);
|
|
2299
2330
|
const clientAction = optionalRecord(data.client_action);
|
|
2300
2331
|
if (normalizedRunUid !== runUid.trim() || !ARKO_RUN_STATUSES.has(status) || !Number.isSafeInteger(sequence) || sequence < 0 || !Number.isSafeInteger(surfaceAssistantMsgId) || surfaceAssistantMsgId <= 0) throw new ArkmePluginError("arko-run-status-contract-invalid", "Arko 运行状态响应不完整", true, 502);
|
|
2301
2332
|
return {
|
|
@@ -2304,7 +2335,7 @@ var ArkoService = class {
|
|
|
2304
2335
|
status,
|
|
2305
2336
|
sequence,
|
|
2306
2337
|
surfaceAssistantMsgId,
|
|
2307
|
-
retryable: booleanValue$
|
|
2338
|
+
retryable: booleanValue$14(data.retryable),
|
|
2308
2339
|
...stringValue$1(data.error_code).trim() === "" ? {} : { errorCode: stringValue$1(data.error_code).trim() },
|
|
2309
2340
|
...stringValue$1(data.retry_of_run_uid).trim() === "" ? {} : { retryOfRunUid: stringValue$1(data.retry_of_run_uid).trim() },
|
|
2310
2341
|
...clientAction === void 0 ? {} : { clientAction }
|
|
@@ -2479,12 +2510,12 @@ var ArkoService = class {
|
|
|
2479
2510
|
if (tailRun !== void 0) {
|
|
2480
2511
|
run = tailRun;
|
|
2481
2512
|
status = tailRun.status;
|
|
2482
|
-
} else if (booleanValue$
|
|
2513
|
+
} else if (booleanValue$14(tail.error) || stringValue$1(tail.status).trim() === "error") status = "failed";
|
|
2483
2514
|
else status = ARKO_COMPLETED_STATUS;
|
|
2484
2515
|
createdRecordUids = arkoCreatedRecordUids(tail.created_record_uids);
|
|
2485
2516
|
const nextProfile = optionalRecord(tail.agent_profile);
|
|
2486
2517
|
if (nextProfile !== void 0) profile = arkoProfileFromData(nextProfile);
|
|
2487
|
-
if (booleanValue$
|
|
2518
|
+
if (booleanValue$14(tail.error) || stringValue$1(tail.status).trim() === "error") errorMessage = stringValue$1(tail.error_message).trim() || "Arko 执行失败";
|
|
2488
2519
|
}
|
|
2489
2520
|
const type = stringValue$1(frame.type ?? frame.event).trim();
|
|
2490
2521
|
const payload = optionalRecord(frame.payload) ?? frame;
|
|
@@ -2533,13 +2564,13 @@ const ARKME_ARRANGEMENT_REF_TTL_MILLIS = 900 * 1e3;
|
|
|
2533
2564
|
const MAX_ARKME_ARRANGEMENT_REFS = 4096;
|
|
2534
2565
|
const ARKME_ARRANGEMENT_REMINDER_REF_TTL_MILLIS = 900 * 1e3;
|
|
2535
2566
|
const MAX_ARKME_ARRANGEMENT_REMINDER_REFS = 4096;
|
|
2536
|
-
function numberValue$
|
|
2567
|
+
function numberValue$23(value) {
|
|
2537
2568
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2538
2569
|
}
|
|
2539
|
-
function booleanValue$
|
|
2570
|
+
function booleanValue$13(value) {
|
|
2540
2571
|
return value === true;
|
|
2541
2572
|
}
|
|
2542
|
-
function listValue$
|
|
2573
|
+
function listValue$24(value) {
|
|
2543
2574
|
return Array.isArray(value) ? value : [];
|
|
2544
2575
|
}
|
|
2545
2576
|
function arrangementStatusCode(status) {
|
|
@@ -2549,7 +2580,7 @@ function arrangementStatusCode(status) {
|
|
|
2549
2580
|
return -1;
|
|
2550
2581
|
}
|
|
2551
2582
|
function arrangementStatus(value) {
|
|
2552
|
-
const code = Math.trunc(numberValue$
|
|
2583
|
+
const code = Math.trunc(numberValue$23(value));
|
|
2553
2584
|
if (code === 1) return "identified";
|
|
2554
2585
|
if (code === 2) return "following";
|
|
2555
2586
|
if (code === 3) return "completed";
|
|
@@ -2598,9 +2629,9 @@ var ArrangementService = class {
|
|
|
2598
2629
|
limit,
|
|
2599
2630
|
offset
|
|
2600
2631
|
}, session, options.signal, { lane: "interactive-read" });
|
|
2601
|
-
const rawItems = listValue$
|
|
2632
|
+
const rawItems = listValue$24(data.list);
|
|
2602
2633
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementItem(raw, session.userId)));
|
|
2603
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
2634
|
+
const total = Math.max(0, Math.trunc(numberValue$23(data.total)));
|
|
2604
2635
|
const nextOffset = offset + rawItems.length;
|
|
2605
2636
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
2606
2637
|
return {
|
|
@@ -2624,9 +2655,9 @@ var ArrangementService = class {
|
|
|
2624
2655
|
offset,
|
|
2625
2656
|
unread_only: options.unreadOnly === true
|
|
2626
2657
|
}, session, options.signal, { lane: "interactive-read" });
|
|
2627
|
-
const rawItems = listValue$
|
|
2658
|
+
const rawItems = listValue$24(data.list);
|
|
2628
2659
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementReminderEvent(raw, session.userId)));
|
|
2629
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
2660
|
+
const total = Math.max(0, Math.trunc(numberValue$23(data.total)));
|
|
2630
2661
|
const nextOffset = offset + rawItems.length;
|
|
2631
2662
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
2632
2663
|
return {
|
|
@@ -2649,7 +2680,7 @@ var ArrangementService = class {
|
|
|
2649
2680
|
project(data.next_reminder)
|
|
2650
2681
|
]);
|
|
2651
2682
|
return {
|
|
2652
|
-
unreadCount: Math.max(0, Math.trunc(numberValue$
|
|
2683
|
+
unreadCount: Math.max(0, Math.trunc(numberValue$23(data.unread_count))),
|
|
2653
2684
|
...latestUnread === void 0 ? {} : { latestUnread },
|
|
2654
2685
|
...latestEvent === void 0 ? {} : { latestEvent },
|
|
2655
2686
|
...nextReminder === void 0 ? {} : { nextReminder }
|
|
@@ -2753,7 +2784,7 @@ var ArrangementService = class {
|
|
|
2753
2784
|
}, session, signal);
|
|
2754
2785
|
return {
|
|
2755
2786
|
outcome: "confirmed",
|
|
2756
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2787
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$23(data.updated_count)))
|
|
2757
2788
|
};
|
|
2758
2789
|
} catch (error) {
|
|
2759
2790
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2771,7 +2802,7 @@ var ArrangementService = class {
|
|
|
2771
2802
|
}, session, signal);
|
|
2772
2803
|
return {
|
|
2773
2804
|
outcome: "confirmed",
|
|
2774
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2805
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$23(data.updated_count)))
|
|
2775
2806
|
};
|
|
2776
2807
|
} catch (error) {
|
|
2777
2808
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2786,7 +2817,7 @@ var ArrangementService = class {
|
|
|
2786
2817
|
const data = await this.runtime.authenticatedIntelligentPost("/api/v1/arrangements/reminders/clear", {}, session, signal);
|
|
2787
2818
|
return {
|
|
2788
2819
|
outcome: "confirmed",
|
|
2789
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2820
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$23(data.updated_count)))
|
|
2790
2821
|
};
|
|
2791
2822
|
} catch (error) {
|
|
2792
2823
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2819,7 +2850,7 @@ var ArrangementService = class {
|
|
|
2819
2850
|
}
|
|
2820
2851
|
async reconcileArrangementDelete(arrangementRef, arrangementUid, session) {
|
|
2821
2852
|
try {
|
|
2822
|
-
const visible = listValue$
|
|
2853
|
+
const visible = listValue$24((await this.runtime.authenticatedIntelligentPost("/api/v1/arrangements/list", {
|
|
2823
2854
|
status: -1,
|
|
2824
2855
|
uids: [arrangementUid],
|
|
2825
2856
|
limit: 1,
|
|
@@ -2850,17 +2881,17 @@ var ArrangementService = class {
|
|
|
2850
2881
|
const item = objectValue$1(raw);
|
|
2851
2882
|
const arrangementUid = stringValue$1(item.uid).trim();
|
|
2852
2883
|
if (arrangementUid === "") throw new ArkmePluginError("arrangement-contract-invalid", "安排响应缺少业务身份", true, 502);
|
|
2853
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
2854
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
2884
|
+
const dueAtMillis = Math.trunc(numberValue$23(item.due_at));
|
|
2885
|
+
const remindAtMillis = Math.trunc(numberValue$23(item.remind_at));
|
|
2855
2886
|
return {
|
|
2856
2887
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
2857
2888
|
title: stringValue$1(item.title),
|
|
2858
2889
|
description: stringValue$1(item.description),
|
|
2859
2890
|
status: arrangementStatus(item.status),
|
|
2860
|
-
reminderEnabled: booleanValue$
|
|
2891
|
+
reminderEnabled: booleanValue$13(item.reminder_enabled),
|
|
2861
2892
|
reminderState: stringValue$1(item.reminder_state),
|
|
2862
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
2863
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
2893
|
+
createdAtMillis: Math.trunc(numberValue$23(item.create_at)),
|
|
2894
|
+
updatedAtMillis: Math.trunc(numberValue$23(item.update_at)),
|
|
2864
2895
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
2865
2896
|
...remindAtMillis > 0 ? { remindAtMillis } : {}
|
|
2866
2897
|
};
|
|
@@ -2881,20 +2912,20 @@ var ArrangementService = class {
|
|
|
2881
2912
|
const eventUid = stringValue$1(item.uid).trim();
|
|
2882
2913
|
const arrangementUid = stringValue$1(item.arrangement_uid).trim();
|
|
2883
2914
|
if (eventUid === "" || arrangementUid === "") throw new ArkmePluginError("arrangement-reminder-contract-invalid", "安排提醒响应缺少有效身份", true, 502);
|
|
2884
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
2885
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
2886
|
-
const readAtMillis = Math.trunc(numberValue$
|
|
2915
|
+
const dueAtMillis = Math.trunc(numberValue$23(item.due_at));
|
|
2916
|
+
const remindAtMillis = Math.trunc(numberValue$23(item.remind_at));
|
|
2917
|
+
const readAtMillis = Math.trunc(numberValue$23(item.read_at));
|
|
2887
2918
|
return {
|
|
2888
2919
|
eventRef: await this.arrangementReminderRef(viewerUserId, eventUid),
|
|
2889
2920
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
2890
2921
|
title: stringValue$1(item.title),
|
|
2891
2922
|
description: stringValue$1(item.description),
|
|
2892
2923
|
eventKind: stringValue$1(item.event_kind),
|
|
2893
|
-
eventAtMillis: Math.trunc(numberValue$
|
|
2924
|
+
eventAtMillis: Math.trunc(numberValue$23(item.event_at)),
|
|
2894
2925
|
read: readAtMillis > 0,
|
|
2895
2926
|
reminderState: stringValue$1(item.reminder_state),
|
|
2896
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
2897
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
2927
|
+
createdAtMillis: Math.trunc(numberValue$23(item.create_at)),
|
|
2928
|
+
updatedAtMillis: Math.trunc(numberValue$23(item.update_at)),
|
|
2898
2929
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
2899
2930
|
...remindAtMillis > 0 ? { remindAtMillis } : {},
|
|
2900
2931
|
...readAtMillis > 0 ? { readAtMillis } : {}
|
|
@@ -2951,7 +2982,7 @@ var ArrangementService = class {
|
|
|
2951
2982
|
const ARKME_PHONE_BIND_SUCCESS = 1;
|
|
2952
2983
|
const ARKME_PHONE_BIND_REPEAT = 2;
|
|
2953
2984
|
const ARKME_PHONE_BIND_CODE_ERR = 3;
|
|
2954
|
-
function numberValue$
|
|
2985
|
+
function numberValue$22(value) {
|
|
2955
2986
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2956
2987
|
}
|
|
2957
2988
|
function jiwoScanLoginAvailable(config) {
|
|
@@ -3036,7 +3067,7 @@ var AuthService = class {
|
|
|
3036
3067
|
const sceneStr = stringValue$1(data.scene_str).trim();
|
|
3037
3068
|
const pollToken = stringValue$1(data.poll_token).trim();
|
|
3038
3069
|
const qrContent = stringValue$1(data.url).trim();
|
|
3039
|
-
const expireSeconds = Math.max(30, numberValue$
|
|
3070
|
+
const expireSeconds = Math.max(30, numberValue$22(data.expire_seconds) || 300);
|
|
3040
3071
|
if (qrContent === "" && sceneStr !== "") throw new ArkmePluginError("wechat-qr-unavailable", "测试环境当前未返回可用微信二维码,请使用手机号登录", true, 503);
|
|
3041
3072
|
if (sceneStr === "" || pollToken === "" || qrContent === "") throw new ArkmePluginError("login-contract-invalid", "Arkme 登录二维码响应不完整", true, 502);
|
|
3042
3073
|
const attemptId = crypto.randomUUID();
|
|
@@ -3075,7 +3106,7 @@ var AuthService = class {
|
|
|
3075
3106
|
ref: 0,
|
|
3076
3107
|
keep_cancel: true
|
|
3077
3108
|
}, void 0, [200]);
|
|
3078
|
-
const userId = numberValue$
|
|
3109
|
+
const userId = numberValue$22(data.user_id);
|
|
3079
3110
|
if (userId <= 0) return {
|
|
3080
3111
|
status: "pending",
|
|
3081
3112
|
environment: this.runtime.config.environment,
|
|
@@ -3105,7 +3136,7 @@ var AuthService = class {
|
|
|
3105
3136
|
}, void 0, [200]);
|
|
3106
3137
|
const ticket = stringValue$1(data.ticket).trim();
|
|
3107
3138
|
const pollSecret = stringValue$1(data.poll_secret).trim();
|
|
3108
|
-
const expiresAtMillis = numberValue$
|
|
3139
|
+
const expiresAtMillis = numberValue$22(data.expires_at);
|
|
3109
3140
|
if (!/^[A-Za-z0-9_-]{43}$/.test(ticket) || !/^[A-Za-z0-9_-]{43}$/.test(pollSecret) || expiresAtMillis <= Date.now()) throw new ArkmePluginError("jiwo-login-contract-invalid", "即我登录二维码响应不完整", true, 502);
|
|
3110
3141
|
if (attemptGeneration !== this.jiwoAttemptGeneration) {
|
|
3111
3142
|
await this.cancelJiwoCredentials(ticket, pollSecret);
|
|
@@ -3155,7 +3186,7 @@ var AuthService = class {
|
|
|
3155
3186
|
};
|
|
3156
3187
|
}
|
|
3157
3188
|
if (status !== "authenticated") throw new ArkmePluginError("jiwo-login-contract-invalid", "即我扫码登录状态无效", true, 502);
|
|
3158
|
-
const userId = numberValue$
|
|
3189
|
+
const userId = numberValue$22(data.user_id);
|
|
3159
3190
|
const accessToken = stringValue$1(data.access_token);
|
|
3160
3191
|
const refreshToken = stringValue$1(data.refresh_token);
|
|
3161
3192
|
if (userId <= 0 || accessToken === "" || refreshToken === "") throw new ArkmePluginError("login-contract-invalid", "Arkme 登录成功响应缺少凭据", false, 502);
|
|
@@ -3224,7 +3255,7 @@ var AuthService = class {
|
|
|
3224
3255
|
const normalizedCaptcha = this.normalizedCaptcha(captcha);
|
|
3225
3256
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
3226
3257
|
if (session !== void 0) {
|
|
3227
|
-
if (numberValue$
|
|
3258
|
+
if (numberValue$22((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/bind-phone-send-code", {
|
|
3228
3259
|
phone: normalizedPhone,
|
|
3229
3260
|
pre: "86",
|
|
3230
3261
|
is_test: this.runtime.config.environment === "test",
|
|
@@ -3246,7 +3277,7 @@ var AuthService = class {
|
|
|
3246
3277
|
if (!/^[0-9]{6}$/.test(normalizedCode)) throw new ArkmePluginError("phone-code-invalid", "请输入有效的短信验证码", false);
|
|
3247
3278
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
3248
3279
|
if (session !== void 0) {
|
|
3249
|
-
const result = numberValue$
|
|
3280
|
+
const result = numberValue$22((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/verify-bind-phone", {
|
|
3250
3281
|
phone: normalizedPhone,
|
|
3251
3282
|
pre: "86",
|
|
3252
3283
|
code: normalizedCode,
|
|
@@ -3267,7 +3298,7 @@ var AuthService = class {
|
|
|
3267
3298
|
keep_cancel: true
|
|
3268
3299
|
}, void 0, [200]);
|
|
3269
3300
|
if (data.ok === false) throw new ArkmePluginError("phone-code-rejected", "手机号或验证码错误", false, 401);
|
|
3270
|
-
const userId = numberValue$
|
|
3301
|
+
const userId = numberValue$22(data.user_id);
|
|
3271
3302
|
const accessToken = stringValue$1(data.access_token);
|
|
3272
3303
|
const refreshToken = stringValue$1(data.refresh_token);
|
|
3273
3304
|
if (userId <= 0 || accessToken === "" || refreshToken === "") throw new ArkmePluginError("login-contract-invalid", "Arkme手机号登录响应不完整", false, 502);
|
|
@@ -3417,7 +3448,7 @@ var ArkmePrivacyVisibilityService = class {
|
|
|
3417
3448
|
};
|
|
3418
3449
|
//#endregion
|
|
3419
3450
|
//#region src/mention-metadata.ts
|
|
3420
|
-
function listValue$
|
|
3451
|
+
function listValue$23(value) {
|
|
3421
3452
|
return Array.isArray(value) ? value : [];
|
|
3422
3453
|
}
|
|
3423
3454
|
function integerLikeValue$3(value) {
|
|
@@ -3438,7 +3469,7 @@ function arkmeMentionMetadataFromRecord(record, payload) {
|
|
|
3438
3469
|
function arkmeMentionMetadataMentionsViewer(record, payload, viewerUserId) {
|
|
3439
3470
|
if (viewerUserId <= 0) return false;
|
|
3440
3471
|
const metadata = arkmeMentionMetadataFromRecord(record, payload);
|
|
3441
|
-
for (const rawMention of listValue$
|
|
3472
|
+
for (const rawMention of listValue$23(metadata.human_mentions ?? metadata.humanMentions)) {
|
|
3442
3473
|
const mention = objectValue$1(rawMention);
|
|
3443
3474
|
const mentionedUserId = integerLikeValue$3(mention.user_id ?? mention.userId);
|
|
3444
3475
|
if (mentionedUserId === 0 || mentionedUserId === viewerUserId) return true;
|
|
@@ -3706,7 +3737,7 @@ const GROUP_AVATAR_NEGATIVE_CACHE_TTL_MS = 6e4;
|
|
|
3706
3737
|
const TOPIC_DISSOLVE_RECORD_CONCURRENCY = 6;
|
|
3707
3738
|
const PRIVATE_REMARK_PAGE_LIMIT = 50;
|
|
3708
3739
|
const PRIVATE_REMARK_MAX_PAGES = 20;
|
|
3709
|
-
function numberValue$
|
|
3740
|
+
function numberValue$21(value) {
|
|
3710
3741
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
3711
3742
|
}
|
|
3712
3743
|
function integerIdentifierValue(value) {
|
|
@@ -3715,10 +3746,10 @@ function integerIdentifierValue(value) {
|
|
|
3715
3746
|
const parsed = Number(value);
|
|
3716
3747
|
return Number.isSafeInteger(parsed) ? parsed : 0;
|
|
3717
3748
|
}
|
|
3718
|
-
function booleanValue$
|
|
3749
|
+
function booleanValue$12(value) {
|
|
3719
3750
|
return value === true;
|
|
3720
3751
|
}
|
|
3721
|
-
function listValue$
|
|
3752
|
+
function listValue$22(value) {
|
|
3722
3753
|
return Array.isArray(value) ? value : [];
|
|
3723
3754
|
}
|
|
3724
3755
|
function integerLikeValue$2(value) {
|
|
@@ -3758,7 +3789,7 @@ function arkmeChatSidebarTargetFromBundle(bundle, fallbackSubjectUid = "") {
|
|
|
3758
3789
|
if (subjectUid === "") return void 0;
|
|
3759
3790
|
return {
|
|
3760
3791
|
subjectUid,
|
|
3761
|
-
hiddenAnchorTimestamp: Math.max(0, numberValue$
|
|
3792
|
+
hiddenAnchorTimestamp: Math.max(0, numberValue$21(bundle.sort_active_at ?? bundle.last_active_at ?? chatSession.last_active_at))
|
|
3762
3793
|
};
|
|
3763
3794
|
}
|
|
3764
3795
|
function backendBooleanValue(value) {
|
|
@@ -3778,7 +3809,7 @@ function chatUnreadMentionState(unread) {
|
|
|
3778
3809
|
if (rawCount === void 0 || rawCount === null) return void 0;
|
|
3779
3810
|
return integerLikeValue$2(rawCount) > 0;
|
|
3780
3811
|
}
|
|
3781
|
-
function encodeOpaqueJson$
|
|
3812
|
+
function encodeOpaqueJson$7(value) {
|
|
3782
3813
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
3783
3814
|
}
|
|
3784
3815
|
function decodeOpaqueJson$6(value) {
|
|
@@ -3790,7 +3821,7 @@ function isSourceKind(value) {
|
|
|
3790
3821
|
function chatMessageDnd$1(value) {
|
|
3791
3822
|
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
3792
3823
|
const policy = value;
|
|
3793
|
-
return numberValue$
|
|
3824
|
+
return numberValue$21(policy.mute_state) === 2 || numberValue$21(policy.notify_state) === 2;
|
|
3794
3825
|
}
|
|
3795
3826
|
function attachmentPreviewKind(item) {
|
|
3796
3827
|
const fileName = stringValue$1(item.file_name ?? item.fileName).trim();
|
|
@@ -3809,13 +3840,13 @@ function arkmeChatConversationPreview(raw) {
|
|
|
3809
3840
|
const nested = stringValue$1(content.text_content ?? content.title ?? content.summary).trim();
|
|
3810
3841
|
if (nested !== "") return nested.slice(0, 300);
|
|
3811
3842
|
if (objectValue$1(content.voice).duration !== void 0) return "[语音]";
|
|
3812
|
-
const displayItems = listValue$
|
|
3843
|
+
const displayItems = listValue$22(raw.media_display_items ?? raw.mediaDisplayItems).map(objectValue$1);
|
|
3813
3844
|
const displayByAsset = /* @__PURE__ */ new Map();
|
|
3814
3845
|
for (const item of displayItems) {
|
|
3815
3846
|
const fileAssetUid = stringValue$1(item.file_asset_uid ?? item.fileAssetUid).trim();
|
|
3816
3847
|
if (fileAssetUid !== "") displayByAsset.set(fileAssetUid, item);
|
|
3817
3848
|
}
|
|
3818
|
-
const mediaRefs = listValue$
|
|
3849
|
+
const mediaRefs = listValue$22(content.media_refs ?? content.mediaRefs).map(objectValue$1);
|
|
3819
3850
|
const firstAttachment = (mediaRefs.length > 0 ? mediaRefs.map((ref) => ({
|
|
3820
3851
|
...displayByAsset.get(stringValue$1(ref.file_asset_uid ?? ref.fileAssetUid).trim()) ?? {},
|
|
3821
3852
|
...ref
|
|
@@ -3967,11 +3998,11 @@ var SourceService = class {
|
|
|
3967
3998
|
lane: "background-read",
|
|
3968
3999
|
key: `world-author-labels:${pageCursor === void 0 ? "first" : String(page)}`
|
|
3969
4000
|
});
|
|
3970
|
-
for (const raw of listValue$
|
|
4001
|
+
for (const raw of listValue$22(data.items)) {
|
|
3971
4002
|
const bundle = objectValue$1(raw);
|
|
3972
|
-
const sessionKind = numberValue$
|
|
4003
|
+
const sessionKind = numberValue$21(objectValue$1(bundle.session).session_kind);
|
|
3973
4004
|
if (sessionKind !== 1 && sessionKind !== 3) continue;
|
|
3974
|
-
const targetUserId = numberValue$
|
|
4005
|
+
const targetUserId = numberValue$21(objectValue$1(bundle.private_counterpart).user_id);
|
|
3975
4006
|
if (!remaining.has(targetUserId)) continue;
|
|
3976
4007
|
const supplement = objectValue$1(bundle.private_supplement);
|
|
3977
4008
|
const counterpart = objectValue$1(bundle.private_counterpart);
|
|
@@ -4005,7 +4036,7 @@ var SourceService = class {
|
|
|
4005
4036
|
key: `private-remarks:${String(offset)}`,
|
|
4006
4037
|
failureCooldownMs: 2e3
|
|
4007
4038
|
});
|
|
4008
|
-
const rawItems = listValue$
|
|
4039
|
+
const rawItems = listValue$22(data.items);
|
|
4009
4040
|
for (const value of rawItems) {
|
|
4010
4041
|
const raw = objectValue$1(value);
|
|
4011
4042
|
const targetUserId = integerIdentifierValue(raw.user_id);
|
|
@@ -4030,9 +4061,9 @@ var SourceService = class {
|
|
|
4030
4061
|
key: `private-remarks:direct:${pageCursor === void 0 ? "first" : String(page)}`,
|
|
4031
4062
|
failureCooldownMs: 2e3
|
|
4032
4063
|
});
|
|
4033
|
-
for (const value of listValue$
|
|
4064
|
+
for (const value of listValue$22(data.items)) {
|
|
4034
4065
|
const bundle = objectValue$1(value);
|
|
4035
|
-
const sessionKind = numberValue$
|
|
4066
|
+
const sessionKind = numberValue$21(objectValue$1(bundle.session).session_kind);
|
|
4036
4067
|
if (sessionKind !== 1 && sessionKind !== 3) continue;
|
|
4037
4068
|
const targetUserId = integerIdentifierValue(objectValue$1(bundle.private_counterpart).user_id);
|
|
4038
4069
|
if (!remaining.has(targetUserId)) continue;
|
|
@@ -4075,10 +4106,10 @@ var SourceService = class {
|
|
|
4075
4106
|
extra: { source: "dsh-arkme" }
|
|
4076
4107
|
}, session);
|
|
4077
4108
|
const topicUid = stringValue$1(created.topic_uid).trim();
|
|
4078
|
-
if (topicUid === "" || numberValue$
|
|
4109
|
+
if (topicUid === "" || numberValue$21(created.status) !== 1) throw new ArkmePluginError("topic-create-contract-invalid", "主题创建响应不完整", true, 502);
|
|
4079
4110
|
const sourceRef = await this.sealSourceRef(session.userId, "topic", topicUid, title);
|
|
4080
4111
|
if (parentTopicUid !== void 0) try {
|
|
4081
|
-
if (numberValue$
|
|
4112
|
+
if (numberValue$21(objectValue$1((await this.runtime.authenticatedPost("/api/v1/topics/hierarchy/bind", {
|
|
4082
4113
|
parent_topic_uid: parentTopicUid,
|
|
4083
4114
|
child_topic_uid: topicUid
|
|
4084
4115
|
}, session)).relation).status) !== 1) throw new ArkmePluginError("topic-hierarchy-bind-contract-invalid", "子主题层级响应不完整", true, 502);
|
|
@@ -4092,7 +4123,7 @@ var SourceService = class {
|
|
|
4092
4123
|
status: 2,
|
|
4093
4124
|
extra: { source: "dsh-arkme" }
|
|
4094
4125
|
}, session);
|
|
4095
|
-
if (stringValue$1(rolledBack.topic_uid).trim() !== topicUid || !booleanValue$
|
|
4126
|
+
if (stringValue$1(rolledBack.topic_uid).trim() !== topicUid || !booleanValue$12(rolledBack.updated)) throw new ArkmePluginError("topic-rollback-contract-invalid", "子主题清理响应不完整", true, 502);
|
|
4096
4127
|
} catch {
|
|
4097
4128
|
return {
|
|
4098
4129
|
source: {
|
|
@@ -4136,7 +4167,7 @@ var SourceService = class {
|
|
|
4136
4167
|
status: 1,
|
|
4137
4168
|
extra: { source: "dsh-arkme" }
|
|
4138
4169
|
}, session);
|
|
4139
|
-
if (stringValue$1(updated.topic_uid).trim() !== topic.ownerRef || !booleanValue$
|
|
4170
|
+
if (stringValue$1(updated.topic_uid).trim() !== topic.ownerRef || !booleanValue$12(updated.updated)) throw new ArkmePluginError("topic-rename-contract-invalid", "主题重命名响应不完整,请重试", true, 502);
|
|
4140
4171
|
this.invalidateSourceListCache(session.userId, "send_to_self");
|
|
4141
4172
|
return {
|
|
4142
4173
|
sourceRef: await this.sealSourceRef(session.userId, "topic", topic.ownerRef, title),
|
|
@@ -4214,7 +4245,7 @@ var SourceService = class {
|
|
|
4214
4245
|
status: 2,
|
|
4215
4246
|
extra: { source: "dsh-arkme" }
|
|
4216
4247
|
}, session);
|
|
4217
|
-
if (stringValue$1(dissolved.topic_uid).trim() !== topic.ownerRef || !booleanValue$
|
|
4248
|
+
if (stringValue$1(dissolved.topic_uid).trim() !== topic.ownerRef || !booleanValue$12(dissolved.updated)) throw new ArkmePluginError("topic-dissolve-contract-invalid", "主题解散响应不完整,请重试", true, 502);
|
|
4218
4249
|
} catch (cause) {
|
|
4219
4250
|
await this.rollbackDissolvedTopicChildren(movedChildren, topic.ownerRef, parent?.ownerRef, session);
|
|
4220
4251
|
await this.rollbackDissolvedTopicRecords(topic.ownerRef, parent?.ownerRef, movedRecordUids, session);
|
|
@@ -4247,14 +4278,14 @@ var SourceService = class {
|
|
|
4247
4278
|
...cursorSendAt === void 0 ? {} : { cursor_send_at: cursorSendAt },
|
|
4248
4279
|
...cursorRecordUid === void 0 ? {} : { cursor_record_uid: cursorRecordUid }
|
|
4249
4280
|
}, session);
|
|
4250
|
-
for (const raw of listValue$
|
|
4281
|
+
for (const raw of listValue$22(data.records)) {
|
|
4251
4282
|
const item = objectValue$1(raw);
|
|
4252
4283
|
const uid = stringValue$1(item.record_uid ?? objectValue$1(item.record_core).record_uid).trim();
|
|
4253
4284
|
if (uid !== "") recordUids.add(uid);
|
|
4254
4285
|
}
|
|
4255
4286
|
onProgress?.(recordUids.size);
|
|
4256
4287
|
if (data.has_more !== true) return [...recordUids];
|
|
4257
|
-
const nextSendAt = numberValue$
|
|
4288
|
+
const nextSendAt = numberValue$21(data.next_cursor_send_at);
|
|
4258
4289
|
const nextRecordUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
4259
4290
|
const cursorKey = `${String(nextSendAt)}:${nextRecordUid}`;
|
|
4260
4291
|
if (nextSendAt <= 0 || nextRecordUid === "" || seenCursors.has(cursorKey)) throw new ArkmePluginError("topic-dissolve-record-page-invalid", "主题快记加载不完整,未解散主题,请刷新后重试", true, 502);
|
|
@@ -4337,7 +4368,7 @@ var SourceService = class {
|
|
|
4337
4368
|
parent_topic_uid: nextParentTopicUid ?? "",
|
|
4338
4369
|
insert_before_topic_uid: ""
|
|
4339
4370
|
}, session);
|
|
4340
|
-
return stringValue$1(moved.topic_uid).trim() === topicUid && stringValue$1(moved.parent_topic_uid).trim() === (nextParentTopicUid ?? "") && numberValue$
|
|
4371
|
+
return stringValue$1(moved.topic_uid).trim() === topicUid && stringValue$1(moved.parent_topic_uid).trim() === (nextParentTopicUid ?? "") && numberValue$21(moved.sibling_order) > 0;
|
|
4341
4372
|
}
|
|
4342
4373
|
async rollbackDissolvedTopicChildren(children, topicUid, parentTopicUid, session) {
|
|
4343
4374
|
for (const child of [...children].reverse()) await this.moveTopicHierarchyForDissolve(child.topic.ownerRef, parentTopicUid ?? "", topicUid, session).catch(() => false);
|
|
@@ -4366,7 +4397,7 @@ var SourceService = class {
|
|
|
4366
4397
|
}, session);
|
|
4367
4398
|
const movedTopicUid = stringValue$1(moved.topic_uid).trim();
|
|
4368
4399
|
const movedParentUid = stringValue$1(moved.parent_topic_uid).trim();
|
|
4369
|
-
const siblingOrder = numberValue$
|
|
4400
|
+
const siblingOrder = numberValue$21(moved.sibling_order);
|
|
4370
4401
|
if (movedTopicUid !== topic.ownerRef || movedParentUid !== (nextParentUid ?? "") || siblingOrder <= 0) throw new ArkmePluginError("topic-hierarchy-move-contract-invalid", "主题移动响应不完整,请刷新后重试", true, 502);
|
|
4371
4402
|
this.sourceListCache.clear();
|
|
4372
4403
|
return {
|
|
@@ -4411,17 +4442,17 @@ var SourceService = class {
|
|
|
4411
4442
|
if (source.kind !== "private_chat" && source.kind !== "group_chat") throw new ArkmePluginError("chat-directory-policy-invalid", "仅支持更新私聊或群聊的会话列表状态", false);
|
|
4412
4443
|
const sidebarTarget = await this.resolveChatSidebarTarget(source, session, options.signal);
|
|
4413
4444
|
const current = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: source.ownerRef }, session, options.signal);
|
|
4414
|
-
const pinned = options.pinned ?? numberValue$
|
|
4415
|
-
const hidden = options.hidden ?? numberValue$
|
|
4445
|
+
const pinned = options.pinned ?? numberValue$21(current.pin_state) === 2;
|
|
4446
|
+
const hidden = options.hidden ?? numberValue$21(current.show_in_home_state) === 2;
|
|
4416
4447
|
const updatedAt = Date.now();
|
|
4417
4448
|
const writes = [this.runtime.authenticatedChatPost("/api/v1/chats/policy/update", {
|
|
4418
4449
|
chat_session_uid: source.ownerRef,
|
|
4419
4450
|
show_in_home_state: hidden ? 2 : 1,
|
|
4420
|
-
privacy_state: numberValue$
|
|
4421
|
-
mute_state: numberValue$
|
|
4451
|
+
privacy_state: numberValue$21(current.privacy_state) || 1,
|
|
4452
|
+
mute_state: numberValue$21(current.mute_state) || 1,
|
|
4422
4453
|
pin_state: pinned ? 2 : 1,
|
|
4423
|
-
notify_state: numberValue$
|
|
4424
|
-
status: numberValue$
|
|
4454
|
+
notify_state: numberValue$21(current.notify_state) || 1,
|
|
4455
|
+
status: numberValue$21(current.status) || 1,
|
|
4425
4456
|
update_at: updatedAt
|
|
4426
4457
|
}, session, options.signal)];
|
|
4427
4458
|
if (options.hidden !== void 0) writes.push(this.runtime.authenticatedSubjectPost("/api/v1/subject/batch-set-sidebar-hidden-status", { items: [{
|
|
@@ -4480,7 +4511,7 @@ var SourceService = class {
|
|
|
4480
4511
|
key: "directory:groups:count",
|
|
4481
4512
|
failureCooldownMs: 2e3
|
|
4482
4513
|
});
|
|
4483
|
-
return Math.max(0, numberValue$
|
|
4514
|
+
return Math.max(0, numberValue$21(data.total ?? data.total_count));
|
|
4484
4515
|
}
|
|
4485
4516
|
async listSourcesUncached(session, directory, options, limit, sessionKind) {
|
|
4486
4517
|
if (directory === "send_to_self") {
|
|
@@ -4498,7 +4529,7 @@ var SourceService = class {
|
|
|
4498
4529
|
options.signal?.throwIfAborted();
|
|
4499
4530
|
const cached = summaryResult.status === "rejected" || latestRecordsResult.status === "rejected" ? await this.runtime.stateStore.cachedSnapshot(session.userId).catch(() => void 0) : void 0;
|
|
4500
4531
|
const defaultRecordCount = summaryResult.status === "fulfilled" ? summaryResult.value.recordCount : cached?.summary?.recordCount;
|
|
4501
|
-
const defaultLatestRecord = latestRecordsResult.status === "fulfilled" ? listValue$
|
|
4532
|
+
const defaultLatestRecord = latestRecordsResult.status === "fulfilled" ? listValue$22(latestRecordsResult.value.items).map((raw) => this.recordReader.isDSHAgentInput?.(raw) === true || this.recordReader.isPrivacyLocked?.(raw) === true || arkmePrivacyLockedRecord(raw) || lockedRecordUids.has(stringValue$1(objectValue$1(raw).record_uid ?? objectValue$1(objectValue$1(raw).record_core).record_uid).trim()) ? void 0 : this.recordReader.recordItem(raw)).find((item) => item !== void 0) : cached?.items.reduce((latest, item) => item.creationSource === 3 ? latest : latest === void 0 || item.sendAtMillis > latest.sendAtMillis ? item : latest, void 0);
|
|
4502
4533
|
const defaultLatestPreview = defaultLatestRecord === void 0 ? "" : defaultLatestRecord.textContent.trim() || defaultLatestRecord.title.trim();
|
|
4503
4534
|
const defaultCategory = {
|
|
4504
4535
|
sourceRef: await this.sealSourceRef(session.userId, "default_category", "uncategorized", "未分类"),
|
|
@@ -4514,24 +4545,24 @@ var SourceService = class {
|
|
|
4514
4545
|
const parentTopicUidByChild = /* @__PURE__ */ new Map();
|
|
4515
4546
|
const siblingOrderByChild = /* @__PURE__ */ new Map();
|
|
4516
4547
|
const childTopicUidsByParent = /* @__PURE__ */ new Map();
|
|
4517
|
-
for (const raw of listValue$
|
|
4548
|
+
for (const raw of listValue$22(hierarchyData?.relations)) {
|
|
4518
4549
|
const relation = objectValue$1(raw);
|
|
4519
|
-
if (numberValue$
|
|
4550
|
+
if (numberValue$21(relation.rel_kind) !== 1 || numberValue$21(relation.status) !== 1) continue;
|
|
4520
4551
|
const parentTopicUid = stringValue$1(relation.parent_topic_uid).trim();
|
|
4521
4552
|
const childTopicUid = stringValue$1(relation.child_topic_uid).trim();
|
|
4522
4553
|
if (parentTopicUid === "" || childTopicUid === "" || parentTopicUid === childTopicUid) continue;
|
|
4523
4554
|
parentTopicUidByChild.set(childTopicUid, parentTopicUid);
|
|
4524
|
-
siblingOrderByChild.set(childTopicUid, numberValue$
|
|
4555
|
+
siblingOrderByChild.set(childTopicUid, numberValue$21(relation.sibling_order));
|
|
4525
4556
|
const children = childTopicUidsByParent.get(parentTopicUid) ?? /* @__PURE__ */ new Set();
|
|
4526
4557
|
children.add(childTopicUid);
|
|
4527
4558
|
childTopicUidsByParent.set(parentTopicUid, children);
|
|
4528
4559
|
}
|
|
4529
|
-
for (const raw of listValue$
|
|
4560
|
+
for (const raw of listValue$22(data.items)) {
|
|
4530
4561
|
const item = objectValue$1(raw);
|
|
4531
4562
|
if (arkmePrivacyLockedTopic(item)) continue;
|
|
4532
4563
|
const core = objectValue$1(item.topic_core);
|
|
4533
4564
|
const status = core.status ?? item.status;
|
|
4534
|
-
if (status !== void 0 && numberValue$
|
|
4565
|
+
if (status !== void 0 && numberValue$21(status) !== 1) continue;
|
|
4535
4566
|
const summary = objectValue$1(item.summary);
|
|
4536
4567
|
const latest = objectValue$1(item.latest_record_core);
|
|
4537
4568
|
const parent = objectValue$1(core.parent_topic_core ?? core.parent_topic ?? item.parent_topic_core ?? item.parent_topic);
|
|
@@ -4543,12 +4574,12 @@ var SourceService = class {
|
|
|
4543
4574
|
topicDescriptors.push({
|
|
4544
4575
|
topicUid,
|
|
4545
4576
|
...parentTopicUid === "" || parentTopicUid === topicUid ? {} : { parentTopicUid },
|
|
4546
|
-
siblingOrder: numberValue$
|
|
4577
|
+
siblingOrder: numberValue$21(siblingOrderByChild.get(topicUid) ?? core.sibling_order ?? item.sibling_order),
|
|
4547
4578
|
title,
|
|
4548
4579
|
latestPreview: arkmeChatConversationPreview(latest),
|
|
4549
|
-
latestMessageAtMillis: numberValue$
|
|
4550
|
-
activeAtMillis: numberValue$
|
|
4551
|
-
recordCount: numberValue$
|
|
4580
|
+
latestMessageAtMillis: numberValue$21(latest.send_at ?? summary.latest_send_at),
|
|
4581
|
+
activeAtMillis: numberValue$21(latest.send_at ?? summary.latest_send_at ?? core.update_at),
|
|
4582
|
+
recordCount: numberValue$21(summary.record_count)
|
|
4552
4583
|
});
|
|
4553
4584
|
}
|
|
4554
4585
|
const sourceRefByTopicUid = /* @__PURE__ */ new Map();
|
|
@@ -4590,12 +4621,12 @@ var SourceService = class {
|
|
|
4590
4621
|
unreadCount: 0
|
|
4591
4622
|
};
|
|
4592
4623
|
const nextPageCursor = objectValue$1(data.next_page_cursor ?? data.next_cursor);
|
|
4593
|
-
const nextOffset = numberValue$
|
|
4624
|
+
const nextOffset = numberValue$21(data.next_offset);
|
|
4594
4625
|
const preferredPageCursor = Object.keys(nextPageCursor).length > 0 ? nextPageCursor : void 0;
|
|
4595
4626
|
const preferredOffset = preferredPageCursor === void 0 && nextOffset > 0 ? nextOffset : void 0;
|
|
4596
4627
|
const hasMore = data.has_more === true && (preferredPageCursor !== void 0 || preferredOffset !== void 0);
|
|
4597
4628
|
const totalValue = data.total ?? data.total_count;
|
|
4598
|
-
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$
|
|
4629
|
+
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$21(totalValue));
|
|
4599
4630
|
return {
|
|
4600
4631
|
directory,
|
|
4601
4632
|
items: [
|
|
@@ -4626,7 +4657,7 @@ var SourceService = class {
|
|
|
4626
4657
|
const items = [];
|
|
4627
4658
|
const privateUserIdByIndex = /* @__PURE__ */ new Map();
|
|
4628
4659
|
const groupSessionUidByIndex = /* @__PURE__ */ new Map();
|
|
4629
|
-
for (const raw of listValue$
|
|
4660
|
+
for (const raw of listValue$22(data.items)) {
|
|
4630
4661
|
const bundle = objectValue$1(raw);
|
|
4631
4662
|
const chatSession = objectValue$1(bundle.session);
|
|
4632
4663
|
const counterpart = objectValue$1(bundle.private_counterpart);
|
|
@@ -4637,14 +4668,14 @@ var SourceService = class {
|
|
|
4637
4668
|
const unread = objectValue$1(bundle.unread_snapshot);
|
|
4638
4669
|
const currentPolicy = objectValue$1(bundle.current_policy);
|
|
4639
4670
|
const isMuted = chatMessageDnd$1(currentPolicy) ?? false;
|
|
4640
|
-
const isPinned = numberValue$
|
|
4671
|
+
const isPinned = numberValue$21(currentPolicy.pin_state) === 2;
|
|
4641
4672
|
const uid = stringValue$1(chatSession.chat_session_uid).trim();
|
|
4642
|
-
const sessionKind = numberValue$
|
|
4673
|
+
const sessionKind = numberValue$21(chatSession.session_kind);
|
|
4643
4674
|
const kind = sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : void 0;
|
|
4644
4675
|
if (uid === "" || kind === void 0) continue;
|
|
4645
4676
|
const displayName = (kind === "private_chat" ? stringValue$1(supplement.remark ?? supplement.counterpart_name_snapshot ?? counterpart.display_name_snapshot ?? supplement.pending_name ?? counterpart.visible_phone) : stringValue$1(chatSession.title)).trim() || "未命名会话";
|
|
4646
4677
|
const preview = arkmeChatConversationPreview(latestPayload);
|
|
4647
|
-
const unreadCount = Math.max(0, Math.trunc(numberValue$
|
|
4678
|
+
const unreadCount = Math.max(0, Math.trunc(numberValue$21(unread.unread_count)));
|
|
4648
4679
|
const latestRelation = objectValue$1(latestPreview.relation);
|
|
4649
4680
|
const latestPreviewMentionsViewer = integerLikeValue$2(latestRelation.sender_user_id ?? latestRelation.senderUserId) !== session.userId && arkmeMentionMetadataMentionsViewer(latestRecord, latestPayload, session.userId);
|
|
4650
4681
|
const backendMentionState = chatUnreadMentionState(unread);
|
|
@@ -4660,17 +4691,17 @@ var SourceService = class {
|
|
|
4660
4691
|
kind,
|
|
4661
4692
|
displayName,
|
|
4662
4693
|
...preview === "" ? {} : { latestPreview: preview },
|
|
4663
|
-
activeAtMillis: numberValue$
|
|
4694
|
+
activeAtMillis: numberValue$21(bundle.sort_active_at ?? chatSession.last_active_at),
|
|
4664
4695
|
unreadCount,
|
|
4665
4696
|
...hasUnreadMention === void 0 ? {} : { hasUnreadMention },
|
|
4666
4697
|
isMuted,
|
|
4667
4698
|
isPinned,
|
|
4668
|
-
...numberValue$
|
|
4699
|
+
...numberValue$21(unread.session_last_seq ?? chatSession.last_seq) > 0 ? { latestSequence: numberValue$21(unread.session_last_seq ?? chatSession.last_seq) } : {}
|
|
4669
4700
|
};
|
|
4670
4701
|
const itemIndex = items.push(item) - 1;
|
|
4671
4702
|
this.chatSourceCache.set(`${String(session.userId)}:${uid}`, item);
|
|
4672
4703
|
if (kind === "private_chat") {
|
|
4673
|
-
const counterpartUserId = numberValue$
|
|
4704
|
+
const counterpartUserId = numberValue$21(counterpart.user_id);
|
|
4674
4705
|
if (Number.isSafeInteger(counterpartUserId) && counterpartUserId > 0) {
|
|
4675
4706
|
item.peerUserId = counterpartUserId;
|
|
4676
4707
|
privateUserIdByIndex.set(itemIndex, counterpartUserId);
|
|
@@ -4684,7 +4715,7 @@ var SourceService = class {
|
|
|
4684
4715
|
}
|
|
4685
4716
|
const hasMore = data.has_more === true;
|
|
4686
4717
|
const totalValue = data.total ?? data.total_count;
|
|
4687
|
-
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$
|
|
4718
|
+
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$21(totalValue));
|
|
4688
4719
|
const nextPageCursor = objectValue$1(data.next_page_cursor);
|
|
4689
4720
|
return {
|
|
4690
4721
|
directory,
|
|
@@ -4740,16 +4771,16 @@ var SourceService = class {
|
|
|
4740
4771
|
continue;
|
|
4741
4772
|
}
|
|
4742
4773
|
const snapshotsByUid = /* @__PURE__ */ new Map();
|
|
4743
|
-
for (const raw of listValue$
|
|
4774
|
+
for (const raw of listValue$22(data.items)) {
|
|
4744
4775
|
const snapshot = objectValue$1(raw);
|
|
4745
4776
|
const uid = stringValue$1(snapshot.chat_session_uid).trim();
|
|
4746
4777
|
const index = indexByGroupUid.get(uid);
|
|
4747
4778
|
if (index === void 0 || !groupUids.includes(uid)) continue;
|
|
4748
|
-
const memberIds = listValue$
|
|
4779
|
+
const memberIds = listValue$22(snapshot.members).map((member) => numberValue$21(objectValue$1(member).user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0).slice(0, 5);
|
|
4749
4780
|
const projection = {
|
|
4750
|
-
memberCount: Math.max(0, Math.trunc(numberValue$
|
|
4781
|
+
memberCount: Math.max(0, Math.trunc(numberValue$21(snapshot.member_count))),
|
|
4751
4782
|
strategy: stringValue$1(snapshot.strategy).trim(),
|
|
4752
|
-
computedAtMillis: numberValue$
|
|
4783
|
+
computedAtMillis: numberValue$21(snapshot.computed_at),
|
|
4753
4784
|
memberIds
|
|
4754
4785
|
};
|
|
4755
4786
|
snapshotsByUid.set(uid, projection);
|
|
@@ -4798,7 +4829,7 @@ var SourceService = class {
|
|
|
4798
4829
|
async sealSourceRef(userId, kind, ownerRef, displayName, options = {}) {
|
|
4799
4830
|
const botGroupTarget = kind === "group_chat" ? sanitizeGroupBotBindingTarget(options.botGroupTarget) : void 0;
|
|
4800
4831
|
const sidebarTarget = kind === "private_chat" || kind === "group_chat" ? options.sidebarTarget : void 0;
|
|
4801
|
-
const payload = encodeOpaqueJson$
|
|
4832
|
+
const payload = encodeOpaqueJson$7({
|
|
4802
4833
|
version: 1,
|
|
4803
4834
|
userId,
|
|
4804
4835
|
kind,
|
|
@@ -4828,7 +4859,7 @@ var SourceService = class {
|
|
|
4828
4859
|
const kind = parsed.kind;
|
|
4829
4860
|
const result = {
|
|
4830
4861
|
version: 1,
|
|
4831
|
-
userId: numberValue$
|
|
4862
|
+
userId: numberValue$21(parsed.userId),
|
|
4832
4863
|
kind: isSourceKind(kind) ? kind : "default_category",
|
|
4833
4864
|
ownerRef: stringValue$1(parsed.ownerRef).trim(),
|
|
4834
4865
|
displayName: isSourceKind(kind) && kind === "default_category" ? "未分类" : stringValue$1(parsed.displayName).trim(),
|
|
@@ -4838,7 +4869,7 @@ var SourceService = class {
|
|
|
4838
4869
|
})() : {},
|
|
4839
4870
|
...kind === "private_chat" || kind === "group_chat" ? (() => {
|
|
4840
4871
|
const sidebarSubjectUid = stringValue$1(parsed.sidebarSubjectUid).trim();
|
|
4841
|
-
const sidebarHiddenAnchorTimestamp = Math.max(0, numberValue$
|
|
4872
|
+
const sidebarHiddenAnchorTimestamp = Math.max(0, numberValue$21(parsed.sidebarHiddenAnchorTimestamp));
|
|
4842
4873
|
return sidebarSubjectUid === "" ? {} : {
|
|
4843
4874
|
sidebarSubjectUid,
|
|
4844
4875
|
sidebarHiddenAnchorTimestamp
|
|
@@ -4872,16 +4903,16 @@ var SourceService = class {
|
|
|
4872
4903
|
const unread = objectValue$1(bundle.unread_snapshot);
|
|
4873
4904
|
const currentPolicy = objectValue$1(bundle.current_policy);
|
|
4874
4905
|
const isMuted = chatMessageDnd$1(currentPolicy) ?? cached?.isMuted ?? false;
|
|
4875
|
-
const isPinned = numberValue$
|
|
4906
|
+
const isPinned = numberValue$21(currentPolicy.pin_state) === 2;
|
|
4876
4907
|
const uid = stringValue$1(chatSession.chat_session_uid).trim();
|
|
4877
|
-
const sessionKind = numberValue$
|
|
4908
|
+
const sessionKind = numberValue$21(chatSession.session_kind);
|
|
4878
4909
|
const kind = sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : void 0;
|
|
4879
4910
|
if (uid === "" || kind === void 0) throw new Error("invalid chat display snapshot");
|
|
4880
4911
|
const displayName = (kind === "private_chat" ? stringValue$1(supplement.remark ?? supplement.counterpart_name_snapshot ?? counterpart.display_name_snapshot ?? supplement.pending_name ?? counterpart.visible_phone) : stringValue$1(chatSession.title)).trim() || cached?.displayName || "未命名会话";
|
|
4881
4912
|
const latestItem = [...timelineItems].sort((left, right) => (right.sequence ?? 0) - (left.sequence ?? 0))[0];
|
|
4882
4913
|
const latestPreview = latestItem === void 0 ? cached?.latestPreview : latestItem.forwardRecords === void 0 ? arkmeTimelineConversationPreview(latestItem) : `[转发] ${latestItem.forwardRecords.title}`;
|
|
4883
|
-
const latestSequence = Math.max(numberValue$
|
|
4884
|
-
const unreadCount = Math.max(0, Math.trunc(numberValue$
|
|
4914
|
+
const latestSequence = Math.max(numberValue$21(unread.session_last_seq ?? chatSession.last_seq), latestItem?.sequence ?? 0, cached?.latestSequence ?? 0);
|
|
4915
|
+
const unreadCount = Math.max(0, Math.trunc(numberValue$21(unread.unread_count)));
|
|
4885
4916
|
const latestMentionsViewer = latestItem?.isMe === false && latestItem.mentionsViewer === true;
|
|
4886
4917
|
const backendMentionState = chatUnreadMentionState(unread);
|
|
4887
4918
|
const hasUnreadMention = kind !== "group_chat" ? void 0 : unreadCount <= 0 ? false : backendMentionState === void 0 && !latestMentionsViewer ? cached?.hasUnreadMention : backendMentionState === true || latestMentionsViewer;
|
|
@@ -4899,7 +4930,7 @@ var SourceService = class {
|
|
|
4899
4930
|
...cached?.avatarRefs === void 0 ? {} : { avatarRefs: cached.avatarRefs },
|
|
4900
4931
|
...cached?.groupAvatar === void 0 ? {} : { groupAvatar: cached.groupAvatar },
|
|
4901
4932
|
...latestPreview === void 0 || latestPreview === "" ? {} : { latestPreview },
|
|
4902
|
-
activeAtMillis: Math.max(numberValue$
|
|
4933
|
+
activeAtMillis: Math.max(numberValue$21(bundle.sort_active_at ?? chatSession.last_active_at), latestItem?.sendAtMillis ?? 0),
|
|
4903
4934
|
unreadCount,
|
|
4904
4935
|
...hasUnreadMention === void 0 ? {} : { hasUnreadMention },
|
|
4905
4936
|
isMuted,
|
|
@@ -4908,7 +4939,7 @@ var SourceService = class {
|
|
|
4908
4939
|
};
|
|
4909
4940
|
}
|
|
4910
4941
|
encodeCursor(value) {
|
|
4911
|
-
return `arkme-cursor-v1.${encodeOpaqueJson$
|
|
4942
|
+
return `arkme-cursor-v1.${encodeOpaqueJson$7(value)}`;
|
|
4912
4943
|
}
|
|
4913
4944
|
decodeCursor(cursor) {
|
|
4914
4945
|
const [prefix, payload, ...extra] = cursor.trim().split(".");
|
|
@@ -4931,7 +4962,7 @@ var SourceService = class {
|
|
|
4931
4962
|
const value = this.decodeCursor(cursor);
|
|
4932
4963
|
if (value.directory !== "send_to_self") throw new ArkmePluginError("source-cursor-invalid", "发给自己的主题分页游标无效", false);
|
|
4933
4964
|
const pageCursor = objectValue$1(value.pageCursor);
|
|
4934
|
-
const offset = numberValue$
|
|
4965
|
+
const offset = numberValue$21(value.offset);
|
|
4935
4966
|
if (Object.keys(pageCursor).length === 0 && offset <= 0) throw new ArkmePluginError("source-cursor-invalid", "发给自己的主题分页游标无效", false);
|
|
4936
4967
|
return {
|
|
4937
4968
|
...Object.keys(pageCursor).length === 0 ? {} : { pageCursor },
|
|
@@ -4943,68 +4974,27 @@ var SourceService = class {
|
|
|
4943
4974
|
//#region src/services/bot-service.ts
|
|
4944
4975
|
const BOT_CONVERSATION_OWNER = {
|
|
4945
4976
|
subject: "jotmo-subject",
|
|
4946
|
-
chat: "jotmo-chat"
|
|
4947
|
-
unavailable: "unavailable"
|
|
4977
|
+
chat: "jotmo-chat"
|
|
4948
4978
|
};
|
|
4949
4979
|
const BOT_REF_TTL_MILLIS = 30 * 6e4;
|
|
4950
4980
|
const BOT_REF_CAP = 2e3;
|
|
4951
4981
|
const BOT_REF_PATTERN = /^arkme-bot-v2\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
4952
4982
|
const BOT_IMAGE_REF_PATTERN = /^arkme-bot-image-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;
|
|
4953
|
-
function numberValue$
|
|
4983
|
+
function numberValue$20(value) {
|
|
4954
4984
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
4955
4985
|
}
|
|
4956
|
-
function booleanValue$
|
|
4986
|
+
function booleanValue$11(value) {
|
|
4957
4987
|
return value === true;
|
|
4958
4988
|
}
|
|
4959
|
-
function listValue$
|
|
4989
|
+
function listValue$21(value) {
|
|
4960
4990
|
return Array.isArray(value) ? value : [];
|
|
4961
4991
|
}
|
|
4962
4992
|
function arkmeNormalizeBotProvider(value) {
|
|
4963
4993
|
const normalized = stringValue$1(value).trim().toLowerCase();
|
|
4964
4994
|
if (normalized === "openclaw" || normalized === "webhook") return normalized;
|
|
4965
4995
|
}
|
|
4966
|
-
const BOT_CHAT_SESSION_UID_KEYS = [
|
|
4967
|
-
"chat_session_uid",
|
|
4968
|
-
"chatSessionUid",
|
|
4969
|
-
"direct_chat_session_uid",
|
|
4970
|
-
"directChatSessionUid",
|
|
4971
|
-
"private_chat_session_uid",
|
|
4972
|
-
"privateChatSessionUid"
|
|
4973
|
-
];
|
|
4974
|
-
/** Read the standard-session aliases accepted by the Flutter desktop client. */
|
|
4975
|
-
function botChatSessionUid(data) {
|
|
4976
|
-
const read = (value, allowUid = false) => {
|
|
4977
|
-
for (const key of BOT_CHAT_SESSION_UID_KEYS) {
|
|
4978
|
-
const candidate = stringValue$1(value[key]).trim();
|
|
4979
|
-
if (candidate !== "" && candidate !== "null") return candidate;
|
|
4980
|
-
}
|
|
4981
|
-
const uid = allowUid ? stringValue$1(value.uid).trim() : "";
|
|
4982
|
-
return uid !== "" && uid !== "null" ? uid : void 0;
|
|
4983
|
-
};
|
|
4984
|
-
const direct = read(data);
|
|
4985
|
-
if (direct !== void 0) return direct;
|
|
4986
|
-
for (const key of [
|
|
4987
|
-
"chat_session",
|
|
4988
|
-
"direct_chat_session",
|
|
4989
|
-
"private_chat_session"
|
|
4990
|
-
]) {
|
|
4991
|
-
const nested = read(objectValue$1(data[key]), true);
|
|
4992
|
-
if (nested !== void 0) return nested;
|
|
4993
|
-
}
|
|
4994
|
-
}
|
|
4995
|
-
/**
|
|
4996
|
-
* Flutter accepts the legacy `session_id` returned by the Bot endpoint only
|
|
4997
|
-
* after proving it resolves to a chat session. Keep the same guard here: a
|
|
4998
|
-
* bot id (or a raw Bot topic id) must never become a generic chat source.
|
|
4999
|
-
*/
|
|
5000
|
-
function legacyBotChatSessionCandidate(value, botId) {
|
|
5001
|
-
const candidate = stringValue$1(value).trim();
|
|
5002
|
-
if (candidate === "" || candidate === botId) return void 0;
|
|
5003
|
-
if (candidate.includes("_bot") && !candidate.startsWith("chat_session_")) return void 0;
|
|
5004
|
-
return candidate;
|
|
5005
|
-
}
|
|
5006
4996
|
function botPrivateChatTimestamp(value) {
|
|
5007
|
-
const numeric = numberValue$
|
|
4997
|
+
const numeric = numberValue$20(value);
|
|
5008
4998
|
if (numeric <= 0) return 0;
|
|
5009
4999
|
if (numeric < 1e10) return numeric * 1e3;
|
|
5010
5000
|
let millis = numeric;
|
|
@@ -5014,89 +5004,44 @@ function botPrivateChatTimestamp(value) {
|
|
|
5014
5004
|
function botWebhookSecurity(value) {
|
|
5015
5005
|
const raw = objectValue$1(value);
|
|
5016
5006
|
return {
|
|
5017
|
-
keywordEnabled: booleanValue$
|
|
5007
|
+
keywordEnabled: booleanValue$11(raw.keyword_enabled),
|
|
5018
5008
|
keyword: stringValue$1(raw.keyword).trim(),
|
|
5019
|
-
tokenEnabled: booleanValue$
|
|
5020
|
-
ipWhitelistEnabled: booleanValue$
|
|
5021
|
-
ipWhitelist: listValue$
|
|
5009
|
+
tokenEnabled: booleanValue$11(raw.token_enabled ?? raw.signature_enabled),
|
|
5010
|
+
ipWhitelistEnabled: booleanValue$11(raw.ip_whitelist_enabled),
|
|
5011
|
+
ipWhitelist: listValue$21(raw.ip_whitelist).map((item) => stringValue$1(item).trim()).filter((item) => item !== "").slice(0, 100)
|
|
5022
5012
|
};
|
|
5023
5013
|
}
|
|
5024
5014
|
function botProfileSource(data) {
|
|
5025
5015
|
const bot = objectValue$1(data.bot);
|
|
5026
5016
|
return Object.keys(bot).length === 0 ? data : bot;
|
|
5027
5017
|
}
|
|
5028
|
-
function
|
|
5029
|
-
const
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5018
|
+
function botConversationTarget(data) {
|
|
5019
|
+
const subjectUid = stringValue$1(data.subject_uid).trim();
|
|
5020
|
+
const chatSessionUid = stringValue$1(data.chat_session_uid).trim();
|
|
5021
|
+
if (subjectUid !== "" && chatSessionUid !== "") return {
|
|
5022
|
+
kind: "unavailable",
|
|
5023
|
+
reason: "conflict"
|
|
5024
|
+
};
|
|
5025
|
+
if (subjectUid !== "") return {
|
|
5026
|
+
kind: "subject",
|
|
5027
|
+
subjectUid
|
|
5028
|
+
};
|
|
5029
|
+
if (chatSessionUid !== "") return {
|
|
5030
|
+
kind: "chat",
|
|
5031
|
+
chatSessionUid
|
|
5042
5032
|
};
|
|
5043
|
-
}
|
|
5044
|
-
function botPrivateChatAttachments(value) {
|
|
5045
|
-
return listValue$20(value).map(objectValue$1).flatMap((raw) => {
|
|
5046
|
-
const kind = stringValue$1(raw.kind).trim();
|
|
5047
|
-
const fileName = stringValue$1(raw.file_name ?? raw.fileName).trim();
|
|
5048
|
-
const mimeType = stringValue$1(raw.mime_type ?? raw.mimeType).trim();
|
|
5049
|
-
const hasSourceFile = stringValue$1(raw.file_id ?? raw.fileId).trim() !== "";
|
|
5050
|
-
if (kind === "" && fileName === "" && mimeType === "" && !hasSourceFile) return [];
|
|
5051
|
-
return [{
|
|
5052
|
-
kind: kind || "file",
|
|
5053
|
-
fileName,
|
|
5054
|
-
mimeType,
|
|
5055
|
-
size: Math.max(0, Math.trunc(numberValue$19(raw.size))),
|
|
5056
|
-
durationMillis: Math.max(0, Math.trunc(numberValue$19(raw.duration_ms ?? raw.durationMillis))),
|
|
5057
|
-
width: Math.max(0, Math.trunc(numberValue$19(raw.width))),
|
|
5058
|
-
height: Math.max(0, Math.trunc(numberValue$19(raw.height))),
|
|
5059
|
-
sortOrder: Math.max(0, Math.trunc(numberValue$19(raw.order ?? raw.sort_order ?? raw.sortOrder)))
|
|
5060
|
-
}];
|
|
5061
|
-
});
|
|
5062
|
-
}
|
|
5063
|
-
function botPrivateChatMessage(value, fallbackContent = "") {
|
|
5064
|
-
const raw = objectValue$1(value);
|
|
5065
|
-
const role = stringValue$1(raw.role).trim().toLowerCase() === "user" ? "user" : "assistant";
|
|
5066
|
-
const recordUid = stringValue$1(raw.record_uid ?? raw.recordUid).trim();
|
|
5067
|
-
const content = stringValue$1(raw.content);
|
|
5068
5033
|
return {
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
role,
|
|
5072
|
-
content: content === "" ? fallbackContent : content,
|
|
5073
|
-
status: stringValue$1(raw.status).trim() || "sent",
|
|
5074
|
-
createdAtMillis: botPrivateChatTimestamp(raw.created_at ?? raw.createdAt),
|
|
5075
|
-
attachments: botPrivateChatAttachments(raw.attachments)
|
|
5034
|
+
kind: "unavailable",
|
|
5035
|
+
reason: "missing"
|
|
5076
5036
|
};
|
|
5077
5037
|
}
|
|
5078
|
-
function
|
|
5079
|
-
const
|
|
5080
|
-
const result = [];
|
|
5081
|
-
for (const message of messages) {
|
|
5082
|
-
if (message.messageId !== "") {
|
|
5083
|
-
if (seenMessageIds.has(message.messageId)) continue;
|
|
5084
|
-
seenMessageIds.add(message.messageId);
|
|
5085
|
-
}
|
|
5086
|
-
result.push(message);
|
|
5087
|
-
}
|
|
5088
|
-
return result;
|
|
5089
|
-
}
|
|
5090
|
-
function botWithPrivateChatActivity(bot, messages) {
|
|
5091
|
-
const latest = messages.reduce((current, message) => {
|
|
5092
|
-
if (current === void 0 || message.createdAtMillis >= current.createdAtMillis) return message;
|
|
5093
|
-
return current;
|
|
5094
|
-
}, void 0);
|
|
5095
|
-
if (latest === void 0) return bot;
|
|
5038
|
+
function botConversationCapabilities(target, provider) {
|
|
5039
|
+
const owner = target.kind === "subject" ? BOT_CONVERSATION_OWNER.subject : target.kind === "chat" ? BOT_CONVERSATION_OWNER.chat : void 0;
|
|
5096
5040
|
return {
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5041
|
+
directChatAvailable: owner !== void 0,
|
|
5042
|
+
privateChatOutboundEnabled: owner === BOT_CONVERSATION_OWNER.chat || owner === BOT_CONVERSATION_OWNER.subject && provider === "openclaw",
|
|
5043
|
+
refreshOnRecordChanges: owner === BOT_CONVERSATION_OWNER.subject,
|
|
5044
|
+
conversationProjection: owner === BOT_CONVERSATION_OWNER.subject ? "record" : owner === BOT_CONVERSATION_OWNER.chat ? "chat" : "none"
|
|
5100
5045
|
};
|
|
5101
5046
|
}
|
|
5102
5047
|
var BotService = class {
|
|
@@ -5142,13 +5087,23 @@ var BotService = class {
|
|
|
5142
5087
|
}
|
|
5143
5088
|
async listBots(options = {}) {
|
|
5144
5089
|
const session = await this.runtime.requireSession();
|
|
5145
|
-
const
|
|
5090
|
+
const rawBots = listValue$21((await this.runtime.authenticatedBotPost("/api/v1/bot/list", {}, session, options.signal)).bots).map(objectValue$1);
|
|
5091
|
+
const candidates = rawBots.filter((raw) => stringValue$1(raw.bot_id).trim() !== "" && stringValue$1(raw.name).trim() !== "" && arkmeNormalizeBotProvider(raw.provider) !== void 0);
|
|
5092
|
+
const chatTargetCounts = /* @__PURE__ */ new Map();
|
|
5093
|
+
for (const raw of rawBots) {
|
|
5094
|
+
const chatSessionUid = stringValue$1(raw.chat_session_uid).trim();
|
|
5095
|
+
if (chatSessionUid === "") continue;
|
|
5096
|
+
chatTargetCounts.set(chatSessionUid, (chatTargetCounts.get(chatSessionUid) ?? 0) + 1);
|
|
5097
|
+
}
|
|
5146
5098
|
const items = [];
|
|
5147
|
-
for (const
|
|
5148
|
-
const
|
|
5149
|
-
|
|
5099
|
+
for (const raw of candidates) {
|
|
5100
|
+
const candidateTarget = botConversationTarget(raw);
|
|
5101
|
+
const target = candidateTarget.kind === "chat" && (chatTargetCounts.get(candidateTarget.chatSessionUid) ?? 0) > 1 ? {
|
|
5102
|
+
kind: "unavailable",
|
|
5103
|
+
reason: "duplicate_chat_target"
|
|
5104
|
+
} : candidateTarget;
|
|
5150
5105
|
try {
|
|
5151
|
-
items.push(await this.botSummaryFromData(raw, session.userId));
|
|
5106
|
+
items.push(await this.botSummaryFromData(raw, session.userId, target));
|
|
5152
5107
|
} catch (error) {
|
|
5153
5108
|
if (!(error instanceof ArkmePluginError) || error.code !== "bot-contract-invalid") throw error;
|
|
5154
5109
|
}
|
|
@@ -5158,7 +5113,7 @@ var BotService = class {
|
|
|
5158
5113
|
async countBots(options = {}) {
|
|
5159
5114
|
const session = await this.runtime.requireSession();
|
|
5160
5115
|
const data = await this.runtime.authenticatedBotPost("/api/v1/bot/list", { limit: 0 }, session, options.signal);
|
|
5161
|
-
return Math.max(0, numberValue$
|
|
5116
|
+
return Math.max(0, numberValue$20(data.total ?? data.total_count));
|
|
5162
5117
|
}
|
|
5163
5118
|
async createBot(input, options = {}) {
|
|
5164
5119
|
const name = input.name.trim();
|
|
@@ -5207,7 +5162,7 @@ var BotService = class {
|
|
|
5207
5162
|
const session = await this.runtime.requireSession();
|
|
5208
5163
|
const reference = await this.openBotRef(botRef, session.userId);
|
|
5209
5164
|
const data = await this.runtime.authenticatedBotPost("/api/v1/bot/profile", { bot_id: reference.botId }, session, options.signal);
|
|
5210
|
-
return await this.botManageProfileFromData(data, session.userId);
|
|
5165
|
+
return await this.botManageProfileFromData(data, session.userId, reference);
|
|
5211
5166
|
}
|
|
5212
5167
|
async updateManagedBot(botRef, input, options = {}) {
|
|
5213
5168
|
const name = input.name.trim();
|
|
@@ -5237,7 +5192,7 @@ var BotService = class {
|
|
|
5237
5192
|
} }
|
|
5238
5193
|
}, session, options.signal);
|
|
5239
5194
|
const refreshed = await this.runtime.authenticatedBotPost("/api/v1/bot/profile", { bot_id: reference.botId }, session, options.signal);
|
|
5240
|
-
return await this.botManageProfileFromData(refreshed, session.userId);
|
|
5195
|
+
return await this.botManageProfileFromData(refreshed, session.userId, reference);
|
|
5241
5196
|
}
|
|
5242
5197
|
async revealManagedBotToken(botRef, options = {}) {
|
|
5243
5198
|
return { token: (await this.revealBotSecret(botRef, options)).reveal() };
|
|
@@ -5250,113 +5205,24 @@ var BotService = class {
|
|
|
5250
5205
|
await this.runtime.authenticatedBotPost("/api/v1/bot/delete", { bot_id: reference.botId }, session, options.signal);
|
|
5251
5206
|
this.deleteBotRef(botRef);
|
|
5252
5207
|
}
|
|
5253
|
-
async botNotificationPreference(botRef, options = {}) {
|
|
5254
|
-
const { session, subjectUid } = await this.botNotificationTarget(botRef, options);
|
|
5255
|
-
return { muted: (await this.runtime.authenticatedSubjectPost("/api/v1/subject/get-able-push-status", { subject_uid: subjectUid }, session, options.signal)).able_push === false };
|
|
5256
|
-
}
|
|
5257
|
-
async updateBotNotificationPreference(botRef, muted, options = {}) {
|
|
5258
|
-
const { session, subjectUid } = await this.botNotificationTarget(botRef, options);
|
|
5259
|
-
await this.runtime.authenticatedSubjectPost("/api/v1/subject/set-able-push-status", {
|
|
5260
|
-
subject_uid: subjectUid,
|
|
5261
|
-
able_push: !muted
|
|
5262
|
-
}, session, options.signal);
|
|
5263
|
-
return { muted };
|
|
5264
|
-
}
|
|
5265
|
-
async botNotificationTarget(botRef, options = {}) {
|
|
5266
|
-
const session = await this.runtime.requireSession();
|
|
5267
|
-
const reference = await this.openBotRef(botRef, session.userId);
|
|
5268
|
-
const subjectUid = botProfileSubjectUid(await this.runtime.authenticatedBotPost("/api/v1/bot/profile", { bot_id: reference.botId }, session, options.signal));
|
|
5269
|
-
if (subjectUid === "") throw new ArkmePluginError("bot-notification-unavailable", "当前 Bot 未返回可用私聊通知标识", false, 409);
|
|
5270
|
-
return {
|
|
5271
|
-
session,
|
|
5272
|
-
subjectUid
|
|
5273
|
-
};
|
|
5274
|
-
}
|
|
5275
|
-
async openBotPrivateChat(botRef, options = {}) {
|
|
5276
|
-
const session = await this.runtime.requireSession();
|
|
5277
|
-
const bot = (await this.listBots(options)).items.find((item) => item.botRef === botRef);
|
|
5278
|
-
if (bot === void 0) throw new ArkmePluginError("bot-ref-not-owned", "当前账号不存在该 Bot", false, 404);
|
|
5279
|
-
return await this.openBotPrivateChatForSummary(bot, session, options.signal);
|
|
5280
|
-
}
|
|
5281
|
-
async listBotPrivateChatDirectory(options = {}) {
|
|
5282
|
-
const session = await this.runtime.requireSession();
|
|
5283
|
-
const { items } = await this.listBots(options);
|
|
5284
|
-
return { items: await Promise.all(items.map(async (bot) => {
|
|
5285
|
-
try {
|
|
5286
|
-
return (await this.openBotPrivateChatForSummary(bot, session, options.signal)).bot;
|
|
5287
|
-
} catch {
|
|
5288
|
-
return bot;
|
|
5289
|
-
}
|
|
5290
|
-
})) };
|
|
5291
|
-
}
|
|
5292
|
-
async openBotPrivateChatForSummary(bot, session, signal) {
|
|
5293
|
-
const reference = await this.openBotRef(bot.botRef, session.userId);
|
|
5294
|
-
if (reference.conversationOwner === BOT_CONVERSATION_OWNER.unavailable) throw new ArkmePluginError("bot-private-chat-owner-unavailable", "当前 Bot 私聊归属信息不可用,请刷新后重试", false, 409);
|
|
5295
|
-
const messages = dedupeBotPrivateChatMessages(listValue$20((await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/open", { bot_id: reference.botId }, session, signal)).messages).map((message) => botPrivateChatMessage(message)));
|
|
5296
|
-
return {
|
|
5297
|
-
bot: botWithPrivateChatActivity(bot, messages),
|
|
5298
|
-
messages
|
|
5299
|
-
};
|
|
5300
|
-
}
|
|
5301
|
-
async sendBotPrivateChatMessage(botRef, contentInput, options = {}) {
|
|
5302
|
-
const content = contentInput.trim();
|
|
5303
|
-
if (content === "") throw new ArkmePluginError("bot-private-chat-content-invalid", "请输入消息内容", false, 400);
|
|
5304
|
-
if (content.length > 2e4) throw new ArkmePluginError("bot-private-chat-content-invalid", "消息不能超过 20000 个字符", false, 400);
|
|
5305
|
-
const session = await this.runtime.requireSession();
|
|
5306
|
-
const reference = await this.openBotRef(botRef, session.userId);
|
|
5307
|
-
if (reference.conversationOwner === BOT_CONVERSATION_OWNER.unavailable) throw new ArkmePluginError("bot-private-chat-owner-unavailable", "当前 Bot 私聊归属信息不可用,请刷新后重试", false, 409);
|
|
5308
|
-
if (reference.conversationOwner === BOT_CONVERSATION_OWNER.subject && reference.provider === "webhook") throw new ArkmePluginError("bot-private-chat-send-unsupported", "Webhook Bot 仅接收外部系统推送", false, 400);
|
|
5309
|
-
let data;
|
|
5310
|
-
try {
|
|
5311
|
-
data = await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/message/send", {
|
|
5312
|
-
bot_id: reference.botId,
|
|
5313
|
-
content
|
|
5314
|
-
}, session, options.signal);
|
|
5315
|
-
} catch (error) {
|
|
5316
|
-
if (reference.conversationOwner === BOT_CONVERSATION_OWNER.subject && error instanceof ArkmePluginError && (error.retryable || [
|
|
5317
|
-
"arkme-network-error",
|
|
5318
|
-
"arkme-timeout",
|
|
5319
|
-
"arkme-response-invalid"
|
|
5320
|
-
].includes(error.code))) throw new ArkmePluginError("bot-private-chat-send-outcome-unknown", "消息发送结果未知,请刷新会话确认;不会自动重试", false, 409, { cause: error });
|
|
5321
|
-
throw error;
|
|
5322
|
-
}
|
|
5323
|
-
if (reference.conversationOwner === BOT_CONVERSATION_OWNER.subject && stringValue$1(objectValue$1(data.user_message).message_id).trim() === "") throw new ArkmePluginError("bot-private-chat-send-outcome-unknown", "消息可能已发送,但响应缺少确认标识;请刷新会话确认", false, 409);
|
|
5324
|
-
const botMessages = dedupeBotPrivateChatMessages([...listValue$20(data.bot_messages).map((message) => botPrivateChatMessage(message)), ...Object.keys(objectValue$1(data.bot_message)).length === 0 ? [] : [botPrivateChatMessage(data.bot_message)]]);
|
|
5325
|
-
return {
|
|
5326
|
-
recordProjectionChanged: reference.conversationOwner === BOT_CONVERSATION_OWNER.subject,
|
|
5327
|
-
result: {
|
|
5328
|
-
userMessage: botPrivateChatMessage(data.user_message, content),
|
|
5329
|
-
botMessages,
|
|
5330
|
-
status: stringValue$1(data.status).trim() || "ok"
|
|
5331
|
-
}
|
|
5332
|
-
};
|
|
5333
|
-
}
|
|
5334
5208
|
async openBotChat(botRef, options = {}) {
|
|
5335
5209
|
const session = await this.runtime.requireSession();
|
|
5336
5210
|
await this.openBotRef(botRef, session.userId);
|
|
5337
5211
|
const bot = (await this.listBots(options)).items.find((item) => item.botRef === botRef);
|
|
5338
5212
|
if (bot === void 0) throw new ArkmePluginError("bot-ref-not-owned", "当前账号不存在该 OpenClaw Bot", false, 404);
|
|
5339
5213
|
const reference = await this.openBotRef(botRef, session.userId);
|
|
5340
|
-
if (reference.
|
|
5341
|
-
const
|
|
5342
|
-
|
|
5343
|
-
|
|
5344
|
-
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
return source;
|
|
5353
|
-
}
|
|
5354
|
-
const legacySessionId = legacyBotChatSessionCandidate(data.session_id, reference.botId);
|
|
5355
|
-
if (legacySessionId !== void 0) {
|
|
5356
|
-
const source = await this.source.searchTargetSource(3, legacySessionId, bot.name, options.signal);
|
|
5357
|
-
if (source !== void 0) return source;
|
|
5358
|
-
}
|
|
5359
|
-
throw new ArkmePluginError("bot-chat-source-unavailable", "当前 Bot 私聊未返回可用会话,暂时不能复用统一 source 读写链路", false, 409);
|
|
5214
|
+
if (reference.target.kind !== "chat") throw new ArkmePluginError("bot-chat-source-unavailable", "当前 Bot 不属于 Chat 私聊链路", false, 409);
|
|
5215
|
+
const chatSessionUid = stringValue$1((await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/open", { bot_id: reference.botId }, session, options.signal)).chat_session_uid).trim();
|
|
5216
|
+
if (chatSessionUid === "" || chatSessionUid !== reference.target.chatSessionUid) throw new ArkmePluginError("bot-chat-source-unavailable", "当前 Bot 私聊会话确认不一致", false, 409);
|
|
5217
|
+
const source = {
|
|
5218
|
+
sourceRef: await this.source.sealSourceRef(session.userId, "private_chat", chatSessionUid, bot.name),
|
|
5219
|
+
kind: "private_chat",
|
|
5220
|
+
displayName: bot.name,
|
|
5221
|
+
activeAtMillis: 0,
|
|
5222
|
+
unreadCount: 0
|
|
5223
|
+
};
|
|
5224
|
+
this.source.setChatSourceByKey(`${String(session.userId)}:${chatSessionUid}`, source);
|
|
5225
|
+
return source;
|
|
5360
5226
|
}
|
|
5361
5227
|
async resolveBotConnectionMetadata(botRef, options = {}) {
|
|
5362
5228
|
const session = await this.runtime.requireSession();
|
|
@@ -5383,19 +5249,19 @@ var BotService = class {
|
|
|
5383
5249
|
const groupTargetBody = await this.resolveGroupBotBindingBody(group, session, options.signal);
|
|
5384
5250
|
const data = await this.runtime.authenticatedBotPost("/api/v1/bot/group/list", groupTargetBody, session, options.signal);
|
|
5385
5251
|
const items = [];
|
|
5386
|
-
for (const value of listValue$
|
|
5252
|
+
for (const value of listValue$21(data.bots)) {
|
|
5387
5253
|
const raw = objectValue$1(value);
|
|
5388
5254
|
if (arkmeNormalizeBotProvider(raw.provider) !== "openclaw") continue;
|
|
5389
5255
|
const summary = await this.groupBotSummaryFromData(raw, session.userId);
|
|
5390
5256
|
items.push({
|
|
5391
5257
|
...summary,
|
|
5392
|
-
installed: booleanValue$
|
|
5258
|
+
installed: booleanValue$11(raw.installed)
|
|
5393
5259
|
});
|
|
5394
5260
|
}
|
|
5395
5261
|
return {
|
|
5396
5262
|
groupSourceRef,
|
|
5397
5263
|
displayName: stringValue$1(data.subject_title).trim() || group.displayName,
|
|
5398
|
-
canAddBots: booleanValue$
|
|
5264
|
+
canAddBots: booleanValue$11(data.can_current_user_add_bots),
|
|
5399
5265
|
items
|
|
5400
5266
|
};
|
|
5401
5267
|
}
|
|
@@ -5435,9 +5301,9 @@ var BotService = class {
|
|
|
5435
5301
|
}
|
|
5436
5302
|
async listMentionableGroupBots(group, session, signal) {
|
|
5437
5303
|
const groupTargetBody = await this.resolveGroupBotBindingBody(group, session, signal);
|
|
5438
|
-
return listValue$
|
|
5304
|
+
return listValue$21((await this.runtime.authenticatedBotPost("/api/v1/bot/group/list", groupTargetBody, session, signal)).bots).flatMap((value) => {
|
|
5439
5305
|
const raw = objectValue$1(value);
|
|
5440
|
-
if (arkmeNormalizeBotProvider(raw.provider) !== "openclaw" || !booleanValue$
|
|
5306
|
+
if (arkmeNormalizeBotProvider(raw.provider) !== "openclaw" || !booleanValue$11(raw.installed)) return [];
|
|
5441
5307
|
const botId = stringValue$1(raw.bot_id).trim();
|
|
5442
5308
|
const name = stringValue$1(raw.name).trim();
|
|
5443
5309
|
if (botId === "" || name === "") throw new ArkmePluginError("bot-contract-invalid", "Bot 响应不完整", true, 502);
|
|
@@ -5460,7 +5326,7 @@ var BotService = class {
|
|
|
5460
5326
|
botGroupTarget
|
|
5461
5327
|
});
|
|
5462
5328
|
}
|
|
5463
|
-
async botSummaryBaseFromData(raw, userId,
|
|
5329
|
+
async botSummaryBaseFromData(raw, userId, target) {
|
|
5464
5330
|
const botId = stringValue$1(raw.bot_id).trim();
|
|
5465
5331
|
const name = stringValue$1(raw.name).trim();
|
|
5466
5332
|
const provider = arkmeNormalizeBotProvider(raw.provider);
|
|
@@ -5469,7 +5335,7 @@ var BotService = class {
|
|
|
5469
5335
|
const status = rawStatus === "online" || rawStatus === "offline" ? rawStatus : "unknown";
|
|
5470
5336
|
const createdAtMillis = botPrivateChatTimestamp(raw.created_at ?? raw.createdAt);
|
|
5471
5337
|
return {
|
|
5472
|
-
botRef: this.sealBotRef(userId, botId, provider,
|
|
5338
|
+
botRef: this.sealBotRef(userId, botId, provider, target),
|
|
5473
5339
|
directoryKey: await this.botDirectoryKey(userId, botId),
|
|
5474
5340
|
name,
|
|
5475
5341
|
provider,
|
|
@@ -5479,21 +5345,23 @@ var BotService = class {
|
|
|
5479
5345
|
...this.botAvatarProjection(raw, userId, botId)
|
|
5480
5346
|
};
|
|
5481
5347
|
}
|
|
5482
|
-
async botSummaryFromData(raw, userId) {
|
|
5483
|
-
const
|
|
5484
|
-
const summary = await this.botSummaryBaseFromData(raw, userId,
|
|
5348
|
+
async botSummaryFromData(raw, userId, knownTarget) {
|
|
5349
|
+
const target = knownTarget ?? botConversationTarget(raw);
|
|
5350
|
+
const summary = await this.botSummaryBaseFromData(raw, userId, target);
|
|
5485
5351
|
return {
|
|
5486
5352
|
...summary,
|
|
5487
|
-
...botConversationCapabilities(
|
|
5353
|
+
...botConversationCapabilities(target, summary.provider),
|
|
5354
|
+
...target.kind === "chat" ? { chatSourceKey: await this.source.chatDirectorySourceKey(userId, target.chatSessionUid) } : {}
|
|
5488
5355
|
};
|
|
5489
5356
|
}
|
|
5490
5357
|
async groupBotSummaryFromData(raw, userId) {
|
|
5491
5358
|
return await this.botSummaryBaseFromData(raw, userId, void 0);
|
|
5492
5359
|
}
|
|
5493
|
-
async botManageProfileFromData(data, userId) {
|
|
5360
|
+
async botManageProfileFromData(data, userId, reference) {
|
|
5494
5361
|
const raw = botProfileSource(data);
|
|
5495
|
-
|
|
5496
|
-
const
|
|
5362
|
+
if (stringValue$1(raw.bot_id).trim() !== reference.botId || arkmeNormalizeBotProvider(raw.provider) !== reference.provider) throw new ArkmePluginError("bot-contract-invalid", "Bot 配置响应与当前 Bot 不一致", true, 502);
|
|
5363
|
+
const summary = await this.botSummaryFromData(raw, userId, reference.target);
|
|
5364
|
+
const joinedGroups = listValue$21(data.joined_groups).map((value) => objectValue$1(value)).map((group) => ({
|
|
5497
5365
|
title: stringValue$1(group.subject_title).trim() || stringValue$1(group.subject_uid).trim() || "未命名群聊",
|
|
5498
5366
|
installedAtMillis: botPrivateChatTimestamp(group.installed_at)
|
|
5499
5367
|
}));
|
|
@@ -5505,7 +5373,7 @@ var BotService = class {
|
|
|
5505
5373
|
tokenRevealEnabled: data.token_reveal_enabled !== false,
|
|
5506
5374
|
gatewayUrl: stringValue$1(data.gateway_url).trim(),
|
|
5507
5375
|
webhookUrl: stringValue$1(data.webhook_url).trim(),
|
|
5508
|
-
recordCount: Math.max(-1, Math.trunc(numberValue$
|
|
5376
|
+
recordCount: Math.max(-1, Math.trunc(numberValue$20(raw.record_count))),
|
|
5509
5377
|
webhookSecurity: botWebhookSecurity(data.webhook_security ?? raw.webhook_security),
|
|
5510
5378
|
joinedGroups
|
|
5511
5379
|
};
|
|
@@ -5565,7 +5433,7 @@ var BotService = class {
|
|
|
5565
5433
|
expiresAtMillis: entry.expiresAtMillis
|
|
5566
5434
|
};
|
|
5567
5435
|
}
|
|
5568
|
-
sealBotRef(userId, botId, provider,
|
|
5436
|
+
sealBotRef(userId, botId, provider, target) {
|
|
5569
5437
|
this.pruneBotRefs();
|
|
5570
5438
|
const key = `${String(userId)}\u0000${provider}\u0000${botId}`;
|
|
5571
5439
|
const existingRef = this.botRefByKey.get(key);
|
|
@@ -5573,7 +5441,7 @@ var BotService = class {
|
|
|
5573
5441
|
if (existing !== void 0) {
|
|
5574
5442
|
this.botRefs.set(existingRef, {
|
|
5575
5443
|
...existing,
|
|
5576
|
-
...
|
|
5444
|
+
...target === void 0 ? {} : { target },
|
|
5577
5445
|
expiresAtMillis: this.now() + (this.refOptions.ttlMillis ?? BOT_REF_TTL_MILLIS)
|
|
5578
5446
|
});
|
|
5579
5447
|
return existingRef;
|
|
@@ -5584,7 +5452,10 @@ var BotService = class {
|
|
|
5584
5452
|
userId,
|
|
5585
5453
|
botId,
|
|
5586
5454
|
provider,
|
|
5587
|
-
|
|
5455
|
+
target: target ?? {
|
|
5456
|
+
kind: "unavailable",
|
|
5457
|
+
reason: "missing"
|
|
5458
|
+
},
|
|
5588
5459
|
key,
|
|
5589
5460
|
expiresAtMillis: this.now() + (this.refOptions.ttlMillis ?? BOT_REF_TTL_MILLIS)
|
|
5590
5461
|
});
|
|
@@ -5628,13 +5499,251 @@ var BotService = class {
|
|
|
5628
5499
|
}
|
|
5629
5500
|
};
|
|
5630
5501
|
//#endregion
|
|
5502
|
+
//#region src/services/bot-conversation-service.ts
|
|
5503
|
+
function numberValue$19(value) {
|
|
5504
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
5505
|
+
}
|
|
5506
|
+
function listValue$20(value) {
|
|
5507
|
+
return Array.isArray(value) ? value : [];
|
|
5508
|
+
}
|
|
5509
|
+
function botConversationTimestamp(value) {
|
|
5510
|
+
const numeric = numberValue$19(value);
|
|
5511
|
+
if (numeric <= 0) return 0;
|
|
5512
|
+
if (numeric < 1e10) return numeric * 1e3;
|
|
5513
|
+
let millis = numeric;
|
|
5514
|
+
while (millis >= 0x5af3107a4000) millis = Math.trunc(millis / 1e3);
|
|
5515
|
+
return millis;
|
|
5516
|
+
}
|
|
5517
|
+
function subjectAttachments(value) {
|
|
5518
|
+
return listValue$20(value).map(objectValue$1).flatMap((raw) => {
|
|
5519
|
+
const kind = stringValue$1(raw.kind).trim();
|
|
5520
|
+
const fileName = stringValue$1(raw.file_name ?? raw.fileName).trim();
|
|
5521
|
+
const mimeType = stringValue$1(raw.mime_type ?? raw.mimeType).trim();
|
|
5522
|
+
const hasSourceFile = stringValue$1(raw.file_id ?? raw.fileId).trim() !== "";
|
|
5523
|
+
if (kind === "" && fileName === "" && mimeType === "" && !hasSourceFile) return [];
|
|
5524
|
+
return [{
|
|
5525
|
+
kind: kind || "file",
|
|
5526
|
+
fileName,
|
|
5527
|
+
mimeType,
|
|
5528
|
+
size: Math.max(0, Math.trunc(numberValue$19(raw.size))),
|
|
5529
|
+
durationMillis: Math.max(0, Math.trunc(numberValue$19(raw.duration_ms ?? raw.durationMillis))),
|
|
5530
|
+
width: Math.max(0, Math.trunc(numberValue$19(raw.width))),
|
|
5531
|
+
height: Math.max(0, Math.trunc(numberValue$19(raw.height))),
|
|
5532
|
+
sortOrder: Math.max(0, Math.trunc(numberValue$19(raw.order ?? raw.sort_order ?? raw.sortOrder)))
|
|
5533
|
+
}];
|
|
5534
|
+
});
|
|
5535
|
+
}
|
|
5536
|
+
function subjectMessage(value, fallbackContent = "") {
|
|
5537
|
+
const raw = objectValue$1(value);
|
|
5538
|
+
const recordUid = stringValue$1(raw.record_uid ?? raw.recordUid).trim();
|
|
5539
|
+
const content = stringValue$1(raw.content);
|
|
5540
|
+
return {
|
|
5541
|
+
messageId: stringValue$1(raw.message_id ?? raw.messageId).trim(),
|
|
5542
|
+
...recordUid === "" ? {} : { recordUid },
|
|
5543
|
+
role: stringValue$1(raw.role).trim().toLowerCase() === "user" ? "user" : "assistant",
|
|
5544
|
+
content: content === "" ? fallbackContent : content,
|
|
5545
|
+
status: stringValue$1(raw.status).trim() || "sent",
|
|
5546
|
+
createdAtMillis: botConversationTimestamp(raw.created_at ?? raw.createdAt),
|
|
5547
|
+
attachments: subjectAttachments(raw.attachments)
|
|
5548
|
+
};
|
|
5549
|
+
}
|
|
5550
|
+
function dedupeMessages(messages) {
|
|
5551
|
+
const seen = /* @__PURE__ */ new Set();
|
|
5552
|
+
return messages.filter((message) => {
|
|
5553
|
+
if (message.messageId === "") return true;
|
|
5554
|
+
if (seen.has(message.messageId)) return false;
|
|
5555
|
+
seen.add(message.messageId);
|
|
5556
|
+
return true;
|
|
5557
|
+
});
|
|
5558
|
+
}
|
|
5559
|
+
function withLatestActivity(bot, messages) {
|
|
5560
|
+
const latest = messages.reduce((current, message) => current === void 0 || message.createdAtMillis >= current.createdAtMillis ? message : current, void 0);
|
|
5561
|
+
if (latest === void 0) return bot;
|
|
5562
|
+
return {
|
|
5563
|
+
...bot,
|
|
5564
|
+
...latest.createdAtMillis > 0 ? { latestMessageAtMillis: latest.createdAtMillis } : {},
|
|
5565
|
+
...latest.content === "" ? {} : { latestMessagePreview: latest.content }
|
|
5566
|
+
};
|
|
5567
|
+
}
|
|
5568
|
+
var SubjectBotConversationAdapter = class {
|
|
5569
|
+
runtime;
|
|
5570
|
+
constructor(runtime) {
|
|
5571
|
+
this.runtime = runtime;
|
|
5572
|
+
}
|
|
5573
|
+
async open(context, signal) {
|
|
5574
|
+
return await this.read(context, signal);
|
|
5575
|
+
}
|
|
5576
|
+
async refresh(context, signal) {
|
|
5577
|
+
return await this.read(context, signal);
|
|
5578
|
+
}
|
|
5579
|
+
async send(context, contentInput, signal) {
|
|
5580
|
+
this.subjectTarget(context);
|
|
5581
|
+
const content = contentInput.trim();
|
|
5582
|
+
if (context.reference.provider === "webhook") throw new ArkmePluginError("bot-conversation-send-unsupported", "Webhook Bot 仅接收外部系统推送", false, 400);
|
|
5583
|
+
if (content === "" || content.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("bot-conversation-content-invalid", "Bot 消息为空或超过长度限制", false, 400);
|
|
5584
|
+
let data;
|
|
5585
|
+
try {
|
|
5586
|
+
data = await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/message/send", {
|
|
5587
|
+
bot_id: context.reference.botId,
|
|
5588
|
+
content
|
|
5589
|
+
}, context.session, signal);
|
|
5590
|
+
} catch (error) {
|
|
5591
|
+
if (error instanceof ArkmePluginError && (error.retryable || [
|
|
5592
|
+
"arkme-network-error",
|
|
5593
|
+
"arkme-timeout",
|
|
5594
|
+
"arkme-response-invalid"
|
|
5595
|
+
].includes(error.code))) throw new ArkmePluginError("bot-conversation-send-outcome-unknown", "消息发送结果未知,请刷新会话确认;不会自动重试", false, 409, { cause: error });
|
|
5596
|
+
throw error;
|
|
5597
|
+
}
|
|
5598
|
+
if (stringValue$1(objectValue$1(data.user_message).message_id).trim() === "") throw new ArkmePluginError("bot-conversation-send-outcome-unknown", "消息可能已发送,但响应缺少确认标识;请刷新会话确认", false, 409);
|
|
5599
|
+
return {
|
|
5600
|
+
userMessage: subjectMessage(data.user_message, content),
|
|
5601
|
+
botMessages: dedupeMessages([...listValue$20(data.bot_messages).map((message) => subjectMessage(message)), ...Object.keys(objectValue$1(data.bot_message)).length === 0 ? [] : [subjectMessage(data.bot_message)]]),
|
|
5602
|
+
status: stringValue$1(data.status).trim() || "ok"
|
|
5603
|
+
};
|
|
5604
|
+
}
|
|
5605
|
+
async notificationPreference(context, signal) {
|
|
5606
|
+
const target = this.subjectTarget(context);
|
|
5607
|
+
return { muted: (await this.runtime.authenticatedSubjectPost("/api/v1/subject/get-able-push-status", { subject_uid: target.subjectUid }, context.session, signal)).able_push === false };
|
|
5608
|
+
}
|
|
5609
|
+
async updateNotificationPreference(context, muted, signal) {
|
|
5610
|
+
const target = this.subjectTarget(context);
|
|
5611
|
+
await this.runtime.authenticatedSubjectPost("/api/v1/subject/set-able-push-status", {
|
|
5612
|
+
subject_uid: target.subjectUid,
|
|
5613
|
+
able_push: !muted
|
|
5614
|
+
}, context.session, signal);
|
|
5615
|
+
return { muted };
|
|
5616
|
+
}
|
|
5617
|
+
async read(context, signal) {
|
|
5618
|
+
this.subjectTarget(context);
|
|
5619
|
+
return { messages: dedupeMessages(listValue$20((await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/open", { bot_id: context.reference.botId }, context.session, signal)).messages).map((message) => subjectMessage(message))) };
|
|
5620
|
+
}
|
|
5621
|
+
subjectTarget(context) {
|
|
5622
|
+
if (context.reference.target.kind !== "subject") throw new ArkmePluginError("bot-conversation-owner-mismatch", "Bot 会话 owner 不匹配", false, 409);
|
|
5623
|
+
return context.reference.target;
|
|
5624
|
+
}
|
|
5625
|
+
};
|
|
5626
|
+
var ChatBotConversationAdapter = class {
|
|
5627
|
+
runtime;
|
|
5628
|
+
chat;
|
|
5629
|
+
constructor(runtime, chat) {
|
|
5630
|
+
this.runtime = runtime;
|
|
5631
|
+
this.chat = chat;
|
|
5632
|
+
}
|
|
5633
|
+
async open(context, signal) {
|
|
5634
|
+
const target = this.chatTarget(context);
|
|
5635
|
+
if (stringValue$1((await this.runtime.authenticatedBotPost("/api/v1/bot/private-chat/open", { bot_id: context.reference.botId }, context.session, signal)).chat_session_uid).trim() !== target.chatSessionUid) throw new ArkmePluginError("bot-conversation-target-mismatch", "Bot Chat 会话确认不一致", false, 409);
|
|
5636
|
+
return await this.chat.readDirectBotConversation(context.reference.botId, target.chatSessionUid, signal === void 0 ? {} : { signal });
|
|
5637
|
+
}
|
|
5638
|
+
async refresh(context, signal) {
|
|
5639
|
+
const target = this.chatTarget(context);
|
|
5640
|
+
return await this.chat.readDirectBotConversation(context.reference.botId, target.chatSessionUid, signal === void 0 ? {} : { signal });
|
|
5641
|
+
}
|
|
5642
|
+
async send(context, content, signal) {
|
|
5643
|
+
const target = this.chatTarget(context);
|
|
5644
|
+
return await this.chat.sendDirectBotText(target.chatSessionUid, content, signal === void 0 ? {} : { signal });
|
|
5645
|
+
}
|
|
5646
|
+
async markRead(context, sequence, signal) {
|
|
5647
|
+
const target = this.chatTarget(context);
|
|
5648
|
+
return await this.chat.markDirectBotRead(target.chatSessionUid, sequence, signal === void 0 ? {} : { signal });
|
|
5649
|
+
}
|
|
5650
|
+
async notificationPreference(context, signal) {
|
|
5651
|
+
const target = this.chatTarget(context);
|
|
5652
|
+
return await this.chat.directBotNotificationPreference(target.chatSessionUid, signal === void 0 ? {} : { signal });
|
|
5653
|
+
}
|
|
5654
|
+
async updateNotificationPreference(context, muted, signal) {
|
|
5655
|
+
const target = this.chatTarget(context);
|
|
5656
|
+
return await this.chat.updateDirectBotNotificationPreference(target.chatSessionUid, muted, signal === void 0 ? {} : { signal });
|
|
5657
|
+
}
|
|
5658
|
+
chatTarget(context) {
|
|
5659
|
+
if (context.reference.target.kind !== "chat") throw new ArkmePluginError("bot-conversation-owner-mismatch", "Bot 会话 owner 不匹配", false, 409);
|
|
5660
|
+
return context.reference.target;
|
|
5661
|
+
}
|
|
5662
|
+
};
|
|
5663
|
+
var BotConversationService = class {
|
|
5664
|
+
runtime;
|
|
5665
|
+
bot;
|
|
5666
|
+
invalidateRecordProjection;
|
|
5667
|
+
subject;
|
|
5668
|
+
chatAdapter;
|
|
5669
|
+
constructor(runtime, bot, chat, invalidateRecordProjection) {
|
|
5670
|
+
this.runtime = runtime;
|
|
5671
|
+
this.bot = bot;
|
|
5672
|
+
this.invalidateRecordProjection = invalidateRecordProjection;
|
|
5673
|
+
this.subject = new SubjectBotConversationAdapter(runtime);
|
|
5674
|
+
this.chatAdapter = new ChatBotConversationAdapter(runtime, chat);
|
|
5675
|
+
}
|
|
5676
|
+
async directory(options = {}) {
|
|
5677
|
+
const session = await this.runtime.requireSession();
|
|
5678
|
+
const { items } = await this.bot.listBots(options);
|
|
5679
|
+
return { items: await Promise.all(items.map(async (bot) => {
|
|
5680
|
+
const reference = await this.bot.openBotRef(bot.botRef, session.userId);
|
|
5681
|
+
if (reference.target.kind !== "subject") return bot;
|
|
5682
|
+
try {
|
|
5683
|
+
return withLatestActivity(bot, (await this.subject.open({
|
|
5684
|
+
session,
|
|
5685
|
+
reference: {
|
|
5686
|
+
...reference,
|
|
5687
|
+
target: reference.target
|
|
5688
|
+
}
|
|
5689
|
+
}, options.signal)).messages);
|
|
5690
|
+
} catch {
|
|
5691
|
+
return bot;
|
|
5692
|
+
}
|
|
5693
|
+
})) };
|
|
5694
|
+
}
|
|
5695
|
+
async open(botRef, options = {}) {
|
|
5696
|
+
const context = await this.context(botRef);
|
|
5697
|
+
return await this.adapter(context).open(context, options.signal);
|
|
5698
|
+
}
|
|
5699
|
+
async refresh(botRef, options = {}) {
|
|
5700
|
+
const context = await this.context(botRef);
|
|
5701
|
+
return await this.adapter(context).refresh(context, options.signal);
|
|
5702
|
+
}
|
|
5703
|
+
async send(botRef, content, options = {}) {
|
|
5704
|
+
const context = await this.context(botRef);
|
|
5705
|
+
const result = await this.adapter(context).send(context, content, options.signal);
|
|
5706
|
+
if (context.reference.target.kind === "subject") await this.invalidateRecordProjection();
|
|
5707
|
+
return result;
|
|
5708
|
+
}
|
|
5709
|
+
async markRead(botRef, sequence, options = {}) {
|
|
5710
|
+
const context = await this.context(botRef);
|
|
5711
|
+
const adapter = this.adapter(context);
|
|
5712
|
+
if (adapter.markRead === void 0) throw new ArkmePluginError("bot-conversation-read-unsupported", "当前 Bot 会话不支持已读游标", false, 400);
|
|
5713
|
+
return await adapter.markRead(context, sequence, options.signal);
|
|
5714
|
+
}
|
|
5715
|
+
async notificationPreference(botRef, options = {}) {
|
|
5716
|
+
const context = await this.context(botRef);
|
|
5717
|
+
return await this.adapter(context).notificationPreference(context, options.signal);
|
|
5718
|
+
}
|
|
5719
|
+
async updateNotificationPreference(botRef, muted, options = {}) {
|
|
5720
|
+
const context = await this.context(botRef);
|
|
5721
|
+
return await this.adapter(context).updateNotificationPreference(context, muted, options.signal);
|
|
5722
|
+
}
|
|
5723
|
+
async context(botRef) {
|
|
5724
|
+
const session = await this.runtime.requireSession();
|
|
5725
|
+
const reference = await this.bot.openBotRef(botRef, session.userId);
|
|
5726
|
+
if (reference.target.kind === "unavailable") throw new ArkmePluginError("bot-conversation-owner-unavailable", "当前 Bot 会话归属信息不可用,请刷新后重试", false, 409);
|
|
5727
|
+
return {
|
|
5728
|
+
session,
|
|
5729
|
+
reference: {
|
|
5730
|
+
...reference,
|
|
5731
|
+
target: reference.target
|
|
5732
|
+
}
|
|
5733
|
+
};
|
|
5734
|
+
}
|
|
5735
|
+
adapter(context) {
|
|
5736
|
+
return context.reference.target.kind === "subject" ? this.subject : this.chatAdapter;
|
|
5737
|
+
}
|
|
5738
|
+
};
|
|
5739
|
+
//#endregion
|
|
5631
5740
|
//#region src/services/calendar-service.ts
|
|
5632
5741
|
const MAX_CALENDAR_RANGE_DAYS = 62;
|
|
5633
5742
|
const MAX_DAY_RECORD_LIMIT = 50;
|
|
5634
5743
|
function numberValue$18(value) {
|
|
5635
5744
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
5636
5745
|
}
|
|
5637
|
-
function booleanValue$
|
|
5746
|
+
function booleanValue$10(value) {
|
|
5638
5747
|
if (typeof value === "boolean") return value;
|
|
5639
5748
|
if (typeof value === "number") return value !== 0;
|
|
5640
5749
|
}
|
|
@@ -5681,7 +5790,7 @@ function sourceKind(raw) {
|
|
|
5681
5790
|
const chat = objectValue$1(raw.chat_core);
|
|
5682
5791
|
if (stringValue$1(topic.topic_uid).trim() !== "") return "topic";
|
|
5683
5792
|
if (stringValue$1(chat.chat_session_uid).trim() !== "") return "chat";
|
|
5684
|
-
if (booleanValue$
|
|
5793
|
+
if (booleanValue$10(raw.is_uncategorized) === true) return "self";
|
|
5685
5794
|
return "unknown";
|
|
5686
5795
|
}
|
|
5687
5796
|
var CalendarService = class {
|
|
@@ -5786,9 +5895,9 @@ var CalendarService = class {
|
|
|
5786
5895
|
const textContent = available ? clippedText(core.text_content, 4e3) : "";
|
|
5787
5896
|
const preview = title || clippedText(textContent, 160) || "无文字内容";
|
|
5788
5897
|
const topic = objectValue$1(item.topic_core);
|
|
5789
|
-
const isUncategorized = booleanValue$
|
|
5790
|
-
const hasManualEdit = booleanValue$
|
|
5791
|
-
const hasPolish = booleanValue$
|
|
5898
|
+
const isUncategorized = booleanValue$10(item.is_uncategorized);
|
|
5899
|
+
const hasManualEdit = booleanValue$10(core.has_manual_edit);
|
|
5900
|
+
const hasPolish = booleanValue$10(core.has_polish);
|
|
5792
5901
|
return {
|
|
5793
5902
|
recordUid,
|
|
5794
5903
|
sendAtMillis,
|
|
@@ -5821,7 +5930,7 @@ function numberValue$17(value) {
|
|
|
5821
5930
|
}
|
|
5822
5931
|
return 0;
|
|
5823
5932
|
}
|
|
5824
|
-
function booleanValue$
|
|
5933
|
+
function booleanValue$9(value) {
|
|
5825
5934
|
return value === true;
|
|
5826
5935
|
}
|
|
5827
5936
|
function firstValue(source, keys) {
|
|
@@ -6166,7 +6275,7 @@ var CallHistoryService = class {
|
|
|
6166
6275
|
});
|
|
6167
6276
|
const validItems = (await Promise.all(this.historyItems(raw).map(async (item) => await this.normalizeHistoryItem(item, session.userId)))).filter((item) => item !== void 0);
|
|
6168
6277
|
await this.attachPeerAvatars(validItems, session, signal);
|
|
6169
|
-
const hasMore = booleanValue$
|
|
6278
|
+
const hasMore = booleanValue$9(raw.has_more ?? raw.hasMore);
|
|
6170
6279
|
const nextCursor = firstString(raw, [
|
|
6171
6280
|
"next_cursor",
|
|
6172
6281
|
"nextCursor",
|
|
@@ -6501,8 +6610,8 @@ var CallHistoryService = class {
|
|
|
6501
6610
|
])),
|
|
6502
6611
|
...summaryText === "" ? {} : { summaryText },
|
|
6503
6612
|
...summaryUpdatedAtMillis > 0 ? { summaryUpdatedAtMillis } : {},
|
|
6504
|
-
transcriptPending: booleanValue$
|
|
6505
|
-
transcriptFailed: booleanValue$
|
|
6613
|
+
transcriptPending: booleanValue$9(raw.transcript_pending ?? raw.transcriptPending),
|
|
6614
|
+
transcriptFailed: booleanValue$9(raw.transcript_failed ?? raw.transcriptFailed),
|
|
6506
6615
|
...videoRecord === void 0 ? {} : { videoRecord },
|
|
6507
6616
|
participants,
|
|
6508
6617
|
transcriptSegments: this.transcriptSegments(raw).slice(0, 200)
|
|
@@ -7497,21 +7606,11 @@ const ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
|
7497
7606
|
const OFFICIAL_AUTHOR_USER_ID = 11;
|
|
7498
7607
|
const OFFICIAL_AUTHOR_FALLBACK_DISPLAY_NAME = "即我作者";
|
|
7499
7608
|
const MAX_MESSAGE_COPY_LINK_ITEMS = 100;
|
|
7500
|
-
const LINK_METADATA_MAX_BYTES = 128 * 1024;
|
|
7501
|
-
const LINK_METADATA_MAX_REDIRECTS = 3;
|
|
7502
7609
|
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;
|
|
7503
|
-
const HTML_ENTITY_MAP = {
|
|
7504
|
-
amp: "&",
|
|
7505
|
-
lt: "<",
|
|
7506
|
-
gt: ">",
|
|
7507
|
-
quot: "\"",
|
|
7508
|
-
apos: "'",
|
|
7509
|
-
nbsp: " "
|
|
7510
|
-
};
|
|
7511
7610
|
function numberValue$16(value) {
|
|
7512
7611
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
7513
7612
|
}
|
|
7514
|
-
function booleanValue$
|
|
7613
|
+
function booleanValue$8(value) {
|
|
7515
7614
|
return value === true;
|
|
7516
7615
|
}
|
|
7517
7616
|
function favoriteStickerPersistenceItem(item) {
|
|
@@ -7523,7 +7622,7 @@ function favoriteStickerPersistenceItem(item) {
|
|
|
7523
7622
|
mime_type: stringValue$1(item.mime_type).trim(),
|
|
7524
7623
|
file_kind: Math.trunc(numberValue$16(item.file_kind)),
|
|
7525
7624
|
file_type: Math.trunc(numberValue$16(item.file_type)),
|
|
7526
|
-
is_animated: booleanValue$
|
|
7625
|
+
is_animated: booleanValue$8(item.is_animated),
|
|
7527
7626
|
file_size: Math.max(0, Math.trunc(numberValue$16(item.file_size))),
|
|
7528
7627
|
file_create_at: Math.max(0, Math.trunc(numberValue$16(item.file_create_at))),
|
|
7529
7628
|
file_push_at: Math.max(0, Math.trunc(numberValue$16(item.file_push_at)))
|
|
@@ -7532,88 +7631,6 @@ function favoriteStickerPersistenceItem(item) {
|
|
|
7532
7631
|
function listValue$16(value) {
|
|
7533
7632
|
return Array.isArray(value) ? value : [];
|
|
7534
7633
|
}
|
|
7535
|
-
function htmlTextValue(value) {
|
|
7536
|
-
return value.replace(/<script[\s\S]*?<\/script>/giu, " ").replace(/<style[\s\S]*?<\/style>/giu, " ").replace(/<[^>]+>/gu, " ").replace(/&(#x[0-9a-f]+|#[0-9]+|[a-z]+);/giu, (_match, entity) => {
|
|
7537
|
-
const normalized = entity.toLowerCase();
|
|
7538
|
-
if (normalized.startsWith("#x")) {
|
|
7539
|
-
const code = Number.parseInt(normalized.slice(2), 16);
|
|
7540
|
-
return Number.isFinite(code) ? String.fromCodePoint(code) : " ";
|
|
7541
|
-
}
|
|
7542
|
-
if (normalized.startsWith("#")) {
|
|
7543
|
-
const code = Number.parseInt(normalized.slice(1), 10);
|
|
7544
|
-
return Number.isFinite(code) ? String.fromCodePoint(code) : " ";
|
|
7545
|
-
}
|
|
7546
|
-
return HTML_ENTITY_MAP[normalized] ?? " ";
|
|
7547
|
-
}).replace(/\s+/gu, " ").trim();
|
|
7548
|
-
}
|
|
7549
|
-
function firstHtmlMetaContent(html, key) {
|
|
7550
|
-
const escaped = key.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
7551
|
-
const patterns = [new RegExp(`<meta\\b(?=[^>]*(?:property|name)=["']${escaped}["'])(?=[^>]*content=["']([^"']*)["'])[^>]*>`, "iu"), new RegExp(`<meta\\b(?=[^>]*content=["']([^"']*)["'])(?=[^>]*(?:property|name)=["']${escaped}["'])[^>]*>`, "iu")];
|
|
7552
|
-
for (const pattern of patterns) {
|
|
7553
|
-
const value = pattern.exec(html)?.[1];
|
|
7554
|
-
if (value !== void 0) return htmlTextValue(value);
|
|
7555
|
-
}
|
|
7556
|
-
return "";
|
|
7557
|
-
}
|
|
7558
|
-
function fallbackLinkTitle(url) {
|
|
7559
|
-
const host = url.hostname.replace(/^www\./iu, "");
|
|
7560
|
-
if (host === "github.com") {
|
|
7561
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
7562
|
-
if (parts.length >= 4 && parts[2] === "pull") return `Pull Request #${parts[3]} · ${parts[0]}/${parts[1]}`;
|
|
7563
|
-
if (parts.length >= 2) return `${parts[0]}/${parts[1]}`;
|
|
7564
|
-
}
|
|
7565
|
-
if (host === "codeup.aliyun.com" || host.endsWith(".codeup.aliyun.com")) {
|
|
7566
|
-
const parts = url.pathname.split("/").filter(Boolean);
|
|
7567
|
-
const changeIndex = parts.indexOf("change");
|
|
7568
|
-
const repository = changeIndex >= 2 ? parts[changeIndex - 1] : parts.at(-1);
|
|
7569
|
-
const changeNo = changeIndex >= 0 ? parts[changeIndex + 1] : void 0;
|
|
7570
|
-
if (repository !== void 0 && changeNo !== void 0) return `${repository} · Change #${changeNo}`;
|
|
7571
|
-
}
|
|
7572
|
-
return "分享链接";
|
|
7573
|
-
}
|
|
7574
|
-
function ensureMetadataUrl(rawUrl) {
|
|
7575
|
-
let url;
|
|
7576
|
-
try {
|
|
7577
|
-
url = new URL(rawUrl.trim());
|
|
7578
|
-
} catch {
|
|
7579
|
-
throw new ArkmePluginError("link-metadata-url-invalid", "链接暂不可预览", false, 400);
|
|
7580
|
-
}
|
|
7581
|
-
if (url.protocol !== "http:" && url.protocol !== "https:") throw new ArkmePluginError("link-metadata-url-invalid", "链接暂不可预览", false, 400);
|
|
7582
|
-
if (url.username !== "" || url.password !== "") throw new ArkmePluginError("link-metadata-url-forbidden", "链接暂不可预览", false, 403);
|
|
7583
|
-
const hostname = url.hostname.toLowerCase();
|
|
7584
|
-
if (hostname === "localhost" || hostname.endsWith(".local")) throw new ArkmePluginError("link-metadata-url-forbidden", "链接暂不可预览", false, 403);
|
|
7585
|
-
if (/^(?:127|10|0|169\.254|192\.168)\./u.test(hostname) || /^172\.(?:1[6-9]|2\d|3[0-1])\./u.test(hostname)) throw new ArkmePluginError("link-metadata-url-forbidden", "链接暂不可预览", false, 403);
|
|
7586
|
-
if (hostname === "::1" || hostname.startsWith("fc") || hostname.startsWith("fd") || hostname.startsWith("fe80")) throw new ArkmePluginError("link-metadata-url-forbidden", "链接暂不可预览", false, 403);
|
|
7587
|
-
return url;
|
|
7588
|
-
}
|
|
7589
|
-
async function readResponseTextPrefix(response) {
|
|
7590
|
-
if (response.body === null) return await response.text();
|
|
7591
|
-
const reader = response.body.getReader();
|
|
7592
|
-
const chunks = [];
|
|
7593
|
-
let bytes = 0;
|
|
7594
|
-
try {
|
|
7595
|
-
while (bytes < LINK_METADATA_MAX_BYTES) {
|
|
7596
|
-
const next = await reader.read();
|
|
7597
|
-
if (next.done) break;
|
|
7598
|
-
chunks.push(next.value);
|
|
7599
|
-
bytes += next.value.byteLength;
|
|
7600
|
-
}
|
|
7601
|
-
} finally {
|
|
7602
|
-
reader.releaseLock();
|
|
7603
|
-
}
|
|
7604
|
-
return new TextDecoder("utf-8", { fatal: false }).decode(Uint8Array.from(chunks.flatMap((chunk) => [...chunk])));
|
|
7605
|
-
}
|
|
7606
|
-
function linkMetadataFromHtml(url, html) {
|
|
7607
|
-
const title = firstHtmlMetaContent(html, "og:title") || firstHtmlMetaContent(html, "twitter:title") || htmlTextValue(/<title\b[^>]*>([\s\S]*?)<\/title>/iu.exec(html)?.[1] ?? "") || fallbackLinkTitle(url);
|
|
7608
|
-
const description = firstHtmlMetaContent(html, "og:description") || firstHtmlMetaContent(html, "description");
|
|
7609
|
-
const siteName = firstHtmlMetaContent(html, "og:site_name") || url.hostname.replace(/^www\./iu, "");
|
|
7610
|
-
return {
|
|
7611
|
-
url: url.toString(),
|
|
7612
|
-
title,
|
|
7613
|
-
...description === "" ? {} : { description },
|
|
7614
|
-
...siteName === "" ? {} : { siteName }
|
|
7615
|
-
};
|
|
7616
|
-
}
|
|
7617
7634
|
function chatMemberRole$1(value) {
|
|
7618
7635
|
if (value === "owner" || value === 1) return "owner";
|
|
7619
7636
|
if (value === "admin" || value === 2) return "admin";
|
|
@@ -8027,7 +8044,7 @@ function selfTopicIdentityFromHomeFeed(raw) {
|
|
|
8027
8044
|
title
|
|
8028
8045
|
};
|
|
8029
8046
|
}
|
|
8030
|
-
function encodeOpaqueJson$
|
|
8047
|
+
function encodeOpaqueJson$6(value) {
|
|
8031
8048
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
8032
8049
|
}
|
|
8033
8050
|
function decodeOpaqueJson$5(value) {
|
|
@@ -8057,6 +8074,171 @@ var ChatService = class {
|
|
|
8057
8074
|
this.realtime = realtime;
|
|
8058
8075
|
this.privacy = privacy;
|
|
8059
8076
|
}
|
|
8077
|
+
async readDirectBotConversation(botId, chatSessionUid, options = {}) {
|
|
8078
|
+
const normalizedBotId = botId.trim();
|
|
8079
|
+
const normalizedSessionUid = chatSessionUid.trim();
|
|
8080
|
+
if (normalizedBotId === "" || normalizedSessionUid === "") throw new ArkmePluginError("bot-chat-target-invalid", "Bot Chat 会话目标无效", false, 400);
|
|
8081
|
+
const session = await this.runtime.requireSession();
|
|
8082
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chat/timeline/page", {
|
|
8083
|
+
chat_session_uid: normalizedSessionUid,
|
|
8084
|
+
before_seq: 0,
|
|
8085
|
+
limit: 100
|
|
8086
|
+
}, session, options.signal, {
|
|
8087
|
+
lane: "interactive-read",
|
|
8088
|
+
key: `bot-timeline:${normalizedSessionUid}`,
|
|
8089
|
+
failureCooldownMs: 2e3
|
|
8090
|
+
});
|
|
8091
|
+
if (stringValue$1(data.chat_session_uid).trim() !== normalizedSessionUid) throw new ArkmePluginError("bot-chat-timeline-contract-invalid", "Bot Chat 时间线返回了不匹配的会话", true, 502);
|
|
8092
|
+
const projected = [];
|
|
8093
|
+
let latestSequence = 0;
|
|
8094
|
+
for (const raw of listValue$16(data.items)) {
|
|
8095
|
+
const item = objectValue$1(raw);
|
|
8096
|
+
const relation = objectValue$1(item.relation);
|
|
8097
|
+
const record = objectValue$1(item.record);
|
|
8098
|
+
const payload = objectValue$1(record.payload);
|
|
8099
|
+
const relationUid = stringValue$1(relation.rel_uid).trim();
|
|
8100
|
+
const recordUid = stringValue$1(relation.record_uid).trim();
|
|
8101
|
+
const hydratedRecordUid = stringValue$1(payload.record_uid).trim();
|
|
8102
|
+
const sequence = Math.trunc(numberValue$16(relation.seq));
|
|
8103
|
+
const actorKind = Math.trunc(numberValue$16(relation.sender_actor_kind));
|
|
8104
|
+
const senderUserId = Math.trunc(numberValue$16(relation.sender_user_id));
|
|
8105
|
+
const senderBotUid = stringValue$1(relation.sender_bot_uid).trim();
|
|
8106
|
+
const userActor = actorKind === 1 && senderUserId === session.userId && senderBotUid === "";
|
|
8107
|
+
const botActor = actorKind === 2 && senderBotUid === normalizedBotId;
|
|
8108
|
+
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);
|
|
8109
|
+
latestSequence = Math.max(latestSequence, sequence);
|
|
8110
|
+
if (numberValue$16(record.status) !== 1) continue;
|
|
8111
|
+
const contentBlocks = this.media.richContentBlocks(item, session.userId);
|
|
8112
|
+
projected.push({
|
|
8113
|
+
messageId: relationUid,
|
|
8114
|
+
recordUid,
|
|
8115
|
+
role: userActor ? "user" : "assistant",
|
|
8116
|
+
content: stringValue$1(payload.text_content),
|
|
8117
|
+
status: "sent",
|
|
8118
|
+
createdAtMillis: Math.max(0, Math.trunc(numberValue$16(relation.attach_at ?? payload.send_at))),
|
|
8119
|
+
attachments: contentBlocks.map((block) => ({
|
|
8120
|
+
kind: block.kind,
|
|
8121
|
+
fileName: block.fileName,
|
|
8122
|
+
mimeType: block.mimeType,
|
|
8123
|
+
size: block.size,
|
|
8124
|
+
durationMillis: Math.max(0, Math.trunc((block.durationSec ?? 0) * 1e3)),
|
|
8125
|
+
width: 0,
|
|
8126
|
+
height: 0,
|
|
8127
|
+
sortOrder: block.sortOrder
|
|
8128
|
+
})),
|
|
8129
|
+
sequence
|
|
8130
|
+
});
|
|
8131
|
+
}
|
|
8132
|
+
projected.sort((left, right) => left.sequence - right.sequence || left.createdAtMillis - right.createdAtMillis || left.messageId.localeCompare(right.messageId));
|
|
8133
|
+
const seenRelationUids = /* @__PURE__ */ new Set();
|
|
8134
|
+
const messages = [];
|
|
8135
|
+
for (const item of projected) {
|
|
8136
|
+
if (seenRelationUids.has(item.messageId)) continue;
|
|
8137
|
+
seenRelationUids.add(item.messageId);
|
|
8138
|
+
const { sequence: _sequence, ...message } = item;
|
|
8139
|
+
messages.push(message);
|
|
8140
|
+
}
|
|
8141
|
+
return {
|
|
8142
|
+
messages,
|
|
8143
|
+
...latestSequence > 0 ? { latestSequence } : {}
|
|
8144
|
+
};
|
|
8145
|
+
}
|
|
8146
|
+
async sendDirectBotText(chatSessionUid, contentInput, options = {}) {
|
|
8147
|
+
const chatSessionUidValue = chatSessionUid.trim();
|
|
8148
|
+
const content = contentInput.trim();
|
|
8149
|
+
if (chatSessionUidValue === "" || content === "" || content.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("bot-conversation-content-invalid", "Bot 消息为空或超过长度限制", false, 400);
|
|
8150
|
+
const session = await this.runtime.requireSession();
|
|
8151
|
+
const recordUid = randomUUID();
|
|
8152
|
+
const relationUid = randomUUID();
|
|
8153
|
+
const sendAtMillis = Date.now();
|
|
8154
|
+
let result;
|
|
8155
|
+
try {
|
|
8156
|
+
result = await this.postChatTextRecord(chatSessionUidValue, content, recordUid, relationUid, sendAtMillis, session, options.signal);
|
|
8157
|
+
} catch (error) {
|
|
8158
|
+
if (error instanceof ArkmePluginError && (error.retryable || [
|
|
8159
|
+
"arkme-network-error",
|
|
8160
|
+
"arkme-timeout",
|
|
8161
|
+
"arkme-response-invalid"
|
|
8162
|
+
].includes(error.code))) throw new ArkmePluginError("bot-conversation-send-outcome-unknown", "消息发送结果未知,请刷新会话确认;不会自动重试", false, 409, { cause: error });
|
|
8163
|
+
throw error;
|
|
8164
|
+
}
|
|
8165
|
+
const responseSessionUid = stringValue$1(result.chat_session_uid).trim();
|
|
8166
|
+
const responseRecordUid = stringValue$1(result.record_uid).trim();
|
|
8167
|
+
const responseRelationUid = stringValue$1(result.rel_uid).trim();
|
|
8168
|
+
const sequence = Math.trunc(numberValue$16(result.seq));
|
|
8169
|
+
if (responseSessionUid !== chatSessionUidValue || responseRecordUid !== recordUid || responseRelationUid !== relationUid || !Number.isSafeInteger(sequence) || sequence <= 0) throw new ArkmePluginError("bot-conversation-send-outcome-unknown", "消息可能已发送,但服务端确认不完整;请刷新会话确认", false, 409);
|
|
8170
|
+
this.realtime.scheduleChatSessionProjection(chatSessionUidValue, sequence);
|
|
8171
|
+
return {
|
|
8172
|
+
userMessage: {
|
|
8173
|
+
messageId: responseRelationUid,
|
|
8174
|
+
recordUid: responseRecordUid,
|
|
8175
|
+
role: "user",
|
|
8176
|
+
content,
|
|
8177
|
+
status: "sent",
|
|
8178
|
+
createdAtMillis: sendAtMillis,
|
|
8179
|
+
attachments: []
|
|
8180
|
+
},
|
|
8181
|
+
botMessages: [],
|
|
8182
|
+
status: "ok"
|
|
8183
|
+
};
|
|
8184
|
+
}
|
|
8185
|
+
async directBotNotificationPreference(chatSessionUid, options = {}) {
|
|
8186
|
+
const { policy } = await this.directBotPolicy(chatSessionUid, options.signal);
|
|
8187
|
+
return { muted: numberValue$16(policy.mute_state) === 2 || numberValue$16(policy.notify_state) === 2 };
|
|
8188
|
+
}
|
|
8189
|
+
async updateDirectBotNotificationPreference(chatSessionUid, muted, options = {}) {
|
|
8190
|
+
const { session, sessionUid, policy } = await this.directBotPolicy(chatSessionUid, options.signal);
|
|
8191
|
+
const updateAt = Math.max(Date.now(), numberValue$16(policy.update_at) + 1);
|
|
8192
|
+
const updated = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/update", {
|
|
8193
|
+
chat_session_uid: sessionUid,
|
|
8194
|
+
show_in_home_state: numberValue$16(policy.show_in_home_state),
|
|
8195
|
+
privacy_state: numberValue$16(policy.privacy_state),
|
|
8196
|
+
mute_state: muted ? 2 : 1,
|
|
8197
|
+
pin_state: numberValue$16(policy.pin_state),
|
|
8198
|
+
notify_state: muted ? 2 : 1,
|
|
8199
|
+
status: numberValue$16(policy.status),
|
|
8200
|
+
update_at: updateAt
|
|
8201
|
+
}, session, options.signal);
|
|
8202
|
+
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);
|
|
8203
|
+
const cacheKey = `${String(session.userId)}:${sessionUid}`;
|
|
8204
|
+
const cached = this.source.cachedChatSourceByKey(cacheKey);
|
|
8205
|
+
if (cached !== void 0) this.source.setChatSourceByKey(cacheKey, {
|
|
8206
|
+
...cached,
|
|
8207
|
+
isMuted: muted
|
|
8208
|
+
});
|
|
8209
|
+
return { muted };
|
|
8210
|
+
}
|
|
8211
|
+
async markDirectBotRead(chatSessionUid, readSequence, options = {}) {
|
|
8212
|
+
const sessionUid = chatSessionUid.trim();
|
|
8213
|
+
if (sessionUid === "") throw new ArkmePluginError("bot-chat-target-invalid", "Bot Chat 会话目标无效", false, 400);
|
|
8214
|
+
const session = await this.runtime.requireSession();
|
|
8215
|
+
const sourceRef = await this.source.sealSourceRef(session.userId, "private_chat", sessionUid, "Bot");
|
|
8216
|
+
const result = await this.advanceChatReadCursor(sourceRef, sessionUid, readSequence, session, options.signal);
|
|
8217
|
+
return {
|
|
8218
|
+
effectiveReadSequence: result.effectiveReadSequence,
|
|
8219
|
+
unreadCount: result.unreadCount
|
|
8220
|
+
};
|
|
8221
|
+
}
|
|
8222
|
+
async directBotPolicy(chatSessionUid, signal) {
|
|
8223
|
+
const sessionUid = chatSessionUid.trim();
|
|
8224
|
+
if (sessionUid === "") throw new ArkmePluginError("bot-chat-target-invalid", "Bot Chat 会话目标无效", false, 400);
|
|
8225
|
+
const session = await this.runtime.requireSession();
|
|
8226
|
+
const policy = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: sessionUid }, session, signal);
|
|
8227
|
+
const updateAt = numberValue$16(policy.update_at);
|
|
8228
|
+
if (stringValue$1(policy.chat_session_uid).trim() !== sessionUid || numberValue$16(policy.user_id) !== session.userId || ![
|
|
8229
|
+
"show_in_home_state",
|
|
8230
|
+
"privacy_state",
|
|
8231
|
+
"mute_state",
|
|
8232
|
+
"pin_state",
|
|
8233
|
+
"notify_state",
|
|
8234
|
+
"status"
|
|
8235
|
+
].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);
|
|
8236
|
+
return {
|
|
8237
|
+
session,
|
|
8238
|
+
sessionUid,
|
|
8239
|
+
policy
|
|
8240
|
+
};
|
|
8241
|
+
}
|
|
8060
8242
|
async serializeFavoriteStickerMutation(work) {
|
|
8061
8243
|
const pending = this.favoriteStickerMutationTail.then(work);
|
|
8062
8244
|
this.favoriteStickerMutationTail = pending.then(() => void 0, () => void 0);
|
|
@@ -8181,7 +8363,7 @@ var ChatService = class {
|
|
|
8181
8363
|
}, session, options.signal);
|
|
8182
8364
|
const rmSubjectId = Math.trunc(numberValue$16(created.rm_subject_id));
|
|
8183
8365
|
if (!Number.isSafeInteger(rmSubjectId) || rmSubjectId <= 0) {
|
|
8184
|
-
if (booleanValue$
|
|
8366
|
+
if (booleanValue$8(created.already_exist)) throw new ArkmePluginError("private-chat-self-invalid", "不能给自己发起私聊", false, 409);
|
|
8185
8367
|
throw new ArkmePluginError("official-author-chat-contract-invalid", "联系作者私聊响应不完整", true, 502);
|
|
8186
8368
|
}
|
|
8187
8369
|
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);
|
|
@@ -8676,71 +8858,6 @@ var ChatService = class {
|
|
|
8676
8858
|
}
|
|
8677
8859
|
};
|
|
8678
8860
|
}
|
|
8679
|
-
async resolveLinkMetadata(rawUrl, options = {}) {
|
|
8680
|
-
const url = ensureMetadataUrl(rawUrl);
|
|
8681
|
-
try {
|
|
8682
|
-
return await this.fetchLinkMetadata(url, 0, options.signal);
|
|
8683
|
-
} catch (error) {
|
|
8684
|
-
if (error instanceof ArkmePluginError && (error.code === "link-metadata-url-invalid" || error.code === "link-metadata-url-forbidden")) throw error;
|
|
8685
|
-
return {
|
|
8686
|
-
url: url.toString(),
|
|
8687
|
-
title: fallbackLinkTitle(url),
|
|
8688
|
-
siteName: url.hostname.replace(/^www\./iu, "")
|
|
8689
|
-
};
|
|
8690
|
-
}
|
|
8691
|
-
}
|
|
8692
|
-
async fetchLinkMetadata(url, redirectCount, signal) {
|
|
8693
|
-
const controller = new AbortController();
|
|
8694
|
-
const abort = () => {
|
|
8695
|
-
controller.abort(signal?.reason);
|
|
8696
|
-
};
|
|
8697
|
-
if (signal?.aborted === true) abort();
|
|
8698
|
-
else signal?.addEventListener("abort", abort, { once: true });
|
|
8699
|
-
const timeout = setTimeout(() => {
|
|
8700
|
-
controller.abort();
|
|
8701
|
-
}, Math.min(8e3, this.runtime.config.requestTimeoutMs));
|
|
8702
|
-
try {
|
|
8703
|
-
const response = await this.runtime.fetchImpl(url, {
|
|
8704
|
-
method: "GET",
|
|
8705
|
-
redirect: "manual",
|
|
8706
|
-
headers: {
|
|
8707
|
-
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
|
|
8708
|
-
"Accept-Language": "zh-CN",
|
|
8709
|
-
"User-Agent": "Mozilla/5.0 ArkmeDSHPlugin/0.1 LinkPreview"
|
|
8710
|
-
},
|
|
8711
|
-
signal: controller.signal
|
|
8712
|
-
});
|
|
8713
|
-
if (response.status >= 300 && response.status < 400) {
|
|
8714
|
-
if (redirectCount >= LINK_METADATA_MAX_REDIRECTS) return {
|
|
8715
|
-
url: url.toString(),
|
|
8716
|
-
title: fallbackLinkTitle(url),
|
|
8717
|
-
siteName: url.hostname.replace(/^www\./iu, "")
|
|
8718
|
-
};
|
|
8719
|
-
const location = response.headers.get("location");
|
|
8720
|
-
if (location === null || location.trim() === "") return {
|
|
8721
|
-
url: url.toString(),
|
|
8722
|
-
title: fallbackLinkTitle(url),
|
|
8723
|
-
siteName: url.hostname.replace(/^www\./iu, "")
|
|
8724
|
-
};
|
|
8725
|
-
return await this.fetchLinkMetadata(ensureMetadataUrl(new URL(location, url).toString()), redirectCount + 1, signal);
|
|
8726
|
-
}
|
|
8727
|
-
if (!response.ok) return {
|
|
8728
|
-
url: url.toString(),
|
|
8729
|
-
title: fallbackLinkTitle(url),
|
|
8730
|
-
siteName: url.hostname.replace(/^www\./iu, "")
|
|
8731
|
-
};
|
|
8732
|
-
const contentType = response.headers.get("content-type")?.toLowerCase() ?? "";
|
|
8733
|
-
if (contentType !== "" && !contentType.includes("html") && !contentType.includes("xml") && !contentType.includes("text/")) return {
|
|
8734
|
-
url: url.toString(),
|
|
8735
|
-
title: fallbackLinkTitle(url),
|
|
8736
|
-
siteName: url.hostname.replace(/^www\./iu, "")
|
|
8737
|
-
};
|
|
8738
|
-
return linkMetadataFromHtml(url, await readResponseTextPrefix(response));
|
|
8739
|
-
} finally {
|
|
8740
|
-
clearTimeout(timeout);
|
|
8741
|
-
signal?.removeEventListener("abort", abort);
|
|
8742
|
-
}
|
|
8743
|
-
}
|
|
8744
8861
|
async forwardSourceMessages(sourceRef, actionRefs, options = {}) {
|
|
8745
8862
|
const session = await this.runtime.requireSession();
|
|
8746
8863
|
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
@@ -9066,20 +9183,14 @@ var ChatService = class {
|
|
|
9066
9183
|
bot_mentions: mentions
|
|
9067
9184
|
}
|
|
9068
9185
|
};
|
|
9069
|
-
return await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, visibleText, recordUid, relationUid, session, void 0, contentPayload, signal, options);
|
|
9070
|
-
}
|
|
9071
|
-
async sendChatSourceTextRaw(sourceRef, chatSessionUid, text, recordUid, relationUid, session, initialAiPolish, contentPayload, signal, options = {}) {
|
|
9072
|
-
const result = await this.
|
|
9073
|
-
|
|
9074
|
-
|
|
9075
|
-
|
|
9076
|
-
|
|
9077
|
-
text_content: text,
|
|
9078
|
-
...options.agentAuthored === true ? { creation_source: 1 } : {},
|
|
9079
|
-
...initialAiPolish === void 0 ? {} : { initial_ai_polish: initialAiPolish },
|
|
9080
|
-
...contentPayload === void 0 ? {} : { content_payload: contentPayload },
|
|
9081
|
-
send_at: Date.now()
|
|
9082
|
-
}, session, signal);
|
|
9186
|
+
return await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, visibleText, recordUid, relationUid, session, void 0, contentPayload, signal, options);
|
|
9187
|
+
}
|
|
9188
|
+
async sendChatSourceTextRaw(sourceRef, chatSessionUid, text, recordUid, relationUid, session, initialAiPolish, contentPayload, signal, options = {}) {
|
|
9189
|
+
const result = await this.postChatTextRecord(chatSessionUid, text, recordUid, relationUid, Date.now(), session, signal, {
|
|
9190
|
+
...options,
|
|
9191
|
+
...initialAiPolish === void 0 ? {} : { initialAiPolish },
|
|
9192
|
+
...contentPayload === void 0 ? {} : { contentPayload }
|
|
9193
|
+
});
|
|
9083
9194
|
const sequence = numberValue$16(result.seq);
|
|
9084
9195
|
this.realtime.scheduleChatSessionProjection(chatSessionUid, sequence);
|
|
9085
9196
|
return {
|
|
@@ -9090,6 +9201,19 @@ var ChatService = class {
|
|
|
9090
9201
|
localState: "synced"
|
|
9091
9202
|
};
|
|
9092
9203
|
}
|
|
9204
|
+
async postChatTextRecord(chatSessionUid, text, recordUid, relationUid, sendAtMillis, session, signal, options = {}) {
|
|
9205
|
+
return await this.runtime.authenticatedChatPost("/api/v1/chats/records/send", {
|
|
9206
|
+
chat_session_uid: chatSessionUid,
|
|
9207
|
+
record_uid: recordUid,
|
|
9208
|
+
rel_uid: relationUid,
|
|
9209
|
+
template_kind: 1,
|
|
9210
|
+
text_content: text,
|
|
9211
|
+
...options.agentAuthored === true ? { creation_source: 1 } : {},
|
|
9212
|
+
...options.initialAiPolish === void 0 ? {} : { initial_ai_polish: options.initialAiPolish },
|
|
9213
|
+
...options.contentPayload === void 0 ? {} : { content_payload: options.contentPayload },
|
|
9214
|
+
send_at: sendAtMillis
|
|
9215
|
+
}, session, signal);
|
|
9216
|
+
}
|
|
9093
9217
|
async sendSourceRich(sourceRef, input, options = {}) {
|
|
9094
9218
|
if (this.runtime.config.richMediaSendEnabled === false) throw new ArkmePluginError("rich-content-disabled", "富内容发送已被插件配置关闭", false, 403);
|
|
9095
9219
|
const session = await this.runtime.requireSession();
|
|
@@ -9208,7 +9332,7 @@ var ChatService = class {
|
|
|
9208
9332
|
mimeType,
|
|
9209
9333
|
size: Math.max(0, Math.trunc(numberValue$16(raw.file_size ?? raw.size))),
|
|
9210
9334
|
fileKind: 1,
|
|
9211
|
-
isAnimated: booleanValue$
|
|
9335
|
+
isAnimated: booleanValue$8(raw.is_animated) || mimeType.toLowerCase() === "image/gif",
|
|
9212
9336
|
isAvailable: serverAvailable && mediaRef !== void 0,
|
|
9213
9337
|
...mediaRef === void 0 ? {} : { mediaRef },
|
|
9214
9338
|
...!serverAvailable || mediaRef === void 0 ? { unavailableReason: stringValue$1(raw.unavailable_reason).trim() || "表情已不可用" } : {}
|
|
@@ -9362,21 +9486,26 @@ var ChatService = class {
|
|
|
9362
9486
|
const session = await this.runtime.requireSession();
|
|
9363
9487
|
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
9364
9488
|
if (source.kind !== "private_chat" && source.kind !== "group_chat") throw new ArkmePluginError("source-read-unsupported", "当前数据源不支持聊天已读", false);
|
|
9489
|
+
if (!Number.isSafeInteger(readSequence) || readSequence <= 0) throw new ArkmePluginError("source-read-sequence-invalid", "聊天已读游标无效", false);
|
|
9490
|
+
return await this.advanceChatReadCursor(sourceRef, source.ownerRef, readSequence, session, options.signal);
|
|
9491
|
+
}
|
|
9492
|
+
async advanceChatReadCursor(sourceRef, chatSessionUid, readSequence, session, signal) {
|
|
9365
9493
|
if (!Number.isSafeInteger(readSequence) || readSequence <= 0) throw new ArkmePluginError("source-read-sequence-invalid", "聊天已读游标无效", false);
|
|
9366
9494
|
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/cursor/update", {
|
|
9367
|
-
chat_session_uid:
|
|
9495
|
+
chat_session_uid: chatSessionUid,
|
|
9368
9496
|
read_seq: readSequence,
|
|
9369
9497
|
read_at: Date.now(),
|
|
9370
9498
|
client_ack_id: randomUUID(),
|
|
9371
9499
|
reason: "arkme_dsh_open_chat"
|
|
9372
|
-
}, session,
|
|
9500
|
+
}, session, signal);
|
|
9373
9501
|
const responseSessionUid = stringValue$1(data.chat_session_uid).trim();
|
|
9502
|
+
const responseUserId = numberValue$16(data.user_id);
|
|
9374
9503
|
const effectiveReadSequence = numberValue$16(data.effective_read_seq);
|
|
9375
9504
|
const readAt = numberValue$16(data.read_at);
|
|
9376
9505
|
const sessionLastSequence = numberValue$16(data.session_last_seq);
|
|
9377
9506
|
const unreadCount = numberValue$16(data.unread_count);
|
|
9378
|
-
if (responseSessionUid !==
|
|
9379
|
-
const cacheKey = `${String(session.userId)}:${
|
|
9507
|
+
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);
|
|
9508
|
+
const cacheKey = `${String(session.userId)}:${chatSessionUid}`;
|
|
9380
9509
|
const cached = this.source.cachedChatSourceByKey(cacheKey);
|
|
9381
9510
|
if (cached !== void 0) this.source.setChatSourceByKey(cacheKey, {
|
|
9382
9511
|
...cached,
|
|
@@ -9387,11 +9516,11 @@ var ChatService = class {
|
|
|
9387
9516
|
type: "read-ack",
|
|
9388
9517
|
revision: this.realtime.nextChatClientRevision(),
|
|
9389
9518
|
sourceRef,
|
|
9390
|
-
sourceKey: await this.source.chatDirectorySourceKey(session.userId,
|
|
9519
|
+
sourceKey: await this.source.chatDirectorySourceKey(session.userId, chatSessionUid),
|
|
9391
9520
|
effectiveReadSequence,
|
|
9392
9521
|
unreadCount
|
|
9393
9522
|
});
|
|
9394
|
-
this.realtime.scheduleChatSessionProjection(
|
|
9523
|
+
this.realtime.scheduleChatSessionProjection(chatSessionUid, sessionLastSequence);
|
|
9395
9524
|
return {
|
|
9396
9525
|
sourceRef,
|
|
9397
9526
|
effectiveReadSequence,
|
|
@@ -9403,6 +9532,7 @@ var ChatService = class {
|
|
|
9403
9532
|
}
|
|
9404
9533
|
async chatTimelineItems(data, session, chatSessionUid) {
|
|
9405
9534
|
const items = [];
|
|
9535
|
+
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
9406
9536
|
for (const raw of listValue$16(data.items)) {
|
|
9407
9537
|
const item = objectValue$1(raw);
|
|
9408
9538
|
const relation = objectValue$1(item.relation);
|
|
@@ -9411,9 +9541,20 @@ var ChatService = class {
|
|
|
9411
9541
|
const uid = stringValue$1(relation.record_uid ?? payload.record_uid).trim();
|
|
9412
9542
|
if (uid === "") continue;
|
|
9413
9543
|
const senderUserId = numberValue$16(relation.sender_user_id);
|
|
9544
|
+
const relationUid = stringValue$1(relation.rel_uid ?? relation.relUid).trim();
|
|
9414
9545
|
const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
|
|
9415
9546
|
const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
|
|
9416
9547
|
const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
|
|
9548
|
+
const sharedRecording = this.withSharedRecordingDetailRef(this.chatSharedRecordingPreview(item), {
|
|
9549
|
+
viewerUserId: session.userId,
|
|
9550
|
+
chatSessionUid,
|
|
9551
|
+
relationUid,
|
|
9552
|
+
recordOwnerUserId: integerLikeValue$1(record.record_owner_user_id ?? record.recordOwnerUserId ?? payload.record_owner_user_id ?? payload.recordOwnerUserId ?? relation.record_owner_user_id ?? relation.recordOwnerUserId),
|
|
9553
|
+
recordUid: uid,
|
|
9554
|
+
senderUserId: integerLikeValue$1(relation.sender_user_id),
|
|
9555
|
+
sequence: integerLikeValue$1(relation.seq),
|
|
9556
|
+
signingKey
|
|
9557
|
+
});
|
|
9417
9558
|
const rawAgentSource = timelineAgentSource(relation, record, payload);
|
|
9418
9559
|
const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
|
|
9419
9560
|
const contentBlocks = this.media.richContentBlocks(item, session.userId);
|
|
@@ -9434,6 +9575,7 @@ var ChatService = class {
|
|
|
9434
9575
|
...numberValue$16(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$16(record.version ?? payload.version) } : {},
|
|
9435
9576
|
...aiPolish === void 0 ? {} : { aiPolish },
|
|
9436
9577
|
...forwardRecords === void 0 ? {} : { forwardRecords },
|
|
9578
|
+
...sharedRecording === void 0 ? {} : { sharedRecording },
|
|
9437
9579
|
displayKind: numberValue$16(payload.display_kind),
|
|
9438
9580
|
contentBlocks
|
|
9439
9581
|
});
|
|
@@ -9539,6 +9681,203 @@ var ChatService = class {
|
|
|
9539
9681
|
...truncated ? { truncated: true } : {}
|
|
9540
9682
|
};
|
|
9541
9683
|
}
|
|
9684
|
+
chatSharedRecordingPreview(raw) {
|
|
9685
|
+
const contentPayload = this.media.recordContentPayload(raw);
|
|
9686
|
+
const direct = this.sharedRecordingPreviewFromPayload(contentPayload);
|
|
9687
|
+
if (direct !== void 0) return direct;
|
|
9688
|
+
const root = objectValue$1(raw);
|
|
9689
|
+
const relation = objectValue$1(root.relation);
|
|
9690
|
+
const relationPayload = parsedObject(relation.render_content_payload ?? relation.renderContentPayload ?? root.render_content_payload ?? root.renderContentPayload);
|
|
9691
|
+
const relationDirect = this.sharedRecordingPreviewFromPayload(relationPayload);
|
|
9692
|
+
if (relationDirect !== void 0) return relationDirect;
|
|
9693
|
+
if (stringValue$1(relationPayload.render_kind ?? relationPayload.renderKind).trim() !== "shared_recording_memory") return void 0;
|
|
9694
|
+
const record = objectValue$1(root.record);
|
|
9695
|
+
const recordPayload = parsedObject(record.payload);
|
|
9696
|
+
const candidates = [
|
|
9697
|
+
contentPayload,
|
|
9698
|
+
recordPayload,
|
|
9699
|
+
parsedObject(recordPayload.content_payload ?? recordPayload.contentPayload),
|
|
9700
|
+
parsedObject(record.content_payload ?? record.contentPayload),
|
|
9701
|
+
parsedObject(root.payload),
|
|
9702
|
+
parsedObject(root.content_payload ?? root.contentPayload)
|
|
9703
|
+
];
|
|
9704
|
+
for (const candidate of candidates) {
|
|
9705
|
+
const body = objectValue$1(candidate.shared_recording ?? candidate.sharedRecording);
|
|
9706
|
+
const payload = Object.keys(body).length === 0 ? candidate : body;
|
|
9707
|
+
if (!this.sharedRecordingSourceDigestCompatible(payload, relationPayload)) continue;
|
|
9708
|
+
const projection = this.sharedRecordingPreviewFromPayload({
|
|
9709
|
+
...payload,
|
|
9710
|
+
...relationPayload,
|
|
9711
|
+
render_kind: "shared_recording_memory"
|
|
9712
|
+
});
|
|
9713
|
+
if (projection !== void 0) return projection;
|
|
9714
|
+
}
|
|
9715
|
+
}
|
|
9716
|
+
sharedRecordingParticipantsFromPayload(payload) {
|
|
9717
|
+
const participants = listValue$16(payload.participants);
|
|
9718
|
+
const mobileParticipants = listValue$16(payload.participant_ls ?? payload.participantLs);
|
|
9719
|
+
const speakers = listValue$16(payload.speaker_ls ?? payload.speakerLs ?? payload.speakers);
|
|
9720
|
+
return (participants.length > 0 ? participants : mobileParticipants.length > 0 ? mobileParticipants : speakers).flatMap((value) => {
|
|
9721
|
+
if (typeof value === "string") {
|
|
9722
|
+
const displayName = value.trim();
|
|
9723
|
+
return displayName === "" ? [] : [{
|
|
9724
|
+
displayName,
|
|
9725
|
+
role: 0
|
|
9726
|
+
}];
|
|
9727
|
+
}
|
|
9728
|
+
const participant = objectValue$1(value);
|
|
9729
|
+
const displayName = stringValue$1(participant.display_name ?? participant.displayName ?? participant.nick_name ?? participant.nickName ?? participant.speaker_name ?? participant.speakerName ?? participant.name).trim();
|
|
9730
|
+
if (displayName === "") return [];
|
|
9731
|
+
const refUserId = integerLikeValue$1(participant.ref_user_id ?? participant.refUserId ?? participant.ref_usr_id ?? participant.refUsrId);
|
|
9732
|
+
return [{
|
|
9733
|
+
...refUserId > 0 ? { refUserId } : {},
|
|
9734
|
+
displayName,
|
|
9735
|
+
role: Math.max(0, integerLikeValue$1(participant.role))
|
|
9736
|
+
}];
|
|
9737
|
+
});
|
|
9738
|
+
}
|
|
9739
|
+
sharedRecordingTranscriptFromPayload(payload) {
|
|
9740
|
+
const direct = stringValue$1(payload.transcript ?? payload.transcript_text ?? payload.transcriptText ?? payload.original_text ?? payload.originalText).trim();
|
|
9741
|
+
if (direct !== "") return direct;
|
|
9742
|
+
for (const key of [
|
|
9743
|
+
"transcript_ls",
|
|
9744
|
+
"transcriptLs",
|
|
9745
|
+
"transcript_segments",
|
|
9746
|
+
"transcriptSegments",
|
|
9747
|
+
"asr_ls",
|
|
9748
|
+
"asrLs"
|
|
9749
|
+
]) {
|
|
9750
|
+
const lines = listValue$16(payload[key]).flatMap((value) => {
|
|
9751
|
+
if (typeof value === "string") {
|
|
9752
|
+
const line = value.trim();
|
|
9753
|
+
return line === "" ? [] : [line];
|
|
9754
|
+
}
|
|
9755
|
+
const segment = objectValue$1(value);
|
|
9756
|
+
const text = stringValue$1(segment.text ?? segment.text_content ?? segment.textContent ?? segment.transcript ?? segment.content).trim();
|
|
9757
|
+
if (text === "") return [];
|
|
9758
|
+
const speakerName = stringValue$1(segment.speaker_name ?? segment.speakerName ?? segment.speaker_label ?? segment.speakerLabel ?? segment.nick_name ?? segment.nickName ?? segment.display_name ?? segment.displayName).trim();
|
|
9759
|
+
return [speakerName === "" ? text : `${speakerName}:${text}`];
|
|
9760
|
+
});
|
|
9761
|
+
if (lines.length > 0) return lines.join("\n");
|
|
9762
|
+
}
|
|
9763
|
+
return "";
|
|
9764
|
+
}
|
|
9765
|
+
sharedRecordingPreviewFromPayload(payload, depth = 0) {
|
|
9766
|
+
const renderKind = stringValue$1(payload.render_kind ?? payload.renderKind).trim();
|
|
9767
|
+
if (renderKind === "shared_recording_memory") {
|
|
9768
|
+
const sourceDigest = stringValue$1(payload.source_digest ?? payload.sourceDigest).trim();
|
|
9769
|
+
const title = stringValue$1(payload.title ?? payload.orig_name ?? payload.origName).trim();
|
|
9770
|
+
const summary = stringValue$1(payload.summary ?? payload.summary_text ?? payload.summaryText ?? payload.content_summary ?? payload.contentSummary).trim();
|
|
9771
|
+
const displayAtMillis = integerLikeValue$1(payload.display_at ?? payload.displayAt);
|
|
9772
|
+
if (sourceDigest === "" || title === "" || summary === "" || displayAtMillis <= 0) return void 0;
|
|
9773
|
+
const transcript = this.sharedRecordingTranscriptFromPayload(payload);
|
|
9774
|
+
return {
|
|
9775
|
+
sourceDigest,
|
|
9776
|
+
sharedByUserId: Math.max(0, integerLikeValue$1(payload.shared_by_user_id ?? payload.sharedByUserId)),
|
|
9777
|
+
sharedAtMillis: Math.max(0, integerLikeValue$1(payload.shared_at ?? payload.sharedAt)),
|
|
9778
|
+
displayAtMillis,
|
|
9779
|
+
endAtMillis: Math.max(0, integerLikeValue$1(payload.end_at ?? payload.endAt)),
|
|
9780
|
+
timeRangeText: stringValue$1(payload.time_range_text ?? payload.timeRangeText).trim(),
|
|
9781
|
+
title,
|
|
9782
|
+
summary,
|
|
9783
|
+
...transcript === "" ? {} : { transcript },
|
|
9784
|
+
transcriptAvailable: transcript !== "",
|
|
9785
|
+
participants: this.sharedRecordingParticipantsFromPayload(payload)
|
|
9786
|
+
};
|
|
9787
|
+
}
|
|
9788
|
+
if (renderKind !== "" || depth >= 4) return void 0;
|
|
9789
|
+
for (const key of [
|
|
9790
|
+
"shared_recording",
|
|
9791
|
+
"sharedRecording",
|
|
9792
|
+
"content_payload",
|
|
9793
|
+
"contentPayload",
|
|
9794
|
+
"record_payload",
|
|
9795
|
+
"recordPayload",
|
|
9796
|
+
"fallback_content_payload",
|
|
9797
|
+
"fallbackContentPayload",
|
|
9798
|
+
"payload",
|
|
9799
|
+
"extra"
|
|
9800
|
+
]) {
|
|
9801
|
+
const nested = parsedObject(payload[key]);
|
|
9802
|
+
if (Object.keys(nested).length === 0) continue;
|
|
9803
|
+
const projection = this.sharedRecordingPreviewFromPayload(nested, depth + 1);
|
|
9804
|
+
if (projection !== void 0) return projection;
|
|
9805
|
+
}
|
|
9806
|
+
}
|
|
9807
|
+
sharedRecordingSourceDigestCompatible(left, right) {
|
|
9808
|
+
const leftDigest = stringValue$1(left.source_digest ?? left.sourceDigest).trim();
|
|
9809
|
+
const rightDigest = stringValue$1(right.source_digest ?? right.sourceDigest).trim();
|
|
9810
|
+
return leftDigest === "" || rightDigest === "" || leftDigest === rightDigest;
|
|
9811
|
+
}
|
|
9812
|
+
withSharedRecordingDetailRef(recording, input) {
|
|
9813
|
+
if (recording === void 0) return void 0;
|
|
9814
|
+
const recordUid = input.recordUid.trim();
|
|
9815
|
+
const recordOwnerUserId = input.recordOwnerUserId > 0 ? input.recordOwnerUserId : recording.sharedByUserId > 0 ? recording.sharedByUserId : input.senderUserId;
|
|
9816
|
+
const chatSessionUid = input.chatSessionUid.trim();
|
|
9817
|
+
if (chatSessionUid === "" || recordUid === "" || recordOwnerUserId <= 0) return recording;
|
|
9818
|
+
return {
|
|
9819
|
+
...recording,
|
|
9820
|
+
detailRef: this.sealSharedRecordingDetailRef({
|
|
9821
|
+
version: 1,
|
|
9822
|
+
viewerUserId: input.viewerUserId,
|
|
9823
|
+
chatSessionUid,
|
|
9824
|
+
relationUid: input.relationUid.trim(),
|
|
9825
|
+
recordOwnerUserId: Math.trunc(recordOwnerUserId),
|
|
9826
|
+
recordUid,
|
|
9827
|
+
sequence: Math.max(0, Math.trunc(input.sequence))
|
|
9828
|
+
}, input.signingKey)
|
|
9829
|
+
};
|
|
9830
|
+
}
|
|
9831
|
+
sealSharedRecordingDetailRef(payload, signingKey) {
|
|
9832
|
+
const encoded = encodeOpaqueJson$6(payload);
|
|
9833
|
+
return `arkme-shared-recording-detail-v1.${encoded}.${createHmac("sha256", signingKey).update(encoded).digest("base64url")}`;
|
|
9834
|
+
}
|
|
9835
|
+
async openSharedRecordingDetailRef(detailRef, expectedViewerUserId) {
|
|
9836
|
+
const parts = detailRef.trim().split(".");
|
|
9837
|
+
if (parts.length !== 3 || parts[0] !== "arkme-shared-recording-detail-v1") throw new ArkmePluginError("shared-recording-detail-ref-invalid", "共享录音详情引用无效,请刷新后重试", false);
|
|
9838
|
+
const encoded = parts[1] ?? "";
|
|
9839
|
+
const supplied = Buffer.from(parts[2] ?? "", "base64url");
|
|
9840
|
+
const expected = createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(encoded).digest();
|
|
9841
|
+
if (supplied.length !== expected.length || !timingSafeEqual(supplied, expected)) throw new ArkmePluginError("shared-recording-detail-ref-invalid", "共享录音详情引用无效,请刷新后重试", false);
|
|
9842
|
+
let parsed;
|
|
9843
|
+
try {
|
|
9844
|
+
parsed = objectValue$1(decodeOpaqueJson$5(encoded));
|
|
9845
|
+
} catch (error) {
|
|
9846
|
+
throw new ArkmePluginError("shared-recording-detail-ref-invalid", "共享录音详情引用无效,请刷新后重试", false, 400, { cause: error });
|
|
9847
|
+
}
|
|
9848
|
+
const result = {
|
|
9849
|
+
version: 1,
|
|
9850
|
+
viewerUserId: integerLikeValue$1(parsed.viewerUserId),
|
|
9851
|
+
chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
|
|
9852
|
+
relationUid: stringValue$1(parsed.relationUid).trim(),
|
|
9853
|
+
recordOwnerUserId: integerLikeValue$1(parsed.recordOwnerUserId),
|
|
9854
|
+
recordUid: stringValue$1(parsed.recordUid).trim(),
|
|
9855
|
+
sequence: Math.max(0, integerLikeValue$1(parsed.sequence))
|
|
9856
|
+
};
|
|
9857
|
+
if (parsed.version !== 1 || result.viewerUserId !== expectedViewerUserId || result.chatSessionUid === "" || result.recordUid === "" || result.recordOwnerUserId <= 0) throw new ArkmePluginError("shared-recording-detail-ref-invalid", "共享录音详情引用与当前账号不匹配,请刷新后重试", false, 403);
|
|
9858
|
+
return result;
|
|
9859
|
+
}
|
|
9860
|
+
async sharedRecordingDetail(detailRef, options = {}) {
|
|
9861
|
+
const session = await this.runtime.requireSession();
|
|
9862
|
+
const reference = await this.openSharedRecordingDetailRef(detailRef, session.userId);
|
|
9863
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/records/detail", {
|
|
9864
|
+
chat_session_uid: reference.chatSessionUid,
|
|
9865
|
+
record_uid: reference.recordUid,
|
|
9866
|
+
record_owner_user_id: reference.recordOwnerUserId,
|
|
9867
|
+
...reference.relationUid === "" ? {} : { rel_uid: reference.relationUid },
|
|
9868
|
+
...reference.sequence <= 0 ? {} : { seq: reference.sequence }
|
|
9869
|
+
}, session, options.signal, {
|
|
9870
|
+
lane: "interactive-read",
|
|
9871
|
+
key: `shared-recording-detail:${reference.chatSessionUid}:${reference.recordUid}:${String(reference.sequence)}`,
|
|
9872
|
+
failureCooldownMs: 2e3
|
|
9873
|
+
});
|
|
9874
|
+
const projection = this.chatSharedRecordingPreview(objectValue$1(data.item)) ?? this.chatSharedRecordingPreview(data);
|
|
9875
|
+
if (projection === void 0) throw new ArkmePluginError("shared-recording-detail-unavailable", "共享录音详情暂时无法读取,请稍后重试", true, 502);
|
|
9876
|
+
return {
|
|
9877
|
+
...projection,
|
|
9878
|
+
detailRef
|
|
9879
|
+
};
|
|
9880
|
+
}
|
|
9542
9881
|
async rawChatMembers(chatSessionUid, activeOnly, session, signal) {
|
|
9543
9882
|
return listValue$16((await this.runtime.authenticatedChatPost("/api/v1/chats/members/list", {
|
|
9544
9883
|
chat_session_uid: chatSessionUid,
|
|
@@ -9603,6 +9942,16 @@ var ChatService = class {
|
|
|
9603
9942
|
const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
|
|
9604
9943
|
const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
|
|
9605
9944
|
const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
|
|
9945
|
+
const sharedRecording = this.withSharedRecordingDetailRef(this.chatSharedRecordingPreview(item), {
|
|
9946
|
+
viewerUserId: session.userId,
|
|
9947
|
+
chatSessionUid: source.ownerRef,
|
|
9948
|
+
relationUid,
|
|
9949
|
+
recordOwnerUserId: integerLikeValue$1(record.record_owner_user_id ?? record.recordOwnerUserId ?? payload.record_owner_user_id ?? payload.recordOwnerUserId ?? relation.record_owner_user_id ?? relation.recordOwnerUserId),
|
|
9950
|
+
recordUid: uid,
|
|
9951
|
+
senderUserId,
|
|
9952
|
+
sequence: integerLikeValue$1(relation.seq),
|
|
9953
|
+
signingKey
|
|
9954
|
+
});
|
|
9606
9955
|
const rawAgentSource = timelineAgentSource(relation, record, payload);
|
|
9607
9956
|
const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
|
|
9608
9957
|
const contentBlocks = this.media.richContentBlocks(item, session.userId);
|
|
@@ -9646,7 +9995,8 @@ var ChatService = class {
|
|
|
9646
9995
|
recordDurationMillis: numberValue$16(payload.record_duration_millis),
|
|
9647
9996
|
editDurationMillis: numberValue$16(payload.edit_duration_millis),
|
|
9648
9997
|
contentBlocks,
|
|
9649
|
-
...forwardRecords === void 0 ? {} : { forwardRecords }
|
|
9998
|
+
...forwardRecords === void 0 ? {} : { forwardRecords },
|
|
9999
|
+
...sharedRecording === void 0 ? {} : { sharedRecording }
|
|
9650
10000
|
}) - 1;
|
|
9651
10001
|
if (senderUserId > 0) senderUserIdByIndex.set(itemIndex, senderUserId);
|
|
9652
10002
|
}
|
|
@@ -9660,7 +10010,7 @@ var ChatService = class {
|
|
|
9660
10010
|
return items;
|
|
9661
10011
|
}
|
|
9662
10012
|
async sealChatMemberRef(viewerUserId, chatSessionUid, targetUserId) {
|
|
9663
|
-
const encoded = encodeOpaqueJson$
|
|
10013
|
+
const encoded = encodeOpaqueJson$6({
|
|
9664
10014
|
version: 1,
|
|
9665
10015
|
viewerUserId,
|
|
9666
10016
|
chatSessionUid,
|
|
@@ -9740,7 +10090,7 @@ var ChatService = class {
|
|
|
9740
10090
|
};
|
|
9741
10091
|
}
|
|
9742
10092
|
sealMessageActionRef(payload, signingKey) {
|
|
9743
|
-
const encoded = encodeOpaqueJson$
|
|
10093
|
+
const encoded = encodeOpaqueJson$6(payload);
|
|
9744
10094
|
return `arkme-message-action-v1.${encoded}.${createHmac("sha256", signingKey).update(encoded).digest("base64url")}`;
|
|
9745
10095
|
}
|
|
9746
10096
|
async openMessageActionRefs(actionRefs, expectedUserId, source) {
|
|
@@ -9861,7 +10211,7 @@ var ChatService = class {
|
|
|
9861
10211
|
};
|
|
9862
10212
|
}
|
|
9863
10213
|
sealMessageRef(userId, chatSessionUid, relationUid, signingKey) {
|
|
9864
|
-
const payload = encodeOpaqueJson$
|
|
10214
|
+
const payload = encodeOpaqueJson$6({
|
|
9865
10215
|
version: 1,
|
|
9866
10216
|
userId,
|
|
9867
10217
|
chatSessionUid,
|
|
@@ -9901,7 +10251,7 @@ function numberValue$15(value) {
|
|
|
9901
10251
|
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
|
|
9902
10252
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
9903
10253
|
}
|
|
9904
|
-
function booleanValue$
|
|
10254
|
+
function booleanValue$7(value) {
|
|
9905
10255
|
return value === true;
|
|
9906
10256
|
}
|
|
9907
10257
|
function normalizeIdentifier(value) {
|
|
@@ -10032,9 +10382,9 @@ var ContactService = class {
|
|
|
10032
10382
|
bypassCache: true
|
|
10033
10383
|
});
|
|
10034
10384
|
const targetUserId = Math.trunc(numberValue$15(data.user_id));
|
|
10035
|
-
const registered = booleanValue$
|
|
10036
|
-
const isSelf = booleanValue$
|
|
10037
|
-
const canAdd = booleanValue$
|
|
10385
|
+
const registered = booleanValue$7(data.is_registered) && targetUserId > 0;
|
|
10386
|
+
const isSelf = booleanValue$7(data.is_self);
|
|
10387
|
+
const canAdd = booleanValue$7(data.can_add) && !isSelf && (normalized.kind === "phone" || registered);
|
|
10038
10388
|
const displayName = stringValue$1(data.nick_name).trim() || stringValue$1(data.jotmo_id).trim() || (normalized.kind === "phone" ? `+${normalized.phonePre} ${normalized.identifier}` : normalized.identifier);
|
|
10039
10389
|
const result = {
|
|
10040
10390
|
contactRef,
|
|
@@ -10043,7 +10393,7 @@ var ContactService = class {
|
|
|
10043
10393
|
...stringValue$1(data.jotmo_id).trim() === "" ? {} : { arkmeId: stringValue$1(data.jotmo_id).trim() },
|
|
10044
10394
|
...registered ? { avatarRef: await this.profile.sealProfileImageRef(session.userId, targetUserId) } : {},
|
|
10045
10395
|
registered,
|
|
10046
|
-
inviteBySms: booleanValue$
|
|
10396
|
+
inviteBySms: booleanValue$7(data.invite_by_sms),
|
|
10047
10397
|
canAdd,
|
|
10048
10398
|
isSelf
|
|
10049
10399
|
};
|
|
@@ -10235,10 +10585,9 @@ var ContactDirectoryService = class {
|
|
|
10235
10585
|
const offset = await this.openOffsetCursor("bots", options.cursor, session.userId);
|
|
10236
10586
|
const bots = (await this.bot.listBots(options.signal === void 0 ? {} : { signal: options.signal })).items;
|
|
10237
10587
|
const slice = bots.slice(offset, offset + limit);
|
|
10238
|
-
const items = slice.map((
|
|
10588
|
+
const items = slice.map((bot) => ({
|
|
10239
10589
|
kind: "bot",
|
|
10240
|
-
|
|
10241
|
-
displayName: item.name
|
|
10590
|
+
bot
|
|
10242
10591
|
}));
|
|
10243
10592
|
const hasMore = offset + slice.length < bots.length;
|
|
10244
10593
|
return {
|
|
@@ -10476,7 +10825,7 @@ var ContactDirectoryService = class {
|
|
|
10476
10825
|
function numberValue$13(value) {
|
|
10477
10826
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
10478
10827
|
}
|
|
10479
|
-
function booleanValue$
|
|
10828
|
+
function booleanValue$6(value) {
|
|
10480
10829
|
return value === true;
|
|
10481
10830
|
}
|
|
10482
10831
|
function listValue$14(value) {
|
|
@@ -10495,7 +10844,7 @@ var CommunityService = class {
|
|
|
10495
10844
|
const session = await this.runtime.requireSession();
|
|
10496
10845
|
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/community/dsh-beta/entry-state", {}, session, signal);
|
|
10497
10846
|
const status = this.dshBetaCommunityStatus(data.status);
|
|
10498
|
-
const visible = booleanValue$
|
|
10847
|
+
const visible = booleanValue$6(data.visible);
|
|
10499
10848
|
const groupTitle = stringValue$1(data.group_title).trim();
|
|
10500
10849
|
const snapshot = objectValue$1(data.group_avatar_snapshot);
|
|
10501
10850
|
const memberCount = Math.max(0, Math.trunc(numberValue$13(snapshot.member_count)));
|
|
@@ -10790,7 +11139,7 @@ var ExtensionReviewService = class {
|
|
|
10790
11139
|
function numberValue$12(value) {
|
|
10791
11140
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
10792
11141
|
}
|
|
10793
|
-
function booleanValue$
|
|
11142
|
+
function booleanValue$5(value) {
|
|
10794
11143
|
return value === true;
|
|
10795
11144
|
}
|
|
10796
11145
|
function listValue$13(value) {
|
|
@@ -11101,7 +11450,7 @@ var GroupAiPolishService = class {
|
|
|
11101
11450
|
active_rule_uid: "",
|
|
11102
11451
|
update_at: Date.now()
|
|
11103
11452
|
}, session, options.signal);
|
|
11104
|
-
if (booleanValue$
|
|
11453
|
+
if (booleanValue$5(objectValue$1(updated.config ?? updated).enabled)) throw new ArkmePluginError("group-ai-polish-disable-invalid", "关闭 AI 表达润色失败,请重试", true, 502);
|
|
11105
11454
|
this.invalidateAiPolishReadCache(session.userId, pending.chatSessionUid);
|
|
11106
11455
|
this.aiPolishConfirmations.delete(confirmationRef.trim());
|
|
11107
11456
|
return {
|
|
@@ -11248,7 +11597,7 @@ var GroupAiPolishService = class {
|
|
|
11248
11597
|
const preview = objectValue$1(payload.ai_polish_preview ?? payload.aiPolishPreview ?? record.ai_polish_preview ?? record.aiPolishPreview);
|
|
11249
11598
|
const originalText = stringValue$1(preview.original_text ?? preview.originalText);
|
|
11250
11599
|
const polishedText = stringValue$1(preview.polished_text ?? preview.polishedText);
|
|
11251
|
-
if (!(booleanValue$
|
|
11600
|
+
if (!(booleanValue$5(payload.has_polish ?? payload.hasPolish ?? record.has_polish ?? record.hasPolish) || originalText !== "" && polishedText !== "") || originalText === "" || polishedText === "") return void 0;
|
|
11252
11601
|
return {
|
|
11253
11602
|
state: "polished",
|
|
11254
11603
|
originalText,
|
|
@@ -11275,8 +11624,8 @@ var GroupAiPolishService = class {
|
|
|
11275
11624
|
};
|
|
11276
11625
|
}).filter((rule) => rule.ruleUid !== "" && rule.ruleText !== "");
|
|
11277
11626
|
return {
|
|
11278
|
-
enabled: booleanValue$
|
|
11279
|
-
canManage: booleanValue$
|
|
11627
|
+
enabled: booleanValue$5(config.enabled ?? config.is_enabled),
|
|
11628
|
+
canManage: booleanValue$5(data.can_manage),
|
|
11280
11629
|
viewerRole: numberValue$12(data.viewer_role),
|
|
11281
11630
|
activeRuleUid,
|
|
11282
11631
|
activeRuleName: rules.find((rule) => rule.ruleUid === activeRuleUid)?.name ?? "",
|
|
@@ -11384,7 +11733,7 @@ function numberValue$11(value) {
|
|
|
11384
11733
|
function listValue$12(value) {
|
|
11385
11734
|
return Array.isArray(value) ? value : [];
|
|
11386
11735
|
}
|
|
11387
|
-
function encodeOpaqueJson$
|
|
11736
|
+
function encodeOpaqueJson$5(value) {
|
|
11388
11737
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
11389
11738
|
}
|
|
11390
11739
|
function decodeOpaqueJson$4(value) {
|
|
@@ -11682,7 +12031,7 @@ var GroupService = class {
|
|
|
11682
12031
|
};
|
|
11683
12032
|
}
|
|
11684
12033
|
async sealCandidateRef(payload) {
|
|
11685
|
-
const encoded = encodeOpaqueJson$
|
|
12034
|
+
const encoded = encodeOpaqueJson$5(payload);
|
|
11686
12035
|
return `arkme-group-candidate-v1.${encoded}.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(encoded).digest("base64url")}`;
|
|
11687
12036
|
}
|
|
11688
12037
|
async openCandidateRef(candidateRef, expectedUserId, expectedGroupChatSessionUid) {
|
|
@@ -11924,7 +12273,7 @@ var GroupService = class {
|
|
|
11924
12273
|
function numberValue$10(value) {
|
|
11925
12274
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
11926
12275
|
}
|
|
11927
|
-
function booleanValue$
|
|
12276
|
+
function booleanValue$4(value) {
|
|
11928
12277
|
return value === true;
|
|
11929
12278
|
}
|
|
11930
12279
|
function listValue$11(value) {
|
|
@@ -11952,7 +12301,7 @@ var InterwovenService = class {
|
|
|
11952
12301
|
moments: [],
|
|
11953
12302
|
preparedAtMillis: Date.now()
|
|
11954
12303
|
};
|
|
11955
|
-
if (!booleanValue$
|
|
12304
|
+
if (!booleanValue$4((await this.runtime.authenticatedAuthPost("/api/v1/auth/able-func", { func_type: 12 }, session, signal)).able)) return {
|
|
11956
12305
|
state: "disabled",
|
|
11957
12306
|
moments: [],
|
|
11958
12307
|
preparedAtMillis: Date.now()
|
|
@@ -12007,7 +12356,7 @@ var InterwovenService = class {
|
|
|
12007
12356
|
groupName,
|
|
12008
12357
|
senderUserId,
|
|
12009
12358
|
summary: stringValue$1(renderPayload.content ?? item.summary).trim().slice(0, 1e3),
|
|
12010
|
-
degraded: booleanValue$
|
|
12359
|
+
degraded: booleanValue$4(item.is_degraded),
|
|
12011
12360
|
sourceChatSessionUid,
|
|
12012
12361
|
recordOwnerUserId,
|
|
12013
12362
|
recordUid,
|
|
@@ -12083,7 +12432,7 @@ var InterwovenService = class {
|
|
|
12083
12432
|
if (source.kind !== "private_chat") throw new ArkmePluginError("interwoven-source-invalid", "交织瞬间仅支持普通私聊", false, 400);
|
|
12084
12433
|
const reference = await this.openInterwovenMomentRef(momentRef, session.userId, source.ownerRef);
|
|
12085
12434
|
if (!this.runtime.config.interwovenMomentsEnabled) throw new ArkmePluginError("interwoven-disabled", "交织瞬间能力当前未开启", false, 403);
|
|
12086
|
-
if (!booleanValue$
|
|
12435
|
+
if (!booleanValue$4((await this.runtime.authenticatedAuthPost("/api/v1/auth/able-func", { func_type: 12 }, session, signal)).able)) throw new ArkmePluginError("interwoven-disabled", "交织瞬间能力当前未开放", false, 403);
|
|
12087
12436
|
await this.assertHumanPrivateSource(source, session, signal);
|
|
12088
12437
|
if (reference.detailMode === "owner_payload") return {
|
|
12089
12438
|
momentId: reference.momentId,
|
|
@@ -12135,7 +12484,7 @@ var InterwovenService = class {
|
|
|
12135
12484
|
}
|
|
12136
12485
|
async resolveLegacyPrivateSubjectId(counterpartUserId, session, signal) {
|
|
12137
12486
|
const data = await this.runtime.authenticatedSubjectPost("/api/v1/private/check-contact-chat", { target_user_id: counterpartUserId }, session, signal);
|
|
12138
|
-
if (!booleanValue$
|
|
12487
|
+
if (!booleanValue$4(data.exist)) return 0;
|
|
12139
12488
|
const rmSubjectId = Math.trunc(numberValue$10(data.rm_subject_id));
|
|
12140
12489
|
if (!Number.isSafeInteger(rmSubjectId) || rmSubjectId <= 0) throw new ArkmePluginError("interwoven-subject-contract-invalid", "私聊交织主题定位响应不完整", true, 502);
|
|
12141
12490
|
return rmSubjectId;
|
|
@@ -12179,6 +12528,365 @@ var InterwovenService = class {
|
|
|
12179
12528
|
}
|
|
12180
12529
|
};
|
|
12181
12530
|
//#endregion
|
|
12531
|
+
//#region src/services/link-metadata-service.ts
|
|
12532
|
+
const MAX_LINK_METADATA_BYTES = 2 * 1024 * 1024;
|
|
12533
|
+
const LINK_METADATA_TIMEOUT_MS = 8e3;
|
|
12534
|
+
const LINK_METADATA_IDLE_TIMEOUT_MS = 4e3;
|
|
12535
|
+
const MAX_LINK_METADATA_REDIRECTS = 3;
|
|
12536
|
+
const MAX_LINK_TITLE_LENGTH = 300;
|
|
12537
|
+
const MAX_LINK_URL_LENGTH = 4096;
|
|
12538
|
+
const blockedAddresses = new BlockList();
|
|
12539
|
+
const globalIpv6Addresses = new BlockList();
|
|
12540
|
+
globalIpv6Addresses.addSubnet("2000::", 3, "ipv6");
|
|
12541
|
+
for (const [network, prefix] of [
|
|
12542
|
+
["0.0.0.0", 8],
|
|
12543
|
+
["10.0.0.0", 8],
|
|
12544
|
+
["100.64.0.0", 10],
|
|
12545
|
+
["127.0.0.0", 8],
|
|
12546
|
+
["169.254.0.0", 16],
|
|
12547
|
+
["172.16.0.0", 12],
|
|
12548
|
+
["192.0.0.0", 24],
|
|
12549
|
+
["192.0.2.0", 24],
|
|
12550
|
+
["192.88.99.0", 24],
|
|
12551
|
+
["192.168.0.0", 16],
|
|
12552
|
+
["198.18.0.0", 15],
|
|
12553
|
+
["198.51.100.0", 24],
|
|
12554
|
+
["203.0.113.0", 24],
|
|
12555
|
+
["224.0.0.0", 4],
|
|
12556
|
+
["240.0.0.0", 4]
|
|
12557
|
+
]) blockedAddresses.addSubnet(network, prefix, "ipv4");
|
|
12558
|
+
for (const [network, prefix] of [
|
|
12559
|
+
["2001::", 23],
|
|
12560
|
+
["2001:db8::", 32],
|
|
12561
|
+
["2002::", 16],
|
|
12562
|
+
["3fff::", 20]
|
|
12563
|
+
]) blockedAddresses.addSubnet(network, prefix, "ipv6");
|
|
12564
|
+
function hostWithoutBrackets(hostname) {
|
|
12565
|
+
return hostname.startsWith("[") && hostname.endsWith("]") ? hostname.slice(1, -1) : hostname;
|
|
12566
|
+
}
|
|
12567
|
+
function ipv4FromMappedIpv6(address) {
|
|
12568
|
+
return /^::ffff:(\d{1,3}(?:\.\d{1,3}){3})$/iu.exec(address)?.[1];
|
|
12569
|
+
}
|
|
12570
|
+
function isPublicNetworkAddress(address) {
|
|
12571
|
+
const mapped = ipv4FromMappedIpv6(address);
|
|
12572
|
+
if (mapped !== void 0) return isIP(mapped) === 4 && !blockedAddresses.check(mapped, "ipv4");
|
|
12573
|
+
const family = isIP(address);
|
|
12574
|
+
if (family === 4) return !blockedAddresses.check(address, "ipv4");
|
|
12575
|
+
if (family === 6) return globalIpv6Addresses.check(address, "ipv6") && !blockedAddresses.check(address, "ipv6");
|
|
12576
|
+
return false;
|
|
12577
|
+
}
|
|
12578
|
+
function safeWebUrl(raw) {
|
|
12579
|
+
let url;
|
|
12580
|
+
try {
|
|
12581
|
+
url = raw instanceof URL ? new URL(raw.href) : new URL(raw);
|
|
12582
|
+
} catch (error) {
|
|
12583
|
+
throw new ArkmePluginError("link-metadata-url-invalid", "网址格式无效", false, 400, { cause: error });
|
|
12584
|
+
}
|
|
12585
|
+
const hostname = hostWithoutBrackets(url.hostname).toLowerCase();
|
|
12586
|
+
if (url.protocol !== "http:" && url.protocol !== "https:" || url.username !== "" || url.password !== "" || url.href.length > MAX_LINK_URL_LENGTH || hostname === "" || hostname === "localhost" || hostname.endsWith(".localhost") || isIP(hostname) !== 0) throw new ArkmePluginError("link-metadata-url-unsafe", "该网址不允许解析标题", false, 400);
|
|
12587
|
+
return url;
|
|
12588
|
+
}
|
|
12589
|
+
function entityValue(value) {
|
|
12590
|
+
if (/^#x[\da-f]+$/iu.test(value)) return String.fromCodePoint(Number.parseInt(value.slice(2), 16));
|
|
12591
|
+
if (/^#\d+$/u.test(value)) return String.fromCodePoint(Number.parseInt(value.slice(1), 10));
|
|
12592
|
+
return {
|
|
12593
|
+
amp: "&",
|
|
12594
|
+
apos: "'",
|
|
12595
|
+
gt: ">",
|
|
12596
|
+
lt: "<",
|
|
12597
|
+
nbsp: " ",
|
|
12598
|
+
quot: "\""
|
|
12599
|
+
}[value.toLowerCase()] ?? `&${value};`;
|
|
12600
|
+
}
|
|
12601
|
+
function normalizedTitle(value) {
|
|
12602
|
+
return value.replace(/<[^>]*>/gu, " ").replace(/&(#x[\da-f]+|#\d+|amp|apos|gt|lt|nbsp|quot);/giu, (_match, entity) => {
|
|
12603
|
+
try {
|
|
12604
|
+
return entityValue(entity);
|
|
12605
|
+
} catch {
|
|
12606
|
+
return "";
|
|
12607
|
+
}
|
|
12608
|
+
}).replace(/[\u0000-\u001f\u007f\s]+/gu, " ").trim().slice(0, MAX_LINK_TITLE_LENGTH);
|
|
12609
|
+
}
|
|
12610
|
+
function tagAttributes(tag) {
|
|
12611
|
+
const attributes = /* @__PURE__ */ new Map();
|
|
12612
|
+
for (const match of tag.matchAll(/([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/gu)) {
|
|
12613
|
+
const name = match[1]?.toLowerCase();
|
|
12614
|
+
if (name !== void 0) attributes.set(name, match[2] ?? match[3] ?? match[4] ?? "");
|
|
12615
|
+
}
|
|
12616
|
+
return attributes;
|
|
12617
|
+
}
|
|
12618
|
+
function documentMetadata(url, html) {
|
|
12619
|
+
const metadata = /* @__PURE__ */ new Map();
|
|
12620
|
+
for (const match of html.matchAll(/<meta\b[^>]*>/giu)) {
|
|
12621
|
+
const attributes = tagAttributes(match[0]);
|
|
12622
|
+
const property = (attributes.get("property") ?? attributes.get("name") ?? "").toLowerCase();
|
|
12623
|
+
if (property === "" || metadata.has(property)) continue;
|
|
12624
|
+
const content = normalizedTitle(attributes.get("content") ?? "");
|
|
12625
|
+
if (content !== "") metadata.set(property, content);
|
|
12626
|
+
}
|
|
12627
|
+
const documentTitle = /<title\b[^>]*>([\s\S]*?)<\/title\s*>/iu.exec(html)?.[1];
|
|
12628
|
+
const title = metadata.get("og:title") ?? metadata.get("twitter:title") ?? (documentTitle === void 0 ? "" : normalizedTitle(documentTitle));
|
|
12629
|
+
if (title === "") return null;
|
|
12630
|
+
const description = metadata.get("og:description") ?? metadata.get("description");
|
|
12631
|
+
const siteName = metadata.get("og:site_name") ?? url.hostname.replace(/^www\./iu, "");
|
|
12632
|
+
return {
|
|
12633
|
+
url: url.href,
|
|
12634
|
+
title,
|
|
12635
|
+
...description === void 0 ? {} : { description },
|
|
12636
|
+
...siteName === "" ? {} : { siteName }
|
|
12637
|
+
};
|
|
12638
|
+
}
|
|
12639
|
+
function redirectStatus(status) {
|
|
12640
|
+
return status === 301 || status === 302 || status === 303 || status === 307 || status === 308;
|
|
12641
|
+
}
|
|
12642
|
+
function isHtmlContentType(contentType) {
|
|
12643
|
+
return contentType === void 0 || /^text\/html\b|^application\/xhtml\+xml\b/iu.test(contentType);
|
|
12644
|
+
}
|
|
12645
|
+
function pluginError(error) {
|
|
12646
|
+
if (error instanceof ArkmePluginError) return error;
|
|
12647
|
+
return new ArkmePluginError("link-metadata-fetch-failed", "网址名称解析失败", true, 502, { cause: error });
|
|
12648
|
+
}
|
|
12649
|
+
function missingDnsAnswer(error) {
|
|
12650
|
+
const code = error !== null && typeof error === "object" && "code" in error ? String(error.code) : "";
|
|
12651
|
+
return code === "ENODATA" || code === "ENOTFOUND" || code === "ENONAME";
|
|
12652
|
+
}
|
|
12653
|
+
var NodeArkmeHostAddressResolver = class {
|
|
12654
|
+
resolverFactory;
|
|
12655
|
+
constructor(resolverFactory = () => new Resolver()) {
|
|
12656
|
+
this.resolverFactory = resolverFactory;
|
|
12657
|
+
}
|
|
12658
|
+
async lookup(hostname, options = {}) {
|
|
12659
|
+
options.signal?.throwIfAborted();
|
|
12660
|
+
const resolver = this.resolverFactory();
|
|
12661
|
+
const abort = () => {
|
|
12662
|
+
resolver.cancel();
|
|
12663
|
+
};
|
|
12664
|
+
options.signal?.addEventListener("abort", abort, { once: true });
|
|
12665
|
+
try {
|
|
12666
|
+
const [ipv4, ipv6] = await Promise.all([resolver.resolve4(hostname).catch((error) => {
|
|
12667
|
+
if (missingDnsAnswer(error)) return [];
|
|
12668
|
+
throw error;
|
|
12669
|
+
}), resolver.resolve6(hostname).catch((error) => {
|
|
12670
|
+
if (missingDnsAnswer(error)) return [];
|
|
12671
|
+
throw error;
|
|
12672
|
+
})]);
|
|
12673
|
+
options.signal?.throwIfAborted();
|
|
12674
|
+
return [...ipv4.map((address) => ({
|
|
12675
|
+
address,
|
|
12676
|
+
family: 4
|
|
12677
|
+
})), ...ipv6.map((address) => ({
|
|
12678
|
+
address,
|
|
12679
|
+
family: 6
|
|
12680
|
+
}))];
|
|
12681
|
+
} catch (error) {
|
|
12682
|
+
options.signal?.throwIfAborted();
|
|
12683
|
+
throw error;
|
|
12684
|
+
} finally {
|
|
12685
|
+
options.signal?.removeEventListener("abort", abort);
|
|
12686
|
+
}
|
|
12687
|
+
}
|
|
12688
|
+
};
|
|
12689
|
+
var NodeArkmePinnedDocumentTransport = class {
|
|
12690
|
+
maxBytes;
|
|
12691
|
+
idleTimeoutMs;
|
|
12692
|
+
constructor(options = {}) {
|
|
12693
|
+
this.maxBytes = Math.max(1, Math.trunc(options.maxBytes ?? MAX_LINK_METADATA_BYTES));
|
|
12694
|
+
this.idleTimeoutMs = Math.max(1, Math.trunc(options.idleTimeoutMs ?? LINK_METADATA_IDLE_TIMEOUT_MS));
|
|
12695
|
+
}
|
|
12696
|
+
async read(url, addresses, options = {}) {
|
|
12697
|
+
const address = addresses[0];
|
|
12698
|
+
if (address === void 0) throw new ArkmePluginError("link-metadata-fetch-failed", "网址名称解析失败", true, 502);
|
|
12699
|
+
const pinnedLookup = (_requestedHost, lookupOptions, callback) => {
|
|
12700
|
+
if (lookupOptions.all === true) callback(null, [...addresses]);
|
|
12701
|
+
else callback(null, address.address, address.family);
|
|
12702
|
+
};
|
|
12703
|
+
const request$2 = url.protocol === "https:" ? request$1 : request;
|
|
12704
|
+
return await new Promise((resolve, reject) => {
|
|
12705
|
+
let settled = false;
|
|
12706
|
+
const finish = (error, value) => {
|
|
12707
|
+
if (settled) return;
|
|
12708
|
+
settled = true;
|
|
12709
|
+
if (error !== void 0) reject(pluginError(error));
|
|
12710
|
+
else if (value !== void 0) resolve(value);
|
|
12711
|
+
};
|
|
12712
|
+
const req = request$2(url, {
|
|
12713
|
+
method: "GET",
|
|
12714
|
+
lookup: pinnedLookup,
|
|
12715
|
+
signal: options.signal,
|
|
12716
|
+
headers: {
|
|
12717
|
+
Accept: "text/html,application/xhtml+xml;q=0.9,*/*;q=0.1",
|
|
12718
|
+
"Accept-Encoding": "identity",
|
|
12719
|
+
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
|
|
12720
|
+
}
|
|
12721
|
+
}, (response) => {
|
|
12722
|
+
const chunks = [];
|
|
12723
|
+
let bytes = 0;
|
|
12724
|
+
let headProbe = "";
|
|
12725
|
+
const status = response.statusCode ?? 0;
|
|
12726
|
+
const contentType = typeof response.headers["content-type"] === "string" ? response.headers["content-type"] : void 0;
|
|
12727
|
+
const location = typeof response.headers.location === "string" ? response.headers.location : void 0;
|
|
12728
|
+
const complete = () => finish(void 0, {
|
|
12729
|
+
status,
|
|
12730
|
+
...contentType === void 0 ? {} : { contentType },
|
|
12731
|
+
...location === void 0 ? {} : { location },
|
|
12732
|
+
body: Buffer.concat(chunks).toString("utf8")
|
|
12733
|
+
});
|
|
12734
|
+
if (redirectStatus(status) || status < 200 || status >= 300 || !isHtmlContentType(contentType)) {
|
|
12735
|
+
complete();
|
|
12736
|
+
response.destroy();
|
|
12737
|
+
return;
|
|
12738
|
+
}
|
|
12739
|
+
response.on("data", (chunk) => {
|
|
12740
|
+
if (settled) return;
|
|
12741
|
+
const buffer = Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk);
|
|
12742
|
+
bytes += buffer.byteLength;
|
|
12743
|
+
if (bytes > this.maxBytes) {
|
|
12744
|
+
finish(new ArkmePluginError("link-metadata-response-too-large", "网址内容过大,无法解析名称", false, 413));
|
|
12745
|
+
response.destroy();
|
|
12746
|
+
return;
|
|
12747
|
+
}
|
|
12748
|
+
chunks.push(buffer);
|
|
12749
|
+
const lowerChunk = buffer.toString("utf8").toLowerCase();
|
|
12750
|
+
if (`${headProbe}${lowerChunk}`.includes("</head>")) {
|
|
12751
|
+
complete();
|
|
12752
|
+
response.destroy();
|
|
12753
|
+
}
|
|
12754
|
+
headProbe = lowerChunk.slice(-6);
|
|
12755
|
+
});
|
|
12756
|
+
response.once("end", () => {
|
|
12757
|
+
if (response.complete) complete();
|
|
12758
|
+
else finish(/* @__PURE__ */ new Error("link metadata response ended before completion"));
|
|
12759
|
+
});
|
|
12760
|
+
response.once("close", () => {
|
|
12761
|
+
if (!settled && response.complete) complete();
|
|
12762
|
+
else if (!settled) finish(/* @__PURE__ */ new Error("link metadata response closed before completion"));
|
|
12763
|
+
});
|
|
12764
|
+
response.once("aborted", () => {
|
|
12765
|
+
if (!settled) finish(/* @__PURE__ */ new Error("link metadata response aborted"));
|
|
12766
|
+
});
|
|
12767
|
+
response.once("error", (error) => {
|
|
12768
|
+
if (!settled) finish(error);
|
|
12769
|
+
});
|
|
12770
|
+
});
|
|
12771
|
+
req.setTimeout(this.idleTimeoutMs, () => {
|
|
12772
|
+
req.destroy(new ArkmePluginError("link-metadata-idle-timeout", "网址名称解析超时", true, 504));
|
|
12773
|
+
});
|
|
12774
|
+
req.once("error", (error) => finish(error));
|
|
12775
|
+
req.end();
|
|
12776
|
+
});
|
|
12777
|
+
}
|
|
12778
|
+
};
|
|
12779
|
+
var NodeArkmeLinkDocumentReader = class {
|
|
12780
|
+
resolver;
|
|
12781
|
+
transport;
|
|
12782
|
+
constructor(resolver = new NodeArkmeHostAddressResolver(), transport = new NodeArkmePinnedDocumentTransport()) {
|
|
12783
|
+
this.resolver = resolver;
|
|
12784
|
+
this.transport = transport;
|
|
12785
|
+
}
|
|
12786
|
+
async read(url, options = {}) {
|
|
12787
|
+
const hostname = hostWithoutBrackets(url.hostname);
|
|
12788
|
+
let addresses;
|
|
12789
|
+
try {
|
|
12790
|
+
addresses = await this.resolver.lookup(hostname, options);
|
|
12791
|
+
} catch (error) {
|
|
12792
|
+
throw pluginError(error);
|
|
12793
|
+
}
|
|
12794
|
+
if (addresses.length === 0 || addresses.some((item) => !isPublicNetworkAddress(item.address))) throw new ArkmePluginError("link-metadata-url-unsafe", "该网址不允许解析标题", false, 400);
|
|
12795
|
+
return await this.transport.read(url, addresses, options);
|
|
12796
|
+
}
|
|
12797
|
+
};
|
|
12798
|
+
var ArkmeLinkMetadataService = class {
|
|
12799
|
+
reader;
|
|
12800
|
+
lifecycle = new AbortController();
|
|
12801
|
+
timeoutMs;
|
|
12802
|
+
coordinator;
|
|
12803
|
+
constructor(reader = new NodeArkmeLinkDocumentReader(), options = {}) {
|
|
12804
|
+
this.reader = reader;
|
|
12805
|
+
const maxConcurrent = Math.max(1, Math.trunc(options.maxConcurrent ?? 4));
|
|
12806
|
+
const maxQueue = Math.max(1, Math.trunc(options.maxQueue ?? 32));
|
|
12807
|
+
const burst = maxConcurrent + maxQueue;
|
|
12808
|
+
this.timeoutMs = Math.max(1, Math.trunc(options.timeoutMs ?? LINK_METADATA_TIMEOUT_MS));
|
|
12809
|
+
this.coordinator = new ArkmeRequestCoordinator({
|
|
12810
|
+
laneLimits: { "background-read": {
|
|
12811
|
+
maxConcurrent,
|
|
12812
|
+
maxQueued: maxQueue,
|
|
12813
|
+
burst,
|
|
12814
|
+
ratePerSecond: burst
|
|
12815
|
+
} },
|
|
12816
|
+
serviceLimits: { other: {
|
|
12817
|
+
maxConcurrent,
|
|
12818
|
+
maxQueued: maxQueue,
|
|
12819
|
+
burst,
|
|
12820
|
+
ratePerSecond: burst
|
|
12821
|
+
} }
|
|
12822
|
+
});
|
|
12823
|
+
}
|
|
12824
|
+
async resolve(rawUrl, options = {}) {
|
|
12825
|
+
if (this.lifecycle.signal.aborted) throw new ArkmePluginError("link-metadata-disposed", "网址名称解析服务已停止", true, 503);
|
|
12826
|
+
const initialUrl = safeWebUrl(rawUrl);
|
|
12827
|
+
initialUrl.hash = "";
|
|
12828
|
+
const deadlineAt = Date.now() + this.timeoutMs;
|
|
12829
|
+
const deadline = new AbortController();
|
|
12830
|
+
const deadlineTimer = setTimeout(() => {
|
|
12831
|
+
deadline.abort(this.timeoutError());
|
|
12832
|
+
}, this.timeoutMs);
|
|
12833
|
+
const signal = AbortSignal.any([
|
|
12834
|
+
this.lifecycle.signal,
|
|
12835
|
+
deadline.signal,
|
|
12836
|
+
...options.signal === void 0 ? [] : [options.signal]
|
|
12837
|
+
]);
|
|
12838
|
+
try {
|
|
12839
|
+
return await this.coordinator.run({
|
|
12840
|
+
scope: "link-metadata",
|
|
12841
|
+
lane: "background-read",
|
|
12842
|
+
service: "other",
|
|
12843
|
+
signal,
|
|
12844
|
+
operation: async (operationSignal) => {
|
|
12845
|
+
if (Date.now() >= deadlineAt) throw this.timeoutError();
|
|
12846
|
+
return await this.load(initialUrl, operationSignal);
|
|
12847
|
+
}
|
|
12848
|
+
});
|
|
12849
|
+
} catch {
|
|
12850
|
+
if (this.lifecycle.signal.aborted) throw this.lifecycle.signal.reason;
|
|
12851
|
+
return null;
|
|
12852
|
+
} finally {
|
|
12853
|
+
clearTimeout(deadlineTimer);
|
|
12854
|
+
}
|
|
12855
|
+
}
|
|
12856
|
+
dispose() {
|
|
12857
|
+
this.lifecycle.abort(new ArkmePluginError("link-metadata-disposed", "网址名称解析服务已停止", true, 503));
|
|
12858
|
+
this.coordinator.dispose();
|
|
12859
|
+
}
|
|
12860
|
+
timeoutError() {
|
|
12861
|
+
return new ArkmePluginError("link-metadata-timeout", "网址名称解析超时", true, 504);
|
|
12862
|
+
}
|
|
12863
|
+
async load(initialUrl, signal) {
|
|
12864
|
+
let url = initialUrl;
|
|
12865
|
+
for (let redirect = 0; redirect <= MAX_LINK_METADATA_REDIRECTS; redirect += 1) {
|
|
12866
|
+
let document;
|
|
12867
|
+
try {
|
|
12868
|
+
document = await this.reader.read(url, { signal });
|
|
12869
|
+
} catch (error) {
|
|
12870
|
+
throw pluginError(error);
|
|
12871
|
+
}
|
|
12872
|
+
if (redirectStatus(document.status) && document.location !== void 0) {
|
|
12873
|
+
if (redirect === MAX_LINK_METADATA_REDIRECTS) throw new ArkmePluginError("link-metadata-redirect-limit", "网址跳转次数过多", false, 400);
|
|
12874
|
+
try {
|
|
12875
|
+
url = safeWebUrl(new URL(document.location, url));
|
|
12876
|
+
} catch (error) {
|
|
12877
|
+
if (error instanceof ArkmePluginError && error.code === "link-metadata-url-unsafe") throw error;
|
|
12878
|
+
throw new ArkmePluginError("link-metadata-redirect-invalid", "网址跳转地址无效", false, 400, { cause: error });
|
|
12879
|
+
}
|
|
12880
|
+
continue;
|
|
12881
|
+
}
|
|
12882
|
+
if (document.status < 200 || document.status >= 300) return null;
|
|
12883
|
+
if (!isHtmlContentType(document.contentType)) return null;
|
|
12884
|
+
return documentMetadata(url, document.body);
|
|
12885
|
+
}
|
|
12886
|
+
return null;
|
|
12887
|
+
}
|
|
12888
|
+
};
|
|
12889
|
+
//#endregion
|
|
12182
12890
|
//#region src/services/media-service.ts
|
|
12183
12891
|
const MAX_ARKME_IMAGE_BYTES = 2 * 1024 * 1024;
|
|
12184
12892
|
const MAX_ARKME_PROFILE_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
@@ -13338,7 +14046,7 @@ const ARKME_STAFF_ACCOUNT_TYPE = 2;
|
|
|
13338
14046
|
function numberValue$7(value) {
|
|
13339
14047
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
13340
14048
|
}
|
|
13341
|
-
function booleanValue$
|
|
14049
|
+
function booleanValue$3(value) {
|
|
13342
14050
|
return value === true;
|
|
13343
14051
|
}
|
|
13344
14052
|
function optionalBooleanValue(value) {
|
|
@@ -13352,7 +14060,7 @@ function chunksOf(values, size) {
|
|
|
13352
14060
|
for (let index = 0; index < values.length; index += size) chunks.push(values.slice(index, index + size));
|
|
13353
14061
|
return chunks;
|
|
13354
14062
|
}
|
|
13355
|
-
function encodeOpaqueJson$
|
|
14063
|
+
function encodeOpaqueJson$4(value) {
|
|
13356
14064
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
13357
14065
|
}
|
|
13358
14066
|
function decodeOpaqueJson$3(value) {
|
|
@@ -13588,9 +14296,9 @@ var ProfileService = class {
|
|
|
13588
14296
|
accountType: numberValue$7(data.type),
|
|
13589
14297
|
createdAt: numberValue$7(data.create_at),
|
|
13590
14298
|
bindings: {
|
|
13591
|
-
apple: booleanValue$
|
|
13592
|
-
wechat: booleanValue$
|
|
13593
|
-
google: booleanValue$
|
|
14299
|
+
apple: booleanValue$3(data.has_bind_apple),
|
|
14300
|
+
wechat: booleanValue$3(data.has_bind_wechat),
|
|
14301
|
+
google: booleanValue$3(data.has_bind_google)
|
|
13594
14302
|
},
|
|
13595
14303
|
...wechatName === "" ? {} : { bindingNames: { wechat: wechatName } },
|
|
13596
14304
|
contact: {
|
|
@@ -13721,7 +14429,7 @@ var ProfileService = class {
|
|
|
13721
14429
|
return profiles;
|
|
13722
14430
|
}
|
|
13723
14431
|
async sealProfileImageRef(viewerUserId, targetUserId) {
|
|
13724
|
-
const payload = encodeOpaqueJson$
|
|
14432
|
+
const payload = encodeOpaqueJson$4({
|
|
13725
14433
|
version: 1,
|
|
13726
14434
|
viewerUserId,
|
|
13727
14435
|
targetUserId
|
|
@@ -14522,7 +15230,7 @@ function speakerUserIds(speakerData) {
|
|
|
14522
15230
|
return userId === void 0 ? [] : [userId];
|
|
14523
15231
|
}))];
|
|
14524
15232
|
}
|
|
14525
|
-
function encodeOpaqueJson$
|
|
15233
|
+
function encodeOpaqueJson$3(value) {
|
|
14526
15234
|
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
14527
15235
|
}
|
|
14528
15236
|
function decodeOpaqueJson$2(value) {
|
|
@@ -14609,7 +15317,7 @@ var RecordingService = class {
|
|
|
14609
15317
|
}
|
|
14610
15318
|
async sealRecordingCursor(payload) {
|
|
14611
15319
|
const session = await this.runtime.requireSession();
|
|
14612
|
-
const encoded = encodeOpaqueJson$
|
|
15320
|
+
const encoded = encodeOpaqueJson$3(payload);
|
|
14613
15321
|
return `arkme-recording-cursor-v1.${encoded}.${createHmac("sha256", await this.recordingCursorKey(session.userId)).update(encoded).digest("base64url")}`;
|
|
14614
15322
|
}
|
|
14615
15323
|
async openRecordingCursor(cursor) {
|
|
@@ -14724,7 +15432,17 @@ const MAX_ARKME_RELATED_RECORDING_CURSOR_LENGTH = 1024;
|
|
|
14724
15432
|
const MAX_ARKME_TIMEZONE_OFFSET_MILLIS = 840 * 60 * 1e3;
|
|
14725
15433
|
const RELATED_RECORDINGS_FUNC_TYPE = 17;
|
|
14726
15434
|
function numberValue$3(value) {
|
|
14727
|
-
|
|
15435
|
+
if (typeof value === "number" && Number.isFinite(value)) return Math.trunc(value);
|
|
15436
|
+
if (typeof value === "string" && value.trim() !== "") {
|
|
15437
|
+
const parsed = Number(value.trim());
|
|
15438
|
+
if (Number.isFinite(parsed)) return Math.trunc(parsed);
|
|
15439
|
+
}
|
|
15440
|
+
return 0;
|
|
15441
|
+
}
|
|
15442
|
+
function booleanValue$2(value) {
|
|
15443
|
+
if (value === true || value === 1) return true;
|
|
15444
|
+
if (typeof value === "string") return ["1", "true"].includes(value.trim().toLowerCase());
|
|
15445
|
+
return false;
|
|
14728
15446
|
}
|
|
14729
15447
|
function listValue$4(value) {
|
|
14730
15448
|
return Array.isArray(value) ? value : [];
|
|
@@ -14737,6 +15455,21 @@ function optionalString$1(value) {
|
|
|
14737
15455
|
const text = stringValue$1(value).trim();
|
|
14738
15456
|
return text === "" ? void 0 : text;
|
|
14739
15457
|
}
|
|
15458
|
+
function firstOptionalString(source, keys) {
|
|
15459
|
+
for (const key of keys) {
|
|
15460
|
+
const value = optionalString$1(source[key]);
|
|
15461
|
+
if (value !== void 0) return value;
|
|
15462
|
+
}
|
|
15463
|
+
}
|
|
15464
|
+
function encodeOpaqueJson$2(value) {
|
|
15465
|
+
return Buffer.from(JSON.stringify(value), "utf8").toString("base64url");
|
|
15466
|
+
}
|
|
15467
|
+
function participantRoleName(role) {
|
|
15468
|
+
if (role === 2) return "我";
|
|
15469
|
+
if (role === 1) return "对方";
|
|
15470
|
+
if (role === 4) return "其他说话人";
|
|
15471
|
+
return "";
|
|
15472
|
+
}
|
|
14740
15473
|
var RelatedRecordingService = class {
|
|
14741
15474
|
runtime;
|
|
14742
15475
|
source;
|
|
@@ -14797,23 +15530,24 @@ var RelatedRecordingService = class {
|
|
|
14797
15530
|
return source;
|
|
14798
15531
|
}
|
|
14799
15532
|
async loadRelatedRecordingEligibility(session, signal) {
|
|
14800
|
-
return (await this.runtime.authenticatedAuthPost("/api/v1/auth/able-func", { func_type: RELATED_RECORDINGS_FUNC_TYPE }, session, signal)).able
|
|
15533
|
+
return booleanValue$2((await this.runtime.authenticatedAuthPost("/api/v1/auth/able-func", { func_type: RELATED_RECORDINGS_FUNC_TYPE }, session, signal)).able);
|
|
14801
15534
|
}
|
|
14802
15535
|
async relatedRecordingPage(raw, legacyTimeIndexFallback, userId, chatSessionUid) {
|
|
14803
15536
|
const items = [];
|
|
14804
|
-
|
|
14805
|
-
|
|
15537
|
+
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
15538
|
+
for (const rawItem of listValue$4(raw.moment_ls ?? raw.momentLs ?? raw.items)) {
|
|
15539
|
+
const item = this.relatedRecordingItem(rawItem, userId, chatSessionUid, signingKey);
|
|
14806
15540
|
if (item !== void 0) items.push(item);
|
|
14807
15541
|
}
|
|
14808
|
-
const partial = raw.partial
|
|
15542
|
+
const partial = booleanValue$2(raw.partial);
|
|
14809
15543
|
const stateCode = numberValue$3(raw.state);
|
|
14810
15544
|
const state = partial ? items.length > 0 ? "partial" : "error" : items.length > 0 ? "success" : stateCode === 2 ? "generating" : stateCode === 4 ? "error" : "empty";
|
|
14811
|
-
const nextCursor = stringValue$1(raw.next_cursor).trim();
|
|
14812
|
-
const timeIndexComplete = raw.time_index_complete
|
|
14813
|
-
const monthBuckets = timeIndexComplete ? listValue$4(raw.month_bucket_ls).flatMap((value) => {
|
|
15545
|
+
const nextCursor = stringValue$1(raw.next_cursor ?? raw.nextCursor).trim();
|
|
15546
|
+
const timeIndexComplete = booleanValue$2(raw.time_index_complete ?? raw.timeIndexComplete) && !legacyTimeIndexFallback;
|
|
15547
|
+
const monthBuckets = timeIndexComplete ? listValue$4(raw.month_bucket_ls ?? raw.monthBucketLs ?? raw.monthBuckets).flatMap((value) => {
|
|
14814
15548
|
const bucket = objectValue$1(value);
|
|
14815
|
-
const monthKey = stringValue$1(bucket.month_key).trim();
|
|
14816
|
-
const itemCount = numberValue$3(bucket.item_count);
|
|
15549
|
+
const monthKey = stringValue$1(bucket.month_key ?? bucket.monthKey).trim();
|
|
15550
|
+
const itemCount = numberValue$3(bucket.item_count ?? bucket.itemCount);
|
|
14817
15551
|
return /^\d{4}-(0[1-9]|1[0-2])$/.test(monthKey) && Number.isInteger(itemCount) && itemCount >= 0 ? [{
|
|
14818
15552
|
monthKey,
|
|
14819
15553
|
itemCount
|
|
@@ -14822,71 +15556,156 @@ var RelatedRecordingService = class {
|
|
|
14822
15556
|
return {
|
|
14823
15557
|
state,
|
|
14824
15558
|
stateCode,
|
|
14825
|
-
stateMessage: stringValue$1(raw.state_msg).trim(),
|
|
14826
|
-
hasEntry: raw.has_entry
|
|
15559
|
+
stateMessage: stringValue$1(raw.state_msg ?? raw.stateMessage).trim(),
|
|
15560
|
+
hasEntry: booleanValue$2(raw.has_entry ?? raw.hasEntry),
|
|
14827
15561
|
items,
|
|
14828
|
-
hasMore: raw.has_more
|
|
14829
|
-
...raw.has_more
|
|
15562
|
+
hasMore: booleanValue$2(raw.has_more ?? raw.hasMore) && nextCursor !== "",
|
|
15563
|
+
...booleanValue$2(raw.has_more ?? raw.hasMore) && nextCursor !== "" ? { nextCursor } : {},
|
|
14830
15564
|
partial,
|
|
14831
15565
|
...timeIndexComplete ? { monthBuckets } : {},
|
|
14832
15566
|
timeIndexComplete,
|
|
14833
15567
|
legacyTimeIndexFallback
|
|
14834
15568
|
};
|
|
14835
15569
|
}
|
|
14836
|
-
|
|
15570
|
+
relatedRecordingItem(raw, userId, chatSessionUid, signingKey) {
|
|
14837
15571
|
const item = objectValue$1(raw);
|
|
14838
|
-
const momentId = stringValue$1(item.moment_id).trim();
|
|
14839
|
-
const startAtMillis = numberValue$3(item.start_at);
|
|
15572
|
+
const momentId = stringValue$1(item.moment_id ?? item.momentId).trim();
|
|
15573
|
+
const startAtMillis = numberValue$3(item.start_at ?? item.startAt ?? item.startAtMillis);
|
|
14840
15574
|
if (momentId === "" || !Number.isSafeInteger(startAtMillis) || startAtMillis <= 0) return void 0;
|
|
14841
|
-
const transcript = stringValue$1(item.transcript);
|
|
14842
|
-
const speakers = listValue$4(item.speaker_ls).flatMap((value) => {
|
|
15575
|
+
const transcript = stringValue$1(item.transcript ?? item.transcript_text ?? item.transcriptText);
|
|
15576
|
+
const speakers = listValue$4(item.speaker_ls ?? item.speakerLs ?? item.speakers).flatMap((value, index) => {
|
|
15577
|
+
if (typeof value === "string") {
|
|
15578
|
+
const nickname = value.trim();
|
|
15579
|
+
return nickname === "" ? [] : [{
|
|
15580
|
+
speakerId: `speaker:${index}`,
|
|
15581
|
+
nickname
|
|
15582
|
+
}];
|
|
15583
|
+
}
|
|
14843
15584
|
const speaker = objectValue$1(value);
|
|
14844
|
-
const speakerId =
|
|
14845
|
-
|
|
14846
|
-
|
|
14847
|
-
|
|
15585
|
+
const speakerId = firstOptionalString(speaker, [
|
|
15586
|
+
"speaker_id",
|
|
15587
|
+
"speakerId",
|
|
15588
|
+
"id"
|
|
15589
|
+
]) ?? "";
|
|
15590
|
+
const refUserId = optionalPositiveNumber$1(speaker.ref_usr_id ?? speaker.refUsrId ?? speaker.ref_user_id ?? speaker.refUserId);
|
|
15591
|
+
const nickname = firstOptionalString(speaker, [
|
|
15592
|
+
"nick_name",
|
|
15593
|
+
"nickName",
|
|
15594
|
+
"nickname",
|
|
15595
|
+
"speaker_name",
|
|
15596
|
+
"speakerName",
|
|
15597
|
+
"display_name",
|
|
15598
|
+
"displayName",
|
|
15599
|
+
"name"
|
|
15600
|
+
]);
|
|
15601
|
+
if (speakerId === "" && nickname === void 0 && refUserId === void 0) return [];
|
|
14848
15602
|
return [{
|
|
14849
15603
|
speakerId,
|
|
14850
15604
|
...refUserId === void 0 ? {} : { refUserId },
|
|
14851
15605
|
...nickname === void 0 ? {} : { nickname }
|
|
14852
15606
|
}];
|
|
14853
15607
|
});
|
|
14854
|
-
const
|
|
15608
|
+
const participantValues = listValue$4(item.participant_ls ?? item.participantLs ?? item.participants);
|
|
15609
|
+
const participants = (participantValues.length > 0 ? participantValues : listValue$4(item.speaker_ls ?? item.speakerLs ?? item.speakers)).flatMap((value, index) => {
|
|
15610
|
+
if (typeof value === "string") {
|
|
15611
|
+
const displayName = value.trim();
|
|
15612
|
+
return displayName === "" ? [] : [{
|
|
15613
|
+
speakerId: `participant:${index}`,
|
|
15614
|
+
displayName,
|
|
15615
|
+
role: 0
|
|
15616
|
+
}];
|
|
15617
|
+
}
|
|
14855
15618
|
const participant = objectValue$1(value);
|
|
14856
|
-
const
|
|
14857
|
-
const
|
|
14858
|
-
|
|
14859
|
-
|
|
14860
|
-
|
|
15619
|
+
const role = Math.max(0, numberValue$3(participant.role));
|
|
15620
|
+
const speakerId = firstOptionalString(participant, [
|
|
15621
|
+
"speaker_id",
|
|
15622
|
+
"speakerId",
|
|
15623
|
+
"id"
|
|
15624
|
+
]) ?? "";
|
|
15625
|
+
const nickname = firstOptionalString(participant, [
|
|
15626
|
+
"nick_name",
|
|
15627
|
+
"nickName",
|
|
15628
|
+
"nickname",
|
|
15629
|
+
"speaker_name",
|
|
15630
|
+
"speakerName",
|
|
15631
|
+
"name"
|
|
15632
|
+
]);
|
|
15633
|
+
const displayName = firstOptionalString(participant, [
|
|
15634
|
+
"display_name",
|
|
15635
|
+
"displayName",
|
|
15636
|
+
"display_name_snapshot",
|
|
15637
|
+
"displayNameSnapshot"
|
|
15638
|
+
]) ?? nickname ?? participantRoleName(role);
|
|
15639
|
+
const refUserId = optionalPositiveNumber$1(participant.ref_usr_id ?? participant.refUsrId ?? participant.ref_user_id ?? participant.refUserId ?? participant.user_id ?? participant.userId);
|
|
15640
|
+
if (displayName === "" && speakerId === "" && refUserId === void 0) return [];
|
|
14861
15641
|
return [{
|
|
14862
|
-
speakerId,
|
|
15642
|
+
speakerId: speakerId === "" ? `participant:${index}` : speakerId,
|
|
14863
15643
|
...refUserId === void 0 ? {} : { refUserId },
|
|
14864
15644
|
...nickname === void 0 ? {} : { nickname },
|
|
14865
15645
|
displayName,
|
|
14866
|
-
role
|
|
15646
|
+
role
|
|
14867
15647
|
}];
|
|
14868
15648
|
});
|
|
14869
|
-
const dateStamp = optionalPositiveNumber$1(item.date_stamp);
|
|
14870
|
-
const timezoneOffsetMillis = numberValue$3(item.tz_offset);
|
|
15649
|
+
const dateStamp = optionalPositiveNumber$1(item.date_stamp ?? item.dateStamp);
|
|
15650
|
+
const timezoneOffsetMillis = numberValue$3(item.tz_offset ?? item.tzOffset ?? item.timezone_offset ?? item.timezoneOffset ?? item.timezoneOffsetMillis);
|
|
15651
|
+
const isSharedByOther = booleanValue$2(item.is_shared_by_other ?? item.isSharedByOther);
|
|
15652
|
+
const sharedByUserId = optionalPositiveNumber$1(item.shared_by_user_id ?? item.sharedByUserId);
|
|
15653
|
+
const itemChatSessionUid = firstOptionalString(item, [
|
|
15654
|
+
"chat_session_uid",
|
|
15655
|
+
"chatSessionUid",
|
|
15656
|
+
"source_chat_session_uid",
|
|
15657
|
+
"sourceChatSessionUid"
|
|
15658
|
+
]) ?? chatSessionUid;
|
|
15659
|
+
const recordUid = firstOptionalString(item, [
|
|
15660
|
+
"record_uid",
|
|
15661
|
+
"recordUid",
|
|
15662
|
+
"shared_record_uid",
|
|
15663
|
+
"sharedRecordUid"
|
|
15664
|
+
]) ?? "";
|
|
15665
|
+
const recordOwnerUserId = optionalPositiveNumber$1(item.record_owner_user_id ?? item.recordOwnerUserId ?? item.owner_user_id ?? item.ownerUserId) ?? sharedByUserId;
|
|
15666
|
+
const sourceRelationUid = firstOptionalString(item, [
|
|
15667
|
+
"source_relation_uid",
|
|
15668
|
+
"sourceRelationUid",
|
|
15669
|
+
"rel_uid",
|
|
15670
|
+
"relUid",
|
|
15671
|
+
"relation_uid",
|
|
15672
|
+
"relationUid"
|
|
15673
|
+
]) ?? "";
|
|
15674
|
+
const sharedSequence = numberValue$3(item.shared_sequence ?? item.sharedSequence ?? item.seq ?? item.sequence);
|
|
15675
|
+
const sharedRecordingDetailRef = isSharedByOther && itemChatSessionUid.trim() !== "" && recordUid.trim() !== "" && recordOwnerUserId !== void 0 && recordOwnerUserId > 0 ? this.sharedRecordingDetailRef({
|
|
15676
|
+
version: 1,
|
|
15677
|
+
viewerUserId: userId,
|
|
15678
|
+
chatSessionUid: itemChatSessionUid.trim(),
|
|
15679
|
+
relationUid: sourceRelationUid.trim(),
|
|
15680
|
+
recordOwnerUserId,
|
|
15681
|
+
recordUid: recordUid.trim(),
|
|
15682
|
+
sequence: Math.max(0, sharedSequence)
|
|
15683
|
+
}, signingKey) : void 0;
|
|
14871
15684
|
return {
|
|
14872
|
-
recordingRef:
|
|
15685
|
+
recordingRef: this.relatedRecordingRef(userId, chatSessionUid, momentId, signingKey),
|
|
15686
|
+
...sharedRecordingDetailRef === void 0 ? {} : { sharedRecordingDetailRef },
|
|
14873
15687
|
startAtMillis,
|
|
14874
|
-
endAtMillis: numberValue$3(item.end_at),
|
|
15688
|
+
endAtMillis: numberValue$3(item.end_at ?? item.endAt ?? item.endAtMillis),
|
|
14875
15689
|
...dateStamp === void 0 ? {} : { dateStamp },
|
|
14876
15690
|
...Number.isSafeInteger(timezoneOffsetMillis) ? { timezoneOffsetMillis } : {},
|
|
14877
|
-
timeRangeText: stringValue$1(item.time_range_text).trim(),
|
|
14878
|
-
title: stringValue$1(item.title).trim(),
|
|
14879
|
-
summary: stringValue$1(item.summary).trim(),
|
|
14880
|
-
summaryStatus: numberValue$3(item.summary_status),
|
|
15691
|
+
timeRangeText: stringValue$1(item.time_range_text ?? item.timeRangeText).trim(),
|
|
15692
|
+
title: stringValue$1(item.title ?? item.orig_name ?? item.origName).trim(),
|
|
15693
|
+
summary: stringValue$1(item.summary ?? item.summary_text ?? item.summaryText).trim(),
|
|
15694
|
+
summaryStatus: numberValue$3(item.summary_status ?? item.summaryStatus),
|
|
14881
15695
|
...transcript === "" ? {} : { transcript },
|
|
14882
|
-
transcriptAvailable: item.transcript_available
|
|
15696
|
+
transcriptAvailable: booleanValue$2(item.transcript_available ?? item.transcriptAvailable) && transcript !== "",
|
|
14883
15697
|
speakers,
|
|
14884
15698
|
participants,
|
|
14885
|
-
isSharedByOther
|
|
15699
|
+
isSharedByOther,
|
|
15700
|
+
...sharedByUserId === void 0 ? {} : { sharedByUserId }
|
|
14886
15701
|
};
|
|
14887
15702
|
}
|
|
14888
|
-
|
|
14889
|
-
return `arkme-related-recording-v1.${createHmac("sha256",
|
|
15703
|
+
relatedRecordingRef(userId, chatSessionUid, momentId, signingKey) {
|
|
15704
|
+
return `arkme-related-recording-v1.${createHmac("sha256", signingKey).update(`related-recording:${userId}:${chatSessionUid}:${momentId}`).digest("base64url")}`;
|
|
15705
|
+
}
|
|
15706
|
+
sharedRecordingDetailRef(payload, signingKey) {
|
|
15707
|
+
const encoded = encodeOpaqueJson$2(payload);
|
|
15708
|
+
return `arkme-shared-recording-detail-v1.${encoded}.${createHmac("sha256", signingKey).update(encoded).digest("base64url")}`;
|
|
14890
15709
|
}
|
|
14891
15710
|
};
|
|
14892
15711
|
function isDshAgentInputSourceTitle(value) {
|
|
@@ -18496,6 +19315,7 @@ var ArkmeService = class {
|
|
|
18496
19315
|
record;
|
|
18497
19316
|
search;
|
|
18498
19317
|
bot;
|
|
19318
|
+
botConversation;
|
|
18499
19319
|
outgoingCall;
|
|
18500
19320
|
world;
|
|
18501
19321
|
arko;
|
|
@@ -18504,6 +19324,7 @@ var ArkmeService = class {
|
|
|
18504
19324
|
community;
|
|
18505
19325
|
realtime;
|
|
18506
19326
|
interwoven;
|
|
19327
|
+
linkMetadata;
|
|
18507
19328
|
aiPolish;
|
|
18508
19329
|
chat;
|
|
18509
19330
|
contact;
|
|
@@ -18513,7 +19334,7 @@ var ArkmeService = class {
|
|
|
18513
19334
|
fileTransfers;
|
|
18514
19335
|
localFileOpener;
|
|
18515
19336
|
worldVoiceprintInviteVariantIndex = 0;
|
|
18516
|
-
constructor(config, sessionStore, stateStore, fetchImpl = fetch, pendingSessionStore, outgoingCallBroker = new ArkmeOutgoingCallBroker(), billingGateway) {
|
|
19337
|
+
constructor(config, sessionStore, stateStore, fetchImpl = fetch, pendingSessionStore, outgoingCallBroker = new ArkmeOutgoingCallBroker(), billingGateway, linkDocumentReader) {
|
|
18517
19338
|
this.config = config;
|
|
18518
19339
|
this.sessionStore = sessionStore;
|
|
18519
19340
|
this.stateStore = stateStore;
|
|
@@ -18551,9 +19372,13 @@ var ArkmeService = class {
|
|
|
18551
19372
|
this.relatedRecording = new RelatedRecordingService(this.runtime, this.source);
|
|
18552
19373
|
this.community = new CommunityService(this.runtime, this.source, this.profile);
|
|
18553
19374
|
this.interwoven = new InterwovenService(this.runtime, this.source, this.profile);
|
|
19375
|
+
this.linkMetadata = new ArkmeLinkMetadataService(linkDocumentReader);
|
|
18554
19376
|
this.aiPolish = new GroupAiPolishService(this.runtime, this.source, { sendChatSourceTextRaw: async (...args) => await this.chat.sendChatSourceTextRaw(...args) });
|
|
18555
19377
|
this.realtime = new ChatRealtimeService(this.runtime, this.source, { chatTimelineItems: async (data, session, chatSessionUid) => await this.chat.chatTimelineItems(data, session, chatSessionUid) });
|
|
18556
19378
|
this.chat = new ChatService(this.runtime, this.source, this.profile, this.media, this.record, this.bot, this.arko, this.aiPolish, this.realtime, this.privacy);
|
|
19379
|
+
this.botConversation = new BotConversationService(this.runtime, this.bot, this.chat, async () => {
|
|
19380
|
+
await this.realtime.invalidateRecordProjection();
|
|
19381
|
+
});
|
|
18557
19382
|
this.contactDirectory = new ContactDirectoryService(this.runtime, this.source, this.bot, this.profile, this.world, this.chat);
|
|
18558
19383
|
this.unmarkedSpeaker = new UnmarkedSpeakerService(this.runtime, this.media);
|
|
18559
19384
|
this.contact = new ContactService(this.runtime, this.source, this.profile, this.realtime);
|
|
@@ -18679,9 +19504,6 @@ var ArkmeService = class {
|
|
|
18679
19504
|
async listBots(options = {}) {
|
|
18680
19505
|
return await this.bot.listBots(options);
|
|
18681
19506
|
}
|
|
18682
|
-
async listBotPrivateChatDirectory(options = {}) {
|
|
18683
|
-
return await this.bot.listBotPrivateChatDirectory(options);
|
|
18684
|
-
}
|
|
18685
19507
|
async createBot(input, options = {}) {
|
|
18686
19508
|
return await this.bot.createBot(input, options);
|
|
18687
19509
|
}
|
|
@@ -18704,21 +19526,28 @@ var ArkmeService = class {
|
|
|
18704
19526
|
await this.bot.deleteManagedBot(botRef, confirmationName, options);
|
|
18705
19527
|
}
|
|
18706
19528
|
async botNotificationPreference(botRef, options = {}) {
|
|
18707
|
-
return await this.
|
|
19529
|
+
return await this.botConversation.notificationPreference(botRef, options);
|
|
18708
19530
|
}
|
|
18709
19531
|
async updateBotNotificationPreference(botRef, muted, options = {}) {
|
|
18710
|
-
return await this.
|
|
19532
|
+
return await this.botConversation.updateNotificationPreference(botRef, muted, options);
|
|
18711
19533
|
}
|
|
18712
19534
|
async openBotChat(botRef, options = {}) {
|
|
18713
19535
|
return await this.bot.openBotChat(botRef, options);
|
|
18714
19536
|
}
|
|
19537
|
+
async listBotPrivateChatDirectory(options = {}) {
|
|
19538
|
+
return await this.botConversation.directory(options);
|
|
19539
|
+
}
|
|
18715
19540
|
async openBotPrivateChat(botRef, options = {}) {
|
|
18716
|
-
return await this.
|
|
19541
|
+
return await this.botConversation.open(botRef, options);
|
|
19542
|
+
}
|
|
19543
|
+
async refreshBotPrivateChat(botRef, options = {}) {
|
|
19544
|
+
return await this.botConversation.refresh(botRef, options);
|
|
18717
19545
|
}
|
|
18718
19546
|
async sendBotPrivateChatMessage(botRef, content, options = {}) {
|
|
18719
|
-
|
|
18720
|
-
|
|
18721
|
-
|
|
19547
|
+
return await this.botConversation.send(botRef, content, options);
|
|
19548
|
+
}
|
|
19549
|
+
async markBotPrivateChatRead(botRef, sequence, options = {}) {
|
|
19550
|
+
return await this.botConversation.markRead(botRef, sequence, options);
|
|
18722
19551
|
}
|
|
18723
19552
|
async listGroupBots(groupSourceRef, options = {}) {
|
|
18724
19553
|
return await this.bot.listGroupBots(groupSourceRef, options);
|
|
@@ -18735,6 +19564,12 @@ var ArkmeService = class {
|
|
|
18735
19564
|
async authStatus() {
|
|
18736
19565
|
return await this.auth.authStatus();
|
|
18737
19566
|
}
|
|
19567
|
+
async dshRemoteGet(path, signal) {
|
|
19568
|
+
return await this.runtime.authenticatedDshRemoteGet(path, signal);
|
|
19569
|
+
}
|
|
19570
|
+
async dshRemotePost(path, body, signal) {
|
|
19571
|
+
return await this.runtime.authenticatedDshRemotePost(path, body, void 0, signal);
|
|
19572
|
+
}
|
|
18738
19573
|
clientConfig() {
|
|
18739
19574
|
return {
|
|
18740
19575
|
captchaId: this.config.geetestCaptchaId,
|
|
@@ -18889,10 +19724,14 @@ var ArkmeService = class {
|
|
|
18889
19724
|
this.outgoingCall.dispose();
|
|
18890
19725
|
this.interwoven.dispose();
|
|
18891
19726
|
this.world.dispose();
|
|
19727
|
+
this.linkMetadata.dispose();
|
|
18892
19728
|
}
|
|
18893
19729
|
requestStats() {
|
|
18894
19730
|
return this.runtime.requestStats();
|
|
18895
19731
|
}
|
|
19732
|
+
async resolveLinkMetadata(url, options = {}) {
|
|
19733
|
+
return await this.linkMetadata.resolve(url, options);
|
|
19734
|
+
}
|
|
18896
19735
|
async cachedProfile() {
|
|
18897
19736
|
return await this.profile.cachedProfile();
|
|
18898
19737
|
}
|
|
@@ -19170,6 +20009,9 @@ var ArkmeService = class {
|
|
|
19170
20009
|
async readSource(sourceRef, options = {}) {
|
|
19171
20010
|
return await this.chat.readSource(sourceRef, options);
|
|
19172
20011
|
}
|
|
20012
|
+
async sharedRecordingDetail(detailRef, options = {}) {
|
|
20013
|
+
return await this.chat.sharedRecordingDetail(detailRef, options);
|
|
20014
|
+
}
|
|
19173
20015
|
async messageReadReceiptSummaries(sourceRef, items, options = {}) {
|
|
19174
20016
|
return await this.chat.messageReadReceiptSummaries(sourceRef, items, options);
|
|
19175
20017
|
}
|
|
@@ -19197,9 +20039,6 @@ var ArkmeService = class {
|
|
|
19197
20039
|
async extendMessageCopyLink(sid, itemIndex, textContent, recordUid, options = {}) {
|
|
19198
20040
|
return await this.chat.extendMessageCopyLink(sid, itemIndex, textContent, recordUid, options);
|
|
19199
20041
|
}
|
|
19200
|
-
async resolveLinkMetadata(rawUrl, options = {}) {
|
|
19201
|
-
return await this.chat.resolveLinkMetadata(rawUrl, options);
|
|
19202
|
-
}
|
|
19203
20042
|
async forwardSourceMessages(sourceRef, actionRefs, options = {}) {
|
|
19204
20043
|
return await this.chat.forwardSourceMessages(sourceRef, actionRefs, options);
|
|
19205
20044
|
}
|