@senguoyun/dsh-arkme 0.1.12 → 0.1.13
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/README.md +2 -2
- package/assets/desktop_call/avatar-lin-xiaoman.jpeg +0 -0
- package/assets/desktop_call/avatar-mother.jpg +0 -0
- package/assets/desktop_call/avatar-self.png +0 -0
- package/assets/desktop_call/call-add-linear.svg +13 -0
- package/assets/desktop_call/icon-scan-add-contact.svg +4 -0
- package/assets/desktop_call/profile-circle-linear.svg +11 -0
- package/assets/desktop_call/user-add-linear.svg +15 -0
- package/cordis.patch.yml +4 -1
- package/docs/consumer-plugin-contract.md +13 -4
- package/docs/extension-market-controls.md +1 -1
- package/docs/gui-production-integration.md +1 -1
- package/lib/client.js +27533 -5149
- package/lib/client.js.map +1 -1
- package/lib/extension-profile-restart-helper.js +19 -3
- package/lib/index.js +1498 -380
- package/lib/{install-store-D6P-dH2i.js → install-store-Sn3Ccxfu.js} +32 -5
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-kUpXXUZI.js → persistent-runtime-Cki0XC3L.js} +826 -183
- package/lib/plugin-updater-helper-CiPlNqBc.js +346 -0
- package/lib/plugin-updater-helper.js +2 -250
- package/lib/sdk.js +114 -2
- package/lib/types/arkme-service.d.ts +30 -2
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeAppUpdateDialog.d.ts +5 -0
- package/lib/types/client/ArkmeAppUpdateDialog.d.ts.map +1 -0
- package/lib/types/client/ArkmeCallHistorySurface.d.ts +57 -0
- package/lib/types/client/ArkmeCallHistorySurface.d.ts.map +1 -0
- package/lib/types/client/ArkmeContactAddSurface.d.ts +9 -0
- package/lib/types/client/ArkmeContactAddSurface.d.ts.map +1 -0
- package/lib/types/client/ArkmeExtensionPublishDialog.d.ts.map +1 -1
- package/lib/types/client/ArkmeExtensionReviews.d.ts +10 -0
- package/lib/types/client/ArkmeExtensionReviews.d.ts.map +1 -1
- package/lib/types/client/ArkmeMarketplace.d.ts +153 -0
- package/lib/types/client/ArkmeMarketplace.d.ts.map +1 -0
- package/lib/types/client/ArkmeProductNavigation.d.ts.map +1 -1
- package/lib/types/client/ArkmeQuickAdd.d.ts +12 -0
- package/lib/types/client/ArkmeQuickAdd.d.ts.map +1 -0
- package/lib/types/client/ArkmeRecordingSurface.d.ts +109 -3
- package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSettingsSurface.d.ts +20 -0
- package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts +12 -0
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/ArkmeWorldSurface.d.ts +30 -0
- package/lib/types/client/ArkmeWorldSurface.d.ts.map +1 -0
- package/lib/types/client/api.d.ts +1 -1
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/app-update-store.d.ts +35 -0
- package/lib/types/client/app-update-store.d.ts.map +1 -0
- package/lib/types/client/demo-audio.d.ts +2 -0
- package/lib/types/client/demo-audio.d.ts.map +1 -0
- package/lib/types/client/extension-market-model.d.ts +1 -0
- package/lib/types/client/extension-market-model.d.ts.map +1 -1
- package/lib/types/client/index.d.ts +8 -2
- package/lib/types/client/index.d.ts.map +1 -1
- package/lib/types/client/personal-test-edition.d.ts +17 -0
- package/lib/types/client/personal-test-edition.d.ts.map +1 -0
- package/lib/types/client/ui-controller.d.ts +4 -1
- package/lib/types/client/ui-controller.d.ts.map +1 -1
- package/lib/types/extensions/bundle-artifact.d.ts +22 -0
- package/lib/types/extensions/bundle-artifact.d.ts.map +1 -1
- package/lib/types/extensions/install-store.d.ts +1 -0
- package/lib/types/extensions/install-store.d.ts.map +1 -1
- package/lib/types/extensions/manager.d.ts +35 -2
- package/lib/types/extensions/manager.d.ts.map +1 -1
- package/lib/types/extensions/owned-inventory.d.ts +2 -2
- package/lib/types/extensions/owned-inventory.d.ts.map +1 -1
- package/lib/types/extensions/owned-refs.d.ts +1 -1
- package/lib/types/extensions/owned-refs.d.ts.map +1 -1
- package/lib/types/extensions/owned-types.d.ts +18 -5
- package/lib/types/extensions/owned-types.d.ts.map +1 -1
- package/lib/types/extensions/profile-owned-inventory.d.ts +1 -0
- package/lib/types/extensions/profile-owned-inventory.d.ts.map +1 -1
- package/lib/types/extensions/profile-restart-helper.d.ts.map +1 -1
- package/lib/types/extensions/publish-client.d.ts +47 -2
- package/lib/types/extensions/publish-client.d.ts.map +1 -1
- package/lib/types/extensions/signature.d.ts +31 -1
- package/lib/types/extensions/signature.d.ts.map +1 -1
- package/lib/types/extensions/types.d.ts +71 -5
- package/lib/types/extensions/types.d.ts.map +1 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts +8 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/outgoing-call-assets.d.ts.map +1 -1
- package/lib/types/plugin-update-artifact.d.ts +46 -0
- package/lib/types/plugin-update-artifact.d.ts.map +1 -0
- package/lib/types/plugin-update.d.ts +20 -11
- package/lib/types/plugin-update.d.ts.map +1 -1
- package/lib/types/plugin-updater-helper.d.ts +11 -0
- package/lib/types/plugin-updater-helper.d.ts.map +1 -1
- package/lib/types/recording-presentation.d.ts +2 -2
- package/lib/types/recording-presentation.d.ts.map +1 -1
- package/lib/types/sdk/index.d.ts +63 -7
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/bot-service.d.ts +5 -1
- package/lib/types/services/bot-service.d.ts.map +1 -1
- package/lib/types/services/contact-service.d.ts +25 -0
- package/lib/types/services/contact-service.d.ts.map +1 -0
- package/lib/types/services/group-service.d.ts +4 -1
- package/lib/types/services/group-service.d.ts.map +1 -1
- package/lib/types/services/recording-service.d.ts +4 -2
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts +1 -0
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/services/world-service.d.ts +13 -0
- package/lib/types/services/world-service.d.ts.map +1 -1
- package/lib/types/tools/business/contacts/index.d.ts +4 -0
- package/lib/types/tools/business/contacts/index.d.ts.map +1 -0
- package/lib/types/tools/business/groups/create.d.ts +2 -0
- package/lib/types/tools/business/groups/create.d.ts.map +1 -0
- package/lib/types/tools/business/groups/index.d.ts +1 -0
- package/lib/types/tools/business/groups/index.d.ts.map +1 -1
- package/lib/types/tools/business/index.d.ts.map +1 -1
- package/lib/types/tools/business/recordings/index.d.ts +2 -1
- package/lib/types/tools/business/recordings/index.d.ts.map +1 -1
- package/lib/types/tools/business/world/index.d.ts +2 -0
- package/lib/types/tools/business/world/index.d.ts.map +1 -1
- package/lib/types/tools/business/world/mine.d.ts +2 -0
- package/lib/types/tools/business/world/mine.d.ts.map +1 -0
- package/lib/types/tools/business/world/voiceprint-invite.d.ts +2 -0
- package/lib/types/tools/business/world/voiceprint-invite.d.ts.map +1 -0
- package/lib/types/tools/extensions/index.d.ts.map +1 -1
- package/lib/types/tools/extensions/publish-conversation.d.ts +8 -1
- package/lib/types/tools/extensions/publish-conversation.d.ts.map +1 -1
- package/lib/types/tools/ports/contacts.d.ts +12 -0
- package/lib/types/tools/ports/contacts.d.ts.map +1 -0
- package/lib/types/tools/ports/groups.d.ts +4 -1
- package/lib/types/tools/ports/groups.d.ts.map +1 -1
- package/lib/types/tools/ports/index.d.ts +3 -2
- package/lib/types/tools/ports/index.d.ts.map +1 -1
- package/lib/types/tools/ports/recordings.d.ts +3 -2
- package/lib/types/tools/ports/recordings.d.ts.map +1 -1
- package/lib/types/tools/ports/world.d.ts +12 -1
- package/lib/types/tools/ports/world.d.ts.map +1 -1
- package/lib/types/tools/prompts/business.d.ts.map +1 -1
- package/lib/types/tools/registry/registrar.d.ts.map +1 -1
- package/lib/types/types.d.ts +48 -3
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -4
- package/lib/plugin-update-install-state-CIsOCjWK.js +0 -67
- package/lib/types/client/ArkmeExtensionCenter.d.ts +0 -74
- package/lib/types/client/ArkmeExtensionCenter.d.ts.map +0 -1
|
@@ -4,10 +4,10 @@ import { dirname, isAbsolute, join, posix, relative, resolve, sep } from "node:p
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { open } from "node:fs/promises";
|
|
6
6
|
import OSS from "ali-oss";
|
|
7
|
+
import { gunzipSync, gzipSync } from "node:zlib";
|
|
7
8
|
import { createContext, runInContext } from "node:vm";
|
|
8
9
|
import { Context } from "@deepseek-ai/cordis";
|
|
9
10
|
import { defineTool } from "@deepseek-ai/dsh-tools";
|
|
10
|
-
import { gunzipSync, gzipSync } from "node:zlib";
|
|
11
11
|
import { parseDocument } from "yaml";
|
|
12
12
|
//#region src/outgoing-call-contract.ts
|
|
13
13
|
var ArkmeOutgoingCallError = class extends Error {
|
|
@@ -1072,7 +1072,7 @@ var ServiceRuntime = class {
|
|
|
1072
1072
|
}
|
|
1073
1073
|
async extensionPost(path, body, signal, options = {}) {
|
|
1074
1074
|
const baseUrl = this.config.extensionPublishBaseUrl?.trim() ?? "";
|
|
1075
|
-
if (baseUrl === "") throw new ArkmePluginError("extension-service-disabled", "
|
|
1075
|
+
if (baseUrl === "") throw new ArkmePluginError("extension-service-disabled", "市集服务尚未配置", false, 503);
|
|
1076
1076
|
let session = await this.requireSession();
|
|
1077
1077
|
const requestOptions = () => ({
|
|
1078
1078
|
...options,
|
|
@@ -1091,10 +1091,10 @@ var ServiceRuntime = class {
|
|
|
1091
1091
|
};
|
|
1092
1092
|
//#endregion
|
|
1093
1093
|
//#region src/services/ai-video-service.ts
|
|
1094
|
-
function numberValue$
|
|
1094
|
+
function numberValue$22(value) {
|
|
1095
1095
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1096
1096
|
}
|
|
1097
|
-
function booleanValue$
|
|
1097
|
+
function booleanValue$13(value) {
|
|
1098
1098
|
return value === true;
|
|
1099
1099
|
}
|
|
1100
1100
|
function listValue$21(value) {
|
|
@@ -1109,12 +1109,12 @@ var AiVideoService = class {
|
|
|
1109
1109
|
const session = await this.runtime.requireSession();
|
|
1110
1110
|
const data = await this.runtime.authenticatedIntelligentPost("/api/v1/ai-comic-video/preflight", this.aiVideoSelectionBody(sessionId, segments), session, signal);
|
|
1111
1111
|
return {
|
|
1112
|
-
allowed: booleanValue$
|
|
1112
|
+
allowed: booleanValue$13(data.allowed),
|
|
1113
1113
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
1114
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1115
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
1116
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
1117
|
-
retryable: booleanValue$
|
|
1114
|
+
selectedDurationMillis: Math.max(0, numberValue$22(data.selected_duration_millis)),
|
|
1115
|
+
minimumDurationMillis: Math.max(0, numberValue$22(data.minimum_duration_millis)),
|
|
1116
|
+
selectedSegmentCount: Math.max(0, numberValue$22(data.selected_segment_count)),
|
|
1117
|
+
retryable: booleanValue$13(data.retryable),
|
|
1118
1118
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
1119
1119
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
1120
1120
|
};
|
|
@@ -1150,7 +1150,7 @@ var AiVideoService = class {
|
|
|
1150
1150
|
}, session, options.signal);
|
|
1151
1151
|
return {
|
|
1152
1152
|
items: listValue$21(data.items).map((raw) => this.aiVideoListItem(raw)).filter((item) => item !== void 0),
|
|
1153
|
-
hasMore: booleanValue$
|
|
1153
|
+
hasMore: booleanValue$13(data.has_more),
|
|
1154
1154
|
...stringValue$1(data.next_cursor).trim() === "" ? {} : { nextCursor: stringValue$1(data.next_cursor).trim() }
|
|
1155
1155
|
};
|
|
1156
1156
|
}
|
|
@@ -1161,13 +1161,13 @@ var AiVideoService = class {
|
|
|
1161
1161
|
texts
|
|
1162
1162
|
}, session, signal);
|
|
1163
1163
|
return {
|
|
1164
|
-
allowed: booleanValue$
|
|
1164
|
+
allowed: booleanValue$13(data.allowed),
|
|
1165
1165
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
1166
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1167
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
1168
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
1169
|
-
selectedTextCount: Math.max(0, numberValue$
|
|
1170
|
-
retryable: booleanValue$
|
|
1166
|
+
selectedDurationMillis: Math.max(0, numberValue$22(data.selected_duration_millis)),
|
|
1167
|
+
minimumDurationMillis: Math.max(0, numberValue$22(data.minimum_duration_millis)),
|
|
1168
|
+
selectedSegmentCount: Math.max(0, numberValue$22(data.selected_segment_count)),
|
|
1169
|
+
selectedTextCount: Math.max(0, numberValue$22(data.selected_text_count)),
|
|
1170
|
+
retryable: booleanValue$13(data.retryable),
|
|
1171
1171
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
1172
1172
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
1173
1173
|
};
|
|
@@ -1212,13 +1212,13 @@ var AiVideoService = class {
|
|
|
1212
1212
|
jobId,
|
|
1213
1213
|
status,
|
|
1214
1214
|
stage: stringValue$1(data.stage).trim() || status,
|
|
1215
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
1215
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$22(data.progress)))),
|
|
1216
1216
|
selectedSegmentCount: segmentCount,
|
|
1217
1217
|
...textCount === 0 ? {} : { selectedTextCount: textCount },
|
|
1218
|
-
retryable: booleanValue$
|
|
1218
|
+
retryable: booleanValue$13(data.retryable),
|
|
1219
1219
|
...stringValue$1(data.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(data.video_asset_uid).trim() },
|
|
1220
1220
|
...stringValue$1(data.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(data.cover_asset_uid).trim() },
|
|
1221
|
-
...numberValue$
|
|
1221
|
+
...numberValue$22(data.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$22(data.video_duration_millis) },
|
|
1222
1222
|
...stringValue$1(data.error_code).trim() === "" ? {} : { errorCode: stringValue$1(data.error_code).trim() },
|
|
1223
1223
|
...stringValue$1(data.error_message).trim() === "" ? {} : { errorMessage: stringValue$1(data.error_message).trim() },
|
|
1224
1224
|
...stringValue$1(data.failure_stage).trim() === "" ? {} : { failureStage: stringValue$1(data.failure_stage).trim() }
|
|
@@ -1241,17 +1241,17 @@ var AiVideoService = class {
|
|
|
1241
1241
|
sessionId: stringValue$1(item.session_id).trim(),
|
|
1242
1242
|
status,
|
|
1243
1243
|
stage: stringValue$1(item.stage).trim() || status,
|
|
1244
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
1244
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$22(item.progress)))),
|
|
1245
1245
|
title: stringValue$1(source.title).trim() || "长录音 AI 视频",
|
|
1246
|
-
sourceStartedAtMillis: numberValue$
|
|
1247
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
1248
|
-
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$
|
|
1249
|
-
retryable: booleanValue$
|
|
1250
|
-
createdAtMillis: numberValue$
|
|
1251
|
-
updatedAtMillis: numberValue$
|
|
1246
|
+
sourceStartedAtMillis: numberValue$22(source.started_at),
|
|
1247
|
+
selectedDurationMillis: Math.max(0, numberValue$22(source.selected_duration_millis)),
|
|
1248
|
+
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$22(item.selected_segment_count))),
|
|
1249
|
+
retryable: booleanValue$13(item.retryable),
|
|
1250
|
+
createdAtMillis: numberValue$22(item.created_at),
|
|
1251
|
+
updatedAtMillis: numberValue$22(item.updated_at),
|
|
1252
1252
|
...stringValue$1(item.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(item.cover_asset_uid).trim() },
|
|
1253
1253
|
...stringValue$1(item.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(item.video_asset_uid).trim() },
|
|
1254
|
-
...numberValue$
|
|
1254
|
+
...numberValue$22(item.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$22(item.video_duration_millis) },
|
|
1255
1255
|
...stringValue$1(item.error_code).trim() === "" ? {} : { errorCode: stringValue$1(item.error_code).trim() },
|
|
1256
1256
|
...stringValue$1(item.error_message).trim() === "" ? {} : { errorMessage: clippedText(item.error_message, 500) }
|
|
1257
1257
|
};
|
|
@@ -1277,10 +1277,10 @@ const ARKO_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
|
1277
1277
|
"expired"
|
|
1278
1278
|
]);
|
|
1279
1279
|
const ARKO_PROFILE_DISPLAY_NAME_CACHE_TTL_MS = 10 * 6e4;
|
|
1280
|
-
function numberValue$
|
|
1280
|
+
function numberValue$21(value) {
|
|
1281
1281
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1282
1282
|
}
|
|
1283
|
-
function booleanValue$
|
|
1283
|
+
function booleanValue$12(value) {
|
|
1284
1284
|
return value === true;
|
|
1285
1285
|
}
|
|
1286
1286
|
function listValue$20(value) {
|
|
@@ -1312,7 +1312,7 @@ function joinUrlWithQuery(baseUrl, path, query) {
|
|
|
1312
1312
|
}
|
|
1313
1313
|
function arkoProfileFromData(data) {
|
|
1314
1314
|
const displayName = stringValue$1(data.display_name).trim();
|
|
1315
|
-
const version = numberValue$
|
|
1315
|
+
const version = numberValue$21(data.version);
|
|
1316
1316
|
if (displayName === "" || !Number.isSafeInteger(version) || version < 0) throw new ArkmePluginError("arko-profile-contract-invalid", "Arko 资料响应不完整", true, 502);
|
|
1317
1317
|
return {
|
|
1318
1318
|
displayName,
|
|
@@ -1336,8 +1336,8 @@ function arkoModelOptionFromData(value) {
|
|
|
1336
1336
|
displayName,
|
|
1337
1337
|
provider,
|
|
1338
1338
|
description,
|
|
1339
|
-
recommended: booleanValue$
|
|
1340
|
-
selected: booleanValue$
|
|
1339
|
+
recommended: booleanValue$12(data.recommended),
|
|
1340
|
+
selected: booleanValue$12(data.selected)
|
|
1341
1341
|
};
|
|
1342
1342
|
}
|
|
1343
1343
|
function arkoModelCatalogFromData(data) {
|
|
@@ -1365,12 +1365,12 @@ function parsedJsonRecord(value) {
|
|
|
1365
1365
|
}
|
|
1366
1366
|
function arkoHistoryItemFromData(value) {
|
|
1367
1367
|
const data = objectValue$1(value);
|
|
1368
|
-
const messageId = numberValue$
|
|
1369
|
-
const sessionId = numberValue$
|
|
1370
|
-
const roleCode = numberValue$
|
|
1368
|
+
const messageId = numberValue$21(data.id ?? data.msg_id ?? data.msgId);
|
|
1369
|
+
const sessionId = numberValue$21(data.session_id ?? data.sessionId);
|
|
1370
|
+
const roleCode = numberValue$21(data.role ?? data.sender_role ?? data.senderRole);
|
|
1371
1371
|
if (!Number.isSafeInteger(messageId) || messageId <= 0 || !Number.isSafeInteger(sessionId) || sessionId <= 0 || roleCode !== 2 && roleCode !== 3) return void 0;
|
|
1372
1372
|
const extra = parsedJsonRecord(data.extra ?? data.metadata ?? data.meta);
|
|
1373
|
-
const createdAt = numberValue$
|
|
1373
|
+
const createdAt = numberValue$21(data.created_at ?? data.create_at ?? data.createdAt ?? data.createAt);
|
|
1374
1374
|
const runUid = optionalString$3(extra.agent_run_uid);
|
|
1375
1375
|
const runStatus = optionalString$3(extra.agent_run_status);
|
|
1376
1376
|
const retryable = optionalBooleanValue$1(extra.agent_run_retryable);
|
|
@@ -1383,7 +1383,7 @@ function arkoHistoryItemFromData(value) {
|
|
|
1383
1383
|
text: stringValue$1(data.content ?? data.text_content ?? data.textContent),
|
|
1384
1384
|
reasoning: stringValue$1(data.reason_content ?? data.reason_text ?? data.reasonText),
|
|
1385
1385
|
createdAtMillis: createdAt > 0 && createdAt < 1e11 ? createdAt * 1e3 : createdAt,
|
|
1386
|
-
status: numberValue$
|
|
1386
|
+
status: numberValue$21(data.status ?? data.msg_status),
|
|
1387
1387
|
...runUid === void 0 ? {} : { runUid },
|
|
1388
1388
|
...runStatus === void 0 ? {} : { runStatus },
|
|
1389
1389
|
...retryable === void 0 ? {} : { retryable },
|
|
@@ -1402,7 +1402,7 @@ function arkoRunProjectionFromData(data) {
|
|
|
1402
1402
|
return {
|
|
1403
1403
|
runUid,
|
|
1404
1404
|
status,
|
|
1405
|
-
retryable: booleanValue$
|
|
1405
|
+
retryable: booleanValue$12(data.agent_run_retryable ?? data.retryable),
|
|
1406
1406
|
...errorCode === "" ? {} : { errorCode },
|
|
1407
1407
|
...retryOfRunUid === "" ? {} : { retryOfRunUid },
|
|
1408
1408
|
...clientAction === void 0 ? {} : { clientAction }
|
|
@@ -1438,7 +1438,7 @@ var ArkoService = class {
|
|
|
1438
1438
|
async arkoEnsureSession(signal) {
|
|
1439
1439
|
const session = await this.runtime.requireSession();
|
|
1440
1440
|
const latest = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/latest-session", { type: ARKO_AGENT_DIRECT_SESSION_TYPE }, session, signal);
|
|
1441
|
-
const latestSessionId = numberValue$
|
|
1441
|
+
const latestSessionId = numberValue$21(latest.id);
|
|
1442
1442
|
if (Number.isSafeInteger(latestSessionId) && latestSessionId > 0) return {
|
|
1443
1443
|
sessionId: latestSessionId,
|
|
1444
1444
|
created: false,
|
|
@@ -1448,7 +1448,7 @@ var ArkoService = class {
|
|
|
1448
1448
|
}
|
|
1449
1449
|
async arkoCreateSession(signal) {
|
|
1450
1450
|
const session = await this.runtime.requireSession();
|
|
1451
|
-
const createdSessionId = numberValue$
|
|
1451
|
+
const createdSessionId = numberValue$21((await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-session", {
|
|
1452
1452
|
name: ARKO_DEFAULT_SESSION_NAME,
|
|
1453
1453
|
type: ARKO_AGENT_DIRECT_SESSION_TYPE
|
|
1454
1454
|
}, session, signal)).session_id);
|
|
@@ -1516,9 +1516,9 @@ var ArkoService = class {
|
|
|
1516
1516
|
};
|
|
1517
1517
|
if (modelRouteKey !== "") body.model_route_key = modelRouteKey;
|
|
1518
1518
|
const accepted = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-msg-v2", body, session, options.signal);
|
|
1519
|
-
const userMsgId = numberValue$
|
|
1520
|
-
const assistantMsgId = numberValue$
|
|
1521
|
-
const acceptedSessionId = numberValue$
|
|
1519
|
+
const userMsgId = numberValue$21(accepted.user_msg_id);
|
|
1520
|
+
const assistantMsgId = numberValue$21(accepted.assistant_msg_id);
|
|
1521
|
+
const acceptedSessionId = numberValue$21(accepted.session_id) || sessionId;
|
|
1522
1522
|
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);
|
|
1523
1523
|
const runUid = stringValue$1(accepted.run_uid).trim();
|
|
1524
1524
|
if (runUid === "") throw new ArkmePluginError("arko-ask-contract-invalid", "Arko 消息响应缺少运行标识", true, 502);
|
|
@@ -1554,8 +1554,8 @@ var ArkoService = class {
|
|
|
1554
1554
|
}, session, signal);
|
|
1555
1555
|
const status = stringValue$1(data.status).trim();
|
|
1556
1556
|
const normalizedRunUid = stringValue$1(data.run_uid).trim() || runUid.trim();
|
|
1557
|
-
const sequence = numberValue$
|
|
1558
|
-
const surfaceAssistantMsgId = numberValue$
|
|
1557
|
+
const sequence = numberValue$21(data.sequence);
|
|
1558
|
+
const surfaceAssistantMsgId = numberValue$21(data.surface_assistant_msg_id);
|
|
1559
1559
|
const clientAction = optionalRecord(data.client_action);
|
|
1560
1560
|
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);
|
|
1561
1561
|
return {
|
|
@@ -1564,7 +1564,7 @@ var ArkoService = class {
|
|
|
1564
1564
|
status,
|
|
1565
1565
|
sequence,
|
|
1566
1566
|
surfaceAssistantMsgId,
|
|
1567
|
-
retryable: booleanValue$
|
|
1567
|
+
retryable: booleanValue$12(data.retryable),
|
|
1568
1568
|
...stringValue$1(data.error_code).trim() === "" ? {} : { errorCode: stringValue$1(data.error_code).trim() },
|
|
1569
1569
|
...stringValue$1(data.retry_of_run_uid).trim() === "" ? {} : { retryOfRunUid: stringValue$1(data.retry_of_run_uid).trim() },
|
|
1570
1570
|
...clientAction === void 0 ? {} : { clientAction }
|
|
@@ -1739,12 +1739,12 @@ var ArkoService = class {
|
|
|
1739
1739
|
if (tailRun !== void 0) {
|
|
1740
1740
|
run = tailRun;
|
|
1741
1741
|
status = tailRun.status;
|
|
1742
|
-
} else if (booleanValue$
|
|
1742
|
+
} else if (booleanValue$12(tail.error) || stringValue$1(tail.status).trim() === "error") status = "failed";
|
|
1743
1743
|
else status = ARKO_COMPLETED_STATUS;
|
|
1744
1744
|
createdRecordUids = arkoCreatedRecordUids(tail.created_record_uids);
|
|
1745
1745
|
const nextProfile = optionalRecord(tail.agent_profile);
|
|
1746
1746
|
if (nextProfile !== void 0) profile = arkoProfileFromData(nextProfile);
|
|
1747
|
-
if (booleanValue$
|
|
1747
|
+
if (booleanValue$12(tail.error) || stringValue$1(tail.status).trim() === "error") errorMessage = stringValue$1(tail.error_message).trim() || "Arko 执行失败";
|
|
1748
1748
|
}
|
|
1749
1749
|
const type = stringValue$1(frame.type ?? frame.event).trim();
|
|
1750
1750
|
const payload = optionalRecord(frame.payload) ?? frame;
|
|
@@ -1793,10 +1793,10 @@ const ARKME_ARRANGEMENT_REF_TTL_MILLIS = 900 * 1e3;
|
|
|
1793
1793
|
const MAX_ARKME_ARRANGEMENT_REFS = 4096;
|
|
1794
1794
|
const ARKME_ARRANGEMENT_REMINDER_REF_TTL_MILLIS = 900 * 1e3;
|
|
1795
1795
|
const MAX_ARKME_ARRANGEMENT_REMINDER_REFS = 4096;
|
|
1796
|
-
function numberValue$
|
|
1796
|
+
function numberValue$20(value) {
|
|
1797
1797
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1798
1798
|
}
|
|
1799
|
-
function booleanValue$
|
|
1799
|
+
function booleanValue$11(value) {
|
|
1800
1800
|
return value === true;
|
|
1801
1801
|
}
|
|
1802
1802
|
function listValue$19(value) {
|
|
@@ -1809,7 +1809,7 @@ function arrangementStatusCode(status) {
|
|
|
1809
1809
|
return -1;
|
|
1810
1810
|
}
|
|
1811
1811
|
function arrangementStatus(value) {
|
|
1812
|
-
const code = Math.trunc(numberValue$
|
|
1812
|
+
const code = Math.trunc(numberValue$20(value));
|
|
1813
1813
|
if (code === 1) return "identified";
|
|
1814
1814
|
if (code === 2) return "following";
|
|
1815
1815
|
if (code === 3) return "completed";
|
|
@@ -1860,7 +1860,7 @@ var ArrangementService = class {
|
|
|
1860
1860
|
}, session, options.signal, { lane: "interactive-read" });
|
|
1861
1861
|
const rawItems = listValue$19(data.list);
|
|
1862
1862
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementItem(raw, session.userId)));
|
|
1863
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
1863
|
+
const total = Math.max(0, Math.trunc(numberValue$20(data.total)));
|
|
1864
1864
|
const nextOffset = offset + rawItems.length;
|
|
1865
1865
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
1866
1866
|
return {
|
|
@@ -1886,7 +1886,7 @@ var ArrangementService = class {
|
|
|
1886
1886
|
}, session, options.signal, { lane: "interactive-read" });
|
|
1887
1887
|
const rawItems = listValue$19(data.list);
|
|
1888
1888
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementReminderEvent(raw, session.userId)));
|
|
1889
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
1889
|
+
const total = Math.max(0, Math.trunc(numberValue$20(data.total)));
|
|
1890
1890
|
const nextOffset = offset + rawItems.length;
|
|
1891
1891
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
1892
1892
|
return {
|
|
@@ -1909,7 +1909,7 @@ var ArrangementService = class {
|
|
|
1909
1909
|
project(data.next_reminder)
|
|
1910
1910
|
]);
|
|
1911
1911
|
return {
|
|
1912
|
-
unreadCount: Math.max(0, Math.trunc(numberValue$
|
|
1912
|
+
unreadCount: Math.max(0, Math.trunc(numberValue$20(data.unread_count))),
|
|
1913
1913
|
...latestUnread === void 0 ? {} : { latestUnread },
|
|
1914
1914
|
...latestEvent === void 0 ? {} : { latestEvent },
|
|
1915
1915
|
...nextReminder === void 0 ? {} : { nextReminder }
|
|
@@ -2013,7 +2013,7 @@ var ArrangementService = class {
|
|
|
2013
2013
|
}, session, signal);
|
|
2014
2014
|
return {
|
|
2015
2015
|
outcome: "confirmed",
|
|
2016
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2016
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$20(data.updated_count)))
|
|
2017
2017
|
};
|
|
2018
2018
|
} catch (error) {
|
|
2019
2019
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2031,7 +2031,7 @@ var ArrangementService = class {
|
|
|
2031
2031
|
}, session, signal);
|
|
2032
2032
|
return {
|
|
2033
2033
|
outcome: "confirmed",
|
|
2034
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2034
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$20(data.updated_count)))
|
|
2035
2035
|
};
|
|
2036
2036
|
} catch (error) {
|
|
2037
2037
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2046,7 +2046,7 @@ var ArrangementService = class {
|
|
|
2046
2046
|
const data = await this.runtime.authenticatedIntelligentPost("/api/v1/arrangements/reminders/clear", {}, session, signal);
|
|
2047
2047
|
return {
|
|
2048
2048
|
outcome: "confirmed",
|
|
2049
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
2049
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$20(data.updated_count)))
|
|
2050
2050
|
};
|
|
2051
2051
|
} catch (error) {
|
|
2052
2052
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -2110,17 +2110,17 @@ var ArrangementService = class {
|
|
|
2110
2110
|
const item = objectValue$1(raw);
|
|
2111
2111
|
const arrangementUid = stringValue$1(item.uid).trim();
|
|
2112
2112
|
if (arrangementUid === "") throw new ArkmePluginError("arrangement-contract-invalid", "安排响应缺少业务身份", true, 502);
|
|
2113
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
2114
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
2113
|
+
const dueAtMillis = Math.trunc(numberValue$20(item.due_at));
|
|
2114
|
+
const remindAtMillis = Math.trunc(numberValue$20(item.remind_at));
|
|
2115
2115
|
return {
|
|
2116
2116
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
2117
2117
|
title: stringValue$1(item.title),
|
|
2118
2118
|
description: stringValue$1(item.description),
|
|
2119
2119
|
status: arrangementStatus(item.status),
|
|
2120
|
-
reminderEnabled: booleanValue$
|
|
2120
|
+
reminderEnabled: booleanValue$11(item.reminder_enabled),
|
|
2121
2121
|
reminderState: stringValue$1(item.reminder_state),
|
|
2122
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
2123
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
2122
|
+
createdAtMillis: Math.trunc(numberValue$20(item.create_at)),
|
|
2123
|
+
updatedAtMillis: Math.trunc(numberValue$20(item.update_at)),
|
|
2124
2124
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
2125
2125
|
...remindAtMillis > 0 ? { remindAtMillis } : {}
|
|
2126
2126
|
};
|
|
@@ -2141,20 +2141,20 @@ var ArrangementService = class {
|
|
|
2141
2141
|
const eventUid = stringValue$1(item.uid).trim();
|
|
2142
2142
|
const arrangementUid = stringValue$1(item.arrangement_uid).trim();
|
|
2143
2143
|
if (eventUid === "" || arrangementUid === "") throw new ArkmePluginError("arrangement-reminder-contract-invalid", "安排提醒响应缺少有效身份", true, 502);
|
|
2144
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
2145
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
2146
|
-
const readAtMillis = Math.trunc(numberValue$
|
|
2144
|
+
const dueAtMillis = Math.trunc(numberValue$20(item.due_at));
|
|
2145
|
+
const remindAtMillis = Math.trunc(numberValue$20(item.remind_at));
|
|
2146
|
+
const readAtMillis = Math.trunc(numberValue$20(item.read_at));
|
|
2147
2147
|
return {
|
|
2148
2148
|
eventRef: await this.arrangementReminderRef(viewerUserId, eventUid),
|
|
2149
2149
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
2150
2150
|
title: stringValue$1(item.title),
|
|
2151
2151
|
description: stringValue$1(item.description),
|
|
2152
2152
|
eventKind: stringValue$1(item.event_kind),
|
|
2153
|
-
eventAtMillis: Math.trunc(numberValue$
|
|
2153
|
+
eventAtMillis: Math.trunc(numberValue$20(item.event_at)),
|
|
2154
2154
|
read: readAtMillis > 0,
|
|
2155
2155
|
reminderState: stringValue$1(item.reminder_state),
|
|
2156
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
2157
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
2156
|
+
createdAtMillis: Math.trunc(numberValue$20(item.create_at)),
|
|
2157
|
+
updatedAtMillis: Math.trunc(numberValue$20(item.update_at)),
|
|
2158
2158
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
2159
2159
|
...remindAtMillis > 0 ? { remindAtMillis } : {},
|
|
2160
2160
|
...readAtMillis > 0 ? { readAtMillis } : {}
|
|
@@ -2211,7 +2211,7 @@ var ArrangementService = class {
|
|
|
2211
2211
|
const ARKME_PHONE_BIND_SUCCESS = 1;
|
|
2212
2212
|
const ARKME_PHONE_BIND_REPEAT = 2;
|
|
2213
2213
|
const ARKME_PHONE_BIND_CODE_ERR = 3;
|
|
2214
|
-
function numberValue$
|
|
2214
|
+
function numberValue$19(value) {
|
|
2215
2215
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2216
2216
|
}
|
|
2217
2217
|
var AuthService = class {
|
|
@@ -2276,7 +2276,7 @@ var AuthService = class {
|
|
|
2276
2276
|
const data = await this.runtime.post(this.runtime.config.authBaseUrl, "/api/public/v1/auth/wechat-login-qrcode", {}, void 0, [200]);
|
|
2277
2277
|
const sceneStr = stringValue$1(data.scene_str).trim();
|
|
2278
2278
|
const qrContent = stringValue$1(data.url).trim();
|
|
2279
|
-
const expireSeconds = Math.max(30, numberValue$
|
|
2279
|
+
const expireSeconds = Math.max(30, numberValue$19(data.expire_seconds) || 300);
|
|
2280
2280
|
if (qrContent === "" && sceneStr !== "") throw new ArkmePluginError("wechat-qr-unavailable", "测试环境当前未返回可用微信二维码,请使用手机号登录", true, 503);
|
|
2281
2281
|
if (sceneStr === "" || qrContent === "") throw new ArkmePluginError("login-contract-invalid", "Arkme 登录二维码响应不完整", true, 502);
|
|
2282
2282
|
const attemptId = crypto.randomUUID();
|
|
@@ -2312,7 +2312,7 @@ var AuthService = class {
|
|
|
2312
2312
|
ref: 0,
|
|
2313
2313
|
keep_cancel: true
|
|
2314
2314
|
}, void 0, [200]);
|
|
2315
|
-
const userId = numberValue$
|
|
2315
|
+
const userId = numberValue$19(data.user_id);
|
|
2316
2316
|
if (userId <= 0) return {
|
|
2317
2317
|
status: "pending",
|
|
2318
2318
|
environment: this.runtime.config.environment,
|
|
@@ -2356,7 +2356,7 @@ var AuthService = class {
|
|
|
2356
2356
|
const normalizedCaptcha = this.normalizedCaptcha(captcha);
|
|
2357
2357
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
2358
2358
|
if (session !== void 0) {
|
|
2359
|
-
if (numberValue$
|
|
2359
|
+
if (numberValue$19((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/bind-phone-send-code", {
|
|
2360
2360
|
phone: normalizedPhone,
|
|
2361
2361
|
pre: "86",
|
|
2362
2362
|
is_test: this.runtime.config.environment === "test",
|
|
@@ -2378,7 +2378,7 @@ var AuthService = class {
|
|
|
2378
2378
|
if (!/^[0-9]{6}$/.test(normalizedCode)) throw new ArkmePluginError("phone-code-invalid", "请输入有效的短信验证码", false);
|
|
2379
2379
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
2380
2380
|
if (session !== void 0) {
|
|
2381
|
-
const result = numberValue$
|
|
2381
|
+
const result = numberValue$19((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/verify-bind-phone", {
|
|
2382
2382
|
phone: normalizedPhone,
|
|
2383
2383
|
pre: "86",
|
|
2384
2384
|
code: normalizedCode,
|
|
@@ -2399,7 +2399,7 @@ var AuthService = class {
|
|
|
2399
2399
|
keep_cancel: true
|
|
2400
2400
|
}, void 0, [200]);
|
|
2401
2401
|
if (data.ok === false) throw new ArkmePluginError("phone-code-rejected", "手机号或验证码错误", false, 401);
|
|
2402
|
-
const userId = numberValue$
|
|
2402
|
+
const userId = numberValue$19(data.user_id);
|
|
2403
2403
|
const accessToken = stringValue$1(data.access_token);
|
|
2404
2404
|
const refreshToken = stringValue$1(data.refresh_token);
|
|
2405
2405
|
if (userId <= 0 || accessToken === "" || refreshToken === "") throw new ArkmePluginError("login-contract-invalid", "Arkme手机号登录响应不完整", false, 502);
|
|
@@ -2466,10 +2466,10 @@ var SecretValue = class {
|
|
|
2466
2466
|
};
|
|
2467
2467
|
//#endregion
|
|
2468
2468
|
//#region src/services/bot-service.ts
|
|
2469
|
-
function numberValue$
|
|
2469
|
+
function numberValue$18(value) {
|
|
2470
2470
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2471
2471
|
}
|
|
2472
|
-
function booleanValue$
|
|
2472
|
+
function booleanValue$10(value) {
|
|
2473
2473
|
return value === true;
|
|
2474
2474
|
}
|
|
2475
2475
|
function listValue$18(value) {
|
|
@@ -2552,6 +2552,10 @@ var BotService = class {
|
|
|
2552
2552
|
throw new ArkmePluginError("bot-create-outcome-unknown", "Bot 可能已创建,但响应不完整;请刷新 Bot 列表确认", false, 409, { cause: error });
|
|
2553
2553
|
}
|
|
2554
2554
|
}
|
|
2555
|
+
/** Browser-safe result: the one-time credential never leaves the Host owner. */
|
|
2556
|
+
async createBotSummary(input, options = {}) {
|
|
2557
|
+
return (await this.createBot(input, options)).bot;
|
|
2558
|
+
}
|
|
2555
2559
|
async revealBotSecret(botRef, options = {}) {
|
|
2556
2560
|
const session = await this.runtime.requireSession();
|
|
2557
2561
|
const reference = await this.openBotRef(botRef, session.userId);
|
|
@@ -2606,13 +2610,13 @@ var BotService = class {
|
|
|
2606
2610
|
const { directChatAvailable: _directChatAvailable, ...summary } = await this.botSummaryFromData(raw, session.userId);
|
|
2607
2611
|
items.push({
|
|
2608
2612
|
...summary,
|
|
2609
|
-
installed: booleanValue$
|
|
2613
|
+
installed: booleanValue$10(raw.installed)
|
|
2610
2614
|
});
|
|
2611
2615
|
}
|
|
2612
2616
|
return {
|
|
2613
2617
|
groupSourceRef,
|
|
2614
2618
|
displayName: stringValue$1(data.subject_title).trim() || group.displayName,
|
|
2615
|
-
canAddBots: booleanValue$
|
|
2619
|
+
canAddBots: booleanValue$10(data.can_current_user_add_bots),
|
|
2616
2620
|
items
|
|
2617
2621
|
};
|
|
2618
2622
|
}
|
|
@@ -2687,7 +2691,7 @@ var BotService = class {
|
|
|
2687
2691
|
}
|
|
2688
2692
|
const reference = {
|
|
2689
2693
|
version: 1,
|
|
2690
|
-
userId: numberValue$
|
|
2694
|
+
userId: numberValue$18(raw.userId),
|
|
2691
2695
|
botId: stringValue$1(raw.botId).trim()
|
|
2692
2696
|
};
|
|
2693
2697
|
if (raw.version !== 1 || reference.userId !== expectedUserId || reference.botId === "") throw new ArkmePluginError("bot-ref-invalid", "Bot 引用与当前账号不匹配", false, 403);
|
|
@@ -2698,10 +2702,10 @@ var BotService = class {
|
|
|
2698
2702
|
//#region src/services/calendar-service.ts
|
|
2699
2703
|
const MAX_CALENDAR_RANGE_DAYS = 62;
|
|
2700
2704
|
const MAX_DAY_RECORD_LIMIT = 50;
|
|
2701
|
-
function numberValue$
|
|
2705
|
+
function numberValue$17(value) {
|
|
2702
2706
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
2703
2707
|
}
|
|
2704
|
-
function booleanValue$
|
|
2708
|
+
function booleanValue$9(value) {
|
|
2705
2709
|
if (typeof value === "boolean") return value;
|
|
2706
2710
|
if (typeof value === "number") return value !== 0;
|
|
2707
2711
|
}
|
|
@@ -2738,7 +2742,7 @@ function boundedLimit(value) {
|
|
|
2738
2742
|
return limit;
|
|
2739
2743
|
}
|
|
2740
2744
|
function contentAccessState(value) {
|
|
2741
|
-
const code = Math.trunc(numberValue$
|
|
2745
|
+
const code = Math.trunc(numberValue$17(value));
|
|
2742
2746
|
if (code === 1) return "available";
|
|
2743
2747
|
if (code === 2) return "protected";
|
|
2744
2748
|
return "unknown";
|
|
@@ -2748,7 +2752,7 @@ function sourceKind(raw) {
|
|
|
2748
2752
|
const chat = objectValue$1(raw.chat_core);
|
|
2749
2753
|
if (stringValue$1(topic.topic_uid).trim() !== "") return "topic";
|
|
2750
2754
|
if (stringValue$1(chat.chat_session_uid).trim() !== "") return "chat";
|
|
2751
|
-
if (booleanValue$
|
|
2755
|
+
if (booleanValue$9(raw.is_uncategorized) === true) return "self";
|
|
2752
2756
|
return "unknown";
|
|
2753
2757
|
}
|
|
2754
2758
|
var CalendarService = class {
|
|
@@ -2807,7 +2811,7 @@ var CalendarService = class {
|
|
|
2807
2811
|
cacheMs: 1e4,
|
|
2808
2812
|
failureCooldownMs: 2e3
|
|
2809
2813
|
});
|
|
2810
|
-
const nextSendAt = Math.trunc(numberValue$
|
|
2814
|
+
const nextSendAt = Math.trunc(numberValue$17(data.next_cursor_send_at));
|
|
2811
2815
|
const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
2812
2816
|
return {
|
|
2813
2817
|
scope: "self",
|
|
@@ -2826,20 +2830,20 @@ var CalendarService = class {
|
|
|
2826
2830
|
const item = objectValue$1(raw);
|
|
2827
2831
|
const bucketDate = stringValue$1(item.bucket_date).trim();
|
|
2828
2832
|
if (bucketDate === "") return void 0;
|
|
2829
|
-
const count = Math.max(0, Math.trunc(numberValue$
|
|
2833
|
+
const count = Math.max(0, Math.trunc(numberValue$17(item.count)));
|
|
2830
2834
|
return {
|
|
2831
2835
|
bucketDate,
|
|
2832
2836
|
count,
|
|
2833
|
-
protectedCount: Math.max(0, Math.trunc(numberValue$
|
|
2837
|
+
protectedCount: Math.max(0, Math.trunc(numberValue$17(item.protected_count))),
|
|
2834
2838
|
hasRecords: count > 0,
|
|
2835
|
-
...numberValue$
|
|
2839
|
+
...numberValue$17(item.first_send_at) > 0 ? { firstSendAtMillis: Math.trunc(numberValue$17(item.first_send_at)) } : {}
|
|
2836
2840
|
};
|
|
2837
2841
|
}
|
|
2838
2842
|
dayRecord(raw) {
|
|
2839
2843
|
const item = objectValue$1(raw);
|
|
2840
2844
|
const core = objectValue$1(item.record_core);
|
|
2841
2845
|
const recordUid = stringValue$1(item.record_uid ?? core.record_uid).trim();
|
|
2842
|
-
const sendAtMillis = Math.trunc(numberValue$
|
|
2846
|
+
const sendAtMillis = Math.trunc(numberValue$17(item.send_at ?? core.send_at));
|
|
2843
2847
|
if (recordUid === "" || sendAtMillis <= 0) return void 0;
|
|
2844
2848
|
const accessState = contentAccessState(core.content_access_state);
|
|
2845
2849
|
const available = accessState === "available";
|
|
@@ -2847,9 +2851,9 @@ var CalendarService = class {
|
|
|
2847
2851
|
const textContent = available ? clippedText(core.text_content, 4e3) : "";
|
|
2848
2852
|
const preview = title || clippedText(textContent, 160) || (available ? "无文字内容" : "受保护内容");
|
|
2849
2853
|
const topic = objectValue$1(item.topic_core);
|
|
2850
|
-
const isUncategorized = booleanValue$
|
|
2851
|
-
const hasManualEdit = booleanValue$
|
|
2852
|
-
const hasPolish = booleanValue$
|
|
2854
|
+
const isUncategorized = booleanValue$9(item.is_uncategorized);
|
|
2855
|
+
const hasManualEdit = booleanValue$9(core.has_manual_edit);
|
|
2856
|
+
const hasPolish = booleanValue$9(core.has_polish);
|
|
2853
2857
|
return {
|
|
2854
2858
|
recordUid,
|
|
2855
2859
|
sendAtMillis,
|
|
@@ -2859,9 +2863,9 @@ var CalendarService = class {
|
|
|
2859
2863
|
preview,
|
|
2860
2864
|
...stringValue$1(topic.title).trim() === "" ? {} : { topicTitle: stringValue$1(topic.title).trim() },
|
|
2861
2865
|
sourceKind: sourceKind(item),
|
|
2862
|
-
creationSource: Math.trunc(numberValue$
|
|
2863
|
-
templateKind: Math.trunc(numberValue$
|
|
2864
|
-
displayKind: Math.trunc(numberValue$
|
|
2866
|
+
creationSource: Math.trunc(numberValue$17(core.creation_source)),
|
|
2867
|
+
templateKind: Math.trunc(numberValue$17(core.template_kind)),
|
|
2868
|
+
displayKind: Math.trunc(numberValue$17(core.display_kind)),
|
|
2865
2869
|
protected: accessState === "protected",
|
|
2866
2870
|
...isUncategorized === void 0 ? {} : { isUncategorized },
|
|
2867
2871
|
...hasManualEdit === void 0 ? {} : { hasManualEdit },
|
|
@@ -3556,10 +3560,10 @@ var ChatRealtimeService = class {
|
|
|
3556
3560
|
};
|
|
3557
3561
|
//#endregion
|
|
3558
3562
|
//#region src/services/chat-service.ts
|
|
3559
|
-
function numberValue$
|
|
3563
|
+
function numberValue$16(value) {
|
|
3560
3564
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
3561
3565
|
}
|
|
3562
|
-
function booleanValue$
|
|
3566
|
+
function booleanValue$8(value) {
|
|
3563
3567
|
return value === true;
|
|
3564
3568
|
}
|
|
3565
3569
|
function listValue$15(value) {
|
|
@@ -3658,15 +3662,15 @@ var ChatService = class {
|
|
|
3658
3662
|
const uid = stringValue$1(chatSession.chat_session_uid).trim();
|
|
3659
3663
|
if (uid === "") throw new ArkmePluginError("private-chat-contract-invalid", "私聊会话响应不完整", true, 502);
|
|
3660
3664
|
const unread = objectValue$1(data.unread_snapshot);
|
|
3661
|
-
const latestSequence = numberValue$
|
|
3665
|
+
const latestSequence = numberValue$16(unread.session_last_seq ?? chatSession.last_seq);
|
|
3662
3666
|
const source = {
|
|
3663
3667
|
sourceRef: await this.source.sealSourceRef(session.userId, "private_chat", uid, displayName),
|
|
3664
3668
|
sourceKey: await this.source.chatDirectorySourceKey(session.userId, uid),
|
|
3665
3669
|
kind: "private_chat",
|
|
3666
3670
|
displayName,
|
|
3667
3671
|
...profile?.avatarUrl === void 0 ? {} : { avatarRef: await this.profile.sealProfileImageRef(session.userId, peerUserId) },
|
|
3668
|
-
activeAtMillis: numberValue$
|
|
3669
|
-
unreadCount: numberValue$
|
|
3672
|
+
activeAtMillis: numberValue$16(chatSession.last_active_at) || Date.now(),
|
|
3673
|
+
unreadCount: numberValue$16(unread.unread_count),
|
|
3670
3674
|
...latestSequence > 0 ? { latestSequence } : {}
|
|
3671
3675
|
};
|
|
3672
3676
|
this.source.setChatSourceByKey(`${String(session.userId)}:${uid}`, source);
|
|
@@ -3693,7 +3697,7 @@ var ChatService = class {
|
|
|
3693
3697
|
mediaUnavailable: media.unavailableRecordUids.has(recordUid)
|
|
3694
3698
|
});
|
|
3695
3699
|
}).filter((item) => item.itemUid !== "");
|
|
3696
|
-
const nextSendAt = numberValue$
|
|
3700
|
+
const nextSendAt = numberValue$16(data.next_cursor_send_at);
|
|
3697
3701
|
const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
3698
3702
|
return {
|
|
3699
3703
|
source: await this.source.sourceItem(source),
|
|
@@ -3737,7 +3741,7 @@ var ChatService = class {
|
|
|
3737
3741
|
mediaUnavailable: media.unavailableRecordUids.has(recordUid)
|
|
3738
3742
|
});
|
|
3739
3743
|
});
|
|
3740
|
-
const nextSendAt = numberValue$
|
|
3744
|
+
const nextSendAt = numberValue$16(data.next_cursor_send_at);
|
|
3741
3745
|
const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
3742
3746
|
return {
|
|
3743
3747
|
source: await this.source.sourceItem(source),
|
|
@@ -3767,14 +3771,14 @@ var ChatService = class {
|
|
|
3767
3771
|
const relation = objectValue$1(item.relation);
|
|
3768
3772
|
const record = objectValue$1(item.record);
|
|
3769
3773
|
const payload = objectValue$1(record.payload);
|
|
3770
|
-
const recordStatus = numberValue$
|
|
3774
|
+
const recordStatus = numberValue$16(record.status);
|
|
3771
3775
|
if (recordStatus !== 1) continue;
|
|
3772
3776
|
const uid = stringValue$1(relation.record_uid ?? payload.record_uid).trim();
|
|
3773
3777
|
if (uid === "") continue;
|
|
3774
3778
|
const relationUid = stringValue$1(relation.rel_uid).trim();
|
|
3775
|
-
const senderUserId = numberValue$
|
|
3779
|
+
const senderUserId = numberValue$16(relation.sender_user_id);
|
|
3776
3780
|
const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
|
|
3777
|
-
const sendAtMillis = numberValue$
|
|
3781
|
+
const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
|
|
3778
3782
|
const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
|
|
3779
3783
|
const rawAgentSource = timelineAgentSource(relation, record, payload);
|
|
3780
3784
|
const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
|
|
@@ -3788,16 +3792,16 @@ var ChatService = class {
|
|
|
3788
3792
|
title: stringValue$1(payload.title),
|
|
3789
3793
|
textContent: stringValue$1(payload.text_content),
|
|
3790
3794
|
status: recordStatus,
|
|
3791
|
-
sequence: numberValue$
|
|
3792
|
-
...numberValue$
|
|
3795
|
+
sequence: numberValue$16(relation.seq),
|
|
3796
|
+
...numberValue$16(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$16(record.version ?? payload.version) } : {},
|
|
3793
3797
|
...aiPolish === void 0 ? {} : { aiPolish },
|
|
3794
3798
|
...forwardRecords === void 0 ? {} : { forwardRecords },
|
|
3795
|
-
templateKind: numberValue$
|
|
3796
|
-
displayKind: numberValue$
|
|
3797
|
-
version: numberValue$
|
|
3798
|
-
updateAtMillis: numberValue$
|
|
3799
|
-
recordDurationMillis: numberValue$
|
|
3800
|
-
editDurationMillis: numberValue$
|
|
3799
|
+
templateKind: numberValue$16(payload.template_kind),
|
|
3800
|
+
displayKind: numberValue$16(payload.display_kind),
|
|
3801
|
+
version: numberValue$16(payload.version ?? record.version),
|
|
3802
|
+
updateAtMillis: numberValue$16(payload.update_at ?? record.update_at),
|
|
3803
|
+
recordDurationMillis: numberValue$16(payload.record_duration_millis),
|
|
3804
|
+
editDurationMillis: numberValue$16(payload.edit_duration_millis),
|
|
3801
3805
|
contentBlocks: this.media.richContentBlocks(item, session.userId)
|
|
3802
3806
|
}) - 1;
|
|
3803
3807
|
if (Number.isSafeInteger(senderUserId) && senderUserId > 0) senderUserIdByIndex.set(itemIndex, senderUserId);
|
|
@@ -3809,7 +3813,7 @@ var ChatService = class {
|
|
|
3809
3813
|
items[index].avatarRef = await this.profile.sealProfileImageRef(session.userId, senderUserId);
|
|
3810
3814
|
}
|
|
3811
3815
|
} catch {}
|
|
3812
|
-
const beforeSequence = numberValue$
|
|
3816
|
+
const beforeSequence = numberValue$16(data.next_before_seq);
|
|
3813
3817
|
let aiPolishSettings;
|
|
3814
3818
|
let aiPolishNotices;
|
|
3815
3819
|
if (aiPolishDecorations !== void 0) {
|
|
@@ -3848,7 +3852,7 @@ var ChatService = class {
|
|
|
3848
3852
|
return {
|
|
3849
3853
|
messageRef,
|
|
3850
3854
|
reportUid,
|
|
3851
|
-
status: numberValue$
|
|
3855
|
+
status: numberValue$16(report.status)
|
|
3852
3856
|
};
|
|
3853
3857
|
}
|
|
3854
3858
|
async sendSourceText(sourceRef, textContent, options = {}) {
|
|
@@ -3879,7 +3883,7 @@ var ChatService = class {
|
|
|
3879
3883
|
return {
|
|
3880
3884
|
sourceRef,
|
|
3881
3885
|
itemUid: stringValue$1(result.record_uid).trim() || recordUid,
|
|
3882
|
-
status: numberValue$
|
|
3886
|
+
status: numberValue$16(result.status),
|
|
3883
3887
|
localState: "synced"
|
|
3884
3888
|
};
|
|
3885
3889
|
}
|
|
@@ -3912,7 +3916,7 @@ var ChatService = class {
|
|
|
3912
3916
|
const raw = objectValue$1(value);
|
|
3913
3917
|
const botId = stringValue$1(raw.bot_id).trim();
|
|
3914
3918
|
if (!requestedById.has(botId)) continue;
|
|
3915
|
-
if (stringValue$1(raw.provider).trim() !== "openclaw" || !booleanValue$
|
|
3919
|
+
if (stringValue$1(raw.provider).trim() !== "openclaw" || !booleanValue$8(raw.installed)) throw new ArkmePluginError("bot-mention-not-installed", "所选 Bot 未安装到该群聊", false, 409);
|
|
3916
3920
|
const name = stringValue$1(raw.name).trim();
|
|
3917
3921
|
if (name === "") throw new ArkmePluginError("bot-contract-invalid", "Bot 响应不完整", true, 502);
|
|
3918
3922
|
const display = `@${name}`;
|
|
@@ -3964,8 +3968,8 @@ var ChatService = class {
|
|
|
3964
3968
|
return {
|
|
3965
3969
|
sourceRef,
|
|
3966
3970
|
itemUid: stringValue$1(result.record_uid).trim() || recordUid,
|
|
3967
|
-
status: numberValue$
|
|
3968
|
-
sequence: numberValue$
|
|
3971
|
+
status: numberValue$16(result.audit_status),
|
|
3972
|
+
sequence: numberValue$16(result.seq),
|
|
3969
3973
|
localState: "synced"
|
|
3970
3974
|
};
|
|
3971
3975
|
}
|
|
@@ -4021,7 +4025,7 @@ var ChatService = class {
|
|
|
4021
4025
|
return {
|
|
4022
4026
|
sourceRef,
|
|
4023
4027
|
itemUid: stringValue$1(result.record_uid).trim() || recordUid,
|
|
4024
|
-
status: numberValue$
|
|
4028
|
+
status: numberValue$16(result.status),
|
|
4025
4029
|
localState: "synced"
|
|
4026
4030
|
};
|
|
4027
4031
|
}
|
|
@@ -4033,7 +4037,7 @@ var ChatService = class {
|
|
|
4033
4037
|
return {
|
|
4034
4038
|
sourceRef,
|
|
4035
4039
|
itemUid: stringValue$1(result.record_uid).trim() || recordUid,
|
|
4036
|
-
status: numberValue$
|
|
4040
|
+
status: numberValue$16(result.status),
|
|
4037
4041
|
localState: "synced"
|
|
4038
4042
|
};
|
|
4039
4043
|
}
|
|
@@ -4045,8 +4049,8 @@ var ChatService = class {
|
|
|
4045
4049
|
return {
|
|
4046
4050
|
sourceRef,
|
|
4047
4051
|
itemUid: stringValue$1(result.record_uid).trim() || recordUid,
|
|
4048
|
-
status: numberValue$
|
|
4049
|
-
sequence: numberValue$
|
|
4052
|
+
status: numberValue$16(result.audit_status ?? result.status),
|
|
4053
|
+
sequence: numberValue$16(result.seq),
|
|
4050
4054
|
localState: "synced"
|
|
4051
4055
|
};
|
|
4052
4056
|
}
|
|
@@ -4096,7 +4100,7 @@ var ChatService = class {
|
|
|
4096
4100
|
send_at: sendAtMillis
|
|
4097
4101
|
}, session, options.signal);
|
|
4098
4102
|
const chatSessionUid = stringValue$1(result.chat_session_uid).trim();
|
|
4099
|
-
const sequence = numberValue$
|
|
4103
|
+
const sequence = numberValue$16(result.seq);
|
|
4100
4104
|
const targetKind = stringValue$1(result.target_kind).trim();
|
|
4101
4105
|
if (chatSessionUid === "" || !Number.isSafeInteger(sequence) || sequence <= 0 || targetKind !== "direct") throw new ArkmePluginError("direct-send-response-invalid", "Chat Agent 发送返回了无效响应", true, 502);
|
|
4102
4106
|
const responseRecordUid = stringValue$1(result.record_uid).trim() || recordUid;
|
|
@@ -4124,10 +4128,10 @@ var ChatService = class {
|
|
|
4124
4128
|
reason: "arkme_dsh_open_chat"
|
|
4125
4129
|
}, session);
|
|
4126
4130
|
const responseSessionUid = stringValue$1(data.chat_session_uid).trim();
|
|
4127
|
-
const effectiveReadSequence = numberValue$
|
|
4128
|
-
const readAt = numberValue$
|
|
4129
|
-
const sessionLastSequence = numberValue$
|
|
4130
|
-
const unreadCount = numberValue$
|
|
4131
|
+
const effectiveReadSequence = numberValue$16(data.effective_read_seq);
|
|
4132
|
+
const readAt = numberValue$16(data.read_at);
|
|
4133
|
+
const sessionLastSequence = numberValue$16(data.session_last_seq);
|
|
4134
|
+
const unreadCount = numberValue$16(data.unread_count);
|
|
4131
4135
|
if (responseSessionUid !== source.ownerRef || !Number.isSafeInteger(effectiveReadSequence) || effectiveReadSequence < readSequence || readAt <= 0 || sessionLastSequence < effectiveReadSequence || !Number.isSafeInteger(unreadCount) || unreadCount < 0) throw new ArkmePluginError("source-read-ack-invalid", "聊天已读响应不完整", true, 502);
|
|
4132
4136
|
const cacheKey = `${String(session.userId)}:${source.ownerRef}`;
|
|
4133
4137
|
const cached = this.source.cachedChatSourceByKey(cacheKey);
|
|
@@ -4162,9 +4166,9 @@ var ChatService = class {
|
|
|
4162
4166
|
const payload = objectValue$1(record.payload);
|
|
4163
4167
|
const uid = stringValue$1(relation.record_uid ?? payload.record_uid).trim();
|
|
4164
4168
|
if (uid === "") continue;
|
|
4165
|
-
const senderUserId = numberValue$
|
|
4169
|
+
const senderUserId = numberValue$16(relation.sender_user_id);
|
|
4166
4170
|
const aiPolish = this.aiPolish.timelineAiPolish(record, payload);
|
|
4167
|
-
const sendAtMillis = numberValue$
|
|
4171
|
+
const sendAtMillis = numberValue$16(relation.attach_at ?? payload.send_at);
|
|
4168
4172
|
const forwardRecords = await this.chatForwardRecordsPreview(item, session.userId, sendAtMillis);
|
|
4169
4173
|
const rawAgentSource = timelineAgentSource(relation, record, payload);
|
|
4170
4174
|
const agentSource = senderUserId === session.userId ? this.arko.currentUserAgentSourceFallback(session.userId, rawAgentSource) : rawAgentSource;
|
|
@@ -4177,12 +4181,12 @@ var ChatService = class {
|
|
|
4177
4181
|
sendAtMillis,
|
|
4178
4182
|
title: stringValue$1(payload.title),
|
|
4179
4183
|
textContent: stringValue$1(payload.text_content),
|
|
4180
|
-
status: numberValue$
|
|
4181
|
-
sequence: numberValue$
|
|
4182
|
-
...numberValue$
|
|
4184
|
+
status: numberValue$16(record.status),
|
|
4185
|
+
sequence: numberValue$16(relation.seq),
|
|
4186
|
+
...numberValue$16(record.version ?? payload.version) > 0 ? { recordVersion: numberValue$16(record.version ?? payload.version) } : {},
|
|
4183
4187
|
...aiPolish === void 0 ? {} : { aiPolish },
|
|
4184
4188
|
...forwardRecords === void 0 ? {} : { forwardRecords },
|
|
4185
|
-
displayKind: numberValue$
|
|
4189
|
+
displayKind: numberValue$16(payload.display_kind),
|
|
4186
4190
|
contentBlocks: this.media.richContentBlocks(item, session.userId)
|
|
4187
4191
|
});
|
|
4188
4192
|
}
|
|
@@ -4198,7 +4202,7 @@ var ChatService = class {
|
|
|
4198
4202
|
const sorted = values.map((value, index) => ({
|
|
4199
4203
|
value,
|
|
4200
4204
|
index,
|
|
4201
|
-
order: numberValue$
|
|
4205
|
+
order: numberValue$16(objectValue$1(value).item_order)
|
|
4202
4206
|
})).sort((left, right) => (left.order || left.index) - (right.order || right.index));
|
|
4203
4207
|
for (const entry of sorted) {
|
|
4204
4208
|
if (projectedItems.length >= 100) return;
|
|
@@ -4208,19 +4212,19 @@ var ChatService = class {
|
|
|
4208
4212
|
await appendItems(listValue$15(nestedForward.items), depth + 1);
|
|
4209
4213
|
continue;
|
|
4210
4214
|
}
|
|
4211
|
-
const senderUserId = numberValue$
|
|
4215
|
+
const senderUserId = numberValue$16(item.source_sender_user_id ?? item.sourceSenderUserId ?? item.owner_id ?? item.ownerId);
|
|
4212
4216
|
const senderName = stringValue$1(item.owner_name ?? item.ownerName ?? item.source_display_name ?? item.sourceDisplayName).trim() || "Arkme用户";
|
|
4213
4217
|
const textContent = stringValue$1(item.text ?? item.text_preview ?? item.textPreview).trim();
|
|
4214
4218
|
const title = stringValue$1(item.title).trim();
|
|
4215
|
-
const imageCount = Math.max(0, Math.trunc(numberValue$
|
|
4216
|
-
const voiceCount = Math.max(0, Math.trunc(numberValue$
|
|
4217
|
-
const fileCount = Math.max(0, Math.trunc(numberValue$
|
|
4219
|
+
const imageCount = Math.max(0, Math.trunc(numberValue$16(item.image_count ?? item.imageCount)));
|
|
4220
|
+
const voiceCount = Math.max(0, Math.trunc(numberValue$16(item.voice_count ?? item.voiceCount)));
|
|
4221
|
+
const fileCount = Math.max(0, Math.trunc(numberValue$16(item.file_count ?? item.fileCount)));
|
|
4218
4222
|
const fileName = listValue$15(item.file_names ?? item.fileNames).map((value) => stringValue$1(value).trim()).find((value) => value !== "");
|
|
4219
4223
|
const contentLabel = imageCount > 0 ? imageCount > 1 ? `[${String(imageCount)}张图片]` : "[图片]" : voiceCount > 0 ? "[语音]" : fileCount > 0 ? fileName === void 0 ? "[文件]" : `[文件] ${fileName}` : stringValue$1(item.availability).trim() !== "" ? "原快记暂不可查看" : void 0;
|
|
4220
4224
|
projectedItems.push({
|
|
4221
4225
|
senderName,
|
|
4222
4226
|
...senderUserId > 0 ? { avatarRef: await this.profile.sealProfileImageRef(viewerUserId, senderUserId) } : {},
|
|
4223
|
-
sendAtMillis: numberValue$
|
|
4227
|
+
sendAtMillis: numberValue$16(item.send_at ?? item.sendAt),
|
|
4224
4228
|
title,
|
|
4225
4229
|
textContent,
|
|
4226
4230
|
...contentLabel === void 0 ? {} : { contentLabel }
|
|
@@ -4229,7 +4233,7 @@ var ChatService = class {
|
|
|
4229
4233
|
};
|
|
4230
4234
|
await appendItems(listValue$15(payload.items), 0);
|
|
4231
4235
|
const summaryLines = listValue$15(payload.summary_lines ?? payload.summaryLines).map((value) => stringValue$1(value).trim()).filter((value) => value !== "");
|
|
4232
|
-
const createdAtMillis = numberValue$
|
|
4236
|
+
const createdAtMillis = numberValue$16(payload.created_at ?? payload.createdAt) || fallbackCreatedAtMillis;
|
|
4233
4237
|
return {
|
|
4234
4238
|
title: stringValue$1(payload.title).trim() || "转发快记",
|
|
4235
4239
|
createdAtMillis,
|
|
@@ -4261,7 +4265,7 @@ var ChatService = class {
|
|
|
4261
4265
|
}
|
|
4262
4266
|
const result = {
|
|
4263
4267
|
version: 1,
|
|
4264
|
-
userId: numberValue$
|
|
4268
|
+
userId: numberValue$16(parsed.userId),
|
|
4265
4269
|
chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
|
|
4266
4270
|
relationUid: stringValue$1(parsed.relationUid).trim()
|
|
4267
4271
|
};
|
|
@@ -4270,6 +4274,167 @@ var ChatService = class {
|
|
|
4270
4274
|
}
|
|
4271
4275
|
};
|
|
4272
4276
|
//#endregion
|
|
4277
|
+
//#region src/services/contact-service.ts
|
|
4278
|
+
const CONTACT_REF_TTL_MS = 10 * 6e4;
|
|
4279
|
+
const MAX_CONTACT_REFS = 512;
|
|
4280
|
+
const CONTACT_REF_PATTERN = /^arkme-contact-v1\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
4281
|
+
function numberValue$15(value) {
|
|
4282
|
+
const parsed = typeof value === "number" ? value : typeof value === "string" ? Number(value) : NaN;
|
|
4283
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
4284
|
+
}
|
|
4285
|
+
function booleanValue$7(value) {
|
|
4286
|
+
return value === true;
|
|
4287
|
+
}
|
|
4288
|
+
function normalizeIdentifier(value) {
|
|
4289
|
+
const trimmed = value.trim().replace(/^@/, "");
|
|
4290
|
+
if (trimmed === "" || trimmed.length > 64) throw new ArkmePluginError("contact-identifier-invalid", "请输入手机号或即我号", false);
|
|
4291
|
+
const compactPhone = trimmed.replace(/[\s()-]/g, "").replace(/^\+86/, "");
|
|
4292
|
+
if (/^\d+$/.test(compactPhone)) {
|
|
4293
|
+
if (!/^1[3-9]\d{9}$/.test(compactPhone)) throw new ArkmePluginError("contact-phone-invalid", "请输入有效的中国大陆手机号", false);
|
|
4294
|
+
return {
|
|
4295
|
+
kind: "phone",
|
|
4296
|
+
identifierType: 1,
|
|
4297
|
+
identifier: compactPhone,
|
|
4298
|
+
phonePre: "86"
|
|
4299
|
+
};
|
|
4300
|
+
}
|
|
4301
|
+
if (!/^[A-Za-z][A-Za-z0-9_-]{1,63}$/.test(trimmed)) throw new ArkmePluginError("contact-arkme-id-invalid", "即我号格式无效", false);
|
|
4302
|
+
return {
|
|
4303
|
+
kind: "arkme_id",
|
|
4304
|
+
identifierType: 2,
|
|
4305
|
+
identifier: trimmed,
|
|
4306
|
+
phonePre: "86"
|
|
4307
|
+
};
|
|
4308
|
+
}
|
|
4309
|
+
var ContactService = class {
|
|
4310
|
+
runtime;
|
|
4311
|
+
source;
|
|
4312
|
+
profile;
|
|
4313
|
+
realtime;
|
|
4314
|
+
candidates = /* @__PURE__ */ new Map();
|
|
4315
|
+
constructor(runtime, source, profile, realtime) {
|
|
4316
|
+
this.runtime = runtime;
|
|
4317
|
+
this.source = source;
|
|
4318
|
+
this.profile = profile;
|
|
4319
|
+
this.realtime = realtime;
|
|
4320
|
+
}
|
|
4321
|
+
dispose() {
|
|
4322
|
+
this.candidates.clear();
|
|
4323
|
+
}
|
|
4324
|
+
async search(identifier, options = {}) {
|
|
4325
|
+
const session = await this.runtime.requireSession();
|
|
4326
|
+
const normalized = normalizeIdentifier(identifier);
|
|
4327
|
+
const candidate = await this.lookup(normalized, session, options.signal);
|
|
4328
|
+
this.prune();
|
|
4329
|
+
this.candidates.set(candidate.result.contactRef, candidate);
|
|
4330
|
+
this.prune();
|
|
4331
|
+
return candidate.result;
|
|
4332
|
+
}
|
|
4333
|
+
async add(contactRef, options = {}) {
|
|
4334
|
+
const session = await this.runtime.requireSession();
|
|
4335
|
+
this.prune();
|
|
4336
|
+
const normalizedContactRef = contactRef.trim();
|
|
4337
|
+
if (!CONTACT_REF_PATTERN.test(normalizedContactRef)) throw new ArkmePluginError("contact-ref-invalid", "联系人搜索引用无效,请重新搜索", false);
|
|
4338
|
+
const cached = this.candidates.get(normalizedContactRef);
|
|
4339
|
+
if (cached === void 0 || cached.userId !== session.userId || cached.expiresAtMillis <= Date.now()) throw new ArkmePluginError("contact-ref-expired", "联系人搜索结果已过期,请重新搜索", false, 410);
|
|
4340
|
+
const candidate = await this.lookup(cached.normalized, session, options.signal, normalizedContactRef);
|
|
4341
|
+
if (candidate.targetUserId !== cached.targetUserId || candidate.result.registered !== cached.result.registered) {
|
|
4342
|
+
this.candidates.delete(normalizedContactRef);
|
|
4343
|
+
throw new ArkmePluginError("contact-candidate-changed", "联系人身份已发生变化,请重新搜索后确认", false, 409);
|
|
4344
|
+
}
|
|
4345
|
+
if (candidate.result.isSelf) throw new ArkmePluginError("contact-self-invalid", "不能添加自己为联系人", false);
|
|
4346
|
+
if (!candidate.result.canAdd) throw new ArkmePluginError("contact-add-unavailable", "该账号当前无法添加", false, 409);
|
|
4347
|
+
const remark = options.remark?.trim() ?? "";
|
|
4348
|
+
if (Array.from(remark).length > 100) throw new ArkmePluginError("contact-remark-invalid", "备注不能超过 100 个字符", false);
|
|
4349
|
+
const requestUid = options.requestUid?.trim() || randomUUID();
|
|
4350
|
+
if (!/^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(requestUid)) throw new ArkmePluginError("contact-request-uid-invalid", "联系人添加请求标识无效", false);
|
|
4351
|
+
const chatSessionUid = `chat_session_${requestUid}`;
|
|
4352
|
+
const displayName = candidate.result.displayName;
|
|
4353
|
+
const common = {
|
|
4354
|
+
chat_session_uid: chatSessionUid,
|
|
4355
|
+
create_at: Date.now(),
|
|
4356
|
+
...remark === "" ? {} : { remark }
|
|
4357
|
+
};
|
|
4358
|
+
const registered = candidate.result.registered && candidate.targetUserId !== void 0;
|
|
4359
|
+
const bundle = registered ? await this.runtime.authenticatedChatPost("/api/v1/chats/contacts/add-and-open-private", {
|
|
4360
|
+
...common,
|
|
4361
|
+
target_user_id: candidate.targetUserId,
|
|
4362
|
+
target_display_name_snapshot: displayName
|
|
4363
|
+
}, session, options.signal, { key: `contact:add:${requestUid}` }) : await this.runtime.authenticatedChatPost("/api/v1/chats/contacts/add-and-open-pending-phone", {
|
|
4364
|
+
...common,
|
|
4365
|
+
phone_pre: candidate.normalized.phonePre,
|
|
4366
|
+
phone: candidate.phone ?? candidate.normalized.identifier,
|
|
4367
|
+
display_name_snapshot: displayName
|
|
4368
|
+
}, session, options.signal, { key: `contact:add:${requestUid}` });
|
|
4369
|
+
let source = await this.source.chatSourceFromBundle(bundle, session, void 0, []);
|
|
4370
|
+
if (registered && candidate.targetUserId !== void 0) source = {
|
|
4371
|
+
...source,
|
|
4372
|
+
avatarRef: await this.profile.sealProfileImageRef(session.userId, candidate.targetUserId)
|
|
4373
|
+
};
|
|
4374
|
+
const returnedUid = stringValue$1(objectValue$1(bundle.session).chat_session_uid).trim();
|
|
4375
|
+
if (returnedUid === "") throw new ArkmePluginError("contact-add-contract-invalid", "联系人添加响应不完整", true, 502);
|
|
4376
|
+
this.source.setChatSource(session.userId, returnedUid, source);
|
|
4377
|
+
this.source.invalidateSourceListCache(session.userId, "root");
|
|
4378
|
+
this.realtime.emitChatClientEvent({
|
|
4379
|
+
type: "sessions-delta",
|
|
4380
|
+
revision: this.realtime.nextChatClientRevision(),
|
|
4381
|
+
updates: [{
|
|
4382
|
+
sourceKey: source.sourceKey ?? await this.source.chatDirectorySourceKey(session.userId, returnedUid),
|
|
4383
|
+
source,
|
|
4384
|
+
timelineItems: []
|
|
4385
|
+
}]
|
|
4386
|
+
});
|
|
4387
|
+
this.candidates.delete(normalizedContactRef);
|
|
4388
|
+
return {
|
|
4389
|
+
state: registered ? "ready" : "pending",
|
|
4390
|
+
source
|
|
4391
|
+
};
|
|
4392
|
+
}
|
|
4393
|
+
async lookup(normalized, session, signal, contactRef = `arkme-contact-v1.${randomUUID()}`) {
|
|
4394
|
+
const data = await this.runtime.authenticatedAuthPost("/api/v1/auth/search-contact-account", {
|
|
4395
|
+
identifier_type: normalized.identifierType,
|
|
4396
|
+
identifier: normalized.identifier,
|
|
4397
|
+
phone_pre: normalized.phonePre
|
|
4398
|
+
}, session, signal, {
|
|
4399
|
+
key: `contact:search:${normalized.identifierType}:${normalized.identifier}`,
|
|
4400
|
+
bypassCache: true
|
|
4401
|
+
});
|
|
4402
|
+
const targetUserId = Math.trunc(numberValue$15(data.user_id));
|
|
4403
|
+
const registered = booleanValue$7(data.is_registered) && targetUserId > 0;
|
|
4404
|
+
const isSelf = booleanValue$7(data.is_self);
|
|
4405
|
+
const canAdd = booleanValue$7(data.can_add) && !isSelf && (normalized.kind === "phone" || registered);
|
|
4406
|
+
const displayName = stringValue$1(data.nick_name).trim() || stringValue$1(data.jotmo_id).trim() || (normalized.kind === "phone" ? `+${normalized.phonePre} ${normalized.identifier}` : normalized.identifier);
|
|
4407
|
+
const result = {
|
|
4408
|
+
contactRef,
|
|
4409
|
+
identifierKind: normalized.kind,
|
|
4410
|
+
displayName,
|
|
4411
|
+
...stringValue$1(data.jotmo_id).trim() === "" ? {} : { arkmeId: stringValue$1(data.jotmo_id).trim() },
|
|
4412
|
+
...registered ? { avatarRef: await this.profile.sealProfileImageRef(session.userId, targetUserId) } : {},
|
|
4413
|
+
registered,
|
|
4414
|
+
inviteBySms: booleanValue$7(data.invite_by_sms),
|
|
4415
|
+
canAdd,
|
|
4416
|
+
isSelf
|
|
4417
|
+
};
|
|
4418
|
+
return {
|
|
4419
|
+
userId: session.userId,
|
|
4420
|
+
expiresAtMillis: Date.now() + CONTACT_REF_TTL_MS,
|
|
4421
|
+
normalized,
|
|
4422
|
+
result,
|
|
4423
|
+
...targetUserId > 0 ? { targetUserId } : {},
|
|
4424
|
+
...normalized.kind === "phone" ? { phone: stringValue$1(data.phone).trim() || normalized.identifier } : {}
|
|
4425
|
+
};
|
|
4426
|
+
}
|
|
4427
|
+
prune() {
|
|
4428
|
+
const now = Date.now();
|
|
4429
|
+
for (const [ref, candidate] of this.candidates) if (candidate.expiresAtMillis <= now) this.candidates.delete(ref);
|
|
4430
|
+
while (this.candidates.size >= MAX_CONTACT_REFS) {
|
|
4431
|
+
const oldest = this.candidates.keys().next().value;
|
|
4432
|
+
if (oldest === void 0) break;
|
|
4433
|
+
this.candidates.delete(oldest);
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
};
|
|
4437
|
+
//#endregion
|
|
4273
4438
|
//#region src/services/community-service.ts
|
|
4274
4439
|
function numberValue$14(value) {
|
|
4275
4440
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -4485,7 +4650,7 @@ var ExtensionReviewService = class {
|
|
|
4485
4650
|
422
|
|
4486
4651
|
].includes(error.httpStatus)) {
|
|
4487
4652
|
await this.runtime.stateStore.removeExtensionReviewOperation(userId, operation.clientMutationId);
|
|
4488
|
-
throw new ArkmePluginError("extension-review-registry-rejected",
|
|
4653
|
+
throw new ArkmePluginError("extension-review-registry-rejected", `评论已写入首页,但市集未接受:${error.message}`, false, error.httpStatus, { cause: error });
|
|
4489
4654
|
}
|
|
4490
4655
|
await this.runtime.stateStore.markExtensionReviewOperation(userId, operation.clientMutationId, "failed", safeFailureMessage$5(error));
|
|
4491
4656
|
throw new ArkmePluginError("extension-review-registry-pending", "评论已写入首页,但同步到扩展详情失败;请保留当前内容并重试", true, 503, { cause: error });
|
|
@@ -5024,6 +5189,7 @@ var GroupAiPolishService = class {
|
|
|
5024
5189
|
};
|
|
5025
5190
|
//#endregion
|
|
5026
5191
|
//#region src/services/group-service.ts
|
|
5192
|
+
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
5027
5193
|
function numberValue$12(value) {
|
|
5028
5194
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
5029
5195
|
}
|
|
@@ -5356,6 +5522,27 @@ var GroupService = class {
|
|
|
5356
5522
|
if (raw.version !== 1 || result.userId !== expectedUserId || result.groupChatSessionUid !== expectedGroupChatSessionUid || !Number.isSafeInteger(result.targetUserId) || result.targetUserId <= 0 || result.targetUserId === expectedUserId || result.displayName === "") throw new ArkmePluginError("group-candidate-ref-invalid", "群成员候选引用与当前账号不匹配", false, 403);
|
|
5357
5523
|
return result;
|
|
5358
5524
|
}
|
|
5525
|
+
async createGroup(title, clientMutationId, options = {}) {
|
|
5526
|
+
const normalizedTitle = title.trim();
|
|
5527
|
+
if (normalizedTitle === "" || Array.from(normalizedTitle).length > 80) throw new ArkmePluginError("group-title-invalid", "群聊名称需为 1-80 个字符", false);
|
|
5528
|
+
if (!UUID.test(clientMutationId)) throw new ArkmePluginError("client-mutation-id-invalid", "群聊操作标识无效", false);
|
|
5529
|
+
const session = await this.runtime.requireSession();
|
|
5530
|
+
let data;
|
|
5531
|
+
try {
|
|
5532
|
+
data = await this.runtime.authenticatedChatPost("/api/v1/chats/create-group", {
|
|
5533
|
+
chat_session_uid: clientMutationId,
|
|
5534
|
+
title: normalizedTitle,
|
|
5535
|
+
member_user_ids: [],
|
|
5536
|
+
create_at: Date.now()
|
|
5537
|
+
}, session, options.signal);
|
|
5538
|
+
} catch (error) {
|
|
5539
|
+
if (error instanceof ArkmePluginError && ["arkme-network-error", "arkme-timeout"].includes(error.code)) throw new ArkmePluginError("group-create-outcome-unknown", "群聊创建结果未知,请刷新会话列表确认;不会自动重试", false, 409, { cause: error });
|
|
5540
|
+
throw error;
|
|
5541
|
+
}
|
|
5542
|
+
const source = await this.source.chatSourceFromBundle(data, session, void 0, []);
|
|
5543
|
+
this.source.setChatSourceByKey(`${String(session.userId)}:${clientMutationId}`, source);
|
|
5544
|
+
return source;
|
|
5545
|
+
}
|
|
5359
5546
|
async listGroupMembers(sourceRef, options = {}) {
|
|
5360
5547
|
const session = await this.runtime.requireSession();
|
|
5361
5548
|
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
@@ -7345,7 +7532,7 @@ function displayTimestamp(value) {
|
|
|
7345
7532
|
const parsed = Date.parse(stringValue(value));
|
|
7346
7533
|
return Number.isFinite(parsed) ? parsed : 0;
|
|
7347
7534
|
}
|
|
7348
|
-
function projectRecordingTranscripts(response, speakerResponse) {
|
|
7535
|
+
function projectRecordingTranscripts(response, speakerResponse, source = "system") {
|
|
7349
7536
|
const data = objectValue(response);
|
|
7350
7537
|
const sessions = /* @__PURE__ */ new Map();
|
|
7351
7538
|
const sessionSpeakerColorIndexes = /* @__PURE__ */ new Map();
|
|
@@ -7389,7 +7576,32 @@ function projectRecordingTranscripts(response, speakerResponse) {
|
|
|
7389
7576
|
const sessionSpeakers = listValue$6(session.spk_ls ?? session.speakers).map(objectValue);
|
|
7390
7577
|
const childOffset = numberValue$6(child.start_at);
|
|
7391
7578
|
const childStart = childOffset >= 1e11 ? childOffset : numberValue$6(session.start_at) + childOffset;
|
|
7392
|
-
const rows = listValue$6(child.asr);
|
|
7579
|
+
const rows = listValue$6(source === "doubao" ? child.doubao_asr : child.asr);
|
|
7580
|
+
const doubaoStatus = numberValue$6(child.doubao_asr_status);
|
|
7581
|
+
if (source === "doubao" && (doubaoStatus === 1 || doubaoStatus === 2 || doubaoStatus === 4 || doubaoStatus === 5)) {
|
|
7582
|
+
const transcriptStatus = doubaoStatus === 1 || doubaoStatus === 2 ? "processing" : doubaoStatus === 4 ? "silent" : "failed";
|
|
7583
|
+
const text = transcriptStatus === "processing" ? "豆包转写中..." : transcriptStatus === "silent" ? "豆包未识别到人声" : "豆包转写失败";
|
|
7584
|
+
const label = transcriptStatus === "processing" ? "豆包转写中" : transcriptStatus === "silent" ? "豆包静音" : "豆包失败";
|
|
7585
|
+
projected.push({
|
|
7586
|
+
itemId: `${childId || sessionId}:doubao:status`,
|
|
7587
|
+
sessionId,
|
|
7588
|
+
childId,
|
|
7589
|
+
asrItemIndex: 0,
|
|
7590
|
+
transcriptSource: "doubao",
|
|
7591
|
+
startAtMillis: childStart,
|
|
7592
|
+
endAtMillis: childStart + Math.max(0, numberValue$6(child.duration)),
|
|
7593
|
+
speakerNumber: -1,
|
|
7594
|
+
speakerColorIndex: -1,
|
|
7595
|
+
speakerLabel: label,
|
|
7596
|
+
isSelf: false,
|
|
7597
|
+
isBackground: false,
|
|
7598
|
+
text,
|
|
7599
|
+
transcriptStatus,
|
|
7600
|
+
sourceIndex
|
|
7601
|
+
});
|
|
7602
|
+
sourceIndex += 1;
|
|
7603
|
+
continue;
|
|
7604
|
+
}
|
|
7393
7605
|
for (let index = 0; index < rows.length; index += 1) {
|
|
7394
7606
|
const row = objectValue(rows[index]);
|
|
7395
7607
|
const isBackground = numberValue$6(row.b ?? row.background) === 1 || row.background === true;
|
|
@@ -7403,15 +7615,15 @@ function projectRecordingTranscripts(response, speakerResponse) {
|
|
|
7403
7615
|
const persistentSpeakerNumber = optionalNumberValue(sessionSpeaker.speaker_display_number ?? sessionSpeaker.speakerDisplayNumber);
|
|
7404
7616
|
const speakerNumber = persistentSpeakerNumber !== void 0 && persistentSpeakerNumber > 0 ? persistentSpeakerNumber : rawSpeakerNumber;
|
|
7405
7617
|
const speakerColorIndex = sessionSpeakerColorIndexes.get(`${sessionId}:${rawSpeakerNumber}`) ?? Math.max(0, rawSpeakerNumber);
|
|
7406
|
-
const speakerLabel = speakerNumber >= 0 ? `说话人 ${speakerNumber}` : "未知说话人";
|
|
7618
|
+
const speakerLabel = source === "doubao" ? rawSpeakerNumber >= 0 ? `豆包说话人 ${rawSpeakerNumber + 1}` : "豆包说话人" : speakerNumber >= 0 ? `说话人 ${speakerNumber}` : "未知说话人";
|
|
7407
7619
|
const startOffset = numberValue$6(row.s ?? row.start_at);
|
|
7408
7620
|
const endOffset = Math.max(startOffset, numberValue$6(row.e ?? row.end_at));
|
|
7409
7621
|
projected.push({
|
|
7410
|
-
itemId: `${childId || sessionId}:${index}`,
|
|
7622
|
+
itemId: source === "system" ? `${childId || sessionId}:${index}` : `${childId || sessionId}:doubao:${index}`,
|
|
7411
7623
|
sessionId,
|
|
7412
7624
|
childId,
|
|
7413
7625
|
asrItemIndex: index,
|
|
7414
|
-
transcriptSource:
|
|
7626
|
+
transcriptSource: source,
|
|
7415
7627
|
startAtMillis: childStart + startOffset,
|
|
7416
7628
|
endAtMillis: childStart + endOffset,
|
|
7417
7629
|
speakerNumber,
|
|
@@ -7420,6 +7632,7 @@ function projectRecordingTranscripts(response, speakerResponse) {
|
|
|
7420
7632
|
isSelf,
|
|
7421
7633
|
isBackground,
|
|
7422
7634
|
text,
|
|
7635
|
+
...source === "doubao" ? { transcriptStatus: "ready" } : {},
|
|
7423
7636
|
sourceIndex
|
|
7424
7637
|
});
|
|
7425
7638
|
sourceIndex += 1;
|
|
@@ -7666,7 +7879,21 @@ var RecordingService = class {
|
|
|
7666
7879
|
days
|
|
7667
7880
|
};
|
|
7668
7881
|
}
|
|
7669
|
-
async recordingTranscript(dateStamp, signal) {
|
|
7882
|
+
async recordingTranscript(dateStamp, signal, source = "system") {
|
|
7883
|
+
const sections = await this.recordingTranscriptSections(dateStamp, signal);
|
|
7884
|
+
return source === "doubao" ? sections.doubao : sections.system;
|
|
7885
|
+
}
|
|
7886
|
+
async startRecordingDoubaoBackfill(dateStamp, signal) {
|
|
7887
|
+
const date = this.recordingDayStart(dateStamp).getTime();
|
|
7888
|
+
const session = await this.runtime.requireSession();
|
|
7889
|
+
const data = await this.runtime.authenticatedAudioPost("/api/v1/audio/doubao-asr/backfill-day", { start_at: date }, session, signal);
|
|
7890
|
+
return {
|
|
7891
|
+
queuedChildCount: Math.max(0, Math.trunc(numberValue$5(data.queued_child_count))),
|
|
7892
|
+
inFlightChildCount: Math.max(0, Math.trunc(numberValue$5(data.in_flight_child_count))),
|
|
7893
|
+
missingAudioChildCount: Math.max(0, Math.trunc(numberValue$5(data.missing_audio_child_count)))
|
|
7894
|
+
};
|
|
7895
|
+
}
|
|
7896
|
+
async recordingTranscriptSections(dateStamp, signal) {
|
|
7670
7897
|
const dayStart = this.recordingDayStart(dateStamp);
|
|
7671
7898
|
const date = dayStart.getTime();
|
|
7672
7899
|
const session = await this.runtime.requireSession();
|
|
@@ -7678,14 +7905,29 @@ var RecordingService = class {
|
|
|
7678
7905
|
let totalDurationMillis = 0;
|
|
7679
7906
|
for (const rawSession of listValue$5(transcriptResult.value.session_ls)) totalDurationMillis += Math.max(0, numberValue$5(objectValue$1(rawSession).duration));
|
|
7680
7907
|
const speakerData = speakerResult.status === "fulfilled" ? listValue$5(speakerResult.value.spk_ls) : [];
|
|
7681
|
-
const
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7908
|
+
const identityCoverage = speakerResult.status === "fulfilled" ? "complete" : "partial";
|
|
7909
|
+
const systemItems = projectRecordingTranscripts(transcriptResult.value, speakerData, "system");
|
|
7910
|
+
const doubaoItems = projectRecordingTranscripts(transcriptResult.value, speakerData, "doubao");
|
|
7911
|
+
const system = {
|
|
7912
|
+
state: systemItems.length > 0 ? "ready" : "empty",
|
|
7913
|
+
items: systemItems,
|
|
7914
|
+
message: systemItems.length > 0 ? "" : "当天无录音",
|
|
7915
|
+
identityCoverage,
|
|
7687
7916
|
totalDurationMillis
|
|
7688
7917
|
};
|
|
7918
|
+
const hasProcessing = doubaoItems.some((item) => item.transcriptStatus === "processing");
|
|
7919
|
+
const hasReady = doubaoItems.some((item) => item.transcriptStatus === "ready" || item.transcriptStatus === "silent" || item.transcriptStatus === void 0);
|
|
7920
|
+
const hasFailed = doubaoItems.some((item) => item.transcriptStatus === "failed");
|
|
7921
|
+
return {
|
|
7922
|
+
system,
|
|
7923
|
+
doubao: {
|
|
7924
|
+
state: hasProcessing ? "processing" : hasReady ? "ready" : hasFailed ? "failed" : "empty",
|
|
7925
|
+
items: doubaoItems,
|
|
7926
|
+
message: hasProcessing ? "豆包转写中" : hasReady ? "" : hasFailed ? "豆包转写失败" : "豆包转写尚未生成",
|
|
7927
|
+
identityCoverage,
|
|
7928
|
+
totalDurationMillis
|
|
7929
|
+
}
|
|
7930
|
+
};
|
|
7689
7931
|
}
|
|
7690
7932
|
async recordingProjection(dateStamp, kind, signal) {
|
|
7691
7933
|
const dayStart = this.recordingDayStart(dateStamp);
|
|
@@ -7723,6 +7965,7 @@ var RecordingService = class {
|
|
|
7723
7965
|
version: 1,
|
|
7724
7966
|
dateStamp: numberValue$5(raw.dateStamp),
|
|
7725
7967
|
content: content === "summary" || content === "timeline" ? content : "transcript",
|
|
7968
|
+
...content === "transcript" && (raw.transcriptSource === "system" || raw.transcriptSource === "doubao") ? { transcriptSource: raw.transcriptSource } : {},
|
|
7726
7969
|
itemOffset: numberValue$5(raw.itemOffset),
|
|
7727
7970
|
textOffset: numberValue$5(raw.textOffset),
|
|
7728
7971
|
fingerprint: stringValue$1(raw.fingerprint),
|
|
@@ -7732,25 +7975,31 @@ var RecordingService = class {
|
|
|
7732
7975
|
"transcript",
|
|
7733
7976
|
"summary",
|
|
7734
7977
|
"timeline"
|
|
7735
|
-
].includes(String(content)) || !Number.isSafeInteger(payload.dateStamp) || payload.dateStamp <= 0 || !Number.isSafeInteger(payload.itemOffset) || payload.itemOffset < 0 || !Number.isSafeInteger(payload.textOffset) || payload.textOffset < 0 || payload.fingerprint === "") throw new ArkmePluginError("recording-cursor-invalid", "录音分页游标无效", false);
|
|
7978
|
+
].includes(String(content)) || content === "transcript" && raw.transcriptSource !== void 0 && raw.transcriptSource !== "system" && raw.transcriptSource !== "doubao" || !Number.isSafeInteger(payload.dateStamp) || payload.dateStamp <= 0 || !Number.isSafeInteger(payload.itemOffset) || payload.itemOffset < 0 || !Number.isSafeInteger(payload.textOffset) || payload.textOffset < 0 || payload.fingerprint === "") throw new ArkmePluginError("recording-cursor-invalid", "录音分页游标无效", false);
|
|
7736
7979
|
return payload;
|
|
7737
7980
|
}
|
|
7738
7981
|
async recordingDay(dateStamp) {
|
|
7739
7982
|
const date = this.recordingDayStart(dateStamp).getTime();
|
|
7740
7983
|
const [transcriptResult, summaryResult, timelineResult] = await Promise.allSettled([
|
|
7741
|
-
this.
|
|
7984
|
+
this.recordingTranscriptSections(date),
|
|
7742
7985
|
this.recordingProjection(date, "summary"),
|
|
7743
7986
|
this.recordingProjection(date, "timeline")
|
|
7744
7987
|
]);
|
|
7745
|
-
const transcript = transcriptResult.status === "fulfilled" ? transcriptResult.value : {
|
|
7988
|
+
const transcript = transcriptResult.status === "fulfilled" ? transcriptResult.value.system : {
|
|
7989
|
+
state: "error",
|
|
7990
|
+
items: [],
|
|
7991
|
+
message: safeFailureMessage$2(transcriptResult.reason)
|
|
7992
|
+
};
|
|
7993
|
+
const doubaoTranscript = transcriptResult.status === "fulfilled" ? transcriptResult.value.doubao : {
|
|
7746
7994
|
state: "error",
|
|
7747
7995
|
items: [],
|
|
7748
7996
|
message: safeFailureMessage$2(transcriptResult.reason)
|
|
7749
7997
|
};
|
|
7750
7998
|
return {
|
|
7751
7999
|
dateStamp: date,
|
|
7752
|
-
totalDurationMillis: transcriptResult.status === "fulfilled" ? transcriptResult.value.totalDurationMillis : 0,
|
|
8000
|
+
totalDurationMillis: transcriptResult.status === "fulfilled" ? transcriptResult.value.system.totalDurationMillis : 0,
|
|
7753
8001
|
transcript,
|
|
8002
|
+
doubaoTranscript,
|
|
7754
8003
|
summary: summaryResult.status === "fulfilled" ? summaryResult.value : {
|
|
7755
8004
|
state: "error",
|
|
7756
8005
|
items: [],
|
|
@@ -9183,6 +9432,8 @@ const ARKME_WORLD_IMAGE_REF_TTL_MILLIS = 900 * 1e3;
|
|
|
9183
9432
|
const MAX_ARKME_WORLD_IMAGE_REFS = 2048;
|
|
9184
9433
|
const ARKME_WORLD_RECORD_REF_TTL_MILLIS = 900 * 1e3;
|
|
9185
9434
|
const MAX_ARKME_WORLD_RECORD_REFS = 4096;
|
|
9435
|
+
const ARKME_VOICEPRINT_PLAY_SCOPE = 2;
|
|
9436
|
+
const ARKME_VOICEPRINT_INVITE_TOKEN_MAX_LENGTH = 2048;
|
|
9186
9437
|
function numberValue(value) {
|
|
9187
9438
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
9188
9439
|
}
|
|
@@ -9194,6 +9445,27 @@ function safeFailureMessage(error) {
|
|
|
9194
9445
|
if (error instanceof Error && error.message.trim() !== "") return error.message;
|
|
9195
9446
|
return "未知错误";
|
|
9196
9447
|
}
|
|
9448
|
+
function optionalTrimmedText(value, limit) {
|
|
9449
|
+
const normalized = value?.replace(/\s+/g, " ").trim();
|
|
9450
|
+
if (normalized === void 0 || normalized === "") return void 0;
|
|
9451
|
+
return normalized.length <= limit ? normalized : `${normalized.slice(0, limit).trimEnd()}...`;
|
|
9452
|
+
}
|
|
9453
|
+
function buildVoiceprintInviteShareUrl(environment, token) {
|
|
9454
|
+
const url = new URL("/app/voiceprint/invite", environment === "prod" ? "https://jiwo.cc" : "https://jotmo-app.senguo.me");
|
|
9455
|
+
url.hash = `t=${encodeURIComponent(token)}`;
|
|
9456
|
+
return url.toString();
|
|
9457
|
+
}
|
|
9458
|
+
function validVoiceprintInviteToken(token) {
|
|
9459
|
+
if (token === "" || token.length > ARKME_VOICEPRINT_INVITE_TOKEN_MAX_LENGTH) return false;
|
|
9460
|
+
let byteLength = 0;
|
|
9461
|
+
for (const char of token) {
|
|
9462
|
+
const codePoint = char.codePointAt(0) ?? 0;
|
|
9463
|
+
if (codePoint <= 31 || codePoint === 127) return false;
|
|
9464
|
+
byteLength += codePoint <= 127 ? 1 : codePoint <= 2047 ? 2 : codePoint <= 65535 ? 3 : 4;
|
|
9465
|
+
if (byteLength > ARKME_VOICEPRINT_INVITE_TOKEN_MAX_LENGTH) return false;
|
|
9466
|
+
}
|
|
9467
|
+
return true;
|
|
9468
|
+
}
|
|
9197
9469
|
function worldVisibility(checkStatus) {
|
|
9198
9470
|
if (checkStatus === 1) return "pending_review";
|
|
9199
9471
|
if (checkStatus === 4) return "rejected";
|
|
@@ -9296,6 +9568,27 @@ var WorldService = class {
|
|
|
9296
9568
|
...hasMore ? { nextOffset } : {}
|
|
9297
9569
|
};
|
|
9298
9570
|
}
|
|
9571
|
+
async listMyWorldFeed(options = {}) {
|
|
9572
|
+
const session = await this.runtime.requireSession();
|
|
9573
|
+
const limit = Math.min(20, Math.max(1, Math.trunc(options.limit ?? 20)));
|
|
9574
|
+
const offset = Math.max(0, Math.trunc(options.offset ?? 0));
|
|
9575
|
+
const data = await this.runtime.authenticatedWorldPost("/api/v1/public-record/my-list", {
|
|
9576
|
+
limit,
|
|
9577
|
+
offset
|
|
9578
|
+
}, session, options.signal);
|
|
9579
|
+
const rawItems = listValue(data.list);
|
|
9580
|
+
const resolvedAvatars = await this.resolveWorldAvatarUrls(rawItems, session, options.signal);
|
|
9581
|
+
const items = (await Promise.all(rawItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars)))).filter((item) => item !== void 0);
|
|
9582
|
+
const total = Math.max(0, Math.trunc(numberValue(data.total)));
|
|
9583
|
+
const nextOffset = offset + rawItems.length;
|
|
9584
|
+
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
9585
|
+
return {
|
|
9586
|
+
items,
|
|
9587
|
+
total,
|
|
9588
|
+
hasMore,
|
|
9589
|
+
...hasMore ? { nextOffset } : {}
|
|
9590
|
+
};
|
|
9591
|
+
}
|
|
9299
9592
|
async worldVoiceprintPlaybackAvailability(recordRefs, signal) {
|
|
9300
9593
|
const session = await this.runtime.requireSession();
|
|
9301
9594
|
const normalizedRefs = [...new Set(recordRefs.map((value) => value.trim()).filter((value) => value !== ""))].slice(0, 20);
|
|
@@ -9357,6 +9650,28 @@ var WorldService = class {
|
|
|
9357
9650
|
chunkEndRune
|
|
9358
9651
|
};
|
|
9359
9652
|
}
|
|
9653
|
+
async createWorldVoiceprintInviteIntent(recordRef, signal) {
|
|
9654
|
+
const session = await this.runtime.requireSession();
|
|
9655
|
+
const entry = this.openWorldRecordRef(recordRef, session.userId);
|
|
9656
|
+
const peerUserId = entry.ownerUserId ?? 0;
|
|
9657
|
+
if (!Number.isSafeInteger(peerUserId) || peerUserId <= 0) throw new ArkmePluginError("world-voiceprint-invite-target-missing", "无法确认这条世界动态的作者,请刷新后重试", false);
|
|
9658
|
+
if (peerUserId === session.userId) throw new ArkmePluginError("world-voiceprint-invite-self-invalid", "这是你自己的动态,不需要提醒自己开启声纹", false, 409);
|
|
9659
|
+
const data = await this.runtime.authenticatedAudioPost("/api/v1/audio/voiceprint/invites/create", { scope: ARKME_VOICEPRINT_PLAY_SCOPE }, session, signal, {
|
|
9660
|
+
lane: "write",
|
|
9661
|
+
bypassCache: true
|
|
9662
|
+
});
|
|
9663
|
+
const token = stringValue$1(data.invite_token).trim();
|
|
9664
|
+
const expiresAtMillis = Math.trunc(numberValue(data.expires_at));
|
|
9665
|
+
const scope = Math.trunc(numberValue(data.scope));
|
|
9666
|
+
if (!validVoiceprintInviteToken(token) || expiresAtMillis <= 0 || scope !== ARKME_VOICEPRINT_PLAY_SCOPE) throw new ArkmePluginError("world-voiceprint-invite-contract-invalid", "声纹邀请响应不完整,请稍后重试", true, 502);
|
|
9667
|
+
return {
|
|
9668
|
+
peerUserId,
|
|
9669
|
+
peerDisplayName: optionalTrimmedText(entry.authorName, 64) ?? "这位用户",
|
|
9670
|
+
inviteUrl: buildVoiceprintInviteShareUrl(this.runtime.config.environment, token),
|
|
9671
|
+
expiresAtMillis,
|
|
9672
|
+
...entry.textPreview === void 0 ? {} : { textPreview: entry.textPreview }
|
|
9673
|
+
};
|
|
9674
|
+
}
|
|
9360
9675
|
async listWorldInteractions(recordRef, options = {}) {
|
|
9361
9676
|
const session = await this.runtime.requireSession();
|
|
9362
9677
|
const root = this.openWorldRecordRef(recordRef, session.userId);
|
|
@@ -9567,7 +9882,14 @@ var WorldService = class {
|
|
|
9567
9882
|
}
|
|
9568
9883
|
const avatarRef = this.isTrustedWorldImageUrl(avatarUrl) ? await this.sealWorldImageRef(viewerUserId, avatarUrl) : void 0;
|
|
9569
9884
|
return {
|
|
9570
|
-
recordRef: await this.worldRecordRef(viewerUserId, recordUid,
|
|
9885
|
+
recordRef: await this.worldRecordRef(viewerUserId, recordUid, {
|
|
9886
|
+
ownerUserId,
|
|
9887
|
+
authorName: stringValue$1(item.nick_name ?? item.nickname).trim() || "Arkme用户",
|
|
9888
|
+
...(() => {
|
|
9889
|
+
const textPreview = optionalTrimmedText(headline || textContent, 80);
|
|
9890
|
+
return textPreview === void 0 ? {} : { textPreview };
|
|
9891
|
+
})()
|
|
9892
|
+
}),
|
|
9571
9893
|
authorName: stringValue$1(item.nick_name ?? item.nickname).trim() || "Arkme用户",
|
|
9572
9894
|
...avatarRef === void 0 ? {} : { avatarRef },
|
|
9573
9895
|
...avatarRef === void 0 && avatarFallback !== void 0 ? { avatarFallback } : {},
|
|
@@ -9637,7 +9959,14 @@ var WorldService = class {
|
|
|
9637
9959
|
const avatarFallback = worldPhoneDefaultAvatar(rawAvatar);
|
|
9638
9960
|
const avatarRef = this.isTrustedWorldImageUrl(avatarUrl) ? await this.sealWorldImageRef(viewerUserId, avatarUrl) : void 0;
|
|
9639
9961
|
return {
|
|
9640
|
-
interactionRef: await this.worldRecordRef(viewerUserId, recordUid
|
|
9962
|
+
interactionRef: await this.worldRecordRef(viewerUserId, recordUid, {
|
|
9963
|
+
ownerUserId,
|
|
9964
|
+
authorName: stringValue$1(item.nick_name ?? item.nickname).trim() || "Arkme用户",
|
|
9965
|
+
...(() => {
|
|
9966
|
+
const textPreview = optionalTrimmedText(textContent, 80);
|
|
9967
|
+
return textPreview === void 0 ? {} : { textPreview };
|
|
9968
|
+
})()
|
|
9969
|
+
}),
|
|
9641
9970
|
parentRef: await this.worldRecordRef(viewerUserId, parentRecordUid),
|
|
9642
9971
|
authorName: stringValue$1(item.nick_name ?? item.nickname).trim() || "Arkme用户",
|
|
9643
9972
|
...avatarRef === void 0 ? {} : { avatarRef },
|
|
@@ -9650,16 +9979,20 @@ var WorldService = class {
|
|
|
9650
9979
|
voiceCount
|
|
9651
9980
|
};
|
|
9652
9981
|
}
|
|
9653
|
-
async worldRecordRef(viewerUserId, recordUid,
|
|
9982
|
+
async worldRecordRef(viewerUserId, recordUid, metadata = {}) {
|
|
9654
9983
|
const recordRef = `arkme-world-record-v1.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(`world-record-v1:${String(viewerUserId)}:${recordUid}`).digest("base64url")}`;
|
|
9655
9984
|
const now = Date.now();
|
|
9656
9985
|
this.pruneWorldRecordRefs(now);
|
|
9657
9986
|
const previous = this.worldRecordRefs.get(recordRef);
|
|
9658
|
-
const resolvedOwnerUserId = ownerUserId ?? previous?.ownerUserId;
|
|
9987
|
+
const resolvedOwnerUserId = metadata.ownerUserId ?? previous?.ownerUserId;
|
|
9988
|
+
const authorName = optionalTrimmedText(metadata.authorName, 64) ?? previous?.authorName;
|
|
9989
|
+
const textPreview = optionalTrimmedText(metadata.textPreview, 80) ?? previous?.textPreview;
|
|
9659
9990
|
this.worldRecordRefs.set(recordRef, {
|
|
9660
9991
|
viewerUserId,
|
|
9661
9992
|
recordUid,
|
|
9662
9993
|
...resolvedOwnerUserId === void 0 || resolvedOwnerUserId <= 0 ? {} : { ownerUserId: resolvedOwnerUserId },
|
|
9994
|
+
...authorName === void 0 ? {} : { authorName },
|
|
9995
|
+
...textPreview === void 0 ? {} : { textPreview },
|
|
9663
9996
|
expiresAtMillis: now + ARKME_WORLD_RECORD_REF_TTL_MILLIS
|
|
9664
9997
|
});
|
|
9665
9998
|
return recordRef;
|
|
@@ -9741,8 +10074,18 @@ var WorldService = class {
|
|
|
9741
10074
|
//#endregion
|
|
9742
10075
|
//#region src/types.ts
|
|
9743
10076
|
const ARKME_PROVIDER_CONTRACT_VERSION = 1;
|
|
10077
|
+
const ARKME_DEFAULT_SHARE_WEBSITE = "https://app.arkme.ai";
|
|
9744
10078
|
//#endregion
|
|
9745
10079
|
//#region src/arkme-service.ts
|
|
10080
|
+
function worldVoiceprintInviteMessage(input) {
|
|
10081
|
+
return `${input.textPreview === void 0 ? "我想邀请你开启声纹。" : `我看到你在世界里发的「${input.textPreview}」,想邀请你开启声纹。`}\n以后看到你的世界动态时,可以直接听到你的声音。\n${input.inviteUrl}`;
|
|
10082
|
+
}
|
|
10083
|
+
function voiceprintInviteRateLimitMessage(error) {
|
|
10084
|
+
if (!(error instanceof ArkmePluginError)) return void 0;
|
|
10085
|
+
if (error.upstreamStatus !== 429 && error.httpStatus !== 429 && !/\bHTTP\s*429\b/.test(error.message)) return void 0;
|
|
10086
|
+
const seconds = error.retryAfterMillis === void 0 ? 0 : Math.ceil(error.retryAfterMillis / 1e3);
|
|
10087
|
+
return seconds > 0 ? `提醒发送太频繁了,请 ${String(seconds)} 秒后再试。` : "提醒发送太频繁了,稍后再试。";
|
|
10088
|
+
}
|
|
9746
10089
|
var ArkmeService = class {
|
|
9747
10090
|
config;
|
|
9748
10091
|
sessionStore;
|
|
@@ -9773,6 +10116,7 @@ var ArkmeService = class {
|
|
|
9773
10116
|
interwoven;
|
|
9774
10117
|
aiPolish;
|
|
9775
10118
|
chat;
|
|
10119
|
+
contact;
|
|
9776
10120
|
constructor(config, sessionStore, stateStore, fetchImpl = fetch, pendingSessionStore, outgoingCallBroker = new ArkmeOutgoingCallBroker()) {
|
|
9777
10121
|
this.config = config;
|
|
9778
10122
|
this.sessionStore = sessionStore;
|
|
@@ -9809,6 +10153,7 @@ var ArkmeService = class {
|
|
|
9809
10153
|
this.aiPolish = new GroupAiPolishService(this.runtime, this.source, { sendChatSourceTextRaw: async (...args) => await this.chat.sendChatSourceTextRaw(...args) });
|
|
9810
10154
|
this.realtime = new ChatRealtimeService(this.runtime, this.source, { chatTimelineItems: async (data, session) => await this.chat.chatTimelineItems(data, session) });
|
|
9811
10155
|
this.chat = new ChatService(this.runtime, this.source, this.profile, this.media, this.record, this.bot, this.arko, this.aiPolish, this.realtime);
|
|
10156
|
+
this.contact = new ContactService(this.runtime, this.source, this.profile, this.realtime);
|
|
9812
10157
|
this.auth = new AuthService(this.runtime, this.profile, {
|
|
9813
10158
|
reconnectChatRealtime: () => {
|
|
9814
10159
|
this.realtime.reconnect();
|
|
@@ -9826,6 +10171,7 @@ var ArkmeService = class {
|
|
|
9826
10171
|
this.interwoven.dispose();
|
|
9827
10172
|
this.world.dispose();
|
|
9828
10173
|
this.arrangement.dispose();
|
|
10174
|
+
this.contact.dispose();
|
|
9829
10175
|
}
|
|
9830
10176
|
startChatRealtime() {
|
|
9831
10177
|
return this.realtime.startChatRealtime();
|
|
@@ -9860,6 +10206,9 @@ var ArkmeService = class {
|
|
|
9860
10206
|
async createBot(input, options = {}) {
|
|
9861
10207
|
return await this.bot.createBot(input, options);
|
|
9862
10208
|
}
|
|
10209
|
+
async createBotSummary(input, options = {}) {
|
|
10210
|
+
return await this.bot.createBotSummary(input, options);
|
|
10211
|
+
}
|
|
9863
10212
|
async revealBotSecret(botRef, options = {}) {
|
|
9864
10213
|
return await this.bot.revealBotSecret(botRef, options);
|
|
9865
10214
|
}
|
|
@@ -9886,7 +10235,8 @@ var ArkmeService = class {
|
|
|
9886
10235
|
captchaId: this.config.geetestCaptchaId,
|
|
9887
10236
|
environment: this.config.environment,
|
|
9888
10237
|
testLoginEnabled: this.config.environment === "test",
|
|
9889
|
-
callAssetBasePath: `${this.config.routePath}/call
|
|
10238
|
+
callAssetBasePath: `${this.config.routePath}/call`,
|
|
10239
|
+
shareWebsite: this.config.shareWebsite ?? "https://app.arkme.ai"
|
|
9890
10240
|
};
|
|
9891
10241
|
}
|
|
9892
10242
|
providerCapabilities() {
|
|
@@ -9918,6 +10268,8 @@ var ArkmeService = class {
|
|
|
9918
10268
|
groupMemberAdd: true,
|
|
9919
10269
|
userCard: true,
|
|
9920
10270
|
openPrivateChat: true,
|
|
10271
|
+
contactAdd: true,
|
|
10272
|
+
conversationQuickAdd: true,
|
|
9921
10273
|
groupSettings: true,
|
|
9922
10274
|
extensionManagement: true,
|
|
9923
10275
|
extensionMetadataEdit: true,
|
|
@@ -9926,9 +10278,12 @@ var ArkmeService = class {
|
|
|
9926
10278
|
worldFeed: true,
|
|
9927
10279
|
worldInteractions: true,
|
|
9928
10280
|
worldVoiceprintPlayback: true,
|
|
10281
|
+
worldVoiceprintInvite: true,
|
|
9929
10282
|
arrangements: true,
|
|
9930
10283
|
myExtensions: true,
|
|
9931
10284
|
extensionPublish: true,
|
|
10285
|
+
recordingTranscripts: true,
|
|
10286
|
+
recordingDoubaoBackfill: true,
|
|
9932
10287
|
extensionReviews: true,
|
|
9933
10288
|
...this.relatedRecording.isEnabled() ? { relatedRecordings: true } : {}
|
|
9934
10289
|
},
|
|
@@ -9974,6 +10329,7 @@ var ArkmeService = class {
|
|
|
9974
10329
|
return await this.outgoingCall.releaseOutgoingCall(callRequestId);
|
|
9975
10330
|
}
|
|
9976
10331
|
dispose() {
|
|
10332
|
+
this.contact.dispose();
|
|
9977
10333
|
this.realtime.dispose();
|
|
9978
10334
|
this.arko.dispose();
|
|
9979
10335
|
this.auth.dispose();
|
|
@@ -9994,6 +10350,12 @@ var ArkmeService = class {
|
|
|
9994
10350
|
async cachedProfile() {
|
|
9995
10351
|
return await this.profile.cachedProfile();
|
|
9996
10352
|
}
|
|
10353
|
+
async searchContact(identifier, options = {}) {
|
|
10354
|
+
return await this.contact.search(identifier, options);
|
|
10355
|
+
}
|
|
10356
|
+
async addContact(contactRef, options = {}) {
|
|
10357
|
+
return await this.contact.add(contactRef, options);
|
|
10358
|
+
}
|
|
9997
10359
|
async extensionAuthors(userIds, signal) {
|
|
9998
10360
|
return await this.extensionReview.extensionAuthors(userIds, signal);
|
|
9999
10361
|
}
|
|
@@ -10008,8 +10370,12 @@ var ArkmeService = class {
|
|
|
10008
10370
|
return await this.recording.recordingCalendar(fromStamp, toStamp, signal);
|
|
10009
10371
|
}
|
|
10010
10372
|
/** Read-only Audio capability shared by the built-in UI and Arkme recording tools. */
|
|
10011
|
-
async recordingTranscript(dateStamp, signal) {
|
|
10012
|
-
return await this.recording.recordingTranscript(dateStamp, signal);
|
|
10373
|
+
async recordingTranscript(dateStamp, signal, source = "system") {
|
|
10374
|
+
return await this.recording.recordingTranscript(dateStamp, signal, source);
|
|
10375
|
+
}
|
|
10376
|
+
/** Queue Doubao backfill only after an explicit UI, SDK, or Tool request. */
|
|
10377
|
+
async startRecordingDoubaoBackfill(dateStamp, signal) {
|
|
10378
|
+
return await this.recording.startRecordingDoubaoBackfill(dateStamp, signal);
|
|
10013
10379
|
}
|
|
10014
10380
|
/** Read-only Audio capability shared by the built-in UI and Arkme recording tools. */
|
|
10015
10381
|
async recordingProjection(dateStamp, kind, signal) {
|
|
@@ -10141,6 +10507,9 @@ var ArkmeService = class {
|
|
|
10141
10507
|
async addGroupMembers(sourceRef, candidateRefs, signal) {
|
|
10142
10508
|
return await this.group.addGroupMembers(sourceRef, candidateRefs, signal);
|
|
10143
10509
|
}
|
|
10510
|
+
async createGroup(title, clientMutationId, options = {}) {
|
|
10511
|
+
return await this.group.createGroup(title, clientMutationId, options);
|
|
10512
|
+
}
|
|
10144
10513
|
async groupSettings(sourceRef, signal) {
|
|
10145
10514
|
return await this.group.groupSettings(sourceRef, signal);
|
|
10146
10515
|
}
|
|
@@ -10353,12 +10722,41 @@ var ArkmeService = class {
|
|
|
10353
10722
|
async listWorldFeed(options = {}) {
|
|
10354
10723
|
return await this.world.listWorldFeed(options);
|
|
10355
10724
|
}
|
|
10725
|
+
/** Build the signed-in account's World projection without exposing owner IDs. */
|
|
10726
|
+
async listMyWorldFeed(options = {}) {
|
|
10727
|
+
return await this.world.listMyWorldFeed(options);
|
|
10728
|
+
}
|
|
10356
10729
|
async worldVoiceprintPlaybackAvailability(recordRefs, signal) {
|
|
10357
10730
|
return await this.world.worldVoiceprintPlaybackAvailability(recordRefs, signal);
|
|
10358
10731
|
}
|
|
10359
10732
|
async generateWorldVoiceprintPlayback(input) {
|
|
10360
10733
|
return await this.world.generateWorldVoiceprintPlayback(input);
|
|
10361
10734
|
}
|
|
10735
|
+
async inviteWorldVoiceprint(recordRef, signal) {
|
|
10736
|
+
try {
|
|
10737
|
+
const intent = await this.world.createWorldVoiceprintInviteIntent(recordRef, signal);
|
|
10738
|
+
const privateChat = await this.chat.openPrivateChatFromUser(intent.peerUserId, {
|
|
10739
|
+
displayName: intent.peerDisplayName,
|
|
10740
|
+
...signal === void 0 ? {} : { signal }
|
|
10741
|
+
});
|
|
10742
|
+
const sent = await this.chat.sendSourceText(privateChat.source.sourceRef, worldVoiceprintInviteMessage(intent), signal === void 0 ? {} : { signal });
|
|
10743
|
+
if (sent.localState !== "synced") throw new ArkmePluginError("world-voiceprint-invite-send-pending", sent.error ?? "声纹邀请已进入发送队列,请稍后在私聊中确认", true);
|
|
10744
|
+
return {
|
|
10745
|
+
sent: true,
|
|
10746
|
+
peerDisplayName: intent.peerDisplayName,
|
|
10747
|
+
messageItemUid: sent.itemUid,
|
|
10748
|
+
expiresAtMillis: intent.expiresAtMillis
|
|
10749
|
+
};
|
|
10750
|
+
} catch (error) {
|
|
10751
|
+
const message = voiceprintInviteRateLimitMessage(error);
|
|
10752
|
+
if (message !== void 0) throw new ArkmePluginError("world-voiceprint-invite-rate-limited", message, true, 429, {
|
|
10753
|
+
cause: error,
|
|
10754
|
+
upstreamStatus: 429,
|
|
10755
|
+
...!(error instanceof ArkmePluginError) || error.retryAfterMillis === void 0 ? {} : { retryAfterMillis: error.retryAfterMillis }
|
|
10756
|
+
});
|
|
10757
|
+
throw error;
|
|
10758
|
+
}
|
|
10759
|
+
}
|
|
10362
10760
|
/** Read the authenticated comment/reply tree behind one account-bound World reference. */
|
|
10363
10761
|
async listWorldInteractions(recordRef, options = {}) {
|
|
10364
10762
|
return await this.world.listWorldInteractions(recordRef, options);
|
|
@@ -10527,6 +10925,7 @@ function canonicalExtensionSignatureMessage(input) {
|
|
|
10527
10925
|
}), "utf8");
|
|
10528
10926
|
}
|
|
10529
10927
|
const ARKME_BUNDLE_ARTIFACT_KIND = "dsh-bundle-tgz";
|
|
10928
|
+
const ARKME_NATIVE_BUNDLE_ARTIFACT_KIND = "dsh-native-package-tgz";
|
|
10530
10929
|
const ARKME_BUNDLE_MAX_BYTES = 100 * 1024 * 1024;
|
|
10531
10930
|
const TAR_BLOCK_BYTES = 512;
|
|
10532
10931
|
const MAX_ARCHIVE_FILES = 1024;
|
|
@@ -10573,9 +10972,22 @@ function writeOctal(header, offset, length, value) {
|
|
|
10573
10972
|
header.write(octal.slice(-(length - 1)), offset, length - 1, "ascii");
|
|
10574
10973
|
header[offset + length - 1] = 0;
|
|
10575
10974
|
}
|
|
10975
|
+
function splitTarPath(path) {
|
|
10976
|
+
const direct = Buffer.from(path, "utf8");
|
|
10977
|
+
if (direct.byteLength <= 100) return { name: direct };
|
|
10978
|
+
const separators = [...path.matchAll(/\//g)].map((match) => match.index).reverse();
|
|
10979
|
+
for (const separator of separators) {
|
|
10980
|
+
const prefix = Buffer.from(path.slice(0, separator), "utf8");
|
|
10981
|
+
const name = Buffer.from(path.slice(separator + 1), "utf8");
|
|
10982
|
+
if (prefix.byteLength <= 155 && name.byteLength <= 100) return {
|
|
10983
|
+
name,
|
|
10984
|
+
prefix
|
|
10985
|
+
};
|
|
10986
|
+
}
|
|
10987
|
+
throw new ArkmeBundleArtifactError("bundle-path-too-long", `Bundle 路径过长:${path}`);
|
|
10988
|
+
}
|
|
10576
10989
|
function tarHeader(path, size) {
|
|
10577
|
-
const name =
|
|
10578
|
-
if (name.byteLength > 100) throw new ArkmeBundleArtifactError("bundle-path-too-long", `Bundle 路径过长:${path}`);
|
|
10990
|
+
const { name, prefix } = splitTarPath(path);
|
|
10579
10991
|
const header = Buffer.alloc(TAR_BLOCK_BYTES);
|
|
10580
10992
|
name.copy(header, 0);
|
|
10581
10993
|
writeOctal(header, 100, 8, 420);
|
|
@@ -10587,6 +10999,7 @@ function tarHeader(path, size) {
|
|
|
10587
10999
|
header[156] = "0".charCodeAt(0);
|
|
10588
11000
|
header.write("ustar\0", 257, 6, "ascii");
|
|
10589
11001
|
header.write("00", 263, 2, "ascii");
|
|
11002
|
+
prefix?.copy(header, 345);
|
|
10590
11003
|
writeOctal(header, 148, 8, [...header].reduce((sum, byte) => sum + byte, 0));
|
|
10591
11004
|
return header;
|
|
10592
11005
|
}
|
|
@@ -10621,7 +11034,9 @@ function readTar(tar) {
|
|
|
10621
11034
|
while (offset + TAR_BLOCK_BYTES <= tar.byteLength) {
|
|
10622
11035
|
const header = tar.subarray(offset, offset + TAR_BLOCK_BYTES);
|
|
10623
11036
|
if (header.every((byte) => byte === 0)) break;
|
|
10624
|
-
const
|
|
11037
|
+
const name = header.subarray(0, 100).toString("utf8").replace(/\0.*$/, "");
|
|
11038
|
+
const prefix = header.subarray(345, 500).toString("utf8").replace(/\0.*$/, "");
|
|
11039
|
+
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
10625
11040
|
validateArchivePath(path);
|
|
10626
11041
|
if (files.has(path)) throw new ArkmeBundleArtifactError("bundle-duplicate-path", `Bundle 包含重复路径:${path}`);
|
|
10627
11042
|
const type = header[156];
|
|
@@ -10706,6 +11121,105 @@ function validatePatch(raw, packageName, executionModel) {
|
|
|
10706
11121
|
if (ids.size === 0) throw new ArkmeBundleArtifactError("bundle-patch-empty", "Bundle patch 至少需要一条 row");
|
|
10707
11122
|
return [...ids].sort();
|
|
10708
11123
|
}
|
|
11124
|
+
const NATIVE_LIFECYCLE_SCRIPTS = /* @__PURE__ */ new Set([
|
|
11125
|
+
"preinstall",
|
|
11126
|
+
"install",
|
|
11127
|
+
"postinstall",
|
|
11128
|
+
"prepare",
|
|
11129
|
+
"prepublish",
|
|
11130
|
+
"prepublishOnly",
|
|
11131
|
+
"prepack",
|
|
11132
|
+
"postpack"
|
|
11133
|
+
]);
|
|
11134
|
+
function nonEmptyManifestValue(value) {
|
|
11135
|
+
if (value === void 0 || value === null) return false;
|
|
11136
|
+
if (typeof value === "string") return value.trim() !== "";
|
|
11137
|
+
if (Array.isArray(value)) return value.length > 0;
|
|
11138
|
+
if (typeof value === "object") return Object.keys(value).length > 0;
|
|
11139
|
+
if (typeof value === "boolean") return value;
|
|
11140
|
+
return true;
|
|
11141
|
+
}
|
|
11142
|
+
function inspectNativePatch(raw, packageName) {
|
|
11143
|
+
const document = parseDocument(raw.toString("utf8"), { uniqueKeys: true });
|
|
11144
|
+
if (document.errors.length > 0) throw new ArkmeBundleArtifactError("bundle-patch-invalid", "Bundle patch YAML 格式无效");
|
|
11145
|
+
const value = document.toJS();
|
|
11146
|
+
if (!Array.isArray(value)) throw new ArkmeBundleArtifactError("bundle-patch-invalid", "Bundle patch 必须是操作数组");
|
|
11147
|
+
const patchIds = /* @__PURE__ */ new Set();
|
|
11148
|
+
const capabilities = /* @__PURE__ */ new Set();
|
|
11149
|
+
for (const operation of value) {
|
|
11150
|
+
if (operation === null || typeof operation !== "object" || Array.isArray(operation)) {
|
|
11151
|
+
capabilities.add("profile_patch_override");
|
|
11152
|
+
continue;
|
|
11153
|
+
}
|
|
11154
|
+
const record = operation;
|
|
11155
|
+
if (!(Object.keys(record).length === 1 && Array.isArray(record.insert))) {
|
|
11156
|
+
capabilities.add("profile_patch_override");
|
|
11157
|
+
if (typeof record.id === "string" && record.id.trim() !== "") patchIds.add(record.id.trim());
|
|
11158
|
+
continue;
|
|
11159
|
+
}
|
|
11160
|
+
for (const row of record.insert) {
|
|
11161
|
+
if (row === null || typeof row !== "object" || Array.isArray(row)) continue;
|
|
11162
|
+
const item = row;
|
|
11163
|
+
if (typeof item.id === "string" && item.id.trim() !== "") patchIds.add(item.id.trim());
|
|
11164
|
+
if (typeof item.name === "string" && item.name !== packageName && !item.name.startsWith(`${packageName}/`)) capabilities.add("external_package_reference");
|
|
11165
|
+
}
|
|
11166
|
+
}
|
|
11167
|
+
return {
|
|
11168
|
+
patchIds: [...patchIds].sort(),
|
|
11169
|
+
capabilities: [...capabilities].sort()
|
|
11170
|
+
};
|
|
11171
|
+
}
|
|
11172
|
+
function inspectNativeManifest(manifest, files) {
|
|
11173
|
+
if (typeof manifest.name !== "string" || manifest.name.length > 214 || !PACKAGE_NAME.test(manifest.name) || manifest.name.startsWith("@deepseek-ai/") || manifest.name === "@senguoyun/dsh-arkme" || manifest.name.startsWith("@arkme-local/")) throw new ArkmeBundleArtifactError("bundle-package-name-invalid", "Bundle package name 无效或属于保留集合");
|
|
11174
|
+
if (typeof manifest.version !== "string" || !SEMVER.test(manifest.version)) throw new ArkmeBundleArtifactError("bundle-version-invalid", "Bundle version 必须是严格 SemVer");
|
|
11175
|
+
if (manifest.dsh?.arkme !== void 0 && manifest.dsh.arkme !== null) throw new ArkmeBundleArtifactError("bundle-execution-model-invalid", "原生 DSH V3 Bundle 不允许声明 Arkme sandbox marker");
|
|
11176
|
+
const patch = manifest.dsh?.bundle?.patch;
|
|
11177
|
+
if (typeof patch !== "string" || patch.trim() === "" || patch.includes("\\") || patch.startsWith("/")) throw new ArkmeBundleArtifactError("bundle-patch-missing", "Bundle 必须声明包内 dsh.bundle.patch");
|
|
11178
|
+
const patchPath = `package/${posix.normalize(patch.replace(/^\.\//, ""))}`;
|
|
11179
|
+
if (!files.has(patchPath) || patchPath.includes("/../")) throw new ArkmeBundleArtifactError("bundle-patch-missing", "Bundle patch 不在包内");
|
|
11180
|
+
const capabilities = /* @__PURE__ */ new Set();
|
|
11181
|
+
if (nonEmptyManifestValue(manifest.dependencies)) capabilities.add("runtime_dependencies");
|
|
11182
|
+
if (nonEmptyManifestValue(manifest.optionalDependencies)) capabilities.add("optional_dependencies");
|
|
11183
|
+
if (nonEmptyManifestValue(manifest.bundledDependencies) || nonEmptyManifestValue(manifest.bundleDependencies)) capabilities.add("bundled_dependencies");
|
|
11184
|
+
for (const name of Object.keys(manifest.peerDependencies ?? {})) if (!name.startsWith("@deepseek-ai/") && name !== "@senguoyun/dsh-arkme" && name !== "react" && name !== "react-dom") {
|
|
11185
|
+
capabilities.add("peer_dependencies");
|
|
11186
|
+
break;
|
|
11187
|
+
}
|
|
11188
|
+
if (Object.entries(manifest.scripts ?? {}).some(([name, value]) => NATIVE_LIFECYCLE_SCRIPTS.has(name) && nonEmptyManifestValue(value))) capabilities.add("lifecycle_scripts");
|
|
11189
|
+
if (nonEmptyManifestValue(manifest.bin)) capabilities.add("bin");
|
|
11190
|
+
if ([...files.keys()].some((name) => name.toLowerCase().endsWith(".node"))) capabilities.add("native_addon");
|
|
11191
|
+
return {
|
|
11192
|
+
patchPath,
|
|
11193
|
+
capabilities: [...capabilities].sort()
|
|
11194
|
+
};
|
|
11195
|
+
}
|
|
11196
|
+
function inspectNativeBundleArtifactV3(bytes) {
|
|
11197
|
+
assertArchiveSize(bytes.byteLength, "Bundle");
|
|
11198
|
+
let tar;
|
|
11199
|
+
try {
|
|
11200
|
+
tar = gunzipSync(bytes, { maxOutputLength: 105907200 });
|
|
11201
|
+
} catch {
|
|
11202
|
+
throw new ArkmeBundleArtifactError("bundle-gzip-invalid", "Bundle 不是有效 gzip");
|
|
11203
|
+
}
|
|
11204
|
+
const files = readTar(tar);
|
|
11205
|
+
const packageJSON = files.get("package/package.json");
|
|
11206
|
+
if (packageJSON === void 0) throw new ArkmeBundleArtifactError("bundle-package-json-missing", "Bundle 缺少 package.json");
|
|
11207
|
+
const manifest = readManifest(packageJSON);
|
|
11208
|
+
const inspected = inspectNativeManifest(manifest, files);
|
|
11209
|
+
const patch = inspectNativePatch(files.get(inspected.patchPath), manifest.name);
|
|
11210
|
+
const nativeCapabilities = [.../* @__PURE__ */ new Set([...inspected.capabilities, ...patch.capabilities])].sort();
|
|
11211
|
+
return {
|
|
11212
|
+
bytes: Buffer.from(bytes),
|
|
11213
|
+
bundleSha256: bundleSha256(bytes),
|
|
11214
|
+
packageJsonSha256: bundleSha256(packageJSON),
|
|
11215
|
+
packageName: manifest.name,
|
|
11216
|
+
version: manifest.version,
|
|
11217
|
+
executionModel: "dsh-native",
|
|
11218
|
+
nativeCapabilities,
|
|
11219
|
+
files,
|
|
11220
|
+
patchIds: patch.patchIds
|
|
11221
|
+
};
|
|
11222
|
+
}
|
|
10709
11223
|
function inspectBundleArtifact(bytes) {
|
|
10710
11224
|
assertArchiveSize(bytes.byteLength, "Bundle");
|
|
10711
11225
|
let tar;
|
|
@@ -10736,29 +11250,114 @@ function pathInside(root, target) {
|
|
|
10736
11250
|
const fromRoot = relative(root, target);
|
|
10737
11251
|
return fromRoot === "" || !fromRoot.startsWith(`..${sep}`) && fromRoot !== ".." && !isAbsolute(fromRoot);
|
|
10738
11252
|
}
|
|
10739
|
-
function
|
|
11253
|
+
function globPattern(pattern) {
|
|
11254
|
+
let expression = "^";
|
|
11255
|
+
for (let index = 0; index < pattern.length; index += 1) {
|
|
11256
|
+
const character = pattern[index];
|
|
11257
|
+
if (character === "*") if (pattern[index + 1] === "*") {
|
|
11258
|
+
index += 1;
|
|
11259
|
+
if (pattern[index + 1] === "/") {
|
|
11260
|
+
index += 1;
|
|
11261
|
+
expression += "(?:.*/)?";
|
|
11262
|
+
} else expression += ".*";
|
|
11263
|
+
} else expression += "[^/]*";
|
|
11264
|
+
else if (character === "?") expression += "[^/]";
|
|
11265
|
+
else expression += character.replace(/[|\\{}()[\]^$+?.]/g, "\\$&");
|
|
11266
|
+
}
|
|
11267
|
+
return new RegExp(`${expression}$`);
|
|
11268
|
+
}
|
|
11269
|
+
function collectPackageFiles(root, manifest, nativeV3 = false) {
|
|
10740
11270
|
const canonicalRoot = realpathSync(root);
|
|
10741
11271
|
const selected = /* @__PURE__ */ new Map();
|
|
10742
|
-
const
|
|
11272
|
+
const ignoredNativeRootEntries = /* @__PURE__ */ new Set([
|
|
11273
|
+
".git",
|
|
11274
|
+
".hg",
|
|
11275
|
+
".svn",
|
|
11276
|
+
"node_modules"
|
|
11277
|
+
]);
|
|
11278
|
+
const ignoredNativeFiles = /* @__PURE__ */ new Set([
|
|
11279
|
+
".npmrc",
|
|
11280
|
+
".yarnrc",
|
|
11281
|
+
".yarnrc.yml",
|
|
11282
|
+
".pnpmfile.cjs"
|
|
11283
|
+
]);
|
|
11284
|
+
const add = (absolute, allowIgnore = false) => {
|
|
10743
11285
|
const stat = lstatSync(absolute);
|
|
10744
|
-
|
|
11286
|
+
const rel = relative(canonicalRoot, absolute).split(sep).join("/");
|
|
11287
|
+
const first = rel.split("/")[0] ?? "";
|
|
11288
|
+
const basename = rel.split("/").at(-1) ?? "";
|
|
11289
|
+
if (allowIgnore && (ignoredNativeRootEntries.has(first) || ignoredNativeFiles.has(basename) || basename === ".env" || basename.startsWith(".env."))) return;
|
|
11290
|
+
if (stat.isSymbolicLink()) {
|
|
11291
|
+
if (allowIgnore) return;
|
|
11292
|
+
throw new ArkmeBundleArtifactError("bundle-link-forbidden", "Bundle source 不允许符号链接");
|
|
11293
|
+
}
|
|
10745
11294
|
const canonical = realpathSync(absolute);
|
|
10746
11295
|
if (!pathInside(canonicalRoot, canonical)) throw new ArkmeBundleArtifactError("bundle-path-invalid", "Bundle source 逃逸 package root");
|
|
10747
11296
|
if (stat.isDirectory()) {
|
|
10748
|
-
for (const child of readdirSync(canonical).sort()) add(join(canonical, child));
|
|
11297
|
+
for (const child of readdirSync(canonical).sort()) add(join(canonical, child), allowIgnore);
|
|
10749
11298
|
return;
|
|
10750
11299
|
}
|
|
10751
11300
|
if (!stat.isFile()) throw new ArkmeBundleArtifactError("bundle-file-type-forbidden", "Bundle source 只允许普通文件");
|
|
10752
|
-
const
|
|
10753
|
-
selected.set(`package/${
|
|
11301
|
+
const canonicalRel = relative(canonicalRoot, canonical).split(sep).join("/");
|
|
11302
|
+
selected.set(`package/${canonicalRel}`, readFileSync(canonical));
|
|
11303
|
+
};
|
|
11304
|
+
const addNativePackageExtras = () => {
|
|
11305
|
+
if (!nativeV3) return;
|
|
11306
|
+
for (const child of readdirSync(canonicalRoot).sort()) if (/^(?:readme|licen[cs]e|copying|notice)(?:\.|$)/i.test(child)) add(join(canonicalRoot, child), true);
|
|
11307
|
+
const paths = /* @__PURE__ */ new Set();
|
|
11308
|
+
if (typeof manifest.main === "string") paths.add(manifest.main);
|
|
11309
|
+
const bin = manifest.bin;
|
|
11310
|
+
if (typeof bin === "string") paths.add(bin);
|
|
11311
|
+
else if (bin !== null && typeof bin === "object" && !Array.isArray(bin)) {
|
|
11312
|
+
for (const value of Object.values(bin)) if (typeof value === "string") paths.add(value);
|
|
11313
|
+
}
|
|
11314
|
+
const patch = manifest.dsh?.bundle?.patch;
|
|
11315
|
+
if (typeof patch === "string") paths.add(patch);
|
|
11316
|
+
for (const entry of paths) {
|
|
11317
|
+
const target = resolve(canonicalRoot, entry);
|
|
11318
|
+
if (pathInside(canonicalRoot, target) && existsSync(target)) add(target, true);
|
|
11319
|
+
}
|
|
10754
11320
|
};
|
|
10755
11321
|
add(join(canonicalRoot, "package.json"));
|
|
10756
|
-
|
|
10757
|
-
|
|
11322
|
+
const entries = manifest.files ?? [];
|
|
11323
|
+
if (entries.length === 0) {
|
|
11324
|
+
if (!nativeV3) throw new ArkmeBundleArtifactError("bundle-files-missing", "Bundle 必须显式声明 files");
|
|
11325
|
+
for (const child of readdirSync(canonicalRoot).sort()) if (child !== "package.json") add(join(canonicalRoot, child), true);
|
|
11326
|
+
addNativePackageExtras();
|
|
11327
|
+
return selected;
|
|
11328
|
+
}
|
|
11329
|
+
let candidates;
|
|
11330
|
+
const listCandidates = () => {
|
|
11331
|
+
if (candidates !== void 0) return candidates;
|
|
11332
|
+
candidates = [];
|
|
11333
|
+
const walk = (directory) => {
|
|
11334
|
+
for (const child of readdirSync(directory).sort()) {
|
|
11335
|
+
const absolute = join(directory, child);
|
|
11336
|
+
const stat = lstatSync(absolute);
|
|
11337
|
+
if (stat.isSymbolicLink()) continue;
|
|
11338
|
+
if (stat.isDirectory()) walk(absolute);
|
|
11339
|
+
else if (stat.isFile()) candidates.push(relative(canonicalRoot, absolute).split(sep).join("/"));
|
|
11340
|
+
}
|
|
11341
|
+
};
|
|
11342
|
+
walk(canonicalRoot);
|
|
11343
|
+
return candidates;
|
|
11344
|
+
};
|
|
11345
|
+
for (const entry of entries) {
|
|
11346
|
+
if (entry.includes("\\") || entry.startsWith("/") || entry.split("/").includes("..")) throw new ArkmeBundleArtifactError("bundle-files-invalid", `Bundle files 路径无效:${entry}`);
|
|
11347
|
+
const hasGlob = entry.includes("*") || entry.includes("?") || entry.includes("[");
|
|
11348
|
+
if (hasGlob && !nativeV3) throw new ArkmeBundleArtifactError("bundle-files-invalid", "Bundle files 暂不接受 glob 或反斜杠");
|
|
11349
|
+
if (hasGlob) {
|
|
11350
|
+
const matcher = globPattern(entry.replace(/^\.\//, ""));
|
|
11351
|
+
const matches = listCandidates().filter((candidate) => matcher.test(candidate));
|
|
11352
|
+
if (matches.length === 0) throw new ArkmeBundleArtifactError("bundle-files-invalid", `Bundle files 路径无效:${entry}`);
|
|
11353
|
+
for (const match of matches) add(resolve(canonicalRoot, match), true);
|
|
11354
|
+
continue;
|
|
11355
|
+
}
|
|
10758
11356
|
const target = resolve(canonicalRoot, entry);
|
|
10759
|
-
if (!pathInside(canonicalRoot, target) || !statSync(target).isFile() && !statSync(target).isDirectory()) throw new ArkmeBundleArtifactError("bundle-files-invalid", `Bundle files 路径无效:${entry}`);
|
|
10760
|
-
add(target);
|
|
11357
|
+
if (!pathInside(canonicalRoot, target) || !existsSync(target) || !statSync(target).isFile() && !statSync(target).isDirectory()) throw new ArkmeBundleArtifactError("bundle-files-invalid", `Bundle files 路径无效:${entry}`);
|
|
11358
|
+
add(target, nativeV3);
|
|
10761
11359
|
}
|
|
11360
|
+
addNativePackageExtras();
|
|
10762
11361
|
return selected;
|
|
10763
11362
|
}
|
|
10764
11363
|
function packBundleFiles(files) {
|
|
@@ -10772,14 +11371,25 @@ function packBundleFiles(files) {
|
|
|
10772
11371
|
}
|
|
10773
11372
|
};
|
|
10774
11373
|
}
|
|
10775
|
-
function
|
|
10776
|
-
|
|
11374
|
+
function packNativeBundleFiles(files) {
|
|
11375
|
+
const bytes = gzipSync(createTar(files), { level: 9 });
|
|
11376
|
+
assertArchiveSize(bytes.byteLength, "Bundle");
|
|
11377
|
+
return {
|
|
11378
|
+
bundle: inspectNativeBundleArtifactV3(bytes),
|
|
11379
|
+
source: {
|
|
11380
|
+
bytes: Buffer.from(bytes),
|
|
11381
|
+
sourceSha256: bundleSha256(bytes)
|
|
11382
|
+
}
|
|
11383
|
+
};
|
|
10777
11384
|
}
|
|
10778
|
-
function
|
|
11385
|
+
function packLocalNativeBundleDirectoryV3(directory) {
|
|
11386
|
+
return packNativeBundleFiles(collectPackageFiles(directory, readManifest(readFileSync(join(directory, "package.json"))), true));
|
|
11387
|
+
}
|
|
11388
|
+
function readNativeBundleTarballV3(path) {
|
|
10779
11389
|
if (!lstatSync(path).isFile()) throw new ArkmeBundleArtifactError("bundle-tarball-invalid", "本地 Bundle tgz 必须是普通文件");
|
|
10780
11390
|
const bytes = readFileSync(path);
|
|
10781
11391
|
return {
|
|
10782
|
-
bundle:
|
|
11392
|
+
bundle: inspectNativeBundleArtifactV3(bytes),
|
|
10783
11393
|
source: {
|
|
10784
11394
|
bytes: Buffer.from(bytes),
|
|
10785
11395
|
sourceSha256: bundleSha256(bytes)
|
|
@@ -10854,6 +11464,39 @@ function verifyBundleResolutionSignature(resolution, trustedKeys) {
|
|
|
10854
11464
|
}
|
|
10855
11465
|
if (!valid) throw new ArkmePluginError("extension-signature-invalid", "扩展 Bundle 平台签名验证失败", false, 403);
|
|
10856
11466
|
}
|
|
11467
|
+
function canonicalNativeBundleSignatureMessage(input) {
|
|
11468
|
+
return Buffer.from(JSON.stringify({
|
|
11469
|
+
format_version: input.artifact_contract_version,
|
|
11470
|
+
artifact_kind: input.artifact_kind,
|
|
11471
|
+
extension_id: input.extension_id,
|
|
11472
|
+
package_name: input.package_name,
|
|
11473
|
+
version: input.version,
|
|
11474
|
+
execution_model: input.execution_model,
|
|
11475
|
+
bundle_sha256: input.bundle_sha256,
|
|
11476
|
+
package_json_sha256: input.package_json_sha256,
|
|
11477
|
+
source_sha256: input.source_sha256,
|
|
11478
|
+
...input.native_capabilities.length === 0 ? {} : { native_capabilities: input.native_capabilities },
|
|
11479
|
+
published_at: input.published_at,
|
|
11480
|
+
signing_key_id: input.signing_key_id
|
|
11481
|
+
}), "utf8");
|
|
11482
|
+
}
|
|
11483
|
+
function verifyNativeBundleResolutionSignature(resolution, trustedKeys) {
|
|
11484
|
+
const capabilities = resolution.native_capabilities;
|
|
11485
|
+
if (resolution.artifact_contract_version !== 3 || resolution.artifact_kind !== "dsh-native-package-tgz" || resolution.package_name.trim() === "" || resolution.execution_model !== "dsh-native" || ![
|
|
11486
|
+
resolution.bundle_sha256,
|
|
11487
|
+
resolution.package_json_sha256,
|
|
11488
|
+
resolution.source_sha256
|
|
11489
|
+
].every((value) => /^[a-f0-9]{64}$/.test(value)) || !Array.isArray(capabilities) || capabilities.some((value) => typeof value !== "string" || value.trim() === "") || capabilities.some((value, index) => index > 0 && capabilities[index - 1] >= value) || !Number.isSafeInteger(resolution.published_at) || resolution.published_at <= 0 || resolution.signature.trim() === "") throw new ArkmePluginError("extension-signature-envelope-invalid", "原生 DSH V3 签名 envelope 字段无效", false, 502);
|
|
11490
|
+
const key = trustedKeys.get(resolution.signing_key_id);
|
|
11491
|
+
if (key === void 0) throw new ArkmePluginError("extension-signing-key-untrusted", `不信任扩展签名密钥 ${resolution.signing_key_id}`, false, 403);
|
|
11492
|
+
let valid = false;
|
|
11493
|
+
try {
|
|
11494
|
+
valid = verify(null, canonicalNativeBundleSignatureMessage(resolution), publicKey(key), Buffer.from(resolution.signature, "base64"));
|
|
11495
|
+
} catch (error) {
|
|
11496
|
+
throw new ArkmePluginError("extension-signature-invalid", "原生 DSH V3 签名格式无效", false, 403, { cause: error });
|
|
11497
|
+
}
|
|
11498
|
+
if (!valid) throw new ArkmePluginError("extension-signature-invalid", "原生 DSH V3 平台签名验证失败", false, 403);
|
|
11499
|
+
}
|
|
10857
11500
|
//#endregion
|
|
10858
11501
|
//#region src/extensions/persistent-client-bundle.ts
|
|
10859
11502
|
/** This function is serialized into each generated browser bundle. It must stay closure-free. */
|
|
@@ -11513,4 +12156,4 @@ async function invokePersistentArkmeExtension(extensionId, method, args) {
|
|
|
11513
12156
|
return jsonValue(await handler(jsonValue(args)));
|
|
11514
12157
|
}
|
|
11515
12158
|
//#endregion
|
|
11516
|
-
export {
|
|
12159
|
+
export { unpackArkmeExtension as A, ArkmeOutgoingCallError as B, packBundleFiles as C, assertExtensionArtifactSize as D, renderArkmeSandboxHostEntry as E, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as F, ArkmeService as I, ARKME_DEFAULT_SHARE_WEBSITE as L, ARKME_EXTENSION_ICON_MAX_BYTES as M, ARKME_EXTENSION_MAX_BYTES as N, canonicalExtensionJson as O, ARKME_EXTENSION_PREVIEW_MAX_BYTES as P, ARKME_PROVIDER_CONTRACT_VERSION as R, inspectNativeBundleArtifactV3 as S, readNativeBundleTarballV3 as T, ArkmeBundleArtifactError as _, persistentArkmeExtensionActive as a, canonicalBundleJson as b, readPersistentExtensionActivation as c, verifyBundleResolutionSignature as d, verifyExtensionResolutionSignature as f, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as g, ARKME_BUNDLE_MAX_BYTES as h, invokePersistentArkmeExtension as i, ARKME_EXTENSION_FORMAT as j, sha256Hex as k, writePersistentExtensionActivation as l, ARKME_BUNDLE_ARTIFACT_KIND as m, applyPersistentArkmeHostExtension as n, persistentArkmeExtensionRuntimeState as o, verifyNativeBundleResolutionSignature as p, deactivatePersistentArkmeExtension as r, materializePersistentExtensionBundle as s, activatePersistentArkmeExtension as t, renderArkmeBundleClientBundle as u, arkmeSandboxEntryId as v, packLocalNativeBundleDirectoryV3 as w, inspectBundleArtifact as x, bundleSha256 as y, ArkmePluginError as z };
|