@xmoxmo/bncr 0.5.7 → 0.5.9

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.
Files changed (44) hide show
  1. package/package.json +1 -1
  2. package/scripts/check-pack.mjs +0 -2
  3. package/scripts/selfcheck.mjs +48 -13
  4. package/src/bootstrap/runtime-loader.ts +1 -1
  5. package/src/channel.ts +50 -138
  6. package/src/core/connection-reachability.ts +1 -1
  7. package/src/core/logging.ts +1 -1
  8. package/src/core/outbox-entry-builders.ts +60 -82
  9. package/src/core/outbox-summary.ts +5 -39
  10. package/src/core/permissions.ts +1 -1
  11. package/src/core/register-trace.ts +2 -2
  12. package/src/messaging/inbound/parse.ts +1 -1
  13. package/src/messaging/outbound/diagnostics-debug-builders.ts +0 -15
  14. package/src/messaging/outbound/diagnostics.ts +0 -1
  15. package/src/messaging/outbound/marker-parser.ts +234 -0
  16. package/src/messaging/outbound/media-dedupe.ts +1 -4
  17. package/src/messaging/outbound/normalize-outbound-send.ts +9 -7
  18. package/src/messaging/outbound/reply-enqueue-media.ts +1 -184
  19. package/src/messaging/outbound/reply-enqueue.ts +249 -162
  20. package/src/openclaw/media-runtime.ts +1 -1
  21. package/src/plugin/ack-outbox-runtime-group.ts +2 -0
  22. package/src/plugin/bridge-media-facade.ts +0 -3
  23. package/src/plugin/bridge-outbox-facade.ts +14 -2
  24. package/src/plugin/channel-runtime-builders-delivery.ts +2 -362
  25. package/src/plugin/channel-runtime-builders-status.ts +0 -160
  26. package/src/plugin/channel-runtime-builders.ts +3 -17
  27. package/src/plugin/channel-runtime-constants.ts +1 -1
  28. package/src/plugin/channel-send.ts +5 -4
  29. package/src/plugin/file-transfer-orchestrator.ts +39 -2
  30. package/src/plugin/media-orchestrators-runtime-group.ts +20 -149
  31. package/src/plugin/messaging.ts +3 -3
  32. package/src/plugin/outbox-drain-failure.ts +34 -1
  33. package/src/plugin/outbox-drain-runtime.ts +3 -0
  34. package/src/plugin/outbox-push.ts +1 -52
  35. package/src/plugin/outbox-unified-push-flow.ts +307 -0
  36. package/src/plugin/scene-registry.ts +1 -1
  37. package/src/runtime/log-dedupe.ts +3 -3
  38. package/src/runtime/outbound-ack-timeout.ts +2 -4
  39. package/src/runtime/status-snapshots.ts +2 -2
  40. package/src/runtime/status-worker.ts +2 -6
  41. package/src/core/outbox-text-push-prep.ts +0 -1
  42. package/src/plugin/bridge-file-transfer-push-facade.ts +0 -142
  43. package/src/plugin/outbox-file-push-flow.ts +0 -69
  44. package/src/plugin/outbox-text-push-flow.ts +0 -90
@@ -0,0 +1,307 @@
1
+ import {
2
+ buildFileTransferPushOkArgs,
3
+ buildFileTransferPushSuccessArgs,
4
+ } from '../core/outbox-file-transfer-bookkeeping.ts';
5
+ import { resolveFileTransferGuard } from '../core/outbox-file-transfer-guards.ts';
6
+ import {
7
+ prepareRouteSelection,
8
+ prepareRouteSelection as prepareTextPushRouteSelection,
9
+ } from '../core/outbox-file-transfer-prep.ts';
10
+ import {
11
+ buildFileTransferBroadcastPayload,
12
+ buildFileTransferRouteSelectArgs,
13
+ } from '../core/outbox-file-transfer-success.ts';
14
+ import { resolveTextPushGuard } from '../core/outbox-text-push-guards.ts';
15
+ import {
16
+ buildTextPushBroadcastPayload,
17
+ buildTextPushOkArgs,
18
+ buildTextPushRouteSelectArgs,
19
+ buildTextPushSuccessArgs,
20
+ } from '../core/outbox-text-push-success.ts';
21
+ import type { BncrConnection, BncrRoute, OutboxEntry } from '../core/types.ts';
22
+ import { isPlainObject } from '../core/value-sanitize.ts';
23
+ import {
24
+ selectOutboxFileTransferRouteCandidates,
25
+ selectOutboxRouteCandidates,
26
+ } from '../messaging/outbound/queue-selectors.ts';
27
+
28
+ type FileTransferGuardFailure = {
29
+ reason: 'media-url-missing' | 'no-gateway-context' | 'no-active-connection';
30
+ lastError: string;
31
+ recentInboundReachable?: boolean;
32
+ };
33
+
34
+ export type RunBncrOutboxPushArgs = {
35
+ entry: OutboxEntry;
36
+ gatewayContext: unknown;
37
+ owner: BncrConnection | null;
38
+ resolvePushConnIds: (accountId: string) => Set<string>;
39
+ resolveRecentInboundConnIds: (accountId: string) => Set<string>;
40
+ hasRecentInboundReachability: (accountId: string) => boolean;
41
+ isRevalidatedAttemptedConn: (connId: string) => boolean;
42
+ // Route + guard failure
43
+ recordOutboxPrePushFailure: (args: {
44
+ entry: OutboxEntry;
45
+ lastError: string;
46
+ persist?: boolean;
47
+ }) => void;
48
+ logOutboxPushSkip: (args: {
49
+ messageId: string;
50
+ accountId: string;
51
+ reason: string;
52
+ recentInboundReachable?: boolean;
53
+ routeReason?: string;
54
+ connIds?: Iterable<string>;
55
+ ownerConnId?: string;
56
+ ownerClientId?: string;
57
+ }) => void;
58
+ handleFileTransferPushGuardFailure: (args: {
59
+ entry: OutboxEntry;
60
+ guard: FileTransferGuardFailure & { ok: false };
61
+ }) => void;
62
+ // Broadcast + bookkeeping (unified)
63
+ pushEvent: string;
64
+ gatewayBroadcastToConnIds: (
65
+ event: string,
66
+ payload: unknown,
67
+ connIds: ReadonlySet<string>,
68
+ ) => void;
69
+ recordOutboxPushSuccess: (args: {
70
+ entry: OutboxEntry;
71
+ connIds: Iterable<string>;
72
+ ownerConnId?: string;
73
+ ownerClientId?: string;
74
+ }) => void;
75
+ logOutboxRouteSelect: (args: {
76
+ messageId: string;
77
+ accountId: string;
78
+ kind?: 'file-transfer';
79
+ routeReason: string;
80
+ connIds: Iterable<string>;
81
+ ownerConnId: string;
82
+ ownerClientId: string;
83
+ recentInboundReachable: boolean;
84
+ event: string;
85
+ }) => void;
86
+ logOutboxPushOkSummary: (messageId: string) => void;
87
+ logOutboundSummary: (entry: OutboxEntry) => void;
88
+ logOutboxPushOk: (args: {
89
+ messageId: string;
90
+ accountId: string;
91
+ kind?: 'file-transfer';
92
+ connIds: Iterable<string>;
93
+ ownerConnId: string;
94
+ ownerClientId: string;
95
+ recentInboundReachable: boolean;
96
+ event: string;
97
+ }) => void;
98
+ // Failure handlers
99
+ handleTextPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
100
+ handleFileTransferPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
101
+ // Media-specific (optional)
102
+ transferMediaToBncrClient?: (params: {
103
+ accountId: string;
104
+ sessionKey: string;
105
+ route: BncrRoute;
106
+ mediaUrl: string;
107
+ mediaLocalRoots?: readonly string[];
108
+ downloadMedia?: boolean;
109
+ }) => Promise<{
110
+ mode: 'base64' | 'chunk';
111
+ mimeType?: string;
112
+ fileName?: string;
113
+ base64?: string;
114
+ path?: string;
115
+ }>;
116
+ buildFileTransferOutboundFrame?: (params: {
117
+ entry: OutboxEntry;
118
+ msg: Record<string, unknown>;
119
+ media: { fileName?: string; mimeType?: string; path?: string; base64?: string; type?: string };
120
+ mediaUrl: string;
121
+ }) => Record<string, unknown>;
122
+ };
123
+
124
+ export async function runBncrOutboxPush(args: RunBncrOutboxPushArgs): Promise<boolean> {
125
+ const entry = args.entry;
126
+ const msg =
127
+ isPlainObject(entry.payload) &&
128
+ isPlainObject((entry.payload as Record<string, unknown>).message)
129
+ ? ((entry.payload as Record<string, unknown>).message as Record<string, unknown>)
130
+ : null;
131
+ const transferMode = msg?.transferMode === 'media' ? 'media' : 'text';
132
+
133
+ // Route selection
134
+ const selection =
135
+ transferMode === 'media'
136
+ ? prepareRouteSelection({
137
+ entry,
138
+ owner: args.owner,
139
+ resolvePushConnIds: args.resolvePushConnIds,
140
+ resolveRecentInboundConnIds: args.resolveRecentInboundConnIds,
141
+ hasRecentInboundReachability: args.hasRecentInboundReachability,
142
+ isRevalidatedAttemptedConn: args.isRevalidatedAttemptedConn,
143
+ selectRouteCandidates: selectOutboxFileTransferRouteCandidates,
144
+ })
145
+ : prepareTextPushRouteSelection({
146
+ entry,
147
+ owner: args.owner,
148
+ resolvePushConnIds: args.resolvePushConnIds,
149
+ resolveRecentInboundConnIds: args.resolveRecentInboundConnIds,
150
+ hasRecentInboundReachability: args.hasRecentInboundReachability,
151
+ isRevalidatedAttemptedConn: args.isRevalidatedAttemptedConn,
152
+ selectRouteCandidates: selectOutboxRouteCandidates,
153
+ });
154
+
155
+ // Guard + dispatch
156
+ if (transferMode === 'media') {
157
+ const guard = resolveFileTransferGuard({
158
+ gatewayContext: args.gatewayContext,
159
+ entry,
160
+ owner: args.owner,
161
+ routeSelection: selection,
162
+ mediaUrl: String(msg!.mediaUrl || '').trim(),
163
+ });
164
+ if (!guard.ok) {
165
+ args.handleFileTransferPushGuardFailure({
166
+ entry,
167
+ guard: guard as FileTransferGuardFailure & { ok: false },
168
+ });
169
+ return false;
170
+ }
171
+
172
+ // ── Media success path (inline) ──
173
+ try {
174
+ const media = await args.transferMediaToBncrClient!({
175
+ accountId: entry.accountId,
176
+ sessionKey: entry.sessionKey,
177
+ route: entry.route,
178
+ mediaUrl: guard.mediaUrl,
179
+ mediaLocalRoots: Array.isArray(msg!.mediaLocalRoots)
180
+ ? (msg!.mediaLocalRoots as readonly string[])
181
+ : undefined,
182
+ downloadMedia: msg!.downloadMedia as boolean | undefined,
183
+ });
184
+ const frame = args.buildFileTransferOutboundFrame!({
185
+ entry,
186
+ msg: msg!,
187
+ media,
188
+ mediaUrl: guard.mediaUrl,
189
+ });
190
+
191
+ args.gatewayBroadcastToConnIds(
192
+ args.pushEvent,
193
+ buildFileTransferBroadcastPayload({ frame, messageId: entry.messageId }),
194
+ new Set(guard.connIds),
195
+ );
196
+ args.logOutboxRouteSelect(
197
+ buildFileTransferRouteSelectArgs({
198
+ entry,
199
+ connIds: guard.connIds,
200
+ routeReason: guard.routeReason,
201
+ recentInboundReachable: guard.recentInboundReachable,
202
+ owner: args.owner,
203
+ event: args.pushEvent,
204
+ }),
205
+ );
206
+ args.recordOutboxPushSuccess(
207
+ buildFileTransferPushSuccessArgs({
208
+ entry,
209
+ connIds: guard.connIds,
210
+ owner: args.owner,
211
+ }),
212
+ );
213
+ args.logOutboxPushOkSummary(entry.messageId);
214
+ // Sync entry type from the resolved frame
215
+ const frameMsg = frame?.message as Record<string, unknown> | undefined;
216
+ if (frameMsg?.type !== undefined) {
217
+ (msg! as Record<string, unknown>).type = frameMsg.type;
218
+ }
219
+ args.logOutboundSummary(entry);
220
+ args.logOutboxPushOk(
221
+ buildFileTransferPushOkArgs({
222
+ entry,
223
+ connIds: guard.connIds,
224
+ recentInboundReachable: guard.recentInboundReachable,
225
+ event: args.pushEvent,
226
+ }),
227
+ );
228
+ return true;
229
+ } catch (error) {
230
+ args.handleFileTransferPushFailure({ entry, error });
231
+ return false;
232
+ }
233
+ }
234
+
235
+ // ── Text ──
236
+ const textGuard = resolveTextPushGuard({
237
+ gatewayContext: args.gatewayContext,
238
+ entry,
239
+ routeSelection: selection,
240
+ });
241
+ if (!textGuard.ok) {
242
+ args.recordOutboxPrePushFailure({
243
+ entry,
244
+ lastError:
245
+ textGuard.reason === 'no-gateway-context'
246
+ ? 'gateway context unavailable'
247
+ : 'no active bncr client',
248
+ persist: true,
249
+ });
250
+ args.logOutboxPushSkip({
251
+ messageId: entry.messageId,
252
+ accountId: entry.accountId,
253
+ reason: textGuard.reason,
254
+ recentInboundReachable:
255
+ textGuard.reason === 'no-active-connection' ? textGuard.recentInboundReachable : undefined,
256
+ routeReason: selection.routeReason,
257
+ connIds: selection.connIds,
258
+ ownerConnId: selection.ownerConnId,
259
+ ownerClientId: args.owner?.clientId,
260
+ });
261
+ return false;
262
+ }
263
+
264
+ // ── Text success path (inline) ──
265
+ try {
266
+ args.gatewayBroadcastToConnIds(
267
+ args.pushEvent,
268
+ buildTextPushBroadcastPayload({
269
+ payload: entry.payload,
270
+ messageId: entry.messageId,
271
+ }),
272
+ new Set(textGuard.connIds),
273
+ );
274
+ args.logOutboxRouteSelect(
275
+ buildTextPushRouteSelectArgs({
276
+ entry,
277
+ connIds: textGuard.connIds,
278
+ routeReason: textGuard.routeReason,
279
+ recentInboundReachable: textGuard.recentInboundReachable,
280
+ owner: args.owner,
281
+ event: args.pushEvent,
282
+ }),
283
+ );
284
+ args.recordOutboxPushSuccess(
285
+ buildTextPushSuccessArgs({
286
+ entry,
287
+ connIds: textGuard.connIds,
288
+ ownerConnId: textGuard.ownerConnId,
289
+ ownerClientId: textGuard.ownerConnId ? args.owner?.clientId : undefined,
290
+ }),
291
+ );
292
+ args.logOutboxPushOkSummary(entry.messageId);
293
+ args.logOutboundSummary(entry);
294
+ args.logOutboxPushOk(
295
+ buildTextPushOkArgs({
296
+ entry,
297
+ connIds: textGuard.connIds,
298
+ recentInboundReachable: textGuard.recentInboundReachable,
299
+ event: args.pushEvent,
300
+ }),
301
+ );
302
+ return true;
303
+ } catch (error) {
304
+ args.handleTextPushFailure({ entry, error });
305
+ return false;
306
+ }
307
+ }
@@ -36,7 +36,7 @@ export function buildSceneKey(parsed: ParsedInbound): string {
36
36
  : `${parsed.platform}:${parsed.userId}`;
37
37
  }
38
38
 
39
- export function buildSceneRecord(args: {
39
+ function buildSceneRecord(args: {
40
40
  parsed: ParsedInbound;
41
41
  sceneKey: string;
42
42
  kind: BncrSceneKind;
@@ -5,10 +5,10 @@ export type LogDedupeStateEntry = {
5
5
 
6
6
  export type LogDedupeState = Map<string, LogDedupeStateEntry>;
7
7
 
8
- export const LOG_DEDUPE_STATE_TTL_MS = 10 * 60 * 1000;
9
- export const LOG_DEDUPE_STATE_MAX_ENTRIES = 1_000;
8
+ const LOG_DEDUPE_STATE_TTL_MS = 10 * 60 * 1000;
9
+ const LOG_DEDUPE_STATE_MAX_ENTRIES = 1_000;
10
10
 
11
- export function pruneLogDedupeState(
11
+ function pruneLogDedupeState(
12
12
  state: LogDedupeState,
13
13
  currentTime: number,
14
14
  options?: {
@@ -42,9 +42,7 @@ function isAdaptiveAckRecovered(args: {
42
42
  );
43
43
  }
44
44
 
45
- export function computeBncrRecommendedAckTimeoutReason(
46
- args: ComputeBncrRecommendedAckTimeoutReasonArgs,
47
- ) {
45
+ function computeBncrRecommendedAckTimeoutReason(args: ComputeBncrRecommendedAckTimeoutReasonArgs) {
48
46
  if (args.recentAckTimeoutCount <= 0) return 'no-timeout-evidence';
49
47
  if (args.lateAckOkCount <= 0) return 'no-late-ack-evidence';
50
48
  if (typeof args.lastLateAckPushLatencyMs !== 'number') return 'missing-latency';
@@ -54,7 +52,7 @@ export function computeBncrRecommendedAckTimeoutReason(
54
52
  return 'late-ack-observed';
55
53
  }
56
54
 
57
- export function computeBncrRecommendedAckTimeoutMs(args: ComputeBncrRecommendedAckTimeoutArgs) {
55
+ function computeBncrRecommendedAckTimeoutMs(args: ComputeBncrRecommendedAckTimeoutArgs) {
58
56
  if (
59
57
  args.lateAckOkCount <= 0 ||
60
58
  args.recentAckTimeoutCount <= 0 ||
@@ -34,7 +34,7 @@ function getCounter(map: Map<string, number>, accountId: string): number {
34
34
  return map.get(normalizeAccountId(accountId)) || 0;
35
35
  }
36
36
 
37
- export function buildRuntimeQueueSnapshot(args: {
37
+ function buildRuntimeQueueSnapshot(args: {
38
38
  accountId: string;
39
39
  outboxEntries: Iterable<OutboxEntry>;
40
40
  deadLetterEntries: Iterable<OutboxEntry>;
@@ -59,7 +59,7 @@ export function buildRuntimeQueueSnapshot(args: {
59
59
  };
60
60
  }
61
61
 
62
- export function buildRuntimeEventCounters(args: {
62
+ function buildRuntimeEventCounters(args: {
63
63
  accountId: string;
64
64
  connectEventsByAccount: Map<string, number>;
65
65
  inboundEventsByAccount: Map<string, number>;
@@ -49,7 +49,7 @@ export type ChannelAccountWorkerHandle = {
49
49
  healthLogState?: HealthStatusLogState;
50
50
  };
51
51
 
52
- export const HEALTH_STATUS_STABLE_WINDOW_MS = 10_000;
52
+ const HEALTH_STATUS_STABLE_WINDOW_MS = 10_000;
53
53
 
54
54
  export type HealthStatusLogState = {
55
55
  emittedSig: string | null;
@@ -112,11 +112,7 @@ type StatusWorkerRuntime = {
112
112
  hooks: StatusWorkerHooks;
113
113
  };
114
114
 
115
- export function clearBncrStatusWorker(
116
- runtime: StatusWorkerRuntime,
117
- accountId: string,
118
- reason: string,
119
- ) {
115
+ function clearBncrStatusWorker(runtime: StatusWorkerRuntime, accountId: string, reason: string) {
120
116
  const worker = runtime.workers.get(accountId);
121
117
  if (!worker) return false;
122
118
  worker.finish(reason);
@@ -1 +0,0 @@
1
- export { prepareRouteSelection as prepareTextPushRouteSelection } from './outbox-file-transfer-prep.ts';
@@ -1,142 +0,0 @@
1
- import {
2
- buildFileTransferPushOkArgs,
3
- buildFileTransferPushSuccessArgs,
4
- } from '../core/outbox-file-transfer-bookkeeping.ts';
5
- import {
6
- buildFileTransferBroadcastPayload,
7
- buildFileTransferRouteSelectArgs,
8
- } from '../core/outbox-file-transfer-success.ts';
9
- import type { BncrConnection, BncrRoute, OutboxEntry } from '../core/types.ts';
10
-
11
- export function createBncrBridgeFileTransferPushFacade(runtime: {
12
- pushEvent: string;
13
- getGatewayContext: () => {
14
- broadcastToConnIds: (event: string, payload: unknown, connIds: ReadonlySet<string>) => void;
15
- } | null;
16
- transferMediaToBncrClient: (params: {
17
- accountId: string;
18
- sessionKey: string;
19
- route: BncrRoute;
20
- mediaUrl: string;
21
- mediaLocalRoots?: readonly string[];
22
- downloadMedia?: boolean;
23
- }) => Promise<{
24
- mode: 'base64' | 'chunk';
25
- mimeType?: string;
26
- fileName?: string;
27
- base64?: string;
28
- path?: string;
29
- }>;
30
- buildFileTransferOutboundFrame: (params: {
31
- entry: OutboxEntry;
32
- msg: Record<string, unknown>;
33
- media: { fileName?: string; mimeType?: string; path?: string; base64?: string; type?: string };
34
- mediaUrl: string;
35
- }) => Record<string, unknown>;
36
- logOutboxRouteSelect: (args: {
37
- messageId: string;
38
- accountId: string;
39
- kind?: 'file-transfer';
40
- routeReason: string;
41
- connIds: Iterable<string>;
42
- ownerConnId: string;
43
- ownerClientId: string;
44
- recentInboundReachable: boolean;
45
- event: string;
46
- }) => void;
47
- recordOutboxPushSuccess: (args: {
48
- entry: OutboxEntry;
49
- connIds: Iterable<string>;
50
- ownerConnId?: string;
51
- ownerClientId?: string;
52
- clearLastError?: boolean;
53
- }) => void;
54
- logOutboxPushOkSummary: (messageId: string) => void;
55
- logOutboxPushOk: (args: {
56
- messageId: string;
57
- accountId: string;
58
- kind?: 'file-transfer';
59
- connIds: Iterable<string>;
60
- ownerConnId: string;
61
- ownerClientId: string;
62
- recentInboundReachable: boolean;
63
- event: string;
64
- }) => void;
65
- handleFileTransferPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
66
- handleFileTransferPushGuardFailure: (args: {
67
- entry: OutboxEntry;
68
- guard: {
69
- reason: 'media-url-missing' | 'no-gateway-context' | 'no-active-connection';
70
- lastError: string;
71
- recentInboundReachable?: boolean;
72
- };
73
- }) => void;
74
- }) {
75
- const pushFileTransferSuccessPath = async (args: {
76
- entry: OutboxEntry;
77
- msg: Record<string, unknown>;
78
- owner: BncrConnection | null;
79
- connIds: Iterable<string>;
80
- recentInboundReachable: boolean;
81
- routeReason: string;
82
- mediaUrl: string;
83
- }): Promise<void> => {
84
- const media = await runtime.transferMediaToBncrClient({
85
- accountId: args.entry.accountId,
86
- sessionKey: args.entry.sessionKey,
87
- route: args.entry.route,
88
- mediaUrl: args.mediaUrl,
89
- mediaLocalRoots: Array.isArray(args.msg.mediaLocalRoots)
90
- ? args.msg.mediaLocalRoots.filter((v): v is string => typeof v === 'string')
91
- : undefined,
92
- downloadMedia: args.msg.downloadMedia as boolean | undefined,
93
- });
94
- const frame = runtime.buildFileTransferOutboundFrame({
95
- entry: args.entry,
96
- msg: args.msg,
97
- media,
98
- mediaUrl: args.mediaUrl,
99
- });
100
-
101
- runtime.getGatewayContext()!.broadcastToConnIds(
102
- runtime.pushEvent,
103
- buildFileTransferBroadcastPayload({
104
- frame,
105
- messageId: args.entry.messageId,
106
- }),
107
- new Set(args.connIds),
108
- );
109
- runtime.logOutboxRouteSelect(
110
- buildFileTransferRouteSelectArgs({
111
- entry: args.entry,
112
- connIds: args.connIds,
113
- routeReason: args.routeReason,
114
- recentInboundReachable: args.recentInboundReachable,
115
- owner: args.owner,
116
- event: runtime.pushEvent,
117
- }),
118
- );
119
- runtime.recordOutboxPushSuccess(
120
- buildFileTransferPushSuccessArgs({
121
- entry: args.entry,
122
- connIds: args.connIds,
123
- owner: args.owner,
124
- }),
125
- );
126
- runtime.logOutboxPushOkSummary(args.entry.messageId);
127
- runtime.logOutboxPushOk(
128
- buildFileTransferPushOkArgs({
129
- entry: args.entry,
130
- connIds: args.connIds,
131
- recentInboundReachable: args.recentInboundReachable,
132
- event: runtime.pushEvent,
133
- }),
134
- );
135
- };
136
-
137
- return {
138
- pushFileTransferSuccessPath,
139
- handleFileTransferPushFailure: runtime.handleFileTransferPushFailure,
140
- handleFileTransferPushGuardFailure: runtime.handleFileTransferPushGuardFailure,
141
- };
142
- }
@@ -1,69 +0,0 @@
1
- import { resolveFileTransferGuard } from '../core/outbox-file-transfer-guards.ts';
2
- import { prepareRouteSelection } from '../core/outbox-file-transfer-prep.ts';
3
- import type { BncrConnection, OutboxEntry } from '../core/types.ts';
4
- import { selectOutboxFileTransferRouteCandidates } from '../messaging/outbound/queue-selectors.ts';
5
-
6
- export async function runBncrFileTransferOutboxPush(args: {
7
- entry: OutboxEntry;
8
- msg: Record<string, unknown>;
9
- gatewayContext: unknown;
10
- owner: BncrConnection | null;
11
- resolvePushConnIds: (accountId: string) => Set<string>;
12
- resolveRecentInboundConnIds: (accountId: string) => Set<string>;
13
- hasRecentInboundReachability: (accountId: string) => boolean;
14
- isRevalidatedAttemptedConn: (connId: string) => boolean;
15
- handleFileTransferPushGuardFailure: (args: {
16
- entry: OutboxEntry;
17
- guard: Exclude<ReturnType<typeof resolveFileTransferGuard>, { ok: true }>;
18
- }) => void;
19
- pushFileTransferSuccessPath: (args: {
20
- entry: OutboxEntry;
21
- msg: Record<string, unknown>;
22
- owner: BncrConnection | null;
23
- connIds: Iterable<string>;
24
- recentInboundReachable: boolean;
25
- routeReason: string;
26
- mediaUrl: string;
27
- }) => Promise<void>;
28
- handleFileTransferPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
29
- }) {
30
- const selection = prepareRouteSelection({
31
- entry: args.entry,
32
- owner: args.owner,
33
- resolvePushConnIds: args.resolvePushConnIds,
34
- resolveRecentInboundConnIds: args.resolveRecentInboundConnIds,
35
- hasRecentInboundReachability: args.hasRecentInboundReachability,
36
- isRevalidatedAttemptedConn: args.isRevalidatedAttemptedConn,
37
- selectRouteCandidates: selectOutboxFileTransferRouteCandidates,
38
- });
39
- const guard = resolveFileTransferGuard({
40
- gatewayContext: args.gatewayContext,
41
- entry: args.entry,
42
- owner: args.owner,
43
- routeSelection: selection,
44
- mediaUrl: String(args.msg.mediaUrl || '').trim(),
45
- });
46
- if (!guard.ok) {
47
- args.handleFileTransferPushGuardFailure({
48
- entry: args.entry,
49
- guard,
50
- });
51
- return false;
52
- }
53
-
54
- try {
55
- await args.pushFileTransferSuccessPath({
56
- entry: args.entry,
57
- msg: args.msg,
58
- owner: args.owner,
59
- connIds: guard.connIds,
60
- recentInboundReachable: guard.recentInboundReachable,
61
- routeReason: guard.routeReason,
62
- mediaUrl: guard.mediaUrl,
63
- });
64
- return true;
65
- } catch (error) {
66
- args.handleFileTransferPushFailure({ entry: args.entry, error });
67
- return false;
68
- }
69
- }
@@ -1,90 +0,0 @@
1
- import { resolveTextPushGuard } from '../core/outbox-text-push-guards.ts';
2
- import { prepareTextPushRouteSelection } from '../core/outbox-text-push-prep.ts';
3
- import type { BncrConnection, OutboxEntry } from '../core/types.ts';
4
- import { selectOutboxRouteCandidates } from '../messaging/outbound/queue-selectors.ts';
5
-
6
- export async function runBncrTextOutboxPush(args: {
7
- entry: OutboxEntry;
8
- gatewayContext: unknown;
9
- owner: BncrConnection | null;
10
- resolvePushConnIds: (accountId: string) => Set<string>;
11
- resolveRecentInboundConnIds: (accountId: string) => Set<string>;
12
- hasRecentInboundReachability: (accountId: string) => boolean;
13
- isRevalidatedAttemptedConn: (connId: string) => boolean;
14
- recordOutboxPrePushFailure: (args: {
15
- entry: OutboxEntry;
16
- lastError: string;
17
- persist?: boolean;
18
- }) => void;
19
- logOutboxPushSkip: (args: {
20
- messageId: string;
21
- accountId: string;
22
- reason: string;
23
- recentInboundReachable?: boolean;
24
- routeReason?: string;
25
- connIds?: Iterable<string>;
26
- ownerConnId?: string;
27
- ownerClientId?: string;
28
- }) => void;
29
- pushTextSuccessPath: (args: {
30
- entry: OutboxEntry;
31
- owner: BncrConnection | null;
32
- connIds: Iterable<string>;
33
- recentInboundReachable: boolean;
34
- routeReason: string;
35
- ownerConnId?: string;
36
- }) => void;
37
- handleTextPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
38
- }) {
39
- const selection = prepareTextPushRouteSelection({
40
- entry: args.entry,
41
- owner: args.owner,
42
- resolvePushConnIds: args.resolvePushConnIds,
43
- resolveRecentInboundConnIds: args.resolveRecentInboundConnIds,
44
- hasRecentInboundReachability: args.hasRecentInboundReachability,
45
- isRevalidatedAttemptedConn: args.isRevalidatedAttemptedConn,
46
- selectRouteCandidates: selectOutboxRouteCandidates,
47
- });
48
- const guard = resolveTextPushGuard({
49
- gatewayContext: args.gatewayContext,
50
- entry: args.entry,
51
- routeSelection: selection,
52
- });
53
- if (!guard.ok) {
54
- args.recordOutboxPrePushFailure({
55
- entry: args.entry,
56
- lastError:
57
- guard.reason === 'no-gateway-context'
58
- ? 'gateway context unavailable'
59
- : 'no active bncr client',
60
- persist: true,
61
- });
62
- args.logOutboxPushSkip({
63
- messageId: args.entry.messageId,
64
- accountId: args.entry.accountId,
65
- reason: guard.reason,
66
- recentInboundReachable:
67
- guard.reason === 'no-active-connection' ? guard.recentInboundReachable : undefined,
68
- routeReason: selection.routeReason,
69
- connIds: selection.connIds,
70
- ownerConnId: selection.ownerConnId,
71
- ownerClientId: args.owner?.clientId,
72
- });
73
- return false;
74
- }
75
-
76
- try {
77
- args.pushTextSuccessPath({
78
- entry: args.entry,
79
- owner: args.owner,
80
- connIds: guard.connIds,
81
- recentInboundReachable: guard.recentInboundReachable,
82
- routeReason: guard.routeReason,
83
- ownerConnId: guard.ownerConnId,
84
- });
85
- return true;
86
- } catch (error) {
87
- args.handleTextPushFailure({ entry: args.entry, error });
88
- return false;
89
- }
90
- }