@senguoyun/dsh-arkme 0.1.78 → 0.1.80
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/reaction-desktop-review.md +33 -0
- package/docs/reaction-pre-merge-review.md +78 -0
- package/lib/client.js +15141 -10588
- package/lib/client.js.map +1 -1
- package/lib/harness-model-client.js +19 -3
- package/lib/harness-native-selection-client.js +19 -3
- package/lib/harness-sidebar-client.js +165 -16
- package/lib/index.js +112 -1
- package/lib/persistent-extension.js +1 -1
- package/lib/{persistent-runtime-aiHgSAmj.js → persistent-runtime-CGclHTN1.js} +1196 -272
- package/lib/sdk.js +8 -0
- package/lib/types/arkme-service.d.ts +10 -0
- package/lib/types/arkme-service.d.ts.map +1 -1
- package/lib/types/client/ArkmeAccountCancellation.d.ts +8 -0
- package/lib/types/client/ArkmeAccountCancellation.d.ts.map +1 -0
- package/lib/types/client/ArkmeDataManagementSettings.d.ts.map +1 -1
- package/lib/types/client/ArkmeDayTimeline.d.ts +2 -0
- package/lib/types/client/ArkmeDayTimeline.d.ts.map +1 -1
- package/lib/types/client/ArkmeGroupChatControls.d.ts.map +1 -1
- package/lib/types/client/ArkmeLogin.d.ts +3 -0
- package/lib/types/client/ArkmeLogin.d.ts.map +1 -1
- package/lib/types/client/ArkmePersonalDayCalendar.d.ts.map +1 -1
- package/lib/types/client/ArkmeReactionActorCard.d.ts +7 -0
- package/lib/types/client/ArkmeReactionActorCard.d.ts.map +1 -0
- package/lib/types/client/ArkmeReactionHistorySettings.d.ts +7 -0
- package/lib/types/client/ArkmeReactionHistorySettings.d.ts.map +1 -0
- package/lib/types/client/ArkmeReactionNotification.d.ts +11 -0
- package/lib/types/client/ArkmeReactionNotification.d.ts.map +1 -0
- package/lib/types/client/ArkmeReactionPhrases.d.ts +8 -0
- package/lib/types/client/ArkmeReactionPhrases.d.ts.map +1 -0
- package/lib/types/client/ArkmeReactionPreview.d.ts +42 -0
- package/lib/types/client/ArkmeReactionPreview.d.ts.map +1 -0
- package/lib/types/client/ArkmeRecordingSurface.d.ts +2 -1
- package/lib/types/client/ArkmeRecordingSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeRichComposerInput.d.ts.map +1 -1
- package/lib/types/client/ArkmeSearchSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSettingsSurface.d.ts +5 -0
- package/lib/types/client/ArkmeSettingsSurface.d.ts.map +1 -1
- package/lib/types/client/ArkmeSidebar.d.ts.map +1 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts +2 -1
- package/lib/types/client/ArkmeVirtualWorkspace.d.ts.map +1 -1
- package/lib/types/client/ReactionLabel.d.ts +8 -0
- package/lib/types/client/ReactionLabel.d.ts.map +1 -0
- package/lib/types/client/ReactionPhraseDialog.d.ts +14 -0
- package/lib/types/client/ReactionPhraseDialog.d.ts.map +1 -0
- package/lib/types/client/arkme-auth-flow.d.ts.map +1 -1
- package/lib/types/client/arkme-login-locales.d.ts +6 -0
- package/lib/types/client/arkme-login-locales.d.ts.map +1 -1
- package/lib/types/client/auth-store.d.ts.map +1 -1
- package/lib/types/client/calendar-activity-model.d.ts +1 -1
- package/lib/types/client/calendar-activity-model.d.ts.map +1 -1
- package/lib/types/client/composer-draft-store.d.ts +6 -1
- package/lib/types/client/composer-draft-store.d.ts.map +1 -1
- package/lib/types/client/conversation-window-sync.d.ts.map +1 -1
- package/lib/types/client/harness-account-sessions.d.ts +6 -0
- package/lib/types/client/harness-account-sessions.d.ts.map +1 -1
- package/lib/types/client/harness-session-dropdown.d.ts.map +1 -1
- package/lib/types/client/harness-session-origin.d.ts +2 -1
- package/lib/types/client/harness-session-origin.d.ts.map +1 -1
- package/lib/types/client/harness-session-summary.d.ts +11 -2
- package/lib/types/client/harness-session-summary.d.ts.map +1 -1
- package/lib/types/client/locales/actions-en.d.ts.map +1 -1
- package/lib/types/client/outgoing-call-runtime.d.ts.map +1 -1
- package/lib/types/client/reaction-expression.d.ts +5 -0
- package/lib/types/client/reaction-expression.d.ts.map +1 -0
- package/lib/types/client/reaction-label-content.d.ts +20 -0
- package/lib/types/client/reaction-label-content.d.ts.map +1 -0
- package/lib/types/client/reaction-library.d.ts +26 -0
- package/lib/types/client/reaction-library.d.ts.map +1 -0
- package/lib/types/client/reaction-locate-layout.d.ts +5 -0
- package/lib/types/client/reaction-locate-layout.d.ts.map +1 -0
- package/lib/types/client/reaction-notifications.d.ts +49 -0
- package/lib/types/client/reaction-notifications.d.ts.map +1 -0
- package/lib/types/client/reaction-phrase-palette.d.ts +99 -0
- package/lib/types/client/reaction-phrase-palette.d.ts.map +1 -0
- package/lib/types/client/reaction-phrases.d.ts +7 -0
- package/lib/types/client/reaction-phrases.d.ts.map +1 -0
- package/lib/types/client/reaction-preview-store.d.ts +70 -0
- package/lib/types/client/reaction-preview-store.d.ts.map +1 -0
- package/lib/types/client/reaction-visible-target.d.ts +3 -0
- package/lib/types/client/reaction-visible-target.d.ts.map +1 -0
- package/lib/types/client/record-input-capture.d.ts +2 -0
- package/lib/types/client/record-input-capture.d.ts.map +1 -1
- package/lib/types/client/recordings/RecordingSearchRow.d.ts +5 -0
- package/lib/types/client/recordings/RecordingSearchRow.d.ts.map +1 -0
- package/lib/types/client/recordings/recording-search-target.d.ts +4 -0
- package/lib/types/client/recordings/recording-search-target.d.ts.map +1 -0
- package/lib/types/client/redesign/styles.d.ts.map +1 -1
- package/lib/types/client/ui-controller.d.ts +5 -6
- package/lib/types/client/ui-controller.d.ts.map +1 -1
- package/lib/types/client/use-phrase-layout-motion.d.ts +2 -0
- package/lib/types/client/use-phrase-layout-motion.d.ts.map +1 -0
- package/lib/types/client/use-reaction-history.d.ts +10 -0
- package/lib/types/client/use-reaction-history.d.ts.map +1 -0
- package/lib/types/client/use-reaction-phrase-drag.d.ts +19 -0
- package/lib/types/client/use-reaction-phrase-drag.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/local-database.d.ts +2 -0
- package/lib/types/local-database.d.ts.map +1 -1
- package/lib/types/reaction-contract.d.ts +217 -0
- package/lib/types/reaction-contract.d.ts.map +1 -0
- package/lib/types/recording-presentation.d.ts +1 -0
- package/lib/types/recording-presentation.d.ts.map +1 -1
- package/lib/types/recording-search-result.d.ts +3 -0
- package/lib/types/recording-search-result.d.ts.map +1 -0
- package/lib/types/recording-search-version.d.ts +17 -0
- package/lib/types/recording-search-version.d.ts.map +1 -0
- package/lib/types/sdk/index.d.ts +2 -0
- package/lib/types/sdk/index.d.ts.map +1 -1
- package/lib/types/services/auth-service.d.ts +20 -1
- package/lib/types/services/auth-service.d.ts.map +1 -1
- package/lib/types/services/chat-realtime-service.d.ts.map +1 -1
- package/lib/types/services/chat-service.d.ts +6 -0
- package/lib/types/services/chat-service.d.ts.map +1 -1
- package/lib/types/services/profile-service.d.ts +1 -1
- package/lib/types/services/profile-service.d.ts.map +1 -1
- package/lib/types/services/reaction-service.d.ts +28 -0
- package/lib/types/services/reaction-service.d.ts.map +1 -0
- package/lib/types/services/recording-import-gateway.d.ts +3 -1
- package/lib/types/services/recording-import-gateway.d.ts.map +1 -1
- package/lib/types/services/recording-import-upload-retry.d.ts +6 -0
- package/lib/types/services/recording-import-upload-retry.d.ts.map +1 -0
- package/lib/types/services/recording-service.d.ts.map +1 -1
- package/lib/types/services/search-service.d.ts +3 -1
- package/lib/types/services/search-service.d.ts.map +1 -1
- package/lib/types/services/service.d.ts +3 -0
- package/lib/types/services/service.d.ts.map +1 -1
- package/lib/types/services/world-service.d.ts +3 -0
- package/lib/types/services/world-service.d.ts.map +1 -1
- package/lib/types/state-store.d.ts +7 -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/reactions.d.ts +3 -0
- package/lib/types/tools/business/conversation/reactions.d.ts.map +1 -0
- package/lib/types/tools/business/index.d.ts.map +1 -1
- package/lib/types/tools/ports/conversations.d.ts +1 -0
- package/lib/types/tools/ports/conversations.d.ts.map +1 -1
- package/lib/types/tools/registry/registrar.d.ts.map +1 -1
- package/lib/types/types.d.ts +46 -2
- package/lib/types/types.d.ts.map +1 -1
- package/package.json +5 -5
|
@@ -1296,6 +1296,9 @@ var ServiceRuntime = class {
|
|
|
1296
1296
|
async deleteSession() {
|
|
1297
1297
|
await this.accountSessions.delete();
|
|
1298
1298
|
}
|
|
1299
|
+
async deleteSessionIfCurrent(expected) {
|
|
1300
|
+
return await this.accountSessions.deleteIfCurrent(expected);
|
|
1301
|
+
}
|
|
1299
1302
|
async moveSessionToPendingBinding(expected) {
|
|
1300
1303
|
return await this.accountSessions.deleteIfCurrent(expected, async (current) => {
|
|
1301
1304
|
await this.writePendingBindingSession(current);
|
|
@@ -1948,6 +1951,372 @@ var ServiceRuntime = class {
|
|
|
1948
1951
|
}
|
|
1949
1952
|
};
|
|
1950
1953
|
//#endregion
|
|
1954
|
+
//#region src/services/reaction-service.ts
|
|
1955
|
+
function invalid$11() {
|
|
1956
|
+
throw new ArkmePluginError("reaction-response-invalid", "表态数据不完整,请重试", true);
|
|
1957
|
+
}
|
|
1958
|
+
function integer$4(value, min = 0) {
|
|
1959
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= min ? value : invalid$11();
|
|
1960
|
+
}
|
|
1961
|
+
function expression(raw) {
|
|
1962
|
+
const value = objectValue$2(raw);
|
|
1963
|
+
if (typeof value.text !== "string" || Array.from(value.text).length > 20) return invalid$11();
|
|
1964
|
+
const result = { text: value.text };
|
|
1965
|
+
for (const key of [
|
|
1966
|
+
"emoji",
|
|
1967
|
+
"hand",
|
|
1968
|
+
"color"
|
|
1969
|
+
]) if (value[key] !== void 0) {
|
|
1970
|
+
if (typeof value[key] !== "string" || value[key].length > 64) return invalid$11();
|
|
1971
|
+
result[key] = value[key];
|
|
1972
|
+
}
|
|
1973
|
+
return result;
|
|
1974
|
+
}
|
|
1975
|
+
function array(raw, max) {
|
|
1976
|
+
return Array.isArray(raw) && raw.length <= max ? raw : invalid$11();
|
|
1977
|
+
}
|
|
1978
|
+
function key(raw) {
|
|
1979
|
+
return typeof raw === "string" && /^[a-f0-9]{64}$/.test(raw) ? raw : invalid$11();
|
|
1980
|
+
}
|
|
1981
|
+
function group(raw) {
|
|
1982
|
+
const value = objectValue$2(raw);
|
|
1983
|
+
return {
|
|
1984
|
+
key: key(value.key),
|
|
1985
|
+
expression: expression(value.expression),
|
|
1986
|
+
count: integer$4(value.count, 1),
|
|
1987
|
+
actorIds: array(value.actor_user_ids ?? [], 3).map((id) => integer$4(id, 1))
|
|
1988
|
+
};
|
|
1989
|
+
}
|
|
1990
|
+
function state(raw) {
|
|
1991
|
+
const value = objectValue$2(raw);
|
|
1992
|
+
return {
|
|
1993
|
+
revision: integer$4(value.revision),
|
|
1994
|
+
selections: array(value.selections, 56).map((raw) => {
|
|
1995
|
+
const item = objectValue$2(raw);
|
|
1996
|
+
return {
|
|
1997
|
+
key: key(item.key),
|
|
1998
|
+
expression: expression(item.expression),
|
|
1999
|
+
at: integer$4(item.at)
|
|
2000
|
+
};
|
|
2001
|
+
})
|
|
2002
|
+
};
|
|
2003
|
+
}
|
|
2004
|
+
function library(raw) {
|
|
2005
|
+
const value = objectValue$2(raw);
|
|
2006
|
+
return {
|
|
2007
|
+
revision: integer$4(value.revision),
|
|
2008
|
+
items: array(value.items, 58).map(expression)
|
|
2009
|
+
};
|
|
2010
|
+
}
|
|
2011
|
+
function boolean(raw) {
|
|
2012
|
+
return typeof raw === "boolean" ? raw : invalid$11();
|
|
2013
|
+
}
|
|
2014
|
+
function targetKey(target) {
|
|
2015
|
+
return JSON.stringify([
|
|
2016
|
+
target.chat_session_uid ?? "",
|
|
2017
|
+
target.rel_uid ?? "",
|
|
2018
|
+
target.record_uid ?? "",
|
|
2019
|
+
target.owned === true
|
|
2020
|
+
]);
|
|
2021
|
+
}
|
|
2022
|
+
/** One Host owner for Browser, SDK and granted Tools; identities are resolved from signed message references. */
|
|
2023
|
+
var ReactionService = class {
|
|
2024
|
+
runtime;
|
|
2025
|
+
resolve;
|
|
2026
|
+
worldReference;
|
|
2027
|
+
chatSourceKey;
|
|
2028
|
+
historyContext;
|
|
2029
|
+
constructor(runtime, resolve, worldReference, chatSourceKey, historyContext) {
|
|
2030
|
+
this.runtime = runtime;
|
|
2031
|
+
this.resolve = resolve;
|
|
2032
|
+
this.worldReference = worldReference;
|
|
2033
|
+
this.chatSourceKey = chatSourceKey;
|
|
2034
|
+
this.historyContext = historyContext;
|
|
2035
|
+
}
|
|
2036
|
+
async request(input, signal) {
|
|
2037
|
+
const session = await this.runtime.requireSession();
|
|
2038
|
+
const accountKey = `${this.runtime.config.environment}:${session.userId}`;
|
|
2039
|
+
if (!input || input.accountKey !== accountKey) throw new ArkmePluginError("reaction-account-changed", "账号已变化,请重新打开表态", false);
|
|
2040
|
+
let path, body;
|
|
2041
|
+
const ids = /* @__PURE__ */ new Map();
|
|
2042
|
+
const resolve = async (target) => {
|
|
2043
|
+
if (!target || typeof target.id !== "string" || !target.id || target.id.length > 1024 || !(typeof target.worldRecordRef === "string" && !target.sourceRef && !target.messageActionRef || !target.worldRecordRef && typeof target.sourceRef === "string" && typeof target.messageActionRef === "string")) throw new ArkmePluginError("reaction-target-invalid", "表态目标无效", false);
|
|
2044
|
+
return await this.resolve(target);
|
|
2045
|
+
};
|
|
2046
|
+
switch (input.action) {
|
|
2047
|
+
case "notifications":
|
|
2048
|
+
path = "notifications/query";
|
|
2049
|
+
body = {
|
|
2050
|
+
after_id: input.after_id ?? "",
|
|
2051
|
+
limit: input.limit
|
|
2052
|
+
};
|
|
2053
|
+
break;
|
|
2054
|
+
case "notifications-read":
|
|
2055
|
+
if (!Array.isArray(input.items) || input.items.length < 1 || input.items.length > 50) return invalid$11();
|
|
2056
|
+
path = "notifications/read";
|
|
2057
|
+
body = { items: input.items.map((item) => ({
|
|
2058
|
+
id: key(item.id),
|
|
2059
|
+
revision: integer$4(item.revision, 1)
|
|
2060
|
+
})) };
|
|
2061
|
+
break;
|
|
2062
|
+
case "query": {
|
|
2063
|
+
if (!Array.isArray(input.targets) || input.targets.length < 1 || input.targets.length > 50) throw new ArkmePluginError("reaction-query-invalid", "表态查询数量无效", false);
|
|
2064
|
+
const targets = [], seenIDs = /* @__PURE__ */ new Set();
|
|
2065
|
+
for (const target of input.targets) {
|
|
2066
|
+
const wire = await resolve(target), key = targetKey(wire);
|
|
2067
|
+
if (seenIDs.has(target.id)) throw new ArkmePluginError("reaction-query-duplicate", "表态目标重复", false);
|
|
2068
|
+
seenIDs.add(target.id);
|
|
2069
|
+
const aliases = ids.get(key);
|
|
2070
|
+
if (aliases) aliases.push(target.id);
|
|
2071
|
+
else {
|
|
2072
|
+
ids.set(key, [target.id]);
|
|
2073
|
+
targets.push(wire);
|
|
2074
|
+
}
|
|
2075
|
+
}
|
|
2076
|
+
path = "query";
|
|
2077
|
+
body = { targets };
|
|
2078
|
+
break;
|
|
2079
|
+
}
|
|
2080
|
+
case "set":
|
|
2081
|
+
if (typeof input.active !== "boolean") throw new ArkmePluginError("reaction-state-invalid", "缺少表态状态", false);
|
|
2082
|
+
path = "set";
|
|
2083
|
+
body = {
|
|
2084
|
+
target: await resolve(input.target),
|
|
2085
|
+
expression: input.expression,
|
|
2086
|
+
active: input.active,
|
|
2087
|
+
expected_revision: input.expected_revision,
|
|
2088
|
+
request_id: input.request_id
|
|
2089
|
+
};
|
|
2090
|
+
break;
|
|
2091
|
+
case "actors":
|
|
2092
|
+
path = "actors/query";
|
|
2093
|
+
body = {
|
|
2094
|
+
target: await resolve(input.target),
|
|
2095
|
+
key: input.key,
|
|
2096
|
+
after_user_id: input.after_user_id,
|
|
2097
|
+
limit: input.limit
|
|
2098
|
+
};
|
|
2099
|
+
break;
|
|
2100
|
+
case "groups":
|
|
2101
|
+
path = "groups/query";
|
|
2102
|
+
body = {
|
|
2103
|
+
target: await resolve(input.target),
|
|
2104
|
+
after_key: input.after_key,
|
|
2105
|
+
limit: input.limit
|
|
2106
|
+
};
|
|
2107
|
+
break;
|
|
2108
|
+
case "history":
|
|
2109
|
+
path = "history/query";
|
|
2110
|
+
body = {
|
|
2111
|
+
start_at: input.start_at,
|
|
2112
|
+
end_at: input.end_at,
|
|
2113
|
+
limit: input.limit,
|
|
2114
|
+
...input.before_at === void 0 ? {} : {
|
|
2115
|
+
before_at: input.before_at,
|
|
2116
|
+
before_id: input.before_id
|
|
2117
|
+
}
|
|
2118
|
+
};
|
|
2119
|
+
break;
|
|
2120
|
+
case "received":
|
|
2121
|
+
path = "received/query";
|
|
2122
|
+
body = {
|
|
2123
|
+
limit: input.limit,
|
|
2124
|
+
world_only: input.world_only,
|
|
2125
|
+
...input.before_at === void 0 ? {} : {
|
|
2126
|
+
before_at: input.before_at,
|
|
2127
|
+
before_id: input.before_id
|
|
2128
|
+
}
|
|
2129
|
+
};
|
|
2130
|
+
break;
|
|
2131
|
+
case "history-policy-query":
|
|
2132
|
+
path = "history-policy/query";
|
|
2133
|
+
body = {};
|
|
2134
|
+
break;
|
|
2135
|
+
case "history-policy-set":
|
|
2136
|
+
path = "history-policy/set";
|
|
2137
|
+
body = {
|
|
2138
|
+
expected_revision: input.expected_revision,
|
|
2139
|
+
locked: input.locked
|
|
2140
|
+
};
|
|
2141
|
+
break;
|
|
2142
|
+
case "library-query":
|
|
2143
|
+
path = "library/query";
|
|
2144
|
+
body = {};
|
|
2145
|
+
break;
|
|
2146
|
+
case "library-set":
|
|
2147
|
+
path = "library/set";
|
|
2148
|
+
body = {
|
|
2149
|
+
items: input.items,
|
|
2150
|
+
expected_revision: input.expected_revision,
|
|
2151
|
+
request_id: input.request_id
|
|
2152
|
+
};
|
|
2153
|
+
break;
|
|
2154
|
+
default: throw new ArkmePluginError("reaction-operation-invalid", "不支持的表态操作", false);
|
|
2155
|
+
}
|
|
2156
|
+
const before = await this.runtime.requireSession();
|
|
2157
|
+
if (`${this.runtime.config.environment}:${before.userId}` !== accountKey) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
2158
|
+
const result = objectValue$2(await this.runtime.authenticatedPost(`/api/v1/reactions/${path}`, body, session, signal));
|
|
2159
|
+
const current = await this.runtime.requireSession();
|
|
2160
|
+
if (signal?.aborted || `${this.runtime.config.environment}:${current.userId}` !== accountKey) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
2161
|
+
if (input.action === "query") {
|
|
2162
|
+
if (!Array.isArray(result.items)) throw new ArkmePluginError("reaction-response-invalid", "表态数据不完整", true);
|
|
2163
|
+
const seen = /* @__PURE__ */ new Set();
|
|
2164
|
+
return { items: array(result.items, 50).flatMap((raw) => {
|
|
2165
|
+
const item = objectValue$2(raw), wireKey = targetKey(objectValue$2(item.target)), aliases = ids.get(wireKey);
|
|
2166
|
+
if (!aliases || seen.has(wireKey)) return invalid$11();
|
|
2167
|
+
seen.add(wireKey);
|
|
2168
|
+
const snapshot = {
|
|
2169
|
+
mine: state(item.mine),
|
|
2170
|
+
groups: array(item.groups, 100).map(group),
|
|
2171
|
+
has_more: boolean(item.has_more),
|
|
2172
|
+
actors_visible: boolean(item.actors_visible),
|
|
2173
|
+
private: boolean(item.private)
|
|
2174
|
+
};
|
|
2175
|
+
return aliases.map((id) => ({
|
|
2176
|
+
target_id: id,
|
|
2177
|
+
...snapshot
|
|
2178
|
+
}));
|
|
2179
|
+
}) };
|
|
2180
|
+
}
|
|
2181
|
+
if (input.action === "notifications-read") return { ok: boolean(result.ok) };
|
|
2182
|
+
if (input.action === "notifications") {
|
|
2183
|
+
if (!this.chatSourceKey) return invalid$11();
|
|
2184
|
+
const items = await Promise.all(array(result.items, 50).map(async (raw) => {
|
|
2185
|
+
const item = objectValue$2(raw), target = objectValue$2(item.target);
|
|
2186
|
+
if (typeof target.chat_session_uid !== "string" || !target.chat_session_uid || typeof item.record_uid !== "string" || !item.record_uid) return invalid$11();
|
|
2187
|
+
return {
|
|
2188
|
+
id: key(item.id),
|
|
2189
|
+
revision: integer$4(item.revision, 1),
|
|
2190
|
+
actorUserId: integer$4(item.actor_user_id, 1),
|
|
2191
|
+
sourceKey: await this.chatSourceKey(session.userId, target.chat_session_uid),
|
|
2192
|
+
itemUid: item.record_uid,
|
|
2193
|
+
recordOwnerUserId: integer$4(item.record_owner_user_id, 1),
|
|
2194
|
+
sendAtMillis: integer$4(item.attach_at),
|
|
2195
|
+
text: typeof item.text === "string" ? item.text.slice(0, 320) : "",
|
|
2196
|
+
selections: array(item.selections, 56).map((raw) => {
|
|
2197
|
+
const selected = objectValue$2(raw);
|
|
2198
|
+
return {
|
|
2199
|
+
key: key(selected.key),
|
|
2200
|
+
expression: expression(selected.expression),
|
|
2201
|
+
at: integer$4(selected.at)
|
|
2202
|
+
};
|
|
2203
|
+
})
|
|
2204
|
+
};
|
|
2205
|
+
}));
|
|
2206
|
+
if (signal?.aborted || `${this.runtime.config.environment}:${(await this.runtime.requireSession()).userId}` !== accountKey) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
2207
|
+
return {
|
|
2208
|
+
items,
|
|
2209
|
+
after_id: result.after_id === "" ? "" : key(result.after_id),
|
|
2210
|
+
has_more: boolean(result.has_more)
|
|
2211
|
+
};
|
|
2212
|
+
}
|
|
2213
|
+
if (input.action === "library-query") return library(result);
|
|
2214
|
+
if (input.action === "history-policy-query") return {
|
|
2215
|
+
revision: integer$4(result.revision),
|
|
2216
|
+
locked: boolean(result.locked)
|
|
2217
|
+
};
|
|
2218
|
+
if (input.action === "history-policy-set") {
|
|
2219
|
+
if (![
|
|
2220
|
+
"updated",
|
|
2221
|
+
"unchanged",
|
|
2222
|
+
"revision_conflict"
|
|
2223
|
+
].includes(String(result.outcome))) return invalid$11();
|
|
2224
|
+
const policy = objectValue$2(result.policy);
|
|
2225
|
+
return {
|
|
2226
|
+
outcome: result.outcome,
|
|
2227
|
+
policy: {
|
|
2228
|
+
revision: integer$4(policy.revision),
|
|
2229
|
+
locked: boolean(policy.locked)
|
|
2230
|
+
}
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
if (input.action === "library-set") {
|
|
2234
|
+
if (![
|
|
2235
|
+
"updated",
|
|
2236
|
+
"idempotent",
|
|
2237
|
+
"revision_conflict"
|
|
2238
|
+
].includes(String(result.outcome))) return invalid$11();
|
|
2239
|
+
return {
|
|
2240
|
+
outcome: result.outcome,
|
|
2241
|
+
library: library(result.library)
|
|
2242
|
+
};
|
|
2243
|
+
}
|
|
2244
|
+
if (input.action === "set") {
|
|
2245
|
+
if (![
|
|
2246
|
+
"updated",
|
|
2247
|
+
"unchanged",
|
|
2248
|
+
"idempotent",
|
|
2249
|
+
"revision_conflict"
|
|
2250
|
+
].includes(String(result.outcome))) return invalid$11();
|
|
2251
|
+
return {
|
|
2252
|
+
outcome: result.outcome,
|
|
2253
|
+
state: state(result.state)
|
|
2254
|
+
};
|
|
2255
|
+
}
|
|
2256
|
+
if (input.action === "actors") return {
|
|
2257
|
+
user_ids: array(result.user_ids, 100).map((id) => integer$4(id, 1)),
|
|
2258
|
+
has_more: boolean(result.has_more)
|
|
2259
|
+
};
|
|
2260
|
+
if (input.action === "groups") return {
|
|
2261
|
+
items: array(result.items, 100).map(group),
|
|
2262
|
+
has_more: boolean(result.has_more)
|
|
2263
|
+
};
|
|
2264
|
+
if (input.action === "history" || input.action === "received") {
|
|
2265
|
+
const rows = array(result.items, 100).map(objectValue$2);
|
|
2266
|
+
const contextRows = rows.filter((item) => item.restricted === false);
|
|
2267
|
+
const contexts = input.action === "history" && this.historyContext ? await this.historyContext(contextRows.map((item) => {
|
|
2268
|
+
const original = objectValue$2(item.original_message);
|
|
2269
|
+
return {
|
|
2270
|
+
sessionUID: String(objectValue$2(item.target).chat_session_uid ?? ""),
|
|
2271
|
+
senderID: integer$4(item.sender_user_id ?? 0),
|
|
2272
|
+
sourceKind: String(item.source_kind ?? ""),
|
|
2273
|
+
...typeof original.record_uid === "string" && original.record_uid ? { message: {
|
|
2274
|
+
recordUID: original.record_uid,
|
|
2275
|
+
ownerUserID: integer$4(original.owner_user_id, 1),
|
|
2276
|
+
sendAtMillis: integer$4(original.send_at, 1)
|
|
2277
|
+
} } : {}
|
|
2278
|
+
};
|
|
2279
|
+
}), signal) : [];
|
|
2280
|
+
if (signal?.aborted || `${this.runtime.config.environment}:${(await this.runtime.requireSession()).userId}` !== accountKey) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
2281
|
+
const contextByRow = new Map(contextRows.map((row, index) => [row, contexts[index]]));
|
|
2282
|
+
return {
|
|
2283
|
+
items: await Promise.all(rows.map(async (item) => {
|
|
2284
|
+
const target = objectValue$2(item.target);
|
|
2285
|
+
if (typeof target.chat_session_uid !== "string" || typeof target.rel_uid !== "string") return invalid$11();
|
|
2286
|
+
const targetID = createHash("sha256").update(JSON.stringify([session.userId, targetKey(target)])).digest("hex");
|
|
2287
|
+
const received = input.action === "received" ? {
|
|
2288
|
+
actor_user_id: integer$4(item.actor_user_id, 1),
|
|
2289
|
+
private: boolean(item.private),
|
|
2290
|
+
...input.world_only && typeof target.record_uid === "string" && this.worldReference ? { target: {
|
|
2291
|
+
id: targetID,
|
|
2292
|
+
worldRecordRef: await this.worldReference(target.record_uid)
|
|
2293
|
+
} } : {}
|
|
2294
|
+
} : {};
|
|
2295
|
+
const restricted = boolean(item.restricted);
|
|
2296
|
+
return {
|
|
2297
|
+
...received,
|
|
2298
|
+
...!restricted ? contextByRow.get(item) : {},
|
|
2299
|
+
event_uid: key(item.event_uid),
|
|
2300
|
+
target_id: targetID,
|
|
2301
|
+
expression: expression(item.expression),
|
|
2302
|
+
active: boolean(item.active),
|
|
2303
|
+
at: integer$4(item.at),
|
|
2304
|
+
restricted,
|
|
2305
|
+
...!restricted && typeof item.source_kind === "string" ? { source_kind: item.source_kind } : {},
|
|
2306
|
+
...!restricted && typeof item.text === "string" ? { text: item.text.slice(0, 320) } : {}
|
|
2307
|
+
};
|
|
2308
|
+
})),
|
|
2309
|
+
has_more: boolean(result.has_more),
|
|
2310
|
+
...result.has_more ? {
|
|
2311
|
+
before_at: integer$4(result.before_at),
|
|
2312
|
+
before_id: key(result.before_id)
|
|
2313
|
+
} : {}
|
|
2314
|
+
};
|
|
2315
|
+
}
|
|
2316
|
+
return invalid$11();
|
|
2317
|
+
}
|
|
2318
|
+
};
|
|
2319
|
+
//#endregion
|
|
1951
2320
|
//#region src/managed-ai/image-preparer.ts
|
|
1952
2321
|
const MAXIMUM_DECODED_IMAGE_PIXELS = 4e7;
|
|
1953
2322
|
const MAXIMUM_SOURCE_IMAGE_BYTES = 64 << 20;
|
|
@@ -3863,7 +4232,7 @@ var ArkmeDesktopScreenshot = class {
|
|
|
3863
4232
|
};
|
|
3864
4233
|
//#endregion
|
|
3865
4234
|
//#region src/services/record-edit-history-service.ts
|
|
3866
|
-
function invalid$
|
|
4235
|
+
function invalid$10() {
|
|
3867
4236
|
throw new ArkmePluginError("record-edit-history-invalid", "编辑记录暂不可用,请刷新后重试", true, 502);
|
|
3868
4237
|
}
|
|
3869
4238
|
var RecordEditHistoryService = class {
|
|
@@ -3874,9 +4243,9 @@ var RecordEditHistoryService = class {
|
|
|
3874
4243
|
this.projector = projector;
|
|
3875
4244
|
}
|
|
3876
4245
|
async page(target, cursorEditAt = 0, signal) {
|
|
3877
|
-
if (!Number.isSafeInteger(cursorEditAt) || cursorEditAt < 0 || target.recordUid.trim() === "") invalid$
|
|
4246
|
+
if (!Number.isSafeInteger(cursorEditAt) || cursorEditAt < 0 || target.recordUid.trim() === "") invalid$10();
|
|
3878
4247
|
const session = await this.runtime.requireSession();
|
|
3879
|
-
if (session.userId !== target.viewerUserId) invalid$
|
|
4248
|
+
if (session.userId !== target.viewerUserId) invalid$10();
|
|
3880
4249
|
const window = {
|
|
3881
4250
|
limit: 50,
|
|
3882
4251
|
...cursorEditAt === 0 ? {} : { cursor_edit_at: cursorEditAt }
|
|
@@ -3889,22 +4258,22 @@ var RecordEditHistoryService = class {
|
|
|
3889
4258
|
rel_uid: target.relationUid,
|
|
3890
4259
|
...window
|
|
3891
4260
|
}, session, signal));
|
|
3892
|
-
if (signal?.aborted || (await this.runtime.requireSession()).userId !== session.userId) invalid$
|
|
3893
|
-
if (!Array.isArray(data.items) || typeof data.has_more !== "boolean") invalid$
|
|
4261
|
+
if (signal?.aborted || (await this.runtime.requireSession()).userId !== session.userId) invalid$10();
|
|
4262
|
+
if (!Array.isArray(data.items) || typeof data.has_more !== "boolean") invalid$10();
|
|
3894
4263
|
const next = data.next_cursor_edit_at;
|
|
3895
|
-
if (data.has_more && (typeof next !== "number" || !Number.isSafeInteger(next) || next <= 0 || cursorEditAt > 0 && next >= cursorEditAt)) invalid$
|
|
4264
|
+
if (data.has_more && (typeof next !== "number" || !Number.isSafeInteger(next) || next <= 0 || cursorEditAt > 0 && next >= cursorEditAt)) invalid$10();
|
|
3896
4265
|
const seen = /* @__PURE__ */ new Set();
|
|
3897
4266
|
const snapshots = data.items.flatMap((raw) => {
|
|
3898
4267
|
const revision = objectValue$2(raw);
|
|
3899
|
-
if (revision.record_uid !== target.recordUid || typeof revision.revision_uid !== "string" || revision.revision_uid.trim() === "") invalid$
|
|
4268
|
+
if (revision.record_uid !== target.recordUid || typeof revision.revision_uid !== "string" || revision.revision_uid.trim() === "") invalid$10();
|
|
3900
4269
|
if (revision.revision_type !== 1 && revision.revision_type !== 5) return [];
|
|
3901
|
-
if (typeof revision.edit_at !== "number" || !Number.isSafeInteger(revision.edit_at) || revision.edit_at <= 0 || !Number.isFinite(new Date(revision.edit_at).getTime()) || typeof revision.text_content !== "string") invalid$
|
|
4270
|
+
if (typeof revision.edit_at !== "number" || !Number.isSafeInteger(revision.edit_at) || revision.edit_at <= 0 || !Number.isFinite(new Date(revision.edit_at).getTime()) || typeof revision.text_content !== "string") invalid$10();
|
|
3902
4271
|
if (seen.has(revision.revision_uid)) return [];
|
|
3903
4272
|
seen.add(revision.revision_uid);
|
|
3904
4273
|
return [revision];
|
|
3905
4274
|
});
|
|
3906
4275
|
const contents = snapshots.length === 0 ? [] : await this.projector.projectPage(snapshots, target, signal);
|
|
3907
|
-
if (signal?.aborted || (await this.runtime.requireSession()).userId !== session.userId || contents.length !== snapshots.length) invalid$
|
|
4276
|
+
if (signal?.aborted || (await this.runtime.requireSession()).userId !== session.userId || contents.length !== snapshots.length) invalid$10();
|
|
3908
4277
|
const items = snapshots.map((revision, index) => ({
|
|
3909
4278
|
revisionUid: revision.revision_uid,
|
|
3910
4279
|
kind: revision.revision_type === 5 ? "original" : "manual",
|
|
@@ -22457,7 +22826,7 @@ function arkmeArticleImageReference(value) {
|
|
|
22457
22826
|
}
|
|
22458
22827
|
//#endregion
|
|
22459
22828
|
//#region src/services/archive-service.ts
|
|
22460
|
-
const invalid$
|
|
22829
|
+
const invalid$9 = () => new ArkmePluginError("archive-contract-invalid", "归档数据无效,请刷新后重试", false, 502);
|
|
22461
22830
|
/** One Host owner for UI, Tools and SDK. Raw topic identities stay here. */
|
|
22462
22831
|
var ArchiveService = class {
|
|
22463
22832
|
runtime;
|
|
@@ -22481,17 +22850,17 @@ var ArchiveService = class {
|
|
|
22481
22850
|
limit: 50,
|
|
22482
22851
|
...cursor === void 0 ? {} : { cursor }
|
|
22483
22852
|
}, session, readSignal, { lane: "interactive-read" });
|
|
22484
|
-
if (!Array.isArray(data.items) || typeof data.has_more !== "boolean") throw invalid$
|
|
22853
|
+
if (!Array.isArray(data.items) || typeof data.has_more !== "boolean") throw invalid$9();
|
|
22485
22854
|
const items = [];
|
|
22486
22855
|
for (const value of data.items) {
|
|
22487
22856
|
const raw = objectValue$2(value);
|
|
22488
|
-
if (typeof raw.title !== "string" || typeof raw.privacy_locked !== "boolean") throw invalid$
|
|
22857
|
+
if (typeof raw.title !== "string" || typeof raw.privacy_locked !== "boolean") throw invalid$9();
|
|
22489
22858
|
const title = raw.privacy_locked ? "隐私主题" : raw.title;
|
|
22490
22859
|
const state = await this.state(session, raw, title);
|
|
22491
|
-
if (!state.ownerAvailable || !state.effectiveArchived) throw invalid$
|
|
22860
|
+
if (!state.ownerAvailable || !state.effectiveArchived) throw invalid$9();
|
|
22492
22861
|
const inherited = raw.inherited_from_summary === void 0 ? void 0 : objectValue$2(raw.inherited_from_summary);
|
|
22493
|
-
if (state.inheritedFrom !== void 0 !== (inherited !== void 0)) throw invalid$
|
|
22494
|
-
if (inherited !== void 0 && (typeof inherited.title !== "string" || typeof inherited.privacy_locked !== "boolean")) throw invalid$
|
|
22862
|
+
if (state.inheritedFrom !== void 0 !== (inherited !== void 0)) throw invalid$9();
|
|
22863
|
+
if (inherited !== void 0 && (typeof inherited.title !== "string" || typeof inherited.privacy_locked !== "boolean")) throw invalid$9();
|
|
22495
22864
|
items.push({
|
|
22496
22865
|
...state,
|
|
22497
22866
|
privacyLocked: raw.privacy_locked,
|
|
@@ -22510,7 +22879,7 @@ var ArchiveService = class {
|
|
|
22510
22879
|
}
|
|
22511
22880
|
});
|
|
22512
22881
|
}
|
|
22513
|
-
if (data.has_more && (typeof data.next_cursor !== "string" || data.next_cursor === "" || data.next_cursor === cursor)) throw invalid$
|
|
22882
|
+
if (data.has_more && (typeof data.next_cursor !== "string" || data.next_cursor === "" || data.next_cursor === cursor)) throw invalid$9();
|
|
22514
22883
|
await this.assertSession(session);
|
|
22515
22884
|
return {
|
|
22516
22885
|
items,
|
|
@@ -22520,7 +22889,7 @@ var ArchiveService = class {
|
|
|
22520
22889
|
}, signal);
|
|
22521
22890
|
}
|
|
22522
22891
|
async states(sourceRefs, signal) {
|
|
22523
|
-
if (sourceRefs.length === 0 || sourceRefs.length > 200 || new Set(sourceRefs).size !== sourceRefs.length) throw invalid$
|
|
22892
|
+
if (sourceRefs.length === 0 || sourceRefs.length > 200 || new Set(sourceRefs).size !== sourceRefs.length) throw invalid$9();
|
|
22524
22893
|
return this.runtime.runOwnerRead("archives", {
|
|
22525
22894
|
operation: "states",
|
|
22526
22895
|
sourceRefs
|
|
@@ -22533,12 +22902,12 @@ var ArchiveService = class {
|
|
|
22533
22902
|
entity_type: 1,
|
|
22534
22903
|
entity_uid: ref.ownerRef
|
|
22535
22904
|
})) }, session, readSignal, { lane: "interactive-read" });
|
|
22536
|
-
if (!Array.isArray(data.items) || data.items.length !== refs.length) throw invalid$
|
|
22905
|
+
if (!Array.isArray(data.items) || data.items.length !== refs.length) throw invalid$9();
|
|
22537
22906
|
const byUID = new Map(data.items.map((value) => {
|
|
22538
22907
|
const raw = objectValue$2(value);
|
|
22539
22908
|
return [raw.entity_uid, raw];
|
|
22540
22909
|
}));
|
|
22541
|
-
if (byUID.size !== refs.length) throw invalid$
|
|
22910
|
+
if (byUID.size !== refs.length) throw invalid$9();
|
|
22542
22911
|
const states = await Promise.all(refs.map(async (ref, i) => ({
|
|
22543
22912
|
...await this.state(session, byUID.get(ref.ownerRef), ""),
|
|
22544
22913
|
sourceRef: sourceRefs[i]
|
|
@@ -22548,7 +22917,7 @@ var ArchiveService = class {
|
|
|
22548
22917
|
}, signal);
|
|
22549
22918
|
}
|
|
22550
22919
|
async set(input, signal) {
|
|
22551
|
-
if (typeof input.selfArchived !== "boolean" || !Number.isSafeInteger(input.expectedRevision) || input.expectedRevision < 0) throw invalid$
|
|
22920
|
+
if (typeof input.selfArchived !== "boolean" || !Number.isSafeInteger(input.expectedRevision) || input.expectedRevision < 0) throw invalid$9();
|
|
22552
22921
|
const session = await this.runtime.requireSession();
|
|
22553
22922
|
const ref = await this.sources.openSourceRef(input.sourceRef, session.userId);
|
|
22554
22923
|
if (ref.kind !== "topic") throw new ArkmePluginError("archive-target-invalid", "仅支持个人主题归档", false, 400);
|
|
@@ -22562,7 +22931,7 @@ var ArchiveService = class {
|
|
|
22562
22931
|
self_status: input.selfArchived ? 2 : 1,
|
|
22563
22932
|
expected_revision: input.expectedRevision
|
|
22564
22933
|
}, session, signal, { trackWriteOutcome: true });
|
|
22565
|
-
if (data.entity_uid !== ref.ownerRef || data.self_status !== (input.selfArchived ? 2 : 1) || typeof data.state_changed !== "boolean" || !Number.isSafeInteger(data.effective_changed_count) || Number(data.effective_changed_count) < 0) throw invalid$
|
|
22934
|
+
if (data.entity_uid !== ref.ownerRef || data.self_status !== (input.selfArchived ? 2 : 1) || typeof data.state_changed !== "boolean" || !Number.isSafeInteger(data.effective_changed_count) || Number(data.effective_changed_count) < 0) throw invalid$9();
|
|
22566
22935
|
const state = await this.state(session, data, "");
|
|
22567
22936
|
await this.assertSession(session);
|
|
22568
22937
|
return {
|
|
@@ -22578,9 +22947,9 @@ var ArchiveService = class {
|
|
|
22578
22947
|
}
|
|
22579
22948
|
async state(session, value, title) {
|
|
22580
22949
|
const raw = objectValue$2(value);
|
|
22581
|
-
if (raw.entity_type !== 1 || typeof raw.entity_uid !== "string" || raw.entity_uid.trim() === "" || raw.self_status !== 1 && raw.self_status !== 2 || raw.effective_status !== 1 && raw.effective_status !== 2 || typeof raw.owner_available !== "boolean" || !Number.isSafeInteger(raw.revision) || Number(raw.revision) < 0 || !Number.isSafeInteger(raw.display_archive_at)) throw invalid$
|
|
22950
|
+
if (raw.entity_type !== 1 || typeof raw.entity_uid !== "string" || raw.entity_uid.trim() === "" || raw.self_status !== 1 && raw.self_status !== 2 || raw.effective_status !== 1 && raw.effective_status !== 2 || typeof raw.owner_available !== "boolean" || !Number.isSafeInteger(raw.revision) || Number(raw.revision) < 0 || !Number.isSafeInteger(raw.display_archive_at)) throw invalid$9();
|
|
22582
22951
|
const parent = raw.inherited_from === void 0 ? void 0 : objectValue$2(raw.inherited_from);
|
|
22583
|
-
if (parent !== void 0 && (parent.entity_type !== 1 || typeof parent.entity_uid !== "string" || parent.entity_uid === "")) throw invalid$
|
|
22952
|
+
if (parent !== void 0 && (parent.entity_type !== 1 || typeof parent.entity_uid !== "string" || parent.entity_uid === "")) throw invalid$9();
|
|
22584
22953
|
return {
|
|
22585
22954
|
entityType: "topic",
|
|
22586
22955
|
sourceRef: await this.sources.sealSourceRef(session.userId, "topic", raw.entity_uid, title),
|
|
@@ -22599,23 +22968,23 @@ var ArchiveService = class {
|
|
|
22599
22968
|
//#endregion
|
|
22600
22969
|
//#region src/record-deletion-ref.ts
|
|
22601
22970
|
const prefix$1 = "arkme-record-delete-v1";
|
|
22602
|
-
const invalid$
|
|
22971
|
+
const invalid$8 = () => new ArkmePluginError("record-delete-reference-invalid", "删除引用已失效,请刷新后重新选择", false, 409);
|
|
22603
22972
|
function sealRecordDeletionRef(ref, key) {
|
|
22604
22973
|
const payload = Buffer.from(JSON.stringify(ref)).toString("base64url");
|
|
22605
22974
|
return `${prefix$1}.${payload}.${createHmac("sha256", key).update(`${prefix$1}.${payload}`).digest("base64url")}`;
|
|
22606
22975
|
}
|
|
22607
22976
|
function openRecordDeletionRef(value, key) {
|
|
22608
|
-
if (typeof value !== "string" || value.length > 2048) throw invalid$
|
|
22977
|
+
if (typeof value !== "string" || value.length > 2048) throw invalid$8();
|
|
22609
22978
|
const [kind, payload, signature, extra] = value.split(".");
|
|
22610
|
-
if (kind !== prefix$1 || !payload || !signature || extra !== void 0) throw invalid$
|
|
22979
|
+
if (kind !== prefix$1 || !payload || !signature || extra !== void 0) throw invalid$8();
|
|
22611
22980
|
const actual = Buffer.from(signature, "base64url");
|
|
22612
22981
|
const expected = createHmac("sha256", key).update(`${prefix$1}.${payload}`).digest();
|
|
22613
|
-
if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) throw invalid$
|
|
22982
|
+
if (actual.length !== expected.length || !timingSafeEqual(actual, expected)) throw invalid$8();
|
|
22614
22983
|
let ref;
|
|
22615
22984
|
try {
|
|
22616
22985
|
ref = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
22617
22986
|
} catch {
|
|
22618
|
-
throw invalid$
|
|
22987
|
+
throw invalid$8();
|
|
22619
22988
|
}
|
|
22620
22989
|
if (!ref || !Number.isSafeInteger(ref.userId) || ref.userId <= 0 || !Number.isSafeInteger(ref.recordVersion) || ref.recordVersion <= 0 || ![
|
|
22621
22990
|
"private_chat",
|
|
@@ -22623,7 +22992,7 @@ function openRecordDeletionRef(value, key) {
|
|
|
22623
22992
|
"send_to_self",
|
|
22624
22993
|
"default_category",
|
|
22625
22994
|
"topic"
|
|
22626
|
-
].includes(ref.sourceKind) || typeof ref.sourceOwnerRef !== "string" || !ref.sourceOwnerRef.trim() || typeof ref.recordUid !== "string" || !ref.recordUid.trim()) throw invalid$
|
|
22995
|
+
].includes(ref.sourceKind) || typeof ref.sourceOwnerRef !== "string" || !ref.sourceOwnerRef.trim() || typeof ref.recordUid !== "string" || !ref.recordUid.trim()) throw invalid$8();
|
|
22627
22996
|
return ref;
|
|
22628
22997
|
}
|
|
22629
22998
|
/** Only authoritative Record snapshots can grant deletion; missing versions never fall back to a relation version. */
|
|
@@ -22736,31 +23105,31 @@ var RecordDeletionService = class {
|
|
|
22736
23105
|
};
|
|
22737
23106
|
//#endregion
|
|
22738
23107
|
//#region src/record-topic-assignment-ref.ts
|
|
22739
|
-
const invalid$
|
|
23108
|
+
const invalid$7 = () => new ArkmePluginError("record-topic-reference-invalid", "快记归属引用已失效,请刷新后重新选择", false, 409);
|
|
22740
23109
|
const prefix = "arkme-record-topic-v1";
|
|
22741
23110
|
function sealRecordTopicAssignmentRef(reference, key) {
|
|
22742
23111
|
const payload = Buffer.from(JSON.stringify(reference)).toString("base64url");
|
|
22743
23112
|
return `${prefix}.${payload}.${createHmac("sha256", key).update(`${prefix}.${payload}`).digest("base64url")}`;
|
|
22744
23113
|
}
|
|
22745
23114
|
function openRecordTopicAssignmentRef(value, key) {
|
|
22746
|
-
if (typeof value !== "string" || value.length > 2048) throw invalid$
|
|
23115
|
+
if (typeof value !== "string" || value.length > 2048) throw invalid$7();
|
|
22747
23116
|
const parts = value.split(".");
|
|
22748
|
-
if (parts.length !== 3 || parts[0] !== prefix) throw invalid$
|
|
23117
|
+
if (parts.length !== 3 || parts[0] !== prefix) throw invalid$7();
|
|
22749
23118
|
const payload = parts[1];
|
|
22750
23119
|
const signature = Buffer.from(parts[2], "base64url");
|
|
22751
23120
|
const expected = createHmac("sha256", key).update(`${prefix}.${payload}`).digest();
|
|
22752
|
-
if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) throw invalid$
|
|
23121
|
+
if (signature.length !== expected.length || !timingSafeEqual(signature, expected)) throw invalid$7();
|
|
22753
23122
|
let parsed;
|
|
22754
23123
|
try {
|
|
22755
23124
|
parsed = JSON.parse(Buffer.from(payload, "base64url").toString("utf8"));
|
|
22756
23125
|
} catch {
|
|
22757
|
-
throw invalid$
|
|
23126
|
+
throw invalid$7();
|
|
22758
23127
|
}
|
|
22759
23128
|
if (!parsed || !Number.isSafeInteger(parsed.userId) || parsed.userId <= 0 || ![
|
|
22760
23129
|
"send_to_self",
|
|
22761
23130
|
"default_category",
|
|
22762
23131
|
"topic"
|
|
22763
|
-
].includes(parsed.sourceKind) || typeof parsed.sourceOwnerRef !== "string" || parsed.sourceOwnerRef.trim() === "" || typeof parsed.recordUid !== "string" || parsed.recordUid.trim() === "" || typeof parsed.sourceTopicUid !== "string") throw invalid$
|
|
23132
|
+
].includes(parsed.sourceKind) || typeof parsed.sourceOwnerRef !== "string" || parsed.sourceOwnerRef.trim() === "" || typeof parsed.recordUid !== "string" || parsed.recordUid.trim() === "" || typeof parsed.sourceTopicUid !== "string") throw invalid$7();
|
|
22764
23133
|
return parsed;
|
|
22765
23134
|
}
|
|
22766
23135
|
//#endregion
|
|
@@ -36846,6 +37215,10 @@ var AuthService = class {
|
|
|
36846
37215
|
runtime;
|
|
36847
37216
|
profile;
|
|
36848
37217
|
lifecycle;
|
|
37218
|
+
cancellationNotice;
|
|
37219
|
+
pendingCancellationLogin;
|
|
37220
|
+
pendingCancellationCleanup;
|
|
37221
|
+
cancellationTask;
|
|
36849
37222
|
pendingPhoneUnbindSession;
|
|
36850
37223
|
attempts = /* @__PURE__ */ new Map();
|
|
36851
37224
|
jiwoAttemptGeneration = 0;
|
|
@@ -36860,6 +37233,7 @@ var AuthService = class {
|
|
|
36860
37233
|
for (const [attemptId, attempt] of this.attempts) if (attempt.kind === "wechat") this.attempts.delete(attemptId);
|
|
36861
37234
|
}
|
|
36862
37235
|
async logout() {
|
|
37236
|
+
this.pendingCancellationLogin = void 0;
|
|
36863
37237
|
this.pendingPhoneUnbindSession = void 0;
|
|
36864
37238
|
const activeSession = await this.runtime.sessionStore.read();
|
|
36865
37239
|
const pendingSession = await this.runtime.readPendingBindingSession();
|
|
@@ -36882,7 +37256,24 @@ var AuthService = class {
|
|
|
36882
37256
|
};
|
|
36883
37257
|
}
|
|
36884
37258
|
async authStatus() {
|
|
37259
|
+
if (this.pendingCancellationLogin !== void 0) return this.cancellationLoginSnapshot();
|
|
36885
37260
|
const activeSession = await this.runtime.sessionStore.read();
|
|
37261
|
+
const completion = await this.runtime.stateStore.readCancellationCompletion?.();
|
|
37262
|
+
if (completion !== void 0) {
|
|
37263
|
+
if (activeSession === void 0) this.cancellationNotice = completion.result.status === "done" ? "done" : "waiting";
|
|
37264
|
+
else if (completion.userId === activeSession.userId && completion.sessionHash === this.cancellationSessionHash(activeSession)) {
|
|
37265
|
+
this.pendingCancellationCleanup = {
|
|
37266
|
+
session: activeSession,
|
|
37267
|
+
result: completion.result
|
|
37268
|
+
};
|
|
37269
|
+
await this.submitCancellation(activeSession.userId, completion.result.mode);
|
|
37270
|
+
return {
|
|
37271
|
+
status: "logged-out",
|
|
37272
|
+
environment: this.runtime.config.environment,
|
|
37273
|
+
cancellationNotice: completion.result.status === "done" ? "done" : "waiting"
|
|
37274
|
+
};
|
|
37275
|
+
}
|
|
37276
|
+
}
|
|
36886
37277
|
if (activeSession !== void 0) {
|
|
36887
37278
|
const cachedProfile = await this.runtime.stateStore.cachedProfile(activeSession.userId);
|
|
36888
37279
|
const snapshot = cachedProfile.profile === null ? await this.authSnapshotForSession(activeSession) : {
|
|
@@ -36900,7 +37291,8 @@ var AuthService = class {
|
|
|
36900
37291
|
const pendingSession = await this.runtime.readPendingBindingSession();
|
|
36901
37292
|
return pendingSession === void 0 ? {
|
|
36902
37293
|
status: "logged-out",
|
|
36903
|
-
environment: this.runtime.config.environment
|
|
37294
|
+
environment: this.runtime.config.environment,
|
|
37295
|
+
...this.cancellationNotice === void 0 ? {} : { cancellationNotice: this.cancellationNotice }
|
|
36904
37296
|
} : {
|
|
36905
37297
|
status: "binding-required",
|
|
36906
37298
|
environment: this.runtime.config.environment,
|
|
@@ -36908,6 +37300,7 @@ var AuthService = class {
|
|
|
36908
37300
|
};
|
|
36909
37301
|
}
|
|
36910
37302
|
async beginWechatLogin() {
|
|
37303
|
+
this.pendingCancellationLogin = void 0;
|
|
36911
37304
|
this.jiwoAttemptGeneration += 1;
|
|
36912
37305
|
await this.cancelAllJiwoLoginAttempts();
|
|
36913
37306
|
const data = await this.runtime.post(this.runtime.config.authBaseUrl, "/api/public/v1/auth/wechat-oauth-login-qrcode", {}, void 0, [200]);
|
|
@@ -36970,10 +37363,11 @@ var AuthService = class {
|
|
|
36970
37363
|
userId
|
|
36971
37364
|
};
|
|
36972
37365
|
this.attempts.delete(attemptId);
|
|
36973
|
-
return await this.acceptLoginSession(session);
|
|
37366
|
+
return await this.acceptLoginSession(session, numberValue$27(data.rest_days_cancel));
|
|
36974
37367
|
}
|
|
36975
37368
|
async beginJiwoLogin() {
|
|
36976
37369
|
if (!jiwoScanLoginAvailable(this.runtime.config)) throw new ArkmePluginError("jiwo-scan-login-disabled", "即我扫码登录当前未启用", false, 403);
|
|
37370
|
+
this.pendingCancellationLogin = void 0;
|
|
36977
37371
|
const attemptGeneration = ++this.jiwoAttemptGeneration;
|
|
36978
37372
|
await this.cancelAllJiwoLoginAttempts();
|
|
36979
37373
|
const data = await this.runtime.post(this.runtime.config.authBaseUrl, "/api/public/v1/auth/app-scan-login/start", {
|
|
@@ -37042,7 +37436,7 @@ var AuthService = class {
|
|
|
37042
37436
|
accessToken,
|
|
37043
37437
|
refreshToken,
|
|
37044
37438
|
userId
|
|
37045
|
-
});
|
|
37439
|
+
}, numberValue$27(data.rest_days_cancel));
|
|
37046
37440
|
}
|
|
37047
37441
|
async cancelJiwoLogin(attemptId) {
|
|
37048
37442
|
if (attemptId.trim() === "") return { canceled: true };
|
|
@@ -37080,6 +37474,7 @@ var AuthService = class {
|
|
|
37080
37474
|
async testLogin(userId) {
|
|
37081
37475
|
if (this.runtime.config.environment !== "test") throw new ArkmePluginError("test-login-disabled", "测试账号登录仅允许测试环境使用", false, 403);
|
|
37082
37476
|
if (!Number.isSafeInteger(userId) || userId <= 0) throw new ArkmePluginError("test-user-id-invalid", "请输入有效的测试账号 user_id", false);
|
|
37477
|
+
this.pendingCancellationLogin = void 0;
|
|
37083
37478
|
const data = await this.runtime.post(this.runtime.config.authBaseUrl, "/api/public/v1/auth/the-best-api-for-testing", {
|
|
37084
37479
|
user_id: userId,
|
|
37085
37480
|
unique_code: await this.runtime.stateStore.uniqueCode(),
|
|
@@ -37095,7 +37490,30 @@ var AuthService = class {
|
|
|
37095
37490
|
userId
|
|
37096
37491
|
};
|
|
37097
37492
|
this.attempts.clear();
|
|
37098
|
-
return await this.acceptLoginSession(session);
|
|
37493
|
+
return await this.acceptLoginSession(session, numberValue$27(data.rest_days_cancel));
|
|
37494
|
+
}
|
|
37495
|
+
async emailBindingRequest(expectedUserId, email, code) {
|
|
37496
|
+
const session = await this.runtime.requireSession();
|
|
37497
|
+
if (session.userId !== expectedUserId) throw new ArkmePluginError("email-session-changed", "账号已切换,请重新打开账号设置", false);
|
|
37498
|
+
const normalizedEmail = email.trim();
|
|
37499
|
+
if (normalizedEmail.length > 254 || !/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(normalizedEmail)) throw new ArkmePluginError("email-invalid", "请输入有效的邮箱地址", false);
|
|
37500
|
+
if (code !== void 0 && !/^[0-9]{4}$/.test(code.trim())) throw new ArkmePluginError("email-code-invalid", "请输入4位邮箱验证码", false);
|
|
37501
|
+
const data = await this.runtime.post(this.runtime.config.authBaseUrl, code === void 0 ? "/api/v1/auth/email-bind-send-code" : "/api/v1/auth/email-bind", {
|
|
37502
|
+
email: normalizedEmail,
|
|
37503
|
+
...code === void 0 ? {} : { code: code.trim() }
|
|
37504
|
+
}, session.accessToken, [200]);
|
|
37505
|
+
const current = await this.runtime.requireSession();
|
|
37506
|
+
if (current.userId !== session.userId || current.refreshToken !== session.refreshToken) throw new ArkmePluginError("email-session-changed", "账号已切换,请重新打开账号设置", false);
|
|
37507
|
+
if (data.result !== 1) throw new ArkmePluginError("email-bind-rejected", data.result === 2 ? "该邮箱已绑定其他账号" : data.result === 3 ? "当前账号已绑定邮箱,请刷新账号信息" : code !== void 0 && data.result === 4 ? "邮箱或验证码错误" : "邮箱绑定响应异常,请重试", false);
|
|
37508
|
+
if (code !== void 0) this.profile.invalidate(session.userId);
|
|
37509
|
+
}
|
|
37510
|
+
async sendEmailBindCode(expectedUserId, email) {
|
|
37511
|
+
await this.emailBindingRequest(expectedUserId, email);
|
|
37512
|
+
return { sent: true };
|
|
37513
|
+
}
|
|
37514
|
+
async bindEmail(expectedUserId, email, code) {
|
|
37515
|
+
await this.emailBindingRequest(expectedUserId, email, code);
|
|
37516
|
+
return { bound: true };
|
|
37099
37517
|
}
|
|
37100
37518
|
async sendPhoneCode(phone, captcha) {
|
|
37101
37519
|
const normalizedPhone = this.normalizedPhone(phone);
|
|
@@ -37122,6 +37540,7 @@ var AuthService = class {
|
|
|
37122
37540
|
const normalizedPhone = this.normalizedPhone(phone);
|
|
37123
37541
|
const normalizedCode = code.trim();
|
|
37124
37542
|
if (!/^[0-9]{6}$/.test(normalizedCode)) throw new ArkmePluginError("phone-code-invalid", "请输入有效的短信验证码", false);
|
|
37543
|
+
this.pendingCancellationLogin = void 0;
|
|
37125
37544
|
const session = await this.runtime.sessionStore.read() ?? await this.runtime.readPendingBindingSession();
|
|
37126
37545
|
if (session !== void 0) {
|
|
37127
37546
|
const result = numberValue$27((await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/verify-bind-phone", {
|
|
@@ -37155,7 +37574,7 @@ var AuthService = class {
|
|
|
37155
37574
|
userId
|
|
37156
37575
|
};
|
|
37157
37576
|
this.attempts.clear();
|
|
37158
|
-
return await this.acceptLoginSession(sessionAfterPhoneLogin);
|
|
37577
|
+
return await this.acceptLoginSession(sessionAfterPhoneLogin, numberValue$27(data.rest_days_cancel));
|
|
37159
37578
|
}
|
|
37160
37579
|
async checkPhoneUnbindEligibility(expectedUserId) {
|
|
37161
37580
|
const session = await this.runtime.requireSession();
|
|
@@ -37250,21 +37669,144 @@ var AuthService = class {
|
|
|
37250
37669
|
profileHasBoundPhone(snapshot) {
|
|
37251
37670
|
return (snapshot.profile?.contact.phoneMasked?.trim() ?? "") !== "";
|
|
37252
37671
|
}
|
|
37253
|
-
async acceptLoginSession(session) {
|
|
37672
|
+
async acceptLoginSession(session, restDaysCancel = 0, assertCurrent) {
|
|
37673
|
+
if (assertCurrent === void 0) this.pendingCancellationLogin = void 0;
|
|
37674
|
+
if (restDaysCancel > 0) {
|
|
37675
|
+
this.pendingCancellationLogin = {
|
|
37676
|
+
session,
|
|
37677
|
+
days: restDaysCancel
|
|
37678
|
+
};
|
|
37679
|
+
return this.cancellationLoginSnapshot();
|
|
37680
|
+
}
|
|
37681
|
+
await this.runtime.stateStore.writeCancellationCompletion?.(void 0);
|
|
37682
|
+
this.cancellationNotice = void 0;
|
|
37254
37683
|
this.runtime.invalidateScope(this.runtime.requestScope(session.userId));
|
|
37255
37684
|
this.profile.invalidate(session.userId);
|
|
37256
37685
|
const snapshot = await this.authSnapshotForSession(session, { forceProfile: true });
|
|
37686
|
+
assertCurrent?.();
|
|
37257
37687
|
if (snapshot.status === "authenticated") {
|
|
37258
37688
|
await this.runtime.clearPendingBindingSession();
|
|
37689
|
+
assertCurrent?.();
|
|
37259
37690
|
await this.runtime.writeSession(session);
|
|
37691
|
+
assertCurrent?.();
|
|
37260
37692
|
this.lifecycle.reconnectChatRealtime();
|
|
37261
37693
|
return snapshot;
|
|
37262
37694
|
}
|
|
37263
37695
|
await this.runtime.writePendingBindingSession(session);
|
|
37696
|
+
assertCurrent?.();
|
|
37264
37697
|
await this.runtime.deleteSession();
|
|
37698
|
+
assertCurrent?.();
|
|
37265
37699
|
this.lifecycle.reconnectChatRealtime();
|
|
37266
37700
|
return snapshot;
|
|
37267
37701
|
}
|
|
37702
|
+
cancellationLoginSnapshot() {
|
|
37703
|
+
return {
|
|
37704
|
+
status: "cancellation-pending",
|
|
37705
|
+
environment: this.runtime.config.environment,
|
|
37706
|
+
restDaysCancel: this.pendingCancellationLogin.days
|
|
37707
|
+
};
|
|
37708
|
+
}
|
|
37709
|
+
async resolveCancellationLogin(continueLogin) {
|
|
37710
|
+
const pending = this.pendingCancellationLogin;
|
|
37711
|
+
if (pending === void 0) throw new ArkmePluginError("cancellation-login-expired", "登录确认已失效,请重新登录", false);
|
|
37712
|
+
if (!continueLogin) {
|
|
37713
|
+
this.pendingCancellationLogin = void 0;
|
|
37714
|
+
return {
|
|
37715
|
+
status: "logged-out",
|
|
37716
|
+
environment: this.runtime.config.environment
|
|
37717
|
+
};
|
|
37718
|
+
}
|
|
37719
|
+
await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/abort-cancel", {}, pending.session.accessToken, [200]);
|
|
37720
|
+
if (this.pendingCancellationLogin !== pending) throw new ArkmePluginError("cancellation-login-expired", "登录确认已失效,请重新登录", false);
|
|
37721
|
+
const snapshot = await this.acceptLoginSession(pending.session, 0, () => {
|
|
37722
|
+
if (this.pendingCancellationLogin !== pending) throw new ArkmePluginError("cancellation-login-expired", "登录确认已失效,请重新登录", false);
|
|
37723
|
+
});
|
|
37724
|
+
if (this.pendingCancellationLogin === pending) this.pendingCancellationLogin = void 0;
|
|
37725
|
+
return snapshot;
|
|
37726
|
+
}
|
|
37727
|
+
async cancellationSession(expectedUserId) {
|
|
37728
|
+
const session = await this.runtime.requireSession();
|
|
37729
|
+
if (session.userId !== expectedUserId) throw new ArkmePluginError("cancellation-session-changed", "账号已切换,请重新打开账号设置", false);
|
|
37730
|
+
return session;
|
|
37731
|
+
}
|
|
37732
|
+
cancellationResult(data) {
|
|
37733
|
+
if (!data || !["immediate", "waiting"].includes(data.mode) || ![
|
|
37734
|
+
"eligible",
|
|
37735
|
+
"waiting",
|
|
37736
|
+
"done"
|
|
37737
|
+
].includes(data.status) || !Number.isSafeInteger(data.cancel_at) || data.cancel_at < 0 || typeof data.has_phone !== "boolean") throw new ArkmePluginError("cancellation-contract-invalid", "注销状态未确认,请稍后重试", true, 502);
|
|
37738
|
+
return data;
|
|
37739
|
+
}
|
|
37740
|
+
async previewCancellation(expectedUserId) {
|
|
37741
|
+
const session = await this.cancellationSession(expectedUserId);
|
|
37742
|
+
const data = await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/cancellation/preview", {}, session.accessToken, [200]);
|
|
37743
|
+
if ((await this.cancellationSession(expectedUserId)).refreshToken !== session.refreshToken) throw new ArkmePluginError("cancellation-session-changed", "登录状态已变化,请重试", false);
|
|
37744
|
+
return this.cancellationResult(data);
|
|
37745
|
+
}
|
|
37746
|
+
async submitCancellation(expectedUserId, expectedMode) {
|
|
37747
|
+
if (expectedMode !== "immediate" && expectedMode !== "waiting") throw new ArkmePluginError("cancellation-mode-invalid", "请重新确认注销方式", false);
|
|
37748
|
+
if (this.cancellationTask !== void 0) throw new ArkmePluginError("cancellation-busy", "正在处理注销,请稍候", true);
|
|
37749
|
+
const task = this.performCancellation(expectedUserId, expectedMode);
|
|
37750
|
+
this.cancellationTask = task;
|
|
37751
|
+
try {
|
|
37752
|
+
return await task;
|
|
37753
|
+
} finally {
|
|
37754
|
+
if (this.cancellationTask === task) this.cancellationTask = void 0;
|
|
37755
|
+
}
|
|
37756
|
+
}
|
|
37757
|
+
async performCancellation(expectedUserId, expectedMode) {
|
|
37758
|
+
let cleanup = this.pendingCancellationCleanup;
|
|
37759
|
+
if (cleanup === void 0) {
|
|
37760
|
+
const completion = await this.runtime.stateStore.readCancellationCompletion?.();
|
|
37761
|
+
const active = await this.runtime.sessionStore.read();
|
|
37762
|
+
if (completion?.userId === expectedUserId && active === void 0) return completion.result;
|
|
37763
|
+
if (completion?.userId === expectedUserId && active !== void 0 && completion.sessionHash === this.cancellationSessionHash(active)) {
|
|
37764
|
+
cleanup = {
|
|
37765
|
+
session: active,
|
|
37766
|
+
result: completion.result
|
|
37767
|
+
};
|
|
37768
|
+
this.pendingCancellationCleanup = cleanup;
|
|
37769
|
+
}
|
|
37770
|
+
}
|
|
37771
|
+
if (cleanup === void 0 || cleanup.session.userId !== expectedUserId) {
|
|
37772
|
+
const session = await this.cancellationSession(expectedUserId);
|
|
37773
|
+
const result = this.cancellationResult(await this.runtime.post(this.runtime.config.authBaseUrl, "/api/v1/auth/cancellation/submit", { expected_mode: expectedMode }, session.accessToken, [200], void 0, false, this.runtime.authenticatedRequestOptions(session, "auth", "write", { trackWriteOutcome: true })));
|
|
37774
|
+
if (result.changed === true && result.status === "eligible") return result;
|
|
37775
|
+
if (result.status !== "done" && result.status !== "waiting") throw new ArkmePluginError("cancellation-contract-invalid", "注销状态未确认,请稍后重试", true);
|
|
37776
|
+
cleanup = {
|
|
37777
|
+
session,
|
|
37778
|
+
result
|
|
37779
|
+
};
|
|
37780
|
+
this.pendingCancellationCleanup = cleanup;
|
|
37781
|
+
}
|
|
37782
|
+
const current = await this.runtime.sessionStore.read();
|
|
37783
|
+
if (current !== void 0 && (current.userId !== cleanup.session.userId || current.refreshToken !== cleanup.session.refreshToken)) {
|
|
37784
|
+
await this.runtime.stateStore.writeCancellationCompletion?.(void 0);
|
|
37785
|
+
this.pendingCancellationCleanup = void 0;
|
|
37786
|
+
throw new ArkmePluginError("cancellation-session-changed", "账号已切换,原账号注销已处理", false);
|
|
37787
|
+
}
|
|
37788
|
+
await this.runtime.stateStore.writeCancellationCompletion?.({
|
|
37789
|
+
userId: cleanup.session.userId,
|
|
37790
|
+
sessionHash: this.cancellationSessionHash(cleanup.session),
|
|
37791
|
+
result: cleanup.result
|
|
37792
|
+
});
|
|
37793
|
+
this.runtime.invalidateScope(this.runtime.requestScope(cleanup.session.userId));
|
|
37794
|
+
this.runtime.clearRefreshForUser(cleanup.session.userId);
|
|
37795
|
+
if (!await this.runtime.deleteSessionIfCurrent(cleanup.session) && await this.runtime.sessionStore.read() !== void 0) {
|
|
37796
|
+
await this.runtime.stateStore.writeCancellationCompletion?.(void 0);
|
|
37797
|
+
this.pendingCancellationCleanup = void 0;
|
|
37798
|
+
throw new ArkmePluginError("cancellation-session-changed", "账号已切换,原账号注销已处理", false);
|
|
37799
|
+
}
|
|
37800
|
+
this.profile.invalidate(cleanup.session.userId);
|
|
37801
|
+
this.lifecycle.clearAccountState([cleanup.session.userId]);
|
|
37802
|
+
this.lifecycle.reconnectChatRealtime();
|
|
37803
|
+
this.cancellationNotice = cleanup.result.status === "done" ? "done" : "waiting";
|
|
37804
|
+
this.pendingCancellationCleanup = void 0;
|
|
37805
|
+
return cleanup.result;
|
|
37806
|
+
}
|
|
37807
|
+
cancellationSessionHash(session) {
|
|
37808
|
+
return createHash("sha256").update(session.refreshToken).digest("hex");
|
|
37809
|
+
}
|
|
37268
37810
|
normalizedPhone(phone) {
|
|
37269
37811
|
const normalized = phone.replace(/[\s-]/g, "");
|
|
37270
37812
|
if (!/^1[3-9][0-9]{9}$/.test(normalized)) throw new ArkmePluginError("phone-invalid", "请输入有效的中国大陆手机号", false);
|
|
@@ -37321,23 +37863,23 @@ var BackgroundSoundMembershipService = class {
|
|
|
37321
37863
|
};
|
|
37322
37864
|
//#endregion
|
|
37323
37865
|
//#region src/services/membership-service.ts
|
|
37324
|
-
function invalid$
|
|
37866
|
+
function invalid$6() {
|
|
37325
37867
|
throw new ArkmePluginError("membership-contract-invalid", "会员信息暂时无法确认,请稍后重试", true, 502);
|
|
37326
37868
|
}
|
|
37327
37869
|
function integer$3(value) {
|
|
37328
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return invalid$
|
|
37870
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) return invalid$6();
|
|
37329
37871
|
return value;
|
|
37330
37872
|
}
|
|
37331
37873
|
function timestamp(value) {
|
|
37332
37874
|
if (value === void 0 || value === null || value === 0) return null;
|
|
37333
37875
|
const micros = integer$3(value);
|
|
37334
37876
|
const millis = Math.floor(micros / 1e3);
|
|
37335
|
-
if (millis < Date.UTC(2e3, 0) || millis > Date.UTC(3e3, 0)) return invalid$
|
|
37877
|
+
if (millis < Date.UTC(2e3, 0) || millis > Date.UTC(3e3, 0)) return invalid$6();
|
|
37336
37878
|
return millis;
|
|
37337
37879
|
}
|
|
37338
37880
|
function parseMembership(raw, userId, now = Date.now()) {
|
|
37339
37881
|
const memberType = integer$3(raw.member_type);
|
|
37340
|
-
if (memberType > 2) return invalid$
|
|
37882
|
+
if (memberType > 2) return invalid$6();
|
|
37341
37883
|
const expireAtMillis = timestamp(raw.expire_at);
|
|
37342
37884
|
return {
|
|
37343
37885
|
userId,
|
|
@@ -37348,16 +37890,16 @@ function parseMembership(raw, userId, now = Date.now()) {
|
|
|
37348
37890
|
};
|
|
37349
37891
|
}
|
|
37350
37892
|
function parseMembershipProducts(raw) {
|
|
37351
|
-
if (!Array.isArray(raw.data_ls)) return invalid$
|
|
37893
|
+
if (!Array.isArray(raw.data_ls)) return invalid$6();
|
|
37352
37894
|
const products = raw.data_ls.map((entry) => {
|
|
37353
|
-
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return invalid$
|
|
37895
|
+
if (!entry || typeof entry !== "object" || Array.isArray(entry)) return invalid$6();
|
|
37354
37896
|
const row = entry;
|
|
37355
37897
|
const memberType = integer$3(row.spu_code);
|
|
37356
|
-
if (memberType !== 1 && memberType !== 2) return invalid$
|
|
37357
|
-
if (typeof row.name !== "string" || !row.name.trim() || typeof row.is_period !== "boolean") return invalid$
|
|
37898
|
+
if (memberType !== 1 && memberType !== 2) return invalid$6();
|
|
37899
|
+
if (typeof row.name !== "string" || !row.name.trim() || typeof row.is_period !== "boolean") return invalid$6();
|
|
37358
37900
|
const alipayId = integer$3(row.alipay_product_id);
|
|
37359
37901
|
const wechatId = integer$3(row.wechat_product_id);
|
|
37360
|
-
if (alipayId === 0 && wechatId === 0) return invalid$
|
|
37902
|
+
if (alipayId === 0 && wechatId === 0) return invalid$6();
|
|
37361
37903
|
return {
|
|
37362
37904
|
id: `${memberType}:${alipayId}:${wechatId}:${row.is_period ? "recurring" : "once"}`,
|
|
37363
37905
|
memberType,
|
|
@@ -37368,7 +37910,7 @@ function parseMembershipProducts(raw) {
|
|
|
37368
37910
|
monthCount: integer$3(row.month_count)
|
|
37369
37911
|
};
|
|
37370
37912
|
});
|
|
37371
|
-
if (new Set(products.map((p) => p.id)).size !== products.length) return invalid$
|
|
37913
|
+
if (new Set(products.map((p) => p.id)).size !== products.length) return invalid$6();
|
|
37372
37914
|
return products.sort((a, b) => a.memberType - b.memberType || a.monthCount - b.monthCount || a.priceMinor - b.priceMinor);
|
|
37373
37915
|
}
|
|
37374
37916
|
/** Membership is distinct from managed-AI balance billing. Only read endpoints are exposed. */
|
|
@@ -37384,7 +37926,7 @@ var MembershipService = class {
|
|
|
37384
37926
|
return parseMembership(raw, userId);
|
|
37385
37927
|
}
|
|
37386
37928
|
async catalog(expectedUserId) {
|
|
37387
|
-
if (!Number.isSafeInteger(expectedUserId) || expectedUserId <= 0) return invalid$
|
|
37929
|
+
if (!Number.isSafeInteger(expectedUserId) || expectedUserId <= 0) return invalid$6();
|
|
37388
37930
|
const session = await this.runtime.requireSession();
|
|
37389
37931
|
if (session.userId !== expectedUserId) throw new ArkmePluginError("membership-account-changed", "账号已切换,请重新打开会员页面", false, 409);
|
|
37390
37932
|
const raw = await this.runtime.authenticatedAuthReadPost("/api/v1/payment/get/sale-product", {}, session);
|
|
@@ -37499,19 +38041,19 @@ var AccountUsageService = class {
|
|
|
37499
38041
|
//#endregion
|
|
37500
38042
|
//#region src/services/account-usage-details-service.ts
|
|
37501
38043
|
const monthPattern = /^\d{4}-(0[1-9]|1[0-2])$/;
|
|
37502
|
-
function invalid$
|
|
38044
|
+
function invalid$5() {
|
|
37503
38045
|
return new ArkmePluginError("account-usage-details-invalid", "用量明细暂时无法确认,请重试", true, 502);
|
|
37504
38046
|
}
|
|
37505
38047
|
function object$5(value) {
|
|
37506
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalid$
|
|
38048
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalid$5();
|
|
37507
38049
|
return value;
|
|
37508
38050
|
}
|
|
37509
38051
|
function count(value) {
|
|
37510
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw invalid$
|
|
38052
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw invalid$5();
|
|
37511
38053
|
return value;
|
|
37512
38054
|
}
|
|
37513
38055
|
function text$4(value, max = 16384) {
|
|
37514
|
-
if (typeof value !== "string" || value.length > max) throw invalid$
|
|
38056
|
+
if (typeof value !== "string" || value.length > max) throw invalid$5();
|
|
37515
38057
|
return value;
|
|
37516
38058
|
}
|
|
37517
38059
|
function tokens(value) {
|
|
@@ -37540,17 +38082,17 @@ function status(value) {
|
|
|
37540
38082
|
}
|
|
37541
38083
|
function parseTokenSummary(value, accountScope) {
|
|
37542
38084
|
const raw = object$5(value), monthKey = text$4(raw.month_key, 7);
|
|
37543
|
-
if (!monthPattern.test(monthKey) || !Array.isArray(raw.available_months)) throw invalid$
|
|
38085
|
+
if (!monthPattern.test(monthKey) || !Array.isArray(raw.available_months)) throw invalid$5();
|
|
37544
38086
|
const availableMonths = [...new Set(raw.available_months.map((value) => {
|
|
37545
38087
|
const month = text$4(value, 7);
|
|
37546
|
-
if (!monthPattern.test(month)) throw invalid$
|
|
38088
|
+
if (!monthPattern.test(month)) throw invalid$5();
|
|
37547
38089
|
return month;
|
|
37548
38090
|
}))].sort().reverse();
|
|
37549
38091
|
const timezone = text$4(raw.timezone, 100);
|
|
37550
38092
|
try {
|
|
37551
38093
|
new Intl.DateTimeFormat("en", { timeZone: timezone });
|
|
37552
38094
|
} catch {
|
|
37553
|
-
throw invalid$
|
|
38095
|
+
throw invalid$5();
|
|
37554
38096
|
}
|
|
37555
38097
|
return {
|
|
37556
38098
|
accountScope,
|
|
@@ -37567,7 +38109,7 @@ function parseTokenSummary(value, accountScope) {
|
|
|
37567
38109
|
}
|
|
37568
38110
|
function parseTokenPage(value, accountScope, kind) {
|
|
37569
38111
|
const raw = object$5(value);
|
|
37570
|
-
if (!Array.isArray(raw.items) || raw.items.length > 100) throw invalid$
|
|
38112
|
+
if (!Array.isArray(raw.items) || raw.items.length > 100) throw invalid$5();
|
|
37571
38113
|
return {
|
|
37572
38114
|
accountScope,
|
|
37573
38115
|
items: raw.items.map((value) => {
|
|
@@ -37583,7 +38125,7 @@ function parseTokenPage(value, accountScope, kind) {
|
|
|
37583
38125
|
usageStatus: status(item.usage_status)
|
|
37584
38126
|
};
|
|
37585
38127
|
const operationUid = text$4(item.operation_uid, 256), displayName = text$4(item.display_name, 2048);
|
|
37586
|
-
if (!operationUid.trim() || !displayName.trim() || !Array.isArray(item.models)) throw invalid$
|
|
38128
|
+
if (!operationUid.trim() || !displayName.trim() || !Array.isArray(item.models)) throw invalid$5();
|
|
37587
38129
|
return {
|
|
37588
38130
|
...common,
|
|
37589
38131
|
operationUid,
|
|
@@ -37610,11 +38152,11 @@ var AccountUsageDetailsService = class {
|
|
|
37610
38152
|
async read(scope, kind, query, signal) {
|
|
37611
38153
|
const session = await this.session(scope);
|
|
37612
38154
|
const month = text$4(query.monthKey, 7), timezone = text$4(query.timezone, 100) || "Asia/Shanghai";
|
|
37613
|
-
if (month && !monthPattern.test(month)) throw invalid$
|
|
38155
|
+
if (month && !monthPattern.test(month)) throw invalid$5();
|
|
37614
38156
|
try {
|
|
37615
38157
|
new Intl.DateTimeFormat("en", { timeZone: timezone });
|
|
37616
38158
|
} catch {
|
|
37617
|
-
throw invalid$
|
|
38159
|
+
throw invalid$5();
|
|
37618
38160
|
}
|
|
37619
38161
|
const body = {
|
|
37620
38162
|
month_key: month,
|
|
@@ -37626,7 +38168,7 @@ var AccountUsageDetailsService = class {
|
|
|
37626
38168
|
}
|
|
37627
38169
|
if (kind === "calls") {
|
|
37628
38170
|
const uid = text$4(query.operationUid, 256), biz = count(query.bizCode);
|
|
37629
|
-
if (!uid.trim() || biz > 32767) throw invalid$
|
|
38171
|
+
if (!uid.trim() || biz > 32767) throw invalid$5();
|
|
37630
38172
|
body.operation_uid = uid;
|
|
37631
38173
|
body.biz_code = biz;
|
|
37632
38174
|
}
|
|
@@ -37636,7 +38178,7 @@ var AccountUsageDetailsService = class {
|
|
|
37636
38178
|
}
|
|
37637
38179
|
async summary(scope, query, signal) {
|
|
37638
38180
|
const result = parseTokenSummary(await this.read(scope, "summary", query, signal), scope);
|
|
37639
|
-
if (query.monthKey && result.monthKey !== query.monthKey) throw invalid$
|
|
38181
|
+
if (query.monthKey && result.monthKey !== query.monthKey) throw invalid$5();
|
|
37640
38182
|
return result;
|
|
37641
38183
|
}
|
|
37642
38184
|
async operations(scope, query, signal) {
|
|
@@ -37649,17 +38191,17 @@ var AccountUsageDetailsService = class {
|
|
|
37649
38191
|
//#endregion
|
|
37650
38192
|
//#region src/services/data-management-service.ts
|
|
37651
38193
|
function object$4(value) {
|
|
37652
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalid$
|
|
38194
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) throw invalid$4();
|
|
37653
38195
|
return value;
|
|
37654
38196
|
}
|
|
37655
|
-
function invalid$
|
|
38197
|
+
function invalid$4() {
|
|
37656
38198
|
return new ArkmePluginError("data-management-contract-invalid", "数据格式暂时无法确认,请重试", true, 502);
|
|
37657
38199
|
}
|
|
37658
38200
|
function text$3(value) {
|
|
37659
38201
|
return typeof value === "string" ? value : "";
|
|
37660
38202
|
}
|
|
37661
38203
|
function integer$1(value) {
|
|
37662
|
-
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw invalid$
|
|
38204
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) throw invalid$4();
|
|
37663
38205
|
return value;
|
|
37664
38206
|
}
|
|
37665
38207
|
const DELETED_RETENTION_MILLIS = 720 * 60 * 60 * 1e3;
|
|
@@ -37682,7 +38224,7 @@ function lifecycle(value) {
|
|
|
37682
38224
|
function parseDeletedRecords(raw, accountScope, nowMillis = Date.now()) {
|
|
37683
38225
|
const envelope = object$4(raw);
|
|
37684
38226
|
const rows = envelope.items ?? envelope.records ?? envelope.list ?? envelope.data;
|
|
37685
|
-
if (!Array.isArray(rows)) throw invalid$
|
|
38227
|
+
if (!Array.isArray(rows)) throw invalid$4();
|
|
37686
38228
|
let unverifiedCount = 0;
|
|
37687
38229
|
return {
|
|
37688
38230
|
accountScope,
|
|
@@ -37690,7 +38232,7 @@ function parseDeletedRecords(raw, accountScope, nowMillis = Date.now()) {
|
|
|
37690
38232
|
const row = object$4(value);
|
|
37691
38233
|
const core = object$4(row.record_core ?? row.record ?? row);
|
|
37692
38234
|
const recordUid = text$3(core.record_uid).trim();
|
|
37693
|
-
if (!recordUid) throw invalid$
|
|
38235
|
+
if (!recordUid) throw invalid$4();
|
|
37694
38236
|
const status = lifecycle(core.status);
|
|
37695
38237
|
if (status === "excluded") return [];
|
|
37696
38238
|
if (status === "unknown") {
|
|
@@ -37753,7 +38295,7 @@ var DataManagementService = class {
|
|
|
37753
38295
|
}, session, signal, { lane: "interactive-read" }), this.runtime.authenticatedPost("/api/v1/records/export/session/latest", {}, session, signal, { lane: "interactive-read" })]);
|
|
37754
38296
|
await this.session(scope);
|
|
37755
38297
|
const raw = object$4(preflightResponse), latest = object$4(latestResponse);
|
|
37756
|
-
if (typeof raw.can_export !== "boolean") throw invalid$
|
|
38298
|
+
if (typeof raw.can_export !== "boolean") throw invalid$4();
|
|
37757
38299
|
return {
|
|
37758
38300
|
accountScope: scope,
|
|
37759
38301
|
canExport: raw.can_export,
|
|
@@ -37765,7 +38307,7 @@ var DataManagementService = class {
|
|
|
37765
38307
|
};
|
|
37766
38308
|
}
|
|
37767
38309
|
async recover(scope, recordUid, version) {
|
|
37768
|
-
if (!recordUid.trim() || integer$1(version) <= 0) throw invalid$
|
|
38310
|
+
if (!recordUid.trim() || integer$1(version) <= 0) throw invalid$4();
|
|
37769
38311
|
const record = (await this.deleted(scope)).items.find((item) => item.recordUid === recordUid);
|
|
37770
38312
|
if (!record || record.version !== version || record.recoverableUntilMillis === void 0 || record.recoverableUntilMillis <= Date.now()) throw new ArkmePluginError("data-management-record-changed", "记录状态已变化或无法确认可恢复,请刷新最近删除列表。", false, 409);
|
|
37771
38313
|
const session = await this.session(scope);
|
|
@@ -37775,7 +38317,7 @@ var DataManagementService = class {
|
|
|
37775
38317
|
}, session);
|
|
37776
38318
|
await this.session(scope);
|
|
37777
38319
|
const envelope = object$4(raw);
|
|
37778
|
-
if (object$4(envelope.record_core ?? envelope.record ?? envelope).record_uid !== recordUid) throw invalid$
|
|
38320
|
+
if (object$4(envelope.record_core ?? envelope.record ?? envelope).record_uid !== recordUid) throw invalid$4();
|
|
37779
38321
|
return {
|
|
37780
38322
|
accountScope: scope,
|
|
37781
38323
|
recordUid
|
|
@@ -44122,7 +44664,6 @@ var ArkmeChatRealtimeRuntime = class {
|
|
|
44122
44664
|
//#region src/services/chat-realtime-service.ts
|
|
44123
44665
|
const MAX_PROJECTION_RETRIES = 5;
|
|
44124
44666
|
const MAX_ATTENTION_SUMMARY_RETRY_DELAY_MS = 3e4;
|
|
44125
|
-
const MAX_NATIVE_NOTIFICATION_DELIVERY_CONCURRENCY = 3;
|
|
44126
44667
|
const MAX_NOTIFICATION_HINTS_PER_TIMELINE_READ = 50;
|
|
44127
44668
|
const NOTIFICATION_EXPIRY_MILLIS = 5 * 6e4;
|
|
44128
44669
|
const CHAT_NOTIFICATION_DIAGNOSTICS = process.env.ARKME_CHAT_NOTIFICATION_DIAGNOSTICS === "1";
|
|
@@ -44234,6 +44775,7 @@ var ChatRealtimeService = class {
|
|
|
44234
44775
|
}
|
|
44235
44776
|
dispose() {
|
|
44236
44777
|
this.disposed = true;
|
|
44778
|
+
this.attentionOwnerGeneration += 1;
|
|
44237
44779
|
this.attentionController.abort();
|
|
44238
44780
|
if (this.projectionTimer !== void 0) clearTimeout(this.projectionTimer);
|
|
44239
44781
|
if (this.connectionBaselineRetryTimer !== void 0) clearTimeout(this.connectionBaselineRetryTimer);
|
|
@@ -44842,7 +45384,7 @@ var ChatRealtimeService = class {
|
|
|
44842
45384
|
accountUserId: notificationHint?.accountUserId ?? current?.accountUserId,
|
|
44843
45385
|
accountOwnerGeneration: notificationHint?.accountOwnerGeneration ?? current?.accountOwnerGeneration
|
|
44844
45386
|
});
|
|
44845
|
-
this.scheduleProjectionFlush(
|
|
45387
|
+
this.scheduleProjectionFlush(0);
|
|
44846
45388
|
}
|
|
44847
45389
|
scheduleProjectionFlush(delayMillis) {
|
|
44848
45390
|
if (this.projectionInFlight || this.disposed) return;
|
|
@@ -44861,7 +45403,7 @@ var ChatRealtimeService = class {
|
|
|
44861
45403
|
const now = Date.now();
|
|
44862
45404
|
let delay = Number.POSITIVE_INFINITY;
|
|
44863
45405
|
for (const projection of this.pendingChatProjections.values()) {
|
|
44864
|
-
if (projection.refreshSource !== false) delay =
|
|
45406
|
+
if (projection.refreshSource !== false) delay = 0;
|
|
44865
45407
|
for (const candidate of projection.notificationHints) {
|
|
44866
45408
|
const dueAtMillis = candidate.nextAttemptAtMillis ?? now + notificationRetryDelay(candidate.attempts);
|
|
44867
45409
|
delay = Math.min(delay, Math.max(0, dueAtMillis - now));
|
|
@@ -44999,26 +45541,29 @@ var ChatRealtimeService = class {
|
|
|
44999
45541
|
if (pending.length === 0) return [];
|
|
45000
45542
|
for (const [uid, projection] of pending) if (projection.refreshSource === false && this.source.cachedChatSourceByKey(`${String(session.userId)}:${uid}`) === void 0) projection.refreshSource = true;
|
|
45001
45543
|
const sourcePending = pending.filter(([, projection]) => projection.refreshSource !== false);
|
|
45002
|
-
const
|
|
45003
|
-
|
|
45004
|
-
|
|
45005
|
-
|
|
45006
|
-
|
|
45007
|
-
|
|
45008
|
-
|
|
45009
|
-
|
|
45010
|
-
|
|
45011
|
-
const
|
|
45012
|
-
|
|
45013
|
-
|
|
45544
|
+
const displayReady = (async () => {
|
|
45545
|
+
const bundles = /* @__PURE__ */ new Map();
|
|
45546
|
+
if (sourcePending.length > 0) {
|
|
45547
|
+
const sessionUids = sourcePending.map(([uid]) => uid).sort();
|
|
45548
|
+
const projectionBatchKey = sessionUids.join("|");
|
|
45549
|
+
const displayData = await this.runtime.authenticatedChatPost("/api/v1/chats/display-snapshots", { chat_session_uids: sessionUids }, session, void 0, {
|
|
45550
|
+
lane: sourcePending.some(([, projection]) => projection.notificationHints.length > 0) ? "interactive-read" : "background-read",
|
|
45551
|
+
key: `projection:display:${projectionBatchKey}`
|
|
45552
|
+
});
|
|
45553
|
+
for (const raw of listValue$18(displayData.items)) {
|
|
45554
|
+
const bundle = objectValue$2(raw);
|
|
45555
|
+
const uid = stringValue$2(objectValue$2(bundle.session).chat_session_uid).trim();
|
|
45556
|
+
if (uid !== "") bundles.set(uid, bundle);
|
|
45557
|
+
}
|
|
45014
45558
|
}
|
|
45015
|
-
|
|
45016
|
-
|
|
45017
|
-
const
|
|
45018
|
-
const
|
|
45019
|
-
|
|
45020
|
-
|
|
45021
|
-
|
|
45559
|
+
return bundles;
|
|
45560
|
+
})().catch(() => void 0);
|
|
45561
|
+
const failed = [];
|
|
45562
|
+
const notificationLanes = Array.from({ length: 3 }, () => Promise.resolve());
|
|
45563
|
+
let nextNotificationLane = 0;
|
|
45564
|
+
const project = async ([uid, projection]) => {
|
|
45565
|
+
let timelineProjection;
|
|
45566
|
+
if (projection.refreshSource !== false || projection.notificationHints.some((candidate) => candidate.resolvedNotification === void 0)) {
|
|
45022
45567
|
const cached = this.source.cachedChatSourceByKey(`${String(session.userId)}:${uid}`);
|
|
45023
45568
|
const unresolvedHints = projection.notificationHints.filter((candidate) => candidate.resolvedNotification === void 0);
|
|
45024
45569
|
const firstHintSequence = unresolvedHints.reduce((minimum, item) => Math.min(minimum, item.hint.latestSequence), projection.latestSequence);
|
|
@@ -45033,32 +45578,24 @@ var ChatRealtimeService = class {
|
|
|
45033
45578
|
lane: projection.notificationHints.length > 0 ? "interactive-read" : "background-read",
|
|
45034
45579
|
key: `projection:tail:${uid}:${String(afterSequence)}:${String(notificationAttempt)}`
|
|
45035
45580
|
});
|
|
45036
|
-
const
|
|
45581
|
+
const bundles = await displayReady;
|
|
45582
|
+
if (bundles === void 0 && projection.refreshSource !== false) throw new Error("Chat display projection failed");
|
|
45583
|
+
const bundle = bundles?.get(uid);
|
|
45037
45584
|
const sessionKind = numberValue$21(objectValue$2(bundle).session_kind ?? objectValue$2(objectValue$2(bundle).session).session_kind);
|
|
45038
45585
|
const sourceKind = sessionKind === 2 ? "group_chat" : sessionKind === 1 || sessionKind === 3 ? "private_chat" : cached?.kind === "group_chat" || cached?.kind === "private_chat" ? cached.kind : void 0;
|
|
45039
|
-
|
|
45586
|
+
timelineProjection = {
|
|
45040
45587
|
items: await this.projectionReader.chatTimelineItems(data, session, uid, sourceKind, bundle),
|
|
45041
45588
|
notificationIdentities: timelineNotificationIdentities(data)
|
|
45042
|
-
}
|
|
45043
|
-
}))).forEach((result, index) => {
|
|
45044
|
-
const uid = chunk[index]?.[0];
|
|
45045
|
-
if (uid === void 0) return;
|
|
45046
|
-
if (result.status === "fulfilled") tailItemsByUid.set(result.value[0], result.value[1]);
|
|
45047
|
-
else failedUids.add(uid);
|
|
45048
|
-
});
|
|
45049
|
-
}
|
|
45050
|
-
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45051
|
-
const updates = [];
|
|
45052
|
-
const sidebarNotificationHints = [];
|
|
45053
|
-
const notifications = [];
|
|
45054
|
-
for (const [uid, projection] of pending) {
|
|
45055
|
-
const bundle = bundles.get(uid);
|
|
45056
|
-
if (projection.refreshSource !== false && bundle === void 0 || failedUids.has(uid)) {
|
|
45057
|
-
failedUids.add(uid);
|
|
45058
|
-
continue;
|
|
45589
|
+
};
|
|
45059
45590
|
}
|
|
45591
|
+
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45592
|
+
const bundles = await displayReady;
|
|
45593
|
+
const updates = [];
|
|
45594
|
+
const sidebarNotificationHints = [];
|
|
45595
|
+
const notifications = [];
|
|
45596
|
+
const bundle = bundles?.get(uid);
|
|
45597
|
+
if (projection.refreshSource !== false && bundle === void 0) return [[uid, projection]];
|
|
45060
45598
|
const cacheKey = `${String(session.userId)}:${uid}`;
|
|
45061
|
-
const timelineProjection = tailItemsByUid.get(uid);
|
|
45062
45599
|
const timelineItems = timelineProjection?.items ?? [];
|
|
45063
45600
|
try {
|
|
45064
45601
|
const cachedSource = this.source.cachedChatSourceByKey(cacheKey);
|
|
@@ -45068,8 +45605,7 @@ var ChatRealtimeService = class {
|
|
|
45068
45605
|
...projection,
|
|
45069
45606
|
refreshSource: true
|
|
45070
45607
|
});
|
|
45071
|
-
|
|
45072
|
-
continue;
|
|
45608
|
+
return [[uid, projection]];
|
|
45073
45609
|
}
|
|
45074
45610
|
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45075
45611
|
if (projection.refreshSource !== false) this.source.setChatSourceByKey(cacheKey, source);
|
|
@@ -45159,117 +45695,137 @@ var ChatRealtimeService = class {
|
|
|
45159
45695
|
});
|
|
45160
45696
|
}
|
|
45161
45697
|
} catch {
|
|
45162
|
-
|
|
45698
|
+
return [[uid, projection]];
|
|
45163
45699
|
}
|
|
45164
|
-
|
|
45165
|
-
|
|
45166
|
-
|
|
45167
|
-
|
|
45168
|
-
|
|
45169
|
-
|
|
45170
|
-
|
|
45171
|
-
|
|
45172
|
-
|
|
45173
|
-
|
|
45174
|
-
|
|
45175
|
-
|
|
45176
|
-
|
|
45177
|
-
|
|
45178
|
-
|
|
45179
|
-
|
|
45180
|
-
|
|
45181
|
-
|
|
45182
|
-
|
|
45183
|
-
|
|
45184
|
-
|
|
45185
|
-
|
|
45186
|
-
|
|
45187
|
-
|
|
45188
|
-
|
|
45189
|
-
|
|
45190
|
-
|
|
45191
|
-
|
|
45192
|
-
|
|
45193
|
-
|
|
45194
|
-
|
|
45195
|
-
|
|
45196
|
-
|
|
45197
|
-
|
|
45198
|
-
|
|
45199
|
-
|
|
45200
|
-
|
|
45201
|
-
|
|
45202
|
-
|
|
45203
|
-
|
|
45204
|
-
|
|
45205
|
-
|
|
45206
|
-
|
|
45207
|
-
|
|
45208
|
-
|
|
45700
|
+
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45701
|
+
if (updates.length > 0) {
|
|
45702
|
+
this.source.invalidateSourceListCache(session.userId, "root");
|
|
45703
|
+
this.runtime.invalidateCalendarDates(this.runtime.requestScope(session.userId), updates.flatMap((update) => [update.source.activeAtMillis, ...update.timelineItems.map((item) => item.sendAtMillis)]));
|
|
45704
|
+
this.emitChatClientEvent({
|
|
45705
|
+
type: "sessions-delta",
|
|
45706
|
+
revision: this.nextChatClientRevision(),
|
|
45707
|
+
updates
|
|
45708
|
+
});
|
|
45709
|
+
const emittedAtMillis = Date.now();
|
|
45710
|
+
for (const { candidate } of sidebarNotificationHints) notificationDiagnostic("notification_sidebar_delta_emitted", {
|
|
45711
|
+
eventUid: candidate.hint.eventUid,
|
|
45712
|
+
connectionGeneration: candidate.connectionGeneration,
|
|
45713
|
+
attempt: candidate.attempts,
|
|
45714
|
+
emittedAtMillis,
|
|
45715
|
+
...candidate.receivedAtMillis === void 0 ? {} : { durationFromHintMillis: Math.max(0, emittedAtMillis - candidate.receivedAtMillis) }
|
|
45716
|
+
});
|
|
45717
|
+
this.refreshAttentionSummary();
|
|
45718
|
+
}
|
|
45719
|
+
if (notifications.length > 0) {
|
|
45720
|
+
const lane = nextNotificationLane++ % notificationLanes.length;
|
|
45721
|
+
notificationLanes[lane] = notificationLanes[lane].then(async () => {
|
|
45722
|
+
const deliveries = [];
|
|
45723
|
+
for (let offset = 0; offset < notifications.length; offset += 1) {
|
|
45724
|
+
const chunk = notifications.slice(offset, offset + 1);
|
|
45725
|
+
deliveries.push(...await Promise.all(chunk.map(async (entry) => {
|
|
45726
|
+
const { notification, candidate } = entry;
|
|
45727
|
+
if (ownerGeneration !== this.attentionOwnerGeneration) return {
|
|
45728
|
+
entry,
|
|
45729
|
+
fallbackToBrowser: false,
|
|
45730
|
+
outcome: "exception"
|
|
45731
|
+
};
|
|
45732
|
+
const dispatchStartedAtMillis = Date.now();
|
|
45733
|
+
try {
|
|
45734
|
+
const outcome = await this.nativeAttention.showNotification({
|
|
45735
|
+
idempotencyKey: notification.eventUid,
|
|
45736
|
+
kind: "chat.message",
|
|
45737
|
+
occurredAtMillis: notification.eventAtMillis,
|
|
45738
|
+
expiresAtMillis: notification.eventAtMillis + NOTIFICATION_EXPIRY_MILLIS,
|
|
45739
|
+
presentation: {
|
|
45740
|
+
title: notification.title,
|
|
45741
|
+
body: notification.body
|
|
45742
|
+
},
|
|
45743
|
+
activation: {
|
|
45744
|
+
kind: "chat-source",
|
|
45745
|
+
sourceRef: notification.sourceRef,
|
|
45746
|
+
sourceKey: notification.sourceKey
|
|
45747
|
+
}
|
|
45748
|
+
});
|
|
45749
|
+
const completedAtMillis = Date.now();
|
|
45750
|
+
notificationDiagnostic("notification_native_dispatch_completed", {
|
|
45751
|
+
eventUid: notification.eventUid,
|
|
45752
|
+
connectionGeneration: candidate.connectionGeneration,
|
|
45753
|
+
attempt: candidate.attempts,
|
|
45754
|
+
outcome: outcome.outcome,
|
|
45755
|
+
completedAtMillis,
|
|
45756
|
+
dispatchDurationMillis: Math.max(0, completedAtMillis - dispatchStartedAtMillis),
|
|
45757
|
+
...candidate.receivedAtMillis === void 0 ? {} : { durationFromHintMillis: Math.max(0, completedAtMillis - candidate.receivedAtMillis) }
|
|
45758
|
+
});
|
|
45759
|
+
return {
|
|
45760
|
+
entry,
|
|
45761
|
+
fallbackToBrowser: outcome.fallbackToBrowser,
|
|
45762
|
+
outcome: outcome.outcome
|
|
45763
|
+
};
|
|
45764
|
+
} catch {
|
|
45765
|
+
const completedAtMillis = Date.now();
|
|
45766
|
+
notificationDiagnostic("notification_native_dispatch_completed", {
|
|
45767
|
+
eventUid: notification.eventUid,
|
|
45768
|
+
connectionGeneration: candidate.connectionGeneration,
|
|
45769
|
+
attempt: candidate.attempts,
|
|
45770
|
+
outcome: "exception",
|
|
45771
|
+
completedAtMillis,
|
|
45772
|
+
dispatchDurationMillis: Math.max(0, completedAtMillis - dispatchStartedAtMillis),
|
|
45773
|
+
...candidate.receivedAtMillis === void 0 ? {} : { durationFromHintMillis: Math.max(0, completedAtMillis - candidate.receivedAtMillis) }
|
|
45774
|
+
});
|
|
45775
|
+
return {
|
|
45776
|
+
entry,
|
|
45777
|
+
fallbackToBrowser: false,
|
|
45778
|
+
outcome: "exception"
|
|
45779
|
+
};
|
|
45780
|
+
}
|
|
45781
|
+
})));
|
|
45782
|
+
}
|
|
45783
|
+
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45784
|
+
for (const { entry, fallbackToBrowser, outcome } of deliveries) {
|
|
45785
|
+
const { notification, candidate, uid, latestSequence } = entry;
|
|
45786
|
+
if (outcome === "native-failed" || outcome === "rate-limited" || outcome === "exception") {
|
|
45787
|
+
if (!notificationExpired(candidate)) {
|
|
45788
|
+
const attempts = candidate.attempts + 1;
|
|
45789
|
+
this.mergePendingChatProjection(uid, {
|
|
45790
|
+
latestSequence,
|
|
45791
|
+
notificationHints: [{
|
|
45792
|
+
...candidate,
|
|
45793
|
+
attempts,
|
|
45794
|
+
nextAttemptAtMillis: Date.now() + notificationRetryDelay(attempts)
|
|
45795
|
+
}],
|
|
45796
|
+
refreshSource: false,
|
|
45797
|
+
accountUserId: session.userId,
|
|
45798
|
+
accountOwnerGeneration: ownerGeneration
|
|
45799
|
+
});
|
|
45800
|
+
}
|
|
45801
|
+
continue;
|
|
45209
45802
|
}
|
|
45210
|
-
|
|
45211
|
-
|
|
45212
|
-
|
|
45213
|
-
|
|
45214
|
-
|
|
45215
|
-
|
|
45216
|
-
|
|
45217
|
-
|
|
45218
|
-
|
|
45219
|
-
|
|
45220
|
-
|
|
45221
|
-
|
|
45222
|
-
|
|
45223
|
-
|
|
45224
|
-
|
|
45225
|
-
|
|
45803
|
+
if (!fallbackToBrowser) continue;
|
|
45804
|
+
this.emitChatClientEvent({
|
|
45805
|
+
type: "message-notification",
|
|
45806
|
+
revision: this.nextChatClientRevision(),
|
|
45807
|
+
notification
|
|
45808
|
+
});
|
|
45809
|
+
}
|
|
45810
|
+
}).then(() => void 0).catch(() => {
|
|
45811
|
+
failed.push([uid, projection]);
|
|
45812
|
+
});
|
|
45813
|
+
}
|
|
45814
|
+
return [];
|
|
45815
|
+
};
|
|
45816
|
+
let next = 0;
|
|
45817
|
+
await Promise.all(Array.from({ length: Math.min(3, pending.length) }, async () => {
|
|
45818
|
+
while (next < pending.length && ownerGeneration === this.attentionOwnerGeneration) {
|
|
45819
|
+
const entry = pending[next++];
|
|
45820
|
+
try {
|
|
45821
|
+
failed.push(...await project(entry));
|
|
45226
45822
|
} catch {
|
|
45227
|
-
|
|
45228
|
-
notificationDiagnostic("notification_native_dispatch_completed", {
|
|
45229
|
-
eventUid: notification.eventUid,
|
|
45230
|
-
connectionGeneration: candidate.connectionGeneration,
|
|
45231
|
-
attempt: candidate.attempts,
|
|
45232
|
-
outcome: "exception",
|
|
45233
|
-
completedAtMillis,
|
|
45234
|
-
dispatchDurationMillis: Math.max(0, completedAtMillis - dispatchStartedAtMillis),
|
|
45235
|
-
...candidate.receivedAtMillis === void 0 ? {} : { durationFromHintMillis: Math.max(0, completedAtMillis - candidate.receivedAtMillis) }
|
|
45236
|
-
});
|
|
45237
|
-
return {
|
|
45238
|
-
entry,
|
|
45239
|
-
fallbackToBrowser: false,
|
|
45240
|
-
outcome: "exception"
|
|
45241
|
-
};
|
|
45242
|
-
}
|
|
45243
|
-
})));
|
|
45244
|
-
}
|
|
45245
|
-
if (ownerGeneration !== this.attentionOwnerGeneration) return [];
|
|
45246
|
-
for (const { entry, fallbackToBrowser, outcome } of deliveries) {
|
|
45247
|
-
const { notification, candidate, uid, latestSequence } = entry;
|
|
45248
|
-
if (outcome === "native-failed" || outcome === "rate-limited" || outcome === "exception") {
|
|
45249
|
-
if (!notificationExpired(candidate)) {
|
|
45250
|
-
const attempts = candidate.attempts + 1;
|
|
45251
|
-
this.mergePendingChatProjection(uid, {
|
|
45252
|
-
latestSequence,
|
|
45253
|
-
notificationHints: [{
|
|
45254
|
-
...candidate,
|
|
45255
|
-
attempts,
|
|
45256
|
-
nextAttemptAtMillis: Date.now() + notificationRetryDelay(attempts)
|
|
45257
|
-
}],
|
|
45258
|
-
refreshSource: false,
|
|
45259
|
-
accountUserId: session.userId,
|
|
45260
|
-
accountOwnerGeneration: ownerGeneration
|
|
45261
|
-
});
|
|
45823
|
+
failed.push(entry);
|
|
45262
45824
|
}
|
|
45263
|
-
continue;
|
|
45264
45825
|
}
|
|
45265
|
-
|
|
45266
|
-
|
|
45267
|
-
|
|
45268
|
-
revision: this.nextChatClientRevision(),
|
|
45269
|
-
notification
|
|
45270
|
-
});
|
|
45271
|
-
}
|
|
45272
|
-
return pending.filter(([uid]) => failedUids.has(uid));
|
|
45826
|
+
}));
|
|
45827
|
+
await Promise.all(notificationLanes);
|
|
45828
|
+
return failed;
|
|
45273
45829
|
}
|
|
45274
45830
|
emitChatClientEvent(event) {
|
|
45275
45831
|
for (const listener of [...this.chatClientListeners]) listener(event);
|
|
@@ -46119,7 +46675,7 @@ var RecordReeditSubmissions = class {
|
|
|
46119
46675
|
};
|
|
46120
46676
|
//#endregion
|
|
46121
46677
|
//#region src/services/record-reedit-attachments.ts
|
|
46122
|
-
const invalid$
|
|
46678
|
+
const invalid$3 = () => new ArkmePluginError("record-reedit-attachment-invalid", "附件引用无效或不属于这条快记,请重新读取后选择", false, 409);
|
|
46123
46679
|
const refs = (payload) => Array.isArray(payload?.media_refs) ? payload.media_refs.map(objectValue$2) : [];
|
|
46124
46680
|
function recordReeditIsBackgroundSound(ref) {
|
|
46125
46681
|
return ref.content_file_role === 4;
|
|
@@ -46141,14 +46697,14 @@ function recordReeditAttachmentSelection(value, payload) {
|
|
|
46141
46697
|
try {
|
|
46142
46698
|
selection = parseArkmeRecordReeditAttachments(value);
|
|
46143
46699
|
} catch {
|
|
46144
|
-
throw invalid$
|
|
46700
|
+
throw invalid$3();
|
|
46145
46701
|
}
|
|
46146
46702
|
const groups = recordReeditMediaGroups(payload);
|
|
46147
46703
|
const supported = new Set(groups.map((group) => group.fileAssetUid));
|
|
46148
|
-
if (selection.some((item) => item.fileAssetUid !== void 0 && !supported.has(item.fileAssetUid))) throw invalid$
|
|
46704
|
+
if (selection.some((item) => item.fileAssetUid !== void 0 && !supported.has(item.fileAssetUid))) throw invalid$3();
|
|
46149
46705
|
const grouped = new Set(groups.flatMap((group) => group.refs));
|
|
46150
|
-
if (refs(payload).some((ref) => !recordReeditIsBackgroundSound(ref) && ref.render_role === 4 && !groups.some((group) => group.refs.some((item) => item.file_asset_uid === ref.file_asset_uid)))) throw invalid$
|
|
46151
|
-
if (groups.some((group) => group.fileAssetUid === "") || grouped.size !== groups.reduce((sum, group) => sum + group.refs.length, 0)) throw invalid$
|
|
46706
|
+
if (refs(payload).some((ref) => !recordReeditIsBackgroundSound(ref) && ref.render_role === 4 && !groups.some((group) => group.refs.some((item) => item.file_asset_uid === ref.file_asset_uid)))) throw invalid$3();
|
|
46707
|
+
if (groups.some((group) => group.fileAssetUid === "") || grouped.size !== groups.reduce((sum, group) => sum + group.refs.length, 0)) throw invalid$3();
|
|
46152
46708
|
return selection;
|
|
46153
46709
|
}
|
|
46154
46710
|
function recordReeditAttachmentChanges(payload, selection) {
|
|
@@ -46170,11 +46726,11 @@ function recordReeditWithAttachments(payload, selection, uploads) {
|
|
|
46170
46726
|
const media = selection.flatMap((item) => {
|
|
46171
46727
|
if (item.fileAssetUid !== void 0) {
|
|
46172
46728
|
const group = groups.find((value) => value.fileAssetUid === item.fileAssetUid);
|
|
46173
|
-
if (group === void 0) throw invalid$
|
|
46729
|
+
if (group === void 0) throw invalid$3();
|
|
46174
46730
|
return group.refs.map((ref) => structuredClone(ref));
|
|
46175
46731
|
}
|
|
46176
46732
|
const asset = uploads.get(item.fileRef);
|
|
46177
|
-
if (asset === void 0 || asset.fileAssetUid.trim() === "") throw invalid$
|
|
46733
|
+
if (asset === void 0 || asset.fileAssetUid.trim() === "") throw invalid$3();
|
|
46178
46734
|
return [{
|
|
46179
46735
|
file_asset_uid: asset.fileAssetUid,
|
|
46180
46736
|
render_role: 1,
|
|
@@ -47701,21 +48257,21 @@ var RecordService = class {
|
|
|
47701
48257
|
const LOCAL_FILE_REF = /^arkme-file-v1\.[0-9a-f-]{36}$/;
|
|
47702
48258
|
const ASSET_REF = /^[A-Za-z0-9._:-]{8,256}$/;
|
|
47703
48259
|
const MAX_AMPLITUDES = 4096;
|
|
47704
|
-
function invalid$
|
|
48260
|
+
function invalid$2(message) {
|
|
47705
48261
|
return new ArkmePluginError("background-sound-invalid", message, false, 400);
|
|
47706
48262
|
}
|
|
47707
48263
|
function invalidFile(message) {
|
|
47708
48264
|
return new ArkmePluginError("background-sound-file-invalid", message, false, 400);
|
|
47709
48265
|
}
|
|
47710
48266
|
function arkmeBackgroundSoundAmplitudes(values) {
|
|
47711
|
-
if (!Array.isArray(values) || values.length > MAX_AMPLITUDES || values.some((value) => typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1)) throw invalid$
|
|
48267
|
+
if (!Array.isArray(values) || values.length > MAX_AMPLITUDES || values.some((value) => typeof value !== "number" || !Number.isFinite(value) || value < 0 || value > 1)) throw invalid$2("背景音振幅数量不能超过 4096,且每项必须是 0 到 1 之间的有限数字");
|
|
47712
48268
|
return [...values];
|
|
47713
48269
|
}
|
|
47714
48270
|
function arkmeFileBackgroundSound(value, allFileRefs) {
|
|
47715
48271
|
if (value === void 0) return void 0;
|
|
47716
|
-
if (!Array.isArray(value.fileRefs) || value.fileRefs.length === 0 || value.fileRefs.some((ref) => typeof ref !== "string" || !LOCAL_FILE_REF.test(ref)) || new Set(value.fileRefs).size !== value.fileRefs.length) throw invalid$
|
|
48272
|
+
if (!Array.isArray(value.fileRefs) || value.fileRefs.length === 0 || value.fileRefs.some((ref) => typeof ref !== "string" || !LOCAL_FILE_REF.test(ref)) || new Set(value.fileRefs).size !== value.fileRefs.length) throw invalid$2("背景音文件引用为空、重复或无效");
|
|
47717
48273
|
const allowed = new Set(allFileRefs);
|
|
47718
|
-
if (value.fileRefs.some((ref) => !allowed.has(ref))) throw invalid$
|
|
48274
|
+
if (value.fileRefs.some((ref) => !allowed.has(ref))) throw invalid$2("背景音文件必须属于同一发送任务");
|
|
47719
48275
|
return {
|
|
47720
48276
|
fileRefs: [...value.fileRefs],
|
|
47721
48277
|
amplitudes: arkmeBackgroundSoundAmplitudes(value.amplitudes)
|
|
@@ -47745,10 +48301,10 @@ function normalizedBackgroundAsset(asset) {
|
|
|
47745
48301
|
}
|
|
47746
48302
|
function arkmeRichBackgroundSound(value) {
|
|
47747
48303
|
if (value === void 0) return void 0;
|
|
47748
|
-
if (!Array.isArray(value.assets) || value.assets.length === 0 || value.assets.length > 20) throw invalid$
|
|
48304
|
+
if (!Array.isArray(value.assets) || value.assets.length === 0 || value.assets.length > 20) throw invalid$2("背景音资产为空或数量超限");
|
|
47749
48305
|
const assets = value.assets.map(normalizedBackgroundAsset);
|
|
47750
48306
|
const identities = assets.map((asset) => asset.fileAssetUid);
|
|
47751
|
-
if (new Set(identities).size !== identities.length) throw invalid$
|
|
48307
|
+
if (new Set(identities).size !== identities.length) throw invalid$2("背景音资产不能重复");
|
|
47752
48308
|
return {
|
|
47753
48309
|
assets,
|
|
47754
48310
|
amplitudes: arkmeBackgroundSoundAmplitudes(value.amplitudes)
|
|
@@ -49252,12 +49808,13 @@ var ChatService = class {
|
|
|
49252
49808
|
if (!options.signal?.aborted && cacheEpoch === (this.runtime.memberCacheEpoch?.() ?? 0)) await this.runtime.stateStore.mergeConversationMembers?.(session.userId, source.ownerRef, result).catch(() => void 0);
|
|
49253
49809
|
return result;
|
|
49254
49810
|
}
|
|
49255
|
-
async memberRead(session, group, path, body, signal) {
|
|
49811
|
+
async memberRead(session, group, path, body, signal, cacheMs) {
|
|
49256
49812
|
try {
|
|
49257
49813
|
return await this.runtime.authenticatedChatPost(path, body, session, signal, {
|
|
49258
49814
|
lane: path.endsWith("/members/page") ? "interactive-read" : "background-read",
|
|
49259
49815
|
key: `members:${this.runtime.memberCacheEpoch?.() ?? 0}:${path}:${JSON.stringify(body)}`,
|
|
49260
|
-
failureCooldownMs: 2e3
|
|
49816
|
+
failureCooldownMs: 2e3,
|
|
49817
|
+
...cacheMs === void 0 ? {} : { cacheMs }
|
|
49261
49818
|
});
|
|
49262
49819
|
} catch (error) {
|
|
49263
49820
|
if (invalidatesMemberSnapshot(error)) {
|
|
@@ -50379,6 +50936,49 @@ var ChatService = class {
|
|
|
50379
50936
|
recordOwnerUserId: reference.recordOwnerUserId
|
|
50380
50937
|
};
|
|
50381
50938
|
}
|
|
50939
|
+
async reactionTarget(sourceRef, messageActionRef) {
|
|
50940
|
+
const session = await this.runtime.requireSession();
|
|
50941
|
+
const source = await this.source.openSourceRef(sourceRef.trim(), session.userId);
|
|
50942
|
+
const reference = await this.openMessageActionRef(messageActionRef, session.userId, source);
|
|
50943
|
+
if (reference.sourceKind === "record") return {
|
|
50944
|
+
record_uid: reference.recordUid,
|
|
50945
|
+
owned: true
|
|
50946
|
+
};
|
|
50947
|
+
return {
|
|
50948
|
+
chat_session_uid: reference.chatSessionUid,
|
|
50949
|
+
rel_uid: reference.relationUid
|
|
50950
|
+
};
|
|
50951
|
+
}
|
|
50952
|
+
/** Keep viewer-owned remarks separate from group nicknames and public profiles. */
|
|
50953
|
+
async reactionActorLabels(sourceRef, userIds, signal) {
|
|
50954
|
+
const session = await this.runtime.requireSession();
|
|
50955
|
+
const source = await this.source.openSourceRef(sourceRef.trim(), session.userId);
|
|
50956
|
+
const names = /* @__PURE__ */ new Map();
|
|
50957
|
+
if (source.kind !== "group_chat" && source.kind !== "private_chat") return names;
|
|
50958
|
+
const ids = [...new Set(userIds)].sort((left, right) => left - right);
|
|
50959
|
+
for (let offset = 0; offset < ids.length; offset += 50) {
|
|
50960
|
+
signal?.throwIfAborted();
|
|
50961
|
+
const batch = ids.slice(offset, offset + 50);
|
|
50962
|
+
const data = await this.memberRead(session, source.ownerRef, "/api/v1/chats/members/by-user-ids", {
|
|
50963
|
+
chat_session_uid: source.ownerRef,
|
|
50964
|
+
user_ids: batch,
|
|
50965
|
+
active_only: true,
|
|
50966
|
+
include_stats: false
|
|
50967
|
+
}, signal, 5e3);
|
|
50968
|
+
const items = listValue$16(data.items).map(objectValue$2);
|
|
50969
|
+
if (stringValue$2(data.chat_session_uid) !== source.ownerRef || !Array.isArray(data.items) || items.length > batch.length || items.some((item) => !batch.includes(numberValue$19(item.user_id)) || numberValue$19(item.status) !== 1)) throw new ArkmePluginError("member-presentation-invalid-response", "成员资料响应无效", true, 502);
|
|
50970
|
+
for (const item of items) {
|
|
50971
|
+
const userId = numberValue$19(item.user_id);
|
|
50972
|
+
const groupNickname = source.kind === "group_chat" ? firstUsableChatMemberName([item.display_name_snapshot], userId) : "";
|
|
50973
|
+
const remark = userId === session.userId ? "" : normalizedJoinDisplayName(item.remark);
|
|
50974
|
+
names.set(userId, {
|
|
50975
|
+
remark,
|
|
50976
|
+
groupNickname
|
|
50977
|
+
});
|
|
50978
|
+
}
|
|
50979
|
+
}
|
|
50980
|
+
return names;
|
|
50981
|
+
}
|
|
50382
50982
|
async sourceMessageExtensionContext(sourceRef, messageActionRef, options = {}) {
|
|
50383
50983
|
const session = await this.runtime.requireSession();
|
|
50384
50984
|
const source = await this.source.openSourceRef(sourceRef.trim(), session.userId);
|
|
@@ -83924,13 +84524,13 @@ var GroupService = class {
|
|
|
83924
84524
|
};
|
|
83925
84525
|
//#endregion
|
|
83926
84526
|
//#region src/services/common-group-service.ts
|
|
83927
|
-
const invalid = () => new ArkmePluginError("common-groups-response-invalid", "共同群聊响应不完整,请重试", true, 502);
|
|
84527
|
+
const invalid$1 = () => new ArkmePluginError("common-groups-response-invalid", "共同群聊响应不完整,请重试", true, 502);
|
|
83928
84528
|
function commonGroupChanges(value, known, after) {
|
|
83929
84529
|
const raw = objectValue$2(value);
|
|
83930
|
-
if (!Array.isArray(raw.items) || !Array.isArray(raw.removed) || typeof raw.has_more !== "boolean" || raw.items.length > 20 || raw.removed.length > 20) throw invalid();
|
|
84530
|
+
if (!Array.isArray(raw.items) || !Array.isArray(raw.removed) || typeof raw.has_more !== "boolean" || raw.items.length > 20 || raw.removed.length > 20) throw invalid$1();
|
|
83931
84531
|
const items = raw.items.map((value) => {
|
|
83932
84532
|
const row = objectValue$2(value);
|
|
83933
|
-
if (typeof row.chat_session_uid !== "string" || !row.chat_session_uid || row.chat_session_uid.length > 128 || typeof row.title !== "string" || row.title.length > 4096 || !Number.isSafeInteger(row.member_count) || Number(row.member_count) < 0) throw invalid();
|
|
84533
|
+
if (typeof row.chat_session_uid !== "string" || !row.chat_session_uid || row.chat_session_uid.length > 128 || typeof row.title !== "string" || row.title.length > 4096 || !Number.isSafeInteger(row.member_count) || Number(row.member_count) < 0) throw invalid$1();
|
|
83934
84534
|
return {
|
|
83935
84535
|
uid: row.chat_session_uid,
|
|
83936
84536
|
title: row.title,
|
|
@@ -83938,14 +84538,14 @@ function commonGroupChanges(value, known, after) {
|
|
|
83938
84538
|
};
|
|
83939
84539
|
});
|
|
83940
84540
|
const removed = raw.removed;
|
|
83941
|
-
if (removed.some((uid) => typeof uid !== "string" || !known.includes(uid))) throw invalid();
|
|
84541
|
+
if (removed.some((uid) => typeof uid !== "string" || !known.includes(uid))) throw invalid$1();
|
|
83942
84542
|
const identities = [...items.map((row) => row.uid), ...removed];
|
|
83943
|
-
if (new Set(identities).size !== identities.length) throw invalid();
|
|
84543
|
+
if (new Set(identities).size !== identities.length) throw invalid$1();
|
|
83944
84544
|
if (known.length) {
|
|
83945
|
-
if (raw.has_more || identities.length !== known.length || identities.some((uid) => !known.includes(String(uid)))) throw invalid();
|
|
83946
|
-
} else if (removed.length || items.some((row, i) => row.uid <= (items[i - 1]?.uid ?? after))) throw invalid();
|
|
84545
|
+
if (raw.has_more || identities.length !== known.length || identities.some((uid) => !known.includes(String(uid)))) throw invalid$1();
|
|
84546
|
+
} else if (removed.length || items.some((row, i) => row.uid <= (items[i - 1]?.uid ?? after))) throw invalid$1();
|
|
83947
84547
|
const next = raw.has_more ? raw.next_after : "";
|
|
83948
|
-
if (typeof next !== "string" || raw.has_more && (!items.length || next !== items.at(-1)?.uid || next <= after)) throw invalid();
|
|
84548
|
+
if (typeof next !== "string" || raw.has_more && (!items.length || next !== items.at(-1)?.uid || next <= after)) throw invalid$1();
|
|
83949
84549
|
return {
|
|
83950
84550
|
items,
|
|
83951
84551
|
removed,
|
|
@@ -87182,7 +87782,7 @@ var ProfileService = class {
|
|
|
87182
87782
|
async userCard(userId, signal) {
|
|
87183
87783
|
const session = await this.runtime.requireSession();
|
|
87184
87784
|
if (!Number.isSafeInteger(userId) || userId <= 0) throw new ArkmePluginError("user-card-target-invalid", "用户信息参数无效", false);
|
|
87185
|
-
const profile = (await this.publicProfileSummariesByUserIds([userId], session, signal)).get(userId);
|
|
87785
|
+
const profile = (await this.publicProfileSummariesByUserIds([userId], session, signal, 0)).get(userId);
|
|
87186
87786
|
return {
|
|
87187
87787
|
displayName: profile?.displayName ?? "群成员",
|
|
87188
87788
|
...profile?.avatarUrl === void 0 ? {} : { avatarRef: await this.sealProfileImageRef(session.userId, userId) }
|
|
@@ -87332,7 +87932,7 @@ var ProfileService = class {
|
|
|
87332
87932
|
const avatarRef = profile.avatarRef.trim();
|
|
87333
87933
|
return /^https?:\/\//i.test(avatarRef) || fileAssetAvatarRef(avatarRef) !== void 0;
|
|
87334
87934
|
}
|
|
87335
|
-
async publicProfileSummariesByUserIds(userIds, session, signal) {
|
|
87935
|
+
async publicProfileSummariesByUserIds(userIds, session, signal, maxAgeMillis = PUBLIC_PROFILE_CACHE_TTL_MS) {
|
|
87336
87936
|
const normalized = [...new Set(userIds.filter((userId) => Number.isSafeInteger(userId) && userId > 0))].sort((left, right) => left - right);
|
|
87337
87937
|
const profiles = /* @__PURE__ */ new Map();
|
|
87338
87938
|
const missing = [];
|
|
@@ -87340,7 +87940,7 @@ var ProfileService = class {
|
|
|
87340
87940
|
for (const [key, cached] of this.publicProfileCache) if (cached.expiresAtMillis <= now) this.publicProfileCache.delete(key);
|
|
87341
87941
|
for (const userId of normalized) {
|
|
87342
87942
|
const cached = this.publicProfileCache.get(`${String(session.userId)}:${String(userId)}`);
|
|
87343
|
-
if (cached === void 0 || cached.expiresAtMillis <= now) {
|
|
87943
|
+
if (cached === void 0 || cached.expiresAtMillis <= now || cached.expiresAtMillis - (cached.value === null ? PUBLIC_PROFILE_NEGATIVE_CACHE_TTL_MS : PUBLIC_PROFILE_CACHE_TTL_MS) + maxAgeMillis <= now) {
|
|
87344
87944
|
missing.push(userId);
|
|
87345
87945
|
continue;
|
|
87346
87946
|
}
|
|
@@ -87884,6 +88484,28 @@ var RelatedQuickNoteService = class {
|
|
|
87884
88484
|
}
|
|
87885
88485
|
};
|
|
87886
88486
|
//#endregion
|
|
88487
|
+
//#region src/recording-search-version.ts
|
|
88488
|
+
/** Public Audio contract: hash raw decrypted text, retaining whitespace and Unicode. */
|
|
88489
|
+
function recordingSearchVersion(item) {
|
|
88490
|
+
return createHash("sha256").update([
|
|
88491
|
+
item.sessionId,
|
|
88492
|
+
item.childId,
|
|
88493
|
+
item.asrItemIndex,
|
|
88494
|
+
item.transcriptSource,
|
|
88495
|
+
item.startAtMillis,
|
|
88496
|
+
item.endAtMillis,
|
|
88497
|
+
item.text
|
|
88498
|
+
].join("\n"), "utf8").digest("hex");
|
|
88499
|
+
}
|
|
88500
|
+
function recordingSearchIdentityHash(item) {
|
|
88501
|
+
return createHash("sha256").update(JSON.stringify([
|
|
88502
|
+
item.sessionId,
|
|
88503
|
+
item.transcriptSource,
|
|
88504
|
+
item.childId,
|
|
88505
|
+
item.itemIndex
|
|
88506
|
+
]), "utf8").digest("hex");
|
|
88507
|
+
}
|
|
88508
|
+
//#endregion
|
|
87887
88509
|
//#region src/recording-import-coordinator.ts
|
|
87888
88510
|
function importFailure(error) {
|
|
87889
88511
|
if (error instanceof RecordingImportContractError) return {
|
|
@@ -88417,6 +89039,7 @@ function projectRecordingTranscripts(response, speakerResponse, profilesByUserId
|
|
|
88417
89039
|
isSelf,
|
|
88418
89040
|
isBackground,
|
|
88419
89041
|
text,
|
|
89042
|
+
rawTranscriptText: stringValue(row.t ?? row.text),
|
|
88420
89043
|
...generationText === text ? {} : { generationText },
|
|
88421
89044
|
...stringValue(row.p).trim() === "" ? {} : { event: stringValue(row.p).trim() },
|
|
88422
89045
|
sourceIndex,
|
|
@@ -89817,6 +90440,18 @@ var RecordingService = class {
|
|
|
89817
90440
|
return {
|
|
89818
90441
|
itemId: item.itemId,
|
|
89819
90442
|
itemRef: this.sealRecordingRefWithKey("arkme-recording-item-v1", payload, refKey),
|
|
90443
|
+
...item.transcriptSource !== "system" ? {} : {
|
|
90444
|
+
searchIdentityHash: recordingSearchIdentityHash({
|
|
90445
|
+
sessionId: item.sessionId,
|
|
90446
|
+
childId: item.childId,
|
|
90447
|
+
itemIndex: item.asrItemIndex,
|
|
90448
|
+
transcriptSource: item.transcriptSource
|
|
90449
|
+
}),
|
|
90450
|
+
searchVersion: recordingSearchVersion({
|
|
90451
|
+
...item,
|
|
90452
|
+
text: item.rawTranscriptText ?? item.text
|
|
90453
|
+
})
|
|
90454
|
+
},
|
|
89820
90455
|
transcriptSource: item.transcriptSource,
|
|
89821
90456
|
sessionKey: createHmac("sha256", refKey).update(`recording-session:${String(viewerUserId)}:${item.sessionId}`).digest("base64url"),
|
|
89822
90457
|
startAtMillis: item.startAtMillis,
|
|
@@ -90008,6 +90643,68 @@ var RecordingService = class {
|
|
|
90008
90643
|
}
|
|
90009
90644
|
};
|
|
90010
90645
|
//#endregion
|
|
90646
|
+
//#region src/services/recording-import-upload-retry.ts
|
|
90647
|
+
const RECORDING_UPLOAD_RETRY_DELAYS = [
|
|
90648
|
+
1e3,
|
|
90649
|
+
2e3,
|
|
90650
|
+
4e3,
|
|
90651
|
+
8e3,
|
|
90652
|
+
16e3
|
|
90653
|
+
];
|
|
90654
|
+
const RECORDING_UPLOAD_REQUEST_TIMEOUT = 300 * 1e3;
|
|
90655
|
+
const transientStatuses = /* @__PURE__ */ new Set([
|
|
90656
|
+
408,
|
|
90657
|
+
429,
|
|
90658
|
+
500,
|
|
90659
|
+
502,
|
|
90660
|
+
503,
|
|
90661
|
+
504
|
|
90662
|
+
]);
|
|
90663
|
+
const transientNames = /* @__PURE__ */ new Set([
|
|
90664
|
+
"ResponseTimeoutError",
|
|
90665
|
+
"ConnectionTimeoutError",
|
|
90666
|
+
"SocketAssignTimeoutError"
|
|
90667
|
+
]);
|
|
90668
|
+
const transientCodes = /* @__PURE__ */ new Set([
|
|
90669
|
+
"ECONNRESET",
|
|
90670
|
+
"ECONNREFUSED",
|
|
90671
|
+
"ECONNABORTED",
|
|
90672
|
+
"ETIMEDOUT",
|
|
90673
|
+
"EPIPE",
|
|
90674
|
+
"EAI_AGAIN",
|
|
90675
|
+
"ENOTFOUND",
|
|
90676
|
+
"ENETUNREACH",
|
|
90677
|
+
"EHOSTUNREACH"
|
|
90678
|
+
]);
|
|
90679
|
+
function isRetryableRecordingUploadError(error) {
|
|
90680
|
+
if (error === null || typeof error !== "object" || error instanceof RecordingImportContractError) return false;
|
|
90681
|
+
const { status, name, code } = error;
|
|
90682
|
+
if (name === "cancel" || name === "abort" || name === "AbortError") return false;
|
|
90683
|
+
if (typeof status === "number" && status >= 400) return transientStatuses.has(status);
|
|
90684
|
+
if (typeof code === "string" && code !== "" && transientCodes.has(code)) return true;
|
|
90685
|
+
if ((status === -1 || status === -2) && code === name && typeof name === "string" && (transientNames.has(name) || name === "RequestError" || name === "ResponseError")) return true;
|
|
90686
|
+
if (typeof code === "string" && code !== "") return false;
|
|
90687
|
+
return typeof name === "string" && transientNames.has(name);
|
|
90688
|
+
}
|
|
90689
|
+
function throwIfRecordingUploadAborted(signal) {
|
|
90690
|
+
if (signal?.aborted === true) throw new RecordingImportContractError("recording-import-cancelled", "录音导入已取消");
|
|
90691
|
+
}
|
|
90692
|
+
function waitForRecordingUploadRetry(delay, signal) {
|
|
90693
|
+
return new Promise((resolve, reject) => {
|
|
90694
|
+
const abort = () => {
|
|
90695
|
+
clearTimeout(timer);
|
|
90696
|
+
signal?.removeEventListener("abort", abort);
|
|
90697
|
+
reject(new RecordingImportContractError("recording-import-cancelled", "录音导入已取消"));
|
|
90698
|
+
};
|
|
90699
|
+
const timer = setTimeout(() => {
|
|
90700
|
+
signal?.removeEventListener("abort", abort);
|
|
90701
|
+
resolve();
|
|
90702
|
+
}, Math.round(delay * (1 + Math.random() * .3)));
|
|
90703
|
+
signal?.addEventListener("abort", abort, { once: true });
|
|
90704
|
+
if (signal?.aborted === true) abort();
|
|
90705
|
+
});
|
|
90706
|
+
}
|
|
90707
|
+
//#endregion
|
|
90011
90708
|
//#region src/services/recording-import-gateway.ts
|
|
90012
90709
|
const AUDIO_SESSION_RECOVERY_LIMIT = 500;
|
|
90013
90710
|
const AUDIO_IMPORT_DUPLICATE_BATCH_SIZE = 100;
|
|
@@ -90361,6 +91058,8 @@ var AudioRecordingImportGateway = class {
|
|
|
90361
91058
|
accessKeyId: credentials.accessKeyId,
|
|
90362
91059
|
accessKeySecret: credentials.accessKeySecret,
|
|
90363
91060
|
stsToken: credentials.stsToken,
|
|
91061
|
+
timeout: RECORDING_UPLOAD_REQUEST_TIMEOUT,
|
|
91062
|
+
retryMax: 0,
|
|
90364
91063
|
refreshSTSTokenInterval: 300 * 1e3,
|
|
90365
91064
|
refreshSTSToken: async () => {
|
|
90366
91065
|
await this.requireJobSession(job);
|
|
@@ -90391,17 +91090,40 @@ var AudioRecordingImportGateway = class {
|
|
|
90391
91090
|
signal?.addEventListener("abort", abort, { once: true });
|
|
90392
91091
|
try {
|
|
90393
91092
|
const objectPath = `pc_upload/${String(job.userId)}/${job.sessionId}/${remoteFileName(job)}`;
|
|
90394
|
-
|
|
90395
|
-
|
|
90396
|
-
|
|
90397
|
-
|
|
90398
|
-
|
|
90399
|
-
|
|
90400
|
-
|
|
90401
|
-
|
|
90402
|
-
|
|
91093
|
+
let latestCheckpoint = job.uploadCheckpoint;
|
|
91094
|
+
const upload = (async () => {
|
|
91095
|
+
for (let attempt = 0;; attempt += 1) {
|
|
91096
|
+
throwIfRecordingUploadAborted(signal);
|
|
91097
|
+
if (attempt > 0) await this.requireJobSession(job);
|
|
91098
|
+
throwIfRecordingUploadAborted(signal);
|
|
91099
|
+
let progressFailed = false;
|
|
91100
|
+
try {
|
|
91101
|
+
await client.multipartUpload(objectPath, job.sourceHandle, {
|
|
91102
|
+
parallel: 1,
|
|
91103
|
+
partSize: 5 * 1024 * 1024,
|
|
91104
|
+
checkpoint: latestCheckpoint,
|
|
91105
|
+
mime: job.mimeType,
|
|
91106
|
+
progress: async (percentage, checkpoint) => {
|
|
91107
|
+
try {
|
|
91108
|
+
if (signal?.aborted === true) throw new RecordingImportContractError("recording-import-cancelled", "录音导入已取消");
|
|
91109
|
+
const bounded = Math.min(1, Math.max(0, percentage));
|
|
91110
|
+
await onProgress(Math.round(job.fileSize * bounded), checkpoint);
|
|
91111
|
+
if (checkpoint !== void 0) latestCheckpoint = checkpoint;
|
|
91112
|
+
} catch (error) {
|
|
91113
|
+
progressFailed = true;
|
|
91114
|
+
throw error;
|
|
91115
|
+
}
|
|
91116
|
+
}
|
|
91117
|
+
});
|
|
91118
|
+
return;
|
|
91119
|
+
} catch (error) {
|
|
91120
|
+
const delay = RECORDING_UPLOAD_RETRY_DELAYS[attempt];
|
|
91121
|
+
if (signal?.aborted === true || progressFailed || !isRetryableRecordingUploadError(error)) throw error;
|
|
91122
|
+
if (delay === void 0) throw new ArkmePluginError("recording-import-upload-failed", error instanceof Error ? error.message : "录音上传失败", true, 503, { cause: error });
|
|
91123
|
+
await waitForRecordingUploadRetry(delay, signal);
|
|
91124
|
+
}
|
|
90403
91125
|
}
|
|
90404
|
-
});
|
|
91126
|
+
})();
|
|
90405
91127
|
await (signal === void 0 ? upload : Promise.race([upload, aborted]));
|
|
90406
91128
|
} finally {
|
|
90407
91129
|
signal?.removeEventListener("abort", abort);
|
|
@@ -90789,6 +91511,60 @@ var RelatedRecordingService = class {
|
|
|
90789
91511
|
}
|
|
90790
91512
|
};
|
|
90791
91513
|
//#endregion
|
|
91514
|
+
//#region src/recording-search-result.ts
|
|
91515
|
+
function invalid() {
|
|
91516
|
+
throw new ArkmePluginError("recording-search-invalid", "录音搜索结果已失效,请重试", true);
|
|
91517
|
+
}
|
|
91518
|
+
function segment(raw) {
|
|
91519
|
+
const value = objectValue$2(raw);
|
|
91520
|
+
if (!stringValue$2(value.session_id).trim() || !stringValue$2(value.child_id).trim() || !Number.isSafeInteger(value.item_index) || Number(value.item_index) < 0 || value.transcript_source !== "system" || !stringValue$2(value.transcript_version).trim() || typeof value.text !== "string" || !Number.isSafeInteger(value.start_at) || !Number.isSafeInteger(value.end_at)) invalid();
|
|
91521
|
+
const speaker = objectValue$2(value.speaker);
|
|
91522
|
+
return {
|
|
91523
|
+
sessionId: String(value.session_id),
|
|
91524
|
+
childId: String(value.child_id),
|
|
91525
|
+
itemIndex: Number(value.item_index),
|
|
91526
|
+
transcriptSource: "system",
|
|
91527
|
+
transcriptVersion: String(value.transcript_version),
|
|
91528
|
+
startAtMillis: Number(value.start_at),
|
|
91529
|
+
endAtMillis: Number(value.end_at),
|
|
91530
|
+
text: String(value.text),
|
|
91531
|
+
...value.speaker === void 0 ? {} : { speaker: {
|
|
91532
|
+
speakerId: stringValue$2(speaker.speaker_id),
|
|
91533
|
+
label: stringValue$2(speaker.label) || "未知说话人",
|
|
91534
|
+
...typeof speaker.user_id === "number" && speaker.user_id > 0 ? { userId: speaker.user_id } : {},
|
|
91535
|
+
...typeof speaker.color_index === "number" ? { colorIndex: speaker.color_index } : {}
|
|
91536
|
+
} }
|
|
91537
|
+
};
|
|
91538
|
+
}
|
|
91539
|
+
function parseRecordingSearchItem(raw) {
|
|
91540
|
+
const value = objectValue$2(raw);
|
|
91541
|
+
const match = segment(value.match);
|
|
91542
|
+
const previous = value.previous == null ? void 0 : segment(value.previous);
|
|
91543
|
+
const next = value.next == null ? void 0 : segment(value.next);
|
|
91544
|
+
if (match.sessionId !== value.session_id) invalid();
|
|
91545
|
+
const day = Number(value.date_stamp);
|
|
91546
|
+
if ([previous, next].some((item) => item && item.sessionId !== match.sessionId && (!Number.isSafeInteger(day) || day <= 0 || item.startAtMillis < day || item.startAtMillis >= day + 864e5))) invalid();
|
|
91547
|
+
if (previous && previous.startAtMillis > match.startAtMillis || next && next.startAtMillis < match.startAtMillis) invalid();
|
|
91548
|
+
const ranges = Array.isArray(value.highlight_ranges) ? value.highlight_ranges : [];
|
|
91549
|
+
const length = Array.from(match.text).length;
|
|
91550
|
+
const highlightRanges = ranges.map(objectValue$2).map((range) => ({
|
|
91551
|
+
start: Number(range.start_index),
|
|
91552
|
+
length: Number(range.length)
|
|
91553
|
+
})).filter((range) => Number.isSafeInteger(range.start) && Number.isSafeInteger(range.length) && range.start >= 0 && range.length > 0 && range.start + range.length <= length).sort((a, b) => a.start - b.start).filter((range, index, all) => index === 0 || range.start >= all[index - 1].start + all[index - 1].length);
|
|
91554
|
+
return {
|
|
91555
|
+
sessionId: match.sessionId,
|
|
91556
|
+
dateStamp: Number(value.date_stamp) || 0,
|
|
91557
|
+
startAtMillis: match.startAtMillis,
|
|
91558
|
+
snippet: match.text,
|
|
91559
|
+
score: Number(value.score) || 0,
|
|
91560
|
+
match,
|
|
91561
|
+
highlightRanges,
|
|
91562
|
+
...stringValue$2(value.record_uid) ? { recordUid: String(value.record_uid) } : {},
|
|
91563
|
+
...previous ? { previous } : {},
|
|
91564
|
+
...next ? { next } : {}
|
|
91565
|
+
};
|
|
91566
|
+
}
|
|
91567
|
+
//#endregion
|
|
90792
91568
|
//#region src/dsh-search-origins.ts
|
|
90793
91569
|
/** Resolve sync identity using the public index and exact deterministic record IDs. */
|
|
90794
91570
|
async function resolveDshSearchOrigins(provider, items, signal) {
|
|
@@ -91115,13 +91891,15 @@ var SearchService = class {
|
|
|
91115
91891
|
media;
|
|
91116
91892
|
source;
|
|
91117
91893
|
privacy;
|
|
91894
|
+
profile;
|
|
91118
91895
|
localDshQuery;
|
|
91119
|
-
constructor(runtime, record, media, source, privacy = new ArkmePrivacyVisibilityService(runtime)) {
|
|
91896
|
+
constructor(runtime, record, media, source, privacy = new ArkmePrivacyVisibilityService(runtime), profile) {
|
|
91120
91897
|
this.runtime = runtime;
|
|
91121
91898
|
this.record = record;
|
|
91122
91899
|
this.media = media;
|
|
91123
91900
|
this.source = source;
|
|
91124
91901
|
this.privacy = privacy;
|
|
91902
|
+
this.profile = profile;
|
|
91125
91903
|
}
|
|
91126
91904
|
async searchRecords(options) {
|
|
91127
91905
|
const query = options.query.trim();
|
|
@@ -91483,22 +92261,37 @@ var SearchService = class {
|
|
|
91483
92261
|
const session = await this.runtime.requireSession();
|
|
91484
92262
|
const data = await this.runtime.authenticatedPost("/api/v1/search/recordings/query", {
|
|
91485
92263
|
keyword: query,
|
|
92264
|
+
result_mode: "segments",
|
|
91486
92265
|
limit: Math.min(50, Math.max(1, Math.trunc(options.limit))),
|
|
91487
92266
|
...options.cursor?.trim() ? { cursor: options.cursor.trim() } : {}
|
|
91488
92267
|
}, session, options.signal);
|
|
92268
|
+
const items = listValue$3(data.items).map(parseRecordingSearchItem);
|
|
92269
|
+
const segments = items.flatMap((item) => [
|
|
92270
|
+
item.previous,
|
|
92271
|
+
item.match,
|
|
92272
|
+
item.next
|
|
92273
|
+
].filter((value) => value !== void 0));
|
|
92274
|
+
const userIds = [...new Set(segments.flatMap((item) => item.speaker?.userId === void 0 ? [] : [item.speaker.userId]))];
|
|
92275
|
+
if (this.profile !== void 0 && userIds.length > 0) try {
|
|
92276
|
+
const profiles = await this.profile.publicProfileSummariesByUserIds(userIds, session, options.signal);
|
|
92277
|
+
const avatars = /* @__PURE__ */ new Map();
|
|
92278
|
+
await Promise.all([...profiles].map(async ([userId, profile]) => {
|
|
92279
|
+
if (profile.avatarUrl !== void 0) avatars.set(userId, await this.profile.sealProfileImageRef(session.userId, userId));
|
|
92280
|
+
}));
|
|
92281
|
+
for (const segment of segments) {
|
|
92282
|
+
const speaker = segment.speaker;
|
|
92283
|
+
if (speaker?.userId === void 0) continue;
|
|
92284
|
+
const profile = profiles.get(speaker.userId);
|
|
92285
|
+
const avatarRef = avatars.get(speaker.userId);
|
|
92286
|
+
if (avatarRef !== void 0) speaker.avatarRef = avatarRef;
|
|
92287
|
+
if (profile && (speaker.userId === session.userId || speaker.label === "未知说话人")) speaker.label = profile.displayName.trim() || profile.nickname.trim() || speaker.label;
|
|
92288
|
+
}
|
|
92289
|
+
} catch (error) {
|
|
92290
|
+
if (options.signal?.aborted) throw error;
|
|
92291
|
+
}
|
|
91489
92292
|
const guard = objectValue$2(data.query_guard);
|
|
91490
92293
|
return {
|
|
91491
|
-
items
|
|
91492
|
-
const item = objectValue$2(raw);
|
|
91493
|
-
return {
|
|
91494
|
-
sessionId: stringValue$2(item.session_id).trim(),
|
|
91495
|
-
...stringValue$2(item.record_uid).trim() === "" ? {} : { recordUid: stringValue$2(item.record_uid).trim() },
|
|
91496
|
-
dateStamp: numberValue$2(item.date_stamp),
|
|
91497
|
-
startAtMillis: numberValue$2(item.start_at),
|
|
91498
|
-
snippet: clippedText(item.snippet, 1e3),
|
|
91499
|
-
score: numberValue$2(item.score)
|
|
91500
|
-
};
|
|
91501
|
-
}).filter((item) => item.sessionId !== "" && item.snippet !== ""),
|
|
92294
|
+
items,
|
|
91502
92295
|
hasMore: booleanValue$1(data.has_more),
|
|
91503
92296
|
...stringValue$2(data.next_cursor).trim() === "" ? {} : { nextCursor: stringValue$2(data.next_cursor).trim() },
|
|
91504
92297
|
queryGuard: {
|
|
@@ -94222,6 +95015,15 @@ var WorldService = class {
|
|
|
94222
95015
|
media;
|
|
94223
95016
|
record;
|
|
94224
95017
|
viewerLabels;
|
|
95018
|
+
/** Called only for a Record-owner-authorized received-reaction response. */
|
|
95019
|
+
async reactionReference(recordUid) {
|
|
95020
|
+
const session = await this.runtime.requireSession();
|
|
95021
|
+
return this.worldRecordRef(session.userId, recordUid, { ownerUserId: session.userId });
|
|
95022
|
+
}
|
|
95023
|
+
async reactionTarget(recordRef) {
|
|
95024
|
+
const session = await this.runtime.requireSession();
|
|
95025
|
+
return { record_uid: this.openWorldRecordRef(recordRef, session.userId).recordUid };
|
|
95026
|
+
}
|
|
94225
95027
|
worldImageRefs = /* @__PURE__ */ new Map();
|
|
94226
95028
|
worldAvatarResolutionCache = /* @__PURE__ */ new Map();
|
|
94227
95029
|
extensionPublicationShareCache = /* @__PURE__ */ new Map();
|
|
@@ -95342,7 +96144,7 @@ var ArkmeService = class {
|
|
|
95342
96144
|
await this.realtime.invalidateRecordProjection();
|
|
95343
96145
|
}, async (source, text, humans, bots, session, textFormat) => await this.chat.resolveMentions(source, text, text, humans, bots, session, void 0, textFormat));
|
|
95344
96146
|
this.calendar = new CalendarService(this.runtime, this.privacy, this.media, this.record, this.source, this.callHistory);
|
|
95345
|
-
this.search = new SearchService(this.runtime, this.record, this.media, this.source, this.privacy);
|
|
96147
|
+
this.search = new SearchService(this.runtime, this.record, this.media, this.source, this.privacy, this.profile);
|
|
95346
96148
|
if (localDshQuery !== void 0) this.search.localDshQuery = localDshQuery;
|
|
95347
96149
|
this.bot = new BotService(this.runtime, this.source);
|
|
95348
96150
|
this.messageActions = new MessageActionService(new ArkmeMessageActionGateway(this.runtime, this.source, async (target, sequence) => {
|
|
@@ -95768,6 +96570,7 @@ var ArkmeService = class {
|
|
|
95768
96570
|
messageReport: true,
|
|
95769
96571
|
userBanManagement: true,
|
|
95770
96572
|
directMessageAdmission: true,
|
|
96573
|
+
reactionsV1: true,
|
|
95771
96574
|
groupOwnerGovernance: true,
|
|
95772
96575
|
...this.config.markdownQuickNotesEnabled === true ? { markdownQuickNotes: true } : {},
|
|
95773
96576
|
...this.config.markdownLongArticlesEnabled === true ? { markdownLongArticles: true } : {},
|
|
@@ -96559,6 +97362,112 @@ var ArkmeService = class {
|
|
|
96559
97362
|
async favoriteStickers(signal) {
|
|
96560
97363
|
return await this.chat.favoriteStickers(signal);
|
|
96561
97364
|
}
|
|
97365
|
+
async reactions(input, signal) {
|
|
97366
|
+
const result = await new ReactionService(this.runtime, (target) => target.worldRecordRef !== void 0 ? this.world.reactionTarget(target.worldRecordRef) : this.chat.reactionTarget(target.sourceRef, target.messageActionRef), (uid) => this.world.reactionReference(uid), (viewer, uid) => this.source.chatDirectorySourceKey(viewer, uid), async (items, signal) => {
|
|
97367
|
+
const session = await this.runtime.requireSession();
|
|
97368
|
+
const [sources, profiles] = await Promise.all([this.source.chatSourcesBySessionUids([...new Set(items.map((item) => item.sessionUID).filter(Boolean))], signal), this.profile.publicProfileSummariesByUserIds([...new Set(items.map((item) => item.senderID).filter((id) => id > 0))], session, signal, 5e3)]);
|
|
97369
|
+
const missingAvatars = [...sources].filter(([, source]) => !source.avatarRef && !source.avatarRefs?.length && !source.groupAvatar);
|
|
97370
|
+
if (missingAvatars.length > 0) try {
|
|
97371
|
+
const hydrated = await this.source.hydrateDirectoryPage(missingAvatars.map(([, source]) => source), signal ?? new AbortController().signal);
|
|
97372
|
+
missingAvatars.forEach(([uid], index) => {
|
|
97373
|
+
if (hydrated[index]) sources.set(uid, hydrated[index]);
|
|
97374
|
+
});
|
|
97375
|
+
} catch {
|
|
97376
|
+
signal?.throwIfAborted();
|
|
97377
|
+
}
|
|
97378
|
+
const selfSource = items.some((item) => item.sourceKind === "send_to_self" && item.message) ? {
|
|
97379
|
+
sourceRef: await this.source.sealSourceRef(session.userId, "send_to_self", "all", "发给自己"),
|
|
97380
|
+
kind: "send_to_self",
|
|
97381
|
+
displayName: "发给自己",
|
|
97382
|
+
activeAtMillis: 0,
|
|
97383
|
+
unreadCount: 0
|
|
97384
|
+
} : void 0;
|
|
97385
|
+
return items.map((item) => {
|
|
97386
|
+
const source = item.sourceKind === "send_to_self" ? selfSource : sources.get(item.sessionUID);
|
|
97387
|
+
return {
|
|
97388
|
+
sourceName: item.sourceKind === "send_to_self" ? "发给自己" : source?.displayName,
|
|
97389
|
+
authorName: item.senderID === session.userId ? "我" : profiles.get(item.senderID)?.displayName,
|
|
97390
|
+
...source && item.message ? { originalMessage: {
|
|
97391
|
+
source,
|
|
97392
|
+
itemUid: item.message.recordUID,
|
|
97393
|
+
recordOwnerUserId: item.message.ownerUserID,
|
|
97394
|
+
sendAtMillis: item.message.sendAtMillis
|
|
97395
|
+
} } : {},
|
|
97396
|
+
...source ? { avatar: {
|
|
97397
|
+
...source.avatarRef ? { avatarRef: source.avatarRef } : {},
|
|
97398
|
+
...source.avatarRefs ? { avatarRefs: source.avatarRefs } : {},
|
|
97399
|
+
...source.groupAvatar ? { groupAvatar: source.groupAvatar } : {}
|
|
97400
|
+
} } : {}
|
|
97401
|
+
};
|
|
97402
|
+
});
|
|
97403
|
+
}).request(input, signal);
|
|
97404
|
+
if (`${this.config.environment}:${(await this.runtime.requireSession()).userId}` !== input.accountKey || signal?.aborted) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
97405
|
+
const actorLabels = async (sourceRef, ids) => {
|
|
97406
|
+
if (!sourceRef || !ids.length) return /* @__PURE__ */ new Map();
|
|
97407
|
+
try {
|
|
97408
|
+
return await this.chat.reactionActorLabels(sourceRef, ids, signal);
|
|
97409
|
+
} catch (error) {
|
|
97410
|
+
if (signal?.aborted) throw error;
|
|
97411
|
+
return /* @__PURE__ */ new Map();
|
|
97412
|
+
}
|
|
97413
|
+
};
|
|
97414
|
+
const actorAvatars = async (viewer, profiles) => new Map(await Promise.all([...profiles].filter(([, profile]) => profile.avatarUrl).map(async ([id]) => [id, await this.profile.sealProfileImageRef(viewer, id)])));
|
|
97415
|
+
const presentActor = (userId, profileName, label, avatarRef) => ({
|
|
97416
|
+
userId,
|
|
97417
|
+
displayName: label?.remark || profileName?.trim() || "用户",
|
|
97418
|
+
...label?.groupNickname ? { groupNickname: label.groupNickname } : {},
|
|
97419
|
+
...avatarRef ? { avatarRef } : {}
|
|
97420
|
+
});
|
|
97421
|
+
if (input.action === "query" || input.action === "groups") {
|
|
97422
|
+
const page = result;
|
|
97423
|
+
const groupPage = result;
|
|
97424
|
+
const groups = input.action === "query" ? page.items.flatMap((item) => item.actors_visible ? item.groups : []) : groupPage.items;
|
|
97425
|
+
const ids = [...new Set(groups.flatMap((group) => group.actorIds))];
|
|
97426
|
+
const session = await this.runtime.requireSession();
|
|
97427
|
+
const sourceByTarget = new Map(input.action === "query" ? input.targets.map((target) => [target.id, target.sourceRef]) : []);
|
|
97428
|
+
const sourceIds = /* @__PURE__ */ new Map();
|
|
97429
|
+
const include = (sourceRef, actorIds) => {
|
|
97430
|
+
if (!sourceRef || !actorIds.length) return;
|
|
97431
|
+
const users = sourceIds.get(sourceRef) ?? /* @__PURE__ */ new Set();
|
|
97432
|
+
actorIds.forEach((id) => users.add(id));
|
|
97433
|
+
sourceIds.set(sourceRef, users);
|
|
97434
|
+
};
|
|
97435
|
+
if (input.action === "query") {
|
|
97436
|
+
for (const item of page.items) if (item.actors_visible) include(sourceByTarget.get(item.target_id), item.groups.flatMap((group) => group.actorIds));
|
|
97437
|
+
} else include(input.target.sourceRef, ids);
|
|
97438
|
+
const [profiles, labels] = await Promise.all([this.profile.publicProfileSummariesByUserIds(ids, session, signal, 5e3), (async () => {
|
|
97439
|
+
const labels = /* @__PURE__ */ new Map();
|
|
97440
|
+
for (const [sourceRef, users] of sourceIds) labels.set(sourceRef, await actorLabels(sourceRef, [...users]));
|
|
97441
|
+
return labels;
|
|
97442
|
+
})()]);
|
|
97443
|
+
const avatars = await actorAvatars(session.userId, profiles);
|
|
97444
|
+
if (`${this.config.environment}:${(await this.runtime.requireSession()).userId}` !== input.accountKey || signal?.aborted) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
97445
|
+
const present = ({ actorIds, ...group }, sourceRef, visible = true) => ({
|
|
97446
|
+
...group,
|
|
97447
|
+
actors: visible ? actorIds.map((userId) => presentActor(userId, profiles.get(userId)?.displayName, labels.get(sourceRef ?? "")?.get(userId), avatars.get(userId))) : []
|
|
97448
|
+
});
|
|
97449
|
+
return input.action === "query" ? {
|
|
97450
|
+
...page,
|
|
97451
|
+
items: page.items.map((item) => ({
|
|
97452
|
+
...item,
|
|
97453
|
+
groups: item.groups.map((group) => present(group, sourceByTarget.get(item.target_id), item.actors_visible))
|
|
97454
|
+
}))
|
|
97455
|
+
} : {
|
|
97456
|
+
...groupPage,
|
|
97457
|
+
items: groupPage.items.map((group) => present(group, input.target.sourceRef))
|
|
97458
|
+
};
|
|
97459
|
+
}
|
|
97460
|
+
if (input.action !== "actors") return result;
|
|
97461
|
+
const page = result;
|
|
97462
|
+
const session = await this.runtime.requireSession();
|
|
97463
|
+
const [profiles, labels] = await Promise.all([this.profile.publicProfileSummariesByUserIds(page.user_ids, session, signal, 5e3), actorLabels(input.target.sourceRef, page.user_ids)]);
|
|
97464
|
+
const avatars = await actorAvatars(session.userId, profiles);
|
|
97465
|
+
if (`${this.config.environment}:${(await this.runtime.requireSession()).userId}` !== input.accountKey || signal?.aborted) throw new ArkmePluginError("reaction-account-changed", "账号已变化", false);
|
|
97466
|
+
return {
|
|
97467
|
+
items: page.user_ids.map((userId) => presentActor(userId, profiles.get(userId)?.displayName, labels.get(userId), avatars.get(userId))),
|
|
97468
|
+
has_more: page.has_more
|
|
97469
|
+
};
|
|
97470
|
+
}
|
|
96562
97471
|
async addFavoriteSticker(item, signal) {
|
|
96563
97472
|
return await this.chat.addFavoriteSticker(item, signal);
|
|
96564
97473
|
}
|
|
@@ -96777,6 +97686,12 @@ var ArkmeService = class {
|
|
|
96777
97686
|
async testLogin(userId) {
|
|
96778
97687
|
return await this.auth.testLogin(userId);
|
|
96779
97688
|
}
|
|
97689
|
+
async sendEmailBindCode(expectedUserId, email) {
|
|
97690
|
+
return await this.auth.sendEmailBindCode(expectedUserId, email);
|
|
97691
|
+
}
|
|
97692
|
+
async bindEmail(expectedUserId, email, code) {
|
|
97693
|
+
return await this.auth.bindEmail(expectedUserId, email, code);
|
|
97694
|
+
}
|
|
96780
97695
|
async sendPhoneCode(phone, captcha) {
|
|
96781
97696
|
return await this.auth.sendPhoneCode(phone, captcha);
|
|
96782
97697
|
}
|
|
@@ -96792,6 +97707,15 @@ var ArkmeService = class {
|
|
|
96792
97707
|
async verifyPhoneCode(phone, code) {
|
|
96793
97708
|
return await this.auth.verifyPhoneCode(phone, code);
|
|
96794
97709
|
}
|
|
97710
|
+
async previewCancellation(expectedUserId) {
|
|
97711
|
+
return await this.auth.previewCancellation(expectedUserId);
|
|
97712
|
+
}
|
|
97713
|
+
async submitCancellation(expectedUserId, expectedMode) {
|
|
97714
|
+
return await this.auth.submitCancellation(expectedUserId, expectedMode);
|
|
97715
|
+
}
|
|
97716
|
+
async resolveCancellationLogin(continueLogin) {
|
|
97717
|
+
return await this.auth.resolveCancellationLogin(continueLogin);
|
|
97718
|
+
}
|
|
96795
97719
|
async logout() {
|
|
96796
97720
|
return await this.auth.logout();
|
|
96797
97721
|
}
|