@xfxstudio/claworld 2026.6.10-testing.4 → 2026.6.10-testing.5
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/openclaw.plugin.json
CHANGED
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
},
|
|
18
18
|
"name": "Claworld Persona Relay",
|
|
19
19
|
"description": "Claworld relay world channel plugin for OpenClaw.",
|
|
20
|
-
"version": "2026.6.10-testing.
|
|
20
|
+
"version": "2026.6.10-testing.5",
|
|
21
21
|
"configSchema": {
|
|
22
22
|
"type": "object",
|
|
23
23
|
"additionalProperties": false,
|
package/package.json
CHANGED
|
@@ -54,3 +54,14 @@ export function resolveConversationViewerRoot({
|
|
|
54
54
|
|| path.join(homeDir, '.openclaw');
|
|
55
55
|
return path.resolve(stateDir.replace(/^~(?=$|\/|\\)/, homeDir), 'claworld', 'conversation-viewers');
|
|
56
56
|
}
|
|
57
|
+
|
|
58
|
+
export function resolveConversationViewerOpenClawRoot({
|
|
59
|
+
env = null,
|
|
60
|
+
homeDir = os.homedir(),
|
|
61
|
+
} = {}) {
|
|
62
|
+
const sourceEnv = resolveEnv(env);
|
|
63
|
+
const stateDir = normalizeText(sourceEnv.OPENCLAW_STATE_DIR, null)
|
|
64
|
+
|| normalizeText(sourceEnv.OPENCLAW_HOME, null)
|
|
65
|
+
|| path.join(homeDir, '.openclaw');
|
|
66
|
+
return path.resolve(stateDir.replace(/^~(?=$|\/|\\)/, homeDir));
|
|
67
|
+
}
|
|
@@ -5,6 +5,7 @@ import { pathToFileURL } from 'node:url';
|
|
|
5
5
|
import { buildRuntimeAuthHeaders } from './account-identity.js';
|
|
6
6
|
import {
|
|
7
7
|
resolveConversationViewerGatewayBaseUrl,
|
|
8
|
+
resolveConversationViewerOpenClawRoot,
|
|
8
9
|
resolveConversationViewerRoot,
|
|
9
10
|
} from './conversation-viewer-env.js';
|
|
10
11
|
import { loadCurrentConfig } from './register-tooling.js';
|
|
@@ -14,6 +15,7 @@ export const CONVERSATION_VIEWER_ROUTE_PREFIX = '/plugins/claworld/conversation-
|
|
|
14
15
|
export const CONVERSATION_VIEWER_SCHEMA = 'claworld.conversationViewer.v1';
|
|
15
16
|
export {
|
|
16
17
|
resolveConversationViewerGatewayBaseUrl,
|
|
18
|
+
resolveConversationViewerOpenClawRoot,
|
|
17
19
|
resolveConversationViewerRoot,
|
|
18
20
|
} from './conversation-viewer-env.js';
|
|
19
21
|
|
|
@@ -1008,6 +1010,294 @@ function collectTurns(turnsPayload = {}) {
|
|
|
1008
1010
|
});
|
|
1009
1011
|
}
|
|
1010
1012
|
|
|
1013
|
+
function uniqueNormalized(values = []) {
|
|
1014
|
+
const seen = new Set();
|
|
1015
|
+
const next = [];
|
|
1016
|
+
for (const value of values) {
|
|
1017
|
+
const normalized = normalizeText(value, null);
|
|
1018
|
+
if (!normalized || seen.has(normalized)) continue;
|
|
1019
|
+
seen.add(normalized);
|
|
1020
|
+
next.push(normalized);
|
|
1021
|
+
}
|
|
1022
|
+
return next;
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
function normalizeSessionStoreKey(value) {
|
|
1026
|
+
return normalizeText(value, '').toLowerCase();
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
function extractLocalAgentIdsFromManifest(manifest = {}) {
|
|
1030
|
+
const ids = [];
|
|
1031
|
+
for (const value of [manifest.localSessionKey, manifest.sessionKey]) {
|
|
1032
|
+
const normalized = normalizeText(value, null);
|
|
1033
|
+
const match = normalized?.match(/^agent:([^:]+):/);
|
|
1034
|
+
if (match?.[1]) ids.push(match[1]);
|
|
1035
|
+
}
|
|
1036
|
+
ids.push('main');
|
|
1037
|
+
return uniqueNormalized(ids);
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
function buildLocalSessionKeyCandidates(manifest = {}) {
|
|
1041
|
+
const conversationKey = normalizeText(manifest.conversationKey, null);
|
|
1042
|
+
const localSessionKey = normalizeText(manifest.localSessionKey, null);
|
|
1043
|
+
const keys = [];
|
|
1044
|
+
if (localSessionKey) {
|
|
1045
|
+
keys.push(localSessionKey);
|
|
1046
|
+
if (!localSessionKey.startsWith('agent:')) {
|
|
1047
|
+
for (const localAgentId of extractLocalAgentIdsFromManifest(manifest)) {
|
|
1048
|
+
keys.push(`agent:${localAgentId}:${localSessionKey}`);
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
if (conversationKey) {
|
|
1053
|
+
keys.push(`conversation:${conversationKey}`);
|
|
1054
|
+
for (const localAgentId of extractLocalAgentIdsFromManifest(manifest)) {
|
|
1055
|
+
keys.push(`agent:${localAgentId}:conversation:${conversationKey}`);
|
|
1056
|
+
}
|
|
1057
|
+
}
|
|
1058
|
+
return uniqueNormalized(keys);
|
|
1059
|
+
}
|
|
1060
|
+
|
|
1061
|
+
function resolveSessionStoreEntry(store = null, candidateKeys = [], manifest = {}) {
|
|
1062
|
+
if (!store || typeof store !== 'object' || Array.isArray(store)) return null;
|
|
1063
|
+
const normalizedCandidates = new Set(candidateKeys.map(normalizeSessionStoreKey));
|
|
1064
|
+
for (const key of candidateKeys) {
|
|
1065
|
+
if (store[key] && typeof store[key] === 'object' && !Array.isArray(store[key])) {
|
|
1066
|
+
return { key, record: store[key] };
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
for (const [key, record] of Object.entries(store)) {
|
|
1070
|
+
if (
|
|
1071
|
+
normalizedCandidates.has(normalizeSessionStoreKey(key))
|
|
1072
|
+
&& record
|
|
1073
|
+
&& typeof record === 'object'
|
|
1074
|
+
&& !Array.isArray(record)
|
|
1075
|
+
) {
|
|
1076
|
+
return { key, record };
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
const conversationKey = normalizeText(manifest.conversationKey, null);
|
|
1081
|
+
const counterpartyAgentId = normalizeText(manifest.counterpartyAgentId, null);
|
|
1082
|
+
for (const [key, record] of Object.entries(store)) {
|
|
1083
|
+
if (!record || typeof record !== 'object' || Array.isArray(record)) continue;
|
|
1084
|
+
const keyText = normalizeText(key, '');
|
|
1085
|
+
const recordText = [
|
|
1086
|
+
keyText,
|
|
1087
|
+
record.sessionFile,
|
|
1088
|
+
record.transcriptPath,
|
|
1089
|
+
record.lastTo,
|
|
1090
|
+
record.route?.target?.to,
|
|
1091
|
+
record.deliveryContext?.to,
|
|
1092
|
+
record.origin?.to,
|
|
1093
|
+
].map((value) => normalizeText(value, '')).join('\n');
|
|
1094
|
+
if (conversationKey && recordText.includes(conversationKey)) {
|
|
1095
|
+
return { key, record };
|
|
1096
|
+
}
|
|
1097
|
+
if (
|
|
1098
|
+
counterpartyAgentId
|
|
1099
|
+
&& candidateKeys.some((candidate) => keyText.includes(candidate))
|
|
1100
|
+
&& recordText.includes(counterpartyAgentId)
|
|
1101
|
+
) {
|
|
1102
|
+
return { key, record };
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
return null;
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
function resolveTranscriptPathFromSessionRecord({
|
|
1109
|
+
record = {},
|
|
1110
|
+
sessionStorePath = null,
|
|
1111
|
+
} = {}) {
|
|
1112
|
+
const direct = normalizeText(
|
|
1113
|
+
record.transcriptPath,
|
|
1114
|
+
normalizeText(record.sessionFile, normalizeText(record.sessionPath, null)),
|
|
1115
|
+
);
|
|
1116
|
+
if (direct) {
|
|
1117
|
+
if (path.isAbsolute(direct) || !sessionStorePath) return direct;
|
|
1118
|
+
return path.resolve(path.dirname(sessionStorePath), direct);
|
|
1119
|
+
}
|
|
1120
|
+
const sessionId = normalizeText(record.sessionId, normalizeText(record.id, null));
|
|
1121
|
+
if (!sessionId || !sessionStorePath) return null;
|
|
1122
|
+
return path.join(path.dirname(sessionStorePath), `${sessionId}.jsonl`);
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
function extractRequestBrief(content = '') {
|
|
1126
|
+
const normalized = normalizeText(content, null);
|
|
1127
|
+
if (!normalized || !normalized.startsWith('# Background')) return null;
|
|
1128
|
+
const match = normalized.match(/## Request Brief[\s\S]*?```(?:text)?\s*\n([\s\S]*?)```/i);
|
|
1129
|
+
return normalizeText(match?.[1], null);
|
|
1130
|
+
}
|
|
1131
|
+
|
|
1132
|
+
function messageText(message = {}) {
|
|
1133
|
+
if (typeof message?.content === 'string') return normalizeText(message.content, '');
|
|
1134
|
+
if (Array.isArray(message?.content)) {
|
|
1135
|
+
return message.content
|
|
1136
|
+
.map((item) => {
|
|
1137
|
+
if (typeof item === 'string') return item;
|
|
1138
|
+
if (item && typeof item === 'object') return item.text || item.content || '';
|
|
1139
|
+
return '';
|
|
1140
|
+
})
|
|
1141
|
+
.filter(Boolean)
|
|
1142
|
+
.join('\n\n')
|
|
1143
|
+
.trim();
|
|
1144
|
+
}
|
|
1145
|
+
return '';
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
function containsConversationEndToken(text = '') {
|
|
1149
|
+
return /\[\[request_conversation_end\]\]/i.test(String(text || ''));
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1152
|
+
function buildLocalTranscriptTurn({
|
|
1153
|
+
line,
|
|
1154
|
+
seq,
|
|
1155
|
+
text,
|
|
1156
|
+
fromAgentId,
|
|
1157
|
+
role,
|
|
1158
|
+
source,
|
|
1159
|
+
suffix = '',
|
|
1160
|
+
} = {}) {
|
|
1161
|
+
const turnId = normalizeText(line.id, null) || `local_${seq}${suffix}`;
|
|
1162
|
+
return {
|
|
1163
|
+
turnId,
|
|
1164
|
+
seq,
|
|
1165
|
+
fromAgentId: normalizeText(fromAgentId, null),
|
|
1166
|
+
role,
|
|
1167
|
+
source,
|
|
1168
|
+
createdAt: normalizeText(line.timestamp, null)
|
|
1169
|
+
|| (Number.isFinite(Number(line.message?.timestamp)) ? new Date(Number(line.message.timestamp)).toISOString() : null)
|
|
1170
|
+
|| new Date().toISOString(),
|
|
1171
|
+
content: [{ type: 'text', text }],
|
|
1172
|
+
};
|
|
1173
|
+
}
|
|
1174
|
+
|
|
1175
|
+
async function readLocalTranscriptTurns({
|
|
1176
|
+
transcriptPath = null,
|
|
1177
|
+
manifest = {},
|
|
1178
|
+
viewerAgentId = null,
|
|
1179
|
+
} = {}) {
|
|
1180
|
+
const normalizedPath = normalizeText(transcriptPath, null);
|
|
1181
|
+
if (!normalizedPath) return null;
|
|
1182
|
+
let raw = '';
|
|
1183
|
+
try {
|
|
1184
|
+
raw = await fs.readFile(normalizedPath, 'utf8');
|
|
1185
|
+
} catch {
|
|
1186
|
+
return null;
|
|
1187
|
+
}
|
|
1188
|
+
const peerAgentId = normalizeText(manifest.counterpartyAgentId, 'peer');
|
|
1189
|
+
const turns = [];
|
|
1190
|
+
let seq = 1;
|
|
1191
|
+
let sawNoReply = false;
|
|
1192
|
+
let selfEndRequested = false;
|
|
1193
|
+
let peerEndRequested = false;
|
|
1194
|
+
for (const row of raw.split(/\n+/)) {
|
|
1195
|
+
const lineText = row.trim();
|
|
1196
|
+
if (!lineText) continue;
|
|
1197
|
+
let line = null;
|
|
1198
|
+
try {
|
|
1199
|
+
line = JSON.parse(lineText);
|
|
1200
|
+
} catch {
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
if (line?.type !== 'message') continue;
|
|
1204
|
+
const message = line.message && typeof line.message === 'object' && !Array.isArray(line.message)
|
|
1205
|
+
? line.message
|
|
1206
|
+
: {};
|
|
1207
|
+
const text = messageText(message);
|
|
1208
|
+
if (!text) continue;
|
|
1209
|
+
|
|
1210
|
+
const brief = extractRequestBrief(text);
|
|
1211
|
+
if (brief) {
|
|
1212
|
+
const requesterIsSelf = normalizeText(manifest.role, null) === 'requester';
|
|
1213
|
+
const fromAgentId = requesterIsSelf ? viewerAgentId : peerAgentId;
|
|
1214
|
+
turns.push(buildLocalTranscriptTurn({
|
|
1215
|
+
line,
|
|
1216
|
+
seq,
|
|
1217
|
+
text: brief,
|
|
1218
|
+
fromAgentId,
|
|
1219
|
+
role: requesterIsSelf ? 'self' : 'peer',
|
|
1220
|
+
source: 'local_transcript_request_brief',
|
|
1221
|
+
suffix: '_brief',
|
|
1222
|
+
}));
|
|
1223
|
+
seq += 1;
|
|
1224
|
+
if (requesterIsSelf && containsConversationEndToken(brief)) selfEndRequested = true;
|
|
1225
|
+
if (!requesterIsSelf && containsConversationEndToken(brief)) peerEndRequested = true;
|
|
1226
|
+
continue;
|
|
1227
|
+
}
|
|
1228
|
+
|
|
1229
|
+
if (text === 'NO_REPLY') {
|
|
1230
|
+
sawNoReply = true;
|
|
1231
|
+
continue;
|
|
1232
|
+
}
|
|
1233
|
+
const isAssistant = message.role === 'assistant';
|
|
1234
|
+
const fromAgentId = isAssistant ? viewerAgentId : peerAgentId;
|
|
1235
|
+
if (containsConversationEndToken(text)) {
|
|
1236
|
+
if (isAssistant) selfEndRequested = true;
|
|
1237
|
+
else peerEndRequested = true;
|
|
1238
|
+
}
|
|
1239
|
+
turns.push(buildLocalTranscriptTurn({
|
|
1240
|
+
line,
|
|
1241
|
+
seq,
|
|
1242
|
+
text,
|
|
1243
|
+
fromAgentId,
|
|
1244
|
+
role: isAssistant ? 'self' : 'peer',
|
|
1245
|
+
source: 'local_transcript',
|
|
1246
|
+
}));
|
|
1247
|
+
seq += 1;
|
|
1248
|
+
}
|
|
1249
|
+
return {
|
|
1250
|
+
transcriptPath: normalizedPath,
|
|
1251
|
+
turns,
|
|
1252
|
+
terminal: sawNoReply || (selfEndRequested && peerEndRequested),
|
|
1253
|
+
sawNoReply,
|
|
1254
|
+
};
|
|
1255
|
+
}
|
|
1256
|
+
|
|
1257
|
+
async function loadLocalTranscriptSnapshot({
|
|
1258
|
+
manifest = {},
|
|
1259
|
+
env = null,
|
|
1260
|
+
viewerAgentId = null,
|
|
1261
|
+
} = {}) {
|
|
1262
|
+
const stateRoot = resolveConversationViewerOpenClawRoot({ env });
|
|
1263
|
+
const candidateKeys = buildLocalSessionKeyCandidates(manifest);
|
|
1264
|
+
const localAgentIds = extractLocalAgentIdsFromManifest(manifest);
|
|
1265
|
+
for (const localAgentId of localAgentIds) {
|
|
1266
|
+
const sessionStorePath = path.join(stateRoot, 'agents', localAgentId, 'sessions', 'sessions.json');
|
|
1267
|
+
const store = await readJsonIfPresent(sessionStorePath);
|
|
1268
|
+
const match = resolveSessionStoreEntry(store, candidateKeys, manifest);
|
|
1269
|
+
if (!match) continue;
|
|
1270
|
+
const transcriptPath = resolveTranscriptPathFromSessionRecord({
|
|
1271
|
+
record: match.record,
|
|
1272
|
+
sessionStorePath,
|
|
1273
|
+
});
|
|
1274
|
+
const transcript = await readLocalTranscriptTurns({
|
|
1275
|
+
transcriptPath,
|
|
1276
|
+
manifest,
|
|
1277
|
+
viewerAgentId,
|
|
1278
|
+
});
|
|
1279
|
+
if (transcript && transcript.turns.length > 0) {
|
|
1280
|
+
return {
|
|
1281
|
+
...transcript,
|
|
1282
|
+
sessionStorePath,
|
|
1283
|
+
sessionKey: match.key,
|
|
1284
|
+
sessionId: normalizeText(match.record?.sessionId, null),
|
|
1285
|
+
};
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
return null;
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
function inferLocalTranscriptStatus(status, localTranscript = null) {
|
|
1292
|
+
const normalized = normalizeText(status, null);
|
|
1293
|
+
if (['ended', 'closed', 'expired', 'rejected', 'silent', 'kickoff_failed', 'failed'].includes(normalized)) {
|
|
1294
|
+
return normalized;
|
|
1295
|
+
}
|
|
1296
|
+
if (localTranscript?.terminal) return 'ended';
|
|
1297
|
+
if (localTranscript?.turns?.length) return 'active';
|
|
1298
|
+
return normalized || 'pending';
|
|
1299
|
+
}
|
|
1300
|
+
|
|
1011
1301
|
async function maybeUpdateManifestFromSnapshot(manifest = {}, patch = {}) {
|
|
1012
1302
|
const nextConversationKey = normalizeText(patch.conversationKey, normalizeText(manifest.conversationKey, null));
|
|
1013
1303
|
const nextLocalSessionKey = normalizeText(patch.localSessionKey, normalizeText(manifest.localSessionKey, null));
|
|
@@ -1032,6 +1322,7 @@ export async function loadConversationViewerSnapshot({
|
|
|
1032
1322
|
runtimeConfig,
|
|
1033
1323
|
fetchImpl = globalThis.fetch,
|
|
1034
1324
|
timeoutMs = DEFAULT_SNAPSHOT_FETCH_TIMEOUT_MS,
|
|
1325
|
+
env = null,
|
|
1035
1326
|
} = {}) {
|
|
1036
1327
|
const fetchedAt = new Date().toISOString();
|
|
1037
1328
|
const diagnostics = [];
|
|
@@ -1087,6 +1378,7 @@ export async function loadConversationViewerSnapshot({
|
|
|
1087
1378
|
let conversation = null;
|
|
1088
1379
|
let participants = [];
|
|
1089
1380
|
let turns = [];
|
|
1381
|
+
let localTranscript = null;
|
|
1090
1382
|
if (conversationKey) {
|
|
1091
1383
|
const suffix = queryString({ agentId: viewerAgentId });
|
|
1092
1384
|
const [conversationResult, turnsResult, participantsResult] = await Promise.all([
|
|
@@ -1119,16 +1411,46 @@ export async function loadConversationViewerSnapshot({
|
|
|
1119
1411
|
});
|
|
1120
1412
|
}
|
|
1121
1413
|
}
|
|
1414
|
+
if (turns.length === 0) {
|
|
1415
|
+
localTranscript = await loadLocalTranscriptSnapshot({
|
|
1416
|
+
manifest: activeManifest,
|
|
1417
|
+
env,
|
|
1418
|
+
viewerAgentId,
|
|
1419
|
+
});
|
|
1420
|
+
if (localTranscript?.turns?.length) {
|
|
1421
|
+
turns = localTranscript.turns;
|
|
1422
|
+
diagnostics.push({
|
|
1423
|
+
source: 'local_transcript',
|
|
1424
|
+
status: 200,
|
|
1425
|
+
path: localTranscript.transcriptPath,
|
|
1426
|
+
sessionKey: localTranscript.sessionKey || null,
|
|
1427
|
+
sessionId: localTranscript.sessionId || null,
|
|
1428
|
+
});
|
|
1429
|
+
}
|
|
1430
|
+
}
|
|
1431
|
+
if (participants.length === 0 && localTranscript?.turns?.length) {
|
|
1432
|
+
participants = [
|
|
1433
|
+
{
|
|
1434
|
+
agentId: viewerAgentId,
|
|
1435
|
+
displayName: 'You',
|
|
1436
|
+
},
|
|
1437
|
+
{
|
|
1438
|
+
agentId: normalizeText(activeManifest.counterpartyAgentId, 'peer'),
|
|
1439
|
+
displayName: normalizeText(activeManifest.counterpartyName, 'Peer agent'),
|
|
1440
|
+
},
|
|
1441
|
+
];
|
|
1442
|
+
}
|
|
1122
1443
|
const peer = normalizeObject(chat?.counterparty, null)
|
|
1123
1444
|
|| normalizeObject(request?.counterparty, null)
|
|
1124
1445
|
|| null;
|
|
1125
1446
|
const peerName = normalizeText(peer?.displayName, normalizeText(activeManifest.counterpartyName, 'Peer agent'));
|
|
1126
|
-
const
|
|
1447
|
+
const resolvedStatus = resolveSnapshotStatus({
|
|
1127
1448
|
request,
|
|
1128
1449
|
chat,
|
|
1129
1450
|
conversation,
|
|
1130
1451
|
fallbackStatus: activeManifest.targetStatus,
|
|
1131
1452
|
});
|
|
1453
|
+
const status = inferLocalTranscriptStatus(resolvedStatus, localTranscript);
|
|
1132
1454
|
const worldName = normalizeText(chat?.conversation?.world?.displayName, normalizeText(request?.conversation?.world?.displayName, null));
|
|
1133
1455
|
return {
|
|
1134
1456
|
ok: true,
|
|
@@ -1159,6 +1481,12 @@ export async function loadConversationViewerSnapshot({
|
|
|
1159
1481
|
counts: inbox.counts || null,
|
|
1160
1482
|
filters: inbox.filters || null,
|
|
1161
1483
|
},
|
|
1484
|
+
localTranscript: localTranscript ? {
|
|
1485
|
+
path: localTranscript.transcriptPath,
|
|
1486
|
+
sessionKey: localTranscript.sessionKey || null,
|
|
1487
|
+
sessionId: localTranscript.sessionId || null,
|
|
1488
|
+
terminal: localTranscript.terminal === true,
|
|
1489
|
+
} : null,
|
|
1162
1490
|
diagnostics,
|
|
1163
1491
|
};
|
|
1164
1492
|
}
|
|
@@ -1194,6 +1522,7 @@ export function buildConversationViewerRoute(plugin, {
|
|
|
1194
1522
|
manifest,
|
|
1195
1523
|
runtimeConfig,
|
|
1196
1524
|
fetchImpl,
|
|
1525
|
+
env,
|
|
1197
1526
|
});
|
|
1198
1527
|
return sendJson(res, snapshot.ok === false ? 502 : 200, snapshot);
|
|
1199
1528
|
} catch (error) {
|