@senguoyun/dsh-arkme 0.1.41 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/client.js +23797 -21177
- package/lib/client.js.map +1 -1
- package/lib/index.js +2172 -1053
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-B1gJH2Nx.js → persistent-runtime-LJ4nj7os.js} +1956 -273
- package/lib/sdk.js +40 -0
- package/lib/types/arkme-service.d.ts +38 -8
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/chat-realtime.d.ts +31 -1
- package/lib/types/chat-realtime.d.ts.map +1 -1
- package/lib/types/client/ArkmeChatMemberActions.d.ts +10 -2
- package/lib/types/client/ArkmeChatMemberActions.d.ts.map +1 -1
- package/lib/types/client/ArkmeConfirmDialog.d.ts +19 -0
- package/lib/types/client/ArkmeConfirmDialog.d.ts.map +1 -0
- package/lib/types/client/ArkmeGroupChatControls.d.ts +1 -0
- package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
- package/lib/types/client/ArkmeLinkText.d.ts +12 -1
- package/lib/types/client/ArkmeLinkText.d.ts.map +1 -1
- package/lib/types/client/ArkmeMentionTextarea.d.ts +2 -2
- package/lib/types/client/ArkmeMentionTextarea.d.ts.map +1 -1
- package/lib/types/client/ArkmeMessageWithdrawalDialog.d.ts +8 -0
- package/lib/types/client/ArkmeMessageWithdrawalDialog.d.ts.map +1 -0
- package/lib/types/client/ArkmeNoteDetails.d.ts.map +1 -1
- package/lib/types/client/ArkmePersistentShell.d.ts.map +1 -1
- package/lib/types/client/ArkmeRecordingSurface.d.ts +5 -1
- package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeRelatedQuickNotes.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichComposerInput.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichContent.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichText.d.ts +9 -3
- package/lib/types/client/ArkmeRichText.d.ts.map +1 -1
- package/lib/types/client/ArkmeSearchSurface.d.ts +6 -3
- package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts +5 -2
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/ArkmeWorldSurface.d.ts +7 -4
- package/lib/types/client/ArkmeWorldSurface.d.ts.map +1 -1
- package/lib/types/client/api.d.ts +4 -4
- package/lib/types/client/api.d.ts.map +1 -1
- package/lib/types/client/bot-chat-directory-projection.d.ts +2 -0
- package/lib/types/client/bot-chat-directory-projection.d.ts.map +1 -1
- package/lib/types/client/bot-directory-preferences.d.ts +0 -3
- package/lib/types/client/bot-directory-preferences.d.ts.map +1 -1
- package/lib/types/client/chat-directory-store.d.ts +15 -0
- package/lib/types/client/chat-directory-store.d.ts.map +1 -1
- package/lib/types/client/composer-draft-store.d.ts +1 -0
- package/lib/types/client/composer-draft-store.d.ts.map +1 -1
- package/lib/types/client/conversation-directory-visibility-overlay.d.ts +27 -0
- package/lib/types/client/conversation-directory-visibility-overlay.d.ts.map +1 -0
- package/lib/types/client/realtime-client-events.d.ts.map +1 -1
- package/lib/types/client/recordings/ArkmeRecordingImportDialog.d.ts +6 -1
- package/lib/types/client/recordings/ArkmeRecordingImportDialog.d.ts.map +1 -1
- package/lib/types/client/recordings/recording-import-selection.d.ts.map +1 -1
- package/lib/types/client/ui-controller.d.ts +7 -0
- package/lib/types/client/ui-controller.d.ts.map +1 -1
- package/lib/types/dsh-remote/api-proxy-adapter.d.ts.map +1 -1
- package/lib/types/dsh-remote/channel-manager.d.ts +1 -0
- package/lib/types/dsh-remote/channel-manager.d.ts.map +1 -1
- package/lib/types/dsh-remote/control-plane.d.ts +5 -0
- package/lib/types/dsh-remote/control-plane.d.ts.map +1 -1
- package/lib/types/dsh-remote/host.d.ts +49 -13
- package/lib/types/dsh-remote/host.d.ts.map +1 -1
- package/lib/types/dsh-remote/realtime-transport.d.ts.map +1 -1
- package/lib/types/dsh-remote/turn-projector.d.ts.map +1 -1
- package/lib/types/dsh-remote/turn-upload-outbox.d.ts +86 -0
- package/lib/types/dsh-remote/turn-upload-outbox.d.ts.map +1 -0
- package/lib/types/dsh-remote/types.d.ts +18 -2
- package/lib/types/dsh-remote/types.d.ts.map +1 -1
- package/lib/types/hashtag.d.ts +47 -0
- package/lib/types/hashtag.d.ts.map +1 -0
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/link-metadata.d.ts +2 -0
- package/lib/types/link-metadata.d.ts.map +1 -1
- package/lib/types/local-database.d.ts +1 -0
- package/lib/types/local-database.d.ts.map +1 -1
- package/lib/types/recording-import-contract.d.ts +66 -2
- package/lib/types/recording-import-contract.d.ts.map +1 -1
- package/lib/types/recording-import-coordinator.d.ts.map +1 -1
- package/lib/types/recording-import-probe.d.ts.map +1 -1
- package/lib/types/recording-import-shared.d.ts +78 -0
- package/lib/types/recording-import-shared.d.ts.map +1 -1
- package/lib/types/recording-wave-probe.d.ts +9 -0
- package/lib/types/recording-wave-probe.d.ts.map +1 -0
- package/lib/types/sdk/index.d.ts +23 -2
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/bot-service.d.ts +3 -0
- package/lib/types/services/bot-service.d.ts.map +1 -1
- package/lib/types/services/chat-realtime-service.d.ts +4 -1
- package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +22 -2
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/conversation-directory-visibility-service.d.ts +34 -0
- package/lib/types/services/conversation-directory-visibility-service.d.ts.map +1 -0
- package/lib/types/services/conversation-list-preference-service.d.ts +56 -0
- package/lib/types/services/conversation-list-preference-service.d.ts.map +1 -0
- package/lib/types/services/group-ai-polish-service.d.ts +3 -0
- package/lib/types/services/group-ai-polish-service.d.ts.map +1 -1
- package/lib/types/services/link-metadata-service.d.ts +5 -2
- package/lib/types/services/link-metadata-service.d.ts.map +1 -1
- package/lib/types/services/record-service.d.ts +8 -1
- package/lib/types/services/record-service.d.ts.map +1 -1
- package/lib/types/services/recording-import-gateway.d.ts +45 -2
- package/lib/types/services/recording-import-gateway.d.ts.map +1 -1
- package/lib/types/services/recording-service.d.ts +18 -2
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/search-service.d.ts +8 -0
- package/lib/types/services/search-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/source-service.d.ts +25 -12
- package/lib/types/services/source-service.d.ts.map +1 -1
- package/lib/types/services/world-service.d.ts +4 -0
- package/lib/types/services/world-service.d.ts.map +1 -1
- package/lib/types/state-store.d.ts +1 -0
- package/lib/types/state-store.d.ts.map +1 -1
- package/lib/types/tools/business/conversation/index.d.ts.map +1 -1
- package/lib/types/tools/business/conversation/withdraw-message.d.ts +2 -0
- package/lib/types/tools/business/conversation/withdraw-message.d.ts.map +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/ports/conversations.d.ts +5 -1
- package/lib/types/tools/ports/conversations.d.ts.map +1 -1
- package/lib/types/tools/ports/groups.d.ts +13 -1
- package/lib/types/tools/ports/groups.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 +75 -4
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -4,7 +4,7 @@ import { basename, dirname, isAbsolute, join, posix, relative, resolve, sep } fr
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
6
|
import { chmod as chmod$1, copyFile, link, mkdir, open, readFile, rename, rm, stat, unlink, writeFile } from "node:fs/promises";
|
|
7
|
-
import { Resolver } from "node:dns/promises";
|
|
7
|
+
import { Resolver, lookup } from "node:dns/promises";
|
|
8
8
|
import { request } from "node:http";
|
|
9
9
|
import { request as request$1 } from "node:https";
|
|
10
10
|
import { BlockList, isIP } from "node:net";
|
|
@@ -11324,6 +11324,9 @@ var Id3V2Reader = class {
|
|
|
11324
11324
|
//#endregion
|
|
11325
11325
|
//#region src/recording-import-shared.ts
|
|
11326
11326
|
const MAX_RECORDING_IMPORT_BYTES = 1024 * 1024 * 1024;
|
|
11327
|
+
function recordingImportFileNameKey(fileName) {
|
|
11328
|
+
return fileName.trim().toLowerCase();
|
|
11329
|
+
}
|
|
11327
11330
|
//#endregion
|
|
11328
11331
|
//#region src/recording-import-contract.ts
|
|
11329
11332
|
function sameRecordingImportIdentity(left, right) {
|
|
@@ -11405,7 +11408,10 @@ function advanceRecordingImportJob(current, input) {
|
|
|
11405
11408
|
}
|
|
11406
11409
|
function toPublicRecordingImportJob(job, importRef) {
|
|
11407
11410
|
const progress = job.fileSize <= 0 ? 0 : Math.min(1, Math.max(0, job.uploadedBytes / job.fileSize));
|
|
11411
|
+
const status = job.phase === "prepared" ? "preparing" : job.phase === "uploading" ? "uploading" : job.phase === "finalizing" ? "processing" : job.phase === "accepted" ? "accepted" : job.phase === "failed" ? "failed" : "cancelled";
|
|
11412
|
+
const statusDetail = job.phase === "prepared" ? "准备中" : job.phase === "uploading" ? "上传中" : job.phase === "finalizing" ? "处理中" : job.phase === "accepted" ? "Audio 已接收" : job.phase === "failed" ? job.errorMessage?.trim() || "导入失败" : "已取消";
|
|
11408
11413
|
return {
|
|
11414
|
+
kind: "local",
|
|
11409
11415
|
importRef,
|
|
11410
11416
|
revision: job.revision,
|
|
11411
11417
|
phase: job.phase,
|
|
@@ -11413,7 +11419,11 @@ function toPublicRecordingImportJob(job, importRef) {
|
|
|
11413
11419
|
fileName: job.fileName,
|
|
11414
11420
|
fileSize: job.fileSize,
|
|
11415
11421
|
durationMillis: job.durationMillis,
|
|
11422
|
+
startAtMillis: job.startAtMillis,
|
|
11423
|
+
endAtMillis: job.startAtMillis + job.durationMillis,
|
|
11416
11424
|
progress,
|
|
11425
|
+
status,
|
|
11426
|
+
statusDetail,
|
|
11417
11427
|
createdAtMillis: job.createdAtMillis,
|
|
11418
11428
|
updatedAtMillis: job.updatedAtMillis,
|
|
11419
11429
|
...job.errorCode === void 0 ? {} : { errorCode: job.errorCode },
|
|
@@ -11422,18 +11432,115 @@ function toPublicRecordingImportJob(job, importRef) {
|
|
|
11422
11432
|
};
|
|
11423
11433
|
}
|
|
11424
11434
|
//#endregion
|
|
11435
|
+
//#region src/recording-wave-probe.ts
|
|
11436
|
+
const MAX_WAVE_CHUNK_COUNT = 1024;
|
|
11437
|
+
function ascii$1(bytes, offset, length) {
|
|
11438
|
+
return String.fromCharCode(...bytes.subarray(offset, offset + length));
|
|
11439
|
+
}
|
|
11440
|
+
function uint16(bytes, offset) {
|
|
11441
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint16(offset, true);
|
|
11442
|
+
}
|
|
11443
|
+
function uint32(bytes, offset) {
|
|
11444
|
+
return new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength).getUint32(offset, true);
|
|
11445
|
+
}
|
|
11446
|
+
async function readExact(source, offset, length) {
|
|
11447
|
+
const bytes = await source.read(offset, length);
|
|
11448
|
+
if (bytes.byteLength !== length) throw new TypeError("WAV 文件内容不完整");
|
|
11449
|
+
return bytes;
|
|
11450
|
+
}
|
|
11451
|
+
async function probeImaAdpcmWave(source) {
|
|
11452
|
+
if (!Number.isSafeInteger(source.size) || source.size < 12) return void 0;
|
|
11453
|
+
const header = await readExact(source, 0, 12);
|
|
11454
|
+
if (ascii$1(header, 0, 4) !== "RIFF" || ascii$1(header, 8, 4) !== "WAVE") return void 0;
|
|
11455
|
+
const riffEnd = uint32(header, 4) + 8;
|
|
11456
|
+
if (riffEnd < 12 || riffEnd > source.size) throw new TypeError("WAV RIFF 长度无效");
|
|
11457
|
+
let offset = 12;
|
|
11458
|
+
let format;
|
|
11459
|
+
let dataSize;
|
|
11460
|
+
let chunkCount = 0;
|
|
11461
|
+
while (offset + 8 <= riffEnd) {
|
|
11462
|
+
chunkCount += 1;
|
|
11463
|
+
if (chunkCount > MAX_WAVE_CHUNK_COUNT) throw new TypeError("WAV chunk 数量过多");
|
|
11464
|
+
const chunkHeader = await readExact(source, offset, 8);
|
|
11465
|
+
const chunkId = ascii$1(chunkHeader, 0, 4);
|
|
11466
|
+
const chunkSize = uint32(chunkHeader, 4);
|
|
11467
|
+
const chunkOffset = offset + 8;
|
|
11468
|
+
const nextOffset = chunkOffset + chunkSize + chunkSize % 2;
|
|
11469
|
+
if (!Number.isSafeInteger(nextOffset) || nextOffset > riffEnd) throw new TypeError("WAV chunk 长度无效");
|
|
11470
|
+
if (chunkId === "fmt ") {
|
|
11471
|
+
if (chunkSize < 2) throw new TypeError("WAV fmt chunk 无效");
|
|
11472
|
+
const bytes = await readExact(source, chunkOffset, Math.min(chunkSize, 20));
|
|
11473
|
+
if (uint16(bytes, 0) !== 17) return void 0;
|
|
11474
|
+
if (bytes.byteLength < 20 || uint16(bytes, 16) < 2) throw new TypeError("IMA ADPCM fmt chunk 无效");
|
|
11475
|
+
format = {
|
|
11476
|
+
channels: uint16(bytes, 2),
|
|
11477
|
+
sampleRate: uint32(bytes, 4),
|
|
11478
|
+
blockAlign: uint16(bytes, 12),
|
|
11479
|
+
bitsPerSample: uint16(bytes, 14),
|
|
11480
|
+
samplesPerBlock: uint16(bytes, 18)
|
|
11481
|
+
};
|
|
11482
|
+
} else if (chunkId === "data") dataSize = chunkSize;
|
|
11483
|
+
if (format !== void 0 && dataSize !== void 0) break;
|
|
11484
|
+
offset = nextOffset;
|
|
11485
|
+
}
|
|
11486
|
+
if (format === void 0) throw new TypeError("IMA ADPCM WAV 缺少 fmt chunk");
|
|
11487
|
+
if (dataSize === void 0 || dataSize <= 0) throw new TypeError("IMA ADPCM WAV 缺少音频数据");
|
|
11488
|
+
const { channels, sampleRate, blockAlign, bitsPerSample, samplesPerBlock } = format;
|
|
11489
|
+
if (channels <= 0 || sampleRate <= 0 || bitsPerSample !== 4) throw new TypeError("IMA ADPCM WAV 编码参数无效");
|
|
11490
|
+
const blockHeaderSize = channels * 4;
|
|
11491
|
+
const encodedGroupSize = channels * 4;
|
|
11492
|
+
const blockPayloadSize = blockAlign - blockHeaderSize;
|
|
11493
|
+
if (blockPayloadSize < 0 || blockPayloadSize % encodedGroupSize !== 0) throw new TypeError("IMA ADPCM WAV 编码参数无效");
|
|
11494
|
+
const expectedSamplesPerBlock = 1 + blockPayloadSize / encodedGroupSize * 8;
|
|
11495
|
+
if (samplesPerBlock <= 0 || samplesPerBlock !== expectedSamplesPerBlock) throw new TypeError("IMA ADPCM WAV 编码参数无效");
|
|
11496
|
+
const completeBlocks = Math.floor(dataSize / blockAlign);
|
|
11497
|
+
const remainder = dataSize % blockAlign;
|
|
11498
|
+
if (remainder !== 0 && (remainder < blockHeaderSize || (remainder - blockHeaderSize) % encodedGroupSize !== 0)) throw new TypeError("IMA ADPCM WAV 音频数据无效");
|
|
11499
|
+
const partialBlockSamples = remainder === 0 ? 0 : 1 + (remainder - blockHeaderSize) / encodedGroupSize * 8;
|
|
11500
|
+
const totalSamples = completeBlocks * samplesPerBlock + partialBlockSamples;
|
|
11501
|
+
const durationMillis = Math.round(totalSamples * 1e3 / sampleRate);
|
|
11502
|
+
if (!Number.isSafeInteger(durationMillis) || durationMillis <= 0) throw new TypeError("IMA ADPCM WAV 时长无效");
|
|
11503
|
+
return { durationMillis };
|
|
11504
|
+
}
|
|
11505
|
+
//#endregion
|
|
11425
11506
|
//#region src/recording-import-probe.ts
|
|
11426
11507
|
async function probeRecordingImportFile(filePath, metadata) {
|
|
11427
|
-
|
|
11428
|
-
|
|
11429
|
-
|
|
11430
|
-
formats: [
|
|
11431
|
-
WAVE,
|
|
11432
|
-
MP3,
|
|
11433
|
-
MP4
|
|
11434
|
-
]
|
|
11435
|
-
});
|
|
11508
|
+
const actualSize = (await stat(filePath)).size;
|
|
11509
|
+
if (actualSize !== metadata.fileSize) throw new RecordingImportContractError("recording-import-size-mismatch", "录音文件大小与声明不一致");
|
|
11510
|
+
let input;
|
|
11436
11511
|
try {
|
|
11512
|
+
const handle = await open(filePath, "r");
|
|
11513
|
+
let imaAdpcm;
|
|
11514
|
+
try {
|
|
11515
|
+
imaAdpcm = await probeImaAdpcmWave({
|
|
11516
|
+
size: actualSize,
|
|
11517
|
+
read: async (offset, length) => {
|
|
11518
|
+
const bytes = new Uint8Array(length);
|
|
11519
|
+
const { bytesRead } = await handle.read(bytes, 0, length, offset);
|
|
11520
|
+
return bytes.subarray(0, bytesRead);
|
|
11521
|
+
}
|
|
11522
|
+
});
|
|
11523
|
+
} finally {
|
|
11524
|
+
await handle.close();
|
|
11525
|
+
}
|
|
11526
|
+
if (imaAdpcm !== void 0) {
|
|
11527
|
+
if (recordingImportFileKind({
|
|
11528
|
+
...metadata,
|
|
11529
|
+
durationMillis: imaAdpcm.durationMillis
|
|
11530
|
+
}) !== "wav") throw new RecordingImportContractError("recording-import-format-mismatch", "录音格式与文件内容不一致");
|
|
11531
|
+
return {
|
|
11532
|
+
kind: "wav",
|
|
11533
|
+
durationMillis: imaAdpcm.durationMillis
|
|
11534
|
+
};
|
|
11535
|
+
}
|
|
11536
|
+
input = new Input({
|
|
11537
|
+
source: new FilePathSource(filePath),
|
|
11538
|
+
formats: [
|
|
11539
|
+
WAVE,
|
|
11540
|
+
MP3,
|
|
11541
|
+
MP4
|
|
11542
|
+
]
|
|
11543
|
+
});
|
|
11437
11544
|
if (!await input.canRead()) throw new RecordingImportContractError("recording-import-format-invalid", "无法识别录音文件内容");
|
|
11438
11545
|
const actualFormat = await input.getFormat();
|
|
11439
11546
|
const actualKind = actualFormat === WAVE ? "wav" : actualFormat === MP3 ? "mp3" : actualFormat === MP4 ? "m4a" : void 0;
|
|
@@ -11455,7 +11562,7 @@ async function probeRecordingImportFile(filePath, metadata) {
|
|
|
11455
11562
|
if (error instanceof RecordingImportContractError) throw error;
|
|
11456
11563
|
throw new RecordingImportContractError("recording-import-probe-failed", "录音文件校验失败");
|
|
11457
11564
|
} finally {
|
|
11458
|
-
input
|
|
11565
|
+
input?.dispose();
|
|
11459
11566
|
}
|
|
11460
11567
|
}
|
|
11461
11568
|
var LocalRecordingImportSource = class {
|
|
@@ -11808,7 +11915,7 @@ function bestMatchingCategory(text) {
|
|
|
11808
11915
|
}
|
|
11809
11916
|
//#endregion
|
|
11810
11917
|
//#region src/services/ai-video-service.ts
|
|
11811
|
-
function numberValue$
|
|
11918
|
+
function numberValue$30(value) {
|
|
11812
11919
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
11813
11920
|
}
|
|
11814
11921
|
function booleanValue$15(value) {
|
|
@@ -11828,9 +11935,9 @@ var AiVideoService = class {
|
|
|
11828
11935
|
return {
|
|
11829
11936
|
allowed: booleanValue$15(data.allowed),
|
|
11830
11937
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
11831
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
11832
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
11833
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
11938
|
+
selectedDurationMillis: Math.max(0, numberValue$30(data.selected_duration_millis)),
|
|
11939
|
+
minimumDurationMillis: Math.max(0, numberValue$30(data.minimum_duration_millis)),
|
|
11940
|
+
selectedSegmentCount: Math.max(0, numberValue$30(data.selected_segment_count)),
|
|
11834
11941
|
retryable: booleanValue$15(data.retryable),
|
|
11835
11942
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
11836
11943
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
@@ -11880,10 +11987,10 @@ var AiVideoService = class {
|
|
|
11880
11987
|
return {
|
|
11881
11988
|
allowed: booleanValue$15(data.allowed),
|
|
11882
11989
|
message: stringValue$1(data.message).trim() || "AI 视频内容检查已完成",
|
|
11883
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
11884
|
-
minimumDurationMillis: Math.max(0, numberValue$
|
|
11885
|
-
selectedSegmentCount: Math.max(0, numberValue$
|
|
11886
|
-
selectedTextCount: Math.max(0, numberValue$
|
|
11990
|
+
selectedDurationMillis: Math.max(0, numberValue$30(data.selected_duration_millis)),
|
|
11991
|
+
minimumDurationMillis: Math.max(0, numberValue$30(data.minimum_duration_millis)),
|
|
11992
|
+
selectedSegmentCount: Math.max(0, numberValue$30(data.selected_segment_count)),
|
|
11993
|
+
selectedTextCount: Math.max(0, numberValue$30(data.selected_text_count)),
|
|
11887
11994
|
retryable: booleanValue$15(data.retryable),
|
|
11888
11995
|
...stringValue$1(data.reason_code).trim() === "" ? {} : { reasonCode: stringValue$1(data.reason_code).trim() },
|
|
11889
11996
|
...stringValue$1(data.proof).trim() === "" ? {} : { proof: stringValue$1(data.proof).trim() }
|
|
@@ -11929,13 +12036,13 @@ var AiVideoService = class {
|
|
|
11929
12036
|
jobId,
|
|
11930
12037
|
status,
|
|
11931
12038
|
stage: stringValue$1(data.stage).trim() || status,
|
|
11932
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
12039
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$30(data.progress)))),
|
|
11933
12040
|
selectedSegmentCount: segmentCount,
|
|
11934
12041
|
...textCount === 0 ? {} : { selectedTextCount: textCount },
|
|
11935
12042
|
retryable: booleanValue$15(data.retryable),
|
|
11936
12043
|
...stringValue$1(data.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(data.video_asset_uid).trim() },
|
|
11937
12044
|
...stringValue$1(data.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(data.cover_asset_uid).trim() },
|
|
11938
|
-
...numberValue$
|
|
12045
|
+
...numberValue$30(data.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$30(data.video_duration_millis) },
|
|
11939
12046
|
...stringValue$1(data.error_code).trim() === "" ? {} : { errorCode: stringValue$1(data.error_code).trim() },
|
|
11940
12047
|
...stringValue$1(data.error_message).trim() === "" ? {} : { errorMessage: stringValue$1(data.error_message).trim() },
|
|
11941
12048
|
...stringValue$1(data.failure_stage).trim() === "" ? {} : { failureStage: stringValue$1(data.failure_stage).trim() }
|
|
@@ -11958,17 +12065,17 @@ var AiVideoService = class {
|
|
|
11958
12065
|
sessionId: stringValue$1(item.session_id).trim(),
|
|
11959
12066
|
status,
|
|
11960
12067
|
stage: stringValue$1(item.stage).trim() || status,
|
|
11961
|
-
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$
|
|
12068
|
+
progress: Math.min(100, Math.max(0, Math.trunc(numberValue$30(item.progress)))),
|
|
11962
12069
|
title: stringValue$1(source.title).trim() || "长录音 AI 视频",
|
|
11963
|
-
sourceStartedAtMillis: numberValue$
|
|
11964
|
-
selectedDurationMillis: Math.max(0, numberValue$
|
|
11965
|
-
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$
|
|
12070
|
+
sourceStartedAtMillis: numberValue$30(source.started_at),
|
|
12071
|
+
selectedDurationMillis: Math.max(0, numberValue$30(source.selected_duration_millis)),
|
|
12072
|
+
selectedSegmentCount: Math.max(0, Math.trunc(numberValue$30(item.selected_segment_count))),
|
|
11966
12073
|
retryable: booleanValue$15(item.retryable),
|
|
11967
|
-
createdAtMillis: numberValue$
|
|
11968
|
-
updatedAtMillis: numberValue$
|
|
12074
|
+
createdAtMillis: numberValue$30(item.created_at),
|
|
12075
|
+
updatedAtMillis: numberValue$30(item.updated_at),
|
|
11969
12076
|
...stringValue$1(item.cover_asset_uid).trim() === "" ? {} : { coverAssetUid: stringValue$1(item.cover_asset_uid).trim() },
|
|
11970
12077
|
...stringValue$1(item.video_asset_uid).trim() === "" ? {} : { videoAssetUid: stringValue$1(item.video_asset_uid).trim() },
|
|
11971
|
-
...numberValue$
|
|
12078
|
+
...numberValue$30(item.video_duration_millis) <= 0 ? {} : { videoDurationMillis: numberValue$30(item.video_duration_millis) },
|
|
11972
12079
|
...stringValue$1(item.error_code).trim() === "" ? {} : { errorCode: stringValue$1(item.error_code).trim() },
|
|
11973
12080
|
...stringValue$1(item.error_message).trim() === "" ? {} : { errorMessage: clippedText(item.error_message, 500) }
|
|
11974
12081
|
};
|
|
@@ -11994,7 +12101,7 @@ const ARKO_RUN_STATUSES = /* @__PURE__ */ new Set([
|
|
|
11994
12101
|
"expired"
|
|
11995
12102
|
]);
|
|
11996
12103
|
const ARKO_PROFILE_DISPLAY_NAME_CACHE_TTL_MS = 10 * 6e4;
|
|
11997
|
-
function numberValue$
|
|
12104
|
+
function numberValue$29(value) {
|
|
11998
12105
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
11999
12106
|
}
|
|
12000
12107
|
function booleanValue$14(value) {
|
|
@@ -12029,7 +12136,7 @@ function joinUrlWithQuery(baseUrl, path, query) {
|
|
|
12029
12136
|
}
|
|
12030
12137
|
function arkoProfileFromData(data) {
|
|
12031
12138
|
const displayName = stringValue$1(data.display_name).trim();
|
|
12032
|
-
const version = numberValue$
|
|
12139
|
+
const version = numberValue$29(data.version);
|
|
12033
12140
|
if (displayName === "" || !Number.isSafeInteger(version) || version < 0) throw new ArkmePluginError("arko-profile-contract-invalid", "Arko 资料响应不完整", true, 502);
|
|
12034
12141
|
return {
|
|
12035
12142
|
displayName,
|
|
@@ -12082,9 +12189,9 @@ function parsedJsonRecord(value) {
|
|
|
12082
12189
|
}
|
|
12083
12190
|
function arkoHistoryItemFromData(value) {
|
|
12084
12191
|
const data = objectValue$1(value);
|
|
12085
|
-
const messageId = numberValue$
|
|
12086
|
-
const sessionId = numberValue$
|
|
12087
|
-
const roleCode = numberValue$
|
|
12192
|
+
const messageId = numberValue$29(data.id ?? data.msg_id ?? data.msgId);
|
|
12193
|
+
const sessionId = numberValue$29(data.session_id ?? data.sessionId);
|
|
12194
|
+
const roleCode = numberValue$29(data.role ?? data.sender_role ?? data.senderRole);
|
|
12088
12195
|
if (!Number.isSafeInteger(messageId) || messageId <= 0 || !Number.isSafeInteger(sessionId) || sessionId <= 0 || roleCode !== 2 && roleCode !== 3) return void 0;
|
|
12089
12196
|
const extra = parsedJsonRecord(data.extra ?? data.metadata ?? data.meta);
|
|
12090
12197
|
const extraData = parsedJsonRecord(extra.data);
|
|
@@ -12105,7 +12212,7 @@ function arkoHistoryItemFromData(value) {
|
|
|
12105
12212
|
extraData.updateAt,
|
|
12106
12213
|
data.updated_at,
|
|
12107
12214
|
data.updatedAt
|
|
12108
|
-
].map(numberValue$
|
|
12215
|
+
].map(numberValue$29).find((candidate) => candidate > 0) ?? 0;
|
|
12109
12216
|
const runUid = optionalString$3(extra.agent_run_uid);
|
|
12110
12217
|
const runStatus = optionalString$3(extra.agent_run_status);
|
|
12111
12218
|
const retryable = optionalBooleanValue$1(extra.agent_run_retryable);
|
|
@@ -12119,7 +12226,7 @@ function arkoHistoryItemFromData(value) {
|
|
|
12119
12226
|
text: stringValue$1(data.content ?? data.text_content ?? data.textContent),
|
|
12120
12227
|
reasoning: stringValue$1(data.reason_content ?? data.reason_text ?? data.reasonText),
|
|
12121
12228
|
createdAtMillis: activityAt > 0 && activityAt < 1e11 ? activityAt * 1e3 : activityAt,
|
|
12122
|
-
status: numberValue$
|
|
12229
|
+
status: numberValue$29(data.status ?? data.msg_status),
|
|
12123
12230
|
...runUid === void 0 ? {} : { runUid },
|
|
12124
12231
|
...runStatus === void 0 ? {} : { runStatus },
|
|
12125
12232
|
...retryable === void 0 ? {} : { retryable },
|
|
@@ -12177,7 +12284,7 @@ var ArkoService = class {
|
|
|
12177
12284
|
async arkoEnsureSession(signal) {
|
|
12178
12285
|
const session = await this.runtime.requireSession();
|
|
12179
12286
|
const latest = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/latest-session", { type: ARKO_AGENT_DIRECT_SESSION_TYPE }, session, signal);
|
|
12180
|
-
const latestSessionId = numberValue$
|
|
12287
|
+
const latestSessionId = numberValue$29(latest.id);
|
|
12181
12288
|
if (Number.isSafeInteger(latestSessionId) && latestSessionId > 0) return {
|
|
12182
12289
|
sessionId: latestSessionId,
|
|
12183
12290
|
created: false,
|
|
@@ -12187,7 +12294,7 @@ var ArkoService = class {
|
|
|
12187
12294
|
}
|
|
12188
12295
|
async arkoCreateSession(signal) {
|
|
12189
12296
|
const session = await this.runtime.requireSession();
|
|
12190
|
-
const createdSessionId = numberValue$
|
|
12297
|
+
const createdSessionId = numberValue$29((await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-session", {
|
|
12191
12298
|
name: ARKO_DEFAULT_SESSION_NAME,
|
|
12192
12299
|
type: ARKO_AGENT_DIRECT_SESSION_TYPE
|
|
12193
12300
|
}, session, signal)).session_id);
|
|
@@ -12270,9 +12377,9 @@ var ArkoService = class {
|
|
|
12270
12377
|
};
|
|
12271
12378
|
if (modelRouteKey !== "") body.model_route_key = modelRouteKey;
|
|
12272
12379
|
const accepted = await this.runtime.authenticatedIntelligentPost("/api/v1/qa/new-msg-v2", body, session, options.signal);
|
|
12273
|
-
const userMsgId = numberValue$
|
|
12274
|
-
const assistantMsgId = numberValue$
|
|
12275
|
-
const acceptedSessionId = numberValue$
|
|
12380
|
+
const userMsgId = numberValue$29(accepted.user_msg_id);
|
|
12381
|
+
const assistantMsgId = numberValue$29(accepted.assistant_msg_id);
|
|
12382
|
+
const acceptedSessionId = numberValue$29(accepted.session_id) || sessionId;
|
|
12276
12383
|
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);
|
|
12277
12384
|
const runUid = stringValue$1(accepted.run_uid).trim();
|
|
12278
12385
|
if (runUid === "") throw new ArkmePluginError("arko-ask-contract-invalid", "Arko 消息响应缺少运行标识", true, 502);
|
|
@@ -12308,8 +12415,8 @@ var ArkoService = class {
|
|
|
12308
12415
|
}, session, signal);
|
|
12309
12416
|
const status = stringValue$1(data.status).trim();
|
|
12310
12417
|
const normalizedRunUid = stringValue$1(data.run_uid).trim() || runUid.trim();
|
|
12311
|
-
const sequence = numberValue$
|
|
12312
|
-
const surfaceAssistantMsgId = numberValue$
|
|
12418
|
+
const sequence = numberValue$29(data.sequence);
|
|
12419
|
+
const surfaceAssistantMsgId = numberValue$29(data.surface_assistant_msg_id);
|
|
12313
12420
|
const clientAction = optionalRecord$1(data.client_action);
|
|
12314
12421
|
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);
|
|
12315
12422
|
return {
|
|
@@ -12547,7 +12654,7 @@ const ARKME_ARRANGEMENT_REF_TTL_MILLIS = 900 * 1e3;
|
|
|
12547
12654
|
const MAX_ARKME_ARRANGEMENT_REFS = 4096;
|
|
12548
12655
|
const ARKME_ARRANGEMENT_REMINDER_REF_TTL_MILLIS = 900 * 1e3;
|
|
12549
12656
|
const MAX_ARKME_ARRANGEMENT_REMINDER_REFS = 4096;
|
|
12550
|
-
function numberValue$
|
|
12657
|
+
function numberValue$28(value) {
|
|
12551
12658
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
12552
12659
|
}
|
|
12553
12660
|
function booleanValue$13(value) {
|
|
@@ -12563,7 +12670,7 @@ function arrangementStatusCode(status) {
|
|
|
12563
12670
|
return -1;
|
|
12564
12671
|
}
|
|
12565
12672
|
function arrangementStatus(value) {
|
|
12566
|
-
const code = Math.trunc(numberValue$
|
|
12673
|
+
const code = Math.trunc(numberValue$28(value));
|
|
12567
12674
|
if (code === 1) return "identified";
|
|
12568
12675
|
if (code === 2) return "following";
|
|
12569
12676
|
if (code === 3) return "completed";
|
|
@@ -12614,7 +12721,7 @@ var ArrangementService = class {
|
|
|
12614
12721
|
}, session, options.signal, { lane: "interactive-read" });
|
|
12615
12722
|
const rawItems = listValue$25(data.list);
|
|
12616
12723
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementItem(raw, session.userId)));
|
|
12617
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
12724
|
+
const total = Math.max(0, Math.trunc(numberValue$28(data.total)));
|
|
12618
12725
|
const nextOffset = offset + rawItems.length;
|
|
12619
12726
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
12620
12727
|
return {
|
|
@@ -12640,7 +12747,7 @@ var ArrangementService = class {
|
|
|
12640
12747
|
}, session, options.signal, { lane: "interactive-read" });
|
|
12641
12748
|
const rawItems = listValue$25(data.list);
|
|
12642
12749
|
const items = await Promise.all(rawItems.map(async (raw) => await this.arrangementReminderEvent(raw, session.userId)));
|
|
12643
|
-
const total = Math.max(0, Math.trunc(numberValue$
|
|
12750
|
+
const total = Math.max(0, Math.trunc(numberValue$28(data.total)));
|
|
12644
12751
|
const nextOffset = offset + rawItems.length;
|
|
12645
12752
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
12646
12753
|
return {
|
|
@@ -12663,7 +12770,7 @@ var ArrangementService = class {
|
|
|
12663
12770
|
project(data.next_reminder)
|
|
12664
12771
|
]);
|
|
12665
12772
|
return {
|
|
12666
|
-
unreadCount: Math.max(0, Math.trunc(numberValue$
|
|
12773
|
+
unreadCount: Math.max(0, Math.trunc(numberValue$28(data.unread_count))),
|
|
12667
12774
|
...latestUnread === void 0 ? {} : { latestUnread },
|
|
12668
12775
|
...latestEvent === void 0 ? {} : { latestEvent },
|
|
12669
12776
|
...nextReminder === void 0 ? {} : { nextReminder }
|
|
@@ -12767,7 +12874,7 @@ var ArrangementService = class {
|
|
|
12767
12874
|
}, session, signal);
|
|
12768
12875
|
return {
|
|
12769
12876
|
outcome: "confirmed",
|
|
12770
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
12877
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$28(data.updated_count)))
|
|
12771
12878
|
};
|
|
12772
12879
|
} catch (error) {
|
|
12773
12880
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -12785,7 +12892,7 @@ var ArrangementService = class {
|
|
|
12785
12892
|
}, session, signal);
|
|
12786
12893
|
return {
|
|
12787
12894
|
outcome: "confirmed",
|
|
12788
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
12895
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$28(data.updated_count)))
|
|
12789
12896
|
};
|
|
12790
12897
|
} catch (error) {
|
|
12791
12898
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -12800,7 +12907,7 @@ var ArrangementService = class {
|
|
|
12800
12907
|
const data = await this.runtime.authenticatedIntelligentPost("/api/v1/arrangements/reminders/clear", {}, session, signal);
|
|
12801
12908
|
return {
|
|
12802
12909
|
outcome: "confirmed",
|
|
12803
|
-
updatedCount: Math.max(0, Math.trunc(numberValue$
|
|
12910
|
+
updatedCount: Math.max(0, Math.trunc(numberValue$28(data.updated_count)))
|
|
12804
12911
|
};
|
|
12805
12912
|
} catch (error) {
|
|
12806
12913
|
if (!isAmbiguousArrangementWriteError(error)) throw error;
|
|
@@ -12864,8 +12971,8 @@ var ArrangementService = class {
|
|
|
12864
12971
|
const item = objectValue$1(raw);
|
|
12865
12972
|
const arrangementUid = stringValue$1(item.uid).trim();
|
|
12866
12973
|
if (arrangementUid === "") throw new ArkmePluginError("arrangement-contract-invalid", "安排响应缺少业务身份", true, 502);
|
|
12867
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
12868
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
12974
|
+
const dueAtMillis = Math.trunc(numberValue$28(item.due_at));
|
|
12975
|
+
const remindAtMillis = Math.trunc(numberValue$28(item.remind_at));
|
|
12869
12976
|
return {
|
|
12870
12977
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
12871
12978
|
title: stringValue$1(item.title),
|
|
@@ -12873,8 +12980,8 @@ var ArrangementService = class {
|
|
|
12873
12980
|
status: arrangementStatus(item.status),
|
|
12874
12981
|
reminderEnabled: booleanValue$13(item.reminder_enabled),
|
|
12875
12982
|
reminderState: stringValue$1(item.reminder_state),
|
|
12876
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
12877
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
12983
|
+
createdAtMillis: Math.trunc(numberValue$28(item.create_at)),
|
|
12984
|
+
updatedAtMillis: Math.trunc(numberValue$28(item.update_at)),
|
|
12878
12985
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
12879
12986
|
...remindAtMillis > 0 ? { remindAtMillis } : {}
|
|
12880
12987
|
};
|
|
@@ -12895,20 +13002,20 @@ var ArrangementService = class {
|
|
|
12895
13002
|
const eventUid = stringValue$1(item.uid).trim();
|
|
12896
13003
|
const arrangementUid = stringValue$1(item.arrangement_uid).trim();
|
|
12897
13004
|
if (eventUid === "" || arrangementUid === "") throw new ArkmePluginError("arrangement-reminder-contract-invalid", "安排提醒响应缺少有效身份", true, 502);
|
|
12898
|
-
const dueAtMillis = Math.trunc(numberValue$
|
|
12899
|
-
const remindAtMillis = Math.trunc(numberValue$
|
|
12900
|
-
const readAtMillis = Math.trunc(numberValue$
|
|
13005
|
+
const dueAtMillis = Math.trunc(numberValue$28(item.due_at));
|
|
13006
|
+
const remindAtMillis = Math.trunc(numberValue$28(item.remind_at));
|
|
13007
|
+
const readAtMillis = Math.trunc(numberValue$28(item.read_at));
|
|
12901
13008
|
return {
|
|
12902
13009
|
eventRef: await this.arrangementReminderRef(viewerUserId, eventUid),
|
|
12903
13010
|
arrangementRef: await this.arrangementRef(viewerUserId, arrangementUid),
|
|
12904
13011
|
title: stringValue$1(item.title),
|
|
12905
13012
|
description: stringValue$1(item.description),
|
|
12906
13013
|
eventKind: stringValue$1(item.event_kind),
|
|
12907
|
-
eventAtMillis: Math.trunc(numberValue$
|
|
13014
|
+
eventAtMillis: Math.trunc(numberValue$28(item.event_at)),
|
|
12908
13015
|
read: readAtMillis > 0,
|
|
12909
13016
|
reminderState: stringValue$1(item.reminder_state),
|
|
12910
|
-
createdAtMillis: Math.trunc(numberValue$
|
|
12911
|
-
updatedAtMillis: Math.trunc(numberValue$
|
|
13017
|
+
createdAtMillis: Math.trunc(numberValue$28(item.create_at)),
|
|
13018
|
+
updatedAtMillis: Math.trunc(numberValue$28(item.update_at)),
|
|
12912
13019
|
...dueAtMillis > 0 ? { dueAtMillis } : {},
|
|
12913
13020
|
...remindAtMillis > 0 ? { remindAtMillis } : {},
|
|
12914
13021
|
...readAtMillis > 0 ? { readAtMillis } : {}
|
|
@@ -12965,7 +13072,7 @@ var ArrangementService = class {
|
|
|
12965
13072
|
const ARKME_PHONE_BIND_SUCCESS = 1;
|
|
12966
13073
|
const ARKME_PHONE_BIND_REPEAT = 2;
|
|
12967
13074
|
const ARKME_PHONE_BIND_CODE_ERR = 3;
|
|
12968
|
-
function numberValue$
|
|
13075
|
+
function numberValue$27(value) {
|
|
12969
13076
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
12970
13077
|
}
|
|
12971
13078
|
function jiwoScanLoginAvailable(config) {
|
|
@@ -13050,7 +13157,7 @@ var AuthService = class {
|
|
|
13050
13157
|
const sceneStr = stringValue$1(data.scene_str).trim();
|
|
13051
13158
|
const pollToken = stringValue$1(data.poll_token).trim();
|
|
13052
13159
|
const qrContent = stringValue$1(data.url).trim();
|
|
13053
|
-
const expireSeconds = Math.max(30, numberValue$
|
|
13160
|
+
const expireSeconds = Math.max(30, numberValue$27(data.expire_seconds) || 300);
|
|
13054
13161
|
if (qrContent === "" && sceneStr !== "") throw new ArkmePluginError("wechat-qr-unavailable", "测试环境当前未返回可用微信二维码,请使用手机号登录", true, 503);
|
|
13055
13162
|
if (sceneStr === "" || pollToken === "" || qrContent === "") throw new ArkmePluginError("login-contract-invalid", "Arkme 登录二维码响应不完整", true, 502);
|
|
13056
13163
|
const attemptId = crypto.randomUUID();
|
|
@@ -13089,7 +13196,7 @@ var AuthService = class {
|
|
|
13089
13196
|
ref: 0,
|
|
13090
13197
|
keep_cancel: true
|
|
13091
13198
|
}, void 0, [200]);
|
|
13092
|
-
const userId = numberValue$
|
|
13199
|
+
const userId = numberValue$27(data.user_id);
|
|
13093
13200
|
if (userId <= 0) return {
|
|
13094
13201
|
status: "pending",
|
|
13095
13202
|
environment: this.runtime.config.environment,
|
|
@@ -13119,7 +13226,7 @@ var AuthService = class {
|
|
|
13119
13226
|
}, void 0, [200]);
|
|
13120
13227
|
const ticket = stringValue$1(data.ticket).trim();
|
|
13121
13228
|
const pollSecret = stringValue$1(data.poll_secret).trim();
|
|
13122
|
-
const expiresAtMillis = numberValue$
|
|
13229
|
+
const expiresAtMillis = numberValue$27(data.expires_at);
|
|
13123
13230
|
if (!/^[A-Za-z0-9_-]{43}$/.test(ticket) || !/^[A-Za-z0-9_-]{43}$/.test(pollSecret) || expiresAtMillis <= Date.now()) throw new ArkmePluginError("jiwo-login-contract-invalid", "即我登录二维码响应不完整", true, 502);
|
|
13124
13231
|
if (attemptGeneration !== this.jiwoAttemptGeneration) {
|
|
13125
13232
|
await this.cancelJiwoCredentials(ticket, pollSecret);
|
|
@@ -13169,7 +13276,7 @@ var AuthService = class {
|
|
|
13169
13276
|
};
|
|
13170
13277
|
}
|
|
13171
13278
|
if (status !== "authenticated") throw new ArkmePluginError("jiwo-login-contract-invalid", "即我扫码登录状态无效", true, 502);
|
|
13172
|
-
const userId = numberValue$
|
|
13279
|
+
const userId = numberValue$27(data.user_id);
|
|
13173
13280
|
const accessToken = stringValue$1(data.access_token);
|
|
13174
13281
|
const refreshToken = stringValue$1(data.refresh_token);
|
|
13175
13282
|
if (userId <= 0 || accessToken === "" || refreshToken === "") throw new ArkmePluginError("login-contract-invalid", "Arkme 登录成功响应缺少凭据", false, 502);
|
|
@@ -13238,7 +13345,7 @@ var AuthService = class {
|
|
|
13238
13345
|
const normalizedCaptcha = this.normalizedCaptcha(captcha);
|
|
13239
13346
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
13240
13347
|
if (session !== void 0) {
|
|
13241
|
-
if (numberValue$
|
|
13348
|
+
if (numberValue$27((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/bind-phone-send-code", {
|
|
13242
13349
|
phone: normalizedPhone,
|
|
13243
13350
|
pre: "86",
|
|
13244
13351
|
is_test: this.runtime.config.environment === "test",
|
|
@@ -13260,7 +13367,7 @@ var AuthService = class {
|
|
|
13260
13367
|
if (!/^[0-9]{6}$/.test(normalizedCode)) throw new ArkmePluginError("phone-code-invalid", "请输入有效的短信验证码", false);
|
|
13261
13368
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
13262
13369
|
if (session !== void 0) {
|
|
13263
|
-
const result = numberValue$
|
|
13370
|
+
const result = numberValue$27((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/verify-bind-phone", {
|
|
13264
13371
|
phone: normalizedPhone,
|
|
13265
13372
|
pre: "86",
|
|
13266
13373
|
code: normalizedCode,
|
|
@@ -13281,7 +13388,7 @@ var AuthService = class {
|
|
|
13281
13388
|
keep_cancel: true
|
|
13282
13389
|
}, void 0, [200]);
|
|
13283
13390
|
if (data.ok === false) throw new ArkmePluginError("phone-code-rejected", "手机号或验证码错误", false, 401);
|
|
13284
|
-
const userId = numberValue$
|
|
13391
|
+
const userId = numberValue$27(data.user_id);
|
|
13285
13392
|
const accessToken = stringValue$1(data.access_token);
|
|
13286
13393
|
const refreshToken = stringValue$1(data.refresh_token);
|
|
13287
13394
|
if (userId <= 0 || accessToken === "" || refreshToken === "") throw new ArkmePluginError("login-contract-invalid", "Arkme手机号登录响应不完整", false, 502);
|
|
@@ -13541,6 +13648,194 @@ var ArkmePrivacyVisibilityService = class {
|
|
|
13541
13648
|
return immutable;
|
|
13542
13649
|
}
|
|
13543
13650
|
};
|
|
13651
|
+
const UPDATED_OUTCOME = 1;
|
|
13652
|
+
const IDEMPOTENT_OUTCOME = 2;
|
|
13653
|
+
const MAX_BATCH_SIZE = 200;
|
|
13654
|
+
const MAX_QUERY_REFS = 1e3;
|
|
13655
|
+
const MAX_ENTITY_UID_BYTES = 128;
|
|
13656
|
+
/** HTTP/CAS adapter. Only revision hints are cached; owner snapshots stay server-owned. */
|
|
13657
|
+
var ConversationListPreferenceService = class {
|
|
13658
|
+
runtime;
|
|
13659
|
+
revisionOwnerUserId;
|
|
13660
|
+
revisionHints = /* @__PURE__ */ new Map();
|
|
13661
|
+
constructor(runtime) {
|
|
13662
|
+
this.runtime = runtime;
|
|
13663
|
+
}
|
|
13664
|
+
async query(refs, operation) {
|
|
13665
|
+
const normalized = normalizeRefs(refs);
|
|
13666
|
+
if (normalized.length === 0) return [];
|
|
13667
|
+
const session = await this.requireOwnerSession(operation.ownerUserId);
|
|
13668
|
+
return await this.queryWithSession(normalized, session, operation.signal);
|
|
13669
|
+
}
|
|
13670
|
+
async dismiss(rawRef, rawEvidence, operation) {
|
|
13671
|
+
const ref = normalizeRef(rawRef);
|
|
13672
|
+
const evidence = normalizeEvidence(rawEvidence);
|
|
13673
|
+
if (evidence.sequence === 0 && evidence.activityAtMillis === 0) throw new ArkmePluginError("conversation-list-preference-evidence-unavailable", "当前会话活动信息不完整,请刷新后重试", true, 409);
|
|
13674
|
+
if (ref.entityKind === 2 && evidence.sequence !== 0) throw new ArkmePluginError("conversation-list-preference-evidence-invalid", "Bot 会话活动信息无效,请刷新后重试", false, 400);
|
|
13675
|
+
const session = await this.requireOwnerSession(operation.ownerUserId);
|
|
13676
|
+
const key = conversationListPreferenceRefKey(ref);
|
|
13677
|
+
const expectedRevision = this.revisionHints.get(key) ?? (await this.queryWithSession([ref], session, operation.signal))[0].revision;
|
|
13678
|
+
const result = (await this.set([{
|
|
13679
|
+
ref,
|
|
13680
|
+
expectedRevision,
|
|
13681
|
+
targetVisibilityState: 2,
|
|
13682
|
+
evidence
|
|
13683
|
+
}], session, operation.signal))[0];
|
|
13684
|
+
if (result.outcome !== UPDATED_OUTCOME && result.outcome !== IDEMPOTENT_OUTCOME || result.snapshot.visibilityState !== 2 || !conversationListPreferenceIsDismissed(result.snapshot, evidence)) throw new ArkmePluginError("conversation-list-preference-conflict", "会话状态已变化,已保留在列表中", false, 409);
|
|
13685
|
+
return result.snapshot;
|
|
13686
|
+
}
|
|
13687
|
+
async restore(refs, operation) {
|
|
13688
|
+
const normalized = normalizeRefs(refs);
|
|
13689
|
+
if (normalized.length === 0) return;
|
|
13690
|
+
const session = await this.requireOwnerSession(operation.ownerUserId);
|
|
13691
|
+
const writes = (await this.queryWithSession(normalized, session, operation.signal)).filter((snapshot) => snapshot.visibilityState === 2).map((snapshot) => ({
|
|
13692
|
+
ref: snapshot.ref,
|
|
13693
|
+
expectedRevision: snapshot.revision,
|
|
13694
|
+
targetVisibilityState: 1,
|
|
13695
|
+
evidence: {
|
|
13696
|
+
sequence: 0,
|
|
13697
|
+
activityAtMillis: 0
|
|
13698
|
+
}
|
|
13699
|
+
}));
|
|
13700
|
+
for (let offset = 0; offset < writes.length; offset += MAX_BATCH_SIZE) await this.set(writes.slice(offset, offset + MAX_BATCH_SIZE), session, operation.signal);
|
|
13701
|
+
}
|
|
13702
|
+
async restoreIfUnchanged(snapshots, operation) {
|
|
13703
|
+
if (snapshots.length === 0) return;
|
|
13704
|
+
const session = await this.requireOwnerSession(operation.ownerUserId);
|
|
13705
|
+
const writes = snapshots.map((snapshot) => {
|
|
13706
|
+
if (snapshot.visibilityState !== 2 || !Number.isSafeInteger(snapshot.revision) || snapshot.revision <= 0) throw contractError$1("restore-snapshot");
|
|
13707
|
+
return {
|
|
13708
|
+
ref: normalizeRef(snapshot.ref),
|
|
13709
|
+
expectedRevision: snapshot.revision,
|
|
13710
|
+
targetVisibilityState: 1,
|
|
13711
|
+
evidence: {
|
|
13712
|
+
sequence: 0,
|
|
13713
|
+
activityAtMillis: 0
|
|
13714
|
+
}
|
|
13715
|
+
};
|
|
13716
|
+
});
|
|
13717
|
+
for (let offset = 0; offset < writes.length; offset += MAX_BATCH_SIZE) await this.set(writes.slice(offset, offset + MAX_BATCH_SIZE), session, operation.signal);
|
|
13718
|
+
}
|
|
13719
|
+
async queryWithSession(refs, session, signal) {
|
|
13720
|
+
const snapshots = [];
|
|
13721
|
+
for (let offset = 0; offset < refs.length; offset += MAX_BATCH_SIZE) {
|
|
13722
|
+
const chunk = refs.slice(offset, offset + MAX_BATCH_SIZE);
|
|
13723
|
+
const items = requiredList((await this.runtime.authenticatedChatPost("/api/v1/conversation-list/preferences/query", { entry_refs: chunk.map(refBody) }, session, signal)).items, "query-items");
|
|
13724
|
+
if (items.length !== chunk.length) throw contractError$1("query-shape");
|
|
13725
|
+
items.forEach((value, index) => {
|
|
13726
|
+
const snapshot = parseSnapshot(objectValue$1(value));
|
|
13727
|
+
if (!sameRef(snapshot.ref, chunk[index])) throw contractError$1("query-identity");
|
|
13728
|
+
snapshots.push(snapshot);
|
|
13729
|
+
});
|
|
13730
|
+
}
|
|
13731
|
+
this.rememberRevisions(snapshots, session.userId);
|
|
13732
|
+
return snapshots;
|
|
13733
|
+
}
|
|
13734
|
+
async set(writes, session, signal) {
|
|
13735
|
+
if (writes.length === 0 || writes.length > MAX_BATCH_SIZE) throw contractError$1("set-batch");
|
|
13736
|
+
const items = requiredList((await this.runtime.authenticatedChatPost("/api/v1/conversation-list/preferences/set", { items: writes.map((write) => ({
|
|
13737
|
+
...refBody(write.ref),
|
|
13738
|
+
target_visibility_state: write.targetVisibilityState,
|
|
13739
|
+
expected_revision: write.expectedRevision,
|
|
13740
|
+
observed_seq: write.evidence.sequence,
|
|
13741
|
+
observed_activity_at: write.evidence.activityAtMillis
|
|
13742
|
+
})) }, session, signal)).items, "set-items");
|
|
13743
|
+
if (items.length !== writes.length) throw contractError$1("set-shape");
|
|
13744
|
+
const results = items.map((value, index) => {
|
|
13745
|
+
const raw = objectValue$1(value);
|
|
13746
|
+
const outcome = requiredInteger$1(raw.outcome, "outcome");
|
|
13747
|
+
const snapshot = parseSnapshot(raw);
|
|
13748
|
+
if (outcome < 1 || outcome > 3) throw contractError$1("outcome");
|
|
13749
|
+
if (!sameRef(snapshot.ref, writes[index].ref)) throw contractError$1("set-identity");
|
|
13750
|
+
return {
|
|
13751
|
+
outcome,
|
|
13752
|
+
snapshot
|
|
13753
|
+
};
|
|
13754
|
+
});
|
|
13755
|
+
this.rememberRevisions(results.map((result) => result.snapshot), session.userId);
|
|
13756
|
+
return results;
|
|
13757
|
+
}
|
|
13758
|
+
async requireOwnerSession(ownerUserId) {
|
|
13759
|
+
const session = await this.runtime.requireSession();
|
|
13760
|
+
if (!Number.isSafeInteger(ownerUserId) || ownerUserId <= 0 || session.userId !== ownerUserId) throw new ArkmePluginError("login-context-changed", "登录账号已切换,请重试当前操作", false, 409);
|
|
13761
|
+
if (this.revisionOwnerUserId !== ownerUserId) {
|
|
13762
|
+
this.revisionOwnerUserId = ownerUserId;
|
|
13763
|
+
this.revisionHints.clear();
|
|
13764
|
+
}
|
|
13765
|
+
return session;
|
|
13766
|
+
}
|
|
13767
|
+
rememberRevisions(snapshots, ownerUserId) {
|
|
13768
|
+
if (this.revisionOwnerUserId !== ownerUserId) return;
|
|
13769
|
+
for (const snapshot of snapshots) {
|
|
13770
|
+
const key = conversationListPreferenceRefKey(snapshot.ref);
|
|
13771
|
+
this.revisionHints.set(key, Math.max(this.revisionHints.get(key) ?? 0, snapshot.revision));
|
|
13772
|
+
}
|
|
13773
|
+
}
|
|
13774
|
+
};
|
|
13775
|
+
function conversationListPreferenceIsDismissed(snapshot, evidence) {
|
|
13776
|
+
return snapshot.visibilityState === 2 && evidence.sequence <= snapshot.dismissedThroughSequence && evidence.activityAtMillis <= snapshot.dismissedThroughActivityAtMillis;
|
|
13777
|
+
}
|
|
13778
|
+
function conversationListPreferenceRefKey(ref) {
|
|
13779
|
+
return `${String(ref.entityKind)}:${ref.entityUid}`;
|
|
13780
|
+
}
|
|
13781
|
+
function parseSnapshot(raw) {
|
|
13782
|
+
const ref = normalizeRef({
|
|
13783
|
+
entityKind: requiredInteger$1(raw.entity_kind, "entity-kind"),
|
|
13784
|
+
entityUid: stringValue$1(raw.entity_uid)
|
|
13785
|
+
});
|
|
13786
|
+
const visibilityState = requiredInteger$1(raw.visibility_state, "visibility-state");
|
|
13787
|
+
if (visibilityState !== 1 && visibilityState !== 2) throw contractError$1("visibility-state");
|
|
13788
|
+
const snapshot = {
|
|
13789
|
+
ref,
|
|
13790
|
+
visibilityState,
|
|
13791
|
+
dismissedThroughSequence: requiredInteger$1(raw.dismissed_through_seq, "dismissed-sequence"),
|
|
13792
|
+
dismissedThroughActivityAtMillis: requiredInteger$1(raw.dismissed_through_activity_at, "dismissed-activity"),
|
|
13793
|
+
revision: requiredInteger$1(raw.revision, "revision"),
|
|
13794
|
+
updatedAtMillis: requiredInteger$1(raw.updated_at, "updated-at")
|
|
13795
|
+
};
|
|
13796
|
+
if (snapshot.visibilityState === 1 && (snapshot.dismissedThroughSequence !== 0 || snapshot.dismissedThroughActivityAtMillis !== 0)) throw contractError$1("visible-anchor");
|
|
13797
|
+
if (snapshot.visibilityState === 2 && snapshot.dismissedThroughSequence === 0 && snapshot.dismissedThroughActivityAtMillis === 0) throw contractError$1("dismissed-anchor");
|
|
13798
|
+
if (snapshot.ref.entityKind === 2 && snapshot.dismissedThroughSequence !== 0) throw contractError$1("bot-sequence");
|
|
13799
|
+
if (snapshot.revision === 0 !== (snapshot.updatedAtMillis === 0) || snapshot.visibilityState === 2 && snapshot.revision === 0) throw contractError$1("revision");
|
|
13800
|
+
return snapshot;
|
|
13801
|
+
}
|
|
13802
|
+
function normalizeRefs(refs) {
|
|
13803
|
+
if (refs.length > MAX_QUERY_REFS) throw contractError$1("query-too-large");
|
|
13804
|
+
const unique = /* @__PURE__ */ new Map();
|
|
13805
|
+
for (const value of refs) {
|
|
13806
|
+
const ref = normalizeRef(value);
|
|
13807
|
+
unique.set(conversationListPreferenceRefKey(ref), ref);
|
|
13808
|
+
}
|
|
13809
|
+
return [...unique.values()];
|
|
13810
|
+
}
|
|
13811
|
+
function normalizeRef(ref) {
|
|
13812
|
+
if (ref.entityKind !== 1 && ref.entityKind !== 2 || ref.entityUid === "" || ref.entityUid !== ref.entityUid.trim() || Buffer.byteLength(ref.entityUid, "utf8") > MAX_ENTITY_UID_BYTES) throw contractError$1("identity");
|
|
13813
|
+
return { ...ref };
|
|
13814
|
+
}
|
|
13815
|
+
function normalizeEvidence(evidence) {
|
|
13816
|
+
if (!Number.isSafeInteger(evidence.sequence) || evidence.sequence < 0 || !Number.isSafeInteger(evidence.activityAtMillis) || evidence.activityAtMillis < 0) throw contractError$1("evidence");
|
|
13817
|
+
return { ...evidence };
|
|
13818
|
+
}
|
|
13819
|
+
function refBody(ref) {
|
|
13820
|
+
return {
|
|
13821
|
+
entity_kind: ref.entityKind,
|
|
13822
|
+
entity_uid: ref.entityUid
|
|
13823
|
+
};
|
|
13824
|
+
}
|
|
13825
|
+
function sameRef(left, right) {
|
|
13826
|
+
return left.entityKind === right.entityKind && left.entityUid === right.entityUid;
|
|
13827
|
+
}
|
|
13828
|
+
function requiredList(value, field) {
|
|
13829
|
+
if (!Array.isArray(value)) throw contractError$1(field);
|
|
13830
|
+
return value;
|
|
13831
|
+
}
|
|
13832
|
+
function requiredInteger$1(value, field) {
|
|
13833
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw contractError$1(field);
|
|
13834
|
+
return value;
|
|
13835
|
+
}
|
|
13836
|
+
function contractError$1(field) {
|
|
13837
|
+
return new ArkmePluginError(`conversation-list-preference-${field}-invalid`, "会话列表偏好响应不完整,请刷新后重试", true, 502);
|
|
13838
|
+
}
|
|
13544
13839
|
//#endregion
|
|
13545
13840
|
//#region src/mention-metadata.ts
|
|
13546
13841
|
function listValue$24(value) {
|
|
@@ -13862,7 +14157,7 @@ const GROUP_AVATAR_NEGATIVE_CACHE_TTL_MS = 6e4;
|
|
|
13862
14157
|
const TOPIC_DISSOLVE_RECORD_CONCURRENCY = 6;
|
|
13863
14158
|
const PRIVATE_REMARK_PAGE_LIMIT = 50;
|
|
13864
14159
|
const PRIVATE_REMARK_MAX_PAGES = 20;
|
|
13865
|
-
function numberValue$
|
|
14160
|
+
function numberValue$26(value) {
|
|
13866
14161
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
13867
14162
|
}
|
|
13868
14163
|
function integerIdentifierValue(value) {
|
|
@@ -13908,15 +14203,20 @@ function arkmeGroupBotBindingBody(source) {
|
|
|
13908
14203
|
if (target?.subjectUid !== void 0 && target.subjectUid.trim() !== "") return { subject_uid: target.subjectUid.trim() };
|
|
13909
14204
|
return { subject_uid: source.ownerRef };
|
|
13910
14205
|
}
|
|
13911
|
-
function
|
|
14206
|
+
function arkmeChatDirectoryMetadataFromBundle(bundle, fallbackSubjectUid = "") {
|
|
13912
14207
|
const chatSession = objectValue$1(bundle.session);
|
|
14208
|
+
const unread = objectValue$1(bundle.unread_snapshot);
|
|
13913
14209
|
const subjectUid = stringValue$1(bundle.subject_uid ?? bundle.subjectUid ?? bundle.topic_uid ?? bundle.topicUid ?? chatSession.subject_uid ?? chatSession.subjectUid ?? chatSession.topic_uid ?? chatSession.topicUid ?? fallbackSubjectUid).trim();
|
|
13914
|
-
if (subjectUid === "") return void 0;
|
|
13915
14210
|
return {
|
|
13916
|
-
subjectUid,
|
|
13917
|
-
|
|
14211
|
+
...subjectUid === "" ? {} : { subjectUid },
|
|
14212
|
+
activityAtMillis: arkmeChatSortActiveAt(bundle, chatSession),
|
|
14213
|
+
latestSequence: Math.max(0, numberValue$26(unread.session_last_seq ?? chatSession.last_seq))
|
|
13918
14214
|
};
|
|
13919
14215
|
}
|
|
14216
|
+
function arkmeChatSortActiveAt(bundle, chatSession) {
|
|
14217
|
+
const projected = numberValue$26(bundle.sort_active_at);
|
|
14218
|
+
return Math.max(0, projected > 0 ? projected : numberValue$26(bundle.last_active_at ?? chatSession.last_active_at));
|
|
14219
|
+
}
|
|
13920
14220
|
function backendBooleanValue(value) {
|
|
13921
14221
|
if (value === null || value === void 0) return void 0;
|
|
13922
14222
|
if (typeof value === "boolean") return value;
|
|
@@ -14160,9 +14460,17 @@ var SourceService = class {
|
|
|
14160
14460
|
* the resolved label into their own viewer-bound response.
|
|
14161
14461
|
*/
|
|
14162
14462
|
async privateDisplayNamesByUserIds(userIds, options = {}) {
|
|
14463
|
+
const labels = await this.privateChatViewerLabelsByUserIds(userIds, options);
|
|
14464
|
+
return new Map([...labels].map(([userId, label]) => [userId, label.displayName]));
|
|
14465
|
+
}
|
|
14466
|
+
/**
|
|
14467
|
+
* Resolve the current viewer's private-chat display label and its exact
|
|
14468
|
+
* remark source without compressing fallback snapshots into remark facts.
|
|
14469
|
+
*/
|
|
14470
|
+
async privateChatViewerLabelsByUserIds(userIds, options = {}) {
|
|
14163
14471
|
const session = await this.runtime.requireSession();
|
|
14164
14472
|
const remaining = new Set(userIds.filter((userId) => Number.isSafeInteger(userId) && userId > 0 && userId !== session.userId));
|
|
14165
|
-
const
|
|
14473
|
+
const labels = /* @__PURE__ */ new Map();
|
|
14166
14474
|
let pageCursor;
|
|
14167
14475
|
for (let page = 0; page < 20 && remaining.size > 0; page += 1) {
|
|
14168
14476
|
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/list", {
|
|
@@ -14170,18 +14478,22 @@ var SourceService = class {
|
|
|
14170
14478
|
...pageCursor === void 0 ? {} : { page_cursor: pageCursor }
|
|
14171
14479
|
}, session, options.signal, {
|
|
14172
14480
|
lane: "background-read",
|
|
14173
|
-
key: `
|
|
14481
|
+
key: `private-chat-viewer-labels:${pageCursor === void 0 ? "first" : String(page)}`
|
|
14174
14482
|
});
|
|
14175
14483
|
for (const raw of listValue$23(data.items)) {
|
|
14176
14484
|
const bundle = objectValue$1(raw);
|
|
14177
|
-
const sessionKind = numberValue$
|
|
14485
|
+
const sessionKind = numberValue$26(objectValue$1(bundle.session).session_kind);
|
|
14178
14486
|
if (sessionKind !== 1 && sessionKind !== 3) continue;
|
|
14179
|
-
const targetUserId = numberValue$
|
|
14487
|
+
const targetUserId = numberValue$26(objectValue$1(bundle.private_counterpart).user_id);
|
|
14180
14488
|
if (!remaining.has(targetUserId)) continue;
|
|
14181
14489
|
const supplement = objectValue$1(bundle.private_supplement);
|
|
14182
14490
|
const counterpart = objectValue$1(bundle.private_counterpart);
|
|
14183
|
-
const
|
|
14184
|
-
|
|
14491
|
+
const remark = stringValue$1(supplement.remark).trim();
|
|
14492
|
+
const displayName = remark || stringValue$1(supplement.counterpart_name_snapshot).trim() || stringValue$1(counterpart.display_name_snapshot).trim() || stringValue$1(supplement.pending_name).trim() || stringValue$1(counterpart.visible_phone).trim();
|
|
14493
|
+
if (displayName !== "") labels.set(targetUserId, {
|
|
14494
|
+
displayName,
|
|
14495
|
+
remark
|
|
14496
|
+
});
|
|
14185
14497
|
remaining.delete(targetUserId);
|
|
14186
14498
|
}
|
|
14187
14499
|
if (data.has_more !== true) break;
|
|
@@ -14189,7 +14501,7 @@ var SourceService = class {
|
|
|
14189
14501
|
if (Object.keys(next).length === 0) break;
|
|
14190
14502
|
pageCursor = next;
|
|
14191
14503
|
}
|
|
14192
|
-
return
|
|
14504
|
+
return labels;
|
|
14193
14505
|
}
|
|
14194
14506
|
/**
|
|
14195
14507
|
* Resolve only viewer-owned contact remarks for the supplied people.
|
|
@@ -14237,7 +14549,7 @@ var SourceService = class {
|
|
|
14237
14549
|
});
|
|
14238
14550
|
for (const value of listValue$23(data.items)) {
|
|
14239
14551
|
const bundle = objectValue$1(value);
|
|
14240
|
-
const sessionKind = numberValue$
|
|
14552
|
+
const sessionKind = numberValue$26(objectValue$1(bundle.session).session_kind);
|
|
14241
14553
|
if (sessionKind !== 1 && sessionKind !== 3) continue;
|
|
14242
14554
|
const targetUserId = integerIdentifierValue(objectValue$1(bundle.private_counterpart).user_id);
|
|
14243
14555
|
if (!remaining.has(targetUserId)) continue;
|
|
@@ -14280,10 +14592,10 @@ var SourceService = class {
|
|
|
14280
14592
|
extra: { source: "dsh-arkme" }
|
|
14281
14593
|
}, session);
|
|
14282
14594
|
const topicUid = stringValue$1(created.topic_uid).trim();
|
|
14283
|
-
if (topicUid === "" || numberValue$
|
|
14595
|
+
if (topicUid === "" || numberValue$26(created.status) !== 1) throw new ArkmePluginError("topic-create-contract-invalid", "主题创建响应不完整", true, 502);
|
|
14284
14596
|
const sourceRef = await this.sealSourceRef(session.userId, "topic", topicUid, title);
|
|
14285
14597
|
if (parentTopicUid !== void 0) try {
|
|
14286
|
-
if (numberValue$
|
|
14598
|
+
if (numberValue$26(objectValue$1((await this.runtime.authenticatedPost("/api/v1/topics/hierarchy/bind", {
|
|
14287
14599
|
parent_topic_uid: parentTopicUid,
|
|
14288
14600
|
child_topic_uid: topicUid
|
|
14289
14601
|
}, session)).relation).status) !== 1) throw new ArkmePluginError("topic-hierarchy-bind-contract-invalid", "子主题层级响应不完整", true, 502);
|
|
@@ -14459,7 +14771,7 @@ var SourceService = class {
|
|
|
14459
14771
|
}
|
|
14460
14772
|
onProgress?.(recordUids.size);
|
|
14461
14773
|
if (data.has_more !== true) return [...recordUids];
|
|
14462
|
-
const nextSendAt = numberValue$
|
|
14774
|
+
const nextSendAt = numberValue$26(data.next_cursor_send_at);
|
|
14463
14775
|
const nextRecordUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
14464
14776
|
const cursorKey = `${String(nextSendAt)}:${nextRecordUid}`;
|
|
14465
14777
|
if (nextSendAt <= 0 || nextRecordUid === "" || seenCursors.has(cursorKey)) throw new ArkmePluginError("topic-dissolve-record-page-invalid", "主题快记加载不完整,未解散主题,请刷新后重试", true, 502);
|
|
@@ -14542,7 +14854,7 @@ var SourceService = class {
|
|
|
14542
14854
|
parent_topic_uid: nextParentTopicUid ?? "",
|
|
14543
14855
|
insert_before_topic_uid: ""
|
|
14544
14856
|
}, session);
|
|
14545
|
-
return stringValue$1(moved.topic_uid).trim() === topicUid && stringValue$1(moved.parent_topic_uid).trim() === (nextParentTopicUid ?? "") && numberValue$
|
|
14857
|
+
return stringValue$1(moved.topic_uid).trim() === topicUid && stringValue$1(moved.parent_topic_uid).trim() === (nextParentTopicUid ?? "") && numberValue$26(moved.sibling_order) > 0;
|
|
14546
14858
|
}
|
|
14547
14859
|
async rollbackDissolvedTopicChildren(children, topicUid, parentTopicUid, session) {
|
|
14548
14860
|
for (const child of [...children].reverse()) await this.moveTopicHierarchyForDissolve(child.topic.ownerRef, parentTopicUid ?? "", topicUid, session).catch(() => false);
|
|
@@ -14571,7 +14883,7 @@ var SourceService = class {
|
|
|
14571
14883
|
}, session);
|
|
14572
14884
|
const movedTopicUid = stringValue$1(moved.topic_uid).trim();
|
|
14573
14885
|
const movedParentUid = stringValue$1(moved.parent_topic_uid).trim();
|
|
14574
|
-
const siblingOrder = numberValue$
|
|
14886
|
+
const siblingOrder = numberValue$26(moved.sibling_order);
|
|
14575
14887
|
if (movedTopicUid !== topic.ownerRef || movedParentUid !== (nextParentUid ?? "") || siblingOrder <= 0) throw new ArkmePluginError("topic-hierarchy-move-contract-invalid", "主题移动响应不完整,请刷新后重试", true, 502);
|
|
14576
14888
|
this.sourceListCache.clear();
|
|
14577
14889
|
return {
|
|
@@ -14610,36 +14922,27 @@ var SourceService = class {
|
|
|
14610
14922
|
if (this.sourceListInFlight.get(cacheKey) === pending) this.sourceListInFlight.delete(cacheKey);
|
|
14611
14923
|
}
|
|
14612
14924
|
}
|
|
14613
|
-
async
|
|
14925
|
+
async setChatDirectoryPin(sourceRef, pinned, signal) {
|
|
14614
14926
|
const session = await this.runtime.requireSession();
|
|
14615
14927
|
const source = await this.openSourceRef(sourceRef, session.userId);
|
|
14616
14928
|
if (source.kind !== "private_chat" && source.kind !== "group_chat") throw new ArkmePluginError("chat-directory-policy-invalid", "仅支持更新私聊或群聊的会话列表状态", false);
|
|
14617
|
-
const
|
|
14618
|
-
const current = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: source.ownerRef }, session,
|
|
14619
|
-
const pinned = options.pinned ?? numberValue$25(current.pin_state) === 2;
|
|
14620
|
-
const hidden = options.hidden ?? numberValue$25(current.show_in_home_state) === 2;
|
|
14929
|
+
const pinTarget = await this.resolveChatPinTarget(source, session, signal);
|
|
14930
|
+
const current = await this.runtime.authenticatedChatPost("/api/v1/chats/policy/get", { chat_session_uid: source.ownerRef }, session, signal);
|
|
14621
14931
|
const updatedAt = Date.now();
|
|
14622
|
-
|
|
14932
|
+
await Promise.all([this.runtime.authenticatedChatPost("/api/v1/chats/policy/update", {
|
|
14623
14933
|
chat_session_uid: source.ownerRef,
|
|
14624
|
-
show_in_home_state:
|
|
14625
|
-
privacy_state: numberValue$
|
|
14626
|
-
mute_state: numberValue$
|
|
14934
|
+
show_in_home_state: numberValue$26(current.show_in_home_state) || 1,
|
|
14935
|
+
privacy_state: numberValue$26(current.privacy_state) || 1,
|
|
14936
|
+
mute_state: numberValue$26(current.mute_state) || 1,
|
|
14627
14937
|
pin_state: pinned ? 2 : 1,
|
|
14628
|
-
notify_state: numberValue$
|
|
14629
|
-
status: numberValue$
|
|
14938
|
+
notify_state: numberValue$26(current.notify_state) || 1,
|
|
14939
|
+
status: numberValue$26(current.status) || 1,
|
|
14630
14940
|
update_at: updatedAt
|
|
14631
|
-
}, session,
|
|
14632
|
-
|
|
14633
|
-
subject_uid: sidebarTarget.subjectUid,
|
|
14634
|
-
hidden,
|
|
14635
|
-
hidden_anchor_timestamp: hidden ? Math.max(1, sidebarTarget.hiddenAnchorTimestamp || updatedAt) : 0
|
|
14636
|
-
}] }, session, options.signal));
|
|
14637
|
-
if (options.pinned !== void 0) writes.push(this.runtime.authenticatedPost("/api/v1/topics/pin/set", {
|
|
14638
|
-
topic_uid: sidebarTarget.subjectUid,
|
|
14941
|
+
}, session, signal), this.runtime.authenticatedPost("/api/v1/topics/pin/set", {
|
|
14942
|
+
topic_uid: pinTarget.subjectUid,
|
|
14639
14943
|
pin_state: pinned ? 1 : 2,
|
|
14640
14944
|
...pinned ? { pinned_at: updatedAt } : {}
|
|
14641
|
-
}, session,
|
|
14642
|
-
await Promise.all(writes);
|
|
14945
|
+
}, session, signal)]);
|
|
14643
14946
|
const cacheKey = `${String(session.userId)}:${source.ownerRef}`;
|
|
14644
14947
|
const cached = this.chatSourceCache.get(cacheKey);
|
|
14645
14948
|
if (cached !== void 0) this.storeChatSourceByKey(cacheKey, {
|
|
@@ -14649,22 +14952,54 @@ var SourceService = class {
|
|
|
14649
14952
|
this.sourceListCache.clear();
|
|
14650
14953
|
return {
|
|
14651
14954
|
sourceRef,
|
|
14652
|
-
pinned
|
|
14653
|
-
hidden
|
|
14955
|
+
pinned
|
|
14654
14956
|
};
|
|
14655
14957
|
}
|
|
14656
|
-
async
|
|
14657
|
-
|
|
14658
|
-
|
|
14659
|
-
|
|
14958
|
+
async chatConversationListPreferenceEntry(sourceRef, signal) {
|
|
14959
|
+
const session = await this.runtime.requireSession();
|
|
14960
|
+
const source = await this.openSourceRef(sourceRef, session.userId);
|
|
14961
|
+
if (source.kind !== "private_chat" && source.kind !== "group_chat") throw new ArkmePluginError("chat-directory-policy-invalid", "仅支持读取私聊或群聊的会话列表状态", false);
|
|
14962
|
+
if (signal?.aborted === true) throw new DOMException("The operation was aborted", "AbortError");
|
|
14963
|
+
const cached = this.chatSourceCache.get(`${String(session.userId)}:${source.ownerRef}`);
|
|
14964
|
+
return {
|
|
14965
|
+
ownerUserId: session.userId,
|
|
14966
|
+
ref: {
|
|
14967
|
+
entityKind: 1,
|
|
14968
|
+
entityUid: source.ownerRef
|
|
14969
|
+
},
|
|
14970
|
+
evidence: {
|
|
14971
|
+
sequence: Math.max(source.conversationListLatestSequence ?? 0, cached?.latestSequence ?? 0),
|
|
14972
|
+
activityAtMillis: Math.max(source.conversationListActivityAtMillis ?? 0, cached?.activeAtMillis ?? 0)
|
|
14973
|
+
}
|
|
14660
14974
|
};
|
|
14661
|
-
|
|
14975
|
+
}
|
|
14976
|
+
async chatConversationListPreferenceEntryBySessionUid(chatSessionUid, expectedOwnerUserId) {
|
|
14977
|
+
const session = await this.runtime.requireSession();
|
|
14978
|
+
const entityUid = chatSessionUid.trim();
|
|
14979
|
+
if (session.userId !== expectedOwnerUserId) throw new ArkmePluginError("login-context-changed", "登录账号已切换,请重试当前操作", false, 409);
|
|
14980
|
+
if (entityUid === "") throw new ArkmePluginError("chat-directory-preference-identity-invalid", "会话列表身份无效", false, 400);
|
|
14981
|
+
const cached = this.chatSourceCache.get(`${String(session.userId)}:${entityUid}`);
|
|
14982
|
+
return {
|
|
14983
|
+
ownerUserId: session.userId,
|
|
14984
|
+
ref: {
|
|
14985
|
+
entityKind: 1,
|
|
14986
|
+
entityUid
|
|
14987
|
+
},
|
|
14988
|
+
evidence: {
|
|
14989
|
+
sequence: cached?.latestSequence ?? 0,
|
|
14990
|
+
activityAtMillis: cached?.activeAtMillis ?? 0
|
|
14991
|
+
}
|
|
14992
|
+
};
|
|
14993
|
+
}
|
|
14994
|
+
async resolveChatPinTarget(source, session, signal) {
|
|
14995
|
+
if (source.sidebarSubjectUid !== void 0 && source.sidebarSubjectUid.trim() !== "") return { subjectUid: source.sidebarSubjectUid.trim() };
|
|
14996
|
+
const target = arkmeChatDirectoryMetadataFromBundle(await this.runtime.authenticatedChatPost("/api/v1/chats/detail", { chat_session_uid: source.ownerRef }, session, signal, {
|
|
14662
14997
|
lane: "interactive-read",
|
|
14663
14998
|
key: `chat-sidebar-target:${source.ownerRef}`,
|
|
14664
14999
|
failureCooldownMs: 2e3
|
|
14665
15000
|
}), source.kind === "group_chat" ? source.ownerRef : "");
|
|
14666
|
-
if (target === void 0) throw new ArkmePluginError("chat-sidebar-target-unavailable", "未能定位该会话的跨端侧边栏数据,请刷新后重试", true, 502);
|
|
14667
|
-
return target;
|
|
15001
|
+
if (target.subjectUid === void 0) throw new ArkmePluginError("chat-sidebar-target-unavailable", "未能定位该会话的跨端侧边栏数据,请刷新后重试", true, 502);
|
|
15002
|
+
return { subjectUid: target.subjectUid };
|
|
14668
15003
|
}
|
|
14669
15004
|
async listGroupSources(options = {}) {
|
|
14670
15005
|
const session = await this.runtime.requireSession();
|
|
@@ -14685,7 +15020,7 @@ var SourceService = class {
|
|
|
14685
15020
|
key: "directory:groups:count",
|
|
14686
15021
|
failureCooldownMs: 2e3
|
|
14687
15022
|
});
|
|
14688
|
-
return Math.max(0, numberValue$
|
|
15023
|
+
return Math.max(0, numberValue$26(data.total ?? data.total_count));
|
|
14689
15024
|
}
|
|
14690
15025
|
async listSourcesUncached(session, directory, options, limit, sessionKind) {
|
|
14691
15026
|
if (directory === "send_to_self") {
|
|
@@ -14721,12 +15056,12 @@ var SourceService = class {
|
|
|
14721
15056
|
const childTopicUidsByParent = /* @__PURE__ */ new Map();
|
|
14722
15057
|
for (const raw of listValue$23(hierarchyData?.relations)) {
|
|
14723
15058
|
const relation = objectValue$1(raw);
|
|
14724
|
-
if (numberValue$
|
|
15059
|
+
if (numberValue$26(relation.rel_kind) !== 1 || numberValue$26(relation.status) !== 1) continue;
|
|
14725
15060
|
const parentTopicUid = stringValue$1(relation.parent_topic_uid).trim();
|
|
14726
15061
|
const childTopicUid = stringValue$1(relation.child_topic_uid).trim();
|
|
14727
15062
|
if (parentTopicUid === "" || childTopicUid === "" || parentTopicUid === childTopicUid) continue;
|
|
14728
15063
|
parentTopicUidByChild.set(childTopicUid, parentTopicUid);
|
|
14729
|
-
siblingOrderByChild.set(childTopicUid, numberValue$
|
|
15064
|
+
siblingOrderByChild.set(childTopicUid, numberValue$26(relation.sibling_order));
|
|
14730
15065
|
const children = childTopicUidsByParent.get(parentTopicUid) ?? /* @__PURE__ */ new Set();
|
|
14731
15066
|
children.add(childTopicUid);
|
|
14732
15067
|
childTopicUidsByParent.set(parentTopicUid, children);
|
|
@@ -14736,7 +15071,7 @@ var SourceService = class {
|
|
|
14736
15071
|
if (arkmePrivacyLockedTopic(item)) continue;
|
|
14737
15072
|
const core = objectValue$1(item.topic_core);
|
|
14738
15073
|
const status = core.status ?? item.status;
|
|
14739
|
-
if (status !== void 0 && numberValue$
|
|
15074
|
+
if (status !== void 0 && numberValue$26(status) !== 1) continue;
|
|
14740
15075
|
const summary = objectValue$1(item.summary);
|
|
14741
15076
|
const latest = objectValue$1(item.latest_record_core);
|
|
14742
15077
|
const parent = objectValue$1(core.parent_topic_core ?? core.parent_topic ?? item.parent_topic_core ?? item.parent_topic);
|
|
@@ -14748,12 +15083,12 @@ var SourceService = class {
|
|
|
14748
15083
|
topicDescriptors.push({
|
|
14749
15084
|
topicUid,
|
|
14750
15085
|
...parentTopicUid === "" || parentTopicUid === topicUid ? {} : { parentTopicUid },
|
|
14751
|
-
siblingOrder: numberValue$
|
|
15086
|
+
siblingOrder: numberValue$26(siblingOrderByChild.get(topicUid) ?? core.sibling_order ?? item.sibling_order),
|
|
14752
15087
|
title,
|
|
14753
15088
|
latestPreview: arkmeChatConversationPreview(latest),
|
|
14754
|
-
latestMessageAtMillis: numberValue$
|
|
14755
|
-
activeAtMillis: numberValue$
|
|
14756
|
-
recordCount: numberValue$
|
|
15089
|
+
latestMessageAtMillis: numberValue$26(latest.send_at ?? summary.latest_send_at),
|
|
15090
|
+
activeAtMillis: numberValue$26(latest.send_at ?? summary.latest_send_at ?? core.update_at),
|
|
15091
|
+
recordCount: numberValue$26(summary.record_count)
|
|
14757
15092
|
});
|
|
14758
15093
|
}
|
|
14759
15094
|
const sourceRefByTopicUid = /* @__PURE__ */ new Map();
|
|
@@ -14795,12 +15130,12 @@ var SourceService = class {
|
|
|
14795
15130
|
unreadCount: 0
|
|
14796
15131
|
};
|
|
14797
15132
|
const nextPageCursor = objectValue$1(data.next_page_cursor ?? data.next_cursor);
|
|
14798
|
-
const nextOffset = numberValue$
|
|
15133
|
+
const nextOffset = numberValue$26(data.next_offset);
|
|
14799
15134
|
const preferredPageCursor = Object.keys(nextPageCursor).length > 0 ? nextPageCursor : void 0;
|
|
14800
15135
|
const preferredOffset = preferredPageCursor === void 0 && nextOffset > 0 ? nextOffset : void 0;
|
|
14801
15136
|
const hasMore = data.has_more === true && (preferredPageCursor !== void 0 || preferredOffset !== void 0);
|
|
14802
15137
|
const totalValue = data.total ?? data.total_count;
|
|
14803
|
-
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$
|
|
15138
|
+
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$26(totalValue));
|
|
14804
15139
|
return {
|
|
14805
15140
|
directory,
|
|
14806
15141
|
items: [
|
|
@@ -14843,9 +15178,9 @@ var SourceService = class {
|
|
|
14843
15178
|
const unread = objectValue$1(bundle.unread_snapshot);
|
|
14844
15179
|
const currentPolicy = objectValue$1(bundle.current_policy);
|
|
14845
15180
|
const attention = projectArkmeChatAttention(unread.unread_count, currentPolicy);
|
|
14846
|
-
const isPinned = numberValue$
|
|
15181
|
+
const isPinned = numberValue$26(currentPolicy.pin_state) === 2;
|
|
14847
15182
|
const uid = stringValue$1(chatSession.chat_session_uid).trim();
|
|
14848
|
-
const sessionKind = numberValue$
|
|
15183
|
+
const sessionKind = numberValue$26(chatSession.session_kind);
|
|
14849
15184
|
const kind = sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : void 0;
|
|
14850
15185
|
if (uid === "" || kind === void 0) continue;
|
|
14851
15186
|
const displayName = (kind === "private_chat" ? stringValue$1(supplement.remark ?? supplement.counterpart_name_snapshot ?? counterpart.display_name_snapshot ?? supplement.pending_name ?? counterpart.visible_phone) : stringValue$1(chatSession.title)).trim() || "未命名会话";
|
|
@@ -14856,12 +15191,12 @@ var SourceService = class {
|
|
|
14856
15191
|
const backendMentionState = chatUnreadMentionState(unread);
|
|
14857
15192
|
const hasUnreadMention = kind !== "group_chat" ? void 0 : unreadCount <= 0 ? false : backendMentionState === void 0 && !latestPreviewMentionsViewer ? void 0 : backendMentionState === true || latestPreviewMentionsViewer;
|
|
14858
15193
|
const botGroupTarget = kind === "group_chat" ? arkmeGroupBotBindingTargetFromBundle(bundle) : void 0;
|
|
14859
|
-
const sidebarTarget = arkmeChatSidebarTargetFromBundle(bundle, kind === "group_chat" ? uid : "");
|
|
14860
15194
|
const cached = this.chatSourceCache.get(`${String(session.userId)}:${uid}`);
|
|
15195
|
+
const chatDirectoryMetadata = arkmeChatDirectoryMetadataFromBundle(bundle, kind === "group_chat" ? uid : "");
|
|
14861
15196
|
const item = {
|
|
14862
15197
|
sourceRef: await this.sealSourceRef(session.userId, kind, uid, displayName, {
|
|
14863
15198
|
...botGroupTarget === void 0 ? {} : { botGroupTarget },
|
|
14864
|
-
|
|
15199
|
+
chatDirectoryMetadata
|
|
14865
15200
|
}),
|
|
14866
15201
|
sourceKey: await this.chatDirectorySourceKey(session.userId, uid),
|
|
14867
15202
|
kind,
|
|
@@ -14870,16 +15205,16 @@ var SourceService = class {
|
|
|
14870
15205
|
...kind === "group_chat" && cached?.avatarRefs !== void 0 ? { avatarRefs: [...cached.avatarRefs] } : {},
|
|
14871
15206
|
...kind === "group_chat" && cached?.groupAvatar !== void 0 ? { groupAvatar: cloneSourceItem(cached).groupAvatar } : {},
|
|
14872
15207
|
...preview === "" ? {} : { latestPreview: preview },
|
|
14873
|
-
activeAtMillis:
|
|
15208
|
+
activeAtMillis: arkmeChatSortActiveAt(bundle, chatSession),
|
|
14874
15209
|
...attention,
|
|
14875
15210
|
...hasUnreadMention === void 0 ? {} : { hasUnreadMention },
|
|
14876
15211
|
isPinned,
|
|
14877
|
-
...numberValue$
|
|
15212
|
+
...numberValue$26(unread.session_last_seq ?? chatSession.last_seq) > 0 ? { latestSequence: numberValue$26(unread.session_last_seq ?? chatSession.last_seq) } : {}
|
|
14878
15213
|
};
|
|
14879
15214
|
const itemIndex = items.push(item) - 1;
|
|
14880
15215
|
chatSessionUidByIndex.set(itemIndex, uid);
|
|
14881
15216
|
if (kind === "private_chat") {
|
|
14882
|
-
const counterpartUserId = numberValue$
|
|
15217
|
+
const counterpartUserId = numberValue$26(counterpart.user_id);
|
|
14883
15218
|
if (Number.isSafeInteger(counterpartUserId) && counterpartUserId > 0) {
|
|
14884
15219
|
item.peerUserId = counterpartUserId;
|
|
14885
15220
|
privateUserIdByIndex.set(itemIndex, counterpartUserId);
|
|
@@ -14897,7 +15232,7 @@ var SourceService = class {
|
|
|
14897
15232
|
}
|
|
14898
15233
|
const hasMore = data.has_more === true;
|
|
14899
15234
|
const totalValue = data.total ?? data.total_count;
|
|
14900
|
-
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$
|
|
15235
|
+
const total = totalValue === void 0 ? void 0 : Math.max(0, numberValue$26(totalValue));
|
|
14901
15236
|
const nextPageCursor = objectValue$1(data.next_page_cursor);
|
|
14902
15237
|
return {
|
|
14903
15238
|
directory,
|
|
@@ -14964,11 +15299,11 @@ var SourceService = class {
|
|
|
14964
15299
|
const uid = stringValue$1(snapshot.chat_session_uid).trim();
|
|
14965
15300
|
const index = indexByGroupUid.get(uid);
|
|
14966
15301
|
if (index === void 0 || !groupUids.includes(uid)) continue;
|
|
14967
|
-
const memberIds = listValue$23(snapshot.members).map((member) => numberValue$
|
|
15302
|
+
const memberIds = listValue$23(snapshot.members).map((member) => numberValue$26(objectValue$1(member).user_id)).filter((userId) => Number.isSafeInteger(userId) && userId > 0).slice(0, 5);
|
|
14968
15303
|
const projection = {
|
|
14969
|
-
memberCount: Math.max(0, Math.trunc(numberValue$
|
|
15304
|
+
memberCount: Math.max(0, Math.trunc(numberValue$26(snapshot.member_count))),
|
|
14970
15305
|
strategy: stringValue$1(snapshot.strategy).trim(),
|
|
14971
|
-
computedAtMillis: numberValue$
|
|
15306
|
+
computedAtMillis: numberValue$26(snapshot.computed_at),
|
|
14972
15307
|
memberIds
|
|
14973
15308
|
};
|
|
14974
15309
|
snapshotsByUid.set(uid, projection);
|
|
@@ -15035,12 +15370,15 @@ var SourceService = class {
|
|
|
15035
15370
|
async chatDirectorySourceKey(userId, chatSessionUid) {
|
|
15036
15371
|
return `arkme-chat-source-v1.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(`chat-source-key-v1:${String(userId)}:${chatSessionUid.trim()}`).digest("base64url")}`;
|
|
15037
15372
|
}
|
|
15373
|
+
async chatTimelineItemKey(userId, chatSessionUid, relationUid) {
|
|
15374
|
+
return `arkme-chat-timeline-item-v1.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(`chat-timeline-item-key-v1:${String(userId)}:${chatSessionUid.trim()}:${relationUid.trim()}`).digest("base64url")}`;
|
|
15375
|
+
}
|
|
15038
15376
|
async topicHierarchyKey(userId, topicUid) {
|
|
15039
15377
|
return `arkme-topic-hierarchy-v1.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(`topic-hierarchy-key-v1:${String(userId)}:${topicUid.trim()}`).digest("base64url")}`;
|
|
15040
15378
|
}
|
|
15041
15379
|
async sealSourceRef(userId, kind, ownerRef, displayName, options = {}) {
|
|
15042
15380
|
const botGroupTarget = kind === "group_chat" ? sanitizeGroupBotBindingTarget(options.botGroupTarget) : void 0;
|
|
15043
|
-
const
|
|
15381
|
+
const chatDirectoryMetadata = kind === "private_chat" || kind === "group_chat" ? options.chatDirectoryMetadata : void 0;
|
|
15044
15382
|
const payload = encodeOpaqueJson$7({
|
|
15045
15383
|
version: 1,
|
|
15046
15384
|
userId,
|
|
@@ -15048,9 +15386,10 @@ var SourceService = class {
|
|
|
15048
15386
|
ownerRef,
|
|
15049
15387
|
displayName,
|
|
15050
15388
|
...botGroupTarget === void 0 ? {} : { botGroupTarget },
|
|
15051
|
-
...
|
|
15052
|
-
sidebarSubjectUid:
|
|
15053
|
-
|
|
15389
|
+
...chatDirectoryMetadata === void 0 ? {} : {
|
|
15390
|
+
...chatDirectoryMetadata.subjectUid === void 0 ? {} : { sidebarSubjectUid: chatDirectoryMetadata.subjectUid },
|
|
15391
|
+
conversationListActivityAtMillis: chatDirectoryMetadata.activityAtMillis,
|
|
15392
|
+
conversationListLatestSequence: chatDirectoryMetadata.latestSequence
|
|
15054
15393
|
}
|
|
15055
15394
|
});
|
|
15056
15395
|
return `arkme-source-v1.${payload}.${createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(payload).digest("base64url")}`;
|
|
@@ -15071,7 +15410,7 @@ var SourceService = class {
|
|
|
15071
15410
|
const kind = parsed.kind;
|
|
15072
15411
|
const result = {
|
|
15073
15412
|
version: 1,
|
|
15074
|
-
userId: numberValue$
|
|
15413
|
+
userId: numberValue$26(parsed.userId),
|
|
15075
15414
|
kind: isSourceKind(kind) ? kind : "default_category",
|
|
15076
15415
|
ownerRef: stringValue$1(parsed.ownerRef).trim(),
|
|
15077
15416
|
displayName: isSourceKind(kind) && kind === "default_category" ? "未分类" : stringValue$1(parsed.displayName).trim(),
|
|
@@ -15081,10 +15420,10 @@ var SourceService = class {
|
|
|
15081
15420
|
})() : {},
|
|
15082
15421
|
...kind === "private_chat" || kind === "group_chat" ? (() => {
|
|
15083
15422
|
const sidebarSubjectUid = stringValue$1(parsed.sidebarSubjectUid).trim();
|
|
15084
|
-
|
|
15085
|
-
|
|
15086
|
-
|
|
15087
|
-
|
|
15423
|
+
return {
|
|
15424
|
+
...sidebarSubjectUid === "" ? {} : { sidebarSubjectUid },
|
|
15425
|
+
conversationListActivityAtMillis: Math.max(0, numberValue$26(parsed.conversationListActivityAtMillis)),
|
|
15426
|
+
conversationListLatestSequence: Math.max(0, numberValue$26(parsed.conversationListLatestSequence))
|
|
15088
15427
|
};
|
|
15089
15428
|
})() : {}
|
|
15090
15429
|
};
|
|
@@ -15096,16 +15435,18 @@ var SourceService = class {
|
|
|
15096
15435
|
return {
|
|
15097
15436
|
sourceRef: await this.sealSourceRef(source.userId, source.kind, source.ownerRef, source.displayName, {
|
|
15098
15437
|
...source.botGroupTarget === void 0 ? {} : { botGroupTarget: source.botGroupTarget },
|
|
15099
|
-
|
|
15100
|
-
subjectUid: source.sidebarSubjectUid,
|
|
15101
|
-
|
|
15102
|
-
|
|
15438
|
+
chatDirectoryMetadata: {
|
|
15439
|
+
...source.sidebarSubjectUid === void 0 ? {} : { subjectUid: source.sidebarSubjectUid },
|
|
15440
|
+
activityAtMillis: source.conversationListActivityAtMillis ?? 0,
|
|
15441
|
+
latestSequence: source.conversationListLatestSequence ?? 0
|
|
15442
|
+
}
|
|
15103
15443
|
}),
|
|
15104
15444
|
...sourceKey === void 0 ? {} : { sourceKey },
|
|
15105
15445
|
kind: source.kind,
|
|
15106
15446
|
displayName: source.displayName,
|
|
15107
|
-
activeAtMillis: 0,
|
|
15108
|
-
unreadCount: 0
|
|
15447
|
+
activeAtMillis: source.conversationListActivityAtMillis ?? 0,
|
|
15448
|
+
unreadCount: 0,
|
|
15449
|
+
...(source.conversationListLatestSequence ?? 0) > 0 ? { latestSequence: source.conversationListLatestSequence } : {}
|
|
15109
15450
|
};
|
|
15110
15451
|
}
|
|
15111
15452
|
async chatSourceFromBundle(bundle, session, cached, timelineItems) {
|
|
@@ -15115,25 +15456,25 @@ var SourceService = class {
|
|
|
15115
15456
|
const unread = objectValue$1(bundle.unread_snapshot);
|
|
15116
15457
|
const currentPolicy = objectValue$1(bundle.current_policy);
|
|
15117
15458
|
const attention = projectArkmeChatAttention(unread.unread_count, currentPolicy, cached?.isMuted ?? false);
|
|
15118
|
-
const isPinned = numberValue$
|
|
15459
|
+
const isPinned = numberValue$26(currentPolicy.pin_state) === 2;
|
|
15119
15460
|
const uid = stringValue$1(chatSession.chat_session_uid).trim();
|
|
15120
|
-
const sessionKind = numberValue$
|
|
15461
|
+
const sessionKind = numberValue$26(chatSession.session_kind);
|
|
15121
15462
|
const kind = sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : void 0;
|
|
15122
15463
|
if (uid === "" || kind === void 0) throw new Error("invalid chat display snapshot");
|
|
15123
15464
|
const displayName = (kind === "private_chat" ? stringValue$1(supplement.remark ?? supplement.counterpart_name_snapshot ?? counterpart.display_name_snapshot ?? supplement.pending_name ?? counterpart.visible_phone) : stringValue$1(chatSession.title)).trim() || cached?.displayName || "未命名会话";
|
|
15124
15465
|
const latestItem = [...timelineItems].sort((left, right) => (right.sequence ?? 0) - (left.sequence ?? 0))[0];
|
|
15125
15466
|
const latestPreview = latestItem === void 0 ? cached?.latestPreview : latestItem.forwardRecords === void 0 ? arkmeTimelineConversationPreview(latestItem) : `[转发] ${latestItem.forwardRecords.title}`;
|
|
15126
|
-
const latestSequence = Math.max(numberValue$
|
|
15467
|
+
const latestSequence = Math.max(numberValue$26(unread.session_last_seq ?? chatSession.last_seq), latestItem?.sequence ?? 0, cached?.latestSequence ?? 0);
|
|
15127
15468
|
const unreadCount = attention.unreadCount;
|
|
15128
15469
|
const latestMentionsViewer = latestItem?.isMe === false && latestItem.mentionsViewer === true;
|
|
15129
15470
|
const backendMentionState = chatUnreadMentionState(unread);
|
|
15130
15471
|
const hasUnreadMention = kind !== "group_chat" ? void 0 : unreadCount <= 0 ? false : backendMentionState === void 0 && !latestMentionsViewer ? cached?.hasUnreadMention : backendMentionState === true || latestMentionsViewer;
|
|
15131
15472
|
const botGroupTarget = kind === "group_chat" ? arkmeGroupBotBindingTargetFromBundle(bundle) : void 0;
|
|
15132
|
-
const
|
|
15473
|
+
const chatDirectoryMetadata = arkmeChatDirectoryMetadataFromBundle(bundle, kind === "group_chat" ? uid : "");
|
|
15133
15474
|
return {
|
|
15134
15475
|
sourceRef: await this.sealSourceRef(session.userId, kind, uid, displayName, {
|
|
15135
15476
|
...botGroupTarget === void 0 ? {} : { botGroupTarget },
|
|
15136
|
-
|
|
15477
|
+
chatDirectoryMetadata
|
|
15137
15478
|
}),
|
|
15138
15479
|
sourceKey: await this.chatDirectorySourceKey(session.userId, uid),
|
|
15139
15480
|
kind,
|
|
@@ -15142,7 +15483,7 @@ var SourceService = class {
|
|
|
15142
15483
|
...cached?.avatarRefs === void 0 ? {} : { avatarRefs: cached.avatarRefs },
|
|
15143
15484
|
...cached?.groupAvatar === void 0 ? {} : { groupAvatar: cached.groupAvatar },
|
|
15144
15485
|
...latestPreview === void 0 || latestPreview === "" ? {} : { latestPreview },
|
|
15145
|
-
activeAtMillis: Math.max(
|
|
15486
|
+
activeAtMillis: Math.max(arkmeChatSortActiveAt(bundle, chatSession), latestItem?.sendAtMillis ?? 0),
|
|
15146
15487
|
...attention,
|
|
15147
15488
|
...hasUnreadMention === void 0 ? {} : { hasUnreadMention },
|
|
15148
15489
|
isPinned,
|
|
@@ -15173,7 +15514,7 @@ var SourceService = class {
|
|
|
15173
15514
|
const value = this.decodeCursor(cursor);
|
|
15174
15515
|
if (value.directory !== "send_to_self") throw new ArkmePluginError("source-cursor-invalid", "发给自己的主题分页游标无效", false);
|
|
15175
15516
|
const pageCursor = objectValue$1(value.pageCursor);
|
|
15176
|
-
const offset = numberValue$
|
|
15517
|
+
const offset = numberValue$26(value.offset);
|
|
15177
15518
|
if (Object.keys(pageCursor).length === 0 && offset <= 0) throw new ArkmePluginError("source-cursor-invalid", "发给自己的主题分页游标无效", false);
|
|
15178
15519
|
return {
|
|
15179
15520
|
...Object.keys(pageCursor).length === 0 ? {} : { pageCursor },
|
|
@@ -15191,7 +15532,7 @@ const BOT_REF_TTL_MILLIS = 30 * 6e4;
|
|
|
15191
15532
|
const BOT_REF_CAP = 2e3;
|
|
15192
15533
|
const BOT_REF_PATTERN = /^arkme-bot-v2\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
15193
15534
|
const BOT_IMAGE_REF_PATTERN = /^arkme-bot-image-v1\.[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
15194
|
-
function numberValue$
|
|
15535
|
+
function numberValue$25(value) {
|
|
15195
15536
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
15196
15537
|
}
|
|
15197
15538
|
function booleanValue$11(value) {
|
|
@@ -15205,7 +15546,7 @@ function arkmeNormalizeBotProvider(value) {
|
|
|
15205
15546
|
if (normalized === "openclaw" || normalized === "webhook") return normalized;
|
|
15206
15547
|
}
|
|
15207
15548
|
function botPrivateChatTimestamp(value) {
|
|
15208
|
-
const numeric = numberValue$
|
|
15549
|
+
const numeric = numberValue$25(value);
|
|
15209
15550
|
if (numeric <= 0) return 0;
|
|
15210
15551
|
if (numeric < 1e10) return numeric * 1e3;
|
|
15211
15552
|
let millis = numeric;
|
|
@@ -15324,7 +15665,7 @@ var BotService = class {
|
|
|
15324
15665
|
async countBots(options = {}) {
|
|
15325
15666
|
const session = await this.runtime.requireSession();
|
|
15326
15667
|
const data = await this.runtime.authenticatedBotPost("/api/v1/bot/list", { limit: 0 }, session, options.signal);
|
|
15327
|
-
return Math.max(0, numberValue$
|
|
15668
|
+
return Math.max(0, numberValue$25(data.total ?? data.total_count));
|
|
15328
15669
|
}
|
|
15329
15670
|
async createBot(input, options = {}) {
|
|
15330
15671
|
const name = input.name.trim();
|
|
@@ -15545,14 +15886,18 @@ var BotService = class {
|
|
|
15545
15886
|
const rawStatus = stringValue$1(raw.status).trim();
|
|
15546
15887
|
const status = rawStatus === "online" || rawStatus === "offline" ? rawStatus : "unknown";
|
|
15547
15888
|
const createdAtMillis = botPrivateChatTimestamp(raw.created_at ?? raw.createdAt);
|
|
15889
|
+
const conversationListActivityAtMillis = botPrivateChatTimestamp(raw.latest_activity_at ?? raw.latestActivityAt);
|
|
15890
|
+
const latestMessageAtMillis = botPrivateChatTimestamp(raw.latest_message_at ?? raw.latestMessageAt ?? raw.last_message_at ?? raw.lastMessageAt);
|
|
15548
15891
|
return {
|
|
15549
|
-
botRef: this.sealBotRef(userId, botId, provider, target),
|
|
15892
|
+
botRef: this.sealBotRef(userId, botId, provider, target, Math.max(createdAtMillis, conversationListActivityAtMillis, latestMessageAtMillis)),
|
|
15550
15893
|
directoryKey: await this.botDirectoryKey(userId, botId),
|
|
15551
15894
|
name,
|
|
15552
15895
|
provider,
|
|
15553
15896
|
description: stringValue$1(raw.description).trim(),
|
|
15554
15897
|
status,
|
|
15555
15898
|
...createdAtMillis === 0 ? {} : { createdAtMillis },
|
|
15899
|
+
...conversationListActivityAtMillis === 0 ? {} : { conversationListActivityAtMillis },
|
|
15900
|
+
...latestMessageAtMillis === 0 ? {} : { latestMessageAtMillis },
|
|
15556
15901
|
...this.botAvatarProjection(raw, userId, botId)
|
|
15557
15902
|
};
|
|
15558
15903
|
}
|
|
@@ -15584,7 +15929,7 @@ var BotService = class {
|
|
|
15584
15929
|
tokenRevealEnabled: data.token_reveal_enabled !== false,
|
|
15585
15930
|
gatewayUrl: stringValue$1(data.gateway_url).trim(),
|
|
15586
15931
|
webhookUrl: stringValue$1(data.webhook_url).trim(),
|
|
15587
|
-
recordCount: Math.max(-1, Math.trunc(numberValue$
|
|
15932
|
+
recordCount: Math.max(-1, Math.trunc(numberValue$25(raw.record_count))),
|
|
15588
15933
|
webhookSecurity: botWebhookSecurity(data.webhook_security ?? raw.webhook_security),
|
|
15589
15934
|
joinedGroups
|
|
15590
15935
|
};
|
|
@@ -15644,7 +15989,7 @@ var BotService = class {
|
|
|
15644
15989
|
expiresAtMillis: entry.expiresAtMillis
|
|
15645
15990
|
};
|
|
15646
15991
|
}
|
|
15647
|
-
sealBotRef(userId, botId, provider, target) {
|
|
15992
|
+
sealBotRef(userId, botId, provider, target, conversationListActivityAtMillis = 0) {
|
|
15648
15993
|
this.pruneBotRefs();
|
|
15649
15994
|
const key = `${String(userId)}\u0000${provider}\u0000${botId}`;
|
|
15650
15995
|
const existingRef = this.botRefByKey.get(key);
|
|
@@ -15653,6 +15998,7 @@ var BotService = class {
|
|
|
15653
15998
|
this.botRefs.set(existingRef, {
|
|
15654
15999
|
...existing,
|
|
15655
16000
|
...target === void 0 ? {} : { target },
|
|
16001
|
+
conversationListActivityAtMillis: Math.max(existing.conversationListActivityAtMillis, conversationListActivityAtMillis),
|
|
15656
16002
|
expiresAtMillis: this.now() + (this.refOptions.ttlMillis ?? BOT_REF_TTL_MILLIS)
|
|
15657
16003
|
});
|
|
15658
16004
|
return existingRef;
|
|
@@ -15667,6 +16013,7 @@ var BotService = class {
|
|
|
15667
16013
|
kind: "unavailable",
|
|
15668
16014
|
reason: "missing"
|
|
15669
16015
|
},
|
|
16016
|
+
conversationListActivityAtMillis: Math.max(0, conversationListActivityAtMillis),
|
|
15670
16017
|
key,
|
|
15671
16018
|
expiresAtMillis: this.now() + (this.refOptions.ttlMillis ?? BOT_REF_TTL_MILLIS)
|
|
15672
16019
|
});
|
|
@@ -15690,6 +16037,23 @@ var BotService = class {
|
|
|
15690
16037
|
const { expiresAtMillis: _expiresAtMillis, key: _key, ...reference } = entry;
|
|
15691
16038
|
return { ...reference };
|
|
15692
16039
|
}
|
|
16040
|
+
async botConversationListPreferenceEntry(botRef) {
|
|
16041
|
+
const session = await this.runtime.requireSession();
|
|
16042
|
+
const bot = await this.openBotRef(botRef, session.userId);
|
|
16043
|
+
if (bot.target.kind === "chat") return await this.source.chatConversationListPreferenceEntryBySessionUid(bot.target.chatSessionUid, session.userId);
|
|
16044
|
+
if (bot.target.kind === "unavailable" && bot.target.reason !== "missing") throw new ArkmePluginError("bot-conversation-preference-identity-unavailable", "当前 Bot 会话归属不明确,请刷新后重试", false, 409);
|
|
16045
|
+
return {
|
|
16046
|
+
ownerUserId: session.userId,
|
|
16047
|
+
ref: {
|
|
16048
|
+
entityKind: 2,
|
|
16049
|
+
entityUid: bot.botId
|
|
16050
|
+
},
|
|
16051
|
+
evidence: {
|
|
16052
|
+
sequence: 0,
|
|
16053
|
+
activityAtMillis: bot.conversationListActivityAtMillis
|
|
16054
|
+
}
|
|
16055
|
+
};
|
|
16056
|
+
}
|
|
15693
16057
|
pruneBotRefs() {
|
|
15694
16058
|
const now = this.now();
|
|
15695
16059
|
for (const [ref, entry] of this.botRefs) if (entry.expiresAtMillis <= now) this.deleteBotRef(ref, entry);
|
|
@@ -15711,14 +16075,14 @@ var BotService = class {
|
|
|
15711
16075
|
};
|
|
15712
16076
|
//#endregion
|
|
15713
16077
|
//#region src/services/bot-conversation-service.ts
|
|
15714
|
-
function numberValue$
|
|
16078
|
+
function numberValue$24(value) {
|
|
15715
16079
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
15716
16080
|
}
|
|
15717
16081
|
function listValue$21(value) {
|
|
15718
16082
|
return Array.isArray(value) ? value : [];
|
|
15719
16083
|
}
|
|
15720
16084
|
function botConversationTimestamp(value) {
|
|
15721
|
-
const numeric = numberValue$
|
|
16085
|
+
const numeric = numberValue$24(value);
|
|
15722
16086
|
if (numeric <= 0) return 0;
|
|
15723
16087
|
if (numeric < 1e10) return numeric * 1e3;
|
|
15724
16088
|
let millis = numeric;
|
|
@@ -15736,11 +16100,11 @@ function subjectAttachments(value) {
|
|
|
15736
16100
|
kind: kind || "file",
|
|
15737
16101
|
fileName,
|
|
15738
16102
|
mimeType,
|
|
15739
|
-
size: Math.max(0, Math.trunc(numberValue$
|
|
15740
|
-
durationMillis: Math.max(0, Math.trunc(numberValue$
|
|
15741
|
-
width: Math.max(0, Math.trunc(numberValue$
|
|
15742
|
-
height: Math.max(0, Math.trunc(numberValue$
|
|
15743
|
-
sortOrder: Math.max(0, Math.trunc(numberValue$
|
|
16103
|
+
size: Math.max(0, Math.trunc(numberValue$24(raw.size))),
|
|
16104
|
+
durationMillis: Math.max(0, Math.trunc(numberValue$24(raw.duration_ms ?? raw.durationMillis))),
|
|
16105
|
+
width: Math.max(0, Math.trunc(numberValue$24(raw.width))),
|
|
16106
|
+
height: Math.max(0, Math.trunc(numberValue$24(raw.height))),
|
|
16107
|
+
sortOrder: Math.max(0, Math.trunc(numberValue$24(raw.order ?? raw.sort_order ?? raw.sortOrder)))
|
|
15744
16108
|
}];
|
|
15745
16109
|
});
|
|
15746
16110
|
}
|
|
@@ -15984,7 +16348,7 @@ var BotConversationService = class {
|
|
|
15984
16348
|
//#region src/services/calendar-service.ts
|
|
15985
16349
|
const MAX_CALENDAR_RANGE_DAYS = 62;
|
|
15986
16350
|
const MAX_DAY_RECORD_LIMIT = 50;
|
|
15987
|
-
function numberValue$
|
|
16351
|
+
function numberValue$23(value) {
|
|
15988
16352
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
15989
16353
|
}
|
|
15990
16354
|
function booleanValue$10(value) {
|
|
@@ -16024,7 +16388,7 @@ function boundedLimit$2(value) {
|
|
|
16024
16388
|
return limit;
|
|
16025
16389
|
}
|
|
16026
16390
|
function contentAccessState(value) {
|
|
16027
|
-
const code = Math.trunc(numberValue$
|
|
16391
|
+
const code = Math.trunc(numberValue$23(value));
|
|
16028
16392
|
if (code === 1) return "available";
|
|
16029
16393
|
if (code === 2) return "protected";
|
|
16030
16394
|
return "unknown";
|
|
@@ -16097,7 +16461,7 @@ var CalendarService = class {
|
|
|
16097
16461
|
cacheMs: 1e4,
|
|
16098
16462
|
failureCooldownMs: 2e3
|
|
16099
16463
|
});
|
|
16100
|
-
const nextSendAt = Math.trunc(numberValue$
|
|
16464
|
+
const nextSendAt = Math.trunc(numberValue$23(data.next_cursor_send_at));
|
|
16101
16465
|
const nextUid = stringValue$1(data.next_cursor_record_uid).trim();
|
|
16102
16466
|
return {
|
|
16103
16467
|
scope: "self",
|
|
@@ -16116,21 +16480,21 @@ var CalendarService = class {
|
|
|
16116
16480
|
const item = objectValue$1(raw);
|
|
16117
16481
|
const bucketDate = stringValue$1(item.bucket_date).trim();
|
|
16118
16482
|
if (bucketDate === "") return void 0;
|
|
16119
|
-
const protectedCount = Math.max(0, Math.trunc(numberValue$
|
|
16120
|
-
const count = Math.max(0, Math.trunc(numberValue$
|
|
16483
|
+
const protectedCount = Math.max(0, Math.trunc(numberValue$23(item.protected_count)));
|
|
16484
|
+
const count = Math.max(0, Math.trunc(numberValue$23(item.count)) - protectedCount);
|
|
16121
16485
|
return {
|
|
16122
16486
|
bucketDate,
|
|
16123
16487
|
count,
|
|
16124
16488
|
protectedCount: 0,
|
|
16125
16489
|
hasRecords: count > 0,
|
|
16126
|
-
...numberValue$
|
|
16490
|
+
...numberValue$23(item.first_send_at) > 0 ? { firstSendAtMillis: Math.trunc(numberValue$23(item.first_send_at)) } : {}
|
|
16127
16491
|
};
|
|
16128
16492
|
}
|
|
16129
16493
|
dayRecord(raw) {
|
|
16130
16494
|
const item = objectValue$1(raw);
|
|
16131
16495
|
const core = objectValue$1(item.record_core);
|
|
16132
16496
|
const recordUid = stringValue$1(item.record_uid ?? core.record_uid).trim();
|
|
16133
|
-
const sendAtMillis = Math.trunc(numberValue$
|
|
16497
|
+
const sendAtMillis = Math.trunc(numberValue$23(item.send_at ?? core.send_at));
|
|
16134
16498
|
if (recordUid === "" || sendAtMillis <= 0) return void 0;
|
|
16135
16499
|
const accessState = contentAccessState(core.content_access_state);
|
|
16136
16500
|
if (accessState === "protected" || arkmePrivacyLockedRecord(item)) return void 0;
|
|
@@ -16151,9 +16515,9 @@ var CalendarService = class {
|
|
|
16151
16515
|
preview,
|
|
16152
16516
|
...stringValue$1(topic.title).trim() === "" ? {} : { topicTitle: stringValue$1(topic.title).trim() },
|
|
16153
16517
|
sourceKind: sourceKind(item),
|
|
16154
|
-
creationSource: Math.trunc(numberValue$
|
|
16155
|
-
templateKind: Math.trunc(numberValue$
|
|
16156
|
-
displayKind: Math.trunc(numberValue$
|
|
16518
|
+
creationSource: Math.trunc(numberValue$23(core.creation_source)),
|
|
16519
|
+
templateKind: Math.trunc(numberValue$23(core.template_kind)),
|
|
16520
|
+
displayKind: Math.trunc(numberValue$23(core.display_kind)),
|
|
16157
16521
|
protected: false,
|
|
16158
16522
|
...isUncategorized === void 0 ? {} : { isUncategorized },
|
|
16159
16523
|
...hasManualEdit === void 0 ? {} : { hasManualEdit },
|
|
@@ -16166,7 +16530,7 @@ var CalendarService = class {
|
|
|
16166
16530
|
function listValue$19(value) {
|
|
16167
16531
|
return Array.isArray(value) ? value : [];
|
|
16168
16532
|
}
|
|
16169
|
-
function numberValue$
|
|
16533
|
+
function numberValue$22(value) {
|
|
16170
16534
|
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
16171
16535
|
if (typeof value === "string" && value.trim() !== "") {
|
|
16172
16536
|
const parsed = Number(value.trim());
|
|
@@ -16189,13 +16553,13 @@ function firstString$1(source, keys) {
|
|
|
16189
16553
|
}
|
|
16190
16554
|
function firstNumber(source, keys) {
|
|
16191
16555
|
for (const key of keys) {
|
|
16192
|
-
const value = numberValue$
|
|
16556
|
+
const value = numberValue$22(source[key]);
|
|
16193
16557
|
if (value !== 0) return value;
|
|
16194
16558
|
}
|
|
16195
16559
|
return 0;
|
|
16196
16560
|
}
|
|
16197
16561
|
function epochMillis$1(value) {
|
|
16198
|
-
const raw = numberValue$
|
|
16562
|
+
const raw = numberValue$22(value);
|
|
16199
16563
|
if (raw <= 0) return 0;
|
|
16200
16564
|
return raw < 1e10 ? Math.trunc(raw * 1e3) : Math.trunc(raw);
|
|
16201
16565
|
}
|
|
@@ -16207,7 +16571,7 @@ function firstEpochMillis(source, keys) {
|
|
|
16207
16571
|
return 0;
|
|
16208
16572
|
}
|
|
16209
16573
|
function numberList(value) {
|
|
16210
|
-
return listValue$19(value).map((item) => Math.trunc(numberValue$
|
|
16574
|
+
return listValue$19(value).map((item) => Math.trunc(numberValue$22(item))).filter((item) => Number.isSafeInteger(item) && item > 0);
|
|
16211
16575
|
}
|
|
16212
16576
|
function callMediaType(value) {
|
|
16213
16577
|
if (value === 0 || value === "0") return "audio";
|
|
@@ -16972,11 +17336,11 @@ var CallHistoryService = class {
|
|
|
16972
17336
|
}
|
|
16973
17337
|
const value = objectValue$1(payload);
|
|
16974
17338
|
const parsed = {
|
|
16975
|
-
version: numberValue$
|
|
16976
|
-
userId: numberValue$
|
|
17339
|
+
version: numberValue$22(value.version),
|
|
17340
|
+
userId: numberValue$22(value.userId),
|
|
16977
17341
|
roomId: stringValue$1(value.roomId).trim(),
|
|
16978
17342
|
stableId: stringValue$1(value.stableId).trim(),
|
|
16979
|
-
issuedAtMillis: numberValue$
|
|
17343
|
+
issuedAtMillis: numberValue$22(value.issuedAtMillis)
|
|
16980
17344
|
};
|
|
16981
17345
|
if (parsed.version !== 1 || parsed.userId !== expectedUserId || parsed.roomId === "" || parsed.stableId === "") throw new ArkmePluginError("call-ref-invalid", "通话记录引用无效,请重新查询通话记录", false, 400);
|
|
16982
17346
|
return parsed;
|
|
@@ -17099,6 +17463,49 @@ function decodeArkmeChatReadCursorAdvancedDataLine(line) {
|
|
|
17099
17463
|
eventAtMillis
|
|
17100
17464
|
};
|
|
17101
17465
|
}
|
|
17466
|
+
const TIMELINE_CHANGED_ALLOWED_FIELDS = /* @__PURE__ */ new Set([
|
|
17467
|
+
"t",
|
|
17468
|
+
"event_uid",
|
|
17469
|
+
"chat_session_uid",
|
|
17470
|
+
"rel_uid",
|
|
17471
|
+
"latest_seq",
|
|
17472
|
+
"actor_user_id",
|
|
17473
|
+
"change_kind",
|
|
17474
|
+
"change_version",
|
|
17475
|
+
"relation_terminal",
|
|
17476
|
+
"event_at",
|
|
17477
|
+
"source_client_id"
|
|
17478
|
+
]);
|
|
17479
|
+
/** Decode one metadata-only timeline invalidation. Record content remains owned by Chat reads. */
|
|
17480
|
+
function decodeArkmeChatTimelineChangedDataLine(line) {
|
|
17481
|
+
const source = decodeDataLine(line);
|
|
17482
|
+
if (source === void 0 || positiveInteger(source.t) !== 20) return void 0;
|
|
17483
|
+
if (Object.keys(source).some((field) => !TIMELINE_CHANGED_ALLOWED_FIELDS.has(field))) return void 0;
|
|
17484
|
+
const eventUid = nonEmptyString(source.event_uid);
|
|
17485
|
+
const chatSessionUid = nonEmptyString(source.chat_session_uid);
|
|
17486
|
+
const relationUid = nonEmptyString(source.rel_uid);
|
|
17487
|
+
const latestSequence = positiveInteger(source.latest_seq);
|
|
17488
|
+
const actorUserId = positiveInteger(source.actor_user_id);
|
|
17489
|
+
const changeVersion = positiveInteger(source.change_version);
|
|
17490
|
+
const relationTerminal = source.relation_terminal === void 0 ? false : typeof source.relation_terminal === "boolean" ? source.relation_terminal : void 0;
|
|
17491
|
+
const eventAtMillis = positiveInteger(source.event_at);
|
|
17492
|
+
const sourceClientId = source.source_client_id === void 0 ? 0 : nonNegativeInteger(source.source_client_id);
|
|
17493
|
+
const changeKindValue = positiveInteger(source.change_kind);
|
|
17494
|
+
const changeKind = changeKindValue === 1 ? "deleted" : changeKindValue === 2 ? "recovered" : changeKindValue === 3 ? "reedited" : changeKindValue === 4 ? "extended" : void 0;
|
|
17495
|
+
if (eventUid === void 0 || chatSessionUid === void 0 || relationUid === void 0 || latestSequence === void 0 || actorUserId === void 0 || changeKind === void 0 || changeVersion === void 0 || relationTerminal === void 0 || eventAtMillis === void 0 || sourceClientId === void 0) return void 0;
|
|
17496
|
+
if (relationTerminal && changeKind !== "deleted") return void 0;
|
|
17497
|
+
return {
|
|
17498
|
+
eventUid,
|
|
17499
|
+
chatSessionUid,
|
|
17500
|
+
relationUid,
|
|
17501
|
+
latestSequence,
|
|
17502
|
+
actorUserId,
|
|
17503
|
+
changeKind,
|
|
17504
|
+
changeVersion,
|
|
17505
|
+
relationTerminal,
|
|
17506
|
+
eventAtMillis
|
|
17507
|
+
};
|
|
17508
|
+
}
|
|
17102
17509
|
const PROJECTION_NAME_PATTERN = /^[a-z][a-z0-9._-]{0,63}$/;
|
|
17103
17510
|
const PROJECTION_INVALIDATION_FORBIDDEN_FIELDS = [
|
|
17104
17511
|
"receiver_user_ids",
|
|
@@ -17125,6 +17532,58 @@ function decodeArkmeProjectionInvalidatedDataLine(line) {
|
|
|
17125
17532
|
eventAtMillis
|
|
17126
17533
|
};
|
|
17127
17534
|
}
|
|
17535
|
+
const CONVERSATION_LIST_PREFERENCE_ALLOWED_ITEM_FIELDS = /* @__PURE__ */ new Set([
|
|
17536
|
+
"entity_kind",
|
|
17537
|
+
"entity_uid",
|
|
17538
|
+
"revision"
|
|
17539
|
+
]);
|
|
17540
|
+
const CONVERSATION_LIST_PREFERENCE_FORBIDDEN_FIELDS = [
|
|
17541
|
+
"visibility_state",
|
|
17542
|
+
"dismissed_through_seq",
|
|
17543
|
+
"dismissed_through_activity_at",
|
|
17544
|
+
"chat_session_uid",
|
|
17545
|
+
"pin_state",
|
|
17546
|
+
"unread_count",
|
|
17547
|
+
"payload",
|
|
17548
|
+
"receiver_user_ids"
|
|
17549
|
+
];
|
|
17550
|
+
/** Decode a metadata-only invalidation. The Browser must query the Chat owner for current state. */
|
|
17551
|
+
function decodeArkmeConversationListPreferenceUpdatedDataLine(line) {
|
|
17552
|
+
const source = decodeDataLine(line);
|
|
17553
|
+
if (source === void 0 || positiveInteger(source.t) !== 26 || CONVERSATION_LIST_PREFERENCE_FORBIDDEN_FIELDS.some((field) => Object.hasOwn(source, field))) return void 0;
|
|
17554
|
+
const eventUid = nonEmptyString(source.event_uid);
|
|
17555
|
+
const userId = positiveInteger(source.user_id);
|
|
17556
|
+
const acceptedAtMillis = positiveInteger(source.accepted_at);
|
|
17557
|
+
const sourceClientId = source.source_client_id === void 0 ? 0 : nonNegativeInteger(source.source_client_id);
|
|
17558
|
+
const rawItems = Array.isArray(source.items) ? source.items : [];
|
|
17559
|
+
if (eventUid === void 0 || userId === void 0 || acceptedAtMillis === void 0 || sourceClientId === void 0 || rawItems.length === 0 || rawItems.length > 200) return void 0;
|
|
17560
|
+
const seen = /* @__PURE__ */ new Set();
|
|
17561
|
+
const items = [];
|
|
17562
|
+
for (const value of rawItems) {
|
|
17563
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
17564
|
+
const item = value;
|
|
17565
|
+
if (Object.keys(item).some((field) => !CONVERSATION_LIST_PREFERENCE_ALLOWED_ITEM_FIELDS.has(field))) return void 0;
|
|
17566
|
+
const entityKind = positiveInteger(item.entity_kind);
|
|
17567
|
+
const entityUid = typeof item.entity_uid === "string" && item.entity_uid !== "" && item.entity_uid.trim() === item.entity_uid ? item.entity_uid : void 0;
|
|
17568
|
+
const revision = positiveInteger(item.revision);
|
|
17569
|
+
if (entityKind !== 1 && entityKind !== 2 || entityUid === void 0 || revision === void 0 || Buffer.byteLength(entityUid, "utf8") > 128) return void 0;
|
|
17570
|
+
const identity = `${String(entityKind)}:${String(Buffer.byteLength(entityUid, "utf8"))}:${entityUid}`;
|
|
17571
|
+
if (seen.has(identity)) return void 0;
|
|
17572
|
+
seen.add(identity);
|
|
17573
|
+
items.push({
|
|
17574
|
+
entityKind,
|
|
17575
|
+
entityUid,
|
|
17576
|
+
revision
|
|
17577
|
+
});
|
|
17578
|
+
}
|
|
17579
|
+
return {
|
|
17580
|
+
eventUid,
|
|
17581
|
+
userId,
|
|
17582
|
+
items,
|
|
17583
|
+
acceptedAtMillis,
|
|
17584
|
+
sourceClientId
|
|
17585
|
+
};
|
|
17586
|
+
}
|
|
17128
17587
|
function waitFor(milliseconds, signal) {
|
|
17129
17588
|
if (signal.aborted) return Promise.resolve();
|
|
17130
17589
|
return new Promise((resolve) => {
|
|
@@ -17404,28 +17863,36 @@ var ArkmeChatRealtimeRuntime = class {
|
|
|
17404
17863
|
}
|
|
17405
17864
|
}
|
|
17406
17865
|
acceptLine(line) {
|
|
17407
|
-
const
|
|
17408
|
-
const
|
|
17409
|
-
const
|
|
17410
|
-
const
|
|
17866
|
+
const conversationListPreferenceUpdated = decodeArkmeConversationListPreferenceUpdatedDataLine(line);
|
|
17867
|
+
const projectionInvalidation = conversationListPreferenceUpdated === void 0 ? decodeArkmeProjectionInvalidatedDataLine(line) : void 0;
|
|
17868
|
+
const readCursorAdvanced = conversationListPreferenceUpdated === void 0 && projectionInvalidation === void 0 ? decodeArkmeChatReadCursorAdvancedDataLine(line) : void 0;
|
|
17869
|
+
const timelineChanged = conversationListPreferenceUpdated === void 0 && projectionInvalidation === void 0 && readCursorAdvanced === void 0 ? decodeArkmeChatTimelineChangedDataLine(line) : void 0;
|
|
17870
|
+
const hint = conversationListPreferenceUpdated === void 0 && projectionInvalidation === void 0 && readCursorAdvanced === void 0 && timelineChanged === void 0 ? decodeArkmeChatReceiveDataLine(line) : void 0;
|
|
17871
|
+
const eventUid = conversationListPreferenceUpdated?.eventUid ?? projectionInvalidation?.eventUid ?? readCursorAdvanced?.eventUid ?? timelineChanged?.eventUid ?? hint?.eventUid;
|
|
17411
17872
|
if (eventUid === void 0 || this.seenEventUids.has(eventUid)) return;
|
|
17412
17873
|
this.seenEventUids.add(eventUid);
|
|
17413
17874
|
if (this.seenEventUids.size > MAX_SEEN_EVENTS) {
|
|
17414
17875
|
const oldest = this.seenEventUids.values().next().value;
|
|
17415
17876
|
if (oldest !== void 0) this.seenEventUids.delete(oldest);
|
|
17416
17877
|
}
|
|
17417
|
-
this.lastEventAtMillis = projectionInvalidation?.eventAtMillis ?? readCursorAdvanced?.eventAtMillis ?? hint?.eventAtMillis;
|
|
17418
|
-
if (
|
|
17419
|
-
else this.advanceRevision("
|
|
17878
|
+
this.lastEventAtMillis = conversationListPreferenceUpdated?.acceptedAtMillis ?? projectionInvalidation?.eventAtMillis ?? readCursorAdvanced?.eventAtMillis ?? timelineChanged?.eventAtMillis ?? hint?.eventAtMillis;
|
|
17879
|
+
if (conversationListPreferenceUpdated !== void 0) this.advanceRevision("conversation-list-preference-invalidation", { conversationListPreferenceUpdated });
|
|
17880
|
+
else if (projectionInvalidation !== void 0) this.advanceRevision("projection-invalidation", { projectionInvalidation });
|
|
17881
|
+
else if (timelineChanged !== void 0) this.advanceRevision("chat-hint", { timelineChanged });
|
|
17882
|
+
else if (readCursorAdvanced !== void 0) this.advanceRevision("chat-hint", { readCursorAdvanced });
|
|
17883
|
+
else if (hint !== void 0) this.advanceRevision("chat-hint", { hint });
|
|
17420
17884
|
}
|
|
17421
|
-
advanceRevision(cause,
|
|
17885
|
+
advanceRevision(cause, evidence = {}) {
|
|
17886
|
+
const { hint, readCursorAdvanced, projectionInvalidation, timelineChanged, conversationListPreferenceUpdated } = evidence;
|
|
17422
17887
|
this.revision += 1;
|
|
17423
17888
|
const notice = {
|
|
17424
17889
|
state: this.state(),
|
|
17425
17890
|
cause,
|
|
17891
|
+
...timelineChanged === void 0 ? {} : { timelineChanged },
|
|
17426
17892
|
...hint === void 0 ? {} : { hint },
|
|
17427
17893
|
...readCursorAdvanced === void 0 ? {} : { readCursorAdvanced },
|
|
17428
|
-
...projectionInvalidation === void 0 ? {} : { projectionInvalidation }
|
|
17894
|
+
...projectionInvalidation === void 0 ? {} : { projectionInvalidation },
|
|
17895
|
+
...conversationListPreferenceUpdated === void 0 ? {} : { conversationListPreferenceUpdated }
|
|
17429
17896
|
};
|
|
17430
17897
|
for (const listener of [...this.listeners]) listener(notice);
|
|
17431
17898
|
}
|
|
@@ -17435,6 +17902,9 @@ var ArkmeChatRealtimeRuntime = class {
|
|
|
17435
17902
|
const MAX_PROJECTION_RETRIES = 5;
|
|
17436
17903
|
const MAX_ATTENTION_SUMMARY_RETRIES = 5;
|
|
17437
17904
|
const MAX_NATIVE_NOTIFICATION_DELIVERY_CONCURRENCY = 3;
|
|
17905
|
+
function numberValue$21(value) {
|
|
17906
|
+
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
17907
|
+
}
|
|
17438
17908
|
function listValue$18(value) {
|
|
17439
17909
|
return Array.isArray(value) ? value : [];
|
|
17440
17910
|
}
|
|
@@ -17576,16 +18046,46 @@ var ChatRealtimeService = class {
|
|
|
17576
18046
|
this.invalidateRecordProjection();
|
|
17577
18047
|
return;
|
|
17578
18048
|
}
|
|
18049
|
+
if (notice.cause === "conversation-list-preference-invalidation" && notice.conversationListPreferenceUpdated !== void 0) {
|
|
18050
|
+
this.invalidateConversationListPreferenceForCurrentSession(notice.conversationListPreferenceUpdated.userId);
|
|
18051
|
+
return;
|
|
18052
|
+
}
|
|
17579
18053
|
if (notice.cause === "chat-hint" && notice.readCursorAdvanced !== void 0) {
|
|
17580
18054
|
this.handleReadCursorAdvanced(notice.readCursorAdvanced);
|
|
17581
18055
|
return;
|
|
17582
18056
|
}
|
|
18057
|
+
if (notice.cause === "chat-hint" && notice.timelineChanged !== void 0) {
|
|
18058
|
+
this.handleTimelineChanged(notice.timelineChanged);
|
|
18059
|
+
return;
|
|
18060
|
+
}
|
|
17583
18061
|
if (notice.cause === "chat-hint" && notice.hint !== void 0) this.scheduleChatSessionProjection(notice.hint.chatSessionUid, notice.hint.latestSequence, {
|
|
17584
18062
|
hint: notice.hint,
|
|
17585
18063
|
connectionGeneration: notice.state.connectionGeneration,
|
|
17586
18064
|
attempts: 0
|
|
17587
18065
|
});
|
|
17588
18066
|
}
|
|
18067
|
+
async handleTimelineChanged(hint) {
|
|
18068
|
+
try {
|
|
18069
|
+
const session = await this.runtime.sessionStore.read();
|
|
18070
|
+
if (session === void 0) return;
|
|
18071
|
+
const [sourceKey, timelineItemKey] = await Promise.all([this.source.chatDirectorySourceKey(session.userId, hint.chatSessionUid), this.source.chatTimelineItemKey(session.userId, hint.chatSessionUid, hint.relationUid)]);
|
|
18072
|
+
if ((await this.runtime.sessionStore.read())?.userId !== session.userId) return;
|
|
18073
|
+
this.emitChatClientEvent({
|
|
18074
|
+
type: "timeline-changed",
|
|
18075
|
+
revision: this.nextChatClientRevision(),
|
|
18076
|
+
sourceKey,
|
|
18077
|
+
timelineItemKey,
|
|
18078
|
+
changeKind: hint.changeKind,
|
|
18079
|
+
changeVersion: hint.changeVersion,
|
|
18080
|
+
relationTerminal: hint.relationTerminal,
|
|
18081
|
+
throughSequence: hint.latestSequence
|
|
18082
|
+
});
|
|
18083
|
+
this.scheduleChatSessionProjection(hint.chatSessionUid, hint.latestSequence);
|
|
18084
|
+
this.refreshAttentionSummary();
|
|
18085
|
+
} catch (error) {
|
|
18086
|
+
console.warn("dsh-arkme: Chat timeline invalidation failed:", safeFailureMessage$5(error));
|
|
18087
|
+
}
|
|
18088
|
+
}
|
|
17589
18089
|
async handleReadCursorAdvanced(hint) {
|
|
17590
18090
|
try {
|
|
17591
18091
|
const session = await this.runtime.sessionStore.read();
|
|
@@ -17753,6 +18253,19 @@ var ChatRealtimeService = class {
|
|
|
17753
18253
|
this.attentionSummaryFingerprint = "";
|
|
17754
18254
|
this.latestAttentionSummary = void 0;
|
|
17755
18255
|
}
|
|
18256
|
+
/** Browser invalidation only; raw source/Bot caches belong to different projections. */
|
|
18257
|
+
async invalidateConversationListPreferenceForCurrentSession(expectedUserId) {
|
|
18258
|
+
try {
|
|
18259
|
+
const session = await this.runtime.sessionStore.read();
|
|
18260
|
+
if (session === void 0 || expectedUserId !== void 0 && session.userId !== expectedUserId) return;
|
|
18261
|
+
this.emitChatClientEvent({
|
|
18262
|
+
type: "conversation-list-preference-invalidated",
|
|
18263
|
+
revision: this.nextChatClientRevision()
|
|
18264
|
+
});
|
|
18265
|
+
} catch (error) {
|
|
18266
|
+
console.warn("dsh-arkme: Conversation-list preference invalidation failed:", safeFailureMessage$5(error));
|
|
18267
|
+
}
|
|
18268
|
+
}
|
|
17756
18269
|
async reconcileChatNotificationBaseline(connectionGeneration) {
|
|
17757
18270
|
try {
|
|
17758
18271
|
const session = await this.runtime.requireSession();
|
|
@@ -17908,7 +18421,8 @@ var ChatRealtimeService = class {
|
|
|
17908
18421
|
lane: "background-read",
|
|
17909
18422
|
key: `projection:tail:${uid}:${String(afterSequence)}:${String(notificationAttempt)}`
|
|
17910
18423
|
});
|
|
17911
|
-
|
|
18424
|
+
const sessionKind = numberValue$21(objectValue$1(bundles.get(uid)).session_kind ?? objectValue$1(objectValue$1(bundles.get(uid)).session).session_kind);
|
|
18425
|
+
return [uid, await this.projectionReader.chatTimelineItems(data, session, uid, sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : void 0)];
|
|
17912
18426
|
}))).forEach((result, index) => {
|
|
17913
18427
|
const uid = chunk[index]?.[0];
|
|
17914
18428
|
if (uid === void 0) return;
|
|
@@ -18050,6 +18564,54 @@ const ARKME_VOICEPRINT_ENROLLMENT_MAX_AUDIO_BYTES = 10 * 1024 * 1024;
|
|
|
18050
18564
|
const ARKME_WORLD_PUBLISH_MAX_IMAGES = 27;
|
|
18051
18565
|
const ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES = 20 * 1024 * 1024;
|
|
18052
18566
|
//#endregion
|
|
18567
|
+
//#region src/hashtag.ts
|
|
18568
|
+
/** Flutter-compatible tag terminators. Keep this list in sync with chat_input_rich_support.dart. */
|
|
18569
|
+
const ARKME_HASH_TAG_TERMINATORS = /* @__PURE__ */ new Set([..." \n##,。!?;:、\"()【】《》,.!?;:'()[]<>"]);
|
|
18570
|
+
function isHashTagAnchor(value) {
|
|
18571
|
+
return value === "#" || value === "#";
|
|
18572
|
+
}
|
|
18573
|
+
/** Normalizes either rendered tag form to the key accepted by the tag projection API. */
|
|
18574
|
+
function arkmeNormalizedHashTag(value) {
|
|
18575
|
+
return value.trim().replace(/^[##]+/u, "").trim();
|
|
18576
|
+
}
|
|
18577
|
+
/** Finds all non-empty tags. An unterminated final tag is complete enough to send. */
|
|
18578
|
+
function arkmeHashTagRanges(text) {
|
|
18579
|
+
const ranges = [];
|
|
18580
|
+
let index = 0;
|
|
18581
|
+
while (index < text.length) {
|
|
18582
|
+
if (!isHashTagAnchor(text[index])) {
|
|
18583
|
+
index += 1;
|
|
18584
|
+
continue;
|
|
18585
|
+
}
|
|
18586
|
+
const contentStart = index + 1;
|
|
18587
|
+
let contentEnd = contentStart;
|
|
18588
|
+
while (contentEnd < text.length && !ARKME_HASH_TAG_TERMINATORS.has(text[contentEnd])) contentEnd += 1;
|
|
18589
|
+
if (contentEnd > contentStart) ranges.push({
|
|
18590
|
+
tag: text.slice(contentStart, contentEnd),
|
|
18591
|
+
startIndex: index,
|
|
18592
|
+
length: contentEnd - index
|
|
18593
|
+
});
|
|
18594
|
+
index = contentEnd > index ? contentEnd : index + 1;
|
|
18595
|
+
}
|
|
18596
|
+
return ranges;
|
|
18597
|
+
}
|
|
18598
|
+
function arkmeHashTagPayload(text) {
|
|
18599
|
+
return arkmeHashTagRanges(text).map((item) => ({
|
|
18600
|
+
tag: item.tag,
|
|
18601
|
+
start_index: item.startIndex,
|
|
18602
|
+
length: item.length
|
|
18603
|
+
}));
|
|
18604
|
+
}
|
|
18605
|
+
function arkmeHashTagContentPayload(text) {
|
|
18606
|
+
const hashTags = arkmeHashTagPayload(text);
|
|
18607
|
+
return hashTags.length === 0 ? void 0 : {
|
|
18608
|
+
payload_kind: 1,
|
|
18609
|
+
schema_version: 1,
|
|
18610
|
+
text_state: 1,
|
|
18611
|
+
hash_tags: hashTags
|
|
18612
|
+
};
|
|
18613
|
+
}
|
|
18614
|
+
//#endregion
|
|
18053
18615
|
//#region src/services/record-service.ts
|
|
18054
18616
|
function numberValue$20(value) {
|
|
18055
18617
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -18207,6 +18769,45 @@ var RecordService = class {
|
|
|
18207
18769
|
async refreshLatest() {
|
|
18208
18770
|
await Promise.all([this.summary(), this.list(50)]);
|
|
18209
18771
|
}
|
|
18772
|
+
async listTags(limit = 100, signal) {
|
|
18773
|
+
const session = await this.runtime.requireSession();
|
|
18774
|
+
return { items: listValue$17((await this.runtime.authenticatedPost("/api/v1/records/tags/list", { limit: Math.max(1, Math.min(200, Math.trunc(limit))) }, session, signal)).items).flatMap((raw) => {
|
|
18775
|
+
const item = objectValue$1(raw);
|
|
18776
|
+
const tagText = stringValue$1(item.tag_text ?? item.tagText).trim();
|
|
18777
|
+
if (tagText === "") return [];
|
|
18778
|
+
return [{
|
|
18779
|
+
normalizedTag: stringValue$1(item.normalized_tag ?? item.normalizedTag).trim() || tagText.toLowerCase(),
|
|
18780
|
+
tagText,
|
|
18781
|
+
recordCount: Math.max(0, Math.trunc(numberValue$20(item.record_count ?? item.recordCount))),
|
|
18782
|
+
latestRecordUid: stringValue$1(item.latest_record_uid ?? item.latestRecordUid).trim(),
|
|
18783
|
+
latestSendAtMillis: Math.max(0, Math.trunc(numberValue$20(item.latest_send_at ?? item.latestSendAtMillis)))
|
|
18784
|
+
}];
|
|
18785
|
+
}) };
|
|
18786
|
+
}
|
|
18787
|
+
/**
|
|
18788
|
+
* Mirrors Flutter's post-commit tag sync. Record creation is already the
|
|
18789
|
+
* commit boundary, so a projection-side failure is diagnostic only and must
|
|
18790
|
+
* never turn an accepted message into a retryable send.
|
|
18791
|
+
*/
|
|
18792
|
+
async syncCreatedRecordTags(recordUid, textContent, expectedUserId, signal) {
|
|
18793
|
+
const tags = arkmeHashTagPayload(textContent);
|
|
18794
|
+
if (tags.length === 0) return;
|
|
18795
|
+
try {
|
|
18796
|
+
const session = await this.runtime.requireSession();
|
|
18797
|
+
if (expectedUserId !== void 0 && session.userId !== expectedUserId) return;
|
|
18798
|
+
await this.runtime.authenticatedPost("/api/v1/records/tags/set", {
|
|
18799
|
+
record_uid: recordUid.trim(),
|
|
18800
|
+
expected_record_version: 1,
|
|
18801
|
+
tags: tags.map((tag) => ({
|
|
18802
|
+
tag_text: tag.tag,
|
|
18803
|
+
start_index: tag.start_index,
|
|
18804
|
+
length: tag.length
|
|
18805
|
+
}))
|
|
18806
|
+
}, session, signal);
|
|
18807
|
+
} catch (error) {
|
|
18808
|
+
if (signal?.aborted !== true) console.warn("dsh-arkme: record tag post-commit sync failed", safeFailureMessage$4(error));
|
|
18809
|
+
}
|
|
18810
|
+
}
|
|
18210
18811
|
async refreshSnapshot() {
|
|
18211
18812
|
await this.refreshLatest();
|
|
18212
18813
|
return await this.cachedSnapshot();
|
|
@@ -18356,6 +18957,7 @@ var RecordService = class {
|
|
|
18356
18957
|
3,
|
|
18357
18958
|
4
|
|
18358
18959
|
].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
|
|
18960
|
+
const hashTags = arkmeHashTagPayload(normalizedText);
|
|
18359
18961
|
const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
|
|
18360
18962
|
record_uid: normalizedUid,
|
|
18361
18963
|
template_kind: 2,
|
|
@@ -18366,6 +18968,7 @@ var RecordService = class {
|
|
|
18366
18968
|
payload_kind: 2,
|
|
18367
18969
|
schema_version: 1,
|
|
18368
18970
|
text_state: normalizedText === "" ? 3 : 1,
|
|
18971
|
+
...hashTags.length === 0 ? {} : { hash_tags: hashTags },
|
|
18369
18972
|
media_refs: assets.map((asset, index) => ({
|
|
18370
18973
|
file_asset_uid: asset.fileAssetUid,
|
|
18371
18974
|
content_file_role: 1,
|
|
@@ -18376,10 +18979,12 @@ var RecordService = class {
|
|
|
18376
18979
|
},
|
|
18377
18980
|
send_at: Date.now()
|
|
18378
18981
|
}, session);
|
|
18379
|
-
|
|
18982
|
+
const result = {
|
|
18380
18983
|
recordUid: stringValue$1(data.record_uid).trim() || normalizedUid,
|
|
18381
18984
|
status: numberValue$20(data.status)
|
|
18382
18985
|
};
|
|
18986
|
+
await this.syncCreatedRecordTags(result.recordUid, normalizedText, session.userId);
|
|
18987
|
+
return result;
|
|
18383
18988
|
}
|
|
18384
18989
|
async createExtensionForConversation(parentRecordUid, recordUid, textContent, assets = []) {
|
|
18385
18990
|
const session = await this.runtime.requireSession();
|
|
@@ -18394,6 +18999,7 @@ var RecordService = class {
|
|
|
18394
18999
|
3,
|
|
18395
19000
|
4
|
|
18396
19001
|
].includes(asset.fileKind)) throw new ArkmePluginError("record-file-asset-invalid", "附件资产参数无效", false);
|
|
19002
|
+
const hashTags = arkmeHashTagPayload(normalizedText);
|
|
18397
19003
|
const data = await this.runtime.authenticatedPost("/api/v1/records/extensions/create", {
|
|
18398
19004
|
parent_record_uid: normalizedParentUid,
|
|
18399
19005
|
record_uid: normalizedUid,
|
|
@@ -18404,6 +19010,7 @@ var RecordService = class {
|
|
|
18404
19010
|
payload_kind: assets.length === 0 ? 1 : 2,
|
|
18405
19011
|
schema_version: 1,
|
|
18406
19012
|
text_state: normalizedText === "" ? 3 : 1,
|
|
19013
|
+
...hashTags.length === 0 ? {} : { hash_tags: hashTags },
|
|
18407
19014
|
...assets.length === 0 ? {} : { media_refs: assets.map((asset, index) => ({
|
|
18408
19015
|
file_asset_uid: asset.fileAssetUid,
|
|
18409
19016
|
content_file_role: 1,
|
|
@@ -18421,6 +19028,7 @@ var RecordService = class {
|
|
|
18421
19028
|
const createdParentUid = stringValue$1(data.parent_record_uid).trim();
|
|
18422
19029
|
const edgeUid = stringValue$1(data.edge_uid).trim();
|
|
18423
19030
|
if (createdRecordUid !== normalizedUid || createdParentUid !== normalizedParentUid || edgeUid === "") throw new ArkmePluginError("record-extension-response-invalid", "延展写入结果无效,请刷新后重试", true, 502);
|
|
19031
|
+
await this.syncCreatedRecordTags(createdRecordUid, normalizedText, session.userId);
|
|
18424
19032
|
return {
|
|
18425
19033
|
recordUid: createdRecordUid,
|
|
18426
19034
|
status: numberValue$20(data.record_status ?? data.status),
|
|
@@ -18440,6 +19048,7 @@ var RecordService = class {
|
|
|
18440
19048
|
async sendPending(session, pending) {
|
|
18441
19049
|
try {
|
|
18442
19050
|
const captureContext = pending.captureContext === void 0 ? void 0 : arkmeRecordCaptureContextPayload(pending.captureContext);
|
|
19051
|
+
const hashTags = arkmeHashTagPayload(pending.textContent);
|
|
18443
19052
|
const data = await this.runtime.authenticatedPost("/api/v1/records/create", {
|
|
18444
19053
|
record_uid: pending.recordUid,
|
|
18445
19054
|
template_kind: 1,
|
|
@@ -18447,12 +19056,19 @@ var RecordService = class {
|
|
|
18447
19056
|
text_content: pending.textContent,
|
|
18448
19057
|
...Math.max(0, Math.trunc(pending.recordDurationMillis ?? 0)) === 0 ? {} : { record_duration_millis: Math.max(0, Math.trunc(pending.recordDurationMillis ?? 0)) },
|
|
18449
19058
|
...captureContext === void 0 || Object.keys(captureContext).length === 0 ? {} : { capture_context: captureContext },
|
|
19059
|
+
...hashTags.length === 0 ? {} : { content_payload: {
|
|
19060
|
+
payload_kind: 1,
|
|
19061
|
+
schema_version: 1,
|
|
19062
|
+
text_state: 1,
|
|
19063
|
+
hash_tags: hashTags
|
|
19064
|
+
} },
|
|
18450
19065
|
send_at: pending.sendAtMillis
|
|
18451
19066
|
}, session);
|
|
18452
19067
|
const result = {
|
|
18453
19068
|
recordUid: stringValue$1(data.record_uid) || pending.recordUid,
|
|
18454
19069
|
status: numberValue$20(data.status)
|
|
18455
19070
|
};
|
|
19071
|
+
await this.syncCreatedRecordTags(result.recordUid, pending.textContent, session.userId);
|
|
18456
19072
|
await this.runtime.stateStore.markSynced(session.userId, pending.recordUid, result.status);
|
|
18457
19073
|
return result;
|
|
18458
19074
|
} catch (error) {
|
|
@@ -18640,7 +19256,8 @@ function arkmeRichContentPayload(input, normalizedTextContent, mentionPayload) {
|
|
|
18640
19256
|
const assets = input.assets ?? [];
|
|
18641
19257
|
const backgroundSound = arkmeRichBackgroundSound(input.backgroundSound);
|
|
18642
19258
|
const mentionMetadata = mentionPayload?.mention_metadata;
|
|
18643
|
-
|
|
19259
|
+
const hashTags = arkmeHashTagPayload(normalizedTextContent);
|
|
19260
|
+
if (assets.length === 0 && backgroundSound === void 0 && mentionMetadata === void 0 && hashTags.length === 0) return void 0;
|
|
18644
19261
|
const mediaRefs = [...assets.map((asset, index) => ({
|
|
18645
19262
|
file_asset_uid: asset.fileAssetUid,
|
|
18646
19263
|
content_file_role: 1,
|
|
@@ -18661,7 +19278,8 @@ function arkmeRichContentPayload(input, normalizedTextContent, mentionPayload) {
|
|
|
18661
19278
|
text_state: normalizedTextContent === "" ? 3 : 1,
|
|
18662
19279
|
...mediaRefs.length === 0 ? {} : { media_refs: mediaRefs },
|
|
18663
19280
|
...backgroundSound === void 0 || backgroundSound.amplitudes.length === 0 ? {} : { background_sound_amplitudes: backgroundSound.amplitudes },
|
|
18664
|
-
...mentionMetadata === void 0 ? {} : { mention_metadata: mentionMetadata }
|
|
19281
|
+
...mentionMetadata === void 0 ? {} : { mention_metadata: mentionMetadata },
|
|
19282
|
+
...hashTags.length === 0 ? {} : { hash_tags: hashTags }
|
|
18665
19283
|
};
|
|
18666
19284
|
}
|
|
18667
19285
|
const OFFICIAL_AUTHOR_USER_ID = 11;
|
|
@@ -18669,6 +19287,8 @@ const OFFICIAL_AUTHOR_FALLBACK_DISPLAY_NAME = "即我作者";
|
|
|
18669
19287
|
const MAX_MESSAGE_COPY_LINK_ITEMS = 100;
|
|
18670
19288
|
const RECORD_UID_PATTERN$1 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
18671
19289
|
const CHAT_MEMBER_REF_PREFIX = "arkme-chat-member-v1";
|
|
19290
|
+
const MESSAGE_WITHDRAWAL_REF_PREFIX = "arkme-message-withdrawal-v1";
|
|
19291
|
+
const JOIN_RESTRICTION_CURSOR_PREFIX = "arkme-join-restriction-cursor-v1";
|
|
18672
19292
|
const CHAT_HUMAN_MENTION_REF_PREFIX = "arkme-chat-human-mention-v1";
|
|
18673
19293
|
function numberValue$19(value) {
|
|
18674
19294
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
@@ -19494,25 +20114,30 @@ function firstJoinDisplayName(source, keys) {
|
|
|
19494
20114
|
}
|
|
19495
20115
|
return "";
|
|
19496
20116
|
}
|
|
20117
|
+
function isUsableChatMemberName(value, userId) {
|
|
20118
|
+
return value !== "" && value !== "成员" && value !== "群成员" && value !== `用户 ${String(userId)}`;
|
|
20119
|
+
}
|
|
20120
|
+
function firstUsableChatMemberName(values, userId) {
|
|
20121
|
+
return values.map(normalizedJoinDisplayName).find((value) => isUsableChatMemberName(value, userId)) ?? "";
|
|
20122
|
+
}
|
|
19497
20123
|
function resolveChatMemberDisplayNames(input) {
|
|
19498
|
-
const
|
|
19499
|
-
const
|
|
19500
|
-
const
|
|
19501
|
-
const memberName = firstUsable(input.memberNameCandidates ?? []);
|
|
19502
|
-
const userName = firstUsable(input.userNameCandidates ?? []);
|
|
20124
|
+
const remarkName = firstUsableChatMemberName(input.remarkCandidates ?? [], input.userId);
|
|
20125
|
+
const memberName = firstUsableChatMemberName(input.memberNameCandidates ?? [], input.userId);
|
|
20126
|
+
const userName = firstUsableChatMemberName(input.userNameCandidates ?? [], input.userId);
|
|
19503
20127
|
const displayName = [
|
|
19504
20128
|
remarkName,
|
|
19505
20129
|
memberName,
|
|
19506
20130
|
userName
|
|
19507
|
-
].find(
|
|
20131
|
+
].find((value) => isUsableChatMemberName(value, input.userId)) ?? "群成员";
|
|
19508
20132
|
return {
|
|
19509
20133
|
displayName,
|
|
19510
20134
|
memberName,
|
|
20135
|
+
userName,
|
|
19511
20136
|
secondaryName: [
|
|
19512
20137
|
memberName,
|
|
19513
20138
|
userName,
|
|
19514
20139
|
remarkName
|
|
19515
|
-
].find((value) =>
|
|
20140
|
+
].find((value) => isUsableChatMemberName(value, input.userId) && value !== displayName) ?? ""
|
|
19516
20141
|
};
|
|
19517
20142
|
}
|
|
19518
20143
|
function projectChatMemberDisplayNames(item, userId, viewerLabel, publicDisplayName) {
|
|
@@ -19523,11 +20148,13 @@ function projectChatMemberDisplayNames(item, userId, viewerLabel, publicDisplayN
|
|
|
19523
20148
|
userNameCandidates: [item.display_name, publicDisplayName]
|
|
19524
20149
|
});
|
|
19525
20150
|
}
|
|
19526
|
-
function
|
|
19527
|
-
|
|
19528
|
-
|
|
19529
|
-
|
|
19530
|
-
|
|
20151
|
+
function projectChatMemberMentionDisplayNames(names, remarkCandidates, userId) {
|
|
20152
|
+
const mentionDisplayName = names.memberName || names.userName || "群成员";
|
|
20153
|
+
const remarkName = firstUsableChatMemberName(remarkCandidates, userId);
|
|
20154
|
+
return {
|
|
20155
|
+
mentionDisplayName,
|
|
20156
|
+
mentionSecondaryName: remarkName !== mentionDisplayName ? remarkName : ""
|
|
20157
|
+
};
|
|
19531
20158
|
}
|
|
19532
20159
|
function normalizedJoinTimestamp(value) {
|
|
19533
20160
|
const raw = integerLikeValue(value);
|
|
@@ -20347,6 +20974,127 @@ var ChatService = class {
|
|
|
20347
20974
|
status: numberValue$19(report.status)
|
|
20348
20975
|
};
|
|
20349
20976
|
}
|
|
20977
|
+
async withdrawGroupMessage(messageWithdrawalRef, options = {}) {
|
|
20978
|
+
const session = await this.runtime.requireSession();
|
|
20979
|
+
const normalizedMessageWithdrawalRef = messageWithdrawalRef.trim();
|
|
20980
|
+
const reference = await this.openMessageWithdrawalRef(normalizedMessageWithdrawalRef, session.userId);
|
|
20981
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/messages/withdraw", {
|
|
20982
|
+
chat_session_uid: reference.chatSessionUid,
|
|
20983
|
+
rel_uid: reference.relationUid
|
|
20984
|
+
}, session, options.signal);
|
|
20985
|
+
const withdrawnAtMillis = numberValue$19(data.withdrawn_at);
|
|
20986
|
+
if (stringValue$1(data.chat_session_uid).trim() !== reference.chatSessionUid || stringValue$1(data.rel_uid).trim() !== reference.relationUid || !Number.isSafeInteger(withdrawnAtMillis) || withdrawnAtMillis <= 0 || typeof data.already_withdrawn !== "boolean") throw new ArkmePluginError("message-withdraw-invalid-response", "撤回服务返回无效", true, 502);
|
|
20987
|
+
return {
|
|
20988
|
+
messageWithdrawalRef: normalizedMessageWithdrawalRef,
|
|
20989
|
+
timelineItemKey: await this.source.chatTimelineItemKey(session.userId, reference.chatSessionUid, reference.relationUid),
|
|
20990
|
+
withdrawnAtMillis,
|
|
20991
|
+
alreadyWithdrawn: data.already_withdrawn
|
|
20992
|
+
};
|
|
20993
|
+
}
|
|
20994
|
+
async removeGroupMember(sourceRef, memberRef, options = {}) {
|
|
20995
|
+
const session = await this.runtime.requireSession();
|
|
20996
|
+
const normalizedSourceRef = sourceRef.trim();
|
|
20997
|
+
const normalizedMemberRef = memberRef.trim();
|
|
20998
|
+
const source = await this.source.openSourceRef(normalizedSourceRef, session.userId);
|
|
20999
|
+
if (source.kind !== "group_chat") throw new ArkmePluginError("group-source-invalid", "仅支持移除群聊成员", false);
|
|
21000
|
+
const member = await this.openChatMemberRef(normalizedMemberRef, session.userId, source.ownerRef);
|
|
21001
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/members/update", {
|
|
21002
|
+
chat_session_uid: source.ownerRef,
|
|
21003
|
+
target_user_id: member.targetUserId,
|
|
21004
|
+
action: 2,
|
|
21005
|
+
prevent_rejoin: options.preventRejoin === true
|
|
21006
|
+
}, session, options.signal);
|
|
21007
|
+
const item = objectValue$1(data.item);
|
|
21008
|
+
if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef || !Number.isSafeInteger(numberValue$19(item.user_id)) || numberValue$19(item.user_id) !== member.targetUserId || !Number.isSafeInteger(numberValue$19(item.status)) || numberValue$19(item.status) !== 3 || typeof item.join_restricted !== "boolean" || options.preventRejoin === true && item.join_restricted !== true) throw new ArkmePluginError("group-member-remove-invalid-response", "移除成员服务返回无效", true, 502);
|
|
21009
|
+
return {
|
|
21010
|
+
sourceRef: normalizedSourceRef,
|
|
21011
|
+
memberRef: normalizedMemberRef,
|
|
21012
|
+
status: "removed",
|
|
21013
|
+
joinRestricted: item.join_restricted
|
|
21014
|
+
};
|
|
21015
|
+
}
|
|
21016
|
+
async listGroupJoinRestrictions(sourceRef, options = {}) {
|
|
21017
|
+
const session = await this.runtime.requireSession();
|
|
21018
|
+
const normalizedSourceRef = sourceRef.trim();
|
|
21019
|
+
const source = await this.source.openSourceRef(normalizedSourceRef, session.userId);
|
|
21020
|
+
if (source.kind !== "group_chat") throw new ArkmePluginError("group-source-invalid", "仅支持查看群聊限制名单", false);
|
|
21021
|
+
const cursor = options.cursor === void 0 ? void 0 : await this.openJoinRestrictionCursor(options.cursor, session.userId, source.ownerRef);
|
|
21022
|
+
const limit = Math.min(100, Math.max(1, Math.trunc(options.limit ?? 30)));
|
|
21023
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/governance/join-restriction/page", {
|
|
21024
|
+
chat_session_uid: source.ownerRef,
|
|
21025
|
+
limit,
|
|
21026
|
+
...cursor === void 0 ? {} : { cursor: {
|
|
21027
|
+
updated_at: cursor.updatedAt,
|
|
21028
|
+
user_id: cursor.targetUserId
|
|
21029
|
+
} }
|
|
21030
|
+
}, session, options.signal);
|
|
21031
|
+
if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef || !Array.isArray(data.items)) throw new ArkmePluginError("join-restrictions-invalid-response", "限制名单服务返回无效", true, 502);
|
|
21032
|
+
const rawItems = listValue$16(data.items).map(objectValue$1);
|
|
21033
|
+
for (const raw of rawItems) {
|
|
21034
|
+
const userId = numberValue$19(raw.user_id);
|
|
21035
|
+
const restrictedAtMillis = numberValue$19(objectValue$1(raw.restriction).updated_at);
|
|
21036
|
+
if (!Number.isSafeInteger(userId) || userId <= 0 || !Number.isSafeInteger(restrictedAtMillis) || restrictedAtMillis <= 0) throw new ArkmePluginError("join-restrictions-invalid-response", "限制名单服务返回无效", true, 502);
|
|
21037
|
+
}
|
|
21038
|
+
const projected = await this.projectChatMembers(source.ownerRef, rawItems, session, {
|
|
21039
|
+
includeViewerLabels: true,
|
|
21040
|
+
includeHumanMentionRefs: false,
|
|
21041
|
+
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
21042
|
+
});
|
|
21043
|
+
const projectedByRef = new Map(projected.map((item) => [item.memberRef, item]));
|
|
21044
|
+
const items = [];
|
|
21045
|
+
for (const raw of rawItems) {
|
|
21046
|
+
const userId = numberValue$19(raw.user_id);
|
|
21047
|
+
const memberRef = await this.sealChatMemberRef(session.userId, source.ownerRef, userId);
|
|
21048
|
+
const member = projectedByRef.get(memberRef);
|
|
21049
|
+
const restrictedAtMillis = numberValue$19(objectValue$1(raw.restriction).updated_at);
|
|
21050
|
+
if (member === void 0) throw new ArkmePluginError("join-restrictions-invalid-response", "限制名单服务返回无效", true, 502);
|
|
21051
|
+
items.push({
|
|
21052
|
+
memberRef,
|
|
21053
|
+
displayName: member.displayName,
|
|
21054
|
+
...member.memberName === void 0 ? {} : { memberName: member.memberName },
|
|
21055
|
+
...member.secondaryName === void 0 ? {} : { secondaryName: member.secondaryName },
|
|
21056
|
+
...member.avatarRef === void 0 ? {} : { avatarRef: member.avatarRef },
|
|
21057
|
+
restrictedAtMillis
|
|
21058
|
+
});
|
|
21059
|
+
}
|
|
21060
|
+
const hasNextCursor = data.next_cursor !== void 0 && data.next_cursor !== null;
|
|
21061
|
+
const rawNextCursor = objectValue$1(data.next_cursor);
|
|
21062
|
+
const nextUpdatedAt = numberValue$19(rawNextCursor.updated_at);
|
|
21063
|
+
const nextUserId = numberValue$19(rawNextCursor.user_id);
|
|
21064
|
+
if (hasNextCursor && (!Number.isSafeInteger(nextUpdatedAt) || nextUpdatedAt <= 0 || !Number.isSafeInteger(nextUserId) || nextUserId <= 0)) throw new ArkmePluginError("join-restrictions-invalid-response", "限制名单服务返回无效", true, 502);
|
|
21065
|
+
return {
|
|
21066
|
+
sourceRef: normalizedSourceRef,
|
|
21067
|
+
items,
|
|
21068
|
+
...!hasNextCursor ? {} : { nextCursor: await this.sealJoinRestrictionCursor({
|
|
21069
|
+
version: 1,
|
|
21070
|
+
userId: session.userId,
|
|
21071
|
+
chatSessionUid: source.ownerRef,
|
|
21072
|
+
updatedAt: nextUpdatedAt,
|
|
21073
|
+
targetUserId: nextUserId
|
|
21074
|
+
}) }
|
|
21075
|
+
};
|
|
21076
|
+
}
|
|
21077
|
+
async setGroupJoinRestriction(sourceRef, memberRef, restricted, options = {}) {
|
|
21078
|
+
const session = await this.runtime.requireSession();
|
|
21079
|
+
const normalizedSourceRef = sourceRef.trim();
|
|
21080
|
+
const normalizedMemberRef = memberRef.trim();
|
|
21081
|
+
const source = await this.source.openSourceRef(normalizedSourceRef, session.userId);
|
|
21082
|
+
if (source.kind !== "group_chat") throw new ArkmePluginError("group-source-invalid", "仅支持设置群聊加入限制", false);
|
|
21083
|
+
const member = await this.openChatMemberRef(normalizedMemberRef, session.userId, source.ownerRef);
|
|
21084
|
+
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/governance/join-restriction/set", {
|
|
21085
|
+
chat_session_uid: source.ownerRef,
|
|
21086
|
+
target_user_id: member.targetUserId,
|
|
21087
|
+
restricted
|
|
21088
|
+
}, session, options.signal);
|
|
21089
|
+
const updatedAtMillis = numberValue$19(data.updated_at);
|
|
21090
|
+
if (stringValue$1(data.chat_session_uid).trim() !== source.ownerRef || !Number.isSafeInteger(numberValue$19(data.user_id)) || numberValue$19(data.user_id) !== member.targetUserId || data.restricted !== restricted || !Number.isSafeInteger(updatedAtMillis) || (restricted ? updatedAtMillis <= 0 : updatedAtMillis !== 0)) throw new ArkmePluginError("join-restriction-invalid-response", "加入限制服务返回无效", true, 502);
|
|
21091
|
+
return {
|
|
21092
|
+
sourceRef: normalizedSourceRef,
|
|
21093
|
+
memberRef: normalizedMemberRef,
|
|
21094
|
+
restricted,
|
|
21095
|
+
...updatedAtMillis <= 0 ? {} : { updatedAtMillis }
|
|
21096
|
+
};
|
|
21097
|
+
}
|
|
20350
21098
|
async messageReadReceiptSummaries(sourceRef, rawItems, options = {}) {
|
|
20351
21099
|
const session = await this.runtime.requireSession();
|
|
20352
21100
|
const source = await this.requireReadReceiptChatSource(sourceRef, session.userId);
|
|
@@ -20673,11 +21421,13 @@ var ChatService = class {
|
|
|
20673
21421
|
const profile = (await this.profile.refreshProfile()).profile;
|
|
20674
21422
|
if (profile === null) throw new ArkmePluginError("profile-unavailable", "无法读取当前 Arkme 账号资料", true);
|
|
20675
21423
|
const sendAtMillis = Date.now();
|
|
20676
|
-
const
|
|
20677
|
-
|
|
21424
|
+
const hashTags = arkmeHashTagPayload(normalizedText);
|
|
21425
|
+
const contentPayload = assets.length === 0 && hashTags.length === 0 ? void 0 : {
|
|
21426
|
+
payload_kind: assets.length === 0 ? 1 : 2,
|
|
20678
21427
|
schema_version: 1,
|
|
20679
21428
|
text_state: normalizedText === "" ? 3 : 1,
|
|
20680
|
-
|
|
21429
|
+
...hashTags.length === 0 ? {} : { hash_tags: hashTags },
|
|
21430
|
+
...assets.length === 0 ? {} : { media_refs: assets.map((asset, index) => ({
|
|
20681
21431
|
file_asset_uid: asset.fileAssetUid,
|
|
20682
21432
|
content_file_role: 1,
|
|
20683
21433
|
render_role: 1,
|
|
@@ -20686,7 +21436,7 @@ var ChatService = class {
|
|
|
20686
21436
|
file_kind: asset.fileKind,
|
|
20687
21437
|
mime_type: asset.mimeType,
|
|
20688
21438
|
size: asset.size
|
|
20689
|
-
}))
|
|
21439
|
+
})) }
|
|
20690
21440
|
};
|
|
20691
21441
|
const data = await this.runtime.authenticatedChatPost("/api/v1/chats/extensions/children/create", {
|
|
20692
21442
|
chat_session_uid: reference.chatSessionUid,
|
|
@@ -20737,11 +21487,13 @@ var ChatService = class {
|
|
|
20737
21487
|
const profile = (await this.profile.refreshProfile()).profile;
|
|
20738
21488
|
if (profile === null) throw new ArkmePluginError("profile-unavailable", "无法读取当前 Arkme 账号资料", true);
|
|
20739
21489
|
const sendAtMillis = Date.now();
|
|
20740
|
-
const
|
|
20741
|
-
|
|
21490
|
+
const hashTags = arkmeHashTagPayload(normalizedText);
|
|
21491
|
+
const contentPayload = assets.length === 0 && hashTags.length === 0 ? void 0 : {
|
|
21492
|
+
payload_kind: assets.length === 0 ? 1 : 2,
|
|
20742
21493
|
schema_version: 1,
|
|
20743
21494
|
text_state: normalizedText === "" ? 3 : 1,
|
|
20744
|
-
|
|
21495
|
+
...hashTags.length === 0 ? {} : { hash_tags: hashTags },
|
|
21496
|
+
...assets.length === 0 ? {} : { media_refs: assets.map((asset, index) => ({
|
|
20745
21497
|
file_asset_uid: asset.fileAssetUid,
|
|
20746
21498
|
content_file_role: 1,
|
|
20747
21499
|
render_role: 1,
|
|
@@ -20750,7 +21502,7 @@ var ChatService = class {
|
|
|
20750
21502
|
file_kind: asset.fileKind,
|
|
20751
21503
|
mime_type: asset.mimeType,
|
|
20752
21504
|
size: asset.size
|
|
20753
|
-
}))
|
|
21505
|
+
})) }
|
|
20754
21506
|
};
|
|
20755
21507
|
const data = await this.runtime.authenticatedPost("/api/v1/topics/records/extensions/create", {
|
|
20756
21508
|
topic_uid: source.ownerRef,
|
|
@@ -20767,6 +21519,7 @@ var ChatService = class {
|
|
|
20767
21519
|
const createdTopicUid = stringValue$1(data.topic_uid).trim();
|
|
20768
21520
|
const edgeUid = stringValue$1(data.edge_uid).trim();
|
|
20769
21521
|
if (createdRecordUid !== normalizedUid || createdParentUid !== reference.recordUid || createdTopicUid !== source.ownerRef || edgeUid === "") throw new ArkmePluginError("record-extension-response-invalid", "主题延展写入结果无效,请刷新后重试", true, 502);
|
|
21522
|
+
await this.record.syncCreatedRecordTags?.(createdRecordUid, normalizedText, session.userId);
|
|
20770
21523
|
const relationUid = stringValue$1(data.rel_uid).trim();
|
|
20771
21524
|
this.source.invalidateSourceListCache(session.userId, "send_to_self");
|
|
20772
21525
|
this.realtime.emitChatClientEvent({
|
|
@@ -21109,6 +21862,7 @@ var ChatService = class {
|
|
|
21109
21862
|
const text = textContent.trim();
|
|
21110
21863
|
if (text === "" || text.length > this.runtime.config.maxTextLength) throw new ArkmePluginError("source-text-invalid", "发送内容为空或超过长度限制", false);
|
|
21111
21864
|
const recordUid = options.recordUid?.trim() || randomUUID();
|
|
21865
|
+
const hashTagContentPayload = arkmeHashTagContentPayload(text);
|
|
21112
21866
|
if (source.kind === "send_to_self" || source.kind === "default_category") {
|
|
21113
21867
|
const sendAtMillis = Date.now();
|
|
21114
21868
|
const result = await this.record.createTextForConversation(recordUid, text, {
|
|
@@ -21145,8 +21899,10 @@ var ChatService = class {
|
|
|
21145
21899
|
text_content: text,
|
|
21146
21900
|
...Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) === 0 ? {} : { record_duration_millis: Math.max(0, Math.trunc(options.recordDurationMillis ?? 0)) },
|
|
21147
21901
|
...captureContext === void 0 || Object.keys(captureContext).length === 0 ? {} : { capture_context: captureContext },
|
|
21902
|
+
...hashTagContentPayload === void 0 ? {} : { content_payload: hashTagContentPayload },
|
|
21148
21903
|
send_at: sendAtMillis
|
|
21149
21904
|
}, session);
|
|
21905
|
+
await this.record.syncCreatedRecordTags?.(stringValue$1(result.record_uid).trim() || recordUid, text, session.userId);
|
|
21150
21906
|
await this.realtime.invalidateRecordProjection();
|
|
21151
21907
|
return await this.withSentMessageActionRef({
|
|
21152
21908
|
sourceRef,
|
|
@@ -21185,6 +21941,7 @@ var ChatService = class {
|
|
|
21185
21941
|
agentAuthored,
|
|
21186
21942
|
...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
|
|
21187
21943
|
...options.captureContext === void 0 ? {} : { captureContext: options.captureContext },
|
|
21944
|
+
...hashTagContentPayload === void 0 ? {} : { contentPayload: hashTagContentPayload },
|
|
21188
21945
|
...options.signal === void 0 ? {} : { signal: options.signal }
|
|
21189
21946
|
});
|
|
21190
21947
|
} else if ((options.humanMentions?.length ?? 0) > 0) throw new ArkmePluginError("mention-group-required", "真人 mention 只能发送到群聊", false);
|
|
@@ -21196,7 +21953,7 @@ var ChatService = class {
|
|
|
21196
21953
|
...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
|
|
21197
21954
|
...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
|
|
21198
21955
|
});
|
|
21199
|
-
} else sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0,
|
|
21956
|
+
} else sent = await this.sendChatSourceTextRaw(sourceRef, source.ownerRef, text, recordUid, relationUid, session, void 0, hashTagContentPayload, options.signal, {
|
|
21200
21957
|
agentAuthored,
|
|
21201
21958
|
...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
|
|
21202
21959
|
...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
|
|
@@ -21237,6 +21994,7 @@ var ChatService = class {
|
|
|
21237
21994
|
payload_kind: 1,
|
|
21238
21995
|
schema_version: 1,
|
|
21239
21996
|
text_state: 1,
|
|
21997
|
+
...arkmeHashTagPayload(normalizedText).length === 0 ? {} : { hash_tags: arkmeHashTagPayload(normalizedText) },
|
|
21240
21998
|
mention_metadata: {
|
|
21241
21999
|
schema_version: 1,
|
|
21242
22000
|
source_checksum: createHash("sha256").update(JSON.stringify(checksumInput)).digest("hex"),
|
|
@@ -21376,6 +22134,7 @@ var ChatService = class {
|
|
|
21376
22134
|
payload_kind: 1,
|
|
21377
22135
|
schema_version: 1,
|
|
21378
22136
|
text_state: 1,
|
|
22137
|
+
...arkmeHashTagPayload(visibleText).length === 0 ? {} : { hash_tags: arkmeHashTagPayload(visibleText) },
|
|
21379
22138
|
mention_metadata: {
|
|
21380
22139
|
schema_version: 1,
|
|
21381
22140
|
source_checksum: createHash("sha256").update(JSON.stringify(checksumInput)).digest("hex"),
|
|
@@ -21479,6 +22238,7 @@ var ChatService = class {
|
|
|
21479
22238
|
};
|
|
21480
22239
|
if (source.kind === "send_to_self" || source.kind === "default_category") {
|
|
21481
22240
|
const result = await this.runtime.authenticatedPost("/api/v1/records/create", commonBody, session, options.signal, { trackWriteOutcome: true });
|
|
22241
|
+
await this.record.syncCreatedRecordTags?.(stringValue$1(result.record_uid).trim() || recordUid, textContent, session.userId);
|
|
21482
22242
|
await this.realtime.invalidateRecordProjection();
|
|
21483
22243
|
return await this.withSentMessageActionRef({
|
|
21484
22244
|
sourceRef,
|
|
@@ -21502,6 +22262,7 @@ var ChatService = class {
|
|
|
21502
22262
|
topic_uid: source.ownerRef,
|
|
21503
22263
|
...commonBody
|
|
21504
22264
|
}, session, options.signal, { trackWriteOutcome: true });
|
|
22265
|
+
await this.record.syncCreatedRecordTags?.(stringValue$1(result.record_uid).trim() || recordUid, textContent, session.userId);
|
|
21505
22266
|
await this.realtime.invalidateRecordProjection();
|
|
21506
22267
|
return await this.withSentMessageActionRef({
|
|
21507
22268
|
sourceRef,
|
|
@@ -21765,9 +22526,10 @@ var ChatService = class {
|
|
|
21765
22526
|
async chatSourceFromBundle(bundle, session, cached, timelineItems) {
|
|
21766
22527
|
return await this.source.chatSourceFromBundle(bundle, session, cached, timelineItems);
|
|
21767
22528
|
}
|
|
21768
|
-
async chatTimelineItems(data, session, chatSessionUid) {
|
|
22529
|
+
async chatTimelineItems(data, session, chatSessionUid, projectedSourceKind) {
|
|
21769
22530
|
const items = [];
|
|
21770
22531
|
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
22532
|
+
const sourceKind = projectedSourceKind;
|
|
21771
22533
|
for (const raw of listValue$16(data.items)) {
|
|
21772
22534
|
const item = objectValue$1(raw);
|
|
21773
22535
|
const relation = objectValue$1(item.relation);
|
|
@@ -21799,6 +22561,11 @@ var ChatService = class {
|
|
|
21799
22561
|
const mentionsViewer = senderUserId !== session.userId && arkmeMentionMetadataMentionsViewer(record, payload, session.userId);
|
|
21800
22562
|
items.push({
|
|
21801
22563
|
itemUid: uid,
|
|
22564
|
+
...relationUid === "" ? {} : { timelineItemKey: await this.source.chatTimelineItemKey(session.userId, chatSessionUid, relationUid) },
|
|
22565
|
+
...sourceKind !== "group_chat" || relationUid === "" || senderUserId === session.userId ? {} : {
|
|
22566
|
+
messageRef: this.sealMessageRef(session.userId, chatSessionUid, relationUid, signingKey),
|
|
22567
|
+
messageWithdrawalRef: this.sealMessageWithdrawalRef(session.userId, chatSessionUid, relationUid, signingKey)
|
|
22568
|
+
},
|
|
21802
22569
|
...relationUid === "" ? {} : { messageActionRef: this.sealMessageActionRef(this.messageActionRefPayload({
|
|
21803
22570
|
sourceKind: "chat_relation",
|
|
21804
22571
|
userId: session.userId,
|
|
@@ -22344,14 +23111,16 @@ var ChatService = class {
|
|
|
22344
23111
|
}
|
|
22345
23112
|
async projectChatMembers(chatSessionUid, rawItems, session, options) {
|
|
22346
23113
|
const userIds = rawItems.map((item) => Math.trunc(numberValue$19(item.user_id))).filter((userId) => Number.isSafeInteger(userId) && userId > 0);
|
|
22347
|
-
const [profiles, viewerLabels] = await Promise.all([this.profile.publicProfileSummariesByUserIds(userIds, session, options.signal).catch(() => /* @__PURE__ */ new Map()), options.includeViewerLabels ? this.source.
|
|
23114
|
+
const [profiles, viewerLabels] = await Promise.all([this.profile.publicProfileSummariesByUserIds(userIds, session, options.signal).catch(() => /* @__PURE__ */ new Map()), options.includeViewerLabels ? this.source.privateChatViewerLabelsByUserIds(userIds, { ...options.signal === void 0 ? {} : { signal: options.signal } }).catch(() => /* @__PURE__ */ new Map()) : Promise.resolve(/* @__PURE__ */ new Map())]);
|
|
22348
23115
|
const members = [];
|
|
22349
23116
|
for (const item of rawItems) {
|
|
22350
23117
|
const userId = Math.trunc(numberValue$19(item.user_id));
|
|
22351
23118
|
if (!Number.isSafeInteger(userId) || userId <= 0) continue;
|
|
22352
23119
|
const profile = profiles.get(userId);
|
|
22353
|
-
const
|
|
22354
|
-
const
|
|
23120
|
+
const viewerLabel = viewerLabels.get(userId);
|
|
23121
|
+
const names = projectChatMemberDisplayNames(item, userId, viewerLabel?.displayName, profile?.displayName);
|
|
23122
|
+
const { displayName, memberName, secondaryName } = names;
|
|
23123
|
+
const { mentionDisplayName, mentionSecondaryName } = projectChatMemberMentionDisplayNames(names, [viewerLabel?.remark, item.remark], userId);
|
|
22355
23124
|
const role = chatMemberRole$1(item.role);
|
|
22356
23125
|
const status = chatMemberStatus$1(item.status);
|
|
22357
23126
|
const extra = parsedObject(item.extra);
|
|
@@ -22359,7 +23128,8 @@ var ChatService = class {
|
|
|
22359
23128
|
memberRef: await this.sealChatMemberRef(session.userId, chatSessionUid, userId),
|
|
22360
23129
|
...options.includeHumanMentionRefs && status === "active" && userId !== session.userId ? {
|
|
22361
23130
|
mentionRef: await this.sealChatHumanMentionRef(session.userId, chatSessionUid, userId, mentionDisplayName),
|
|
22362
|
-
mentionDisplayName
|
|
23131
|
+
mentionDisplayName,
|
|
23132
|
+
...mentionSecondaryName === "" ? {} : { mentionSecondaryName }
|
|
22363
23133
|
} : {},
|
|
22364
23134
|
displayName,
|
|
22365
23135
|
...memberName === "" ? {} : { memberName },
|
|
@@ -22420,7 +23190,11 @@ var ChatService = class {
|
|
|
22420
23190
|
const editDurationMillis = positiveNumberValue$1(payload.edit_duration_millis, record.edit_duration_millis, payload.editDurationMillis, record.editDurationMillis, payload.incr_cost_mill_sec, record.incr_cost_mill_sec, payload.incrCostMillSec, record.incrCostMillSec);
|
|
22421
23191
|
const itemIndex = items.push({
|
|
22422
23192
|
itemUid: uid,
|
|
22423
|
-
...
|
|
23193
|
+
...relationUid === "" ? {} : { timelineItemKey: await this.source.chatTimelineItemKey(session.userId, source.ownerRef, relationUid) },
|
|
23194
|
+
...source.kind !== "group_chat" || relationUid === "" || senderUserId === session.userId ? {} : {
|
|
23195
|
+
messageRef: this.sealMessageRef(session.userId, source.ownerRef, relationUid, signingKey),
|
|
23196
|
+
messageWithdrawalRef: this.sealMessageWithdrawalRef(session.userId, source.ownerRef, relationUid, signingKey)
|
|
23197
|
+
},
|
|
22424
23198
|
...relationUid === "" ? {} : { messageActionRef: this.sealMessageActionRef(this.messageActionRefPayload({
|
|
22425
23199
|
sourceKind: "chat_relation",
|
|
22426
23200
|
userId: session.userId,
|
|
@@ -22811,6 +23585,57 @@ var ChatService = class {
|
|
|
22811
23585
|
});
|
|
22812
23586
|
return `arkme-message-v1.${payload}.${createHmac("sha256", signingKey).update(payload).digest("base64url")}`;
|
|
22813
23587
|
}
|
|
23588
|
+
sealMessageWithdrawalRef(userId, chatSessionUid, relationUid, signingKey) {
|
|
23589
|
+
const payload = encodeOpaqueJson$6({
|
|
23590
|
+
version: 1,
|
|
23591
|
+
userId,
|
|
23592
|
+
chatSessionUid,
|
|
23593
|
+
relationUid
|
|
23594
|
+
});
|
|
23595
|
+
const signature = createHmac("sha256", signingKey).update(payload).digest("base64url");
|
|
23596
|
+
return `${MESSAGE_WITHDRAWAL_REF_PREFIX}.${payload}.${signature}`;
|
|
23597
|
+
}
|
|
23598
|
+
async openMessageWithdrawalRef(messageWithdrawalRef, expectedUserId) {
|
|
23599
|
+
const parsed = await this.openSignedOpaquePayload(messageWithdrawalRef, MESSAGE_WITHDRAWAL_REF_PREFIX, "message-withdrawal-ref-invalid", "消息撤回引用无效,请刷新后重试");
|
|
23600
|
+
const result = {
|
|
23601
|
+
version: 1,
|
|
23602
|
+
userId: Math.trunc(numberValue$19(parsed.userId)),
|
|
23603
|
+
chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
|
|
23604
|
+
relationUid: stringValue$1(parsed.relationUid).trim()
|
|
23605
|
+
};
|
|
23606
|
+
if (parsed.version !== 1 || result.userId !== expectedUserId || result.chatSessionUid === "" || result.relationUid === "") throw new ArkmePluginError("message-withdrawal-ref-invalid", "消息撤回引用与当前账号不匹配", false, 403);
|
|
23607
|
+
return result;
|
|
23608
|
+
}
|
|
23609
|
+
async sealJoinRestrictionCursor(payload) {
|
|
23610
|
+
const encoded = encodeOpaqueJson$6(payload);
|
|
23611
|
+
const signature = createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(encoded).digest("base64url");
|
|
23612
|
+
return `${JOIN_RESTRICTION_CURSOR_PREFIX}.${encoded}.${signature}`;
|
|
23613
|
+
}
|
|
23614
|
+
async openJoinRestrictionCursor(cursor, expectedUserId, expectedChatSessionUid) {
|
|
23615
|
+
const parsed = await this.openSignedOpaquePayload(cursor, JOIN_RESTRICTION_CURSOR_PREFIX, "join-restriction-cursor-invalid", "限制名单游标无效,请重新打开");
|
|
23616
|
+
const result = {
|
|
23617
|
+
version: 1,
|
|
23618
|
+
userId: Math.trunc(numberValue$19(parsed.userId)),
|
|
23619
|
+
chatSessionUid: stringValue$1(parsed.chatSessionUid).trim(),
|
|
23620
|
+
updatedAt: Math.trunc(numberValue$19(parsed.updatedAt)),
|
|
23621
|
+
targetUserId: Math.trunc(numberValue$19(parsed.targetUserId))
|
|
23622
|
+
};
|
|
23623
|
+
if (parsed.version !== 1 || result.userId !== expectedUserId || result.chatSessionUid !== expectedChatSessionUid || result.updatedAt <= 0 || result.targetUserId <= 0) throw new ArkmePluginError("join-restriction-cursor-invalid", "限制名单游标与当前账号或群聊不匹配", false, 403);
|
|
23624
|
+
return result;
|
|
23625
|
+
}
|
|
23626
|
+
async openSignedOpaquePayload(reference, prefix, code, message) {
|
|
23627
|
+
const parts = reference.trim().split(".");
|
|
23628
|
+
if (parts.length !== 3 || parts[0] !== prefix) throw new ArkmePluginError(code, message, false);
|
|
23629
|
+
const encoded = parts[1] ?? "";
|
|
23630
|
+
const supplied = Buffer.from(parts[2] ?? "", "base64url");
|
|
23631
|
+
const expected = createHmac("sha256", await this.runtime.stateStore.uniqueCode()).update(encoded).digest();
|
|
23632
|
+
if (supplied.length !== expected.length || !timingSafeEqual(supplied, expected)) throw new ArkmePluginError(code, message, false);
|
|
23633
|
+
try {
|
|
23634
|
+
return objectValue$1(decodeOpaqueJson$5(encoded));
|
|
23635
|
+
} catch (error) {
|
|
23636
|
+
throw new ArkmePluginError(code, message, false, 400, { cause: error });
|
|
23637
|
+
}
|
|
23638
|
+
}
|
|
22814
23639
|
async openMessageRef(messageRef, expectedUserId) {
|
|
22815
23640
|
const parts = messageRef.trim().split(".");
|
|
22816
23641
|
if (parts.length !== 3 || parts[0] !== "arkme-message-v1") throw new ArkmePluginError("message-ref-invalid", "Arkme 消息引用无效", false);
|
|
@@ -22835,6 +23660,130 @@ var ChatService = class {
|
|
|
22835
23660
|
}
|
|
22836
23661
|
};
|
|
22837
23662
|
//#endregion
|
|
23663
|
+
//#region src/services/conversation-directory-visibility-service.ts
|
|
23664
|
+
const MAX_DIRECTORY_VISIBILITY_REFS = 1e3;
|
|
23665
|
+
/** Sidebar application service; raw source and Bot APIs remain unfiltered owner projections. */
|
|
23666
|
+
var ConversationDirectoryVisibilityService = class {
|
|
23667
|
+
preference;
|
|
23668
|
+
source;
|
|
23669
|
+
bot;
|
|
23670
|
+
invalidation;
|
|
23671
|
+
constructor(preference, source, bot, invalidation) {
|
|
23672
|
+
this.preference = preference;
|
|
23673
|
+
this.source = source;
|
|
23674
|
+
this.bot = bot;
|
|
23675
|
+
this.invalidation = invalidation;
|
|
23676
|
+
}
|
|
23677
|
+
async query(sourceRefs, botRefs, signal) {
|
|
23678
|
+
if (sourceRefs.length + botRefs.length > MAX_DIRECTORY_VISIBILITY_REFS) throw new ArkmePluginError("conversation-directory-visibility-too-large", "会话列表状态查询数量过多", false, 400);
|
|
23679
|
+
const handles = [...sourceRefs.map((entryRef) => ({
|
|
23680
|
+
entryKind: "source",
|
|
23681
|
+
entryRef
|
|
23682
|
+
})), ...botRefs.map((entryRef) => ({
|
|
23683
|
+
entryKind: "bot",
|
|
23684
|
+
entryRef
|
|
23685
|
+
}))];
|
|
23686
|
+
const resolved = await Promise.allSettled(handles.map(async (handle) => ({
|
|
23687
|
+
...handle,
|
|
23688
|
+
...handle.entryKind === "source" ? await this.source.chatConversationListPreferenceEntry(handle.entryRef, signal) : await this.bot.botConversationListPreferenceEntry(handle.entryRef)
|
|
23689
|
+
})));
|
|
23690
|
+
const fatal = resolved.find((result) => result.status === "rejected" && isFatalResolutionError(result.reason));
|
|
23691
|
+
if (fatal?.status === "rejected") throw fatal.reason;
|
|
23692
|
+
const entries = resolved.flatMap((result) => result.status === "fulfilled" ? [result.value] : []);
|
|
23693
|
+
if (entries.length === 0) return { items: handles.map((handle) => ({
|
|
23694
|
+
...handle,
|
|
23695
|
+
hidden: false
|
|
23696
|
+
})) };
|
|
23697
|
+
const ownerUserId = entries[0].ownerUserId;
|
|
23698
|
+
if (entries.some((entry) => entry.ownerUserId !== ownerUserId)) throw new ArkmePluginError("login-context-changed", "登录账号已切换,请重试当前操作", false, 409);
|
|
23699
|
+
const owner = await this.preference.query(entries.map((entry) => entry.ref), {
|
|
23700
|
+
ownerUserId,
|
|
23701
|
+
...signal === void 0 ? {} : { signal }
|
|
23702
|
+
});
|
|
23703
|
+
const snapshots = new Map(owner.map((item) => [conversationListPreferenceRefKey(item.ref), item]));
|
|
23704
|
+
const evidenceByOwnerRef = /* @__PURE__ */ new Map();
|
|
23705
|
+
for (const entry of entries) {
|
|
23706
|
+
const key = conversationListPreferenceRefKey(entry.ref);
|
|
23707
|
+
const current = evidenceByOwnerRef.get(key);
|
|
23708
|
+
evidenceByOwnerRef.set(key, {
|
|
23709
|
+
sequence: Math.max(current?.sequence ?? 0, entry.evidence.sequence),
|
|
23710
|
+
activityAtMillis: Math.max(current?.activityAtMillis ?? 0, entry.evidence.activityAtMillis)
|
|
23711
|
+
});
|
|
23712
|
+
}
|
|
23713
|
+
const staleSnapshots = [...evidenceByOwnerRef.entries()].flatMap(([key, evidence]) => {
|
|
23714
|
+
const snapshot = snapshots.get(key);
|
|
23715
|
+
const evidenceAvailable = evidence.sequence > 0 || evidence.activityAtMillis > 0;
|
|
23716
|
+
return snapshot?.visibilityState === 2 && evidenceAvailable && !conversationListPreferenceIsDismissed(snapshot, evidence) ? [snapshot] : [];
|
|
23717
|
+
});
|
|
23718
|
+
if (staleSnapshots.length > 0) this.preference.restoreIfUnchanged(staleSnapshots, { ownerUserId }).catch(() => void 0);
|
|
23719
|
+
return { items: resolved.map((result, index) => {
|
|
23720
|
+
if (result.status === "rejected") return {
|
|
23721
|
+
...handles[index],
|
|
23722
|
+
hidden: false
|
|
23723
|
+
};
|
|
23724
|
+
const entry = result.value;
|
|
23725
|
+
const key = conversationListPreferenceRefKey(entry.ref);
|
|
23726
|
+
const snapshot = snapshots.get(key);
|
|
23727
|
+
const evidence = evidenceByOwnerRef.get(key) ?? entry.evidence;
|
|
23728
|
+
const hidden = (evidence.sequence > 0 || evidence.activityAtMillis > 0) && snapshot !== void 0 && conversationListPreferenceIsDismissed(snapshot, evidence);
|
|
23729
|
+
return {
|
|
23730
|
+
entryKind: entry.entryKind,
|
|
23731
|
+
entryRef: entry.entryRef,
|
|
23732
|
+
hidden
|
|
23733
|
+
};
|
|
23734
|
+
}) };
|
|
23735
|
+
}
|
|
23736
|
+
async setVisibility(entryKind, entryRef, hidden, signal) {
|
|
23737
|
+
const entry = await this.resolveEntry(entryKind, entryRef, signal);
|
|
23738
|
+
const operation = {
|
|
23739
|
+
ownerUserId: entry.ownerUserId,
|
|
23740
|
+
...signal === void 0 ? {} : { signal }
|
|
23741
|
+
};
|
|
23742
|
+
if (hidden) await this.preference.dismiss(entry.ref, entry.evidence, operation);
|
|
23743
|
+
else await this.preference.restore([entry.ref], operation);
|
|
23744
|
+
await this.invalidateBestEffort();
|
|
23745
|
+
}
|
|
23746
|
+
async restoreSource(source, signal) {
|
|
23747
|
+
const entry = await this.source.chatConversationListPreferenceEntry(source.sourceRef, signal);
|
|
23748
|
+
await this.restoreEntries([entry], signal);
|
|
23749
|
+
}
|
|
23750
|
+
async openBotContactConversation(botRef, options = {}) {
|
|
23751
|
+
const previous = await this.bot.botConversationListPreferenceEntry(botRef).catch(() => void 0);
|
|
23752
|
+
const source = await this.bot.openBotChat(botRef, options);
|
|
23753
|
+
(previous === void 0 ? this.restoreSource(source) : this.restoreBotConversation(previous, source)).catch(() => void 0);
|
|
23754
|
+
return source;
|
|
23755
|
+
}
|
|
23756
|
+
/** Restores the exact owner identities when a Bot directory entry resolves from direct Bot to Chat. */
|
|
23757
|
+
async restoreBotConversation(previous, source, signal) {
|
|
23758
|
+
const current = await this.source.chatConversationListPreferenceEntry(source.sourceRef, signal);
|
|
23759
|
+
if (previous.ownerUserId !== current.ownerUserId) throw new ArkmePluginError("login-context-changed", "登录账号已切换,请重试当前操作", false, 409);
|
|
23760
|
+
const previousIsCurrentChat = previous.ref.entityKind === 1 && previous.ref.entityUid === current.ref.entityUid;
|
|
23761
|
+
if (current.ref.entityKind !== 1 || previous.ref.entityKind !== 2 && !previousIsCurrentChat) throw new ArkmePluginError("bot-conversation-preference-identity-changed", "Bot 会话归属已变化,请刷新后重试", false, 409);
|
|
23762
|
+
await this.restoreEntries([previous, current], signal);
|
|
23763
|
+
}
|
|
23764
|
+
async restoreEntries(entries, signal) {
|
|
23765
|
+
const ownerUserId = entries[0]?.ownerUserId;
|
|
23766
|
+
if (ownerUserId === void 0 || entries.some((entry) => entry.ownerUserId !== ownerUserId)) throw new ArkmePluginError("login-context-changed", "登录账号已切换,请重试当前操作", false, 409);
|
|
23767
|
+
await this.preference.restore(entries.map((entry) => entry.ref), {
|
|
23768
|
+
ownerUserId,
|
|
23769
|
+
...signal === void 0 ? {} : { signal }
|
|
23770
|
+
});
|
|
23771
|
+
await this.invalidateBestEffort();
|
|
23772
|
+
}
|
|
23773
|
+
async resolveEntry(entryKind, entryRef, signal) {
|
|
23774
|
+
return entryKind === "source" ? await this.source.chatConversationListPreferenceEntry(entryRef, signal) : await this.bot.botConversationListPreferenceEntry(entryRef);
|
|
23775
|
+
}
|
|
23776
|
+
async invalidateBestEffort() {
|
|
23777
|
+
try {
|
|
23778
|
+
await this.invalidation.invalidateConversationListPreferenceForCurrentSession();
|
|
23779
|
+
} catch {}
|
|
23780
|
+
}
|
|
23781
|
+
};
|
|
23782
|
+
function isFatalResolutionError(error) {
|
|
23783
|
+
if (error instanceof Error && error.name === "AbortError") return true;
|
|
23784
|
+
return error !== null && typeof error === "object" && "code" in error && error.code === "login-context-changed";
|
|
23785
|
+
}
|
|
23786
|
+
//#endregion
|
|
22838
23787
|
//#region src/services/contact-service.ts
|
|
22839
23788
|
const CONTACT_REF_TTL_MS = 10 * 6e4;
|
|
22840
23789
|
const MAX_CONTACT_REFS = 512;
|
|
@@ -52639,9 +53588,9 @@ var GroupAiPolishService = class {
|
|
|
52639
53588
|
try {
|
|
52640
53589
|
config = await this.queryGroupAiPolishConfig(chatSessionUid, session, options.signal);
|
|
52641
53590
|
} catch {
|
|
52642
|
-
return await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0,
|
|
53591
|
+
return await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0, options.contentPayload, options.signal, options);
|
|
52643
53592
|
}
|
|
52644
|
-
if (!config.enabled || config.activeRuleUid === "") return await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0,
|
|
53593
|
+
if (!config.enabled || config.activeRuleUid === "") return await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0, options.contentPayload, options.signal, options);
|
|
52645
53594
|
const taskUid = randomUUID();
|
|
52646
53595
|
let polished;
|
|
52647
53596
|
try {
|
|
@@ -52657,7 +53606,7 @@ var GroupAiPolishService = class {
|
|
|
52657
53606
|
}, session, options.signal);
|
|
52658
53607
|
polished = this.aiPolishTextResult(data);
|
|
52659
53608
|
} catch (error) {
|
|
52660
|
-
const sent = await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0,
|
|
53609
|
+
const sent = await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0, options.contentPayload, options.signal, options);
|
|
52661
53610
|
return this.withFailedAiPolishRetry(sent, sourceRef, chatSessionUid, relationUid, recordUid, originalText, 1, session.userId, safeFailureMessage$2(error));
|
|
52662
53611
|
}
|
|
52663
53612
|
if (polished.state === 1 && polished.action === 1 && polished.polishedText !== "") {
|
|
@@ -52673,7 +53622,7 @@ var GroupAiPolishService = class {
|
|
|
52673
53622
|
model: polished.modelVersion,
|
|
52674
53623
|
prompt: polished.promptVersion,
|
|
52675
53624
|
...Object.keys(polished.extra).length === 0 ? {} : { extra: polished.extra }
|
|
52676
|
-
},
|
|
53625
|
+
}, options.contentPayload, options.signal, options),
|
|
52677
53626
|
aiPolish: {
|
|
52678
53627
|
state: "polished",
|
|
52679
53628
|
originalText,
|
|
@@ -52681,7 +53630,7 @@ var GroupAiPolishService = class {
|
|
|
52681
53630
|
}
|
|
52682
53631
|
};
|
|
52683
53632
|
}
|
|
52684
|
-
const sent = await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0,
|
|
53633
|
+
const sent = await this.chat.sendChatSourceTextRaw(sourceRef, chatSessionUid, originalText, recordUid, relationUid, session, void 0, options.contentPayload, options.signal, options);
|
|
52685
53634
|
if (polished.action === 2) return {
|
|
52686
53635
|
...sent,
|
|
52687
53636
|
aiPolish: {
|
|
@@ -53650,6 +54599,79 @@ var InterwovenService = class {
|
|
|
53650
54599
|
}
|
|
53651
54600
|
};
|
|
53652
54601
|
//#endregion
|
|
54602
|
+
//#region src/link-metadata.ts
|
|
54603
|
+
function arkmeIsGenericLinkMetadataTitle(rawTitle) {
|
|
54604
|
+
const title = rawTitle?.trim() ?? "";
|
|
54605
|
+
if (title === "") return true;
|
|
54606
|
+
if (title === "分享链接") return true;
|
|
54607
|
+
if (title === "即我" || title === "即我-对话发现自我" || title === "即我 - 对话发现自我") return true;
|
|
54608
|
+
if (title === "即我-进入Ta的世界" || title === "即我 - 进入Ta的世界") return true;
|
|
54609
|
+
if (title.toLowerCase().includes("this page could not be found")) return true;
|
|
54610
|
+
return /^404\b/u.test(title);
|
|
54611
|
+
}
|
|
54612
|
+
function linkUrl(rawUrl) {
|
|
54613
|
+
return rawUrl instanceof URL ? new URL(rawUrl.href) : new URL(rawUrl);
|
|
54614
|
+
}
|
|
54615
|
+
function arkmeExtensionShareRefFromLink(rawUrl) {
|
|
54616
|
+
let url;
|
|
54617
|
+
try {
|
|
54618
|
+
url = linkUrl(rawUrl);
|
|
54619
|
+
} catch {
|
|
54620
|
+
return;
|
|
54621
|
+
}
|
|
54622
|
+
if (url.protocol !== "https:" || url.username !== "" || url.password !== "") return void 0;
|
|
54623
|
+
const host = url.hostname.replace(/^www\./iu, "").toLowerCase();
|
|
54624
|
+
if (![
|
|
54625
|
+
"jiwo.cc",
|
|
54626
|
+
"app.arkme.ai",
|
|
54627
|
+
"app-test.arkme.ai",
|
|
54628
|
+
"jotmo-app.senguo.me"
|
|
54629
|
+
].includes(host)) return void 0;
|
|
54630
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
54631
|
+
const shareRef = parts.length === 4 && parts[0] === "app" && parts[1] === "share" && parts[2] === "extension" ? parts[3] : void 0;
|
|
54632
|
+
return shareRef !== void 0 && /^extshare_[0-9a-f]{32}$/u.test(shareRef) ? shareRef : void 0;
|
|
54633
|
+
}
|
|
54634
|
+
function arkmeKnownLinkMetadataFallback(rawUrl) {
|
|
54635
|
+
try {
|
|
54636
|
+
const url = linkUrl(rawUrl);
|
|
54637
|
+
const host = url.hostname.replace(/^www\./iu, "").toLowerCase();
|
|
54638
|
+
const parts = url.pathname.split("/").filter(Boolean);
|
|
54639
|
+
if (host === "github.com") {
|
|
54640
|
+
if (parts.length >= 4 && parts[2] === "pull") return {
|
|
54641
|
+
url: url.href,
|
|
54642
|
+
title: `Pull Request #${parts[3]} · ${parts[0]}/${parts[1]}`
|
|
54643
|
+
};
|
|
54644
|
+
if (parts.length >= 2) return {
|
|
54645
|
+
url: url.href,
|
|
54646
|
+
title: `${parts[0]}/${parts[1]}`
|
|
54647
|
+
};
|
|
54648
|
+
}
|
|
54649
|
+
if ((host === "codeup.aliyun.com" || host.endsWith(".codeup.aliyun.com")) && parts.includes("change")) {
|
|
54650
|
+
const changeIndex = parts.indexOf("change");
|
|
54651
|
+
const repository = changeIndex >= 2 ? parts[changeIndex - 1] : void 0;
|
|
54652
|
+
const changeNo = parts[changeIndex + 1];
|
|
54653
|
+
if (repository !== void 0 && changeNo !== void 0) return {
|
|
54654
|
+
url: url.href,
|
|
54655
|
+
title: `${repository} · Change #${changeNo}`
|
|
54656
|
+
};
|
|
54657
|
+
}
|
|
54658
|
+
} catch {}
|
|
54659
|
+
return null;
|
|
54660
|
+
}
|
|
54661
|
+
function arkmeRequiredLinkMetadataFallback(rawUrl) {
|
|
54662
|
+
const url = linkUrl(rawUrl);
|
|
54663
|
+
const siteName = url.hostname.replace(/^www\./iu, "");
|
|
54664
|
+
const known = arkmeKnownLinkMetadataFallback(url);
|
|
54665
|
+
return known === null ? {
|
|
54666
|
+
url: url.href,
|
|
54667
|
+
title: "分享链接",
|
|
54668
|
+
siteName
|
|
54669
|
+
} : {
|
|
54670
|
+
...known,
|
|
54671
|
+
siteName
|
|
54672
|
+
};
|
|
54673
|
+
}
|
|
54674
|
+
//#endregion
|
|
53653
54675
|
//#region src/services/link-metadata-service.ts
|
|
53654
54676
|
const MAX_LINK_METADATA_BYTES = 2 * 1024 * 1024;
|
|
53655
54677
|
const LINK_METADATA_TIMEOUT_MS = 8e3;
|
|
@@ -53658,8 +54680,10 @@ const MAX_LINK_METADATA_REDIRECTS = 3;
|
|
|
53658
54680
|
const MAX_LINK_TITLE_LENGTH = 300;
|
|
53659
54681
|
const MAX_LINK_URL_LENGTH = 4096;
|
|
53660
54682
|
const blockedAddresses = new BlockList();
|
|
54683
|
+
const proxySyntheticAddresses = new BlockList();
|
|
53661
54684
|
const globalIpv6Addresses = new BlockList();
|
|
53662
54685
|
globalIpv6Addresses.addSubnet("2000::", 3, "ipv6");
|
|
54686
|
+
proxySyntheticAddresses.addSubnet("198.18.0.0", 15, "ipv4");
|
|
53663
54687
|
for (const [network, prefix] of [
|
|
53664
54688
|
["0.0.0.0", 8],
|
|
53665
54689
|
["10.0.0.0", 8],
|
|
@@ -53697,6 +54721,14 @@ function isPublicNetworkAddress(address) {
|
|
|
53697
54721
|
if (family === 6) return globalIpv6Addresses.check(address, "ipv6") && !blockedAddresses.check(address, "ipv6");
|
|
53698
54722
|
return false;
|
|
53699
54723
|
}
|
|
54724
|
+
function isProxySyntheticNetworkAddress(address) {
|
|
54725
|
+
const mapped = ipv4FromMappedIpv6(address);
|
|
54726
|
+
if (mapped !== void 0) return isIP(mapped) === 4 && proxySyntheticAddresses.check(mapped, "ipv4");
|
|
54727
|
+
return isIP(address) === 4 && proxySyntheticAddresses.check(address, "ipv4");
|
|
54728
|
+
}
|
|
54729
|
+
function isAllowedLinkMetadataAddress(address) {
|
|
54730
|
+
return isPublicNetworkAddress(address) || isProxySyntheticNetworkAddress(address);
|
|
54731
|
+
}
|
|
53700
54732
|
function safeWebUrl(raw) {
|
|
53701
54733
|
let url;
|
|
53702
54734
|
try {
|
|
@@ -53737,6 +54769,10 @@ function tagAttributes(tag) {
|
|
|
53737
54769
|
}
|
|
53738
54770
|
return attributes;
|
|
53739
54771
|
}
|
|
54772
|
+
function preferredDocumentTitle(candidates) {
|
|
54773
|
+
for (const candidate of candidates) if (candidate !== void 0 && !arkmeIsGenericLinkMetadataTitle(candidate)) return candidate;
|
|
54774
|
+
return "";
|
|
54775
|
+
}
|
|
53740
54776
|
function documentMetadata(url, html) {
|
|
53741
54777
|
const metadata = /* @__PURE__ */ new Map();
|
|
53742
54778
|
for (const match of html.matchAll(/<meta\b[^>]*>/giu)) {
|
|
@@ -53747,7 +54783,11 @@ function documentMetadata(url, html) {
|
|
|
53747
54783
|
if (content !== "") metadata.set(property, content);
|
|
53748
54784
|
}
|
|
53749
54785
|
const documentTitle = /<title\b[^>]*>([\s\S]*?)<\/title\s*>/iu.exec(html)?.[1];
|
|
53750
|
-
const title =
|
|
54786
|
+
const title = preferredDocumentTitle([
|
|
54787
|
+
metadata.get("og:title"),
|
|
54788
|
+
metadata.get("twitter:title"),
|
|
54789
|
+
documentTitle === void 0 ? void 0 : normalizedTitle(documentTitle)
|
|
54790
|
+
]);
|
|
53751
54791
|
if (title === "") return null;
|
|
53752
54792
|
const description = metadata.get("og:description") ?? metadata.get("description");
|
|
53753
54793
|
const siteName = metadata.get("og:site_name") ?? url.hostname.replace(/^www\./iu, "");
|
|
@@ -53774,8 +54814,13 @@ function missingDnsAnswer(error) {
|
|
|
53774
54814
|
}
|
|
53775
54815
|
var NodeArkmeHostAddressResolver = class {
|
|
53776
54816
|
resolverFactory;
|
|
53777
|
-
|
|
54817
|
+
systemLookup;
|
|
54818
|
+
constructor(resolverFactory = () => new Resolver(), systemLookup = async (hostname) => await lookup(hostname, {
|
|
54819
|
+
all: true,
|
|
54820
|
+
verbatim: true
|
|
54821
|
+
})) {
|
|
53778
54822
|
this.resolverFactory = resolverFactory;
|
|
54823
|
+
this.systemLookup = systemLookup;
|
|
53779
54824
|
}
|
|
53780
54825
|
async lookup(hostname, options = {}) {
|
|
53781
54826
|
options.signal?.throwIfAborted();
|
|
@@ -53802,7 +54847,13 @@ var NodeArkmeHostAddressResolver = class {
|
|
|
53802
54847
|
}))];
|
|
53803
54848
|
} catch (error) {
|
|
53804
54849
|
options.signal?.throwIfAborted();
|
|
53805
|
-
|
|
54850
|
+
try {
|
|
54851
|
+
const addresses = await this.systemLookup(hostname);
|
|
54852
|
+
options.signal?.throwIfAborted();
|
|
54853
|
+
return addresses;
|
|
54854
|
+
} catch {
|
|
54855
|
+
throw error;
|
|
54856
|
+
}
|
|
53806
54857
|
} finally {
|
|
53807
54858
|
options.signal?.removeEventListener("abort", abort);
|
|
53808
54859
|
}
|
|
@@ -53913,7 +54964,7 @@ var NodeArkmeLinkDocumentReader = class {
|
|
|
53913
54964
|
} catch (error) {
|
|
53914
54965
|
throw pluginError(error);
|
|
53915
54966
|
}
|
|
53916
|
-
if (addresses.length === 0 || addresses.some((item) => !
|
|
54967
|
+
if (addresses.length === 0 || addresses.some((item) => !isAllowedLinkMetadataAddress(item.address))) throw new ArkmePluginError("link-metadata-url-unsafe", "该网址不允许解析标题", false, 400);
|
|
53917
54968
|
return await this.transport.read(url, addresses, options);
|
|
53918
54969
|
}
|
|
53919
54970
|
};
|
|
@@ -56513,9 +57564,6 @@ var RecordingImportCoordinator = class {
|
|
|
56513
57564
|
job = await this.transition(job, "accepted", {
|
|
56514
57565
|
sourceHandle: "",
|
|
56515
57566
|
sha256: "",
|
|
56516
|
-
sessionId: void 0,
|
|
56517
|
-
childId: void 0,
|
|
56518
|
-
childFinished: void 0,
|
|
56519
57567
|
uploadCheckpoint: void 0
|
|
56520
57568
|
});
|
|
56521
57569
|
await this.source.discard(sourceHandle).catch(() => void 0);
|
|
@@ -57138,8 +58186,78 @@ function safeFailureMessage$1(error) {
|
|
|
57138
58186
|
if (error instanceof Error && error.message.trim() !== "") return error.message;
|
|
57139
58187
|
return "未知错误";
|
|
57140
58188
|
}
|
|
58189
|
+
function recordingImportErrorCode(error) {
|
|
58190
|
+
if (error === null || typeof error !== "object" || !("code" in error)) return void 0;
|
|
58191
|
+
return typeof error.code === "string" ? error.code : void 0;
|
|
58192
|
+
}
|
|
57141
58193
|
const RECORDING_IMPORT_VISIBLE_LIMIT = 20;
|
|
57142
58194
|
const RECORDING_IMPORT_UNRESOLVED_LIMIT = 20;
|
|
58195
|
+
const RECORDING_IMPORT_HISTORY_MAX_PAGE_SIZE = 50;
|
|
58196
|
+
const RECORDING_IMPORT_SESSION_REF_PREFIX = "arkme-recording-import-session-v1";
|
|
58197
|
+
function recordingImportOwnerStatus(task) {
|
|
58198
|
+
const owner = task.session;
|
|
58199
|
+
const ownerProgress = task.progress;
|
|
58200
|
+
if (!owner.hasFinishedUpload) return {
|
|
58201
|
+
status: "uploading",
|
|
58202
|
+
statusDetail: "上传中"
|
|
58203
|
+
};
|
|
58204
|
+
if (task.processingCompleted) {
|
|
58205
|
+
if (ownerProgress?.displayStatus === "partial") return {
|
|
58206
|
+
status: "partial",
|
|
58207
|
+
statusDetail: "部分完成"
|
|
58208
|
+
};
|
|
58209
|
+
if (ownerProgress?.displayStatus === "failed") return {
|
|
58210
|
+
status: "failed",
|
|
58211
|
+
statusDetail: "处理失败"
|
|
58212
|
+
};
|
|
58213
|
+
if (ownerProgress?.displayStatus === "completed") return {
|
|
58214
|
+
status: "completed",
|
|
58215
|
+
statusDetail: "导入完成"
|
|
58216
|
+
};
|
|
58217
|
+
return {
|
|
58218
|
+
status: "completed",
|
|
58219
|
+
statusDetail: "已完成"
|
|
58220
|
+
};
|
|
58221
|
+
}
|
|
58222
|
+
if ([
|
|
58223
|
+
"completed",
|
|
58224
|
+
"partial",
|
|
58225
|
+
"failed"
|
|
58226
|
+
].includes(ownerProgress?.displayStatus ?? "")) return {
|
|
58227
|
+
status: "processing",
|
|
58228
|
+
statusDetail: "处理中"
|
|
58229
|
+
};
|
|
58230
|
+
switch (ownerProgress?.displayStatus) {
|
|
58231
|
+
case "speaker-waiting": return {
|
|
58232
|
+
status: "speaker-waiting",
|
|
58233
|
+
statusDetail: "等待识别说话人"
|
|
58234
|
+
};
|
|
58235
|
+
case "speaker-recognizing": return {
|
|
58236
|
+
status: "speaker-recognizing",
|
|
58237
|
+
statusDetail: "说话人识别中"
|
|
58238
|
+
};
|
|
58239
|
+
case "transcript-waiting": return {
|
|
58240
|
+
status: "transcript-waiting",
|
|
58241
|
+
statusDetail: "等待转写"
|
|
58242
|
+
};
|
|
58243
|
+
case "transcribing": return {
|
|
58244
|
+
status: "transcribing",
|
|
58245
|
+
statusDetail: "转写中"
|
|
58246
|
+
};
|
|
58247
|
+
case "unavailable": return {
|
|
58248
|
+
status: "unavailable",
|
|
58249
|
+
statusDetail: "状态不可用"
|
|
58250
|
+
};
|
|
58251
|
+
default: return {
|
|
58252
|
+
status: "waiting",
|
|
58253
|
+
statusDetail: "等待中"
|
|
58254
|
+
};
|
|
58255
|
+
}
|
|
58256
|
+
}
|
|
58257
|
+
function recordingImportProcessingDuration(timing) {
|
|
58258
|
+
if (timing === void 0 || timing.timingState === "unavailable") return void 0;
|
|
58259
|
+
return Math.max(0, timing.totalDurationMillis);
|
|
58260
|
+
}
|
|
57143
58261
|
var RecordingService = class {
|
|
57144
58262
|
runtime;
|
|
57145
58263
|
recordingImports;
|
|
@@ -57148,12 +58266,14 @@ var RecordingService = class {
|
|
|
57148
58266
|
media;
|
|
57149
58267
|
userCandidates;
|
|
57150
58268
|
recordingImportSource;
|
|
58269
|
+
recordingImportOwnerGateway;
|
|
57151
58270
|
constructor(runtime, dependencies) {
|
|
57152
58271
|
this.runtime = runtime;
|
|
57153
58272
|
this.profile = dependencies.profile;
|
|
57154
58273
|
this.media = dependencies.media;
|
|
57155
58274
|
this.userCandidates = dependencies.userCandidates;
|
|
57156
58275
|
this.recordingImportSource = dependencies.recordingImportSource;
|
|
58276
|
+
this.recordingImportOwnerGateway = dependencies.recordingImportOwnerGateway;
|
|
57157
58277
|
this.recordingImports = new RecordingImportCoordinator(runtime.stateStore, dependencies.recordingImportGateway, dependencies.recordingImportSource, async () => (await runtime.requireSession()).userId);
|
|
57158
58278
|
}
|
|
57159
58279
|
dispose() {
|
|
@@ -57332,11 +58452,26 @@ var RecordingService = class {
|
|
|
57332
58452
|
}
|
|
57333
58453
|
async recordingImportPreflight(fileNames, signal) {
|
|
57334
58454
|
this.assertWorkbenchEnabled();
|
|
57335
|
-
const
|
|
57336
|
-
|
|
57337
|
-
|
|
57338
|
-
|
|
57339
|
-
|
|
58455
|
+
const candidatesByKey = /* @__PURE__ */ new Map();
|
|
58456
|
+
for (const value of fileNames) {
|
|
58457
|
+
const candidate = value.trim();
|
|
58458
|
+
const key = recordingImportFileNameKey(candidate);
|
|
58459
|
+
if (key !== "" && !candidatesByKey.has(key)) candidatesByKey.set(key, candidate);
|
|
58460
|
+
}
|
|
58461
|
+
const candidates = [...candidatesByKey.values()];
|
|
58462
|
+
if (candidates.length === 0 || candidates.some((value) => value.length > 255)) throw new ArkmePluginError("recording-import-preflight-invalid", "待检查录音文件名无效", false);
|
|
58463
|
+
const session = await this.runtime.requireSession();
|
|
58464
|
+
const unresolvedLocalFileNameKeys = new Set((await this.runtime.stateStore.listRecordingImportJobs(session.userId)).filter((job) => !["accepted", "cancelled"].includes(job.phase)).map((job) => recordingImportFileNameKey(job.fileName)));
|
|
58465
|
+
const audioOwnerFileNameKeys = /* @__PURE__ */ new Set();
|
|
58466
|
+
for (const value of await this.recordingImportOwnerGateway.findExistingFileNames({
|
|
58467
|
+
viewerUserId: session.userId,
|
|
58468
|
+
fileNames: candidates,
|
|
58469
|
+
...signal === void 0 ? {} : { signal }
|
|
58470
|
+
})) {
|
|
58471
|
+
const key = recordingImportFileNameKey(value);
|
|
58472
|
+
if (key !== "") audioOwnerFileNameKeys.add(key);
|
|
58473
|
+
}
|
|
58474
|
+
return { duplicateFileNames: candidates.filter((value) => unresolvedLocalFileNameKeys.has(recordingImportFileNameKey(value)) || audioOwnerFileNameKeys.has(recordingImportFileNameKey(value))) };
|
|
57340
58475
|
}
|
|
57341
58476
|
async acceptRecordingImport(sourceHandle, metadata, expectedUserId) {
|
|
57342
58477
|
this.assertWorkbenchEnabled();
|
|
@@ -57360,7 +58495,8 @@ var RecordingService = class {
|
|
|
57360
58495
|
await this.recordingImportSource.discard(sourceHandle).catch(() => void 0);
|
|
57361
58496
|
return toPublicRecordingImportJob(existing, await this.recordingImportRef(existing));
|
|
57362
58497
|
}
|
|
57363
|
-
|
|
58498
|
+
const fileNameKey = recordingImportFileNameKey(metadata.fileName);
|
|
58499
|
+
if (unresolvedJobs.some((job) => recordingImportFileNameKey(job.fileName) === fileNameKey)) throw new ArkmePluginError("recording-import-duplicate-in-progress", "同名录音正在导入,请等待当前任务完成或取消后重试", false, 409);
|
|
57364
58500
|
if (unresolvedJobs.length >= RECORDING_IMPORT_UNRESOLVED_LIMIT) throw new ArkmePluginError("recording-import-pending-limit", "待处理录音过多,请先重试或取消现有任务", false, 409);
|
|
57365
58501
|
const probe = await this.recordingImportSource.inspect(sourceHandle, metadata);
|
|
57366
58502
|
session = await this.requireRecordingImportSession(expectedUserId);
|
|
@@ -57402,7 +58538,7 @@ var RecordingService = class {
|
|
|
57402
58538
|
if (job === void 0) throw new ArkmePluginError("recording-import-not-found", "录音导入任务不存在", false, 404);
|
|
57403
58539
|
return toPublicRecordingImportJob(job, importRef);
|
|
57404
58540
|
}
|
|
57405
|
-
async recordingImportList() {
|
|
58541
|
+
async recordingImportList(signal) {
|
|
57406
58542
|
this.assertWorkbenchEnabled();
|
|
57407
58543
|
const session = await this.runtime.requireSession();
|
|
57408
58544
|
const jobs = await this.runtime.stateStore.listRecordingImportJobs(session.userId);
|
|
@@ -57413,9 +58549,106 @@ var RecordingService = class {
|
|
|
57413
58549
|
].includes(job.phase)) this.runRecordingImport(job);
|
|
57414
58550
|
const newestFirst = (left, right) => right.createdAtMillis - left.createdAtMillis;
|
|
57415
58551
|
const unresolved = jobs.filter((job) => !["accepted", "cancelled"].includes(job.phase)).sort(newestFirst);
|
|
57416
|
-
|
|
57417
|
-
|
|
57418
|
-
|
|
58552
|
+
let activeOwnerTasks;
|
|
58553
|
+
let owner = { state: "available" };
|
|
58554
|
+
try {
|
|
58555
|
+
activeOwnerTasks = (await this.recordingImportOwnerGateway.listOwnerTasks({
|
|
58556
|
+
viewerUserId: session.userId,
|
|
58557
|
+
scope: "active",
|
|
58558
|
+
toMillis: Date.now(),
|
|
58559
|
+
limit: RECORDING_IMPORT_VISIBLE_LIMIT,
|
|
58560
|
+
offset: 0,
|
|
58561
|
+
...signal === void 0 ? {} : { signal }
|
|
58562
|
+
})).tasks;
|
|
58563
|
+
} catch (error) {
|
|
58564
|
+
if (signal?.aborted === true || recordingImportErrorCode(error) === "recording-import-account-mismatch") throw error;
|
|
58565
|
+
owner = {
|
|
58566
|
+
state: "unavailable",
|
|
58567
|
+
message: "Audio 上传任务读取失败,请稍后重试"
|
|
58568
|
+
};
|
|
58569
|
+
}
|
|
58570
|
+
const visibleLocal = unresolved;
|
|
58571
|
+
const projectedLocal = await Promise.all(visibleLocal.map(async (job) => toPublicRecordingImportJob(job, await this.recordingImportRef(job))));
|
|
58572
|
+
if (activeOwnerTasks === void 0) return {
|
|
58573
|
+
items: projectedLocal,
|
|
58574
|
+
owner
|
|
58575
|
+
};
|
|
58576
|
+
const ownerRefKey = await this.recordingRefKey(RECORDING_IMPORT_SESSION_REF_PREFIX);
|
|
58577
|
+
const unresolvedOwnerSessionIds = new Set(unresolved.flatMap((job) => job.sessionId === void 0 ? [] : [job.sessionId]));
|
|
58578
|
+
const projectedOwner = await Promise.all(activeOwnerTasks.filter((task) => !unresolvedOwnerSessionIds.has(task.session.sessionId)).map(async (task) => await this.projectRecordingImportOwnerTask(task, session.userId, ownerRefKey)));
|
|
58579
|
+
return {
|
|
58580
|
+
items: [...projectedLocal, ...projectedOwner].sort((left, right) => right.createdAtMillis - left.createdAtMillis),
|
|
58581
|
+
owner
|
|
58582
|
+
};
|
|
58583
|
+
}
|
|
58584
|
+
async recordingImportHistory(input, signal) {
|
|
58585
|
+
this.assertWorkbenchEnabled();
|
|
58586
|
+
const session = await this.runtime.requireSession();
|
|
58587
|
+
const toMillis = Math.trunc(input.toMillis);
|
|
58588
|
+
const limit = Math.trunc(input.limit);
|
|
58589
|
+
const offset = Math.trunc(input.offset);
|
|
58590
|
+
if (!Number.isSafeInteger(toMillis) || toMillis <= 0 || !Number.isSafeInteger(limit) || limit < 1 || limit > RECORDING_IMPORT_HISTORY_MAX_PAGE_SIZE || !Number.isSafeInteger(offset) || offset < 0) throw new ArkmePluginError("recording-import-history-invalid", "已完成任务查询参数无效", false);
|
|
58591
|
+
const page = await this.recordingImportOwnerGateway.listOwnerTasks({
|
|
58592
|
+
viewerUserId: session.userId,
|
|
58593
|
+
scope: "completed",
|
|
58594
|
+
toMillis,
|
|
58595
|
+
limit,
|
|
58596
|
+
offset,
|
|
58597
|
+
...signal === void 0 ? {} : { signal }
|
|
58598
|
+
});
|
|
58599
|
+
if (page.tasks.some((task) => !task.session.hasFinishedUpload || !task.processingCompleted)) throw new ArkmePluginError("recording-import-history-owner-invalid", "已完成任务数据暂不可用,请稍后重试", true, 502);
|
|
58600
|
+
const ownerRefKey = await this.recordingRefKey(RECORDING_IMPORT_SESSION_REF_PREFIX);
|
|
58601
|
+
return {
|
|
58602
|
+
items: await Promise.all(page.tasks.map(async (task) => await this.projectRecordingImportHistoryItem(task, session.userId, ownerRefKey))),
|
|
58603
|
+
...page.total === void 0 ? {} : { total: page.total },
|
|
58604
|
+
offset,
|
|
58605
|
+
hasMore: page.hasMore
|
|
58606
|
+
};
|
|
58607
|
+
}
|
|
58608
|
+
async updateRecordingImportSessionStart(sessionRef, startAtMillis, signal) {
|
|
58609
|
+
this.assertWorkbenchEnabled();
|
|
58610
|
+
const start = Math.trunc(startAtMillis);
|
|
58611
|
+
if (!isRecordingInstantOnOrAfterUnixEpoch(start) || start > Date.now()) throw new ArkmePluginError("recording-import-start-invalid", "录音开始时间无效", false);
|
|
58612
|
+
const session = await this.runtime.requireSession();
|
|
58613
|
+
const target = await this.openRecordingImportSessionRef(sessionRef);
|
|
58614
|
+
await this.assertRecordingImportOwnerMutationSafe(session.userId, target.sessionId);
|
|
58615
|
+
if (start + (await this.recordingImportOwnerGateway.loadOwnerSession({
|
|
58616
|
+
viewerUserId: session.userId,
|
|
58617
|
+
sessionId: target.sessionId,
|
|
58618
|
+
...signal === void 0 ? {} : { signal }
|
|
58619
|
+
})).durationMillis > Date.now()) throw new ArkmePluginError("recording-import-end-invalid", "录音结束时间不能晚于当前时间", false);
|
|
58620
|
+
await this.recordingImportOwnerGateway.updateOwnerSessionStart({
|
|
58621
|
+
viewerUserId: session.userId,
|
|
58622
|
+
sessionId: target.sessionId,
|
|
58623
|
+
startAtMillis: start,
|
|
58624
|
+
...signal === void 0 ? {} : { signal }
|
|
58625
|
+
});
|
|
58626
|
+
}
|
|
58627
|
+
async updateRecordingImportSessionOwnership(sessionRef, ownership, signal) {
|
|
58628
|
+
this.assertWorkbenchEnabled();
|
|
58629
|
+
const session = await this.runtime.requireSession();
|
|
58630
|
+
const target = await this.openRecordingImportSessionRef(sessionRef);
|
|
58631
|
+
const belongUserId = ownership === "self" ? session.userId : 0;
|
|
58632
|
+
await this.assertRecordingImportOwnerMutationSafe(session.userId, target.sessionId);
|
|
58633
|
+
await this.recordingImportOwnerGateway.updateOwnerSessionOwnership({
|
|
58634
|
+
viewerUserId: session.userId,
|
|
58635
|
+
sessionId: target.sessionId,
|
|
58636
|
+
belongUserId,
|
|
58637
|
+
...signal === void 0 ? {} : { signal }
|
|
58638
|
+
});
|
|
58639
|
+
}
|
|
58640
|
+
async deleteRecordingImportSession(sessionRef, signal) {
|
|
58641
|
+
this.assertWorkbenchEnabled();
|
|
58642
|
+
const session = await this.runtime.requireSession();
|
|
58643
|
+
const target = await this.openRecordingImportSessionRef(sessionRef);
|
|
58644
|
+
await this.assertRecordingImportOwnerMutationSafe(session.userId, target.sessionId);
|
|
58645
|
+
const jobs = await this.runtime.stateStore.listRecordingImportJobs(session.userId);
|
|
58646
|
+
await this.recordingImportOwnerGateway.deleteOwnerSession({
|
|
58647
|
+
viewerUserId: session.userId,
|
|
58648
|
+
sessionId: target.sessionId,
|
|
58649
|
+
...signal === void 0 ? {} : { signal }
|
|
58650
|
+
});
|
|
58651
|
+
await Promise.all(jobs.filter((job) => job.sessionId === target.sessionId).map(async (job) => await this.runtime.stateStore.removeRecordingImportJob(session.userId, job.jobId)));
|
|
57419
58652
|
}
|
|
57420
58653
|
async retryRecordingImport(importRef, expectedRevision) {
|
|
57421
58654
|
this.assertWorkbenchEnabled();
|
|
@@ -57494,6 +58727,81 @@ var RecordingService = class {
|
|
|
57494
58727
|
throw error;
|
|
57495
58728
|
}
|
|
57496
58729
|
}
|
|
58730
|
+
async projectRecordingImportHistoryItem(task, viewerUserId, ownerRefKey) {
|
|
58731
|
+
const owner = task.session;
|
|
58732
|
+
const ownerProgress = task.progress;
|
|
58733
|
+
const status = recordingImportOwnerStatus(task);
|
|
58734
|
+
const processingDurationMillis = recordingImportProcessingDuration(ownerProgress?.processingTiming);
|
|
58735
|
+
return {
|
|
58736
|
+
taskKey: await this.recordingImportTaskKey(owner.sessionId, viewerUserId, ownerRefKey),
|
|
58737
|
+
sessionRef: await this.recordingImportSessionRef(owner, viewerUserId, ownerRefKey),
|
|
58738
|
+
ownership: owner.ownership,
|
|
58739
|
+
fileName: owner.fileName,
|
|
58740
|
+
fileSize: owner.fileSize,
|
|
58741
|
+
parsedSize: owner.parsedSize,
|
|
58742
|
+
durationMillis: owner.durationMillis,
|
|
58743
|
+
startAtMillis: owner.startAtMillis,
|
|
58744
|
+
endAtMillis: owner.endAtMillis,
|
|
58745
|
+
progress: 1,
|
|
58746
|
+
status: status.status,
|
|
58747
|
+
statusDetail: status.statusDetail,
|
|
58748
|
+
...processingDurationMillis === void 0 ? {} : { processingDurationMillis },
|
|
58749
|
+
createdAtMillis: owner.createdAtMillis,
|
|
58750
|
+
updatedAtMillis: owner.updatedAtMillis,
|
|
58751
|
+
...ownerProgress?.processingTiming === void 0 ? {} : { processing: ownerProgress.processingTiming }
|
|
58752
|
+
};
|
|
58753
|
+
}
|
|
58754
|
+
async projectRecordingImportOwnerTask(task, viewerUserId, ownerRefKey) {
|
|
58755
|
+
const owner = task.session;
|
|
58756
|
+
const ownerProgress = task.progress;
|
|
58757
|
+
const status = recordingImportOwnerStatus(task);
|
|
58758
|
+
const processingDurationMillis = recordingImportProcessingDuration(ownerProgress?.processingTiming);
|
|
58759
|
+
return {
|
|
58760
|
+
kind: "owner",
|
|
58761
|
+
taskKey: await this.recordingImportTaskKey(owner.sessionId, viewerUserId, ownerRefKey),
|
|
58762
|
+
sessionRef: await this.recordingImportSessionRef(owner, viewerUserId, ownerRefKey),
|
|
58763
|
+
ownership: owner.ownership,
|
|
58764
|
+
fileName: owner.fileName,
|
|
58765
|
+
fileSize: owner.fileSize,
|
|
58766
|
+
parsedSize: owner.parsedSize,
|
|
58767
|
+
durationMillis: owner.durationMillis,
|
|
58768
|
+
startAtMillis: owner.startAtMillis,
|
|
58769
|
+
endAtMillis: owner.endAtMillis,
|
|
58770
|
+
progress: owner.hasFinishedUpload ? 1 : owner.fileSize <= 0 ? 0 : Math.min(1, owner.parsedSize / owner.fileSize),
|
|
58771
|
+
status: status.status,
|
|
58772
|
+
statusDetail: status.statusDetail,
|
|
58773
|
+
...processingDurationMillis === void 0 ? {} : { processingDurationMillis },
|
|
58774
|
+
createdAtMillis: owner.createdAtMillis,
|
|
58775
|
+
updatedAtMillis: owner.updatedAtMillis,
|
|
58776
|
+
...ownerProgress?.processingTiming === void 0 ? {} : { processing: ownerProgress.processingTiming }
|
|
58777
|
+
};
|
|
58778
|
+
}
|
|
58779
|
+
async recordingImportTaskKey(sessionId, viewerUserId, refKey) {
|
|
58780
|
+
const userId = viewerUserId ?? (await this.runtime.requireSession()).userId;
|
|
58781
|
+
return createHmac("sha256", refKey ?? await this.recordingRefKey(RECORDING_IMPORT_SESSION_REF_PREFIX)).update(`${String(userId)}\0${sessionId}`).digest("base64url");
|
|
58782
|
+
}
|
|
58783
|
+
async recordingImportSessionRef(owner, viewerUserId, refKey) {
|
|
58784
|
+
const payload = {
|
|
58785
|
+
version: 1,
|
|
58786
|
+
viewerUserId: viewerUserId ?? (await this.runtime.requireSession()).userId,
|
|
58787
|
+
sessionId: owner.sessionId
|
|
58788
|
+
};
|
|
58789
|
+
return this.sealRecordingRefWithKey(RECORDING_IMPORT_SESSION_REF_PREFIX, payload, refKey ?? await this.recordingRefKey(RECORDING_IMPORT_SESSION_REF_PREFIX));
|
|
58790
|
+
}
|
|
58791
|
+
async openRecordingImportSessionRef(sessionRef) {
|
|
58792
|
+
const raw = await this.openRecordingRef(RECORDING_IMPORT_SESSION_REF_PREFIX, sessionRef);
|
|
58793
|
+
const payload = {
|
|
58794
|
+
version: 1,
|
|
58795
|
+
viewerUserId: numberValue$5(raw.viewerUserId),
|
|
58796
|
+
sessionId: stringValue$1(raw.sessionId).trim()
|
|
58797
|
+
};
|
|
58798
|
+
if (payload.sessionId === "") throw new ArkmePluginError("recording-import-session-ref-invalid", "录音导入任务引用无效", false);
|
|
58799
|
+
return payload;
|
|
58800
|
+
}
|
|
58801
|
+
async assertRecordingImportOwnerMutationSafe(userId, sessionId) {
|
|
58802
|
+
if ((await this.runtime.stateStore.listRecordingImportJobs(userId)).find((job) => job.sessionId === sessionId && !["accepted", "cancelled"].includes(job.phase)) === void 0) return;
|
|
58803
|
+
throw new ArkmePluginError("recording-import-owner-mutation-active", "录音仍在本机上传任务中,请先重试或取消当前任务", false, 409);
|
|
58804
|
+
}
|
|
57497
58805
|
async recordingCalendar(fromStamp, toStamp, signal) {
|
|
57498
58806
|
const from = Math.trunc(fromStamp);
|
|
57499
58807
|
const to = Math.trunc(toStamp);
|
|
@@ -57874,12 +59182,115 @@ var RecordingService = class {
|
|
|
57874
59182
|
//#endregion
|
|
57875
59183
|
//#region src/services/recording-import-gateway.ts
|
|
57876
59184
|
const AUDIO_SESSION_RECOVERY_LIMIT = 500;
|
|
59185
|
+
const AUDIO_IMPORT_DUPLICATE_BATCH_SIZE = 100;
|
|
59186
|
+
const AUDIO_IMPORT_PROGRESS_BATCH_SIZE = 100;
|
|
59187
|
+
const AUDIO_IMPORT_OWNER_PAGE_SIZE = 100;
|
|
59188
|
+
const PROCESSING_STAGES = /* @__PURE__ */ new Set([
|
|
59189
|
+
"sd",
|
|
59190
|
+
"vad",
|
|
59191
|
+
"asr"
|
|
59192
|
+
]);
|
|
59193
|
+
const PROCESSING_OUTCOMES = /* @__PURE__ */ new Set(["success", "failed"]);
|
|
57877
59194
|
function numberValue$4(value) {
|
|
57878
59195
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
57879
59196
|
}
|
|
57880
59197
|
function optionalIntegerValue(value) {
|
|
57881
59198
|
return typeof value === "number" && Number.isSafeInteger(value) ? value : void 0;
|
|
57882
59199
|
}
|
|
59200
|
+
function nonNegativeIntegerValue(value) {
|
|
59201
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value > 0 ? value : 0;
|
|
59202
|
+
}
|
|
59203
|
+
function processingTimingState(value) {
|
|
59204
|
+
return value === "processing" || value === "completed" ? value : "unavailable";
|
|
59205
|
+
}
|
|
59206
|
+
function processingTimingRow(value) {
|
|
59207
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
59208
|
+
const raw = value;
|
|
59209
|
+
const stage = stringValue$1(raw.stage).trim().toLowerCase();
|
|
59210
|
+
const outcome = stringValue$1(raw.outcome).trim().toLowerCase();
|
|
59211
|
+
const startedAtMillis = optionalIntegerValue(raw.started_at_ms);
|
|
59212
|
+
const endedAtMillis = optionalIntegerValue(raw.ended_at_ms);
|
|
59213
|
+
const durationMillis = optionalIntegerValue(raw.duration_ms);
|
|
59214
|
+
const provider = stringValue$1(raw.provider).trim();
|
|
59215
|
+
const model = stringValue$1(raw.model).trim();
|
|
59216
|
+
if (!PROCESSING_STAGES.has(stage) || !PROCESSING_OUTCOMES.has(outcome) || startedAtMillis === void 0 || endedAtMillis === void 0 || durationMillis === void 0 || startedAtMillis <= 0 || endedAtMillis < startedAtMillis || durationMillis < 0 || provider === "" || model === "") return void 0;
|
|
59217
|
+
return {
|
|
59218
|
+
stage,
|
|
59219
|
+
outcome,
|
|
59220
|
+
startedAtMillis,
|
|
59221
|
+
endedAtMillis,
|
|
59222
|
+
durationMillis,
|
|
59223
|
+
provider,
|
|
59224
|
+
model,
|
|
59225
|
+
modelVersion: stringValue$1(raw.model_version).trim()
|
|
59226
|
+
};
|
|
59227
|
+
}
|
|
59228
|
+
function processingTiming(value, timingState) {
|
|
59229
|
+
if (!Array.isArray(value)) return {
|
|
59230
|
+
timingState: "unavailable",
|
|
59231
|
+
totalDurationMillis: 0,
|
|
59232
|
+
rows: []
|
|
59233
|
+
};
|
|
59234
|
+
const parsedRows = value.map(processingTimingRow);
|
|
59235
|
+
if (parsedRows.some((row) => row === void 0)) return {
|
|
59236
|
+
timingState: "unavailable",
|
|
59237
|
+
totalDurationMillis: 0,
|
|
59238
|
+
rows: []
|
|
59239
|
+
};
|
|
59240
|
+
const rows = parsedRows;
|
|
59241
|
+
const totalDurationMillis = rows.reduce((total, row) => total + row.durationMillis, 0);
|
|
59242
|
+
if (!Number.isSafeInteger(totalDurationMillis)) return {
|
|
59243
|
+
timingState: "unavailable",
|
|
59244
|
+
totalDurationMillis: 0,
|
|
59245
|
+
rows: []
|
|
59246
|
+
};
|
|
59247
|
+
return {
|
|
59248
|
+
timingState,
|
|
59249
|
+
totalDurationMillis,
|
|
59250
|
+
rows
|
|
59251
|
+
};
|
|
59252
|
+
}
|
|
59253
|
+
function ownerDisplayStatus(values) {
|
|
59254
|
+
const statuses = values.filter((value) => Number.isSafeInteger(value) && value >= 1 && value <= 6);
|
|
59255
|
+
if (statuses.length === 0) return void 0;
|
|
59256
|
+
const active = statuses.filter((value) => value <= 4);
|
|
59257
|
+
if (active.length > 0) switch (Math.min(...active)) {
|
|
59258
|
+
case 1: return "speaker-waiting";
|
|
59259
|
+
case 2: return "speaker-recognizing";
|
|
59260
|
+
case 3: return "transcript-waiting";
|
|
59261
|
+
case 4: return "transcribing";
|
|
59262
|
+
}
|
|
59263
|
+
const completedCount = statuses.filter((value) => value === 5).length;
|
|
59264
|
+
const failedCount = statuses.filter((value) => value === 6).length;
|
|
59265
|
+
if (completedCount > 0 && failedCount > 0) return "partial";
|
|
59266
|
+
if (failedCount > 0) return "failed";
|
|
59267
|
+
if (completedCount > 0) return "completed";
|
|
59268
|
+
}
|
|
59269
|
+
function ownerSession(value, viewerUserId) {
|
|
59270
|
+
const owner = objectValue$1(value);
|
|
59271
|
+
const sessionId = stringValue$1(owner.id).trim();
|
|
59272
|
+
const rawStartAtMillis = optionalIntegerValue(owner.start_at);
|
|
59273
|
+
if (optionalIntegerValue(owner.source) !== 2 || sessionId === "" || rawStartAtMillis === void 0 || rawStartAtMillis < 0) return void 0;
|
|
59274
|
+
const startAtMillis = rawStartAtMillis;
|
|
59275
|
+
const durationMillis = optionalIntegerValue(owner.duration);
|
|
59276
|
+
const explicitEndAtMillis = owner.end_at === void 0 ? 0 : optionalIntegerValue(owner.end_at);
|
|
59277
|
+
if (durationMillis === void 0 || durationMillis < 0 || explicitEndAtMillis === void 0 || explicitEndAtMillis < 0) return void 0;
|
|
59278
|
+
const inferredEndAtMillis = startAtMillis + durationMillis;
|
|
59279
|
+
if (!Number.isSafeInteger(inferredEndAtMillis)) return void 0;
|
|
59280
|
+
return {
|
|
59281
|
+
sessionId,
|
|
59282
|
+
ownership: numberValue$4(owner.belong_usr) === viewerUserId ? "self" : "other",
|
|
59283
|
+
fileName: stringValue$1(owner.orig_name).trim(),
|
|
59284
|
+
fileSize: nonNegativeIntegerValue(owner.source_size),
|
|
59285
|
+
parsedSize: nonNegativeIntegerValue(owner.size),
|
|
59286
|
+
durationMillis,
|
|
59287
|
+
startAtMillis,
|
|
59288
|
+
endAtMillis: explicitEndAtMillis > startAtMillis ? explicitEndAtMillis : inferredEndAtMillis,
|
|
59289
|
+
createdAtMillis: nonNegativeIntegerValue(owner.create_at),
|
|
59290
|
+
updatedAtMillis: nonNegativeIntegerValue(owner.update_at),
|
|
59291
|
+
hasFinishedUpload: owner.has_finish_spk === true
|
|
59292
|
+
};
|
|
59293
|
+
}
|
|
57883
59294
|
function remoteFileName(job) {
|
|
57884
59295
|
const extension = job.fileName.trim().toLowerCase().match(/\.[^.]+$/)?.[0] ?? "";
|
|
57885
59296
|
return `arkme_${job.jobId}_0${extension}`;
|
|
@@ -57891,12 +59302,137 @@ var AudioRecordingImportGateway = class {
|
|
|
57891
59302
|
this.runtime = runtime;
|
|
57892
59303
|
this.createOssClient = createOssClient;
|
|
57893
59304
|
}
|
|
59305
|
+
async findExistingFileNames(input) {
|
|
59306
|
+
const existing = [];
|
|
59307
|
+
for (let offset = 0; offset < input.fileNames.length; offset += AUDIO_IMPORT_DUPLICATE_BATCH_SIZE) {
|
|
59308
|
+
const data = await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/check-exist-same-orig", { orig_names: input.fileNames.slice(offset, offset + AUDIO_IMPORT_DUPLICATE_BATCH_SIZE) }, input.signal);
|
|
59309
|
+
if (!Array.isArray(data.exist_names)) continue;
|
|
59310
|
+
existing.push(...data.exist_names.map(stringValue$1).map((value) => value.trim()).filter(Boolean));
|
|
59311
|
+
}
|
|
59312
|
+
return existing;
|
|
59313
|
+
}
|
|
59314
|
+
async listOwnerTasks(input) {
|
|
59315
|
+
const offset = Math.max(0, Math.trunc(input.offset));
|
|
59316
|
+
const limit = Math.max(0, Math.trunc(input.limit));
|
|
59317
|
+
if (limit === 0) return {
|
|
59318
|
+
tasks: [],
|
|
59319
|
+
hasMore: false
|
|
59320
|
+
};
|
|
59321
|
+
const scoped = [];
|
|
59322
|
+
const targetCount = offset + limit + 1;
|
|
59323
|
+
let remoteOffset = 0;
|
|
59324
|
+
let exhausted = false;
|
|
59325
|
+
while (scoped.length < targetCount) {
|
|
59326
|
+
const data = await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/get-session-ls", {
|
|
59327
|
+
to_stamp: Math.trunc(input.toMillis),
|
|
59328
|
+
limit: AUDIO_IMPORT_OWNER_PAGE_SIZE,
|
|
59329
|
+
offset: remoteOffset,
|
|
59330
|
+
query_new: false,
|
|
59331
|
+
task_scope: input.scope
|
|
59332
|
+
}, input.signal);
|
|
59333
|
+
const rawSessions = Array.isArray(data.session_ls) ? data.session_ls : [];
|
|
59334
|
+
const ownerSnapshots = rawSessions.map((raw) => ({
|
|
59335
|
+
raw: objectValue$1(raw),
|
|
59336
|
+
session: ownerSession(raw, input.viewerUserId)
|
|
59337
|
+
})).filter((owner) => owner.session !== void 0).map(({ raw, session: owner }) => {
|
|
59338
|
+
if (typeof raw.has_done_child !== "boolean") throw new RecordingImportContractError("recording-import-owner-completion-unavailable", "Audio 暂未返回录音处理终态,请稍后重试", true);
|
|
59339
|
+
const processingCompleted = raw.has_done_child;
|
|
59340
|
+
if (input.scope === "completed" !== processingCompleted) throw new RecordingImportContractError("recording-import-owner-scope-invalid", "Audio 返回的录音任务范围无效,请稍后重试", true);
|
|
59341
|
+
return {
|
|
59342
|
+
session: owner,
|
|
59343
|
+
processingCompleted
|
|
59344
|
+
};
|
|
59345
|
+
});
|
|
59346
|
+
const sealed = ownerSnapshots.filter((task) => task.session.hasFinishedUpload);
|
|
59347
|
+
let progress = /* @__PURE__ */ new Map();
|
|
59348
|
+
if (sealed.length > 0) try {
|
|
59349
|
+
progress = await this.loadOwnerProgressForSession(input.viewerUserId, sealed.map((task) => task.session.sessionId), input.signal);
|
|
59350
|
+
} catch (error) {
|
|
59351
|
+
if (input.signal?.aborted === true || this.isAccountMismatch(error)) throw error;
|
|
59352
|
+
}
|
|
59353
|
+
for (const task of ownerSnapshots) {
|
|
59354
|
+
const ownerProgress = progress.get(task.session.sessionId);
|
|
59355
|
+
scoped.push({
|
|
59356
|
+
...task,
|
|
59357
|
+
...ownerProgress === void 0 ? {} : { progress: ownerProgress }
|
|
59358
|
+
});
|
|
59359
|
+
}
|
|
59360
|
+
remoteOffset += rawSessions.length;
|
|
59361
|
+
if (rawSessions.length < AUDIO_IMPORT_OWNER_PAGE_SIZE) {
|
|
59362
|
+
exhausted = true;
|
|
59363
|
+
break;
|
|
59364
|
+
}
|
|
59365
|
+
}
|
|
59366
|
+
return {
|
|
59367
|
+
tasks: scoped.slice(offset, offset + limit),
|
|
59368
|
+
...exhausted ? { total: scoped.length } : {},
|
|
59369
|
+
hasMore: scoped.length > offset + limit || !exhausted
|
|
59370
|
+
};
|
|
59371
|
+
}
|
|
59372
|
+
async loadOwnerSession(input) {
|
|
59373
|
+
const normalized = input.sessionId.trim();
|
|
59374
|
+
if (normalized === "") throw new RecordingImportContractError("recording-import-session-invalid", "Audio 会话引用无效");
|
|
59375
|
+
const owner = ownerSession(await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/get-session-by-id", { session_id: normalized }, input.signal), input.viewerUserId);
|
|
59376
|
+
if (owner === void 0 || owner.sessionId !== normalized) throw new RecordingImportContractError("recording-import-session-invalid", "Audio 会话数据无效", true);
|
|
59377
|
+
return owner;
|
|
59378
|
+
}
|
|
59379
|
+
async loadOwnerProgressForSession(viewerUserId, sessionIds, signal) {
|
|
59380
|
+
const normalized = [...new Set(sessionIds.map((value) => value.trim()).filter((value) => value !== ""))];
|
|
59381
|
+
if (normalized.length === 0) return /* @__PURE__ */ new Map();
|
|
59382
|
+
const result = /* @__PURE__ */ new Map();
|
|
59383
|
+
for (let offset = 0; offset < normalized.length; offset += AUDIO_IMPORT_PROGRESS_BATCH_SIZE) {
|
|
59384
|
+
const batch = normalized.slice(offset, offset + AUDIO_IMPORT_PROGRESS_BATCH_SIZE);
|
|
59385
|
+
const data = await this.authenticatedOwnerPost(viewerUserId, "/api/v1/audio/get-session-deal-status", { session_ids: batch }, signal);
|
|
59386
|
+
for (const raw of Array.isArray(data.item_ls) ? data.item_ls : []) {
|
|
59387
|
+
const owner = objectValue$1(raw);
|
|
59388
|
+
const sessionId = stringValue$1(owner.session_id).trim();
|
|
59389
|
+
if (sessionId === "" || !batch.includes(sessionId)) continue;
|
|
59390
|
+
const statusListAvailable = Array.isArray(owner.child_status_ls);
|
|
59391
|
+
const parsedStatuses = (statusListAvailable ? owner.child_status_ls : []).map((child) => optionalIntegerValue(objectValue$1(child).status));
|
|
59392
|
+
const displayStatus = statusListAvailable && parsedStatuses.every((status) => status !== void 0 && status >= 1 && status <= 6) ? ownerDisplayStatus(parsedStatuses) : "unavailable";
|
|
59393
|
+
const timingState = processingTimingState(owner.timing_state);
|
|
59394
|
+
result.set(sessionId, {
|
|
59395
|
+
...displayStatus === void 0 ? {} : { displayStatus },
|
|
59396
|
+
timingState,
|
|
59397
|
+
processingTiming: processingTiming(owner.processing_timing_ls, timingState)
|
|
59398
|
+
});
|
|
59399
|
+
}
|
|
59400
|
+
}
|
|
59401
|
+
return result;
|
|
59402
|
+
}
|
|
59403
|
+
async updateOwnerSessionStart(input) {
|
|
59404
|
+
await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/modify-session-start", {
|
|
59405
|
+
session_id: input.sessionId.trim(),
|
|
59406
|
+
start_at: Math.trunc(input.startAtMillis),
|
|
59407
|
+
tz_offset: -new Date(input.startAtMillis).getTimezoneOffset() * 6e4
|
|
59408
|
+
}, input.signal, {
|
|
59409
|
+
lane: "write",
|
|
59410
|
+
bypassCache: true
|
|
59411
|
+
});
|
|
59412
|
+
}
|
|
59413
|
+
async updateOwnerSessionOwnership(input) {
|
|
59414
|
+
if (input.belongUserId !== 0 && input.belongUserId !== input.viewerUserId) throw new ArkmePluginError("recording-import-owner-invalid", "录音数据归属无效", false);
|
|
59415
|
+
await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/modify-session-belong-usr", {
|
|
59416
|
+
session_id: input.sessionId.trim(),
|
|
59417
|
+
belong_usr: input.belongUserId
|
|
59418
|
+
}, input.signal, {
|
|
59419
|
+
lane: "write",
|
|
59420
|
+
bypassCache: true
|
|
59421
|
+
});
|
|
59422
|
+
}
|
|
59423
|
+
async deleteOwnerSession(input) {
|
|
59424
|
+
await this.authenticatedOwnerPost(input.viewerUserId, "/api/v1/audio/del-session", { session_id: input.sessionId.trim() }, input.signal, {
|
|
59425
|
+
lane: "write",
|
|
59426
|
+
bypassCache: true
|
|
59427
|
+
});
|
|
59428
|
+
}
|
|
57894
59429
|
async ensureSession(job, signal) {
|
|
57895
59430
|
const recovered = await this.recoverSession(job, signal);
|
|
57896
59431
|
if (recovered !== void 0) return recovered.sessionId;
|
|
57897
59432
|
let session = await this.requireJobSession(job);
|
|
57898
59433
|
const duplicate = await this.runtime.authenticatedAudioPost("/api/v1/audio/check-exist-same-orig", { orig_names: [job.fileName] }, session, signal);
|
|
57899
|
-
|
|
59434
|
+
const fileNameKey = recordingImportFileNameKey(job.fileName);
|
|
59435
|
+
if ((Array.isArray(duplicate.exist_names) ? duplicate.exist_names : []).some((value) => recordingImportFileNameKey(stringValue$1(value)) === fileNameKey)) throw new RecordingImportContractError("recording-import-duplicate", "已存在同名录音,请更名后重试");
|
|
57900
59436
|
const timezoneOffsetMillis = -new Date(job.startAtMillis).getTimezoneOffset() * 6e4;
|
|
57901
59437
|
session = await this.requireJobSession(job);
|
|
57902
59438
|
const sessionId = stringValue$1((await this.runtime.authenticatedAudioPost("/api/v1/audio/new-session", {
|
|
@@ -58020,10 +59556,19 @@ var AudioRecordingImportGateway = class {
|
|
|
58020
59556
|
return credentials;
|
|
58021
59557
|
}
|
|
58022
59558
|
async requireJobSession(job) {
|
|
59559
|
+
return await this.requireViewerSession(job.userId);
|
|
59560
|
+
}
|
|
59561
|
+
async requireViewerSession(viewerUserId) {
|
|
58023
59562
|
const session = await this.runtime.requireSession();
|
|
58024
|
-
if (session.userId !==
|
|
59563
|
+
if (session.userId !== viewerUserId) throw new ArkmePluginError("recording-import-account-mismatch", "登录账号已变化,已停止录音导入", true, 403);
|
|
58025
59564
|
return session;
|
|
58026
59565
|
}
|
|
59566
|
+
async authenticatedOwnerPost(viewerUserId, path, body, signal, options = {}) {
|
|
59567
|
+
return await this.runtime.authenticatedAudioPost(path, body, await this.requireViewerSession(viewerUserId), signal, options);
|
|
59568
|
+
}
|
|
59569
|
+
isAccountMismatch(error) {
|
|
59570
|
+
return error instanceof ArkmePluginError && error.code === "recording-import-account-mismatch";
|
|
59571
|
+
}
|
|
58027
59572
|
async recoverSession(job, signal, normalizeOwnership = true) {
|
|
58028
59573
|
const session = await this.requireJobSession(job);
|
|
58029
59574
|
const matchesIdentity = (item) => numberValue$4(item.source) === 2 && numberValue$4(item.start_at) === job.startAtMillis && stringValue$1(item.orig_name) === job.fileName;
|
|
@@ -58414,6 +59959,42 @@ var SearchService = class {
|
|
|
58414
59959
|
}, session, options.signal);
|
|
58415
59960
|
return await this.withNavigationTargets(this.recordSearchResult(data, lockedRecordUids), options.signal);
|
|
58416
59961
|
}
|
|
59962
|
+
/** Query the canonical record-tag projection used by Flutter's tag search. */
|
|
59963
|
+
async searchTagRecords(options) {
|
|
59964
|
+
const normalizedTag = arkmeNormalizedHashTag(options.normalizedTag);
|
|
59965
|
+
if (normalizedTag === "") throw new ArkmePluginError("record-tag-query-empty", "搜索标签不能为空", false);
|
|
59966
|
+
const session = await this.runtime.requireSession();
|
|
59967
|
+
const data = await this.runtime.authenticatedPost("/api/v1/records/tags/query", {
|
|
59968
|
+
normalized_tag: normalizedTag,
|
|
59969
|
+
limit: Math.min(100, Math.max(1, Math.trunc(options.limit))),
|
|
59970
|
+
...options.cursorSendAt === void 0 ? {} : { cursor_send_at: Math.trunc(options.cursorSendAt) },
|
|
59971
|
+
...options.cursorRecordUid?.trim() ? { cursor_record_uid: options.cursorRecordUid.trim() } : {}
|
|
59972
|
+
}, session, options.signal);
|
|
59973
|
+
const items = listValue$3(data.items).map((raw) => {
|
|
59974
|
+
const item = objectValue$1(raw);
|
|
59975
|
+
const core = objectValue$1(item.record_core);
|
|
59976
|
+
const sourceKind = Math.trunc(numberValue$2(core.origin_kind));
|
|
59977
|
+
const sourceUid = stringValue$1(core.origin_container_ref).trim();
|
|
59978
|
+
return {
|
|
59979
|
+
...item,
|
|
59980
|
+
source_kind: sourceKind,
|
|
59981
|
+
...sourceUid === "" ? {} : { source_uid: sourceUid },
|
|
59982
|
+
route_target_kind: sourceKind === 2 ? "topic" : "default_category",
|
|
59983
|
+
match_summary: { snippet: stringValue$1(core.text_content) }
|
|
59984
|
+
};
|
|
59985
|
+
});
|
|
59986
|
+
const nextSendAt = numberValue$2(data.next_send_at);
|
|
59987
|
+
const nextRecordUid = stringValue$1(data.next_record_uid).trim();
|
|
59988
|
+
const result = this.recordSearchResult({
|
|
59989
|
+
items,
|
|
59990
|
+
source_aggregates: [],
|
|
59991
|
+
has_more: booleanValue$1(data.has_more),
|
|
59992
|
+
query_guard: { state: "complete" },
|
|
59993
|
+
page_summary: { item_count: items.length },
|
|
59994
|
+
...nextSendAt > 0 && nextRecordUid !== "" ? { next_cursor: `${String(nextSendAt)}:${nextRecordUid}` } : {}
|
|
59995
|
+
});
|
|
59996
|
+
return await this.withNavigationTargets(result, options.signal);
|
|
59997
|
+
}
|
|
58417
59998
|
async searchFiles(options) {
|
|
58418
59999
|
const page = options.query?.trim() ? await this.searchRemote({
|
|
58419
60000
|
...options,
|
|
@@ -61011,6 +62592,8 @@ const ARKME_WORLD_IMAGE_REF_TTL_MILLIS = 900 * 1e3;
|
|
|
61011
62592
|
const MAX_ARKME_WORLD_IMAGE_REFS = 2048;
|
|
61012
62593
|
const ARKME_WORLD_AVATAR_RESOLUTION_CACHE_TTL_MILLIS = 300 * 1e3;
|
|
61013
62594
|
const MAX_ARKME_WORLD_AVATAR_RESOLUTION_CACHE_ENTRIES = 2048;
|
|
62595
|
+
const ARKME_WORLD_EXTENSION_SHARE_CACHE_TTL_MILLIS = 300 * 1e3;
|
|
62596
|
+
const MAX_ARKME_WORLD_EXTENSION_SHARE_CACHE_ENTRIES = 512;
|
|
61014
62597
|
const ARKME_WORLD_RECORD_REF_TTL_MILLIS = 900 * 1e3;
|
|
61015
62598
|
const MAX_ARKME_WORLD_RECORD_REFS = 4096;
|
|
61016
62599
|
const ARKME_VOICEPRINT_PLAY_SCOPE = 2;
|
|
@@ -61087,6 +62670,18 @@ function worldExtensionPublicationShare(rawPublication, rawItem) {
|
|
|
61087
62670
|
url: parsed.href
|
|
61088
62671
|
};
|
|
61089
62672
|
}
|
|
62673
|
+
function worldExtensionShareFromCatalogDetail(raw) {
|
|
62674
|
+
const response = objectValue$1(raw);
|
|
62675
|
+
return worldExtensionPublicationShare({ share: objectValue$1(response.extension ?? response).share }, {});
|
|
62676
|
+
}
|
|
62677
|
+
function worldTextWithExtensionShare(textContent, share) {
|
|
62678
|
+
const content = textContent.trim();
|
|
62679
|
+
if (share === void 0) return content;
|
|
62680
|
+
const shareUrl = share.url.trim();
|
|
62681
|
+
if (shareUrl === "") return content;
|
|
62682
|
+
if (content.includes(shareUrl)) return content;
|
|
62683
|
+
return content === "" ? shareUrl : `${content}\n${shareUrl}`;
|
|
62684
|
+
}
|
|
61090
62685
|
function isTopLevelWorldRecord(raw) {
|
|
61091
62686
|
return stringValue$1(objectValue$1(raw).parent_record_uid).trim() === "";
|
|
61092
62687
|
}
|
|
@@ -61201,6 +62796,8 @@ var WorldService = class {
|
|
|
61201
62796
|
viewerLabels;
|
|
61202
62797
|
worldImageRefs = /* @__PURE__ */ new Map();
|
|
61203
62798
|
worldAvatarResolutionCache = /* @__PURE__ */ new Map();
|
|
62799
|
+
extensionPublicationShareCache = /* @__PURE__ */ new Map();
|
|
62800
|
+
extensionPublicationShareInFlight = /* @__PURE__ */ new Map();
|
|
61204
62801
|
worldRecordRefs = /* @__PURE__ */ new Map();
|
|
61205
62802
|
voiceprintSocialCache = /* @__PURE__ */ new Map();
|
|
61206
62803
|
voiceprintSocialInFlight = /* @__PURE__ */ new Map();
|
|
@@ -61214,6 +62811,8 @@ var WorldService = class {
|
|
|
61214
62811
|
dispose() {
|
|
61215
62812
|
this.worldImageRefs.clear();
|
|
61216
62813
|
this.worldAvatarResolutionCache.clear();
|
|
62814
|
+
this.extensionPublicationShareCache.clear();
|
|
62815
|
+
this.extensionPublicationShareInFlight.clear();
|
|
61217
62816
|
this.worldRecordRefs.clear();
|
|
61218
62817
|
this.voiceprintSocialCache.clear();
|
|
61219
62818
|
this.voiceprintSocialInFlight.clear();
|
|
@@ -61247,7 +62846,7 @@ var WorldService = class {
|
|
|
61247
62846
|
}, void 0, [200], options.signal);
|
|
61248
62847
|
const rawItems = listValue(data.list);
|
|
61249
62848
|
const resolvedAvatars = await this.resolveWorldAvatarUrls(rawItems, session, options.signal);
|
|
61250
|
-
const items = (await Promise.all(rawItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars)))).filter((item) => item !== void 0);
|
|
62849
|
+
const items = (await Promise.all(rawItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars, options.signal)))).filter((item) => item !== void 0);
|
|
61251
62850
|
const total = Math.max(0, Math.trunc(numberValue(data.total)));
|
|
61252
62851
|
const nextOffset = offset + rawItems.length;
|
|
61253
62852
|
const hasMore = rawItems.length > 0 && nextOffset < total;
|
|
@@ -61274,7 +62873,7 @@ var WorldService = class {
|
|
|
61274
62873
|
const rawItems = listValue(data.list);
|
|
61275
62874
|
const rootItems = rawItems.filter(isTopLevelWorldRecord);
|
|
61276
62875
|
const resolvedAvatars = await this.resolveWorldAvatarUrls(rootItems, session, options.signal);
|
|
61277
|
-
items = (await Promise.all(rootItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars)))).filter((item) => item !== void 0);
|
|
62876
|
+
items = (await Promise.all(rootItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars, options.signal)))).filter((item) => item !== void 0);
|
|
61278
62877
|
total = Math.max(0, Math.trunc(numberValue(data.total)));
|
|
61279
62878
|
offset += rawItems.length;
|
|
61280
62879
|
hasMore = rawItems.length > 0 && offset < total;
|
|
@@ -61306,7 +62905,7 @@ var WorldService = class {
|
|
|
61306
62905
|
total = Math.max(0, Math.trunc(numberValue(data.total)));
|
|
61307
62906
|
const rootItems = rawItems.filter(isTopLevelWorldRecord);
|
|
61308
62907
|
const resolvedAvatars = await this.resolveWorldAvatarUrls(rootItems, session, options.signal);
|
|
61309
|
-
items = (await Promise.all(rootItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars)))).filter((item) => item !== void 0);
|
|
62908
|
+
items = (await Promise.all(rootItems.map((raw) => this.worldFeedItem(raw, session.userId, resolvedAvatars, options.signal)))).filter((item) => item !== void 0);
|
|
61310
62909
|
offset += rawItems.length;
|
|
61311
62910
|
hasMore = rawItems.length > 0 && offset < total;
|
|
61312
62911
|
attempts += 1;
|
|
@@ -61873,7 +63472,7 @@ var WorldService = class {
|
|
|
61873
63472
|
extendCount: Math.max(0, Math.trunc(numberValue(item.extend_count)))
|
|
61874
63473
|
};
|
|
61875
63474
|
}
|
|
61876
|
-
async worldFeedItem(raw, viewerUserId, resolvedAvatars) {
|
|
63475
|
+
async worldFeedItem(raw, viewerUserId, resolvedAvatars, signal) {
|
|
61877
63476
|
const item = objectValue$1(raw);
|
|
61878
63477
|
const recordUid = stringValue$1(item.record_uid).trim();
|
|
61879
63478
|
const textContent = stringValue$1(item.text_content ?? item.content).trim();
|
|
@@ -61883,6 +63482,8 @@ var WorldService = class {
|
|
|
61883
63482
|
const extensionId = stringValue$1(rawExtensionPublication.extension_id).trim();
|
|
61884
63483
|
const extensionVisibility = stringValue$1(rawExtensionPublication.visibility).trim();
|
|
61885
63484
|
const isExtensionPublication = recordType === "extension_publication" && extensionId !== "" && extensionVisibility === "public";
|
|
63485
|
+
let extensionShare = isExtensionPublication ? worldExtensionPublicationShare(rawExtensionPublication, item) : void 0;
|
|
63486
|
+
if (isExtensionPublication && extensionShare === void 0) extensionShare = await this.extensionPublicationShare(extensionId, signal);
|
|
61886
63487
|
const rawImages = listValue(item.images).map(stringValue$1).map((value) => value.trim()).filter((value) => value !== "");
|
|
61887
63488
|
const videoCount = listValue(item.videos).length;
|
|
61888
63489
|
const voiceCount = listValue(item.voices).length;
|
|
@@ -61916,7 +63517,7 @@ var WorldService = class {
|
|
|
61916
63517
|
...avatarRef === void 0 ? {} : { avatarRef },
|
|
61917
63518
|
...avatarRef === void 0 && avatarFallback !== void 0 ? { avatarFallback } : {},
|
|
61918
63519
|
headline,
|
|
61919
|
-
textContent,
|
|
63520
|
+
textContent: isExtensionPublication ? worldTextWithExtensionShare(textContent, extensionShare) : textContent,
|
|
61920
63521
|
tags: listValue(item.tags).map(stringValue$1).map((tag) => tag.trim()).filter((tag) => tag !== ""),
|
|
61921
63522
|
templateKind: Math.trunc(numberValue(item.template_kind)),
|
|
61922
63523
|
createdAtMillis: Math.trunc(numberValue(item.created_at)),
|
|
@@ -61933,10 +63534,7 @@ var WorldService = class {
|
|
|
61933
63534
|
version: stringValue$1(rawExtensionPublication.version).trim(),
|
|
61934
63535
|
name: stringValue$1(rawExtensionPublication.name).trim() || "未命名插件",
|
|
61935
63536
|
description: stringValue$1(rawExtensionPublication.description).trim(),
|
|
61936
|
-
...
|
|
61937
|
-
const share = worldExtensionPublicationShare(rawExtensionPublication, item);
|
|
61938
|
-
return share === void 0 ? {} : { share };
|
|
61939
|
-
})(),
|
|
63537
|
+
...extensionShare === void 0 ? {} : { share: extensionShare },
|
|
61940
63538
|
...(() => {
|
|
61941
63539
|
const iconRef = stringValue$1(rawExtensionPublication.icon_ref).trim();
|
|
61942
63540
|
return iconRef === "" ? {} : { iconRef };
|
|
@@ -61953,6 +63551,44 @@ var WorldService = class {
|
|
|
61953
63551
|
} : {}
|
|
61954
63552
|
};
|
|
61955
63553
|
}
|
|
63554
|
+
async extensionPublicationShare(extensionId, signal) {
|
|
63555
|
+
const normalized = extensionId.trim();
|
|
63556
|
+
if (normalized === "") return void 0;
|
|
63557
|
+
const now = Date.now();
|
|
63558
|
+
const cached = this.extensionPublicationShareCache.get(normalized);
|
|
63559
|
+
if (cached !== void 0 && cached.expiresAtMillis > now) return cached.share;
|
|
63560
|
+
const inFlight = this.extensionPublicationShareInFlight.get(normalized);
|
|
63561
|
+
if (inFlight !== void 0) return await inFlight;
|
|
63562
|
+
const load = this.loadExtensionPublicationShare(normalized, signal);
|
|
63563
|
+
this.extensionPublicationShareInFlight.set(normalized, load);
|
|
63564
|
+
try {
|
|
63565
|
+
const share = await load;
|
|
63566
|
+
if (this.extensionPublicationShareCache.size >= MAX_ARKME_WORLD_EXTENSION_SHARE_CACHE_ENTRIES) {
|
|
63567
|
+
const oldestKey = this.extensionPublicationShareCache.keys().next().value;
|
|
63568
|
+
if (oldestKey !== void 0) this.extensionPublicationShareCache.delete(oldestKey);
|
|
63569
|
+
}
|
|
63570
|
+
this.extensionPublicationShareCache.set(normalized, {
|
|
63571
|
+
...share === void 0 ? {} : { share },
|
|
63572
|
+
expiresAtMillis: Date.now() + ARKME_WORLD_EXTENSION_SHARE_CACHE_TTL_MILLIS
|
|
63573
|
+
});
|
|
63574
|
+
return share;
|
|
63575
|
+
} finally {
|
|
63576
|
+
this.extensionPublicationShareInFlight.delete(normalized);
|
|
63577
|
+
}
|
|
63578
|
+
}
|
|
63579
|
+
async loadExtensionPublicationShare(extensionId, signal) {
|
|
63580
|
+
try {
|
|
63581
|
+
return worldExtensionShareFromCatalogDetail(await this.runtime.extensionPost("/api/public/v1/extensions/detail", { extension_id: extensionId }, signal, {
|
|
63582
|
+
lane: "background-read",
|
|
63583
|
+
key: `world-extension-share:${extensionId}`,
|
|
63584
|
+
cacheMs: ARKME_WORLD_EXTENSION_SHARE_CACHE_TTL_MILLIS,
|
|
63585
|
+
failureCooldownMs: 3e4
|
|
63586
|
+
}));
|
|
63587
|
+
} catch (error) {
|
|
63588
|
+
if (error instanceof Error && error.name === "AbortError") throw error;
|
|
63589
|
+
return;
|
|
63590
|
+
}
|
|
63591
|
+
}
|
|
61956
63592
|
isTrustedWorldImageUrl(raw) {
|
|
61957
63593
|
if (raw.length > 4096) return false;
|
|
61958
63594
|
try {
|
|
@@ -62204,6 +63840,7 @@ var ArkmeService = class {
|
|
|
62204
63840
|
media;
|
|
62205
63841
|
privacy;
|
|
62206
63842
|
source;
|
|
63843
|
+
conversationDirectoryVisibility;
|
|
62207
63844
|
record;
|
|
62208
63845
|
search;
|
|
62209
63846
|
bot;
|
|
@@ -62276,7 +63913,8 @@ var ArkmeService = class {
|
|
|
62276
63913
|
this.interwoven = new InterwovenService(this.runtime, this.source, this.profile);
|
|
62277
63914
|
this.linkMetadata = new ArkmeLinkMetadataService(linkDocumentReader);
|
|
62278
63915
|
this.aiPolish = new GroupAiPolishService(this.runtime, this.source, { sendChatSourceTextRaw: async (...args) => await this.chat.sendChatSourceTextRaw(...args) });
|
|
62279
|
-
this.realtime = new ChatRealtimeService(this.runtime, this.source, { chatTimelineItems: async (data, session, chatSessionUid) => await this.chat.chatTimelineItems(data, session, chatSessionUid) });
|
|
63916
|
+
this.realtime = new ChatRealtimeService(this.runtime, this.source, { chatTimelineItems: async (data, session, chatSessionUid, sourceKind) => await this.chat.chatTimelineItems(data, session, chatSessionUid, sourceKind) });
|
|
63917
|
+
this.conversationDirectoryVisibility = new ConversationDirectoryVisibilityService(new ConversationListPreferenceService(this.runtime), this.source, this.bot, this.realtime);
|
|
62280
63918
|
this.chat = new ChatService(this.runtime, this.source, this.profile, this.media, this.record, this.bot, this.arko, this.aiPolish, this.realtime, this.privacy, this.messageActions);
|
|
62281
63919
|
this.userBan = new UserBanService(this.runtime, this.chat);
|
|
62282
63920
|
this.botConversation = new BotConversationService(this.runtime, this.bot, this.chat, async () => {
|
|
@@ -62284,8 +63922,10 @@ var ArkmeService = class {
|
|
|
62284
63922
|
}, this.messageActions);
|
|
62285
63923
|
this.relatedQuickNote = new RelatedQuickNoteService(this.runtime, this.record, this.media, this.profile, this.privacy);
|
|
62286
63924
|
this.contactDirectory = new ContactDirectoryService(this.runtime, this.source, this.bot, this.profile, this.world, this.chat);
|
|
63925
|
+
const recordingImportGateway = new AudioRecordingImportGateway(this.runtime);
|
|
62287
63926
|
this.recording = new RecordingService(this.runtime, {
|
|
62288
|
-
recordingImportGateway
|
|
63927
|
+
recordingImportGateway,
|
|
63928
|
+
recordingImportOwnerGateway: recordingImportGateway,
|
|
62289
63929
|
recordingImportSource: new LocalRecordingImportSource(),
|
|
62290
63930
|
profile: this.profile,
|
|
62291
63931
|
media: this.media,
|
|
@@ -62452,7 +64092,7 @@ var ArkmeService = class {
|
|
|
62452
64092
|
return await this.botConversation.updateNotificationPreference(botRef, muted, options);
|
|
62453
64093
|
}
|
|
62454
64094
|
async openBotChat(botRef, options = {}) {
|
|
62455
|
-
return await this.
|
|
64095
|
+
return await this.conversationDirectoryVisibility.openBotContactConversation(botRef, options);
|
|
62456
64096
|
}
|
|
62457
64097
|
async listBotPrivateChatDirectory(options = {}) {
|
|
62458
64098
|
return await this.botConversation.directory(options);
|
|
@@ -62550,6 +64190,7 @@ var ArkmeService = class {
|
|
|
62550
64190
|
messageReadReceipts: true,
|
|
62551
64191
|
messageReport: true,
|
|
62552
64192
|
userBanManagement: true,
|
|
64193
|
+
groupOwnerGovernance: true,
|
|
62553
64194
|
richContentRead: this.config.richMediaRenderEnabled !== false,
|
|
62554
64195
|
richContentSend: this.config.richMediaSendEnabled !== false,
|
|
62555
64196
|
...this.config.richMediaSendEnabled === false ? {} : { backgroundSound: true },
|
|
@@ -62677,10 +64318,14 @@ var ArkmeService = class {
|
|
|
62677
64318
|
return await this.contactDirectory.contactWorld(contactRef, options);
|
|
62678
64319
|
}
|
|
62679
64320
|
async openDirectoryContactChat(contactRef, signal) {
|
|
62680
|
-
|
|
64321
|
+
const result = await this.contactDirectory.openContactChat(contactRef, signal);
|
|
64322
|
+
this.conversationDirectoryVisibility.restoreSource(result.source).catch(() => void 0);
|
|
64323
|
+
return result;
|
|
62681
64324
|
}
|
|
62682
64325
|
async openDirectoryGroupChat(sourceRef, signal) {
|
|
62683
|
-
|
|
64326
|
+
const source = await this.contactDirectory.openGroupChat(sourceRef, signal);
|
|
64327
|
+
this.conversationDirectoryVisibility.restoreSource(source).catch(() => void 0);
|
|
64328
|
+
return source;
|
|
62684
64329
|
}
|
|
62685
64330
|
async unmarkedSpeakerOptions(candidateRef, signal) {
|
|
62686
64331
|
return await this.unmarkedSpeaker.markOptions(candidateRef, signal);
|
|
@@ -62745,8 +64390,11 @@ var ArkmeService = class {
|
|
|
62745
64390
|
/** @internal Built-in loopback UI only. */ async recordingImportStatus(importRef) {
|
|
62746
64391
|
return await this.recording.recordingImportStatus(importRef);
|
|
62747
64392
|
}
|
|
62748
|
-
/** @internal Built-in loopback UI only. */ async recordingImportList() {
|
|
62749
|
-
return await this.recording.recordingImportList();
|
|
64393
|
+
/** @internal Built-in loopback UI only. */ async recordingImportList(signal) {
|
|
64394
|
+
return await this.recording.recordingImportList(signal);
|
|
64395
|
+
}
|
|
64396
|
+
/** @internal Built-in loopback UI only. */ async recordingImportHistory(input, signal) {
|
|
64397
|
+
return await this.recording.recordingImportHistory(input, signal);
|
|
62750
64398
|
}
|
|
62751
64399
|
/** @internal Built-in loopback UI only. */ async retryRecordingImport(importRef, expectedRevision) {
|
|
62752
64400
|
return await this.recording.retryRecordingImport(importRef, expectedRevision);
|
|
@@ -62754,6 +64402,15 @@ var ArkmeService = class {
|
|
|
62754
64402
|
/** @internal Built-in loopback UI only. */ async cancelRecordingImport(importRef, expectedRevision) {
|
|
62755
64403
|
return await this.recording.cancelRecordingImport(importRef, expectedRevision);
|
|
62756
64404
|
}
|
|
64405
|
+
/** @internal Built-in loopback UI only. */ async updateRecordingImportSessionStart(sessionRef, startAtMillis, signal) {
|
|
64406
|
+
await this.recording.updateRecordingImportSessionStart(sessionRef, startAtMillis, signal);
|
|
64407
|
+
}
|
|
64408
|
+
/** @internal Built-in loopback UI only. */ async updateRecordingImportSessionOwnership(sessionRef, ownership, signal) {
|
|
64409
|
+
await this.recording.updateRecordingImportSessionOwnership(sessionRef, ownership, signal);
|
|
64410
|
+
}
|
|
64411
|
+
/** @internal Built-in loopback UI only. */ async deleteRecordingImportSession(sessionRef, signal) {
|
|
64412
|
+
await this.recording.deleteRecordingImportSession(sessionRef, signal);
|
|
64413
|
+
}
|
|
62757
64414
|
async resumeRecordingImports() {
|
|
62758
64415
|
await this.recording.resumeRecordingImports();
|
|
62759
64416
|
}
|
|
@@ -62835,8 +64492,14 @@ var ArkmeService = class {
|
|
|
62835
64492
|
async listSources(directory, options = {}) {
|
|
62836
64493
|
return await this.source.listSources(directory, options);
|
|
62837
64494
|
}
|
|
62838
|
-
async
|
|
62839
|
-
return await this.source.
|
|
64495
|
+
async setChatDirectoryPin(sourceRef, pinned, signal) {
|
|
64496
|
+
return await this.source.setChatDirectoryPin(sourceRef, pinned, signal);
|
|
64497
|
+
}
|
|
64498
|
+
async conversationDirectoryVisibilitySnapshot(sourceRefs, botRefs, signal) {
|
|
64499
|
+
return await this.conversationDirectoryVisibility.query(sourceRefs, botRefs, signal);
|
|
64500
|
+
}
|
|
64501
|
+
async setConversationDirectoryVisibility(entryKind, entryRef, hidden, signal) {
|
|
64502
|
+
await this.conversationDirectoryVisibility.setVisibility(entryKind, entryRef, hidden, signal);
|
|
62840
64503
|
}
|
|
62841
64504
|
async dshBetaCommunityEntryState(signal) {
|
|
62842
64505
|
return await this.community.dshBetaCommunityEntryState(signal);
|
|
@@ -62961,7 +64624,9 @@ var ArkmeService = class {
|
|
|
62961
64624
|
async openPrivateChatFromContact(contactRef, options = {}) {
|
|
62962
64625
|
const session = await this.runtime.requireSession();
|
|
62963
64626
|
const peerUserId = await this.contact.resolveRegisteredContactUserId(contactRef, session, options.signal);
|
|
62964
|
-
|
|
64627
|
+
const result = await this.chat.openPrivateChatFromUser(peerUserId, options);
|
|
64628
|
+
this.conversationDirectoryVisibility.restoreSource(result.source).catch(() => void 0);
|
|
64629
|
+
return result;
|
|
62965
64630
|
}
|
|
62966
64631
|
async officialAuthorProfile(signal) {
|
|
62967
64632
|
return await this.chat.officialAuthorProfile(signal === void 0 ? {} : { signal });
|
|
@@ -63015,6 +64680,18 @@ var ArkmeService = class {
|
|
|
63015
64680
|
async reportMessage(messageRef, reportType, options = {}) {
|
|
63016
64681
|
return await this.chat.reportMessage(messageRef, reportType, options);
|
|
63017
64682
|
}
|
|
64683
|
+
async withdrawGroupMessage(messageWithdrawalRef, options = {}) {
|
|
64684
|
+
return await this.chat.withdrawGroupMessage(messageWithdrawalRef, options);
|
|
64685
|
+
}
|
|
64686
|
+
async removeGroupMember(sourceRef, memberRef, options = {}) {
|
|
64687
|
+
return await this.chat.removeGroupMember(sourceRef, memberRef, options);
|
|
64688
|
+
}
|
|
64689
|
+
async listGroupJoinRestrictions(sourceRef, options = {}) {
|
|
64690
|
+
return await this.chat.listGroupJoinRestrictions(sourceRef, options);
|
|
64691
|
+
}
|
|
64692
|
+
async setGroupJoinRestriction(sourceRef, memberRef, restricted, options = {}) {
|
|
64693
|
+
return await this.chat.setGroupJoinRestriction(sourceRef, memberRef, restricted, options);
|
|
64694
|
+
}
|
|
63018
64695
|
async copySourceMessageLink(sourceRef, actionRefs, options = {}) {
|
|
63019
64696
|
return await this.chat.copySourceMessageLink(sourceRef, actionRefs, options);
|
|
63020
64697
|
}
|
|
@@ -63164,6 +64841,9 @@ var ArkmeService = class {
|
|
|
63164
64841
|
async searchRemote(options) {
|
|
63165
64842
|
return await this.search.searchRemote(options);
|
|
63166
64843
|
}
|
|
64844
|
+
async searchTagRecords(options) {
|
|
64845
|
+
return await this.search.searchTagRecords(options);
|
|
64846
|
+
}
|
|
63167
64847
|
async searchHistory(limit = 10) {
|
|
63168
64848
|
return await this.search.searchHistory(limit);
|
|
63169
64849
|
}
|
|
@@ -63339,6 +65019,9 @@ var ArkmeService = class {
|
|
|
63339
65019
|
await this.realtime.invalidateRecordProjection();
|
|
63340
65020
|
return result;
|
|
63341
65021
|
}
|
|
65022
|
+
async listRecordTags(limit = 100, signal) {
|
|
65023
|
+
return await this.record.listTags(limit, signal);
|
|
65024
|
+
}
|
|
63342
65025
|
async createTextForConversation(recordUid, textContent) {
|
|
63343
65026
|
const result = await this.record.createTextForConversation(recordUid, textContent);
|
|
63344
65027
|
if (result.localState !== "failed") await this.realtime.invalidateRecordProjection();
|
|
@@ -64939,4 +66622,4 @@ async function invokePersistentArkmeExtension(extensionId, method, args) {
|
|
|
64939
66622
|
return jsonValue(await handler(jsonValue(args)));
|
|
64940
66623
|
}
|
|
64941
66624
|
//#endregion
|
|
64942
|
-
export {
|
|
66625
|
+
export { ARKME_PROVIDER_CONTRACT_VERSION as $, inspectNativeBundleArtifactV3 as A, ARKME_EXTENSION_ICON_MAX_BYTES as B, ARKME_BUNDLE_MAX_BYTES as C, bundleSha256 as D, arkmeSandboxEntryId as E, assertExtensionArtifactSize as F, validateVoiceprintPcm16Wav as G, ARKME_EXTENSION_PREVIEW_MAX_BYTES as H, canonicalExtensionJson as I, arkmeIsGenericLinkMetadataTitle as J, isRecordingInstantOnOrAfterUnixEpoch as K, sha256Hex as L, packLocalNativeBundleDirectoryV3 as M, readNativeBundleTarballV3 as N, canonicalBundleJson as O, renderArkmeSandboxHostEntry as P, ARKME_DEFAULT_SHARE_WEBSITE as Q, unpackArkmeExtension as R, ARKME_BUNDLE_ARTIFACT_KIND as S, ArkmeBundleArtifactError as T, ARKME_EXTENSION_RUNTIME_UNAVAILABLE_MESSAGE as U, ARKME_EXTENSION_MAX_BYTES as V, ArkmeService as W, arkmeFileBackgroundSound as X, arkmeRequiredLinkMetadataFallback as Y, arkmeRichBackgroundSound as Z, arkmeClientContentDigest as _, SecretValue as _t, persistentArkmeExtensionActive as a, ARKME_RUNTIME_INSTANCE_ID as at, verifyExtensionResolutionSignature as b, persistentExtensionBundleDirectory as c, arkmeNormalizedFileMimeType as ct, readPersistentExtensionActivation as d, recordingImportFileKind as dt, ARKME_VOICEPRINT_ENROLLMENT_MAX_AUDIO_BYTES as et, refreshPersistentClientWrapper as f, sameRecordingImportIdentity as ft, activeProfileExtensionOwnerConflicts as g, ArkmeOutgoingCallError as gt, renderArkmeBundleClientBundle as h, ArkmePluginError as ht, invokePersistentArkmeExtension as i, ARKME_WORLD_PUBLISH_MAX_IMAGE_BYTES as it, packBundleFiles as j, inspectBundleArtifact as k, persistentExtensionPackageIdentity as l, arkmePickedFileKind as lt, writePersistentExtensionActivation as m, recordingImportFileNameKey as mt, applyPersistentArkmeHostExtension as n, ARKME_VOICEPRINT_ENROLLMENT_MIN_DURATION_MS as nt, persistentArkmeExtensionRuntimeState as o, ARKME_TOOL_FILE_MAX_BYTES as ot, repairPersistentExtensionInstallation as p, MAX_RECORDING_IMPORT_BYTES as pt, arkmeExtensionShareRefFromLink as q, deactivatePersistentArkmeExtension as r, ARKME_WORLD_PUBLISH_MAX_IMAGES as rt, materializePersistentExtensionBundle as s, arkmeCanInlineLocalFile as st, activatePersistentArkmeExtension as t, ARKME_VOICEPRINT_ENROLLMENT_MAX_DURATION_MS as tt, quarantinePersistentExtension as u, isArkmeBotAvatarRef as ut, arkmeClientContentDigestFromSource as v, ARKME_NATIVE_BUNDLE_ARTIFACT_KIND as w, verifyNativeBundleResolutionSignature as x, verifyBundleResolutionSignature as y, ARKME_EXTENSION_FORMAT as z };
|