@xmoxmo/bncr 0.1.7 → 0.1.8
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/index.ts +18 -11
- package/package.json +1 -1
- package/src/channel.ts +299 -209
- package/src/core/logging.ts +65 -0
- package/src/messaging/inbound/commands.ts +4 -2
- package/src/messaging/inbound/dispatch.ts +4 -3
- package/src/messaging/outbound/media.ts +2 -0
- package/src/messaging/outbound/send.ts +11 -1
package/index.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { createRequire } from 'node:module';
|
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { BncrConfigSchema } from './src/core/config-schema.ts';
|
|
7
|
+
import { emitBncrLogLine } from './src/core/logging.ts';
|
|
7
8
|
|
|
8
9
|
const pluginFile = fileURLToPath(import.meta.url);
|
|
9
10
|
const pluginDir = path.dirname(pluginFile);
|
|
@@ -254,12 +255,12 @@ const ensureGatewayMethodRegistered = (
|
|
|
254
255
|
) => {
|
|
255
256
|
const meta = getRegisterMeta(api);
|
|
256
257
|
if (meta.methods?.has(name)) {
|
|
257
|
-
debugLog(`
|
|
258
|
+
debugLog(`register method skip ${name} (already registered on this api)`);
|
|
258
259
|
return;
|
|
259
260
|
}
|
|
260
261
|
api.registerGatewayMethod(name, handler);
|
|
261
262
|
meta.methods?.add(name);
|
|
262
|
-
debugLog(`
|
|
263
|
+
debugLog(`register method ok ${name}`);
|
|
263
264
|
};
|
|
264
265
|
|
|
265
266
|
const getBridgeSingleton = (api: OpenClawPluginApi) => {
|
|
@@ -291,14 +292,20 @@ const plugin = {
|
|
|
291
292
|
registryFingerprint: meta.registryFingerprint,
|
|
292
293
|
});
|
|
293
294
|
const debugLog = (...args: any[]) => {
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
const rendered = args
|
|
296
|
+
.map((arg) => (typeof arg === 'string' ? arg : JSON.stringify(arg)))
|
|
297
|
+
.join(' ')
|
|
298
|
+
.trim();
|
|
299
|
+
if (!rendered) return;
|
|
300
|
+
emitBncrLogLine('info', `[bncr] debug ${rendered}`, { debugOnly: true }, () =>
|
|
301
|
+
Boolean(bridge.isDebugEnabled?.()),
|
|
302
|
+
);
|
|
296
303
|
};
|
|
297
304
|
|
|
298
305
|
debugLog(
|
|
299
|
-
`
|
|
306
|
+
`register begin bridge=${bridge.getBridgeId?.() || 'unknown'} created=${created}`,
|
|
300
307
|
);
|
|
301
|
-
if (!created) debugLog('
|
|
308
|
+
if (!created) debugLog('bridge api rebound');
|
|
302
309
|
|
|
303
310
|
const resolveDebug = async () => {
|
|
304
311
|
try {
|
|
@@ -319,17 +326,17 @@ const plugin = {
|
|
|
319
326
|
stop: bridge.stopService,
|
|
320
327
|
});
|
|
321
328
|
meta.service = true;
|
|
322
|
-
debugLog('
|
|
329
|
+
debugLog('register service ok');
|
|
323
330
|
} else {
|
|
324
|
-
debugLog('
|
|
331
|
+
debugLog('register service skip (already registered on this api)');
|
|
325
332
|
}
|
|
326
333
|
|
|
327
334
|
if (!meta.channel) {
|
|
328
335
|
api.registerChannel({ plugin: runtime.createBncrChannelPlugin(bridge) });
|
|
329
336
|
meta.channel = true;
|
|
330
|
-
debugLog('
|
|
337
|
+
debugLog('register channel ok');
|
|
331
338
|
} else {
|
|
332
|
-
debugLog('
|
|
339
|
+
debugLog('register channel skip (already registered on this api)');
|
|
333
340
|
}
|
|
334
341
|
|
|
335
342
|
ensureGatewayMethodRegistered(
|
|
@@ -387,7 +394,7 @@ const plugin = {
|
|
|
387
394
|
(opts) => bridge.handleFileAck(opts),
|
|
388
395
|
debugLog,
|
|
389
396
|
);
|
|
390
|
-
debugLog('
|
|
397
|
+
debugLog('register done');
|
|
391
398
|
},
|
|
392
399
|
};
|
|
393
400
|
|
package/package.json
CHANGED
package/src/channel.ts
CHANGED
|
@@ -25,6 +25,10 @@ import {
|
|
|
25
25
|
resolveAccount,
|
|
26
26
|
resolveDefaultDisplayName,
|
|
27
27
|
} from './core/accounts.ts';
|
|
28
|
+
import {
|
|
29
|
+
emitBncrLog,
|
|
30
|
+
emitBncrLogLine,
|
|
31
|
+
} from './core/logging.ts';
|
|
28
32
|
import { BncrConfigSchema } from './core/config-schema.ts';
|
|
29
33
|
import { buildBncrPermissionSummary } from './core/permissions.ts';
|
|
30
34
|
import { resolveBncrChannelPolicy } from './core/policy.ts';
|
|
@@ -367,6 +371,54 @@ class BncrBridgeRuntime {
|
|
|
367
371
|
return this.bridgeId;
|
|
368
372
|
}
|
|
369
373
|
|
|
374
|
+
private isDebugEnabled() {
|
|
375
|
+
return BNCR_DEBUG_VERBOSE;
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
private logInfo(scope: string | undefined, message: string, options?: { debugOnly?: boolean }) {
|
|
379
|
+
emitBncrLog('info', scope, message, options, () => this.isDebugEnabled());
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
private logWarn(scope: string | undefined, message: string, options?: { debugOnly?: boolean }) {
|
|
383
|
+
emitBncrLog('warn', scope, message, options, () => this.isDebugEnabled());
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private logError(scope: string | undefined, message: string, options?: { debugOnly?: boolean }) {
|
|
387
|
+
emitBncrLog('error', scope, message, options, () => this.isDebugEnabled());
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
|
|
391
|
+
private summarizeTextPreview(raw: string, limit = 8) {
|
|
392
|
+
const compact = asString(raw || '').replace(/\s+/g, ' ').trim();
|
|
393
|
+
if (!compact) return '-';
|
|
394
|
+
const chars = Array.from(compact);
|
|
395
|
+
return chars.length > limit ? `${chars.slice(0, Math.max(1, limit)).join('')}…` : compact;
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
private summarizeScope(route: BncrRoute) {
|
|
399
|
+
return formatDisplayScope(route);
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
private logInboundSummary(params: {
|
|
403
|
+
accountId: string;
|
|
404
|
+
route: BncrRoute;
|
|
405
|
+
msgType: string;
|
|
406
|
+
text: string;
|
|
407
|
+
hasMedia: boolean;
|
|
408
|
+
}) {
|
|
409
|
+
const type = params.hasMedia ? `${params.msgType}+media` : params.msgType;
|
|
410
|
+
const preview = this.summarizeTextPreview(params.text);
|
|
411
|
+
this.logInfo('inbound', [type, this.summarizeScope(params.route), preview].join('|'));
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
private logOutboundSummary(entry: OutboxEntry) {
|
|
415
|
+
const msg = (entry.payload as any)?.message || {};
|
|
416
|
+
const type = asString(msg.type || (entry.payload as any)?.type || 'unknown');
|
|
417
|
+
const text = asString(msg.msg || '');
|
|
418
|
+
const preview = this.summarizeTextPreview(text);
|
|
419
|
+
this.logInfo('outbound', [type, this.summarizeScope(entry.route), preview].join('|'));
|
|
420
|
+
}
|
|
421
|
+
|
|
370
422
|
private classifyRegisterTrace(stack: string) {
|
|
371
423
|
if (
|
|
372
424
|
stack.includes('prepareSecretsRuntimeSnapshot') ||
|
|
@@ -509,9 +561,7 @@ class BncrBridgeRuntime {
|
|
|
509
561
|
const summary = this.buildRegisterTraceSummary();
|
|
510
562
|
if (summary.postWarmupRegisterCount > 0) this.captureDriftSnapshot(summary);
|
|
511
563
|
|
|
512
|
-
|
|
513
|
-
this.api.logger.info?.(`[bncr-register-trace] ${JSON.stringify(trace)}`);
|
|
514
|
-
}
|
|
564
|
+
this.logInfo('debug', `register-trace ${JSON.stringify(trace)}`, { debugOnly: true });
|
|
515
565
|
}
|
|
516
566
|
|
|
517
567
|
private createLeaseId() {
|
|
@@ -595,8 +645,9 @@ class BncrBridgeRuntime {
|
|
|
595
645
|
this.staleCounters.staleFileAbort += 1;
|
|
596
646
|
break;
|
|
597
647
|
}
|
|
598
|
-
this.
|
|
599
|
-
|
|
648
|
+
this.logWarn(
|
|
649
|
+
'stale',
|
|
650
|
+
`observed kind=${kind} lease=${leaseId || '-'} epoch=${connectionEpoch ?? '-'} currentLease=${this.primaryLeaseId || '-'} currentEpoch=${this.connectionEpoch}`,
|
|
600
651
|
);
|
|
601
652
|
return { stale: true, reason: 'mismatch' as const };
|
|
602
653
|
}
|
|
@@ -674,12 +725,13 @@ class BncrBridgeRuntime {
|
|
|
674
725
|
// ignore startup canonical agent initialization errors
|
|
675
726
|
}
|
|
676
727
|
if (typeof debug === 'boolean') BNCR_DEBUG_VERBOSE = debug;
|
|
728
|
+
await this.refreshDebugFlagFromConfig({ forceLog: true });
|
|
677
729
|
const bootDiag = this.buildIntegratedDiagnostics(BNCR_DEFAULT_ACCOUNT_ID);
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
730
|
+
this.logInfo(
|
|
731
|
+
'debug',
|
|
732
|
+
`service started bridge=${this.bridgeId} diag.ok=${bootDiag.regression.ok} routes=${bootDiag.regression.totalKnownRoutes} pending=${bootDiag.health.pending} dead=${bootDiag.health.deadLetter} debug=${BNCR_DEBUG_VERBOSE}`,
|
|
733
|
+
{ debugOnly: true },
|
|
734
|
+
);
|
|
683
735
|
};
|
|
684
736
|
|
|
685
737
|
stopService = async () => {
|
|
@@ -688,9 +740,7 @@ class BncrBridgeRuntime {
|
|
|
688
740
|
this.pushTimer = null;
|
|
689
741
|
}
|
|
690
742
|
await this.flushState();
|
|
691
|
-
|
|
692
|
-
this.api.logger.info('bncr-channel service stopped');
|
|
693
|
-
}
|
|
743
|
+
this.logInfo('debug', 'service stopped', { debugOnly: true });
|
|
694
744
|
};
|
|
695
745
|
|
|
696
746
|
private scheduleSave() {
|
|
@@ -710,20 +760,25 @@ class BncrBridgeRuntime {
|
|
|
710
760
|
return map.get(normalizeAccountId(accountId)) || 0;
|
|
711
761
|
}
|
|
712
762
|
|
|
713
|
-
private async
|
|
763
|
+
private async refreshDebugFlagFromConfig(options?: { forceLog?: boolean }) {
|
|
714
764
|
try {
|
|
715
765
|
const cfg = await this.api.runtime.config.loadConfig();
|
|
716
766
|
const raw = (cfg as any)?.channels?.[CHANNEL_ID]?.debug?.verbose;
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
767
|
+
const next = typeof raw === 'boolean' ? raw : false;
|
|
768
|
+
const changed = next !== BNCR_DEBUG_VERBOSE;
|
|
769
|
+
BNCR_DEBUG_VERBOSE = next;
|
|
770
|
+
if (changed || options?.forceLog) {
|
|
771
|
+
this.logInfo('debug', `verbose=${BNCR_DEBUG_VERBOSE}`);
|
|
721
772
|
}
|
|
722
773
|
} catch {
|
|
723
774
|
// ignore config read errors
|
|
724
775
|
}
|
|
725
776
|
}
|
|
726
777
|
|
|
778
|
+
private syncDebugFlag() {
|
|
779
|
+
void this.refreshDebugFlagFromConfig();
|
|
780
|
+
}
|
|
781
|
+
|
|
727
782
|
private tryResolveBindingAgentId(args: {
|
|
728
783
|
cfg: any;
|
|
729
784
|
accountId: string;
|
|
@@ -777,9 +832,7 @@ class BncrBridgeRuntime {
|
|
|
777
832
|
this.canonicalAgentId = 'main';
|
|
778
833
|
this.canonicalAgentSource = 'fallback-main';
|
|
779
834
|
this.canonicalAgentResolvedAt = now();
|
|
780
|
-
this.
|
|
781
|
-
'[bncr-canonical-agent] binding agent unresolved; fallback to main for current process lifetime',
|
|
782
|
-
);
|
|
835
|
+
this.logWarn('target', 'binding agent unresolved; fallback to main for current process lifetime');
|
|
783
836
|
return this.canonicalAgentId;
|
|
784
837
|
}
|
|
785
838
|
|
|
@@ -1146,29 +1199,29 @@ class BncrBridgeRuntime {
|
|
|
1146
1199
|
private tryPushEntry(entry: OutboxEntry): boolean {
|
|
1147
1200
|
const ctx = this.gatewayContext;
|
|
1148
1201
|
if (!ctx) {
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1202
|
+
this.logInfo(
|
|
1203
|
+
'outbox',
|
|
1204
|
+
`push-skip ${JSON.stringify({
|
|
1205
|
+
messageId: entry.messageId,
|
|
1206
|
+
accountId: entry.accountId,
|
|
1207
|
+
reason: 'no-gateway-context',
|
|
1208
|
+
})}`,
|
|
1209
|
+
{ debugOnly: true },
|
|
1210
|
+
);
|
|
1158
1211
|
return false;
|
|
1159
1212
|
}
|
|
1160
1213
|
|
|
1161
1214
|
const connIds = this.resolvePushConnIds(entry.accountId);
|
|
1162
1215
|
if (!connIds.size) {
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1216
|
+
this.logInfo(
|
|
1217
|
+
'outbox',
|
|
1218
|
+
`push-skip ${JSON.stringify({
|
|
1219
|
+
messageId: entry.messageId,
|
|
1220
|
+
accountId: entry.accountId,
|
|
1221
|
+
reason: 'no-active-connection',
|
|
1222
|
+
})}`,
|
|
1223
|
+
{ debugOnly: true },
|
|
1224
|
+
);
|
|
1172
1225
|
return false;
|
|
1173
1226
|
}
|
|
1174
1227
|
|
|
@@ -1179,16 +1232,16 @@ class BncrBridgeRuntime {
|
|
|
1179
1232
|
};
|
|
1180
1233
|
|
|
1181
1234
|
ctx.broadcastToConnIds(BNCR_PUSH_EVENT, payload, connIds);
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
|
|
1190
|
-
|
|
1191
|
-
|
|
1235
|
+
this.logInfo(
|
|
1236
|
+
'outbox',
|
|
1237
|
+
`push-ok ${JSON.stringify({
|
|
1238
|
+
messageId: entry.messageId,
|
|
1239
|
+
accountId: entry.accountId,
|
|
1240
|
+
connIds: Array.from(connIds),
|
|
1241
|
+
event: BNCR_PUSH_EVENT,
|
|
1242
|
+
})}`,
|
|
1243
|
+
{ debugOnly: true },
|
|
1244
|
+
);
|
|
1192
1245
|
this.lastOutboundByAccount.set(entry.accountId, now());
|
|
1193
1246
|
this.markActivity(entry.accountId);
|
|
1194
1247
|
this.scheduleSave();
|
|
@@ -1196,15 +1249,15 @@ class BncrBridgeRuntime {
|
|
|
1196
1249
|
} catch (error) {
|
|
1197
1250
|
entry.lastError = asString((error as any)?.message || error || 'push-error');
|
|
1198
1251
|
this.outbox.set(entry.messageId, entry);
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
|
|
1203
|
-
|
|
1204
|
-
|
|
1205
|
-
|
|
1206
|
-
|
|
1207
|
-
|
|
1252
|
+
this.logInfo(
|
|
1253
|
+
'outbox',
|
|
1254
|
+
`push-fail ${JSON.stringify({
|
|
1255
|
+
messageId: entry.messageId,
|
|
1256
|
+
accountId: entry.accountId,
|
|
1257
|
+
error: entry.lastError,
|
|
1258
|
+
})}`,
|
|
1259
|
+
{ debugOnly: true },
|
|
1260
|
+
);
|
|
1208
1261
|
return false;
|
|
1209
1262
|
}
|
|
1210
1263
|
}
|
|
@@ -1227,37 +1280,37 @@ class BncrBridgeRuntime {
|
|
|
1227
1280
|
Array.from(this.outbox.values()).map((entry) => normalizeAccountId(entry.accountId)),
|
|
1228
1281
|
),
|
|
1229
1282
|
);
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1283
|
+
this.logInfo(
|
|
1284
|
+
'outbox',
|
|
1285
|
+
`flush ${JSON.stringify({
|
|
1286
|
+
bridge: this.bridgeId,
|
|
1287
|
+
accountId: filterAcc,
|
|
1288
|
+
targetAccounts,
|
|
1289
|
+
outboxSize: this.outbox.size,
|
|
1290
|
+
})}`,
|
|
1291
|
+
{ debugOnly: true },
|
|
1292
|
+
);
|
|
1240
1293
|
|
|
1241
1294
|
let globalNextDelay: number | null = null;
|
|
1242
1295
|
|
|
1243
1296
|
for (const acc of targetAccounts) {
|
|
1244
1297
|
if (!acc || this.pushDrainRunningAccounts.has(acc)) continue;
|
|
1245
1298
|
const online = this.isOnline(acc);
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1299
|
+
this.logInfo(
|
|
1300
|
+
'outbox',
|
|
1301
|
+
`online ${JSON.stringify({
|
|
1302
|
+
bridge: this.bridgeId,
|
|
1303
|
+
accountId: acc,
|
|
1304
|
+
online,
|
|
1305
|
+
connections: Array.from(this.connections.values()).map((c) => ({
|
|
1306
|
+
accountId: c.accountId,
|
|
1307
|
+
connId: c.connId,
|
|
1308
|
+
clientId: c.clientId,
|
|
1309
|
+
lastSeenAt: c.lastSeenAt,
|
|
1310
|
+
})),
|
|
1311
|
+
})}`,
|
|
1312
|
+
{ debugOnly: true },
|
|
1313
|
+
);
|
|
1261
1314
|
this.pushDrainRunningAccounts.add(acc);
|
|
1262
1315
|
try {
|
|
1263
1316
|
let localNextDelay: number | null = null;
|
|
@@ -1375,19 +1428,19 @@ class BncrBridgeRuntime {
|
|
|
1375
1428
|
const staleBefore = t - CONNECT_TTL_MS * 2;
|
|
1376
1429
|
for (const [key, c] of this.connections.entries()) {
|
|
1377
1430
|
if (c.lastSeenAt < staleBefore) {
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1431
|
+
this.logInfo(
|
|
1432
|
+
'connection',
|
|
1433
|
+
`gc ${JSON.stringify({
|
|
1434
|
+
bridge: this.bridgeId,
|
|
1435
|
+
key,
|
|
1436
|
+
accountId: c.accountId,
|
|
1437
|
+
connId: c.connId,
|
|
1438
|
+
clientId: c.clientId,
|
|
1439
|
+
lastSeenAt: c.lastSeenAt,
|
|
1440
|
+
staleBefore,
|
|
1441
|
+
})}`,
|
|
1442
|
+
{ debugOnly: true },
|
|
1443
|
+
);
|
|
1391
1444
|
this.connections.delete(key);
|
|
1392
1445
|
}
|
|
1393
1446
|
}
|
|
@@ -1428,18 +1481,18 @@ class BncrBridgeRuntime {
|
|
|
1428
1481
|
};
|
|
1429
1482
|
|
|
1430
1483
|
this.connections.set(key, nextConn);
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1484
|
+
this.logInfo(
|
|
1485
|
+
'connection',
|
|
1486
|
+
`seen ${JSON.stringify({
|
|
1487
|
+
bridge: this.bridgeId,
|
|
1488
|
+
accountId: acc,
|
|
1489
|
+
connId,
|
|
1490
|
+
clientId: nextConn.clientId,
|
|
1491
|
+
connectedAt: nextConn.connectedAt,
|
|
1492
|
+
lastSeenAt: nextConn.lastSeenAt,
|
|
1493
|
+
})}`,
|
|
1494
|
+
{ debugOnly: true },
|
|
1495
|
+
);
|
|
1443
1496
|
|
|
1444
1497
|
const current = this.activeConnectionByAccount.get(acc);
|
|
1445
1498
|
if (!current) {
|
|
@@ -1541,9 +1594,7 @@ class BncrBridgeRuntime {
|
|
|
1541
1594
|
const raw = asString(rawTarget).trim();
|
|
1542
1595
|
if (!raw) throw new Error('bncr invalid target(empty)');
|
|
1543
1596
|
|
|
1544
|
-
|
|
1545
|
-
this.api.logger.info?.(`[bncr-target-incoming] raw=${raw} accountId=${acc}`);
|
|
1546
|
-
}
|
|
1597
|
+
this.logInfo('target', `incoming raw=${raw} accountId=${acc}`, { debugOnly: true });
|
|
1547
1598
|
|
|
1548
1599
|
let route: BncrRoute | null = null;
|
|
1549
1600
|
|
|
@@ -1555,8 +1606,9 @@ class BncrBridgeRuntime {
|
|
|
1555
1606
|
}
|
|
1556
1607
|
|
|
1557
1608
|
if (!route) {
|
|
1558
|
-
this.
|
|
1559
|
-
|
|
1609
|
+
this.logWarn(
|
|
1610
|
+
'target',
|
|
1611
|
+
`invalid raw=${raw} accountId=${acc} reason=unparseable-or-unknown standardTo=Bncr:<platform>:<groupId>:<userId>|Bncr:<platform>:<userId> standardSessionKey=agent:<agentId>:bncr:direct:<hex(scope)>`,
|
|
1560
1612
|
);
|
|
1561
1613
|
throw new Error(
|
|
1562
1614
|
`bncr invalid target(standard: Bncr:<platform>:<groupId>:<userId> | Bncr:<platform>:<userId>): ${raw}`,
|
|
@@ -1577,11 +1629,11 @@ class BncrBridgeRuntime {
|
|
|
1577
1629
|
displayScope: formatDisplayScope(route),
|
|
1578
1630
|
};
|
|
1579
1631
|
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1632
|
+
this.logInfo(
|
|
1633
|
+
'target',
|
|
1634
|
+
`canonical raw=${raw} accountId=${acc} verified=${JSON.stringify(verified)}`,
|
|
1635
|
+
{ debugOnly: true },
|
|
1636
|
+
);
|
|
1585
1637
|
|
|
1586
1638
|
// 发送链路命中目标时,同步刷新 lastSession,避免状态页显示过期会话。
|
|
1587
1639
|
this.lastSessionByAccount.set(acc, {
|
|
@@ -1805,22 +1857,25 @@ class BncrBridgeRuntime {
|
|
|
1805
1857
|
}
|
|
1806
1858
|
|
|
1807
1859
|
private enqueueOutbound(entry: OutboxEntry) {
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1860
|
+
const msg = (entry.payload as any)?.message || {};
|
|
1861
|
+
const type = asString(msg.type || (entry.payload as any)?.type || 'unknown');
|
|
1862
|
+
const text = asString(msg.msg || '');
|
|
1863
|
+
const displayScope = formatDisplayScope(entry.route);
|
|
1864
|
+
this.logInfo(
|
|
1865
|
+
'outbound',
|
|
1866
|
+
JSON.stringify({
|
|
1867
|
+
bridge: this.bridgeId,
|
|
1868
|
+
messageId: entry.messageId,
|
|
1869
|
+
accountId: entry.accountId,
|
|
1870
|
+
sessionKey: entry.sessionKey,
|
|
1871
|
+
scope: displayScope,
|
|
1872
|
+
type,
|
|
1873
|
+
textLen: text.length,
|
|
1874
|
+
textPreview: text.slice(0, 120),
|
|
1875
|
+
}),
|
|
1876
|
+
{ debugOnly: true },
|
|
1877
|
+
);
|
|
1878
|
+
this.logOutboundSummary(entry);
|
|
1824
1879
|
this.outbox.set(entry.messageId, entry);
|
|
1825
1880
|
this.scheduleSave();
|
|
1826
1881
|
this.wakeAccountWaiters(entry.accountId);
|
|
@@ -2133,6 +2188,7 @@ class BncrBridgeRuntime {
|
|
|
2133
2188
|
asVoice?: boolean;
|
|
2134
2189
|
audioAsVoice?: boolean;
|
|
2135
2190
|
kind?: 'tool' | 'block' | 'final';
|
|
2191
|
+
replyToId?: string;
|
|
2136
2192
|
};
|
|
2137
2193
|
mediaLocalRoots?: readonly string[];
|
|
2138
2194
|
}) {
|
|
@@ -2171,6 +2227,7 @@ class BncrBridgeRuntime {
|
|
|
2171
2227
|
}),
|
|
2172
2228
|
hintedType: wantsVoice ? 'voice' : undefined,
|
|
2173
2229
|
kind: payload.kind,
|
|
2230
|
+
replyToId: asString(payload.replyToId || '').trim() || undefined,
|
|
2174
2231
|
now: now(),
|
|
2175
2232
|
});
|
|
2176
2233
|
|
|
@@ -2198,6 +2255,7 @@ class BncrBridgeRuntime {
|
|
|
2198
2255
|
messageId,
|
|
2199
2256
|
idempotencyKey: messageId,
|
|
2200
2257
|
sessionKey,
|
|
2258
|
+
replyToId: asString(payload.replyToId || '').trim() || undefined,
|
|
2201
2259
|
message: {
|
|
2202
2260
|
platform: route.platform,
|
|
2203
2261
|
groupId: route.groupId,
|
|
@@ -2225,21 +2283,22 @@ class BncrBridgeRuntime {
|
|
|
2225
2283
|
}
|
|
2226
2284
|
|
|
2227
2285
|
handleConnect = async ({ params, respond, client, context }: GatewayRequestHandlerOptions) => {
|
|
2286
|
+
this.syncDebugFlag();
|
|
2228
2287
|
const accountId = normalizeAccountId(asString(params?.accountId || ''));
|
|
2229
2288
|
const connId = asString(client?.connId || '').trim() || `no-conn-${Date.now()}`;
|
|
2230
2289
|
const clientId = asString((params as any)?.clientId || '').trim() || undefined;
|
|
2231
2290
|
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2291
|
+
this.logInfo(
|
|
2292
|
+
'connection',
|
|
2293
|
+
`connect ${JSON.stringify({
|
|
2294
|
+
bridge: this.bridgeId,
|
|
2295
|
+
accountId,
|
|
2296
|
+
connId,
|
|
2297
|
+
clientId,
|
|
2298
|
+
hasContext: Boolean(context),
|
|
2299
|
+
})}`,
|
|
2300
|
+
{ debugOnly: true },
|
|
2301
|
+
);
|
|
2243
2302
|
|
|
2244
2303
|
this.rememberGatewayContext(context);
|
|
2245
2304
|
this.markSeen(accountId, connId, clientId);
|
|
@@ -2272,6 +2331,7 @@ class BncrBridgeRuntime {
|
|
|
2272
2331
|
};
|
|
2273
2332
|
|
|
2274
2333
|
handleAck = async ({ params, respond, client, context }: GatewayRequestHandlerOptions) => {
|
|
2334
|
+
this.syncDebugFlag();
|
|
2275
2335
|
const accountId = normalizeAccountId(asString(params?.accountId || ''));
|
|
2276
2336
|
const connId = asString(client?.connId || '').trim() || `no-conn-${Date.now()}`;
|
|
2277
2337
|
const clientId = asString((params as any)?.clientId || '').trim() || undefined;
|
|
@@ -2282,17 +2342,17 @@ class BncrBridgeRuntime {
|
|
|
2282
2342
|
this.incrementCounter(this.ackEventsByAccount, accountId);
|
|
2283
2343
|
|
|
2284
2344
|
const messageId = asString(params?.messageId || '').trim();
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2345
|
+
this.logInfo(
|
|
2346
|
+
'outbox',
|
|
2347
|
+
`ack ${JSON.stringify({
|
|
2348
|
+
accountId,
|
|
2349
|
+
messageId,
|
|
2350
|
+
ok: params?.ok !== false,
|
|
2351
|
+
fatal: params?.fatal === true,
|
|
2352
|
+
error: asString(params?.error || ''),
|
|
2353
|
+
})}`,
|
|
2354
|
+
{ debugOnly: true },
|
|
2355
|
+
);
|
|
2296
2356
|
if (!messageId) {
|
|
2297
2357
|
respond(false, { error: 'messageId required' });
|
|
2298
2358
|
return;
|
|
@@ -2335,23 +2395,23 @@ class BncrBridgeRuntime {
|
|
|
2335
2395
|
};
|
|
2336
2396
|
|
|
2337
2397
|
handleActivity = async ({ params, respond, client, context }: GatewayRequestHandlerOptions) => {
|
|
2338
|
-
|
|
2398
|
+
this.syncDebugFlag();
|
|
2339
2399
|
const accountId = normalizeAccountId(asString(params?.accountId || ''));
|
|
2340
2400
|
const connId = asString(client?.connId || '').trim() || `no-conn-${Date.now()}`;
|
|
2341
2401
|
const clientId = asString((params as any)?.clientId || '').trim() || undefined;
|
|
2342
2402
|
this.observeLease('activity', params ?? {});
|
|
2343
2403
|
this.lastActivityAtGlobal = now();
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2404
|
+
this.logInfo(
|
|
2405
|
+
'activity',
|
|
2406
|
+
`event ${JSON.stringify({
|
|
2407
|
+
bridge: this.bridgeId,
|
|
2408
|
+
accountId,
|
|
2409
|
+
connId,
|
|
2410
|
+
clientId,
|
|
2411
|
+
hasContext: Boolean(context),
|
|
2412
|
+
})}`,
|
|
2413
|
+
{ debugOnly: true },
|
|
2414
|
+
);
|
|
2355
2415
|
this.rememberGatewayContext(context);
|
|
2356
2416
|
this.markSeen(accountId, connId, clientId);
|
|
2357
2417
|
this.markActivity(accountId);
|
|
@@ -2696,6 +2756,7 @@ class BncrBridgeRuntime {
|
|
|
2696
2756
|
};
|
|
2697
2757
|
|
|
2698
2758
|
handleInbound = async ({ params, respond, client, context }: GatewayRequestHandlerOptions) => {
|
|
2759
|
+
this.syncDebugFlag();
|
|
2699
2760
|
const parsed = parseBncrInboundParams(params);
|
|
2700
2761
|
const {
|
|
2701
2762
|
accountId,
|
|
@@ -2771,6 +2832,30 @@ class BncrBridgeRuntime {
|
|
|
2771
2832
|
resolvedRoute.sessionKey;
|
|
2772
2833
|
const taskSessionKey = withTaskSessionKey(baseSessionKey, extracted.taskKey);
|
|
2773
2834
|
const sessionKey = taskSessionKey || baseSessionKey;
|
|
2835
|
+
const inboundText = asString(extracted.text || text || '');
|
|
2836
|
+
this.logInfo(
|
|
2837
|
+
'inbound',
|
|
2838
|
+
JSON.stringify({
|
|
2839
|
+
accountId,
|
|
2840
|
+
msgId: msgId ?? null,
|
|
2841
|
+
platform,
|
|
2842
|
+
chatType: peer.kind,
|
|
2843
|
+
scope: formatDisplayScope(route),
|
|
2844
|
+
sessionKey,
|
|
2845
|
+
msgType,
|
|
2846
|
+
textLen: inboundText.length,
|
|
2847
|
+
textPreview: inboundText.slice(0, 120),
|
|
2848
|
+
hasMedia: Boolean(mediaBase64 || mediaPathFromTransfer),
|
|
2849
|
+
}),
|
|
2850
|
+
{ debugOnly: true },
|
|
2851
|
+
);
|
|
2852
|
+
this.logInboundSummary({
|
|
2853
|
+
accountId,
|
|
2854
|
+
route,
|
|
2855
|
+
msgType,
|
|
2856
|
+
text: inboundText,
|
|
2857
|
+
hasMedia: Boolean(mediaBase64 || mediaPathFromTransfer),
|
|
2858
|
+
});
|
|
2774
2859
|
|
|
2775
2860
|
respond(true, {
|
|
2776
2861
|
accepted: true,
|
|
@@ -2794,9 +2879,12 @@ class BncrBridgeRuntime {
|
|
|
2794
2879
|
this.markActivity(accountId, at);
|
|
2795
2880
|
},
|
|
2796
2881
|
scheduleSave: () => this.scheduleSave(),
|
|
2797
|
-
logger:
|
|
2882
|
+
logger: {
|
|
2883
|
+
warn: (msg: string) => emitBncrLogLine('warn', msg),
|
|
2884
|
+
error: (msg: string) => emitBncrLogLine('error', msg),
|
|
2885
|
+
},
|
|
2798
2886
|
}).catch((err) => {
|
|
2799
|
-
this.
|
|
2887
|
+
this.logError('inbound', `process failed: ${String(err)}`);
|
|
2800
2888
|
});
|
|
2801
2889
|
};
|
|
2802
2890
|
|
|
@@ -2847,30 +2935,31 @@ class BncrBridgeRuntime {
|
|
|
2847
2935
|
const accountId = normalizeAccountId(ctx.accountId);
|
|
2848
2936
|
const to = asString(ctx.to || '').trim();
|
|
2849
2937
|
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2938
|
+
this.logInfo(
|
|
2939
|
+
'outbound',
|
|
2940
|
+
`send-entry:text ${JSON.stringify({
|
|
2941
|
+
accountId,
|
|
2942
|
+
to,
|
|
2943
|
+
text: asString(ctx?.text || ''),
|
|
2944
|
+
mediaUrl: asString(ctx?.mediaUrl || ''),
|
|
2945
|
+
sessionKey: asString(ctx?.sessionKey || ''),
|
|
2946
|
+
mirrorSessionKey: asString(ctx?.mirror?.sessionKey || ''),
|
|
2947
|
+
rawCtx: {
|
|
2948
|
+
to: ctx?.to,
|
|
2949
|
+
accountId: ctx?.accountId,
|
|
2950
|
+
threadId: ctx?.threadId,
|
|
2951
|
+
replyToId: ctx?.replyToId,
|
|
2952
|
+
},
|
|
2953
|
+
})}`,
|
|
2954
|
+
{ debugOnly: true },
|
|
2955
|
+
);
|
|
2868
2956
|
|
|
2869
2957
|
return sendBncrText({
|
|
2870
2958
|
channelId: CHANNEL_ID,
|
|
2871
2959
|
accountId,
|
|
2872
2960
|
to,
|
|
2873
2961
|
text: asString(ctx.text || ''),
|
|
2962
|
+
replyToId: asString(ctx?.replyToId || ctx?.replyToMessageId || '').trim() || undefined,
|
|
2874
2963
|
mediaLocalRoots: ctx.mediaLocalRoots,
|
|
2875
2964
|
resolveVerifiedTarget: (to, accountId) => this.resolveVerifiedTarget(to, accountId),
|
|
2876
2965
|
rememberSessionRoute: (sessionKey, accountId, route) =>
|
|
@@ -2886,27 +2975,27 @@ class BncrBridgeRuntime {
|
|
|
2886
2975
|
const asVoice = ctx?.asVoice === true;
|
|
2887
2976
|
const audioAsVoice = ctx?.audioAsVoice === true;
|
|
2888
2977
|
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2978
|
+
this.logInfo(
|
|
2979
|
+
'outbound',
|
|
2980
|
+
`send-entry:media ${JSON.stringify({
|
|
2981
|
+
accountId,
|
|
2982
|
+
to,
|
|
2983
|
+
text: asString(ctx?.text || ''),
|
|
2984
|
+
mediaUrl: asString(ctx?.mediaUrl || ''),
|
|
2985
|
+
mediaUrls: Array.isArray(ctx?.mediaUrls) ? ctx.mediaUrls : undefined,
|
|
2986
|
+
asVoice,
|
|
2987
|
+
audioAsVoice,
|
|
2988
|
+
sessionKey: asString(ctx?.sessionKey || ''),
|
|
2989
|
+
mirrorSessionKey: asString(ctx?.mirror?.sessionKey || ''),
|
|
2990
|
+
rawCtx: {
|
|
2991
|
+
to: ctx?.to,
|
|
2992
|
+
accountId: ctx?.accountId,
|
|
2993
|
+
threadId: ctx?.threadId,
|
|
2994
|
+
replyToId: ctx?.replyToId,
|
|
2995
|
+
},
|
|
2996
|
+
})}`,
|
|
2997
|
+
{ debugOnly: true },
|
|
2998
|
+
);
|
|
2910
2999
|
|
|
2911
3000
|
return sendBncrMedia({
|
|
2912
3001
|
channelId: CHANNEL_ID,
|
|
@@ -2916,6 +3005,7 @@ class BncrBridgeRuntime {
|
|
|
2916
3005
|
mediaUrl: asString(ctx.mediaUrl || ''),
|
|
2917
3006
|
asVoice,
|
|
2918
3007
|
audioAsVoice,
|
|
3008
|
+
replyToId: asString(ctx?.replyToId || ctx?.replyToMessageId || '').trim() || undefined,
|
|
2919
3009
|
mediaLocalRoots: ctx.mediaLocalRoots,
|
|
2920
3010
|
resolveVerifiedTarget: (to, accountId) => this.resolveVerifiedTarget(to, accountId),
|
|
2921
3011
|
rememberSessionRoute: (sessionKey, accountId, route) =>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export type BncrLogLevel = 'info' | 'warn' | 'error';
|
|
2
|
+
export type BncrLogOptions = { debugOnly?: boolean };
|
|
3
|
+
|
|
4
|
+
const BNCR_PREFIX = '[bncr]';
|
|
5
|
+
|
|
6
|
+
type DebugGate = () => boolean;
|
|
7
|
+
|
|
8
|
+
type ConsoleMethod = 'log' | 'warn' | 'error';
|
|
9
|
+
|
|
10
|
+
function resolveConsoleMethod(level: BncrLogLevel): ConsoleMethod {
|
|
11
|
+
switch (level) {
|
|
12
|
+
case 'warn':
|
|
13
|
+
return 'warn';
|
|
14
|
+
case 'error':
|
|
15
|
+
return 'error';
|
|
16
|
+
default:
|
|
17
|
+
return 'log';
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function emitConsole(method: ConsoleMethod, line: string) {
|
|
22
|
+
if (method === 'warn') {
|
|
23
|
+
console.warn(line);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
if (method === 'error') {
|
|
27
|
+
console.error(line);
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(line);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function normalizeBncrLogLine(raw: string | undefined) {
|
|
34
|
+
const text = String(raw || '').trim();
|
|
35
|
+
if (!text) return BNCR_PREFIX;
|
|
36
|
+
return text.startsWith(BNCR_PREFIX) ? text : `${BNCR_PREFIX} ${text}`;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function formatBncrLogLine(scope: string | undefined, message: string | undefined) {
|
|
40
|
+
const normalizedScope = String(scope || '').trim();
|
|
41
|
+
const normalizedMessage = String(message || '').trim();
|
|
42
|
+
const prefix = normalizedScope ? `${BNCR_PREFIX} ${normalizedScope}` : BNCR_PREFIX;
|
|
43
|
+
return normalizedMessage ? `${prefix} ${normalizedMessage}` : prefix;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function emitBncrLog(
|
|
47
|
+
level: BncrLogLevel,
|
|
48
|
+
scope: string | undefined,
|
|
49
|
+
message: string | undefined,
|
|
50
|
+
options?: BncrLogOptions,
|
|
51
|
+
isDebugEnabled?: DebugGate,
|
|
52
|
+
) {
|
|
53
|
+
if (options?.debugOnly && !(isDebugEnabled?.() ?? false)) return;
|
|
54
|
+
emitConsole(resolveConsoleMethod(level), formatBncrLogLine(scope, message));
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function emitBncrLogLine(
|
|
58
|
+
level: BncrLogLevel,
|
|
59
|
+
line: string | undefined,
|
|
60
|
+
options?: BncrLogOptions,
|
|
61
|
+
isDebugEnabled?: DebugGate,
|
|
62
|
+
) {
|
|
63
|
+
if (options?.debugOnly && !(isDebugEnabled?.() ?? false)) return;
|
|
64
|
+
emitConsole(resolveConsoleMethod(level), normalizeBncrLogLine(line));
|
|
65
|
+
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { emitBncrLogLine } from '../../core/logging.ts';
|
|
1
2
|
import {
|
|
2
3
|
formatDisplayScope,
|
|
3
4
|
normalizeInboundSessionKey,
|
|
@@ -78,7 +79,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
78
79
|
const displayTo = formatDisplayScope(route);
|
|
79
80
|
const body = command.body;
|
|
80
81
|
if (!clientId) {
|
|
81
|
-
|
|
82
|
+
emitBncrLogLine('warn', '[bncr] inbound missing clientId for native command identity');
|
|
82
83
|
return { handled: false };
|
|
83
84
|
}
|
|
84
85
|
const senderIdForContext = clientId;
|
|
@@ -119,7 +120,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
119
120
|
sessionKey,
|
|
120
121
|
ctx: ctxPayload,
|
|
121
122
|
onRecordError: (err: unknown) => {
|
|
122
|
-
|
|
123
|
+
emitBncrLogLine('warn', `[bncr] inbound record native command session failed: ${String(err)}`);
|
|
123
124
|
},
|
|
124
125
|
});
|
|
125
126
|
|
|
@@ -155,6 +156,7 @@ export async function handleBncrNativeCommand(params: {
|
|
|
155
156
|
payload: {
|
|
156
157
|
...payload,
|
|
157
158
|
kind: kind as 'tool' | 'block' | 'final' | undefined,
|
|
159
|
+
replyToId: msgId || undefined,
|
|
158
160
|
},
|
|
159
161
|
});
|
|
160
162
|
},
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { emitBncrLogLine } from '../../core/logging.ts';
|
|
1
2
|
import {
|
|
2
3
|
formatDisplayScope,
|
|
3
4
|
normalizeInboundSessionKey,
|
|
@@ -132,7 +133,7 @@ export async function dispatchBncrInbound(params: {
|
|
|
132
133
|
|
|
133
134
|
const displayTo = formatDisplayScope(route);
|
|
134
135
|
if (!clientId) {
|
|
135
|
-
|
|
136
|
+
emitBncrLogLine('warn', '[bncr] inbound missing clientId for chat identity');
|
|
136
137
|
return {
|
|
137
138
|
accountId,
|
|
138
139
|
sessionKey,
|
|
@@ -171,7 +172,7 @@ export async function dispatchBncrInbound(params: {
|
|
|
171
172
|
sessionKey,
|
|
172
173
|
ctx: ctxPayload,
|
|
173
174
|
onRecordError: (err: unknown) => {
|
|
174
|
-
|
|
175
|
+
emitBncrLogLine('warn', `[bncr] inbound record session failed: ${String(err)}`);
|
|
175
176
|
},
|
|
176
177
|
});
|
|
177
178
|
|
|
@@ -207,7 +208,7 @@ export async function dispatchBncrInbound(params: {
|
|
|
207
208
|
});
|
|
208
209
|
},
|
|
209
210
|
onError: (err: unknown) => {
|
|
210
|
-
|
|
211
|
+
emitBncrLogLine('error', `[bncr] outbound reply failed: ${String(err)}`);
|
|
211
212
|
},
|
|
212
213
|
},
|
|
213
214
|
replyOptions: {
|
|
@@ -56,6 +56,7 @@ export function buildBncrMediaOutboundFrame(params: {
|
|
|
56
56
|
fileName: string;
|
|
57
57
|
hintedType?: string;
|
|
58
58
|
kind?: 'tool' | 'block' | 'final';
|
|
59
|
+
replyToId?: string;
|
|
59
60
|
now: number;
|
|
60
61
|
}) {
|
|
61
62
|
return {
|
|
@@ -63,6 +64,7 @@ export function buildBncrMediaOutboundFrame(params: {
|
|
|
63
64
|
messageId: params.messageId,
|
|
64
65
|
idempotencyKey: params.messageId,
|
|
65
66
|
sessionKey: params.sessionKey,
|
|
67
|
+
replyToId: asString(params.replyToId || '').trim() || undefined,
|
|
66
68
|
message: {
|
|
67
69
|
platform: params.route.platform,
|
|
68
70
|
groupId: params.route.groupId,
|
|
@@ -3,6 +3,7 @@ export async function sendBncrText(params: {
|
|
|
3
3
|
accountId: string;
|
|
4
4
|
to: string;
|
|
5
5
|
text: string;
|
|
6
|
+
replyToId?: string;
|
|
6
7
|
mediaLocalRoots?: readonly string[];
|
|
7
8
|
resolveVerifiedTarget: (
|
|
8
9
|
to: string,
|
|
@@ -13,7 +14,12 @@ export async function sendBncrText(params: {
|
|
|
13
14
|
accountId: string;
|
|
14
15
|
sessionKey: string;
|
|
15
16
|
route: any;
|
|
16
|
-
payload: {
|
|
17
|
+
payload: {
|
|
18
|
+
text?: string;
|
|
19
|
+
mediaUrl?: string;
|
|
20
|
+
mediaUrls?: string[];
|
|
21
|
+
replyToId?: string;
|
|
22
|
+
};
|
|
17
23
|
mediaLocalRoots?: readonly string[];
|
|
18
24
|
}) => Promise<void>;
|
|
19
25
|
createMessageId: () => string;
|
|
@@ -27,6 +33,7 @@ export async function sendBncrText(params: {
|
|
|
27
33
|
route: verified.route,
|
|
28
34
|
payload: {
|
|
29
35
|
text: params.text,
|
|
36
|
+
replyToId: params.replyToId,
|
|
30
37
|
},
|
|
31
38
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
32
39
|
});
|
|
@@ -46,6 +53,7 @@ export async function sendBncrMedia(params: {
|
|
|
46
53
|
mediaUrl?: string;
|
|
47
54
|
asVoice?: boolean;
|
|
48
55
|
audioAsVoice?: boolean;
|
|
56
|
+
replyToId?: string;
|
|
49
57
|
mediaLocalRoots?: readonly string[];
|
|
50
58
|
resolveVerifiedTarget: (
|
|
51
59
|
to: string,
|
|
@@ -62,6 +70,7 @@ export async function sendBncrMedia(params: {
|
|
|
62
70
|
mediaUrls?: string[];
|
|
63
71
|
asVoice?: boolean;
|
|
64
72
|
audioAsVoice?: boolean;
|
|
73
|
+
replyToId?: string;
|
|
65
74
|
};
|
|
66
75
|
mediaLocalRoots?: readonly string[];
|
|
67
76
|
}) => Promise<void>;
|
|
@@ -79,6 +88,7 @@ export async function sendBncrMedia(params: {
|
|
|
79
88
|
mediaUrl: params.mediaUrl || '',
|
|
80
89
|
asVoice: params.asVoice === true ? true : undefined,
|
|
81
90
|
audioAsVoice: params.audioAsVoice === true ? true : undefined,
|
|
91
|
+
replyToId: params.replyToId,
|
|
82
92
|
},
|
|
83
93
|
mediaLocalRoots: params.mediaLocalRoots,
|
|
84
94
|
});
|