@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
package/dist/index.js
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
// index.ts
|
|
2
|
-
import path3 from "node:path";
|
|
3
|
-
|
|
4
1
|
// src/bootstrap/channel-plugin-runtime.ts
|
|
5
2
|
function createDynamicChannelPlugin(args) {
|
|
6
3
|
const { loaded, getCurrentBridge: getCurrentBridge2 } = args;
|
|
@@ -786,12 +783,7 @@ var BncrConfigSchema = {
|
|
|
786
783
|
};
|
|
787
784
|
|
|
788
785
|
// index.ts
|
|
789
|
-
var
|
|
790
|
-
const packageJsonPath = path3.join(rootDir, "package.json");
|
|
791
|
-
void packageJsonPath;
|
|
792
|
-
return pluginVersion;
|
|
793
|
-
};
|
|
794
|
-
var pluginVersion2 = readPluginVersion2();
|
|
786
|
+
var pluginVersion2 = pluginVersion;
|
|
795
787
|
var registerRuntime = createBncrRegisterRuntime();
|
|
796
788
|
var {
|
|
797
789
|
ensureGatewayMethodRegistered,
|
package/index.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
1
|
import { createDynamicChannelPlugin } from './src/bootstrap/channel-plugin-runtime.ts';
|
|
3
2
|
import {
|
|
4
3
|
type BncrRegistrationApi,
|
|
@@ -10,7 +9,6 @@ import {
|
|
|
10
9
|
type ChannelModule,
|
|
11
10
|
type LoadedRuntime,
|
|
12
11
|
loadBncrRuntimeSync,
|
|
13
|
-
pluginRoot,
|
|
14
12
|
pluginVersion as runtimePluginVersion,
|
|
15
13
|
} from './src/bootstrap/runtime-loader.ts';
|
|
16
14
|
import { BncrConfigSchema } from './src/core/config-schema.ts';
|
|
@@ -19,13 +17,7 @@ import { getOpenClawRuntimeConfig } from './src/openclaw/config-runtime.ts';
|
|
|
19
17
|
|
|
20
18
|
type ChannelPlugin = ReturnType<ChannelModule['createBncrChannelPlugin']>;
|
|
21
19
|
|
|
22
|
-
const
|
|
23
|
-
const packageJsonPath = path.join(rootDir, 'package.json');
|
|
24
|
-
void packageJsonPath;
|
|
25
|
-
return runtimePluginVersion;
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
const pluginVersion = readPluginVersion();
|
|
20
|
+
const pluginVersion = runtimePluginVersion;
|
|
29
21
|
|
|
30
22
|
const registerRuntime = createBncrRegisterRuntime();
|
|
31
23
|
|
package/package.json
CHANGED
package/scripts/check-pack.mjs
CHANGED
|
@@ -76,10 +76,8 @@ const requiredSourceFiles = [
|
|
|
76
76
|
'src/messaging/inbound/session-label.ts',
|
|
77
77
|
'src/messaging/inbound/turn-context.ts',
|
|
78
78
|
'src/messaging/outbound/actions.ts',
|
|
79
|
-
'src/messaging/outbound/build-send-action.ts',
|
|
80
79
|
'src/messaging/outbound/diagnostics.ts',
|
|
81
80
|
'src/messaging/outbound/diagnostics-debug-builders.ts',
|
|
82
|
-
'src/messaging/outbound/durable-message-adapter.ts',
|
|
83
81
|
'src/messaging/outbound/durable-queue-adapter.ts',
|
|
84
82
|
'src/messaging/outbound/media-dedupe.ts',
|
|
85
83
|
'src/messaging/outbound/media.ts',
|
|
@@ -88,13 +86,10 @@ const requiredSourceFiles = [
|
|
|
88
86
|
'src/messaging/outbound/reply-enqueue.ts',
|
|
89
87
|
'src/messaging/outbound/reply-target-policy.ts',
|
|
90
88
|
'src/messaging/outbound/retry-policy.ts',
|
|
91
|
-
'src/messaging/outbound/send-params.ts',
|
|
92
|
-
'src/messaging/outbound/send.ts',
|
|
93
89
|
'src/messaging/outbound/session-route.ts',
|
|
94
90
|
'src/messaging/outbound/target-resolver.ts',
|
|
95
91
|
'src/openclaw/config-runtime.ts',
|
|
96
92
|
'src/openclaw/inbound-session-runtime.ts',
|
|
97
|
-
'src/openclaw/ingress-runtime.ts',
|
|
98
93
|
'src/openclaw/media-runtime.ts',
|
|
99
94
|
'src/openclaw/reply-runtime.ts',
|
|
100
95
|
'src/openclaw/routing-runtime.ts',
|
|
@@ -111,7 +106,6 @@ const requiredSourceFiles = [
|
|
|
111
106
|
'src/plugin/channel-plugin-surface-group.ts',
|
|
112
107
|
'src/plugin/channel-runtime-constants.ts',
|
|
113
108
|
'src/plugin/channel-runtime-builders.ts',
|
|
114
|
-
'src/plugin/channel-send-runtime-group.ts',
|
|
115
109
|
'src/plugin/channel-runtime-types.ts',
|
|
116
110
|
'src/plugin/channel-send.ts',
|
|
117
111
|
'src/plugin/channel-utils.ts',
|
|
@@ -155,11 +149,9 @@ const requiredSourceFiles = [
|
|
|
155
149
|
'src/plugin/outbox-drain-post-push.ts',
|
|
156
150
|
'src/plugin/outbox-drain-runtime.ts',
|
|
157
151
|
'src/plugin/outbox-drain-schedule.ts',
|
|
158
|
-
'src/plugin/outbox-file-push-flow.ts',
|
|
159
152
|
'src/plugin/outbox-push-route-runtime-group.ts',
|
|
160
153
|
'src/plugin/outbox-push.ts',
|
|
161
154
|
'src/plugin/outbox-route.ts',
|
|
162
|
-
'src/plugin/outbox-text-push-flow.ts',
|
|
163
155
|
'src/plugin/runtime-diagnostics-snapshot.ts',
|
|
164
156
|
'src/plugin/setup.ts',
|
|
165
157
|
'src/plugin/state-transient-runtime-group.ts',
|
package/scripts/selfcheck.mjs
CHANGED
|
@@ -44,7 +44,6 @@ const requiredSourceFiles = [
|
|
|
44
44
|
'src/core/outbox-summary.ts',
|
|
45
45
|
'src/core/outbox-text-push-failure.ts',
|
|
46
46
|
'src/core/outbox-text-push-guards.ts',
|
|
47
|
-
'src/core/outbox-text-push-prep.ts',
|
|
48
47
|
'src/core/outbox-text-push-success.ts',
|
|
49
48
|
'src/core/permissions.ts',
|
|
50
49
|
'src/core/persisted-outbox-entry.ts',
|
|
@@ -72,10 +71,8 @@ const requiredSourceFiles = [
|
|
|
72
71
|
'src/messaging/inbound/session-label.ts',
|
|
73
72
|
'src/messaging/inbound/turn-context.ts',
|
|
74
73
|
'src/messaging/outbound/actions.ts',
|
|
75
|
-
'src/messaging/outbound/build-send-action.ts',
|
|
76
74
|
'src/messaging/outbound/diagnostics.ts',
|
|
77
75
|
'src/messaging/outbound/diagnostics-debug-builders.ts',
|
|
78
|
-
'src/messaging/outbound/durable-message-adapter.ts',
|
|
79
76
|
'src/messaging/outbound/durable-queue-adapter.ts',
|
|
80
77
|
'src/messaging/outbound/media-dedupe.ts',
|
|
81
78
|
'src/messaging/outbound/media.ts',
|
|
@@ -84,13 +81,10 @@ const requiredSourceFiles = [
|
|
|
84
81
|
'src/messaging/outbound/reply-enqueue.ts',
|
|
85
82
|
'src/messaging/outbound/reply-target-policy.ts',
|
|
86
83
|
'src/messaging/outbound/retry-policy.ts',
|
|
87
|
-
'src/messaging/outbound/send-params.ts',
|
|
88
|
-
'src/messaging/outbound/send.ts',
|
|
89
84
|
'src/messaging/outbound/session-route.ts',
|
|
90
85
|
'src/messaging/outbound/target-resolver.ts',
|
|
91
86
|
'src/openclaw/config-runtime.ts',
|
|
92
87
|
'src/openclaw/inbound-session-runtime.ts',
|
|
93
|
-
'src/openclaw/ingress-runtime.ts',
|
|
94
88
|
'src/openclaw/media-runtime.ts',
|
|
95
89
|
'src/openclaw/reply-runtime.ts',
|
|
96
90
|
'src/openclaw/routing-runtime.ts',
|
|
@@ -107,7 +101,6 @@ const requiredSourceFiles = [
|
|
|
107
101
|
'src/plugin/channel-plugin-surface-group.ts',
|
|
108
102
|
'src/plugin/channel-runtime-constants.ts',
|
|
109
103
|
'src/plugin/channel-runtime-builders.ts',
|
|
110
|
-
'src/plugin/channel-send-runtime-group.ts',
|
|
111
104
|
'src/plugin/channel-runtime-types.ts',
|
|
112
105
|
'src/plugin/channel-send.ts',
|
|
113
106
|
'src/plugin/channel-utils.ts',
|
|
@@ -151,11 +144,9 @@ const requiredSourceFiles = [
|
|
|
151
144
|
'src/plugin/outbox-drain-post-push.ts',
|
|
152
145
|
'src/plugin/outbox-drain-runtime.ts',
|
|
153
146
|
'src/plugin/outbox-drain-schedule.ts',
|
|
154
|
-
'src/plugin/outbox-file-push-flow.ts',
|
|
155
147
|
'src/plugin/outbox-push-route-runtime-group.ts',
|
|
156
148
|
'src/plugin/outbox-push.ts',
|
|
157
149
|
'src/plugin/outbox-route.ts',
|
|
158
|
-
'src/plugin/outbox-text-push-flow.ts',
|
|
159
150
|
'src/plugin/runtime-diagnostics-snapshot.ts',
|
|
160
151
|
'src/plugin/setup.ts',
|
|
161
152
|
'src/plugin/state-transient-runtime-group.ts',
|
|
@@ -198,7 +189,6 @@ const readNpmLatestVersion = (packageName) => {
|
|
|
198
189
|
|
|
199
190
|
const requiredOpenClawSdkSubpaths = [
|
|
200
191
|
'openclaw/plugin-sdk',
|
|
201
|
-
'openclaw/plugin-sdk/boolean-param',
|
|
202
192
|
'openclaw/plugin-sdk/channel-outbound',
|
|
203
193
|
'openclaw/plugin-sdk/channel-ingress-runtime',
|
|
204
194
|
'openclaw/plugin-sdk/channel-message',
|
|
@@ -44,7 +44,7 @@ export const pluginRoot = resolveBncrPluginRoot(pluginFile);
|
|
|
44
44
|
const runtimeSourceDir = resolveBncrRuntimeSourceDir(pluginDir);
|
|
45
45
|
let runtime: LoadedRuntime | null = null;
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
const readPluginVersion = (rootDir = pluginRoot) => {
|
|
48
48
|
try {
|
|
49
49
|
const raw = fs.readFileSync(path.join(rootDir, 'package.json'), 'utf8');
|
|
50
50
|
const parsed = JSON.parse(raw);
|
package/src/channel.ts
CHANGED
|
@@ -19,10 +19,7 @@ import {
|
|
|
19
19
|
emitBncrLog,
|
|
20
20
|
summarizeBncrTextPreview,
|
|
21
21
|
} from './core/logging.ts';
|
|
22
|
-
import {
|
|
23
|
-
buildFileTransferOutboxEntry as buildFileTransferOutboxEntryFromRuntime,
|
|
24
|
-
buildTextOutboxEntry as buildTextOutboxEntryFromRuntime,
|
|
25
|
-
} from './core/outbox-entry-builders.ts';
|
|
22
|
+
import { buildOutboxEntry as buildOutboxEntryFromRuntime } from './core/outbox-entry-builders.ts';
|
|
26
23
|
import { summarizeOutboxEntry } from './core/outbox-summary.ts';
|
|
27
24
|
import { normalizePersistedOutboxEntry as normalizePersistedOutboxEntryFromRuntime } from './core/persisted-outbox-entry.ts';
|
|
28
25
|
import {
|
|
@@ -53,7 +50,6 @@ import { OUTBOUND_FLUSH_REASON, OUTBOUND_FLUSH_TRIGGER } from './messaging/outbo
|
|
|
53
50
|
import type {
|
|
54
51
|
NormalizedReplyPayload,
|
|
55
52
|
OutboundReplyTargetPolicy,
|
|
56
|
-
ReplyMediaEntriesParams,
|
|
57
53
|
ReplyPayloadInput,
|
|
58
54
|
} from './messaging/outbound/reply-enqueue.ts';
|
|
59
55
|
import type { OpenClawChannelRuntimeApiHolder } from './openclaw/channel-runtime-contracts.ts';
|
|
@@ -67,7 +63,6 @@ import { createBncrBridgeConnectionFacade } from './plugin/bridge-connection-fac
|
|
|
67
63
|
import { createBncrBridgeDiagnosticsFacade } from './plugin/bridge-diagnostics-facade.ts';
|
|
68
64
|
import { createBncrBridgeDrainFacade } from './plugin/bridge-drain-facade.ts';
|
|
69
65
|
import { createBncrBridgeExtendedDiagnosticsFacade } from './plugin/bridge-extended-diagnostics-facade.ts';
|
|
70
|
-
import { createBncrBridgeFileTransferPushFacade } from './plugin/bridge-file-transfer-push-facade.ts';
|
|
71
66
|
import {
|
|
72
67
|
cleanupBncrBridgeRuntime,
|
|
73
68
|
shutdownBncrBridgeService,
|
|
@@ -152,10 +147,9 @@ import type {
|
|
|
152
147
|
BncrChannelConfigRoot,
|
|
153
148
|
BncrChannelSendContext,
|
|
154
149
|
BncrSceneRecord,
|
|
155
|
-
FileAckPayloadState,
|
|
156
150
|
PersistedState,
|
|
157
151
|
} from './plugin/channel-runtime-types.ts';
|
|
158
|
-
import {
|
|
152
|
+
import { createBncrChannelSendRuntime } from './plugin/channel-send.ts';
|
|
159
153
|
import {
|
|
160
154
|
asString,
|
|
161
155
|
backoffMs,
|
|
@@ -168,6 +162,7 @@ import {
|
|
|
168
162
|
} from './plugin/channel-utils.ts';
|
|
169
163
|
import { BNCR_CONFIG_SURFACE } from './plugin/config.ts';
|
|
170
164
|
import { createBncrConnectionStateRuntimeGroup } from './plugin/connection-state-runtime-group.ts';
|
|
165
|
+
import type { FileAckPayloadState } from './plugin/file-ack-runtime.ts';
|
|
171
166
|
import { createBncrFileTransferRuntimeGroup } from './plugin/file-transfer-runtime-group.ts';
|
|
172
167
|
import { BNCR_GATEWAY_METHODS } from './plugin/gateway-methods.ts';
|
|
173
168
|
import { prepareBncrInboundAcceptance } from './plugin/inbound-acceptance.ts';
|
|
@@ -175,9 +170,9 @@ import { createBncrInboundSurfaceHandlersGroup } from './plugin/inbound-surface-
|
|
|
175
170
|
import { createBncrMediaOrchestratorsRuntimeGroup } from './plugin/media-orchestrators-runtime-group.ts';
|
|
176
171
|
import { BNCR_CHANNEL_META } from './plugin/meta.ts';
|
|
177
172
|
import type { BncrOutboxAckOkTelemetryPatch } from './plugin/outbox-ack-outcome.ts';
|
|
178
|
-
|
|
173
|
+
|
|
179
174
|
import { createBncrOutboxPushRouteRuntimeGroup } from './plugin/outbox-push-route-runtime-group.ts';
|
|
180
|
-
import {
|
|
175
|
+
import { runBncrOutboxPush } from './plugin/outbox-unified-push-flow.ts';
|
|
181
176
|
import {
|
|
182
177
|
createBncrDeadLetterDiagnosticsHelpers,
|
|
183
178
|
createBncrDiagnosticsSelectionHelpers,
|
|
@@ -1131,85 +1126,54 @@ class BncrBridgeRuntime {
|
|
|
1131
1126
|
// This block prepares media, chooses transfer mode, sends chunk/complete
|
|
1132
1127
|
// frames, and feeds successful media pushes back into the shared outbox path.
|
|
1133
1128
|
|
|
1134
|
-
private async pushFileTransferSuccessPath(args: {
|
|
1135
|
-
entry: OutboxEntry;
|
|
1136
|
-
meta: Record<string, unknown>;
|
|
1137
|
-
owner: ReturnType<BncrBridgeRuntime['resolveOutboxPushOwner']>;
|
|
1138
|
-
connIds: Iterable<string>;
|
|
1139
|
-
recentInboundReachable: boolean;
|
|
1140
|
-
routeReason: string;
|
|
1141
|
-
mediaUrl: string;
|
|
1142
|
-
}): Promise<void> {
|
|
1143
|
-
await this.fileTransferPushFacade.pushFileTransferSuccessPath(args);
|
|
1144
|
-
}
|
|
1145
|
-
|
|
1146
1129
|
private handleFileTransferPushFailure(args: { entry: OutboxEntry; error: unknown }) {
|
|
1147
|
-
this.
|
|
1130
|
+
this.outboxPush.handleFileTransferPushFailure(args);
|
|
1148
1131
|
}
|
|
1149
1132
|
|
|
1150
1133
|
private handleFileTransferPushGuardFailure(
|
|
1151
|
-
args: Parameters<typeof this.
|
|
1134
|
+
args: Parameters<typeof this.outboxPush.handleFileTransferPushGuardFailure>[0],
|
|
1152
1135
|
) {
|
|
1153
|
-
this.
|
|
1136
|
+
this.outboxPush.handleFileTransferPushGuardFailure(args);
|
|
1154
1137
|
}
|
|
1155
1138
|
|
|
1156
1139
|
// File-transfer outbound entry builders / dedupe -------------------------
|
|
1157
1140
|
|
|
1158
|
-
private
|
|
1159
|
-
entry: OutboxEntry,
|
|
1160
|
-
meta: Record<string, unknown>,
|
|
1161
|
-
): Promise<boolean> {
|
|
1162
|
-
return await runBncrFileTransferOutboxPush({
|
|
1163
|
-
entry,
|
|
1164
|
-
meta,
|
|
1165
|
-
gatewayContext: this.gatewayContext,
|
|
1166
|
-
owner: this.resolveOutboxPushOwner(entry.accountId),
|
|
1167
|
-
resolvePushConnIds: (accountId) => this.resolvePushConnIds(accountId),
|
|
1168
|
-
resolveRecentInboundConnIds: (accountId) => this.resolveRecentInboundConnIds(accountId),
|
|
1169
|
-
hasRecentInboundReachability: (accountId) => this.hasRecentInboundReachability(accountId),
|
|
1170
|
-
isRevalidatedAttemptedConn: (connId) => this.isRevalidatedAttemptedConn(entry, connId),
|
|
1171
|
-
handleFileTransferPushGuardFailure: (flowArgs) =>
|
|
1172
|
-
this.handleFileTransferPushGuardFailure(flowArgs),
|
|
1173
|
-
pushFileTransferSuccessPath: (flowArgs) => this.pushFileTransferSuccessPath(flowArgs),
|
|
1174
|
-
handleFileTransferPushFailure: (flowArgs) => this.handleFileTransferPushFailure(flowArgs),
|
|
1175
|
-
});
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
private buildFileTransferOutboxEntry(params: {
|
|
1141
|
+
private buildOutboxEntry(params: {
|
|
1179
1142
|
accountId: string;
|
|
1180
1143
|
sessionKey: string;
|
|
1181
1144
|
route: BncrRoute;
|
|
1182
|
-
mediaUrl: string;
|
|
1183
|
-
mediaLocalRoots?: readonly string[];
|
|
1184
|
-
text?: string;
|
|
1185
|
-
asVoice?: boolean;
|
|
1186
|
-
audioAsVoice?: boolean;
|
|
1187
1145
|
type?: string;
|
|
1188
|
-
|
|
1146
|
+
msg: string;
|
|
1189
1147
|
kind?: 'tool' | 'block' | 'final';
|
|
1190
1148
|
replyToId?: string;
|
|
1191
1149
|
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
1150
|
+
extra?: Record<string, unknown>;
|
|
1151
|
+
transferMode?: 'text' | 'media';
|
|
1152
|
+
mediaUrl?: string;
|
|
1153
|
+
mediaLocalRoots?: readonly string[];
|
|
1154
|
+
asVoice?: boolean;
|
|
1155
|
+
audioAsVoice?: boolean;
|
|
1192
1156
|
downloadMedia?: boolean;
|
|
1193
1157
|
}): OutboxEntry {
|
|
1194
|
-
return
|
|
1158
|
+
return buildOutboxEntryFromRuntime({
|
|
1195
1159
|
createMessageId: () => randomUUID(),
|
|
1196
1160
|
now,
|
|
1197
1161
|
normalizeAccountId,
|
|
1198
|
-
pushEvent: BNCR_PUSH_EVENT,
|
|
1199
1162
|
accountId: params.accountId,
|
|
1200
1163
|
sessionKey: params.sessionKey,
|
|
1201
1164
|
route: params.route,
|
|
1202
|
-
mediaUrl: params.mediaUrl,
|
|
1203
|
-
mediaLocalRoots: params.mediaLocalRoots,
|
|
1204
|
-
text: asString(params.text || ''),
|
|
1205
|
-
asVoice: params.asVoice,
|
|
1206
|
-
audioAsVoice: params.audioAsVoice,
|
|
1207
1165
|
type: params.type,
|
|
1208
|
-
|
|
1166
|
+
msg: params.msg,
|
|
1209
1167
|
kind: params.kind,
|
|
1210
1168
|
replyToId: asString(params.replyToId || '').trim() || undefined,
|
|
1211
1169
|
replyTargetPolicy: params.replyTargetPolicy,
|
|
1212
|
-
|
|
1170
|
+
extra: params.extra,
|
|
1171
|
+
transferMode: params.transferMode,
|
|
1172
|
+
mediaUrl: params.mediaUrl,
|
|
1173
|
+
mediaLocalRoots: params.mediaLocalRoots,
|
|
1174
|
+
asVoice: params.asVoice,
|
|
1175
|
+
audioAsVoice: params.audioAsVoice,
|
|
1176
|
+
downloadMedia: params.downloadMedia,
|
|
1213
1177
|
});
|
|
1214
1178
|
}
|
|
1215
1179
|
|
|
@@ -1243,29 +1207,55 @@ class BncrBridgeRuntime {
|
|
|
1243
1207
|
|
|
1244
1208
|
private buildFileTransferOutboundFrame(params: {
|
|
1245
1209
|
entry: OutboxEntry;
|
|
1246
|
-
|
|
1210
|
+
msg: Record<string, unknown>;
|
|
1247
1211
|
media: { fileName?: string; mimeType?: string; path?: string; base64?: string; type?: string };
|
|
1248
1212
|
mediaUrl: string;
|
|
1249
1213
|
}) {
|
|
1250
|
-
const wantsVoice = params.
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
? params.meta.messageKind
|
|
1214
|
+
const wantsVoice = params.msg.asVoice === true || params.msg.audioAsVoice === true;
|
|
1215
|
+
const rawKind = params.msg.kind ?? (params.msg as Record<string, unknown>).messageKind;
|
|
1216
|
+
const messageKind: 'tool' | 'block' | 'final' | undefined =
|
|
1217
|
+
rawKind === 'tool' || rawKind === 'block' || rawKind === 'final'
|
|
1218
|
+
? (rawKind as 'tool' | 'block' | 'final')
|
|
1256
1219
|
: undefined;
|
|
1257
1220
|
|
|
1258
1221
|
const hasPayload = !!(params.media.base64 || params.media.path);
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1222
|
+
this.logInfoJson(
|
|
1223
|
+
'outbound',
|
|
1224
|
+
'media-frame',
|
|
1225
|
+
{
|
|
1226
|
+
mid: params.entry.messageId,
|
|
1227
|
+
mode: hasPayload ? (params.media.path ? 'chunk' : 'base64') : 'pass-through',
|
|
1228
|
+
type: wantsVoice ? 'voice' : asString(params.msg.type || '') || undefined,
|
|
1229
|
+
url: params.mediaUrl.split('?')[0],
|
|
1230
|
+
...(params.media.path ? { path: params.media.path } : {}),
|
|
1231
|
+
...(params.media.base64 ? { base64: true } : {}),
|
|
1232
|
+
},
|
|
1233
|
+
{ debugOnly: true },
|
|
1234
|
+
);
|
|
1235
|
+
// Collect non-control fields from msg for passthrough into message.*
|
|
1236
|
+
const MSG_PASSTHROUGH_KEYS = new Set([
|
|
1237
|
+
'platform',
|
|
1238
|
+
'groupId',
|
|
1239
|
+
'userId',
|
|
1240
|
+
'mediaUrl',
|
|
1241
|
+
'mediaLocalRoots',
|
|
1242
|
+
'asVoice',
|
|
1243
|
+
'audioAsVoice',
|
|
1244
|
+
'downloadMedia',
|
|
1245
|
+
'transferMode',
|
|
1246
|
+
'path',
|
|
1247
|
+
'base64',
|
|
1248
|
+
'fileName',
|
|
1249
|
+
'kind',
|
|
1250
|
+
'replyToId',
|
|
1251
|
+
]);
|
|
1252
|
+
const passthroughExtra: Record<string, unknown> = {};
|
|
1253
|
+
for (const [key, value] of Object.entries(params.msg)) {
|
|
1254
|
+
if (!MSG_PASSTHROUGH_KEYS.has(key) && value !== undefined) {
|
|
1255
|
+
passthroughExtra[key] = value;
|
|
1256
|
+
}
|
|
1268
1257
|
}
|
|
1258
|
+
|
|
1269
1259
|
return buildBncrMediaOutboundFrame({
|
|
1270
1260
|
messageId: params.entry.messageId,
|
|
1271
1261
|
sessionKey: params.entry.sessionKey,
|
|
@@ -1278,16 +1268,16 @@ class BncrBridgeRuntime {
|
|
|
1278
1268
|
path: params.media.path,
|
|
1279
1269
|
},
|
|
1280
1270
|
mediaUrl: params.mediaUrl,
|
|
1281
|
-
mediaMsg: asString(params.
|
|
1271
|
+
mediaMsg: asString(params.msg.msg ?? ''),
|
|
1282
1272
|
fileName: resolveOutboundFileName({
|
|
1283
1273
|
mediaUrl: params.mediaUrl,
|
|
1284
1274
|
fileName: params.media.fileName,
|
|
1285
1275
|
mimeType: params.media.mimeType,
|
|
1286
1276
|
}),
|
|
1287
|
-
hintedType: wantsVoice ? 'voice' : asString(params.
|
|
1288
|
-
extra:
|
|
1277
|
+
hintedType: wantsVoice ? 'voice' : asString(params.msg.type || '') || undefined,
|
|
1278
|
+
extra: Object.keys(passthroughExtra).length > 0 ? passthroughExtra : undefined,
|
|
1289
1279
|
kind: messageKind,
|
|
1290
|
-
replyToId: normalizeReplyToId(params.
|
|
1280
|
+
replyToId: normalizeReplyToId(asString(params.msg.replyToId || '')) || undefined,
|
|
1291
1281
|
now: now(),
|
|
1292
1282
|
});
|
|
1293
1283
|
}
|
|
@@ -1296,66 +1286,8 @@ class BncrBridgeRuntime {
|
|
|
1296
1286
|
// This is the core outbound state machine: build entries, enqueue them,
|
|
1297
1287
|
// push them, observe ACK outcomes, and terminate in retry or dead-letter.
|
|
1298
1288
|
|
|
1299
|
-
private buildTextOutboxEntry(params: {
|
|
1300
|
-
accountId: string;
|
|
1301
|
-
sessionKey: string;
|
|
1302
|
-
route: BncrRoute;
|
|
1303
|
-
text: string;
|
|
1304
|
-
extra?: Record<string, unknown>;
|
|
1305
|
-
kind?: 'tool' | 'block' | 'final';
|
|
1306
|
-
replyToId?: string;
|
|
1307
|
-
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
1308
|
-
downloadMedia?: boolean;
|
|
1309
|
-
}): OutboxEntry {
|
|
1310
|
-
return buildTextOutboxEntryFromRuntime({
|
|
1311
|
-
createMessageId: () => randomUUID(),
|
|
1312
|
-
now,
|
|
1313
|
-
normalizeAccountId,
|
|
1314
|
-
normalizeReplyToId,
|
|
1315
|
-
accountId: params.accountId,
|
|
1316
|
-
sessionKey: params.sessionKey,
|
|
1317
|
-
route: params.route,
|
|
1318
|
-
text: params.text,
|
|
1319
|
-
extra: params.extra && Object.keys(params.extra).length > 0 ? { ...params.extra } : undefined,
|
|
1320
|
-
kind: params.kind,
|
|
1321
|
-
replyToId: params.replyToId,
|
|
1322
|
-
replyTargetPolicy: params.replyTargetPolicy,
|
|
1323
|
-
downloadMedia: params.downloadMedia === true ? true : undefined,
|
|
1324
|
-
});
|
|
1325
|
-
}
|
|
1326
|
-
|
|
1327
1289
|
private async tryPushEntry(entry: OutboxEntry): Promise<boolean> {
|
|
1328
|
-
|
|
1329
|
-
if (meta?.kind === 'file-transfer') {
|
|
1330
|
-
return this.tryPushFileTransferEntry(entry, meta);
|
|
1331
|
-
}
|
|
1332
|
-
|
|
1333
|
-
return this.tryPushTextEntry(entry);
|
|
1334
|
-
}
|
|
1335
|
-
|
|
1336
|
-
private pushTextSuccessPath(args: {
|
|
1337
|
-
entry: OutboxEntry;
|
|
1338
|
-
owner: ReturnType<BncrBridgeRuntime['resolveOutboxPushOwner']>;
|
|
1339
|
-
connIds: Iterable<string>;
|
|
1340
|
-
recentInboundReachable: boolean;
|
|
1341
|
-
routeReason: string;
|
|
1342
|
-
ownerConnId?: string;
|
|
1343
|
-
}) {
|
|
1344
|
-
this.outboxPush.pushTextSuccessPath(args);
|
|
1345
|
-
}
|
|
1346
|
-
|
|
1347
|
-
private handleTextPushFailure(args: { entry: OutboxEntry; error: unknown }) {
|
|
1348
|
-
this.outboxPush.handleTextPushFailure(args);
|
|
1349
|
-
}
|
|
1350
|
-
|
|
1351
|
-
// Text outbound push runtime bridge --------------------------------------
|
|
1352
|
-
|
|
1353
|
-
// Outbound diagnostics/logging helpers -----------------------------------
|
|
1354
|
-
// Keep the compact logging helpers adjacent to the outbound state machine so
|
|
1355
|
-
// queue transitions and emitted diagnostics remain easy to correlate.
|
|
1356
|
-
|
|
1357
|
-
private async tryPushTextEntry(entry: OutboxEntry): Promise<boolean> {
|
|
1358
|
-
return await runBncrTextOutboxPush({
|
|
1290
|
+
return runBncrOutboxPush({
|
|
1359
1291
|
entry,
|
|
1360
1292
|
gatewayContext: this.gatewayContext,
|
|
1361
1293
|
owner: this.resolveOutboxPushOwner(entry.accountId),
|
|
@@ -1365,11 +1297,34 @@ class BncrBridgeRuntime {
|
|
|
1365
1297
|
isRevalidatedAttemptedConn: (connId) => this.isRevalidatedAttemptedConn(entry, connId),
|
|
1366
1298
|
recordOutboxPrePushFailure: (flowArgs) => this.recordOutboxPrePushFailure(flowArgs),
|
|
1367
1299
|
logOutboxPushSkip: (flowArgs) => this.logOutboxPushSkip(flowArgs),
|
|
1368
|
-
|
|
1300
|
+
handleFileTransferPushGuardFailure: (flowArgs) =>
|
|
1301
|
+
this.handleFileTransferPushGuardFailure(flowArgs),
|
|
1369
1302
|
handleTextPushFailure: (flowArgs) => this.handleTextPushFailure(flowArgs),
|
|
1303
|
+
handleFileTransferPushFailure: (flowArgs) => this.handleFileTransferPushFailure(flowArgs),
|
|
1304
|
+
// Unified push deps
|
|
1305
|
+
pushEvent: BNCR_PUSH_EVENT,
|
|
1306
|
+
gatewayBroadcastToConnIds: (event, payload, connIds) =>
|
|
1307
|
+
this.gatewayContext?.broadcastToConnIds(event, payload, connIds),
|
|
1308
|
+
recordOutboxPushSuccess: (args) => this.recordOutboxPushSuccess(args),
|
|
1309
|
+
logOutboxRouteSelect: (args) => this.logOutboxRouteSelect(args),
|
|
1310
|
+
logOutboxPushOkSummary: (mid) => this.logOutboxPushOkSummary(mid),
|
|
1311
|
+
logOutboundSummary: (entry) => this.logOutboundSummary(entry),
|
|
1312
|
+
logOutboxPushOk: (args) => this.logOutboxPushOk(args),
|
|
1313
|
+
transferMediaToBncrClient: (params) => this.transferMediaToBncrClient(params),
|
|
1314
|
+
buildFileTransferOutboundFrame: (params) => this.buildFileTransferOutboundFrame(params),
|
|
1370
1315
|
});
|
|
1371
1316
|
}
|
|
1372
1317
|
|
|
1318
|
+
private handleTextPushFailure(args: { entry: OutboxEntry; error: unknown }) {
|
|
1319
|
+
this.outboxPush.handleTextPushFailure(args);
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
// Text outbound push runtime bridge --------------------------------------
|
|
1323
|
+
|
|
1324
|
+
// Outbound diagnostics/logging helpers -----------------------------------
|
|
1325
|
+
// Keep the compact logging helpers adjacent to the outbound state machine so
|
|
1326
|
+
// queue transitions and emitted diagnostics remain easy to correlate.
|
|
1327
|
+
|
|
1373
1328
|
private logOutboxPushSkip(args: {
|
|
1374
1329
|
messageId: string;
|
|
1375
1330
|
accountId: string;
|
|
@@ -1753,8 +1708,12 @@ class BncrBridgeRuntime {
|
|
|
1753
1708
|
clampFiniteNumber(value, fallback, min ?? fallback, max ?? fallback),
|
|
1754
1709
|
normalizeAccountId,
|
|
1755
1710
|
formatDisplayScope,
|
|
1756
|
-
isFileTransferEntry: (entry) =>
|
|
1757
|
-
isPlainObject(entry.payload
|
|
1711
|
+
isFileTransferEntry: (entry) => {
|
|
1712
|
+
const msg = isPlainObject(entry.payload)
|
|
1713
|
+
? (entry.payload as Record<string, unknown>).message
|
|
1714
|
+
: null;
|
|
1715
|
+
return isPlainObject(msg) && (msg as Record<string, unknown>).transferMode === 'media';
|
|
1716
|
+
},
|
|
1758
1717
|
recommendedAckTimeoutMaxMs: RECOMMENDED_ACK_TIMEOUT_MAX_MS,
|
|
1759
1718
|
adaptiveAckTimeoutEnabled: ADAPTIVE_ACK_TIMEOUT_DEFAULT_ENABLED,
|
|
1760
1719
|
defaultAckTimeoutMs: PUSH_ACK_TIMEOUT_MS,
|
|
@@ -2705,8 +2664,7 @@ class BncrBridgeRuntime {
|
|
|
2705
2664
|
logInfo: (scope, message, options) => this.logInfo(scope, message, options),
|
|
2706
2665
|
logEnqueueFromReply: (args) => this.logEnqueueFromReply(args),
|
|
2707
2666
|
enqueueOutbound: (entry) => this.enqueueOutbound(entry),
|
|
2708
|
-
|
|
2709
|
-
buildFileTransferOutboxEntry: (args) => this.buildFileTransferOutboxEntry(args),
|
|
2667
|
+
buildOutboxEntry: (args) => this.buildOutboxEntry(args),
|
|
2710
2668
|
rememberRecentMediaSend: (args) => this.rememberRecentMediaSend(args),
|
|
2711
2669
|
tryBuildMediaDedupeFallback: (args) => this.tryBuildMediaDedupeFallback(args),
|
|
2712
2670
|
});
|
|
@@ -2760,7 +2718,7 @@ class BncrBridgeRuntime {
|
|
|
2760
2718
|
mediaLocalRoots?: readonly string[];
|
|
2761
2719
|
replyTargetPolicy?: OutboundReplyTargetPolicy;
|
|
2762
2720
|
}) {
|
|
2763
|
-
this.bridgeMediaFacade.enqueueFromReply(params);
|
|
2721
|
+
return this.bridgeMediaFacade.enqueueFromReply(params);
|
|
2764
2722
|
}
|
|
2765
2723
|
|
|
2766
2724
|
private logEnqueueFromReply(args: {
|
|
@@ -2800,24 +2758,6 @@ class BncrBridgeRuntime {
|
|
|
2800
2758
|
normalizeAccountId,
|
|
2801
2759
|
});
|
|
2802
2760
|
|
|
2803
|
-
private readonly fileTransferPushFacade = createBncrBridgeFileTransferPushFacade({
|
|
2804
|
-
pushEvent: BNCR_PUSH_EVENT,
|
|
2805
|
-
getGatewayContext: () => this.gatewayContext,
|
|
2806
|
-
transferMediaToBncrClient: (params) => this.transferMediaToBncrClient(params),
|
|
2807
|
-
buildFileTransferOutboundFrame: (params) => this.buildFileTransferOutboundFrame(params),
|
|
2808
|
-
logOutboxRouteSelect: (args) => this.logOutboxRouteSelect(args),
|
|
2809
|
-
recordOutboxPushSuccess: (args) => this.recordOutboxPushSuccess(args),
|
|
2810
|
-
logOutboxPushOkSummary: (messageId) => this.logOutboxPushOkSummary(messageId),
|
|
2811
|
-
logOutboxPushOk: (args) => this.logOutboxPushOk(args),
|
|
2812
|
-
handleFileTransferPushFailure: (args) => this.outboxPush.handleFileTransferPushFailure(args),
|
|
2813
|
-
handleFileTransferPushGuardFailure: (args) =>
|
|
2814
|
-
this.outboxPush.handleFileTransferPushGuardFailure(args),
|
|
2815
|
-
});
|
|
2816
|
-
|
|
2817
|
-
private enqueueReplyMediaEntries(params: ReplyMediaEntriesParams) {
|
|
2818
|
-
this.bridgeMediaFacade.enqueueReplyMediaEntries(params);
|
|
2819
|
-
}
|
|
2820
|
-
|
|
2821
2761
|
// Surface runtime assembly -----------------------------------------------
|
|
2822
2762
|
// The bridge remains the ownership root, but these builders keep the final
|
|
2823
2763
|
// gateway/inbound/channel send wiring readable by concern instead of as one
|
|
@@ -2937,6 +2877,18 @@ class BncrBridgeRuntime {
|
|
|
2937
2877
|
logInfo: (scope, message, options) => this.logInfo(scope, message, options),
|
|
2938
2878
|
...targetRuntime,
|
|
2939
2879
|
listOutboxEntries: () => Array.from(this.outbox.values()),
|
|
2880
|
+
resolveSceneDownloadMedia: (to: string) => {
|
|
2881
|
+
const parts = to.split(':');
|
|
2882
|
+
if (parts.length >= 3) {
|
|
2883
|
+
const key = `${parts[1]}:${parts[2]}`;
|
|
2884
|
+
const sc = this.sceneRegistry.get(key);
|
|
2885
|
+
// Scene boolean wins (including explicit false); else fall to global.
|
|
2886
|
+
if (typeof sc?.downloadMedia === 'boolean') return sc.downloadMedia;
|
|
2887
|
+
const g = this.sceneRegistry.get('__global__');
|
|
2888
|
+
if (typeof g?.downloadMedia === 'boolean') return g.downloadMedia;
|
|
2889
|
+
}
|
|
2890
|
+
return undefined;
|
|
2891
|
+
},
|
|
2940
2892
|
});
|
|
2941
2893
|
}
|
|
2942
2894
|
|
|
@@ -3021,20 +2973,15 @@ class BncrBridgeRuntime {
|
|
|
3021
2973
|
if (ctx.forceDocument === true) extra.forceDocument = true;
|
|
3022
2974
|
if (ctx.gifPlayback === true) extra.gifPlayback = true;
|
|
3023
2975
|
if (ctx.silent === true) extra.silent = true;
|
|
3024
|
-
//
|
|
2976
|
+
// Promote host flags into extra so marker params can override them via mergeMarkerAndHostFields
|
|
3025
2977
|
return { ...ctx, extra, forceDocument: undefined, gifPlayback: undefined, silent: undefined };
|
|
3026
2978
|
}
|
|
3027
2979
|
|
|
3028
2980
|
// Channel send surface assembly ------------------------------------------
|
|
3029
|
-
|
|
3030
|
-
// the final exposed channel* methods for quick top-down scanning.
|
|
3031
|
-
|
|
3032
|
-
private readonly channelSendRuntimeGroup = createBncrChannelSendRuntimeGroup(
|
|
2981
|
+
private readonly channelSendRuntime = createBncrChannelSendRuntime(
|
|
3033
2982
|
this.buildChannelSendRuntime(),
|
|
3034
2983
|
);
|
|
3035
2984
|
|
|
3036
|
-
private readonly channelSendRuntime = this.channelSendRuntimeGroup.channelSendRuntime;
|
|
3037
|
-
|
|
3038
2985
|
channelSendText = async (ctx: BncrChannelSendContext) =>
|
|
3039
2986
|
this.channelSendRuntime.channelSendText(this.mergeHostFields(ctx));
|
|
3040
2987
|
|
package/src/core/accounts.ts
CHANGED
|
@@ -3,16 +3,11 @@ import type {
|
|
|
3
3
|
BncrChannelConfigRoot,
|
|
4
4
|
BncrChannelConfigSection,
|
|
5
5
|
} from '../plugin/channel-runtime-types.ts';
|
|
6
|
+
import { asString } from './value-sanitize.ts';
|
|
6
7
|
|
|
7
8
|
const CHANNEL_ID = 'bncr';
|
|
8
9
|
const BNCR_DEFAULT_ACCOUNT_ID = 'Primary';
|
|
9
10
|
|
|
10
|
-
function asString(v: unknown, fallback = ''): string {
|
|
11
|
-
if (typeof v === 'string') return v;
|
|
12
|
-
if (v == null) return fallback;
|
|
13
|
-
return String(v);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
11
|
export function normalizeAccountId(accountId?: string | null): string {
|
|
17
12
|
const v = asString(accountId || '').trim();
|
|
18
13
|
if (!v) return BNCR_DEFAULT_ACCOUNT_ID;
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import type { BncrConnection, OutboxEntry } from './types.ts';
|
|
2
|
-
|
|
3
|
-
function finiteNumberOr(value: unknown, fallback: number): number {
|
|
4
|
-
const n = Number(value);
|
|
5
|
-
return Number.isFinite(n) ? n : fallback;
|
|
6
|
-
}
|
|
2
|
+
import { finiteNumberOr } from './value-sanitize.ts';
|
|
7
3
|
|
|
8
4
|
export function hasRecentInboundReachability(args: {
|
|
9
5
|
now: number;
|
|
@@ -145,7 +141,7 @@ function scoreOutboundPushConnection(args: {
|
|
|
145
141
|
};
|
|
146
142
|
}
|
|
147
143
|
|
|
148
|
-
|
|
144
|
+
function compareOutboundPushConnections(args: {
|
|
149
145
|
a: BncrConnection;
|
|
150
146
|
b: BncrConnection;
|
|
151
147
|
now: number;
|