@xmoxmo/bncr 0.5.6 → 0.5.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/dist/index.js +1 -9
- package/index.ts +1 -9
- package/package.json +1 -1
- package/scripts/check-pack.mjs +0 -8
- package/scripts/selfcheck.mjs +0 -10
- package/src/bootstrap/runtime-loader.ts +1 -1
- package/src/channel.ts +118 -171
- package/src/core/accounts.ts +1 -6
- package/src/core/connection-reachability.ts +2 -6
- package/src/core/dead-letter-diagnostics.ts +4 -10
- package/src/core/logging.ts +1 -1
- package/src/core/outbox-entry-builders.ts +78 -84
- package/src/core/outbox-file-transfer-failure.ts +5 -0
- package/src/core/outbox-file-transfer-guards.ts +6 -0
- package/src/core/outbox-file-transfer-prep.ts +8 -5
- package/src/core/outbox-file-transfer-success.ts +5 -0
- package/src/core/outbox-queue.ts +1 -7
- package/src/core/outbox-summary.ts +10 -56
- package/src/core/permissions.ts +2 -10
- package/src/core/persisted-outbox-entry.ts +54 -11
- package/src/core/policy.ts +1 -11
- package/src/core/register-trace.ts +4 -7
- package/src/core/status-meta.ts +1 -9
- package/src/core/status.ts +1 -21
- package/src/core/targets.ts +52 -70
- package/src/core/types.ts +1 -17
- package/src/core/value-sanitize.ts +38 -1
- package/src/messaging/inbound/commands.ts +2 -24
- package/src/messaging/inbound/dispatch-prep.ts +1 -1
- package/src/messaging/inbound/gate.ts +2 -31
- package/src/messaging/inbound/group-history.ts +0 -75
- package/src/messaging/inbound/parse.ts +2 -32
- package/src/messaging/inbound/scene-admin.ts +8 -8
- package/src/messaging/outbound/diagnostics-debug-builders.ts +0 -15
- package/src/messaging/outbound/diagnostics.ts +1 -7
- package/src/messaging/outbound/durable-queue-adapter.ts +17 -11
- package/src/messaging/outbound/marker-parser.ts +277 -28
- package/src/messaging/outbound/media-dedupe.ts +3 -10
- package/src/messaging/outbound/media.ts +1 -6
- package/src/messaging/outbound/normalize-outbound-send.ts +329 -0
- package/src/messaging/outbound/queue-selectors.ts +1 -5
- package/src/messaging/outbound/reply-enqueue-media.ts +1 -184
- package/src/messaging/outbound/reply-enqueue.ts +313 -175
- package/src/messaging/outbound/session-route.ts +6 -11
- package/src/messaging/outbound/target-resolver.ts +1 -6
- package/src/openclaw/media-runtime.ts +1 -1
- package/src/openclaw/routing-runtime.ts +0 -11
- package/src/openclaw/sdk-helpers.ts +0 -2
- package/src/plugin/bridge-media-facade.ts +0 -4
- package/src/plugin/bridge-outbox-facade.ts +0 -1
- package/src/plugin/channel-components.ts +0 -13
- package/src/plugin/channel-plugin-surface-group.ts +52 -65
- package/src/plugin/channel-runtime-builders-delivery.ts +3 -362
- package/src/plugin/channel-runtime-builders-status.ts +0 -160
- package/src/plugin/channel-runtime-builders.ts +3 -17
- package/src/plugin/channel-runtime-constants.ts +1 -1
- package/src/plugin/channel-runtime-types.ts +2 -24
- package/src/plugin/channel-send.ts +206 -221
- package/src/plugin/channel-utils.ts +8 -29
- package/src/plugin/connection-handlers-helpers.ts +0 -15
- package/src/plugin/connection-handlers.ts +6 -5
- package/src/plugin/file-inbound-abort.ts +5 -0
- package/src/plugin/file-inbound-chunk.ts +5 -0
- package/src/plugin/file-inbound-complete.ts +5 -0
- package/src/plugin/file-transfer-orchestrator.ts +39 -2
- package/src/plugin/media-dedupe-runtime.ts +1 -6
- package/src/plugin/media-orchestrators-runtime-group.ts +20 -149
- package/src/plugin/message-send.ts +7 -8
- package/src/plugin/messaging.ts +3 -3
- package/src/plugin/outbound.ts +6 -26
- package/src/plugin/outbox-drain-loop.ts +2 -2
- package/src/plugin/outbox-push.ts +1 -52
- package/src/plugin/outbox-unified-push-flow.ts +307 -0
- package/src/plugin/scene-registry.ts +1 -1
- package/src/plugin/target-runtime.ts +1 -6
- package/src/runtime/log-dedupe.ts +3 -3
- package/src/runtime/outbound-ack-timeout.ts +3 -12
- package/src/runtime/outbox-transitions.ts +1 -4
- package/src/runtime/status-snapshots.ts +2 -2
- package/src/runtime/status-worker.ts +3 -15
- package/src/core/outbox-text-push-prep.ts +0 -36
- package/src/messaging/outbound/build-send-action.ts +0 -130
- package/src/messaging/outbound/durable-message-adapter.ts +0 -121
- package/src/messaging/outbound/send-params.ts +0 -114
- package/src/messaging/outbound/send.ts +0 -127
- package/src/openclaw/ingress-runtime.ts +0 -25
- package/src/plugin/bridge-file-transfer-push-facade.ts +0 -142
- package/src/plugin/channel-send-runtime-group.ts +0 -37
- package/src/plugin/outbox-file-push-flow.ts +0 -69
- package/src/plugin/outbox-text-push-flow.ts +0 -90
|
@@ -193,7 +193,38 @@ export function createBncrFileTransferOrchestrator(runtime: BncrFileTransferOrch
|
|
|
193
193
|
};
|
|
194
194
|
const HTTP_URL_RE = /^https?:\/\//i;
|
|
195
195
|
|
|
196
|
-
|
|
196
|
+
const EXT_TO_MIME: Record<string, string> = {
|
|
197
|
+
jpg: 'image/jpeg',
|
|
198
|
+
jpeg: 'image/jpeg',
|
|
199
|
+
png: 'image/png',
|
|
200
|
+
gif: 'image/gif',
|
|
201
|
+
webp: 'image/webp',
|
|
202
|
+
bmp: 'image/bmp',
|
|
203
|
+
heic: 'image/heic',
|
|
204
|
+
heif: 'image/heif',
|
|
205
|
+
mp4: 'video/mp4',
|
|
206
|
+
mov: 'video/quicktime',
|
|
207
|
+
mkv: 'video/x-matroska',
|
|
208
|
+
webm: 'video/webm',
|
|
209
|
+
avi: 'video/x-msvideo',
|
|
210
|
+
m4v: 'video/x-m4v',
|
|
211
|
+
mp3: 'audio/mpeg',
|
|
212
|
+
wav: 'audio/wav',
|
|
213
|
+
ogg: 'audio/ogg',
|
|
214
|
+
oga: 'audio/ogg',
|
|
215
|
+
opus: 'audio/opus',
|
|
216
|
+
m4a: 'audio/mp4',
|
|
217
|
+
aac: 'audio/aac',
|
|
218
|
+
flac: 'audio/flac',
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
function mimeFromUrlExt(url: string): string | undefined {
|
|
222
|
+
const clean = url.split(/[?#]/, 1)[0] || '';
|
|
223
|
+
const ext = clean.includes('.') ? clean.slice(clean.lastIndexOf('.') + 1).toLowerCase() : '';
|
|
224
|
+
return EXT_TO_MIME[ext];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/** Try HEAD for Content-Type; fall back to Range+sniff for magic bytes; then URL extension. */
|
|
197
228
|
async function resolveRemoteMediaType(url: string): Promise<{ mimeType?: string }> {
|
|
198
229
|
// 1) HEAD -> Content-Type
|
|
199
230
|
let headerType = '';
|
|
@@ -229,8 +260,14 @@ export function createBncrFileTransferOrchestrator(runtime: BncrFileTransferOrch
|
|
|
229
260
|
if (!sniffed) return {};
|
|
230
261
|
return { mimeType: sniffed };
|
|
231
262
|
} catch {
|
|
232
|
-
|
|
263
|
+
/* Range sniff failed, fall through to extension inference */
|
|
233
264
|
}
|
|
265
|
+
|
|
266
|
+
// 3) URL extension -> mime type (fallback when HEAD and Range both fail)
|
|
267
|
+
const extMime = mimeFromUrlExt(url);
|
|
268
|
+
if (extMime) return { mimeType: extMime };
|
|
269
|
+
|
|
270
|
+
return {};
|
|
234
271
|
}
|
|
235
272
|
|
|
236
273
|
/** Minimal magic-byte MIME sniffer for the first ~512 bytes. */
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { asString } from '../core/value-sanitize.ts';
|
|
1
2
|
import {
|
|
2
3
|
buildMediaTextFallback,
|
|
3
4
|
type MediaDedupeCacheEntry,
|
|
@@ -5,12 +6,6 @@ import {
|
|
|
5
6
|
normalizeReplyToId,
|
|
6
7
|
} from '../messaging/outbound/media-dedupe.ts';
|
|
7
8
|
|
|
8
|
-
function asString(v: unknown, fallback = ''): string {
|
|
9
|
-
if (typeof v === 'string') return v;
|
|
10
|
-
if (v == null) return fallback;
|
|
11
|
-
return String(v);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
9
|
export function createBncrMediaDedupeRuntime(runtime: {
|
|
15
10
|
now: () => number;
|
|
16
11
|
recentMediaDedupeBySession: Map<string, Map<string, MediaDedupeCacheEntry>>;
|
|
@@ -1,21 +1,13 @@
|
|
|
1
1
|
import type { BncrRoute, FileSendTransferState, OutboxEntry } from '../core/types.ts';
|
|
2
|
-
import { normalizeMessageText } from '../messaging/outbound/media-dedupe.ts';
|
|
3
2
|
import type {
|
|
4
3
|
NormalizedReplyPayload,
|
|
5
4
|
OutboundReplyTargetPolicy,
|
|
6
|
-
ReplyMediaEntriesParams,
|
|
7
5
|
ReplyPayloadInput,
|
|
8
6
|
} from '../messaging/outbound/reply-enqueue.ts';
|
|
9
7
|
import {
|
|
10
8
|
enqueueNormalizedReplyPayload,
|
|
11
|
-
enqueueReplyTextEntry,
|
|
12
9
|
normalizeReplyPayload,
|
|
13
10
|
} from '../messaging/outbound/reply-enqueue.ts';
|
|
14
|
-
import {
|
|
15
|
-
enqueueReplyMediaFallbackTextEntry,
|
|
16
|
-
enqueueReplyMediaFileTransferEntry,
|
|
17
|
-
enqueueSingleReplyMediaEntry,
|
|
18
|
-
} from '../messaging/outbound/reply-enqueue-media.ts';
|
|
19
11
|
import type { createBncrFileAckRuntime } from './file-ack-runtime.ts';
|
|
20
12
|
import { createBncrFileTransferOrchestrator } from './file-transfer-orchestrator.ts';
|
|
21
13
|
import type { createBncrFileTransferSetup } from './file-transfer-setup.ts';
|
|
@@ -27,92 +19,12 @@ type FileAckPayload = Awaited<
|
|
|
27
19
|
ReturnType<ReturnType<typeof createBncrFileAckRuntime>['waitForFileAck']>
|
|
28
20
|
>;
|
|
29
21
|
|
|
30
|
-
function
|
|
31
|
-
logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
|
|
32
|
-
enqueueOutbound: (entry: OutboxEntry) => void;
|
|
33
|
-
buildTextOutboxEntry: (args: {
|
|
34
|
-
accountId: string;
|
|
35
|
-
sessionKey: string;
|
|
36
|
-
route: BncrRoute;
|
|
37
|
-
text: string;
|
|
38
|
-
kind?: 'tool' | 'block' | 'final';
|
|
39
|
-
replyToId?: string;
|
|
40
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
41
|
-
}) => OutboxEntry;
|
|
42
|
-
buildFileTransferOutboxEntry: (args: {
|
|
43
|
-
accountId: string;
|
|
44
|
-
sessionKey: string;
|
|
45
|
-
route: BncrRoute;
|
|
46
|
-
mediaUrl: string;
|
|
47
|
-
mediaLocalRoots?: readonly string[];
|
|
48
|
-
text: string;
|
|
49
|
-
asVoice: boolean;
|
|
50
|
-
audioAsVoice: boolean;
|
|
51
|
-
type?: string;
|
|
52
|
-
extra?: Record<string, unknown>;
|
|
53
|
-
kind?: 'tool' | 'block' | 'final';
|
|
54
|
-
replyToId?: string;
|
|
55
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
56
|
-
downloadMedia?: boolean;
|
|
57
|
-
}) => OutboxEntry;
|
|
58
|
-
rememberRecentMediaSend: (args: {
|
|
59
|
-
sessionKey: string;
|
|
60
|
-
mediaUrl: string;
|
|
61
|
-
text: string;
|
|
62
|
-
replyToId: string;
|
|
63
|
-
createdAt: number;
|
|
64
|
-
}) => void;
|
|
65
|
-
}) {
|
|
66
|
-
return {
|
|
67
|
-
enqueueReplyMediaFallbackTextEntry: (
|
|
68
|
-
params: Parameters<typeof enqueueReplyMediaFallbackTextEntry>[0],
|
|
69
|
-
) =>
|
|
70
|
-
enqueueReplyMediaFallbackTextEntry(params, {
|
|
71
|
-
logInfo: runtime.logInfo,
|
|
72
|
-
enqueueOutbound: runtime.enqueueOutbound,
|
|
73
|
-
buildTextOutboxEntry: runtime.buildTextOutboxEntry,
|
|
74
|
-
}),
|
|
75
|
-
enqueueReplyMediaFileTransferEntry: (
|
|
76
|
-
params: Parameters<typeof enqueueReplyMediaFileTransferEntry>[0],
|
|
77
|
-
) =>
|
|
78
|
-
enqueueReplyMediaFileTransferEntry(params, {
|
|
79
|
-
enqueueOutbound: runtime.enqueueOutbound,
|
|
80
|
-
buildFileTransferOutboxEntry: runtime.buildFileTransferOutboxEntry,
|
|
81
|
-
rememberRecentMediaSend: runtime.rememberRecentMediaSend,
|
|
82
|
-
}),
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
function buildReplyTextEntryHelper(runtime: {
|
|
87
|
-
enqueueOutbound: (entry: OutboxEntry) => void;
|
|
88
|
-
buildTextOutboxEntry: (args: {
|
|
89
|
-
accountId: string;
|
|
90
|
-
sessionKey: string;
|
|
91
|
-
route: BncrRoute;
|
|
92
|
-
text: string;
|
|
93
|
-
kind?: 'tool' | 'block' | 'final';
|
|
94
|
-
replyToId?: string;
|
|
95
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
96
|
-
}) => OutboxEntry;
|
|
97
|
-
}) {
|
|
98
|
-
return (params: {
|
|
99
|
-
accountId: string;
|
|
100
|
-
sessionKey: string;
|
|
101
|
-
route: BncrRoute;
|
|
102
|
-
payload: NormalizedReplyPayload;
|
|
103
|
-
}) =>
|
|
104
|
-
enqueueReplyTextEntry(params, {
|
|
105
|
-
enqueueOutbound: runtime.enqueueOutbound,
|
|
106
|
-
buildTextOutboxEntry: runtime.buildTextOutboxEntry,
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
function normalizeReplyOrchestratorPayload(args: {
|
|
22
|
+
async function normalizeReplyOrchestratorPayload(args: {
|
|
111
23
|
payload: ReplyPayloadInput;
|
|
112
24
|
asString: (value: unknown, fallback?: string) => string;
|
|
113
25
|
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
114
26
|
}) {
|
|
115
|
-
return normalizeReplyPayload(
|
|
27
|
+
return await normalizeReplyPayload(
|
|
116
28
|
args.payload,
|
|
117
29
|
{ asString: args.asString },
|
|
118
30
|
{
|
|
@@ -186,29 +98,21 @@ export function createBncrMediaOrchestratorsRuntimeGroup(runtime: {
|
|
|
186
98
|
payload: NormalizedReplyPayload;
|
|
187
99
|
}) => void;
|
|
188
100
|
enqueueOutbound: (entry: OutboxEntry) => void;
|
|
189
|
-
|
|
101
|
+
buildOutboxEntry: (args: {
|
|
190
102
|
accountId: string;
|
|
191
103
|
sessionKey: string;
|
|
192
104
|
route: BncrRoute;
|
|
193
|
-
text: string;
|
|
194
|
-
kind?: 'tool' | 'block' | 'final';
|
|
195
|
-
replyToId?: string;
|
|
196
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
197
|
-
}) => OutboxEntry;
|
|
198
|
-
buildFileTransferOutboxEntry: (args: {
|
|
199
|
-
accountId: string;
|
|
200
|
-
sessionKey: string;
|
|
201
|
-
route: BncrRoute;
|
|
202
|
-
mediaUrl: string;
|
|
203
|
-
mediaLocalRoots?: readonly string[];
|
|
204
|
-
text: string;
|
|
205
|
-
asVoice: boolean;
|
|
206
|
-
audioAsVoice: boolean;
|
|
207
105
|
type?: string;
|
|
208
|
-
|
|
106
|
+
msg: string;
|
|
209
107
|
kind?: 'tool' | 'block' | 'final';
|
|
210
108
|
replyToId?: string;
|
|
211
109
|
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
110
|
+
extra?: Record<string, unknown>;
|
|
111
|
+
transferMode?: 'text' | 'media';
|
|
112
|
+
mediaUrl?: string;
|
|
113
|
+
mediaLocalRoots?: readonly string[];
|
|
114
|
+
asVoice?: boolean;
|
|
115
|
+
audioAsVoice?: boolean;
|
|
212
116
|
downloadMedia?: boolean;
|
|
213
117
|
}) => OutboxEntry;
|
|
214
118
|
rememberRecentMediaSend: (args: {
|
|
@@ -244,40 +148,7 @@ export function createBncrMediaOrchestratorsRuntimeGroup(runtime: {
|
|
|
244
148
|
logFileTransferCompleteAck: runtime.logFileTransferCompleteAck,
|
|
245
149
|
});
|
|
246
150
|
|
|
247
|
-
const
|
|
248
|
-
const replyTextEntryHelper = buildReplyTextEntryHelper(runtime);
|
|
249
|
-
|
|
250
|
-
const enqueueReplyMediaEntries = (params: ReplyMediaEntriesParams) => {
|
|
251
|
-
let first = true;
|
|
252
|
-
const currentTime = runtime.now();
|
|
253
|
-
|
|
254
|
-
for (const mediaUrl of params.payload.mediaList) {
|
|
255
|
-
const normalizedText = normalizeMessageText(first ? params.payload.text : '');
|
|
256
|
-
const fallback = runtime.tryBuildMediaDedupeFallback({
|
|
257
|
-
sessionKey: params.sessionKey,
|
|
258
|
-
mediaUrl,
|
|
259
|
-
text: normalizedText,
|
|
260
|
-
replyToId: params.payload.replyToId,
|
|
261
|
-
currentTime,
|
|
262
|
-
});
|
|
263
|
-
|
|
264
|
-
enqueueSingleReplyMediaEntry(
|
|
265
|
-
{
|
|
266
|
-
params,
|
|
267
|
-
mediaUrl,
|
|
268
|
-
normalizedText,
|
|
269
|
-
text: first ? params.payload.text : '',
|
|
270
|
-
fallback,
|
|
271
|
-
currentTime,
|
|
272
|
-
},
|
|
273
|
-
replyMediaEntryHelpers,
|
|
274
|
-
);
|
|
275
|
-
|
|
276
|
-
first = false;
|
|
277
|
-
}
|
|
278
|
-
};
|
|
279
|
-
|
|
280
|
-
const enqueueFromReply = (params: {
|
|
151
|
+
const enqueueFromReply = async (params: {
|
|
281
152
|
accountId: string;
|
|
282
153
|
sessionKey: string;
|
|
283
154
|
route: BncrRoute;
|
|
@@ -286,7 +157,7 @@ export function createBncrMediaOrchestratorsRuntimeGroup(runtime: {
|
|
|
286
157
|
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
287
158
|
}) => {
|
|
288
159
|
const { accountId, sessionKey, route, payload, mediaLocalRoots, replyTargetPolicy } = params;
|
|
289
|
-
const normalized = normalizeReplyOrchestratorPayload({
|
|
160
|
+
const normalized = await normalizeReplyOrchestratorPayload({
|
|
290
161
|
payload,
|
|
291
162
|
asString: runtime.asString,
|
|
292
163
|
replyTargetPolicy,
|
|
@@ -302,19 +173,19 @@ export function createBncrMediaOrchestratorsRuntimeGroup(runtime: {
|
|
|
302
173
|
},
|
|
303
174
|
{
|
|
304
175
|
logEnqueueFromReply: runtime.logEnqueueFromReply,
|
|
305
|
-
|
|
306
|
-
|
|
176
|
+
enqueueOutbound: runtime.enqueueOutbound,
|
|
177
|
+
buildOutboxEntry: runtime.buildOutboxEntry,
|
|
178
|
+
tryBuildMediaDedupeFallback: runtime.tryBuildMediaDedupeFallback,
|
|
179
|
+
rememberRecentMediaSend: runtime.rememberRecentMediaSend,
|
|
180
|
+
logInfo: runtime.logInfo,
|
|
307
181
|
},
|
|
308
182
|
);
|
|
309
183
|
};
|
|
310
184
|
|
|
311
|
-
const replyMediaOrchestrator = {
|
|
312
|
-
enqueueFromReply,
|
|
313
|
-
enqueueReplyMediaEntries,
|
|
314
|
-
};
|
|
315
|
-
|
|
316
185
|
return {
|
|
317
186
|
fileTransferOrchestrator,
|
|
318
|
-
replyMediaOrchestrator
|
|
187
|
+
replyMediaOrchestrator: {
|
|
188
|
+
enqueueFromReply,
|
|
189
|
+
},
|
|
319
190
|
};
|
|
320
191
|
}
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import type { ChannelMessageSendResult } from 'openclaw/plugin-sdk/channel-message';
|
|
2
|
-
|
|
3
|
-
type MessageSendContext = Record<string, unknown>;
|
|
2
|
+
import type { BncrChannelSendContext } from './channel-runtime-types.ts';
|
|
4
3
|
|
|
5
4
|
export type BncrMessageSendBridge = {
|
|
6
5
|
channelMessageSendText: (
|
|
7
|
-
ctx:
|
|
6
|
+
ctx: BncrChannelSendContext,
|
|
8
7
|
) => ChannelMessageSendResult | Promise<ChannelMessageSendResult>;
|
|
9
8
|
channelMessageSendMedia: (
|
|
10
|
-
ctx:
|
|
9
|
+
ctx: BncrChannelSendContext,
|
|
11
10
|
) => ChannelMessageSendResult | Promise<ChannelMessageSendResult>;
|
|
12
11
|
channelMessageSendPayload: (
|
|
13
|
-
ctx:
|
|
12
|
+
ctx: BncrChannelSendContext,
|
|
14
13
|
) => ChannelMessageSendResult | Promise<ChannelMessageSendResult>;
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
export function createBncrMessageSend(getBridge: () => BncrMessageSendBridge) {
|
|
18
17
|
return {
|
|
19
|
-
text: async (ctx:
|
|
20
|
-
media: async (ctx:
|
|
21
|
-
payload: async (ctx:
|
|
18
|
+
text: async (ctx: BncrChannelSendContext) => getBridge().channelMessageSendText(ctx),
|
|
19
|
+
media: async (ctx: BncrChannelSendContext) => getBridge().channelMessageSendMedia(ctx),
|
|
20
|
+
payload: async (ctx: BncrChannelSendContext) => getBridge().channelMessageSendPayload(ctx),
|
|
22
21
|
};
|
|
23
22
|
}
|
package/src/plugin/messaging.ts
CHANGED
|
@@ -67,12 +67,12 @@ function isDisplayTarget(
|
|
|
67
67
|
return Boolean(value && typeof value === 'object');
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
function normalizeBncrMessagingTarget(raw: string) {
|
|
71
71
|
const input = asSanitizedString(raw).trim();
|
|
72
72
|
return input || undefined;
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
|
|
75
|
+
function formatBncrMessagingTargetDisplay({ target }: BncrMessagingTargetDisplayInput) {
|
|
76
76
|
if (typeof target === 'string') {
|
|
77
77
|
const parsed = parseExplicitTarget(asSanitizedString(target).trim());
|
|
78
78
|
return parsed?.route ? formatBncrHumanDisplay(parsed.route) : asSanitizedString(target).trim();
|
|
@@ -183,7 +183,7 @@ export function createBncrMessagingSurface(getBridge: () => BncrMessagingRuntime
|
|
|
183
183
|
};
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
-
|
|
186
|
+
function createBncrMessagingTargetResolver(getBridge: () => BncrMessagingRuntimeBridge) {
|
|
187
187
|
return {
|
|
188
188
|
looksLikeId: (raw: string, normalized?: string) => {
|
|
189
189
|
return looksLikeBncrExplicitTarget(asSanitizedString(normalized || raw).trim());
|
package/src/plugin/outbound.ts
CHANGED
|
@@ -1,35 +1,15 @@
|
|
|
1
1
|
import { normalizeAccountId } from '../core/accounts.ts';
|
|
2
|
+
import { asString } from '../core/value-sanitize.ts';
|
|
2
3
|
import {
|
|
3
4
|
deleteBncrMessageAction,
|
|
4
5
|
editBncrMessageAction,
|
|
5
6
|
reactBncrMessageAction,
|
|
6
7
|
sendBncrReplyAction,
|
|
7
8
|
} from '../messaging/outbound/actions.ts';
|
|
8
|
-
|
|
9
|
-
function asString(v: unknown, fallback = ''): string {
|
|
10
|
-
return typeof v === 'string' ? v : v == null ? fallback : String(v);
|
|
11
|
-
}
|
|
9
|
+
import type { BncrChannelSendContext } from './channel-runtime-types.ts';
|
|
12
10
|
|
|
13
11
|
type BncrOutboundDeliveryResult = { channel: string; messageId: string; chatId: string };
|
|
14
12
|
|
|
15
|
-
type BncrOutboundSendContext = {
|
|
16
|
-
accountId?: string | null;
|
|
17
|
-
to?: string;
|
|
18
|
-
text?: string;
|
|
19
|
-
mediaUrl?: string;
|
|
20
|
-
type?: string;
|
|
21
|
-
kind?: string;
|
|
22
|
-
replyToId?: string | null;
|
|
23
|
-
replyToMessageId?: string | null;
|
|
24
|
-
asVoice?: boolean;
|
|
25
|
-
audioAsVoice?: boolean;
|
|
26
|
-
mediaLocalRoots?: readonly string[];
|
|
27
|
-
/** Pass-through fields from host — bncr plugin does NOT consume these. */
|
|
28
|
-
forceDocument?: boolean;
|
|
29
|
-
gifPlayback?: boolean;
|
|
30
|
-
silent?: boolean;
|
|
31
|
-
};
|
|
32
|
-
|
|
33
13
|
type BncrOutboundReplyActionContext = {
|
|
34
14
|
accountId?: string | null;
|
|
35
15
|
to?: string;
|
|
@@ -54,18 +34,18 @@ type BncrOutboundEditActionContext = BncrOutboundTargetActionContext & {
|
|
|
54
34
|
|
|
55
35
|
export type BncrOutboundBridge = {
|
|
56
36
|
channelSendText: (
|
|
57
|
-
ctx:
|
|
37
|
+
ctx: BncrChannelSendContext,
|
|
58
38
|
) => BncrOutboundDeliveryResult | Promise<BncrOutboundDeliveryResult>;
|
|
59
39
|
channelSendMedia: (
|
|
60
|
-
ctx:
|
|
40
|
+
ctx: BncrChannelSendContext,
|
|
61
41
|
) => BncrOutboundDeliveryResult | Promise<BncrOutboundDeliveryResult>;
|
|
62
42
|
};
|
|
63
43
|
|
|
64
44
|
export function createBncrOutboundRuntime(getBridge: () => BncrOutboundBridge) {
|
|
65
45
|
return {
|
|
66
46
|
deliveryMode: 'gateway' as const,
|
|
67
|
-
sendText: async (ctx:
|
|
68
|
-
sendMedia: async (ctx:
|
|
47
|
+
sendText: async (ctx: BncrChannelSendContext) => getBridge().channelSendText(ctx),
|
|
48
|
+
sendMedia: async (ctx: BncrChannelSendContext) => getBridge().channelSendMedia(ctx),
|
|
69
49
|
replyAction: async (ctx: BncrOutboundReplyActionContext) =>
|
|
70
50
|
sendBncrReplyAction({
|
|
71
51
|
accountId: normalizeAccountId(ctx?.accountId),
|
|
@@ -295,8 +295,8 @@ export function createBncrOutboxDrainLoop(
|
|
|
295
295
|
try {
|
|
296
296
|
pushed = await runtime.tryPushEntry(entry);
|
|
297
297
|
} catch (error) {
|
|
298
|
-
const
|
|
299
|
-
if (
|
|
298
|
+
const msg = runtime.isPlainObject(entry.payload?.message) ? entry.payload.message : null;
|
|
299
|
+
if (msg?.transferMode === 'media') {
|
|
300
300
|
runtime.handleFileTransferPushFailure({ entry, error });
|
|
301
301
|
} else {
|
|
302
302
|
runtime.handleTextPushFailure({ entry, error });
|
|
@@ -3,12 +3,7 @@ import {
|
|
|
3
3
|
resolveFileTransferFailureState,
|
|
4
4
|
} from '../core/outbox-file-transfer-failure.ts';
|
|
5
5
|
import { buildTextPushFailureArgs } from '../core/outbox-text-push-failure.ts';
|
|
6
|
-
|
|
7
|
-
buildTextPushBroadcastPayload,
|
|
8
|
-
buildTextPushOkArgs,
|
|
9
|
-
buildTextPushRouteSelectArgs,
|
|
10
|
-
buildTextPushSuccessArgs,
|
|
11
|
-
} from '../core/outbox-text-push-success.ts';
|
|
6
|
+
|
|
12
7
|
import type { BncrConnection, OutboxEntry } from '../core/types.ts';
|
|
13
8
|
import {
|
|
14
9
|
buildOutboxPushOkDebugInfo,
|
|
@@ -137,51 +132,6 @@ export function createBncrOutboxPush(runtime: BncrOutboxPushRuntime) {
|
|
|
137
132
|
);
|
|
138
133
|
};
|
|
139
134
|
|
|
140
|
-
const pushTextSuccessPath = (args: {
|
|
141
|
-
entry: OutboxEntry;
|
|
142
|
-
owner: BncrConnection | null;
|
|
143
|
-
connIds: Iterable<string>;
|
|
144
|
-
recentInboundReachable: boolean;
|
|
145
|
-
routeReason: string;
|
|
146
|
-
ownerConnId?: string;
|
|
147
|
-
}) => {
|
|
148
|
-
runtime.gatewayBroadcastToConnIds(
|
|
149
|
-
runtime.pushEvent,
|
|
150
|
-
buildTextPushBroadcastPayload({
|
|
151
|
-
payload: args.entry.payload,
|
|
152
|
-
messageId: args.entry.messageId,
|
|
153
|
-
}),
|
|
154
|
-
new Set(args.connIds),
|
|
155
|
-
);
|
|
156
|
-
logOutboxRouteSelect(
|
|
157
|
-
buildTextPushRouteSelectArgs({
|
|
158
|
-
entry: args.entry,
|
|
159
|
-
connIds: args.connIds,
|
|
160
|
-
routeReason: args.routeReason,
|
|
161
|
-
recentInboundReachable: args.recentInboundReachable,
|
|
162
|
-
owner: args.owner,
|
|
163
|
-
event: runtime.pushEvent,
|
|
164
|
-
}),
|
|
165
|
-
);
|
|
166
|
-
runtime.recordOutboxPushSuccess(
|
|
167
|
-
buildTextPushSuccessArgs({
|
|
168
|
-
entry: args.entry,
|
|
169
|
-
connIds: args.connIds,
|
|
170
|
-
ownerConnId: args.ownerConnId,
|
|
171
|
-
ownerClientId: args.ownerConnId ? args.owner?.clientId : undefined,
|
|
172
|
-
}),
|
|
173
|
-
);
|
|
174
|
-
logOutboxPushOkSummary(args.entry.messageId);
|
|
175
|
-
logOutboxPushOk(
|
|
176
|
-
buildTextPushOkArgs({
|
|
177
|
-
entry: args.entry,
|
|
178
|
-
connIds: args.connIds,
|
|
179
|
-
recentInboundReachable: args.recentInboundReachable,
|
|
180
|
-
event: runtime.pushEvent,
|
|
181
|
-
}),
|
|
182
|
-
);
|
|
183
|
-
};
|
|
184
|
-
|
|
185
135
|
const handleTextPushFailure = (args: { entry: OutboxEntry; error: unknown }) => {
|
|
186
136
|
runtime.recordOutboxPushFailure({
|
|
187
137
|
entry: args.entry,
|
|
@@ -253,7 +203,6 @@ export function createBncrOutboxPush(runtime: BncrOutboxPushRuntime) {
|
|
|
253
203
|
};
|
|
254
204
|
|
|
255
205
|
return {
|
|
256
|
-
pushTextSuccessPath,
|
|
257
206
|
handleTextPushFailure,
|
|
258
207
|
handleFileTransferPushFailure,
|
|
259
208
|
handleFileTransferPushGuardFailure,
|