@xmoxmo/bncr 0.3.5 → 0.3.7

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 (164) hide show
  1. package/README.md +5 -0
  2. package/dist/index.js +28 -5
  3. package/index.ts +55 -721
  4. package/package.json +8 -4
  5. package/scripts/check-pack.mjs +93 -18
  6. package/scripts/check-register-drift.mjs +35 -13
  7. package/scripts/selfcheck.mjs +80 -11
  8. package/src/bootstrap/channel-plugin-runtime.ts +81 -0
  9. package/src/bootstrap/cli.ts +97 -0
  10. package/src/bootstrap/register-runtime-gateway.ts +129 -0
  11. package/src/bootstrap/register-runtime-helpers.ts +140 -0
  12. package/src/bootstrap/register-runtime-singleton.ts +137 -0
  13. package/src/bootstrap/register-runtime.ts +201 -0
  14. package/src/bootstrap/runtime-discovery.ts +187 -0
  15. package/src/bootstrap/runtime-loader.ts +54 -0
  16. package/src/channel.ts +1590 -4967
  17. package/src/core/accounts.ts +23 -4
  18. package/src/core/dead-letter-diagnostics.ts +37 -5
  19. package/src/core/diagnostics.ts +31 -15
  20. package/src/core/downlink-health.ts +3 -11
  21. package/src/core/extended-diagnostics.ts +78 -36
  22. package/src/core/file-transfer-payloads.ts +1 -1
  23. package/src/core/logging.ts +1 -0
  24. package/src/core/outbox-enqueue.ts +13 -2
  25. package/src/core/outbox-entry-builders.ts +2 -0
  26. package/src/core/outbox-summary.ts +75 -3
  27. package/src/core/permissions.ts +15 -2
  28. package/src/core/persisted-outbox-entry.ts +21 -6
  29. package/src/core/policy.ts +45 -4
  30. package/src/core/probe.ts +3 -15
  31. package/src/core/register-trace.ts +3 -3
  32. package/src/core/status.ts +43 -4
  33. package/src/core/targets.ts +216 -205
  34. package/src/core/types.ts +221 -0
  35. package/src/core/value-sanitize.ts +29 -0
  36. package/src/messaging/inbound/commands.ts +147 -172
  37. package/src/messaging/inbound/context-facts.ts +4 -2
  38. package/src/messaging/inbound/contracts.ts +70 -0
  39. package/src/messaging/inbound/dispatch-prep.ts +303 -0
  40. package/src/messaging/inbound/dispatch.ts +49 -462
  41. package/src/messaging/inbound/gate.ts +18 -5
  42. package/src/messaging/inbound/last-route.ts +10 -4
  43. package/src/messaging/inbound/media-url-download.ts +109 -0
  44. package/src/messaging/inbound/native-command-runtime.ts +225 -0
  45. package/src/messaging/inbound/parse.ts +2 -1
  46. package/src/messaging/inbound/remote-media.ts +49 -0
  47. package/src/messaging/inbound/reply-config.ts +16 -4
  48. package/src/messaging/inbound/reply-dispatch.ts +162 -0
  49. package/src/messaging/inbound/runtime-compat.ts +31 -10
  50. package/src/messaging/inbound/session-label.ts +15 -7
  51. package/src/messaging/inbound/turn-context.ts +131 -0
  52. package/src/messaging/outbound/actions.ts +24 -10
  53. package/src/messaging/outbound/diagnostics-debug-builders.ts +365 -0
  54. package/src/messaging/outbound/diagnostics.ts +31 -355
  55. package/src/messaging/outbound/durable-message-adapter.ts +20 -16
  56. package/src/messaging/outbound/durable-queue-adapter.ts +20 -7
  57. package/src/messaging/outbound/media.ts +24 -13
  58. package/src/messaging/outbound/reply-enqueue-media.ts +181 -0
  59. package/src/messaging/outbound/reply-enqueue.ts +57 -134
  60. package/src/messaging/outbound/send-params.ts +3 -0
  61. package/src/messaging/outbound/send.ts +19 -10
  62. package/src/messaging/outbound/session-route.ts +18 -3
  63. package/src/openclaw/channel-runtime-contracts.ts +76 -0
  64. package/src/openclaw/config-runtime.ts +13 -7
  65. package/src/openclaw/inbound-session-runtime.ts +7 -3
  66. package/src/openclaw/ingress-runtime.ts +17 -27
  67. package/src/openclaw/reply-runtime.ts +54 -59
  68. package/src/openclaw/routing-runtime.ts +35 -18
  69. package/src/openclaw/runtime-surface.ts +156 -12
  70. package/src/openclaw/sdk-helpers.ts +8 -1
  71. package/src/openclaw/session-route-runtime.ts +12 -12
  72. package/src/plugin/ack-outbox-runtime-group.ts +264 -0
  73. package/src/plugin/bridge-ack-facade.ts +137 -0
  74. package/src/plugin/bridge-connection-facade.ts +111 -0
  75. package/src/plugin/bridge-diagnostics-facade.ts +23 -0
  76. package/src/plugin/bridge-drain-facade.ts +98 -0
  77. package/src/plugin/bridge-extended-diagnostics-facade.ts +149 -0
  78. package/src/plugin/bridge-file-transfer-push-facade.ts +140 -0
  79. package/src/plugin/bridge-lifecycle.ts +156 -0
  80. package/src/plugin/bridge-media-facade.ts +241 -0
  81. package/src/plugin/bridge-outbox-facade.ts +182 -0
  82. package/src/plugin/bridge-runtime-helpers.ts +266 -0
  83. package/src/plugin/bridge-runtime-snapshots.ts +104 -0
  84. package/src/plugin/bridge-runtime-surface-facade.ts +8 -0
  85. package/src/plugin/bridge-status-facade.ts +76 -0
  86. package/src/plugin/bridge-status-worker-facade.ts +72 -0
  87. package/src/plugin/bridge-support-runtime.ts +137 -0
  88. package/src/plugin/bridge-surface-handlers-group.ts +242 -0
  89. package/src/plugin/bridge-surface-helpers.ts +28 -0
  90. package/src/plugin/capabilities.ts +1 -3
  91. package/src/plugin/channel-components.ts +289 -0
  92. package/src/plugin/channel-inbound-helpers.ts +149 -0
  93. package/src/plugin/channel-plugin-bridge-group.ts +129 -0
  94. package/src/plugin/channel-plugin-surface-group.ts +202 -0
  95. package/src/plugin/channel-runtime-builders-delivery.ts +513 -0
  96. package/src/plugin/channel-runtime-builders-status.ts +331 -0
  97. package/src/plugin/channel-runtime-builders.ts +25 -0
  98. package/src/plugin/channel-runtime-constants.ts +40 -0
  99. package/src/plugin/channel-runtime-types.ts +146 -0
  100. package/src/plugin/channel-send-runtime-group.ts +37 -0
  101. package/src/plugin/channel-send.ts +226 -0
  102. package/src/plugin/channel-utils.ts +102 -0
  103. package/src/plugin/config.ts +24 -3
  104. package/src/plugin/connection-handlers-helpers.ts +254 -0
  105. package/src/plugin/connection-handlers.ts +440 -0
  106. package/src/plugin/connection-state-helpers.ts +159 -0
  107. package/src/plugin/connection-state-runtime-group.ts +51 -0
  108. package/src/plugin/connection-state.ts +527 -0
  109. package/src/plugin/diagnostics-handlers.ts +211 -0
  110. package/src/plugin/error-message.ts +15 -0
  111. package/src/plugin/file-ack-runtime.ts +284 -0
  112. package/src/plugin/file-inbound-abort.ts +112 -0
  113. package/src/plugin/file-inbound-chunk.ts +146 -0
  114. package/src/plugin/file-inbound-complete.ts +153 -0
  115. package/src/plugin/file-inbound-handlers.ts +19 -0
  116. package/src/plugin/file-inbound-init.ts +122 -0
  117. package/src/plugin/file-inbound-runtime.ts +51 -0
  118. package/src/plugin/file-inbound-state.ts +62 -0
  119. package/src/plugin/file-transfer-logs.ts +227 -0
  120. package/src/plugin/file-transfer-orchestrator-chunk.ts +135 -0
  121. package/src/plugin/file-transfer-orchestrator.ts +304 -0
  122. package/src/plugin/file-transfer-runtime-group.ts +102 -0
  123. package/src/plugin/file-transfer-send.ts +89 -0
  124. package/src/plugin/file-transfer-setup.ts +206 -0
  125. package/src/plugin/gateway-event-context.ts +41 -0
  126. package/src/plugin/gateway-runtime.ts +14 -4
  127. package/src/plugin/inbound-acceptance.ts +107 -0
  128. package/src/plugin/inbound-handlers.ts +248 -0
  129. package/src/plugin/inbound-surface-handlers-group.ts +152 -0
  130. package/src/plugin/media-dedupe-runtime.ts +90 -0
  131. package/src/plugin/media-orchestrators-runtime-group.ts +316 -0
  132. package/src/plugin/message-ack-runtime.ts +284 -0
  133. package/src/plugin/message-send.ts +16 -6
  134. package/src/plugin/messaging.ts +98 -36
  135. package/src/plugin/outbound.ts +50 -8
  136. package/src/plugin/outbox-ack-logs.ts +136 -0
  137. package/src/plugin/outbox-ack-outcome.ts +128 -0
  138. package/src/plugin/outbox-drain-ack.ts +145 -0
  139. package/src/plugin/outbox-drain-failure.ts +84 -0
  140. package/src/plugin/outbox-drain-loop.ts +554 -0
  141. package/src/plugin/outbox-drain-post-push.ts +159 -0
  142. package/src/plugin/outbox-drain-runtime.ts +141 -0
  143. package/src/plugin/outbox-drain-schedule.ts +116 -0
  144. package/src/plugin/outbox-file-push-flow.ts +69 -0
  145. package/src/plugin/outbox-push-route-runtime-group.ts +81 -0
  146. package/src/plugin/outbox-push.ts +267 -0
  147. package/src/plugin/outbox-route.ts +181 -0
  148. package/src/plugin/outbox-text-push-flow.ts +90 -0
  149. package/src/plugin/runtime-diagnostics-assembler.ts +183 -0
  150. package/src/plugin/runtime-diagnostics-helpers.ts +302 -0
  151. package/src/plugin/runtime-diagnostics-payload-builders.ts +171 -0
  152. package/src/plugin/runtime-diagnostics-snapshot.ts +31 -0
  153. package/src/plugin/setup.ts +33 -6
  154. package/src/plugin/state-store.ts +249 -0
  155. package/src/plugin/state-transient-runtime-group.ts +105 -0
  156. package/src/plugin/status-runtime.ts +251 -0
  157. package/src/plugin/status.ts +33 -7
  158. package/src/plugin/target-runtime.ts +141 -0
  159. package/src/plugin/target-status-runtime-group.ts +130 -0
  160. package/src/plugin/transient-state-runtime.ts +82 -0
  161. package/src/runtime/outbound-ack-timeout.ts +5 -3
  162. package/src/runtime/outbound-flags.ts +24 -8
  163. package/src/runtime/status-snapshots.ts +36 -7
  164. package/src/runtime/status-worker.ts +34 -4
@@ -0,0 +1,513 @@
1
+ import type { GatewayRequestHandlerOptions } from 'openclaw/plugin-sdk/core';
2
+ import type { RegisterDriftSnapshot } from '../core/register-trace.ts';
3
+ import type { normalizeStoredSessionKey as normalizeStoredSessionKeyFromRuntime } from '../core/targets.ts';
4
+ import type {
5
+ BncrConnection,
6
+ BncrRoute,
7
+ FileSendTransferState,
8
+ OutboxEntry,
9
+ } from '../core/types.ts';
10
+ import type { parseBncrInboundParams } from '../messaging/inbound/parse.ts';
11
+ import type {
12
+ NormalizedReplyPayload,
13
+ ReplyPayloadInput,
14
+ } from '../messaging/outbound/reply-enqueue.ts';
15
+ import type { OutboundReplyTargetPolicy } from '../messaging/outbound/reply-target-policy.ts';
16
+ import type { createBncrInboundHandlersComponent } from './channel-components.ts';
17
+ import type {
18
+ buildInboundAcceptedLifecycleDebugInfo as buildInboundAcceptedLifecycleDebugInfoFromRuntime,
19
+ buildInboundResponsePayload as buildInboundResponsePayloadFromRuntime,
20
+ } from './channel-inbound-helpers.ts';
21
+ import type { BncrChannelConfigRoot, BncrVerifiedTarget } from './channel-runtime-types.ts';
22
+ import type { LeaseEventPayload } from './connection-handlers.ts';
23
+ import type { BncrActiveConnectionDebugEntry } from './connection-state.ts';
24
+ import type { FileAckPayloadState, FileAckWaiter } from './file-ack-runtime.ts';
25
+ import type { createBncrFileInboundHandlers } from './file-inbound-handlers.ts';
26
+ import type { BncrFileTransferOrchestratorRuntime } from './file-transfer-orchestrator.ts';
27
+ import type { BncrFileTransferRouteDiagnostics } from './file-transfer-setup.ts';
28
+ import type { MessageAckWaiter } from './message-ack-runtime.ts';
29
+
30
+ type StoredRouteRecord = { accountId: string; route: BncrRoute; updatedAt: number };
31
+ type StoredLastSessionRecord = { sessionKey: string; scope: string; updatedAt: number };
32
+
33
+ // Delivery-side wiring catalog.
34
+ //
35
+ // Order is intentional:
36
+ // 1) gateway / connection entrypoints
37
+ // 2) outbound + file-transfer state machines
38
+ // 3) inbound/public send surfaces
39
+
40
+ export function buildBncrConnectionStateRuntime(deps: {
41
+ bridgeId: string;
42
+ now: () => number;
43
+ asString: (value: unknown, fallback?: string) => string;
44
+ connectTtlMs: number;
45
+ recentInboundSendWindowMs: number;
46
+ outboundReadyTtlMs: number;
47
+ preferredOutboundTtlMs: number;
48
+ connections: Map<string, BncrConnection>;
49
+ activeConnectionByAccount: Map<string, string>;
50
+ lastInboundByAccount: Map<string, number>;
51
+ lastActivityByAccount: Map<string, number>;
52
+ gcTransientState: () => void;
53
+ connectionKey: (accountId: string, clientId?: string) => string;
54
+ buildActiveConnectionDebugList: (
55
+ accountId: string,
56
+ options?: { includeOutboundState?: boolean },
57
+ ) => BncrActiveConnectionDebugEntry[];
58
+ rememberGatewayContext: (context: GatewayRequestHandlerOptions['context']) => void;
59
+ markActivity: (accountId: string, at?: number) => void;
60
+ logInfo: (scope: string, message: string, options?: { debugOnly?: boolean }) => void;
61
+ logInfoDedupJson: (
62
+ scope: string,
63
+ label: string,
64
+ payload: unknown,
65
+ options?: { key?: string; sig?: string; debugOnly?: boolean },
66
+ ) => void;
67
+ }) {
68
+ return { ...deps };
69
+ }
70
+
71
+ export function buildBncrFileTransferRuntime(deps: {
72
+ bridgeId: string;
73
+ now: () => number;
74
+ asString: (value: unknown, fallback?: string) => string;
75
+ clampFiniteNumber: (value: unknown, fallback: number, min?: number, max?: number) => number;
76
+ fileAckTimeoutMs: number;
77
+ maxEarlyFileAcks: number;
78
+ fileAckWaiters: Map<string, FileAckWaiter>;
79
+ earlyFileAcks: Map<string, FileAckPayloadState>;
80
+ getFileAckOwnerInfo: (transferId: string) => Record<string, unknown>;
81
+ fileForceChunk: boolean;
82
+ fileInlineThreshold: number;
83
+ normalizeAccountId: (accountId: string) => string;
84
+ loadOutboundTransferMedia: (args: {
85
+ mediaUrl: string;
86
+ mediaLocalRoots?: readonly string[];
87
+ }) => Promise<{ loaded: { buffer: Buffer }; size: number; mimeType?: string; fileName: string }>;
88
+ resolveOutboxPushOwner: (accountId: string) => { connId?: string; clientId?: string } | null;
89
+ hasRecentInboundReachability: (accountId: string) => boolean;
90
+ buildTransferRouteDiagnostics: (args: {
91
+ accountId: string;
92
+ recentInboundReachable: boolean;
93
+ }) => BncrFileTransferRouteDiagnostics;
94
+ selectTransferConnIds: (args: {
95
+ directConnIds: Set<string>;
96
+ recentConnIds: Set<string>;
97
+ recentInboundReachable: boolean;
98
+ }) => Set<string>;
99
+ broadcastToConnIds: (event: string, payload: unknown, connIds: ReadonlySet<string>) => void;
100
+ chunkEvent: string;
101
+ completeEvent: string;
102
+ logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
103
+ logWarn: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
104
+ }) {
105
+ return { ...deps };
106
+ }
107
+
108
+ export function buildBncrStateTransientRuntime(deps: {
109
+ bridgeId: string;
110
+ getStatePath: () => string | null;
111
+ now: () => number;
112
+ asString: (value: unknown, fallback?: string) => string;
113
+ finiteNumberOr: (value: unknown, fallback: number) => number;
114
+ normalizeAccountId: (accountId: string) => string;
115
+ normalizeStoredSessionKey: typeof normalizeStoredSessionKeyFromRuntime;
116
+ parseRouteLike: (value: unknown) => BncrRoute | null;
117
+ routeKey: (accountId: string, route: BncrRoute) => string;
118
+ formatDisplayScope: (route: BncrRoute) => string;
119
+ canonicalAgentId: () => string;
120
+ normalizePersistedOutboxEntry: (entry: unknown) => OutboxEntry | null;
121
+ maxDeadLetterEntries: number;
122
+ maxSessionRouteEntries: number;
123
+ maxAccountActivityEntries: number;
124
+ outbox: Map<string, OutboxEntry>;
125
+ getDeadLetter: () => OutboxEntry[];
126
+ setDeadLetter: (entries: OutboxEntry[]) => void;
127
+ sessionRoutes: Map<string, StoredRouteRecord>;
128
+ routeAliases: Map<string, StoredRouteRecord>;
129
+ lastSessionByAccount: Map<string, StoredLastSessionRecord>;
130
+ lastActivityByAccount: Map<string, number>;
131
+ lastInboundByAccount: Map<string, number>;
132
+ lastOutboundByAccount: Map<string, number>;
133
+ getLastDriftSnapshot: () => RegisterDriftSnapshot | null;
134
+ setLastDriftSnapshot: (value: RegisterDriftSnapshot | null) => void;
135
+ connectTtlMs: number;
136
+ fileTransferKeepMs: number;
137
+ fileTransferTerminalKeepMs: number;
138
+ fileTransferAckTtlMs: number;
139
+ connections: Map<string, BncrConnection>;
140
+ activeConnectionByAccount: Map<string, string>;
141
+ recentInbound: Map<string, number>;
142
+ fileSendTransfers: Map<string, { status: string; startedAt: number; terminalAt?: number }>;
143
+ fileRecvTransfers: Map<string, { status: string; startedAt: number; terminalAt?: number }>;
144
+ earlyFileAcks: Map<string, { at: number }>;
145
+ logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
146
+ }) {
147
+ return { ...deps };
148
+ }
149
+
150
+ export function buildBncrAckOutboxRuntime(deps: {
151
+ bridgeId: string;
152
+ pushEvent: string;
153
+ now: () => number;
154
+ asString: (value: unknown, fallback?: string) => string;
155
+ backoffMs: (retryCount: number) => number;
156
+ isPlainObject: (value: unknown) => value is Record<string, unknown>;
157
+ clampFiniteNumber: (value: unknown, fallback: number, min?: number, max?: number) => number;
158
+ normalizeAccountId: (accountId: string) => string;
159
+ formatDisplayScope: (route: BncrRoute) => string;
160
+ isFileTransferEntry: (entry: OutboxEntry) => boolean;
161
+ recommendedAckTimeoutMaxMs: number;
162
+ adaptiveAckTimeoutEnabled: boolean;
163
+ defaultAckTimeoutMs: number;
164
+ stopped: () => boolean;
165
+ outbox: Map<string, OutboxEntry>;
166
+ deadLetter: () => OutboxEntry[];
167
+ connectionsValues: () => IterableIterator<BncrConnection>;
168
+ gatewayContextAvailable: () => boolean;
169
+ messageAckWaiters: Map<string, MessageAckWaiter>;
170
+ fileAckWaiterCount: () => number;
171
+ activeConnectionCount: (accountId: string) => number;
172
+ getAccountPendingOutboxEntries: (accountId: string) => OutboxEntry[];
173
+ pushDrainRunningAccounts: Set<string>;
174
+ pushDrainRunningSinceByAccount: Map<string, number>;
175
+ pushDrainStuckWarnedAtByAccount: Map<string, number>;
176
+ isOnline: (accountId: string) => boolean;
177
+ hasRecentInboundReachability: (accountId: string) => boolean;
178
+ isOutboundAckRequired: (accountId?: string) => boolean;
179
+ resolveMessageAckTimeoutMs: (accountId: string) => number;
180
+ waitForMessageAck: (messageId: string, waitMs: number) => Promise<'acked' | 'timeout'>;
181
+ resolvePushConnIds: (accountId: string) => Iterable<string>;
182
+ sleepMs: (ms: number) => Promise<void>;
183
+ schedulePushDrain: (delayMs: number) => void;
184
+ tryPushEntry: (entry: OutboxEntry) => Promise<boolean>;
185
+ handleFileTransferPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
186
+ handleTextPushFailure: (args: { entry: OutboxEntry; error: unknown }) => void;
187
+ isPrePushGuardDeferral: (entry: OutboxEntry) => boolean;
188
+ scheduleSave: () => void;
189
+ logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
190
+ logWarn: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
191
+ logError: (scope: string, message: string) => void;
192
+ observeLease: (
193
+ kind:
194
+ | 'connect'
195
+ | 'inbound'
196
+ | 'activity'
197
+ | 'ack'
198
+ | 'file.init'
199
+ | 'file.chunk'
200
+ | 'file.complete'
201
+ | 'file.abort',
202
+ payload: Record<string, unknown>,
203
+ ) => { stale: boolean };
204
+ rememberGatewayContext: (context: GatewayRequestHandlerOptions['context']) => void;
205
+ markSeen: (accountId: string, connId: string, clientId?: string) => void;
206
+ markOutboundCapability: (args: {
207
+ accountId: string;
208
+ connId: string;
209
+ clientId?: string;
210
+ outboundReady: boolean;
211
+ preferredForOutbound: boolean;
212
+ }) => void;
213
+ recordAckOkTelemetry: (args: {
214
+ accountId: string;
215
+ entry: OutboxEntry;
216
+ telemetryPatch: { queueLatencyMs?: number; pushLatencyMs?: number; lateAfterTimeout?: boolean };
217
+ }) => void;
218
+ deleteOutboxEntry: (messageId: string) => void;
219
+ setOutboxEntry: (messageId: string, entry: OutboxEntry) => void;
220
+ resolveMessageAck: (messageId: string, result: 'acked' | 'timeout') => boolean;
221
+ moveToDeadLetter: (entry: OutboxEntry, reason: string) => void;
222
+ recordAckTimeoutTelemetry: (accountId: string) => void;
223
+ degradeOutboundCapability: (args: {
224
+ accountId: string;
225
+ connId?: string;
226
+ clientId?: string;
227
+ reason: string;
228
+ }) => void;
229
+ flushPushQueueBestEffort: (args?: {
230
+ accountId?: string;
231
+ trigger?: string;
232
+ reason?: string;
233
+ }) => void;
234
+ flushTriggerTimer: string;
235
+ flushReasonScheduledDrain: string;
236
+ outboundFlushTriggerAckOk: string;
237
+ outboundFlushReasonMessageAcked: string;
238
+ pushDrainExceptionRetryLimit: number;
239
+ pushDrainExceptionRetryDelayMs: number;
240
+ pushDrainStuckWarnMs: number;
241
+ pushDrainIntervalMs: number;
242
+ pushDrainAccountTimeBudgetMs: number;
243
+ pushDrainAccountBudget: number;
244
+ pushAckTimeoutMs: number;
245
+ maxRetry: number;
246
+ prePushGuardRetryDelayMs: number;
247
+ }) {
248
+ return { ...deps };
249
+ }
250
+
251
+ export function buildBncrOutboxPushRouteRuntime(deps: {
252
+ bridgeId: string;
253
+ pushEvent: string;
254
+ now: () => number;
255
+ connectTtlMs: number;
256
+ finiteNumberOr: (value: unknown, fallback: number) => number;
257
+ outboxSize: () => number;
258
+ gatewayBroadcastToConnIds: (
259
+ event: string,
260
+ payload: unknown,
261
+ connIds: ReadonlySet<string>,
262
+ ) => void;
263
+ recordOutboxPushSuccess: (args: {
264
+ entry: OutboxEntry;
265
+ connIds: Iterable<string>;
266
+ ownerConnId?: string;
267
+ ownerClientId?: string;
268
+ clearLastError?: boolean;
269
+ }) => void;
270
+ recordOutboxPushFailure: (args: {
271
+ entry: OutboxEntry;
272
+ error: unknown;
273
+ fallbackError: string;
274
+ persist?: boolean;
275
+ }) => void;
276
+ recordOutboxPrePushFailure: (args: {
277
+ entry: OutboxEntry;
278
+ lastError: string;
279
+ persist?: boolean;
280
+ }) => void;
281
+ recordPrePushGuardSkip: (args: { accountId: string; reason: string }) => void;
282
+ moveToDeadLetter: (entry: OutboxEntry, reason: string) => void;
283
+ activeConnectionCount: (accountId: string) => number;
284
+ connections: Map<string, BncrConnection>;
285
+ connectionsValues: () => Iterable<BncrConnection>;
286
+ activeConnectionByAccount: Map<string, string>;
287
+ resolveRecentInboundConnIds: (accountId: string) => Set<string>;
288
+ connectionKey: (accountId: string, clientId?: string) => string;
289
+ isRetryableFileTransferError: (value: unknown) => boolean;
290
+ logInfo: (scope: string, message: string, options?: { debugOnly?: boolean }) => void;
291
+ buildActiveConnectionDebugList: (
292
+ accountId: string,
293
+ options?: { includeOutboundState?: boolean },
294
+ ) => BncrActiveConnectionDebugEntry[];
295
+ }) {
296
+ return { ...deps };
297
+ }
298
+
299
+ export function buildBncrMediaOrchestratorsRuntime(deps: {
300
+ now: () => number;
301
+ asString: (value: unknown, fallback?: string) => string;
302
+ fileSendTransfers: Map<string, FileSendTransferState>;
303
+ getGatewayContext: () => GatewayRequestHandlerOptions['context'] | null;
304
+ fileInitEvent: string;
305
+ fileAbortEvent: string;
306
+ prepareOutboundTransfer: BncrFileTransferOrchestratorRuntime['prepareOutboundTransfer'];
307
+ sendChunk: BncrFileTransferOrchestratorRuntime['sendChunk'];
308
+ sendComplete: BncrFileTransferOrchestratorRuntime['sendComplete'];
309
+ waitForFileAck: BncrFileTransferOrchestratorRuntime['waitForFileAck'];
310
+ logFileTransferChunkAck: BncrFileTransferOrchestratorRuntime['logFileTransferChunkAck'];
311
+ logFileTransferChunkAckFail: BncrFileTransferOrchestratorRuntime['logFileTransferChunkAckFail'];
312
+ logFileTransferCompleteAck: BncrFileTransferOrchestratorRuntime['logFileTransferCompleteAck'];
313
+ logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
314
+ logEnqueueFromReply: (args: {
315
+ accountId: string;
316
+ sessionKey: string;
317
+ route: BncrRoute;
318
+ payload: NormalizedReplyPayload;
319
+ }) => void;
320
+ enqueueOutbound: (entry: OutboxEntry) => void;
321
+ buildTextOutboxEntry: (args: {
322
+ accountId: string;
323
+ sessionKey: string;
324
+ route: BncrRoute;
325
+ text: string;
326
+ kind?: 'tool' | 'block' | 'final';
327
+ replyToId?: string;
328
+ replyTargetPolicy?: OutboundReplyTargetPolicy;
329
+ }) => OutboxEntry;
330
+ buildFileTransferOutboxEntry: (args: {
331
+ accountId: string;
332
+ sessionKey: string;
333
+ route: BncrRoute;
334
+ mediaUrl: string;
335
+ mediaLocalRoots?: readonly string[];
336
+ text: string;
337
+ asVoice: boolean;
338
+ audioAsVoice: boolean;
339
+ type?: string;
340
+ kind?: 'tool' | 'block' | 'final';
341
+ replyToId?: string;
342
+ replyTargetPolicy?: OutboundReplyTargetPolicy;
343
+ }) => OutboxEntry;
344
+ rememberRecentMediaSend: (args: {
345
+ sessionKey: string;
346
+ mediaUrl: string;
347
+ text: string;
348
+ replyToId: string;
349
+ createdAt: number;
350
+ }) => void;
351
+ tryBuildMediaDedupeFallback: (args: {
352
+ sessionKey: string;
353
+ mediaUrl: string;
354
+ text: string;
355
+ replyToId: string;
356
+ currentTime: number;
357
+ }) => {
358
+ text: string;
359
+ reason: 'same-text-sent-checkmark' | 'text-changed-downgrade';
360
+ } | null;
361
+ }) {
362
+ return {
363
+ ...deps,
364
+ getGatewayContext: () => {
365
+ const context = deps.getGatewayContext();
366
+ if (!context) return null;
367
+ return {
368
+ broadcastToConnIds: (event: string, payload: unknown, connIds: ReadonlySet<string>) =>
369
+ context.broadcastToConnIds(event, payload, connIds),
370
+ };
371
+ },
372
+ };
373
+ }
374
+
375
+ export function buildBncrInboundSurfaceRuntime(deps: {
376
+ getApi: Parameters<typeof createBncrInboundHandlersComponent>[0]['getApi'];
377
+ channelId: string;
378
+ bridgeId: string;
379
+ pluginRoot: string;
380
+ asString: (value: unknown, fallback?: string) => string;
381
+ now: () => number;
382
+ normalizeAccountId: (value: string) => string;
383
+ finiteNonNegativeNumberOrNull: (value: unknown) => number | null;
384
+ syncDebugFlag: () => Promise<void>;
385
+ shouldIgnoreStaleEvent: (args: {
386
+ kind:
387
+ | 'activity'
388
+ | 'ack'
389
+ | 'file.init'
390
+ | 'file.chunk'
391
+ | 'file.complete'
392
+ | 'file.abort'
393
+ | 'inbound';
394
+ payload: LeaseEventPayload;
395
+ accountId: string;
396
+ connId: string;
397
+ clientId?: string;
398
+ }) => boolean;
399
+ observeLease: (
400
+ kind:
401
+ | 'connect'
402
+ | 'inbound'
403
+ | 'activity'
404
+ | 'ack'
405
+ | 'file.init'
406
+ | 'file.chunk'
407
+ | 'file.complete'
408
+ | 'file.abort',
409
+ payload: LeaseEventPayload,
410
+ ) => { stale: boolean };
411
+ matchesTransferOwner: (args: {
412
+ ownerConnId?: string;
413
+ ownerClientId?: string;
414
+ connId: string;
415
+ clientId?: string;
416
+ }) => boolean;
417
+ refreshAcceptedFileTransferLiveState: (args: {
418
+ accountId: string;
419
+ connId: string;
420
+ clientId?: string;
421
+ context: GatewayRequestHandlerOptions['context'];
422
+ }) => void;
423
+ refreshLiveConnectionState: (args: {
424
+ accountId: string;
425
+ connId: string;
426
+ clientId?: string;
427
+ outboundReady: boolean;
428
+ preferredForOutbound: boolean;
429
+ inboundOnly: boolean;
430
+ context: GatewayRequestHandlerOptions['context'];
431
+ }) => void;
432
+ logInfo: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
433
+ logWarn: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
434
+ logError: (scope: string | undefined, message: string, options?: { debugOnly?: boolean }) => void;
435
+ buildInboundResponsePayload: typeof buildInboundResponsePayloadFromRuntime;
436
+ buildInboundAcceptedLifecycleDebugInfo: typeof buildInboundAcceptedLifecycleDebugInfoFromRuntime;
437
+ isOnline: (accountId: string) => boolean;
438
+ hasRecentInboundReachability: (accountId: string) => boolean;
439
+ getActiveConnectionKey: (accountId: string) => string | null;
440
+ buildActiveConnectionDebugList: (accountId: string) => BncrActiveConnectionDebugEntry[];
441
+ markLastInboundAt: (accountId: string) => void;
442
+ ensureCanonicalAgentId: (args: {
443
+ cfg: BncrChannelConfigRoot;
444
+ accountId: string;
445
+ peer?: unknown;
446
+ channelId?: string;
447
+ }) => string;
448
+ prepareInboundAcceptance: (args: {
449
+ parsed: ReturnType<typeof parseBncrInboundParams>;
450
+ canonicalAgentId: string;
451
+ }) => Promise<
452
+ | {
453
+ ok: true;
454
+ accountId: string;
455
+ sessionKey: string;
456
+ inboundText: string;
457
+ hasMedia: boolean;
458
+ }
459
+ | {
460
+ ok: false;
461
+ status: boolean;
462
+ payload: Record<string, unknown>;
463
+ }
464
+ >;
465
+ logInboundSummary: (args: {
466
+ accountId: string;
467
+ route: BncrRoute;
468
+ msgType: string;
469
+ text: string;
470
+ hasMedia: boolean;
471
+ }) => void;
472
+ flushPushQueueBestEffort: (args?: {
473
+ accountId?: string;
474
+ trigger?: string;
475
+ reason?: string;
476
+ }) => void;
477
+ rememberSessionRoute: (sessionKey: string, accountId: string, route: BncrRoute) => void;
478
+ enqueueFromReply: (args: {
479
+ accountId: string;
480
+ sessionKey: string;
481
+ route: BncrRoute;
482
+ payload: ReplyPayloadInput;
483
+ mediaLocalRoots?: readonly string[];
484
+ replyTargetPolicy?: OutboundReplyTargetPolicy;
485
+ }) => Promise<void>;
486
+ setInboundActivity: (accountId: string, at: number) => void;
487
+ scheduleSave: () => void;
488
+ fileRecvTransfers: Parameters<typeof createBncrFileInboundHandlers>[0]['fileRecvTransfers'];
489
+ inboundFileTransferMaxBytes: number;
490
+ inboundFileTransferMaxChunks: number;
491
+ }) {
492
+ return { ...deps };
493
+ }
494
+
495
+ export function buildBncrChannelSendRuntime(deps: {
496
+ channelId: string;
497
+ asString: (value: unknown, fallback?: string) => string;
498
+ syncDebugFlag: () => Promise<void>;
499
+ logInfo: (scope: string, message: string, options?: Record<string, unknown>) => void;
500
+ resolveVerifiedTarget: (to: string, accountId: string) => BncrVerifiedTarget;
501
+ rememberSessionRoute: (sessionKey: string, accountId: string, route: BncrRoute) => void;
502
+ enqueueFromReply: (args: {
503
+ accountId: string;
504
+ sessionKey: string;
505
+ route: BncrRoute;
506
+ payload: ReplyPayloadInput;
507
+ mediaLocalRoots?: readonly string[];
508
+ replyTargetPolicy?: OutboundReplyTargetPolicy;
509
+ }) => Promise<void>;
510
+ listOutboxEntries: () => OutboxEntry[];
511
+ }) {
512
+ return { ...deps };
513
+ }