@senguoyun/dsh-arkme 0.1.58 → 0.1.60
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/docs/dsh-input-system-topic.md +7 -3
- package/docs/plugin-release.md +1 -1
- package/lib/client.js +3479 -1686
- package/lib/client.js.map +1 -1
- package/lib/harness-sidebar-client.js +214 -23
- package/lib/index.js +51 -6
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-BnDj8qcY.js → persistent-runtime-DqPfc6RO.js} +411 -66
- package/lib/types/arkme-service.d.ts +3 -0
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeCalendarSurface.d.ts +22 -1
- package/lib/types/client/ArkmeCalendarSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeCallSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeDshMenu.d.ts +38 -0
- package/lib/types/client/ArkmeDshMenu.d.ts.map +1 -0
- package/lib/types/client/ArkmeGroupChatControls.d.ts +4 -0
- package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
- package/lib/types/client/ArkmeProductNavigation.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeSourceBreadcrumb.d.ts +6 -2
- package/lib/types/client/ArkmeSourceBreadcrumb.d.ts.map +1 -1
- package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts +4 -2
- package/lib/types/client/ArkmeTopicDirectoryPopover.d.ts.map +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/DeepSeekHarnessSurface.d.ts.map +1 -1
- package/lib/types/client/PrivateChatActions.d.ts +15 -3
- package/lib/types/client/PrivateChatActions.d.ts.map +1 -1
- package/lib/types/client/calendar-invalidation-store.d.ts +10 -1
- package/lib/types/client/calendar-invalidation-store.d.ts.map +1 -1
- package/lib/types/client/calendar-month-cache.d.ts +37 -0
- package/lib/types/client/calendar-month-cache.d.ts.map +1 -0
- package/lib/types/client/conversation-export.d.ts +18 -0
- package/lib/types/client/conversation-export.d.ts.map +1 -0
- package/lib/types/client/conversation-menu-layer.d.ts +27 -0
- package/lib/types/client/conversation-menu-layer.d.ts.map +1 -0
- package/lib/types/client/conversation-menu-scrollbars.d.ts +3 -0
- package/lib/types/client/conversation-menu-scrollbars.d.ts.map +1 -0
- package/lib/types/client/conversation-selector-style.d.ts +34 -0
- package/lib/types/client/conversation-selector-style.d.ts.map +1 -0
- package/lib/types/client/harness-session-dropdown.d.ts.map +1 -1
- package/lib/types/client/harness-session-hover.d.ts +1 -1
- package/lib/types/client/harness-session-hover.d.ts.map +1 -1
- package/lib/types/client/harness-session-menu-bridge.d.ts +2 -0
- package/lib/types/client/harness-session-menu-bridge.d.ts.map +1 -1
- package/lib/types/client/harness-surface-viewport.d.ts +7 -0
- package/lib/types/client/harness-surface-viewport.d.ts.map +1 -0
- package/lib/types/client/live-photo-playback.d.ts.map +1 -1
- package/lib/types/client/navigation-cache.d.ts +6 -1
- package/lib/types/client/navigation-cache.d.ts.map +1 -1
- package/lib/types/client/provider-instance-runtime.d.ts.map +1 -1
- package/lib/types/client/realtime-client-events.d.ts.map +1 -1
- package/lib/types/client/self-topic-directory-cache.d.ts +42 -0
- package/lib/types/client/self-topic-directory-cache.d.ts.map +1 -0
- package/lib/types/client/self-topic-expansion-preference.d.ts +23 -0
- package/lib/types/client/self-topic-expansion-preference.d.ts.map +1 -0
- package/lib/types/client/self-topic-menu-bridge.d.ts +20 -0
- package/lib/types/client/self-topic-menu-bridge.d.ts.map +1 -0
- package/lib/types/client/self-topic-menu-hover.d.ts +3 -0
- package/lib/types/client/self-topic-menu-hover.d.ts.map +1 -0
- package/lib/types/client/use-calendar-month.d.ts +4 -0
- package/lib/types/client/use-calendar-month.d.ts.map +1 -0
- package/lib/types/dsh-agent-input-source.d.ts +2 -0
- package/lib/types/dsh-agent-input-source.d.ts.map +1 -1
- package/lib/types/dsh-remote/session-persistence.d.ts +4 -0
- package/lib/types/dsh-remote/session-persistence.d.ts.map +1 -0
- package/lib/types/dsh-remote/transport-fragment.d.ts.map +1 -1
- package/lib/types/host-api.d.ts.map +1 -1
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/services/calendar-service.d.ts +10 -0
- package/lib/types/services/calendar-service.d.ts.map +1 -1
- package/lib/types/services/call-history-service.d.ts +4 -2
- package/lib/types/services/call-history-service.d.ts.map +1 -1
- package/lib/types/services/chat-realtime-service.d.ts +3 -1
- package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +3 -1
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/record-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts +5 -0
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/services/source-service.d.ts +3 -0
- package/lib/types/services/source-service.d.ts.map +1 -1
- package/lib/types/types.d.ts +3 -1
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1153,6 +1153,51 @@ var ServiceRuntime = class {
|
|
|
1153
1153
|
readRevision(scope) {
|
|
1154
1154
|
return this.readRevisions.get(scope) ?? 0;
|
|
1155
1155
|
}
|
|
1156
|
+
calendarRevisions = /* @__PURE__ */ new Map();
|
|
1157
|
+
calendarVersion(scope) {
|
|
1158
|
+
let value = this.calendarRevisions.get(scope);
|
|
1159
|
+
if (!value) {
|
|
1160
|
+
value = {
|
|
1161
|
+
epoch: 0,
|
|
1162
|
+
revision: 0,
|
|
1163
|
+
dates: /* @__PURE__ */ new Map()
|
|
1164
|
+
};
|
|
1165
|
+
this.calendarRevisions.set(scope, value);
|
|
1166
|
+
}
|
|
1167
|
+
return value;
|
|
1168
|
+
}
|
|
1169
|
+
calendarReadRevision(scope, start, end, timezone) {
|
|
1170
|
+
const value = this.calendarVersion(scope);
|
|
1171
|
+
const format = new Intl.DateTimeFormat("en-CA", {
|
|
1172
|
+
timeZone: timezone === "local" ? void 0 : timezone,
|
|
1173
|
+
year: "numeric",
|
|
1174
|
+
month: "2-digit",
|
|
1175
|
+
day: "2-digit"
|
|
1176
|
+
});
|
|
1177
|
+
let revision = 0;
|
|
1178
|
+
for (const [stamp, changed] of value.dates) {
|
|
1179
|
+
const day = format.format(new Date(stamp));
|
|
1180
|
+
if (day >= start && day <= end) revision = Math.max(revision, changed);
|
|
1181
|
+
}
|
|
1182
|
+
return `${value.epoch}:${revision}`;
|
|
1183
|
+
}
|
|
1184
|
+
/** Chat deltas invalidate only affected composite month results (in any timezone). */
|
|
1185
|
+
invalidateCalendarDates(scope, stamps) {
|
|
1186
|
+
const dates = [...new Set(stamps.filter((stamp) => Number.isFinite(stamp) && stamp > 0))];
|
|
1187
|
+
if (!dates.length) {
|
|
1188
|
+
this.invalidateKey(scope, "calendar:");
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
const value = this.calendarVersion(scope);
|
|
1192
|
+
if (value.dates.size + dates.length > 256) {
|
|
1193
|
+
value.epoch++;
|
|
1194
|
+
value.dates.clear();
|
|
1195
|
+
}
|
|
1196
|
+
for (const stamp of dates) value.dates.set(stamp, ++value.revision);
|
|
1197
|
+
this.readRevisions.set(scope, this.readRevision(scope) + 1);
|
|
1198
|
+
this.requestCoordinator.invalidateKey(scope, "calendar:");
|
|
1199
|
+
this.requestCoordinator.invalidateKey(scope, "owner-read:");
|
|
1200
|
+
}
|
|
1156
1201
|
async withOwnerReadInvalidation(route, operation) {
|
|
1157
1202
|
const session = await this.requireSession();
|
|
1158
1203
|
try {
|
|
@@ -1194,16 +1239,25 @@ var ServiceRuntime = class {
|
|
|
1194
1239
|
});
|
|
1195
1240
|
}
|
|
1196
1241
|
invalidateScope(scope) {
|
|
1242
|
+
const calendar = this.calendarVersion(scope);
|
|
1243
|
+
calendar.epoch++;
|
|
1244
|
+
calendar.dates.clear();
|
|
1197
1245
|
this.readRevisions.set(scope, this.readRevision(scope) + 1);
|
|
1198
1246
|
this.requestCoordinator.invalidateScope(scope);
|
|
1199
1247
|
}
|
|
1200
1248
|
invalidateKey(scope, key) {
|
|
1249
|
+
if (key.startsWith("calendar:")) {
|
|
1250
|
+
const calendar = this.calendarVersion(scope);
|
|
1251
|
+
calendar.epoch++;
|
|
1252
|
+
calendar.dates.clear();
|
|
1253
|
+
}
|
|
1201
1254
|
this.readRevisions.set(scope, this.readRevision(scope) + 1);
|
|
1202
1255
|
this.requestCoordinator.invalidateKey(scope, key);
|
|
1203
1256
|
this.requestCoordinator.invalidateKey(scope, "owner-read:");
|
|
1204
1257
|
}
|
|
1205
1258
|
dispose() {
|
|
1206
1259
|
this.refreshInFlightByUserId.clear();
|
|
1260
|
+
this.calendarRevisions.clear();
|
|
1207
1261
|
this.requestCoordinator.dispose();
|
|
1208
1262
|
}
|
|
1209
1263
|
async requireSession() {
|
|
@@ -35608,6 +35662,8 @@ var SourceService = class {
|
|
|
35608
35662
|
chatSourceCache = /* @__PURE__ */ new Map();
|
|
35609
35663
|
sourceListCache = /* @__PURE__ */ new Map();
|
|
35610
35664
|
sourceListInFlight = new SharedReadGroup();
|
|
35665
|
+
selfDirectoryContexts = /* @__PURE__ */ new Map();
|
|
35666
|
+
selfDirectoryContextReads = new SharedReadGroup();
|
|
35611
35667
|
groupAvatarSnapshotCache = /* @__PURE__ */ new Map();
|
|
35612
35668
|
topicDissolveProgress = /* @__PURE__ */ new Map();
|
|
35613
35669
|
constructor(runtime, profile, recordReader, privacy = new ArkmePrivacyVisibilityService(runtime)) {
|
|
@@ -35886,6 +35942,8 @@ var SourceService = class {
|
|
|
35886
35942
|
this.chatSourceCache.clear();
|
|
35887
35943
|
this.sourceListCache.clear();
|
|
35888
35944
|
this.sourceListInFlight.clear();
|
|
35945
|
+
this.selfDirectoryContexts.clear();
|
|
35946
|
+
this.selfDirectoryContextReads.clear();
|
|
35889
35947
|
this.groupAvatarSnapshotCache.clear();
|
|
35890
35948
|
this.topicDissolveProgress.clear();
|
|
35891
35949
|
}
|
|
@@ -36224,7 +36282,7 @@ var SourceService = class {
|
|
|
36224
36282
|
const movedParentUid = stringValue$2(moved.parent_topic_uid).trim();
|
|
36225
36283
|
const siblingOrder = numberValue$26(moved.sibling_order);
|
|
36226
36284
|
if (movedTopicUid !== topic.ownerRef || movedParentUid !== (nextParentUid ?? "") || siblingOrder <= 0) throw new ArkmePluginError("topic-hierarchy-move-contract-invalid", "主题移动响应不完整,请刷新后重试", true, 502);
|
|
36227
|
-
this.
|
|
36285
|
+
this.invalidateSourceListCache(session.userId, "send_to_self");
|
|
36228
36286
|
return {
|
|
36229
36287
|
sourceRef,
|
|
36230
36288
|
...nextParentSourceRef === void 0 ? {} : { parentSourceRef: nextParentSourceRef },
|
|
@@ -36286,6 +36344,10 @@ var SourceService = class {
|
|
|
36286
36344
|
options.signal?.throwIfAborted();
|
|
36287
36345
|
const limit = Math.min(directory === "send_to_self" ? 100 : 50, Math.max(1, Math.trunc(options.limit ?? 30)));
|
|
36288
36346
|
const cursor = options.cursor?.trim() ?? "";
|
|
36347
|
+
if (directory === "send_to_self" && options.refresh === true && cursor === "") {
|
|
36348
|
+
this.selfDirectoryContexts.delete(session.userId);
|
|
36349
|
+
this.selfDirectoryContextReads.invalidate((key) => key === String(session.userId));
|
|
36350
|
+
}
|
|
36289
36351
|
const cacheKey = `${String(session.userId)}:${directory}:${String(limit)}:${cursor}:${options.firstPaint === true ? "first" : "full"}`;
|
|
36290
36352
|
this.pruneSourceListCache();
|
|
36291
36353
|
const cached = this.sourceListCache.get(cacheKey);
|
|
@@ -36464,19 +36526,34 @@ var SourceService = class {
|
|
|
36464
36526
|
}
|
|
36465
36527
|
throw new ArkmePluginError("directory-groups-pagination-limit", "群聊列表超过安全分页上限", false, 502);
|
|
36466
36528
|
}
|
|
36529
|
+
async selfDirectoryContext(session, signal) {
|
|
36530
|
+
const cached = this.selfDirectoryContexts.get(session.userId);
|
|
36531
|
+
if (cached && cached.expiresAtMillis > Date.now()) return cached.value;
|
|
36532
|
+
return this.selfDirectoryContextReads.run(String(session.userId), async (inner, isCurrent) => {
|
|
36533
|
+
const [hierarchyData, [summaryResult, latestRecordsResult]] = await Promise.all([this.runtime.authenticatedPost("/api/v1/topics/hierarchy/relations/list", {}, session, inner).catch(() => void 0), Promise.allSettled([this.recordReader.summary(), this.runtime.authenticatedPost("/api/v1/records/uncategorized/query", { limit: 10 }, session, inner)])]);
|
|
36534
|
+
const value = {
|
|
36535
|
+
hierarchyData,
|
|
36536
|
+
summaryResult,
|
|
36537
|
+
latestRecordsResult
|
|
36538
|
+
};
|
|
36539
|
+
if (isCurrent()) this.selfDirectoryContexts.set(session.userId, {
|
|
36540
|
+
value,
|
|
36541
|
+
expiresAtMillis: Date.now() + SOURCE_LIST_CACHE_TTL_MS
|
|
36542
|
+
});
|
|
36543
|
+
return value;
|
|
36544
|
+
}, signal);
|
|
36545
|
+
}
|
|
36467
36546
|
async listSourcesUncached(session, directory, options, limit, sessionKind) {
|
|
36468
36547
|
if (directory === "send_to_self") {
|
|
36469
36548
|
const lockedRecordUids = await this.privacy.lockedRecordUids(session, options.signal);
|
|
36470
36549
|
const topicPage = options.cursor === void 0 || options.cursor.trim() === "" ? void 0 : this.decodeTopicDirectoryCursor(options.cursor);
|
|
36471
|
-
const [data, hierarchyData] = await Promise.all([this.runtime.authenticatedPost("/api/v1/topics/display/list", {
|
|
36550
|
+
const [data, { hierarchyData, summaryResult, latestRecordsResult }] = await Promise.all([this.runtime.authenticatedPost("/api/v1/topics/display/list", {
|
|
36472
36551
|
limit: Math.min(100, Math.max(1, limit)),
|
|
36473
36552
|
keyword: "",
|
|
36474
36553
|
privacy_state: 1,
|
|
36475
36554
|
...topicPage?.pageCursor === void 0 ? {} : { page_cursor: topicPage.pageCursor },
|
|
36476
36555
|
...topicPage?.offset === void 0 ? {} : { offset: topicPage.offset }
|
|
36477
|
-
}, session, options.signal), this.
|
|
36478
|
-
options.signal?.throwIfAborted();
|
|
36479
|
-
const [summaryResult, latestRecordsResult] = await Promise.allSettled([this.recordReader.summary(), this.runtime.authenticatedPost("/api/v1/records/uncategorized/query", { limit: 10 }, session, options.signal)]);
|
|
36556
|
+
}, session, options.signal), this.selfDirectoryContext(session, options.signal)]);
|
|
36480
36557
|
options.signal?.throwIfAborted();
|
|
36481
36558
|
const cached = summaryResult.status === "rejected" || latestRecordsResult.status === "rejected" ? await this.runtime.stateStore.cachedSnapshot(session.userId).catch(() => void 0) : void 0;
|
|
36482
36559
|
const defaultRecordCount = summaryResult.status === "fulfilled" ? summaryResult.value.recordCount : cached?.summary?.recordCount;
|
|
@@ -36512,6 +36589,7 @@ var SourceService = class {
|
|
|
36512
36589
|
const item = objectValue$2(raw);
|
|
36513
36590
|
if (arkmePrivacyLockedTopic(item)) continue;
|
|
36514
36591
|
const core = objectValue$2(item.topic_core);
|
|
36592
|
+
if (numberValue$26(core.kind) === 3) continue;
|
|
36515
36593
|
const status = core.status ?? item.status;
|
|
36516
36594
|
if (status !== void 0 && numberValue$26(status) !== 1) continue;
|
|
36517
36595
|
const summary = objectValue$2(item.summary);
|
|
@@ -36690,6 +36768,10 @@ var SourceService = class {
|
|
|
36690
36768
|
};
|
|
36691
36769
|
}
|
|
36692
36770
|
invalidateSourceListCache(userId, directory) {
|
|
36771
|
+
if (directory === void 0 || directory === "send_to_self") {
|
|
36772
|
+
this.selfDirectoryContexts.delete(userId);
|
|
36773
|
+
this.selfDirectoryContextReads.invalidate((key) => key === String(userId));
|
|
36774
|
+
}
|
|
36693
36775
|
if (directory === void 0 || directory === "root") this.runtime.invalidateKey(this.runtime.requestScope(userId), "directory:root:");
|
|
36694
36776
|
const prefix = `${String(userId)}:`;
|
|
36695
36777
|
const matches = (key) => key.startsWith(prefix) && (directory === void 0 || key.startsWith(`${prefix}${directory}:`));
|
|
@@ -37879,10 +37961,29 @@ var BotConversationService = class {
|
|
|
37879
37961
|
return context.reference.target.kind === "subject" ? this.subject : this.chatAdapter;
|
|
37880
37962
|
}
|
|
37881
37963
|
};
|
|
37964
|
+
/** Authoritative wire fields only: ordinary topics may have the same title. */
|
|
37965
|
+
function isDshAgentInputRawRecord(raw) {
|
|
37966
|
+
const object = (value) => value !== null && typeof value === "object" ? value : {};
|
|
37967
|
+
const item = object(raw);
|
|
37968
|
+
const core = object(item.record_core);
|
|
37969
|
+
const topic = object(item.topic_core);
|
|
37970
|
+
return Number(item.creation_source ?? item.creationSource ?? core.creation_source ?? core.creationSource) === 3 || Number(topic.kind ?? item.topicKind) === 3;
|
|
37971
|
+
}
|
|
37882
37972
|
//#endregion
|
|
37883
37973
|
//#region src/services/calendar-service.ts
|
|
37884
37974
|
const MAX_CALENDAR_RANGE_DAYS = 62;
|
|
37885
37975
|
const MAX_DAY_RECORD_LIMIT = 50;
|
|
37976
|
+
async function mapBounded(items, project) {
|
|
37977
|
+
const result = new Array(items.length);
|
|
37978
|
+
let index = 0;
|
|
37979
|
+
await Promise.all(Array.from({ length: Math.min(4, items.length) }, async () => {
|
|
37980
|
+
while (index < items.length) {
|
|
37981
|
+
const current = index++;
|
|
37982
|
+
result[current] = await project(items[current]);
|
|
37983
|
+
}
|
|
37984
|
+
}));
|
|
37985
|
+
return result;
|
|
37986
|
+
}
|
|
37886
37987
|
function numberValue$23(value) {
|
|
37887
37988
|
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
37888
37989
|
}
|
|
@@ -37943,6 +38044,12 @@ var CalendarService = class {
|
|
|
37943
38044
|
media;
|
|
37944
38045
|
record;
|
|
37945
38046
|
source;
|
|
38047
|
+
months = /* @__PURE__ */ new Map();
|
|
38048
|
+
monthReads = new SharedReadGroup();
|
|
38049
|
+
dispose() {
|
|
38050
|
+
this.months.clear();
|
|
38051
|
+
this.monthReads.clear();
|
|
38052
|
+
}
|
|
37946
38053
|
constructor(runtime, privacy, media, record, source) {
|
|
37947
38054
|
this.runtime = runtime;
|
|
37948
38055
|
this.privacy = privacy;
|
|
@@ -37951,6 +38058,44 @@ var CalendarService = class {
|
|
|
37951
38058
|
this.source = source;
|
|
37952
38059
|
}
|
|
37953
38060
|
async bucketPage(options) {
|
|
38061
|
+
options.signal?.throwIfAborted();
|
|
38062
|
+
const session = await this.runtime.requireSession();
|
|
38063
|
+
const timezone = readTimezone(options.timezone);
|
|
38064
|
+
const key = JSON.stringify([
|
|
38065
|
+
session.userId,
|
|
38066
|
+
options.sourceRef ?? "global",
|
|
38067
|
+
options.startDate,
|
|
38068
|
+
options.endDate,
|
|
38069
|
+
timezone
|
|
38070
|
+
]);
|
|
38071
|
+
const revision = () => this.runtime.calendarReadRevision?.(`user:${session.userId}`, options.startDate, options.endDate, timezone) ?? "0";
|
|
38072
|
+
const version = revision();
|
|
38073
|
+
const cached = this.months.get(key);
|
|
38074
|
+
if (cached && cached.revision === version && cached.expires > Date.now()) {
|
|
38075
|
+
this.months.delete(key);
|
|
38076
|
+
this.months.set(key, cached);
|
|
38077
|
+
return structuredClone(cached.value);
|
|
38078
|
+
}
|
|
38079
|
+
return structuredClone(await this.monthReads.run(`${key}:${version}`, async (signal, isCurrent) => {
|
|
38080
|
+
const value = await this.bucketPageUncached({
|
|
38081
|
+
...options,
|
|
38082
|
+
timezone,
|
|
38083
|
+
signal
|
|
38084
|
+
});
|
|
38085
|
+
signal.throwIfAborted();
|
|
38086
|
+
if (isCurrent() && revision() === version) {
|
|
38087
|
+
this.months.delete(key);
|
|
38088
|
+
this.months.set(key, {
|
|
38089
|
+
revision: version,
|
|
38090
|
+
expires: Date.now() + 6e4,
|
|
38091
|
+
value
|
|
38092
|
+
});
|
|
38093
|
+
while (this.months.size > 48) this.months.delete(this.months.keys().next().value);
|
|
38094
|
+
}
|
|
38095
|
+
return value;
|
|
38096
|
+
}, options.signal));
|
|
38097
|
+
}
|
|
38098
|
+
async bucketPageUncached(options) {
|
|
37954
38099
|
const startDate = readCalendarDate(options.startDate, "start_date");
|
|
37955
38100
|
const endDate = readCalendarDate(options.endDate, "end_date");
|
|
37956
38101
|
const startDay = calendarDayNumber(startDate);
|
|
@@ -37959,25 +38104,60 @@ var CalendarService = class {
|
|
|
37959
38104
|
if (endDay - startDay + 1 > MAX_CALENDAR_RANGE_DAYS) throw new ArkmePluginError("calendar-range-too-wide", `日历范围最多查询 ${MAX_CALENDAR_RANGE_DAYS} 天`, false);
|
|
37960
38105
|
const timezone = readTimezone(options.timezone);
|
|
37961
38106
|
const session = await this.runtime.requireSession();
|
|
37962
|
-
await this.privacy.lockedRecordUids(session, options.signal);
|
|
37963
|
-
const
|
|
37964
|
-
|
|
37965
|
-
|
|
37966
|
-
|
|
37967
|
-
|
|
37968
|
-
|
|
37969
|
-
|
|
37970
|
-
|
|
37971
|
-
|
|
37972
|
-
|
|
38107
|
+
const locked = await this.privacy.lockedRecordUids(session, options.signal);
|
|
38108
|
+
const scope = await this.resolveScope(options.sourceRef, session, options.signal);
|
|
38109
|
+
const pages = await mapBounded(scope.buckets, async (bucket) => {
|
|
38110
|
+
return {
|
|
38111
|
+
bucket,
|
|
38112
|
+
days: listValue$20((await this.runtime.authenticatedCalendarPost("/api/v1/calendar/buckets/query", {
|
|
38113
|
+
bucket_scope_kind: bucket.kind,
|
|
38114
|
+
bucket_scope_uid: bucket.uid,
|
|
38115
|
+
start_date: startDate,
|
|
38116
|
+
end_date: endDate,
|
|
38117
|
+
timezone
|
|
38118
|
+
}, session, options.signal, {
|
|
38119
|
+
key: `calendar:buckets:${bucket.kind === 1 ? "self" : `topic:${bucket.uid}`}:${startDate}:${endDate}:${timezone}`,
|
|
38120
|
+
cacheMs: 3e4,
|
|
38121
|
+
lane: options.background ? "background-read" : "interactive-read",
|
|
38122
|
+
failureCooldownMs: 2e3
|
|
38123
|
+
})).daily_data).map((raw) => this.bucketDay(raw)).filter((day) => day !== void 0)
|
|
38124
|
+
};
|
|
38125
|
+
});
|
|
38126
|
+
const days = await mapBounded([...new Set(pages.flatMap((page) => page.days.map((day) => day.bucketDate)))].sort(), async (bucketDate) => {
|
|
38127
|
+
const contributors = pages.flatMap((page) => {
|
|
38128
|
+
const day = page.days.find((day) => day.bucketDate === bucketDate);
|
|
38129
|
+
return day?.hasRecords ? [{
|
|
38130
|
+
bucket: page.bucket,
|
|
38131
|
+
day
|
|
38132
|
+
}] : [];
|
|
38133
|
+
});
|
|
38134
|
+
if (scope.kind === "self") return contributors[0]?.day ?? {
|
|
38135
|
+
bucketDate,
|
|
38136
|
+
count: 0,
|
|
38137
|
+
protectedCount: 0,
|
|
38138
|
+
hasRecords: false
|
|
38139
|
+
};
|
|
38140
|
+
const records = /* @__PURE__ */ new Map();
|
|
38141
|
+
for (const { bucket } of contributors) {
|
|
38142
|
+
const rows = await this.scopedDayRows(bucket, scope.kind, bucketDate, timezone, Infinity, void 0, session, locked, options.signal, options.background);
|
|
38143
|
+
for (const { item } of rows) records.set(item.recordUid, item);
|
|
38144
|
+
}
|
|
38145
|
+
const first = Math.min(...[...records.values()].map((item) => item.sendAtMillis));
|
|
38146
|
+
return {
|
|
38147
|
+
bucketDate,
|
|
38148
|
+
count: records.size,
|
|
38149
|
+
protectedCount: 0,
|
|
38150
|
+
hasRecords: records.size > 0,
|
|
38151
|
+
...Number.isFinite(first) ? { firstSendAtMillis: first } : {}
|
|
38152
|
+
};
|
|
37973
38153
|
});
|
|
37974
38154
|
return {
|
|
37975
|
-
scope:
|
|
38155
|
+
scope: scope.kind,
|
|
37976
38156
|
startDate,
|
|
37977
38157
|
endDate,
|
|
37978
|
-
timezone
|
|
38158
|
+
timezone,
|
|
37979
38159
|
refreshedAtMillis: Date.now(),
|
|
37980
|
-
days
|
|
38160
|
+
days
|
|
37981
38161
|
};
|
|
37982
38162
|
}
|
|
37983
38163
|
async dayRecords(options) {
|
|
@@ -37988,7 +38168,21 @@ var CalendarService = class {
|
|
|
37988
38168
|
const cursorRecordUid = options.cursor?.recordUid.trim() ?? "";
|
|
37989
38169
|
const session = await this.runtime.requireSession();
|
|
37990
38170
|
const lockedRecordUids = await this.privacy.lockedRecordUids(session, options.signal);
|
|
37991
|
-
const
|
|
38171
|
+
const scope = await this.resolveScope(options.sourceRef, session, options.signal);
|
|
38172
|
+
let data;
|
|
38173
|
+
if (scope.kind !== "self") {
|
|
38174
|
+
const streams = await mapBounded(scope.buckets, (bucket) => this.scopedDayRows(bucket, scope.kind, bucketDate, timezone, limit + 1, options.cursor, session, lockedRecordUids, options.signal));
|
|
38175
|
+
const sorted = [...new Map(streams.flat().map((row) => [row.item.recordUid, row])).values()].sort((a, b) => b.item.sendAtMillis - a.item.sendAtMillis || b.item.recordUid.localeCompare(a.item.recordUid));
|
|
38176
|
+
const last = sorted[Math.min(limit, sorted.length) - 1]?.item;
|
|
38177
|
+
data = {
|
|
38178
|
+
items: sorted.slice(0, limit).map((row) => row.raw),
|
|
38179
|
+
has_more: sorted.length > limit,
|
|
38180
|
+
...sorted.length > limit && last ? {
|
|
38181
|
+
next_cursor_send_at: last.sendAtMillis,
|
|
38182
|
+
next_cursor_record_uid: last.recordUid
|
|
38183
|
+
} : {}
|
|
38184
|
+
};
|
|
38185
|
+
} else data = await this.runtime.authenticatedCalendarPost("/api/v1/calendar/records/query", {
|
|
37992
38186
|
bucket_scope_kind: 1,
|
|
37993
38187
|
bucket_scope_uid: "",
|
|
37994
38188
|
bucket_date: bucketDate,
|
|
@@ -38034,7 +38228,7 @@ var CalendarService = class {
|
|
|
38034
38228
|
}
|
|
38035
38229
|
const media = await this.media.hydrateRecordMediaPage(rows.filter((row) => row.item.accessState === "available").map((row) => row.raw), session, options.signal);
|
|
38036
38230
|
return {
|
|
38037
|
-
scope:
|
|
38231
|
+
scope: scope.kind,
|
|
38038
38232
|
bucketDate,
|
|
38039
38233
|
timezone: stringValue$2(data.timezone).trim() || timezone,
|
|
38040
38234
|
refreshedAtMillis: Date.now(),
|
|
@@ -38064,6 +38258,96 @@ var CalendarService = class {
|
|
|
38064
38258
|
} } : {}
|
|
38065
38259
|
};
|
|
38066
38260
|
}
|
|
38261
|
+
async resolveScope(sourceRef, session, signal) {
|
|
38262
|
+
if (sourceRef === void 0) return {
|
|
38263
|
+
kind: "self",
|
|
38264
|
+
buckets: [{
|
|
38265
|
+
kind: 1,
|
|
38266
|
+
uid: ""
|
|
38267
|
+
}]
|
|
38268
|
+
};
|
|
38269
|
+
const source = await this.source.openSourceRef(sourceRef, session.userId);
|
|
38270
|
+
if (source.kind === "send_to_self") return {
|
|
38271
|
+
kind: "send_to_self",
|
|
38272
|
+
buckets: [{
|
|
38273
|
+
kind: 1,
|
|
38274
|
+
uid: ""
|
|
38275
|
+
}]
|
|
38276
|
+
};
|
|
38277
|
+
if (source.kind === "default_category") return {
|
|
38278
|
+
kind: "uncategorized",
|
|
38279
|
+
buckets: [{
|
|
38280
|
+
kind: 1,
|
|
38281
|
+
uid: ""
|
|
38282
|
+
}]
|
|
38283
|
+
};
|
|
38284
|
+
if (source.kind !== "topic") throw new ArkmePluginError("calendar-source-invalid", "此日历仅支持发给自己和主题", false, 400);
|
|
38285
|
+
const metadata = await readTopicMetadata(this.runtime, session, source.ownerRef, signal);
|
|
38286
|
+
if (metadata.privacyState === 2) throw new ArkmePluginError("topic-privacy-locked", "隐私锁主题不能在 Arkme 插件中查看", false, 403);
|
|
38287
|
+
if (metadata.topicKind === 3) return {
|
|
38288
|
+
kind: "topic",
|
|
38289
|
+
buckets: []
|
|
38290
|
+
};
|
|
38291
|
+
return {
|
|
38292
|
+
kind: "topic",
|
|
38293
|
+
buckets: (await mapBounded(await this.source.topicSubtreeSources(sourceRef, signal), async (topic) => {
|
|
38294
|
+
const opened = await this.source.openSourceRef(topic.sourceRef, session.userId);
|
|
38295
|
+
const meta = opened.ownerRef === source.ownerRef ? metadata : await readTopicMetadata(this.runtime, session, opened.ownerRef, signal);
|
|
38296
|
+
return meta.privacyState === 2 || meta.topicKind === 3 ? [] : [{
|
|
38297
|
+
kind: 2,
|
|
38298
|
+
uid: opened.ownerRef
|
|
38299
|
+
}];
|
|
38300
|
+
})).flat()
|
|
38301
|
+
};
|
|
38302
|
+
}
|
|
38303
|
+
/** Read only one calendar day; backfill filtered rows and reject stalled cursors. */
|
|
38304
|
+
async scopedDayRows(bucket, scope, bucketDate, timezone, count, cursor, session, locked, signal, background = false) {
|
|
38305
|
+
const rows = /* @__PURE__ */ new Map();
|
|
38306
|
+
const visited = /* @__PURE__ */ new Set();
|
|
38307
|
+
for (let page = 0; page < 1e3; page++) {
|
|
38308
|
+
signal?.throwIfAborted();
|
|
38309
|
+
const key = `${cursor?.sendAtMillis ?? 0}:${cursor?.recordUid ?? ""}`;
|
|
38310
|
+
if (visited.has(key)) throw new ArkmePluginError("calendar-cursor-invalid", "日历分页未推进,请重试", true, 502);
|
|
38311
|
+
visited.add(key);
|
|
38312
|
+
const data = await this.runtime.authenticatedCalendarPost("/api/v1/calendar/records/query", {
|
|
38313
|
+
bucket_scope_kind: bucket.kind,
|
|
38314
|
+
bucket_scope_uid: bucket.uid,
|
|
38315
|
+
bucket_date: bucketDate,
|
|
38316
|
+
timezone,
|
|
38317
|
+
limit: MAX_DAY_RECORD_LIMIT,
|
|
38318
|
+
...cursor ? {
|
|
38319
|
+
cursor_send_at: cursor.sendAtMillis,
|
|
38320
|
+
cursor_record_uid: cursor.recordUid
|
|
38321
|
+
} : {}
|
|
38322
|
+
}, session, signal, {
|
|
38323
|
+
key: `calendar:records:${bucket.kind === 1 ? "self" : `topic:${bucket.uid}`}:${bucketDate}:${timezone}:50:${key}`,
|
|
38324
|
+
cacheMs: 1e4,
|
|
38325
|
+
failureCooldownMs: 2e3,
|
|
38326
|
+
lane: background ? "background-read" : "interactive-read"
|
|
38327
|
+
});
|
|
38328
|
+
for (const raw of listValue$20(data.items)) {
|
|
38329
|
+
const item = this.dayRecord(raw);
|
|
38330
|
+
if (!item || locked.has(item.recordUid)) continue;
|
|
38331
|
+
if (isDshAgentInputRawRecord(raw)) continue;
|
|
38332
|
+
if (scope === "uncategorized" && item.isUncategorized !== true) continue;
|
|
38333
|
+
if (scope === "send_to_self" && item.sourceKind !== "self" && item.sourceKind !== "topic") continue;
|
|
38334
|
+
rows.set(item.recordUid, {
|
|
38335
|
+
raw,
|
|
38336
|
+
item
|
|
38337
|
+
});
|
|
38338
|
+
if (rows.size >= count) return [...rows.values()];
|
|
38339
|
+
}
|
|
38340
|
+
if (data.has_more !== true) return [...rows.values()];
|
|
38341
|
+
const sendAtMillis = Math.trunc(numberValue$23(data.next_cursor_send_at));
|
|
38342
|
+
const recordUid = stringValue$2(data.next_cursor_record_uid).trim();
|
|
38343
|
+
if (sendAtMillis <= 0 || recordUid === "") throw new ArkmePluginError("calendar-cursor-invalid", "日历分页信息缺失,请重试", true, 502);
|
|
38344
|
+
cursor = {
|
|
38345
|
+
sendAtMillis,
|
|
38346
|
+
recordUid
|
|
38347
|
+
};
|
|
38348
|
+
}
|
|
38349
|
+
throw new ArkmePluginError("calendar-pagination-limit", "日历当日记录尚未加载完整,请重试", true, 502);
|
|
38350
|
+
}
|
|
38067
38351
|
bucketDay(raw) {
|
|
38068
38352
|
const item = objectValue$2(raw);
|
|
38069
38353
|
const bucketDate = stringValue$2(item.bucket_date).trim();
|
|
@@ -38103,7 +38387,7 @@ var CalendarService = class {
|
|
|
38103
38387
|
preview,
|
|
38104
38388
|
...stringValue$2(topic.title).trim() === "" ? {} : { topicTitle: stringValue$2(topic.title).trim() },
|
|
38105
38389
|
sourceKind: sourceKind(item),
|
|
38106
|
-
creationSource: Math.trunc(numberValue$23(core.creation_source)),
|
|
38390
|
+
creationSource: isDshAgentInputRawRecord(raw) ? 3 : Math.trunc(numberValue$23(core.creation_source)),
|
|
38107
38391
|
templateKind: Math.trunc(numberValue$23(core.template_kind)),
|
|
38108
38392
|
displayKind: Math.trunc(numberValue$23(core.display_kind)),
|
|
38109
38393
|
protected: false,
|
|
@@ -38669,10 +38953,12 @@ var CallHistoryService = class {
|
|
|
38669
38953
|
runtime;
|
|
38670
38954
|
profile;
|
|
38671
38955
|
media;
|
|
38672
|
-
|
|
38956
|
+
source;
|
|
38957
|
+
constructor(runtime, profile, media, source) {
|
|
38673
38958
|
this.runtime = runtime;
|
|
38674
38959
|
this.profile = profile;
|
|
38675
38960
|
this.media = media;
|
|
38961
|
+
this.source = source;
|
|
38676
38962
|
}
|
|
38677
38963
|
async listCallHistory(options = {}, signal) {
|
|
38678
38964
|
const session = await this.runtime.requireSession();
|
|
@@ -38688,7 +38974,7 @@ var CallHistoryService = class {
|
|
|
38688
38974
|
failureCooldownMs: 2e3
|
|
38689
38975
|
});
|
|
38690
38976
|
const validItems = (await Promise.all(this.historyItems(raw).map(async (item) => await this.normalizeHistoryItem(item, session.userId)))).filter((item) => item !== void 0);
|
|
38691
|
-
await this.
|
|
38977
|
+
await this.attachPeerPresentation(validItems, session, signal);
|
|
38692
38978
|
const hasMore = booleanValue$9(raw.has_more ?? raw.hasMore);
|
|
38693
38979
|
const nextCursor = firstString$1(raw, [
|
|
38694
38980
|
"next_cursor",
|
|
@@ -38931,16 +39217,18 @@ var CallHistoryService = class {
|
|
|
38931
39217
|
return [];
|
|
38932
39218
|
}
|
|
38933
39219
|
}
|
|
38934
|
-
async
|
|
39220
|
+
async attachPeerPresentation(items, session, signal) {
|
|
38935
39221
|
const ids = [...new Set(items.flatMap((item) => item.peerUserId === void 0 ? [] : [item.peerUserId]))];
|
|
38936
39222
|
if (ids.length === 0) return;
|
|
38937
|
-
const profiles = await this.profile.
|
|
39223
|
+
const [profiles, remarks] = await Promise.all([this.profile.publicProfileSummariesByUserIds(ids, session, signal).catch(() => /* @__PURE__ */ new Map()), this.source?.privateRemarksByUserIds(ids, signal === void 0 ? {} : { signal }).catch(() => /* @__PURE__ */ new Map()) ?? Promise.resolve(/* @__PURE__ */ new Map())]);
|
|
38938
39224
|
await Promise.all(items.map(async (item) => {
|
|
38939
39225
|
const peerUserId = item.peerUserId;
|
|
38940
39226
|
if (peerUserId === void 0) return;
|
|
38941
39227
|
const profile = profiles.get(peerUserId);
|
|
38942
39228
|
const displayName = profile?.displayName?.trim() ?? "";
|
|
38943
|
-
|
|
39229
|
+
const remark = remarks.get(peerUserId)?.trim() ?? "";
|
|
39230
|
+
if (remark !== "") item.peerDisplayName = remark;
|
|
39231
|
+
else if (displayName !== "" && /^Arkme 用户 \d+$/.test(item.peerDisplayName.trim())) item.peerDisplayName = displayName;
|
|
38944
39232
|
if (profile?.avatarUrl === void 0) return;
|
|
38945
39233
|
item.peerAvatarRef = await this.profile.sealProfileImageRef(session.userId, peerUserId);
|
|
38946
39234
|
}));
|
|
@@ -40337,7 +40625,7 @@ var ChatRealtimeService = class {
|
|
|
40337
40625
|
console.warn("dsh-arkme: Chat read receipt invalidation failed:", safeFailureMessage$5(error));
|
|
40338
40626
|
}
|
|
40339
40627
|
}
|
|
40340
|
-
async invalidateRecordProjection() {
|
|
40628
|
+
async invalidateRecordProjection(options = {}) {
|
|
40341
40629
|
try {
|
|
40342
40630
|
const session = await this.runtime.sessionStore.read();
|
|
40343
40631
|
if (session === void 0) return;
|
|
@@ -40346,7 +40634,8 @@ var ChatRealtimeService = class {
|
|
|
40346
40634
|
this.emitChatClientEvent({
|
|
40347
40635
|
type: "projection-invalidated",
|
|
40348
40636
|
revision: this.nextChatClientRevision(),
|
|
40349
|
-
projection: "record"
|
|
40637
|
+
projection: "record",
|
|
40638
|
+
...options.contentOnly ? { retainTopicCounts: true } : {}
|
|
40350
40639
|
});
|
|
40351
40640
|
} catch (error) {
|
|
40352
40641
|
console.warn("dsh-arkme: Record projection invalidation failed:", safeFailureMessage$5(error));
|
|
@@ -40971,7 +41260,7 @@ var ChatRealtimeService = class {
|
|
|
40971
41260
|
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
40972
41261
|
if (updates.length > 0) {
|
|
40973
41262
|
this.source.invalidateSourceListCache(session.userId, "root");
|
|
40974
|
-
this.runtime.
|
|
41263
|
+
this.runtime.invalidateCalendarDates(this.runtime.requestScope(session.userId), updates.flatMap((update) => [update.source.activeAtMillis, ...update.timelineItems.map((item) => item.sendAtMillis)]));
|
|
40975
41264
|
this.emitChatClientEvent({
|
|
40976
41265
|
type: "sessions-delta",
|
|
40977
41266
|
revision: this.nextChatClientRevision(),
|
|
@@ -41860,7 +42149,6 @@ function numberValue$20(value) {
|
|
|
41860
42149
|
function listValue$17(value) {
|
|
41861
42150
|
return Array.isArray(value) ? value : [];
|
|
41862
42151
|
}
|
|
41863
|
-
const DSH_AGENT_INPUT_CREATION_SOURCE = 3;
|
|
41864
42152
|
const MAX_DEFAULT_CATEGORY_FILTER_BACKFILL_PAGES = 5;
|
|
41865
42153
|
const RECORD_REEDIT_SUPPORTED_TEMPLATE_KINDS = /* @__PURE__ */ new Set([
|
|
41866
42154
|
1,
|
|
@@ -41882,7 +42170,7 @@ function recordCreationSource(raw) {
|
|
|
41882
42170
|
return integerLikeValue$1(item.creation_source ?? item.creationSource ?? core.creation_source ?? core.creationSource);
|
|
41883
42171
|
}
|
|
41884
42172
|
function isDSHAgentInputRecord(raw) {
|
|
41885
|
-
return
|
|
42173
|
+
return isDshAgentInputRawRecord(raw);
|
|
41886
42174
|
}
|
|
41887
42175
|
function safeFailureMessage$4(error) {
|
|
41888
42176
|
if (error instanceof ArkmePluginError) return error.message;
|
|
@@ -43784,7 +44072,11 @@ function snapshotDetailFromChatRaw(raw, fallback) {
|
|
|
43784
44072
|
...position,
|
|
43785
44073
|
...objectValue$2(values.position)
|
|
43786
44074
|
});
|
|
43787
|
-
const locationLabel = firstSnapshotText(
|
|
44075
|
+
const locationLabel = firstSnapshotText([
|
|
44076
|
+
[firstSnapshotText(position.city)?.replace(/市$/, ""), firstSnapshotText(position.county)?.replace(/(区|县|市)$/, "")].filter(Boolean).join("·"),
|
|
44077
|
+
firstSnapshotText(position.road),
|
|
44078
|
+
firstSnapshotText(position.poi, position.poi_name, position.poiName)
|
|
44079
|
+
].join(""), position.address, location.poi_name, location.poiName, location.address, location.name);
|
|
43788
44080
|
const weather = snapshotWeatherText(position.weather, position.weatherText, location.weather, values.weather);
|
|
43789
44081
|
const altitudeMeters = nonNegativeNumberValue(location.altitude, location.alt, position.altitude, position.alt);
|
|
43790
44082
|
const movement = snapshotMovement({
|
|
@@ -45022,9 +45314,13 @@ var ChatService = class {
|
|
|
45022
45314
|
const opened = await this.source.openSourceRef(topic.sourceRef, session.userId);
|
|
45023
45315
|
if (opened.kind !== "topic") throw new ArkmePluginError("topic-subtree-source-invalid", "下级主题信息无效,请刷新后重试", true, 409);
|
|
45024
45316
|
const records = [];
|
|
45317
|
+
const visited = /* @__PURE__ */ new Set();
|
|
45025
45318
|
let pageCursor = cursor;
|
|
45026
45319
|
for (let pageIndex = 0; pageIndex < 100; pageIndex += 1) {
|
|
45027
45320
|
signal?.throwIfAborted();
|
|
45321
|
+
const key = JSON.stringify(pageCursor ?? {});
|
|
45322
|
+
if (visited.has(key)) throw new ArkmePluginError("topic-record-page-invalid", "主题快记分页未推进,请重试", true, 502);
|
|
45323
|
+
visited.add(key);
|
|
45028
45324
|
const page = await readTopicRecordPage(this.runtime, session, opened.ownerRef, {
|
|
45029
45325
|
limit,
|
|
45030
45326
|
...pageCursor === void 0 ? {} : { cursor: pageCursor },
|
|
@@ -45039,24 +45335,35 @@ var ChatService = class {
|
|
|
45039
45335
|
hasMore: false
|
|
45040
45336
|
};
|
|
45041
45337
|
}
|
|
45338
|
+
let filtered = false;
|
|
45042
45339
|
for (const raw of page.records) {
|
|
45043
|
-
if (arkmePrivacyLockedRecord(raw) || lockedRecordUids.has(this.record.recordUid(raw)))
|
|
45340
|
+
if (isDshAgentInputRawRecord(raw) || arkmePrivacyLockedRecord(raw) || lockedRecordUids.has(this.record.recordUid(raw))) {
|
|
45341
|
+
filtered = true;
|
|
45342
|
+
continue;
|
|
45343
|
+
}
|
|
45044
45344
|
records.push(raw);
|
|
45045
45345
|
}
|
|
45046
|
-
if (!merged) return {
|
|
45346
|
+
if (!merged && !filtered && records.length <= limit) return {
|
|
45047
45347
|
topic,
|
|
45048
45348
|
topicUid: opened.ownerRef,
|
|
45049
45349
|
records,
|
|
45050
45350
|
hasMore: page.hasMore,
|
|
45051
45351
|
...page.nextCursor === void 0 ? {} : { nextCursor: page.nextCursor }
|
|
45052
45352
|
};
|
|
45053
|
-
if (records.length >= limit)
|
|
45054
|
-
|
|
45055
|
-
|
|
45056
|
-
|
|
45057
|
-
|
|
45058
|
-
|
|
45059
|
-
|
|
45353
|
+
if (records.length >= limit) {
|
|
45354
|
+
const last = objectValue$2(records[limit - 1]);
|
|
45355
|
+
const nextCursor = records.length > limit ? {
|
|
45356
|
+
sendAtMillis: numberValue$19(last.send_at ?? objectValue$2(last.record_core).send_at),
|
|
45357
|
+
itemUid: this.record.recordUid(last)
|
|
45358
|
+
} : page.nextCursor;
|
|
45359
|
+
return {
|
|
45360
|
+
topic,
|
|
45361
|
+
topicUid: opened.ownerRef,
|
|
45362
|
+
records: records.slice(0, limit),
|
|
45363
|
+
hasMore: records.length > limit || page.hasMore,
|
|
45364
|
+
...nextCursor === void 0 ? {} : { nextCursor }
|
|
45365
|
+
};
|
|
45366
|
+
}
|
|
45060
45367
|
if (!page.hasMore) return {
|
|
45061
45368
|
topic,
|
|
45062
45369
|
topicUid: opened.ownerRef,
|
|
@@ -45095,13 +45402,55 @@ var ChatService = class {
|
|
|
45095
45402
|
const limit = Math.min(100, Math.max(1, Math.trunc(options.limit ?? 30)));
|
|
45096
45403
|
if (source.kind === "send_to_self") {
|
|
45097
45404
|
const lockedRecordUids = await this.privacy.lockedRecordUids(session, options.signal);
|
|
45098
|
-
const
|
|
45099
|
-
|
|
45100
|
-
|
|
45101
|
-
|
|
45102
|
-
|
|
45103
|
-
|
|
45104
|
-
|
|
45405
|
+
const rawRecords = [];
|
|
45406
|
+
const seen = /* @__PURE__ */ new Set();
|
|
45407
|
+
const visited = /* @__PURE__ */ new Set();
|
|
45408
|
+
let cursor = options.cursor;
|
|
45409
|
+
let hasMore = false;
|
|
45410
|
+
let nextCursor;
|
|
45411
|
+
for (let pageIndex = 0; pageIndex < 100; pageIndex++) {
|
|
45412
|
+
options.signal?.throwIfAborted();
|
|
45413
|
+
const key = `${cursor?.sendAtMillis ?? 0}:${cursor?.itemUid ?? ""}`;
|
|
45414
|
+
if (visited.has(key)) throw new ArkmePluginError("self-feed-cursor-invalid", "发给自己分页未推进,请重试", true, 502);
|
|
45415
|
+
visited.add(key);
|
|
45416
|
+
const data = await this.runtime.authenticatedPost("/api/v1/home/feed/query", {
|
|
45417
|
+
limit,
|
|
45418
|
+
source_kinds: [1, 2],
|
|
45419
|
+
...cursor?.sendAtMillis === void 0 ? {} : { cursor_send_at: cursor.sendAtMillis },
|
|
45420
|
+
...cursor?.itemUid === void 0 ? {} : { cursor_record_uid: cursor.itemUid }
|
|
45421
|
+
}, session, options.signal);
|
|
45422
|
+
const rows = listValue$16(data.items);
|
|
45423
|
+
let filtered = false;
|
|
45424
|
+
for (const raw of rows) {
|
|
45425
|
+
const uid = this.record.recordUid(raw);
|
|
45426
|
+
if (isDshAgentInputRawRecord(raw) || arkmePrivacyLockedRecord(raw) || lockedRecordUids.has(uid) || seen.has(uid)) {
|
|
45427
|
+
filtered = true;
|
|
45428
|
+
continue;
|
|
45429
|
+
}
|
|
45430
|
+
seen.add(uid);
|
|
45431
|
+
rawRecords.push(raw);
|
|
45432
|
+
}
|
|
45433
|
+
hasMore = data.has_more === true;
|
|
45434
|
+
const nextSendAt = numberValue$19(data.next_cursor_send_at);
|
|
45435
|
+
const nextUid = stringValue$2(data.next_cursor_record_uid).trim();
|
|
45436
|
+
nextCursor = nextSendAt > 0 && nextUid !== "" ? {
|
|
45437
|
+
sendAtMillis: nextSendAt,
|
|
45438
|
+
itemUid: nextUid
|
|
45439
|
+
} : void 0;
|
|
45440
|
+
if (rawRecords.length >= limit || !hasMore || !filtered) break;
|
|
45441
|
+
if (!nextCursor) throw new ArkmePluginError("self-feed-cursor-invalid", "发给自己分页信息缺失,请重试", true, 502);
|
|
45442
|
+
cursor = nextCursor;
|
|
45443
|
+
if (pageIndex === 99) throw new ArkmePluginError("self-feed-pagination-limit", "发给自己加载未完成,请重试", true, 502);
|
|
45444
|
+
}
|
|
45445
|
+
if (rawRecords.length > limit) {
|
|
45446
|
+
rawRecords.length = limit;
|
|
45447
|
+
const last = objectValue$2(rawRecords.at(-1));
|
|
45448
|
+
nextCursor = {
|
|
45449
|
+
sendAtMillis: numberValue$19(last.send_at ?? objectValue$2(last.record_core).send_at),
|
|
45450
|
+
itemUid: this.record.recordUid(last)
|
|
45451
|
+
};
|
|
45452
|
+
hasMore = true;
|
|
45453
|
+
}
|
|
45105
45454
|
const media = await this.media.hydrateRecordMediaPage(rawRecords, session, options.signal);
|
|
45106
45455
|
const signingKey = await this.runtime.stateStore.uniqueCode();
|
|
45107
45456
|
const items = (await Promise.all(rawRecords.map(async (raw) => {
|
|
@@ -45132,16 +45481,11 @@ var ChatService = class {
|
|
|
45132
45481
|
}))).filter((item) => item.itemUid !== "");
|
|
45133
45482
|
this.hydrateTimelineExtensionParents(items);
|
|
45134
45483
|
const projectedItems = items.map((item) => this.withRecordMessageActionRef(source, item, session.userId, signingKey));
|
|
45135
|
-
const nextSendAt = numberValue$19(data.next_cursor_send_at);
|
|
45136
|
-
const nextUid = stringValue$2(data.next_cursor_record_uid).trim();
|
|
45137
45484
|
return {
|
|
45138
45485
|
source: await this.source.sourceItem(source),
|
|
45139
45486
|
items: projectedItems,
|
|
45140
|
-
hasMore
|
|
45141
|
-
...
|
|
45142
|
-
sendAtMillis: nextSendAt,
|
|
45143
|
-
itemUid: nextUid
|
|
45144
|
-
} } : {}
|
|
45487
|
+
hasMore,
|
|
45488
|
+
...nextCursor === void 0 ? {} : { nextCursor }
|
|
45145
45489
|
};
|
|
45146
45490
|
}
|
|
45147
45491
|
if (source.kind === "default_category") {
|
|
@@ -46247,7 +46591,7 @@ var ChatService = class {
|
|
|
46247
46591
|
const publishedRecordUid = stringValue$2(data.record_uid).trim() || createdRecordUid;
|
|
46248
46592
|
const senderDisplayName = profile.nickname.trim() || profile.displayName.trim() || "我";
|
|
46249
46593
|
const senderAvatarUrl = profile.avatarRef.trim();
|
|
46250
|
-
await this.realtime.invalidateRecordProjection();
|
|
46594
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46251
46595
|
return {
|
|
46252
46596
|
sid: detail.sid,
|
|
46253
46597
|
recordUid: publishedRecordUid,
|
|
@@ -46342,7 +46686,7 @@ var ChatService = class {
|
|
|
46342
46686
|
content_payload: contentPayload,
|
|
46343
46687
|
send_at: Date.now()
|
|
46344
46688
|
}, session, options.signal);
|
|
46345
|
-
await this.realtime.invalidateRecordProjection();
|
|
46689
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46346
46690
|
return await appendCommentWarning({
|
|
46347
46691
|
sourceRef: targetSourceRef,
|
|
46348
46692
|
itemUid: stringValue$2(data.record_uid).trim() || recordUid,
|
|
@@ -46358,7 +46702,7 @@ var ChatService = class {
|
|
|
46358
46702
|
content_payload: contentPayload,
|
|
46359
46703
|
send_at: Date.now()
|
|
46360
46704
|
}, session, options.signal);
|
|
46361
|
-
await this.realtime.invalidateRecordProjection();
|
|
46705
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46362
46706
|
return await appendCommentWarning({
|
|
46363
46707
|
sourceRef: targetSourceRef,
|
|
46364
46708
|
itemUid: stringValue$2(data.record_uid).trim() || recordUid,
|
|
@@ -46381,7 +46725,7 @@ var ChatService = class {
|
|
|
46381
46725
|
...options.recordDurationMillis === void 0 ? {} : { recordDurationMillis: options.recordDurationMillis },
|
|
46382
46726
|
...options.captureContext === void 0 ? {} : { captureContext: options.captureContext }
|
|
46383
46727
|
});
|
|
46384
|
-
if (result.localState !== "failed") await this.realtime.invalidateRecordProjection();
|
|
46728
|
+
if (result.localState !== "failed") await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46385
46729
|
return await this.withConfirmedSendReferences({
|
|
46386
46730
|
sourceRef,
|
|
46387
46731
|
itemUid: result.recordUid,
|
|
@@ -46414,7 +46758,7 @@ var ChatService = class {
|
|
|
46414
46758
|
send_at: sendAtMillis
|
|
46415
46759
|
}, session);
|
|
46416
46760
|
await this.record.syncCreatedRecordTags?.(stringValue$2(result.record_uid).trim() || recordUid, text, session.userId);
|
|
46417
|
-
await this.realtime.invalidateRecordProjection();
|
|
46761
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46418
46762
|
return await this.withConfirmedSendReferences({
|
|
46419
46763
|
sourceRef,
|
|
46420
46764
|
itemUid: stringValue$2(result.record_uid).trim() || recordUid,
|
|
@@ -46785,7 +47129,7 @@ var ChatService = class {
|
|
|
46785
47129
|
if (source.kind === "send_to_self" || source.kind === "default_category") {
|
|
46786
47130
|
const result = await this.runtime.authenticatedPost("/api/v1/records/create", commonBody, session, options.signal, { trackWriteOutcome: true });
|
|
46787
47131
|
await this.record.syncCreatedRecordTags?.(stringValue$2(result.record_uid).trim() || recordUid, textContent, session.userId, options.signal, input.textFormat);
|
|
46788
|
-
await this.realtime.invalidateRecordProjection();
|
|
47132
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46789
47133
|
return await this.withConfirmedSendReferences({
|
|
46790
47134
|
sourceRef,
|
|
46791
47135
|
itemUid: stringValue$2(result.record_uid).trim() || recordUid,
|
|
@@ -46810,7 +47154,7 @@ var ChatService = class {
|
|
|
46810
47154
|
...commonBody
|
|
46811
47155
|
}, session, options.signal, { trackWriteOutcome: true });
|
|
46812
47156
|
await this.record.syncCreatedRecordTags?.(stringValue$2(result.record_uid).trim() || recordUid, textContent, session.userId, options.signal, input.textFormat);
|
|
46813
|
-
await this.realtime.invalidateRecordProjection();
|
|
47157
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
46814
47158
|
return await this.withConfirmedSendReferences({
|
|
46815
47159
|
sourceRef,
|
|
46816
47160
|
itemUid: stringValue$2(result.record_uid).trim() || recordUid,
|
|
@@ -89513,7 +89857,7 @@ var ArkmeService = class {
|
|
|
89513
89857
|
this.arrangement = new ArrangementService(this.runtime);
|
|
89514
89858
|
this.wechat = new WechatService(this.runtime);
|
|
89515
89859
|
this.profile = new ProfileService(this.runtime);
|
|
89516
|
-
this.callHistory = new CallHistoryService(this.runtime, this.profile, { forwardContentBlocks: (files, viewerUserId) => this.media.forwardContentBlocks(files, viewerUserId) });
|
|
89860
|
+
this.callHistory = new CallHistoryService(this.runtime, this.profile, { forwardContentBlocks: (files, viewerUserId) => this.media.forwardContentBlocks(files, viewerUserId) }, { privateRemarksByUserIds: (userIds, options) => this.source.privateRemarksByUserIds(userIds, options) });
|
|
89517
89861
|
this.extensionReview = new ExtensionReviewService(this.runtime, this.profile, { createTextForConversation: async (recordUid, textContent) => {
|
|
89518
89862
|
return await this.createTextForConversation(recordUid, textContent);
|
|
89519
89863
|
} });
|
|
@@ -89675,6 +90019,7 @@ var ArkmeService = class {
|
|
|
89675
90019
|
return await this.backgroundSoundPreferenceOwner.update(enabled, signal, expectedUserId);
|
|
89676
90020
|
}
|
|
89677
90021
|
clearAccountState(userIds) {
|
|
90022
|
+
this.calendar.dispose();
|
|
89678
90023
|
this.directory.reset();
|
|
89679
90024
|
this.realtime.resetAttentionSummary();
|
|
89680
90025
|
for (const userId of userIds) this.privacy.clear(userId);
|
|
@@ -90903,7 +91248,7 @@ var ArkmeService = class {
|
|
|
90903
91248
|
}
|
|
90904
91249
|
async createText(recordUid, textContent) {
|
|
90905
91250
|
const result = await this.record.createText(recordUid, textContent);
|
|
90906
|
-
await this.realtime.invalidateRecordProjection();
|
|
91251
|
+
await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
90907
91252
|
return result;
|
|
90908
91253
|
}
|
|
90909
91254
|
async listRecordTags(limit = 100, signal) {
|
|
@@ -90911,7 +91256,7 @@ var ArkmeService = class {
|
|
|
90911
91256
|
}
|
|
90912
91257
|
async createTextForConversation(recordUid, textContent) {
|
|
90913
91258
|
const result = await this.record.createTextForConversation(recordUid, textContent);
|
|
90914
|
-
if (result.localState !== "failed") await this.realtime.invalidateRecordProjection();
|
|
91259
|
+
if (result.localState !== "failed") await this.realtime.invalidateRecordProjection({ contentOnly: true });
|
|
90915
91260
|
return result;
|
|
90916
91261
|
}
|
|
90917
91262
|
async createDSHAgentInputText(recordUid, textContent, sendAtMillis) {
|