@toon-protocol/connector 3.20.0 → 3.28.6
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/README.md +6 -6
- package/dist/auth/rfc9421/content-digest.d.ts +16 -0
- package/dist/auth/rfc9421/content-digest.d.ts.map +1 -0
- package/dist/auth/rfc9421/content-digest.js +35 -0
- package/dist/auth/rfc9421/content-digest.js.map +1 -0
- package/dist/auth/rfc9421/index.d.ts +9 -0
- package/dist/auth/rfc9421/index.d.ts.map +1 -0
- package/dist/auth/rfc9421/index.js +24 -0
- package/dist/auth/rfc9421/index.js.map +1 -0
- package/dist/auth/rfc9421/sign.d.ts +20 -0
- package/dist/auth/rfc9421/sign.d.ts.map +1 -0
- package/dist/auth/rfc9421/sign.js +43 -0
- package/dist/auth/rfc9421/sign.js.map +1 -0
- package/dist/auth/rfc9421/signature-base.d.ts +21 -0
- package/dist/auth/rfc9421/signature-base.d.ts.map +1 -0
- package/dist/auth/rfc9421/signature-base.js +57 -0
- package/dist/auth/rfc9421/signature-base.js.map +1 -0
- package/dist/auth/rfc9421/verify.d.ts +19 -0
- package/dist/auth/rfc9421/verify.d.ts.map +1 -0
- package/dist/auth/rfc9421/verify.js +215 -0
- package/dist/auth/rfc9421/verify.js.map +1 -0
- package/dist/btp/btp-client-manager.d.ts +1 -1
- package/dist/btp/btp-client-manager.d.ts.map +1 -1
- package/dist/btp/btp-client.d.ts +2 -2
- package/dist/btp/btp-client.d.ts.map +1 -1
- package/dist/btp/btp-client.js.map +1 -1
- package/dist/cli/admin-client-factory.d.ts +10 -0
- package/dist/cli/admin-client-factory.d.ts.map +1 -0
- package/dist/cli/admin-client-factory.js +33 -0
- package/dist/cli/admin-client-factory.js.map +1 -0
- package/dist/cli/commands/app.d.ts +6 -0
- package/dist/cli/commands/app.d.ts.map +1 -0
- package/dist/cli/commands/app.js +132 -0
- package/dist/cli/commands/app.js.map +1 -0
- package/dist/cli/commands/route.d.ts +3 -0
- package/dist/cli/commands/route.d.ts.map +1 -0
- package/dist/cli/commands/route.js +63 -0
- package/dist/cli/commands/route.js.map +1 -0
- package/dist/cli/commands/up.d.ts +3 -0
- package/dist/cli/commands/up.d.ts.map +1 -0
- package/dist/cli/commands/up.js +27 -0
- package/dist/cli/commands/up.js.map +1 -0
- package/dist/cli/index.js +32 -16
- package/dist/cli/index.js.map +1 -1
- package/dist/client/connector-admin-client.d.ts +17 -12
- package/dist/client/connector-admin-client.d.ts.map +1 -1
- package/dist/client/connector-admin-client.js.map +1 -1
- package/dist/config/config-loader.d.ts +0 -3
- package/dist/config/config-loader.d.ts.map +1 -1
- package/dist/config/config-loader.js +41 -161
- package/dist/config/config-loader.js.map +1 -1
- package/dist/config/environment-validator.js +6 -6
- package/dist/config/environment-validator.js.map +1 -1
- package/dist/config/types.d.ts +47 -17
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +93 -1
- package/dist/config/types.js.map +1 -1
- package/dist/core/connector-node.d.ts +13 -1
- package/dist/core/connector-node.d.ts.map +1 -1
- package/dist/core/connector-node.js +279 -171
- package/dist/core/connector-node.js.map +1 -1
- package/dist/core/handlers/http-proxy-handler.d.ts +47 -0
- package/dist/core/handlers/http-proxy-handler.d.ts.map +1 -0
- package/dist/core/handlers/http-proxy-handler.js +223 -0
- package/dist/core/handlers/http-proxy-handler.js.map +1 -0
- package/dist/core/local-delivery-client.js +9 -9
- package/dist/core/local-delivery-client.js.map +1 -1
- package/dist/core/packet-handler.d.ts +7 -0
- package/dist/core/packet-handler.d.ts.map +1 -1
- package/dist/core/packet-handler.js +55 -3
- package/dist/core/packet-handler.js.map +1 -1
- package/dist/core/registry-db-schema.d.ts +2 -1
- package/dist/core/registry-db-schema.d.ts.map +1 -1
- package/dist/core/registry-db-schema.js +9 -0
- package/dist/core/registry-db-schema.js.map +1 -1
- package/dist/core/registry-store.d.ts +1 -0
- package/dist/core/registry-store.d.ts.map +1 -1
- package/dist/core/registry-store.js +6 -4
- package/dist/core/registry-store.js.map +1 -1
- package/dist/core/route-upstream-registry.d.ts +17 -0
- package/dist/core/route-upstream-registry.d.ts.map +1 -0
- package/dist/core/route-upstream-registry.js +51 -0
- package/dist/core/route-upstream-registry.js.map +1 -0
- package/dist/discovery/ilp-peer-info-event.d.ts +22 -0
- package/dist/discovery/ilp-peer-info-event.d.ts.map +1 -0
- package/dist/discovery/ilp-peer-info-event.js +21 -0
- package/dist/discovery/ilp-peer-info-event.js.map +1 -0
- package/dist/discovery/index.d.ts +8 -0
- package/dist/discovery/index.d.ts.map +1 -1
- package/dist/discovery/index.js +16 -1
- package/dist/discovery/index.js.map +1 -1
- package/dist/discovery/self-announce-builder.d.ts +14 -0
- package/dist/discovery/self-announce-builder.d.ts.map +1 -0
- package/dist/discovery/self-announce-builder.js +88 -0
- package/dist/discovery/self-announce-builder.js.map +1 -0
- package/dist/discovery/self-announce-publish.d.ts +17 -0
- package/dist/discovery/self-announce-publish.d.ts.map +1 -0
- package/dist/discovery/self-announce-publish.js +35 -0
- package/dist/discovery/self-announce-publish.js.map +1 -0
- package/dist/discovery/self-announce-service.d.ts +36 -0
- package/dist/discovery/self-announce-service.d.ts.map +1 -0
- package/dist/discovery/self-announce-service.js +118 -0
- package/dist/discovery/self-announce-service.js.map +1 -0
- package/dist/http/admin-api-inventory.d.ts.map +1 -1
- package/dist/http/admin-api-inventory.js +0 -42
- package/dist/http/admin-api-inventory.js.map +1 -1
- package/dist/http/admin-api.d.ts +29 -13
- package/dist/http/admin-api.d.ts.map +1 -1
- package/dist/http/admin-api.js +141 -76
- package/dist/http/admin-api.js.map +1 -1
- package/dist/http/admin-server.d.ts +3 -4
- package/dist/http/admin-server.d.ts.map +1 -1
- package/dist/http/admin-server.js +4 -6
- package/dist/http/admin-server.js.map +1 -1
- package/dist/http/ilp-http-adapter.d.ts +10 -0
- package/dist/http/ilp-http-adapter.d.ts.map +1 -1
- package/dist/http/ilp-http-adapter.js +118 -0
- package/dist/http/ilp-http-adapter.js.map +1 -1
- package/dist/http/types.d.ts +1 -1
- package/dist/http/types.d.ts.map +1 -1
- package/dist/http/x402-greeting.d.ts +46 -0
- package/dist/http/x402-greeting.d.ts.map +1 -0
- package/dist/http/x402-greeting.js +77 -0
- package/dist/http/x402-greeting.js.map +1 -0
- package/dist/lib.d.ts +13 -2
- package/dist/lib.d.ts.map +1 -1
- package/dist/lib.js +41 -1
- package/dist/lib.js.map +1 -1
- package/dist/main.d.ts +3 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +3 -1
- package/dist/main.js.map +1 -1
- package/dist/settlement/channel-manager.d.ts.map +1 -1
- package/dist/settlement/channel-manager.js +1 -1
- package/dist/settlement/channel-manager.js.map +1 -1
- package/dist/settlement/provider/solana-payment-channel-provider.d.ts.map +1 -1
- package/dist/settlement/provider/solana-payment-channel-provider.js +1 -1
- package/dist/settlement/provider/solana-payment-channel-provider.js.map +1 -1
- package/dist/settlement/solana-payment-channel-sdk.d.ts +1 -1
- package/dist/settlement/solana-payment-channel-sdk.d.ts.map +1 -1
- package/dist/settlement/solana-payment-channel-sdk.js +2 -2
- package/dist/settlement/solana-payment-channel-sdk.js.map +1 -1
- package/dist/transport/http-peer-transport.d.ts +46 -0
- package/dist/transport/http-peer-transport.d.ts.map +1 -0
- package/dist/transport/http-peer-transport.js +185 -0
- package/dist/transport/http-peer-transport.js.map +1 -0
- package/dist/transport/index.d.ts +0 -3
- package/dist/transport/index.d.ts.map +1 -1
- package/dist/transport/index.js +1 -8
- package/dist/transport/index.js.map +1 -1
- package/dist/wallet/mnemonic-keys.d.ts +15 -0
- package/dist/wallet/mnemonic-keys.d.ts.map +1 -0
- package/dist/wallet/mnemonic-keys.js +150 -0
- package/dist/wallet/mnemonic-keys.js.map +1 -0
- package/package.json +11 -8
- package/dist/transport/hs-desc-monitor.d.ts +0 -12
- package/dist/transport/hs-desc-monitor.d.ts.map +0 -1
- package/dist/transport/hs-desc-monitor.js +0 -105
- package/dist/transport/hs-desc-monitor.js.map +0 -1
- package/dist/transport/managed-anon-client.d.ts +0 -93
- package/dist/transport/managed-anon-client.d.ts.map +0 -1
- package/dist/transport/managed-anon-client.js +0 -522
- package/dist/transport/managed-anon-client.js.map +0 -1
- package/dist/transport/socks-transport-provider.d.ts +0 -29
- package/dist/transport/socks-transport-provider.d.ts.map +0 -1
- package/dist/transport/socks-transport-provider.js +0 -136
- package/dist/transport/socks-transport-provider.js.map +0 -1
- package/dist/transport/socks-url.d.ts +0 -6
- package/dist/transport/socks-url.d.ts.map +0 -1
- package/dist/transport/socks-url.js +0 -29
- package/dist/transport/socks-url.js.map +0 -1
- package/dist/transport/socks5-connect.d.ts +0 -12
- package/dist/transport/socks5-connect.d.ts.map +0 -1
- package/dist/transport/socks5-connect.js +0 -89
- package/dist/transport/socks5-connect.js.map +0 -1
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.ConnectorNode = void 0;
|
|
4
4
|
const tslib_1 = require("tslib");
|
|
5
5
|
const fs_1 = require("fs");
|
|
6
|
-
const nodePath = tslib_1.__importStar(require("path"));
|
|
7
6
|
const routing_table_1 = require("../routing/routing-table");
|
|
8
7
|
const relation_route_validator_1 = require("../routing/relation-route-validator");
|
|
9
8
|
const btp_client_manager_1 = require("../btp/btp-client-manager");
|
|
@@ -11,7 +10,10 @@ const btp_server_1 = require("../btp/btp-server");
|
|
|
11
10
|
const packet_handler_1 = require("./packet-handler");
|
|
12
11
|
const shared_1 = require("@toon-protocol/shared");
|
|
13
12
|
const types_1 = require("../config/types");
|
|
13
|
+
const route_upstream_registry_1 = require("./route-upstream-registry");
|
|
14
|
+
const http_proxy_handler_1 = require("./handlers/http-proxy-handler");
|
|
14
15
|
const transport_1 = require("../transport");
|
|
16
|
+
const http_peer_transport_1 = require("../transport/http-peer-transport");
|
|
15
17
|
const payment_handler_1 = require("./payment-handler");
|
|
16
18
|
const types_2 = require("../settlement/types");
|
|
17
19
|
const admin_api_1 = require("../http/admin-api");
|
|
@@ -42,14 +44,20 @@ const solana_payment_channel_provider_1 = require("../settlement/provider/solana
|
|
|
42
44
|
const claim_sender_db_schema_1 = require("../settlement/claim-sender-db-schema");
|
|
43
45
|
const inbound_claim_validator_1 = require("../btp/inbound-claim-validator");
|
|
44
46
|
const nip59_claim_wrapper_1 = require("../settlement/privacy/nip59-claim-wrapper");
|
|
47
|
+
const mnemonic_keys_1 = require("../wallet/mnemonic-keys");
|
|
48
|
+
const self_announce_service_1 = require("../discovery/self-announce-service");
|
|
49
|
+
const self_announce_publish_1 = require("../discovery/self-announce-publish");
|
|
45
50
|
const utils_1 = require("@noble/hashes/utils");
|
|
51
|
+
const SELF_ANNOUNCE_PREPARE_TIMEOUT_MS = 30_000;
|
|
46
52
|
const dns_1 = require("dns");
|
|
47
53
|
const package_json_1 = tslib_1.__importDefault(require("../../package.json"));
|
|
48
54
|
class ConnectorNode {
|
|
49
55
|
_config;
|
|
50
56
|
_logger;
|
|
51
57
|
_routingTable;
|
|
58
|
+
_routeTerminationRegistry;
|
|
52
59
|
_btpClientManager;
|
|
60
|
+
_httpPeerClientManager;
|
|
53
61
|
_packetHandler;
|
|
54
62
|
_btpServer;
|
|
55
63
|
_healthServer;
|
|
@@ -73,17 +81,21 @@ class ConnectorNode {
|
|
|
73
81
|
_btpServerStarted = false;
|
|
74
82
|
_defaultSettlementTokenId = 'M2M';
|
|
75
83
|
_transportProvider = null;
|
|
76
|
-
_managedAnonClient = null;
|
|
77
84
|
_transportProviderReady = false;
|
|
78
85
|
_transportType = null;
|
|
79
86
|
_lastTransportHealthy = true;
|
|
80
87
|
_transportHealthInterval = null;
|
|
81
88
|
_transportHealthIntervalMs;
|
|
89
|
+
_mnemonicOverride;
|
|
90
|
+
_mnemonicAccountIndex;
|
|
91
|
+
_selfAnnounceService = null;
|
|
82
92
|
get defaultSettlementTokenId() {
|
|
83
93
|
return this._defaultSettlementTokenId;
|
|
84
94
|
}
|
|
85
95
|
constructor(config, logger, opts) {
|
|
86
96
|
this._transportHealthIntervalMs = opts?.transportHealthIntervalMs ?? 30000;
|
|
97
|
+
this._mnemonicOverride = opts?.mnemonic;
|
|
98
|
+
this._mnemonicAccountIndex = opts?.mnemonicAccountIndex;
|
|
87
99
|
let resolvedConfig;
|
|
88
100
|
try {
|
|
89
101
|
if (typeof config === 'string') {
|
|
@@ -115,22 +127,22 @@ class ConnectorNode {
|
|
|
115
127
|
priority: route.priority,
|
|
116
128
|
}));
|
|
117
129
|
this._routingTable = new routing_table_1.RoutingTable(routingTableEntries, logger.child({ component: 'RoutingTable' }));
|
|
130
|
+
this._routeTerminationRegistry = new route_upstream_registry_1.RouteTerminationRegistry(resolvedConfig.routes.map((route) => ({
|
|
131
|
+
prefix: route.prefix,
|
|
132
|
+
termination: (0, types_1.toRouteTermination)(route),
|
|
133
|
+
})));
|
|
118
134
|
this._btpClientManager = new btp_client_manager_1.BTPClientManager(resolvedConfig.nodeId, logger.child({ component: 'BTPClientManager' }));
|
|
119
|
-
this._btpClientManager.setAgentFactory((
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
}, 'Peer requested SOCKS5 transport but connector has no SOCKS5 provider — refusing to fall through to direct dial');
|
|
129
|
-
throw new Error('SOCKS5 transport requested for peer but no SOCKS5 provider configured');
|
|
130
|
-
}
|
|
131
|
-
return effective === 'socks5' ? this._transportProvider.createAgent(peer.url) : undefined;
|
|
132
|
-
});
|
|
135
|
+
this._btpClientManager.setAgentFactory(() => undefined);
|
|
136
|
+
const httpEgressTransport = {
|
|
137
|
+
createAgent: () => undefined,
|
|
138
|
+
getExternalUrl: () => this._transportProvider?.getExternalUrl() ?? '',
|
|
139
|
+
start: async () => { },
|
|
140
|
+
stop: async () => { },
|
|
141
|
+
healthCheck: async () => this._transportProvider?.healthCheck() ?? true,
|
|
142
|
+
};
|
|
143
|
+
this._httpPeerClientManager = new http_peer_transport_1.HttpPeerClientManager(resolvedConfig.nodeId, logger.child({ component: 'HttpPeerClientManager' }), httpEgressTransport);
|
|
133
144
|
this._packetHandler = new packet_handler_1.PacketHandler(this._routingTable, this._btpClientManager, resolvedConfig.nodeId, logger.child({ component: 'PacketHandler' }));
|
|
145
|
+
this._packetHandler.setHttpEgress(this._httpPeerClientManager);
|
|
134
146
|
this._btpServer = new btp_server_1.BTPServer(logger.child({ component: 'BTPServer' }), this._packetHandler);
|
|
135
147
|
this._packetHandler.setBTPServer(this._btpServer);
|
|
136
148
|
const localDeliveryEnabled = resolvedConfig.localDelivery?.enabled || process.env.LOCAL_DELIVERY_ENABLED === 'true';
|
|
@@ -146,11 +158,35 @@ class ConnectorNode {
|
|
|
146
158
|
};
|
|
147
159
|
this._packetHandler.setLocalDelivery(localDeliveryConfig);
|
|
148
160
|
}
|
|
161
|
+
if (this._routeTerminationRegistry.size > 0) {
|
|
162
|
+
if (localDeliveryEnabled) {
|
|
163
|
+
this._logger.warn({
|
|
164
|
+
event: 'route_termination_proxy_skipped',
|
|
165
|
+
terminatedRoutes: this._routeTerminationRegistry.size,
|
|
166
|
+
reason: 'global_local_delivery_handler_configured',
|
|
167
|
+
}, 'Terminated routes are configured but a global localDelivery.handlerUrl ' +
|
|
168
|
+
'is also enabled; preserving the existing handlerUrl path and NOT ' +
|
|
169
|
+
'installing the per-route HTTP proxy (requires PacketHandler fall-through — human decision)');
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
const proxy = new http_proxy_handler_1.HttpProxyHandler({
|
|
173
|
+
upstreamResolver: this._routeTerminationRegistry.resolveUpstream,
|
|
174
|
+
logger: this._logger,
|
|
175
|
+
});
|
|
176
|
+
this.setLocalDeliveryHandler(proxy.handler);
|
|
177
|
+
this._logger.info({
|
|
178
|
+
event: 'route_termination_proxy_installed',
|
|
179
|
+
terminatedRoutes: this._routeTerminationRegistry.size,
|
|
180
|
+
prefixes: this._routeTerminationRegistry.prefixes(),
|
|
181
|
+
}, 'HttpProxyHandler installed as local-delivery handler for terminated routes');
|
|
182
|
+
}
|
|
183
|
+
}
|
|
149
184
|
this._btpClientManager.setPacketHandler(this._packetHandler);
|
|
150
185
|
this._ilpMetrics = new metrics_registry_1.IlpMetricsRegistry({ collectDefaults: false });
|
|
151
186
|
for (const peer of resolvedConfig.peers) {
|
|
152
187
|
this._ilpMetrics.registerPeer(peer.id);
|
|
153
188
|
this._packetHandler.setPeerRelation(peer.id, peer.relation ?? 'peer');
|
|
189
|
+
this._packetHandler.setPeerProtocol(peer.id, peer.peerProtocol ?? 'btp');
|
|
154
190
|
}
|
|
155
191
|
this._packetHandler.setIlpMetrics(this._ilpMetrics);
|
|
156
192
|
this._healthServer = new health_server_1.HealthServer(logger.child({ component: 'HealthServer' }), this, {
|
|
@@ -234,6 +270,118 @@ class ConnectorNode {
|
|
|
234
270
|
};
|
|
235
271
|
}
|
|
236
272
|
}
|
|
273
|
+
_applyMnemonicSigningMode() {
|
|
274
|
+
const mnemonic = this._mnemonicOverride ?? process.env.TOON_MNEMONIC;
|
|
275
|
+
if (!mnemonic) {
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
const providers = this._config.chainProviders;
|
|
279
|
+
if (!providers || providers.length === 0) {
|
|
280
|
+
this._logger.warn({ event: 'mnemonic_mode_no_chain_providers' }, 'TOON_MNEMONIC is set but no chainProviders are configured; no settlement keys to derive');
|
|
281
|
+
return;
|
|
282
|
+
}
|
|
283
|
+
const keys = (0, mnemonic_keys_1.deriveChainKeysFromMnemonic)(mnemonic, this._mnemonicAccountIndex ?? 0);
|
|
284
|
+
let evmInjected = false;
|
|
285
|
+
let solanaInjected = false;
|
|
286
|
+
let minaInjected = false;
|
|
287
|
+
for (const provider of providers) {
|
|
288
|
+
switch (provider.chainType) {
|
|
289
|
+
case 'evm':
|
|
290
|
+
provider.keyId = keys.evm.privateKey;
|
|
291
|
+
evmInjected = true;
|
|
292
|
+
break;
|
|
293
|
+
case 'solana':
|
|
294
|
+
provider.keyId = keys.solana.privateKey;
|
|
295
|
+
solanaInjected = true;
|
|
296
|
+
break;
|
|
297
|
+
case 'mina':
|
|
298
|
+
provider.keyId = keys.mina.privateKey;
|
|
299
|
+
minaInjected = true;
|
|
300
|
+
break;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
this._logger.info({
|
|
304
|
+
event: 'mnemonic_signing_mode_enabled',
|
|
305
|
+
evm: evmInjected,
|
|
306
|
+
solana: solanaInjected,
|
|
307
|
+
mina: minaInjected,
|
|
308
|
+
evmAddress: evmInjected ? keys.evm.address : undefined,
|
|
309
|
+
solanaAddress: solanaInjected ? keys.solana.address : undefined,
|
|
310
|
+
}, 'Mnemonic signing mode active: derived per-chain settlement keys from TOON_MNEMONIC');
|
|
311
|
+
}
|
|
312
|
+
_resolveNostrSecretKey() {
|
|
313
|
+
const evmProvider = this._config.chainProviders?.find((p) => p.chainType === 'evm');
|
|
314
|
+
const keyId = evmProvider?.keyId;
|
|
315
|
+
if (keyId && /^(0x)?[0-9a-fA-F]{64}$/.test(keyId)) {
|
|
316
|
+
return (0, utils_1.hexToBytes)(keyId.replace(/^0x/, ''));
|
|
317
|
+
}
|
|
318
|
+
const mnemonic = this._mnemonicOverride ?? process.env.TOON_MNEMONIC;
|
|
319
|
+
if (mnemonic) {
|
|
320
|
+
try {
|
|
321
|
+
const keys = (0, mnemonic_keys_1.deriveChainKeysFromMnemonic)(mnemonic, this._mnemonicAccountIndex ?? 0);
|
|
322
|
+
return (0, utils_1.hexToBytes)(keys.evm.privateKey.replace(/^0x/, ''));
|
|
323
|
+
}
|
|
324
|
+
catch (err) {
|
|
325
|
+
this._logger.warn({
|
|
326
|
+
event: 'self_announce_key_derive_failed',
|
|
327
|
+
err: err instanceof Error ? err.message : String(err),
|
|
328
|
+
}, 'Failed to derive Nostr key for self-announce');
|
|
329
|
+
return null;
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
_startSelfAnnounce() {
|
|
335
|
+
const selfAnnounce = this._config.selfAnnounce;
|
|
336
|
+
if (!selfAnnounce?.enabled) {
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const secretKey = this._resolveNostrSecretKey();
|
|
340
|
+
if (!secretKey) {
|
|
341
|
+
this._logger.warn({ event: 'self_announce_no_identity' }, 'selfAnnounce.enabled but no Nostr signing identity (set TOON_MNEMONIC or an EVM keyId); not announcing');
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
try {
|
|
345
|
+
this._selfAnnounceService = new self_announce_service_1.SelfAnnounceService({
|
|
346
|
+
config: this._config,
|
|
347
|
+
selfAnnounce,
|
|
348
|
+
secretKey,
|
|
349
|
+
publish: (event) => this._publishAnnouncement(event),
|
|
350
|
+
logger: this._logger,
|
|
351
|
+
});
|
|
352
|
+
this._selfAnnounceService.start();
|
|
353
|
+
}
|
|
354
|
+
catch (err) {
|
|
355
|
+
this._selfAnnounceService = null;
|
|
356
|
+
this._logger.warn({
|
|
357
|
+
event: 'self_announce_start_failed',
|
|
358
|
+
err: err instanceof Error ? err.message : String(err),
|
|
359
|
+
}, 'Failed to start self-announce service; continuing without it');
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
async _publishAnnouncement(event) {
|
|
363
|
+
const selfAnnounce = this._config.selfAnnounce;
|
|
364
|
+
const announceTo = selfAnnounce.announceTo;
|
|
365
|
+
const isLocallyTerminated = this._routeTerminationRegistry.match(announceTo) !== undefined;
|
|
366
|
+
const plan = (0, self_announce_publish_1.planAnnouncePublish)({
|
|
367
|
+
announceTo,
|
|
368
|
+
event,
|
|
369
|
+
isLocallyTerminated,
|
|
370
|
+
...(selfAnnounce.announcePrice ? { remotePriceAtomic: selfAnnounce.announcePrice } : {}),
|
|
371
|
+
});
|
|
372
|
+
const expiresAt = new Date(Date.now() + SELF_ANNOUNCE_PREPARE_TIMEOUT_MS);
|
|
373
|
+
const response = await this.sendPacket({
|
|
374
|
+
destination: plan.destination,
|
|
375
|
+
amount: plan.amount,
|
|
376
|
+
expiresAt,
|
|
377
|
+
data: plan.data,
|
|
378
|
+
});
|
|
379
|
+
if (response.type === shared_1.PacketType.FULFILL) {
|
|
380
|
+
return { mode: plan.mode, ok: true };
|
|
381
|
+
}
|
|
382
|
+
const reject = response;
|
|
383
|
+
return { mode: plan.mode, ok: false, detail: `${reject.code}: ${reject.message ?? ''}`.trim() };
|
|
384
|
+
}
|
|
237
385
|
async start() {
|
|
238
386
|
this._logger.info({
|
|
239
387
|
event: 'connector_starting',
|
|
@@ -243,6 +391,7 @@ class ConnectorNode {
|
|
|
243
391
|
}, 'Starting connector node');
|
|
244
392
|
try {
|
|
245
393
|
(0, types_1.validateChainProviders)(this._config, this._logger);
|
|
394
|
+
this._applyMnemonicSigningMode();
|
|
246
395
|
const createdProvider = this._createTransportProvider(this._config.transport);
|
|
247
396
|
this._transportProvider = createdProvider;
|
|
248
397
|
this._transportType =
|
|
@@ -716,6 +865,15 @@ class ConnectorNode {
|
|
|
716
865
|
else {
|
|
717
866
|
this._logger.info({ event: 'payment_channels_disabled' }, 'Payment channel infrastructure disabled (missing configuration)');
|
|
718
867
|
}
|
|
868
|
+
const terminationChainIds = {};
|
|
869
|
+
for (const cp of this._config.chainProviders ?? []) {
|
|
870
|
+
if (cp.chainType === 'evm' && !terminationChainIds.evm) {
|
|
871
|
+
terminationChainIds.evm = cp.chainId;
|
|
872
|
+
}
|
|
873
|
+
else if (cp.chainType === 'solana' && !terminationChainIds.solana) {
|
|
874
|
+
terminationChainIds.solana = cp.chainId;
|
|
875
|
+
}
|
|
876
|
+
}
|
|
719
877
|
const ilpHttpAdapter = new ilp_http_adapter_1.IlpHttpAdapter({
|
|
720
878
|
logger: this._logger,
|
|
721
879
|
nodeId: this._config.nodeId,
|
|
@@ -724,6 +882,8 @@ class ConnectorNode {
|
|
|
724
882
|
recordClaim: this._claimReceiver
|
|
725
883
|
? (peerId, protocolData) => this._claimReceiver.ingestProtocolData(peerId, protocolData)
|
|
726
884
|
: undefined,
|
|
885
|
+
resolveTermination: (prepare) => this._routeTerminationRegistry.match(prepare.destination) ?? null,
|
|
886
|
+
terminationChainIds,
|
|
727
887
|
});
|
|
728
888
|
this._btpServer.setIlpHttpHandler((req, res) => ilpHttpAdapter.handle(req, res));
|
|
729
889
|
await this._btpServer.start(this._config.btpServerPort);
|
|
@@ -763,11 +923,12 @@ class ConnectorNode {
|
|
|
763
923
|
packetSender: (params) => this.sendPacket(params),
|
|
764
924
|
isReady: () => this._btpServerStarted,
|
|
765
925
|
metricsRegistry: this._ilpMetrics,
|
|
766
|
-
managedAnonClient: this._managedAnonClient ?? undefined,
|
|
767
|
-
transportType: this._transportType ?? 'direct',
|
|
768
926
|
setPeerRelation: (peerId, relation) => this._packetHandler.setPeerRelation(peerId, relation),
|
|
769
927
|
getPeerRelation: (peerId) => this._packetHandler.getPeerRelation(peerId),
|
|
770
928
|
registryStore: this._registryStore ?? undefined,
|
|
929
|
+
httpPeerEgress: this._httpPeerClientManager,
|
|
930
|
+
setPeerProtocol: (peerId, protocol) => this._packetHandler.setPeerProtocol(peerId, protocol),
|
|
931
|
+
routeTerminationRegistry: this._routeTerminationRegistry,
|
|
771
932
|
});
|
|
772
933
|
await this._adminServer.start();
|
|
773
934
|
this._logger.info({
|
|
@@ -782,6 +943,17 @@ class ConnectorNode {
|
|
|
782
943
|
}
|
|
783
944
|
const peerConnections = [];
|
|
784
945
|
for (const peerConfig of this._config.peers) {
|
|
946
|
+
if (peerConfig.peerProtocol === 'ilp-http') {
|
|
947
|
+
const httpPeer = {
|
|
948
|
+
id: peerConfig.id,
|
|
949
|
+
httpUrl: peerConfig.httpUrl,
|
|
950
|
+
httpPath: peerConfig.httpPath,
|
|
951
|
+
authToken: peerConfig.authToken,
|
|
952
|
+
httpTimeoutMs: peerConfig.httpTimeoutMs,
|
|
953
|
+
};
|
|
954
|
+
peerConnections.push(this._httpPeerClientManager.addPeer(httpPeer));
|
|
955
|
+
continue;
|
|
956
|
+
}
|
|
785
957
|
const peer = {
|
|
786
958
|
id: peerConfig.id,
|
|
787
959
|
url: peerConfig.url,
|
|
@@ -829,6 +1001,7 @@ class ConnectorNode {
|
|
|
829
1001
|
await Promise.allSettled(channelCreationPromises);
|
|
830
1002
|
this._logger.info({ event: 'payment_channels_initialized' }, 'Payment channel creation completed');
|
|
831
1003
|
}
|
|
1004
|
+
this._startSelfAnnounce();
|
|
832
1005
|
this._updateHealthStatus();
|
|
833
1006
|
this._logger.info({
|
|
834
1007
|
event: 'connector_ready',
|
|
@@ -877,6 +1050,10 @@ class ConnectorNode {
|
|
|
877
1050
|
nodeId: this._config.nodeId,
|
|
878
1051
|
}, 'Stopping connector node');
|
|
879
1052
|
try {
|
|
1053
|
+
if (this._selfAnnounceService) {
|
|
1054
|
+
this._selfAnnounceService.stop();
|
|
1055
|
+
this._selfAnnounceService = null;
|
|
1056
|
+
}
|
|
880
1057
|
if (this._settlementMonitor) {
|
|
881
1058
|
await this._settlementMonitor.stop();
|
|
882
1059
|
this._logger.info({ event: 'settlement_monitor_stopped' }, 'Settlement monitor stopped');
|
|
@@ -987,133 +1164,19 @@ class ConnectorNode {
|
|
|
987
1164
|
get routingTable() {
|
|
988
1165
|
return this._routingTable;
|
|
989
1166
|
}
|
|
1167
|
+
get routeTerminationRegistry() {
|
|
1168
|
+
return this._routeTerminationRegistry;
|
|
1169
|
+
}
|
|
990
1170
|
get btpClientManager() {
|
|
991
1171
|
return this._btpClientManager;
|
|
992
1172
|
}
|
|
993
1173
|
get transportProvider() {
|
|
994
1174
|
return this._transportProviderReady ? this._transportProvider : null;
|
|
995
1175
|
}
|
|
996
|
-
_createTransportProvider(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
return new transport_1.DirectTransportProvider(externalUrl);
|
|
1001
|
-
}
|
|
1002
|
-
if (cfg.type === 'socks5') {
|
|
1003
|
-
let managedClient;
|
|
1004
|
-
let externalUrl = cfg.externalUrl;
|
|
1005
|
-
if (cfg.managed === true) {
|
|
1006
|
-
let cachedFactory;
|
|
1007
|
-
let prewarmError;
|
|
1008
|
-
const prewarmPromise = (0, transport_1.createDefaultAnonFactory)().then((f) => {
|
|
1009
|
-
cachedFactory = f;
|
|
1010
|
-
}, (err) => {
|
|
1011
|
-
prewarmError = err;
|
|
1012
|
-
});
|
|
1013
|
-
const anonFactory = (opts) => {
|
|
1014
|
-
if (cachedFactory) {
|
|
1015
|
-
return cachedFactory(opts);
|
|
1016
|
-
}
|
|
1017
|
-
if (prewarmError) {
|
|
1018
|
-
if (prewarmError.code === 'MODULE_NOT_FOUND') {
|
|
1019
|
-
throw prewarmError;
|
|
1020
|
-
}
|
|
1021
|
-
throw new Error(`Failed to load optional dependency "@anyone-protocol/anyone-client": ` +
|
|
1022
|
-
`${prewarmError.message ?? String(prewarmError)}`, { cause: prewarmError });
|
|
1023
|
-
}
|
|
1024
|
-
try {
|
|
1025
|
-
const pkg = '@anyone-protocol/anyone-client';
|
|
1026
|
-
const mod = require(pkg);
|
|
1027
|
-
const AnonCtor = mod?.Anon ?? mod?.default?.Anon ?? mod?.default;
|
|
1028
|
-
if (typeof AnonCtor !== 'function') {
|
|
1029
|
-
throw new Error('@anyone-protocol/anyone-client did not export an `Anon` constructor');
|
|
1030
|
-
}
|
|
1031
|
-
cachedFactory = (o) => new AnonCtor(o);
|
|
1032
|
-
return cachedFactory(opts);
|
|
1033
|
-
}
|
|
1034
|
-
catch (err) {
|
|
1035
|
-
const cause = err;
|
|
1036
|
-
if (cause?.code === 'MODULE_NOT_FOUND') {
|
|
1037
|
-
throw cause;
|
|
1038
|
-
}
|
|
1039
|
-
if (cause?.code === 'ERR_REQUIRE_ESM') {
|
|
1040
|
-
throw new Error(`@anyone-protocol/anyone-client is an ESM-only package; ` +
|
|
1041
|
-
`the async lazy-import pre-warm had not completed when the factory ` +
|
|
1042
|
-
`was invoked. This is a timing bug — please file an issue.`, { cause });
|
|
1043
|
-
}
|
|
1044
|
-
throw new Error(`Failed to load optional dependency "@anyone-protocol/anyone-client": ` +
|
|
1045
|
-
`${cause?.message ?? String(err)}`, { cause });
|
|
1046
|
-
}
|
|
1047
|
-
};
|
|
1048
|
-
void prewarmPromise;
|
|
1049
|
-
managedClient = new transport_1.ManagedAnonClient({
|
|
1050
|
-
socksProxy: cfg.socksProxy,
|
|
1051
|
-
hiddenServiceDir: cfg.managedOptions?.hiddenServiceDir,
|
|
1052
|
-
hiddenServicePort: cfg.managedOptions?.hiddenServicePort,
|
|
1053
|
-
controlPort: cfg.managedOptions?.controlPort,
|
|
1054
|
-
binaryPath: cfg.managedOptions?.binaryPath,
|
|
1055
|
-
startupTimeoutMs: cfg.managedOptions?.startupTimeoutMs,
|
|
1056
|
-
stopTimeoutMs: cfg.managedOptions?.stopTimeoutMs,
|
|
1057
|
-
logger: this._logger,
|
|
1058
|
-
anonFactory,
|
|
1059
|
-
});
|
|
1060
|
-
this._managedAnonClient = managedClient;
|
|
1061
|
-
if (externalUrl === 'auto') {
|
|
1062
|
-
externalUrl = 'wss://pending.invalid/btp';
|
|
1063
|
-
}
|
|
1064
|
-
}
|
|
1065
|
-
else if (externalUrl === 'auto') {
|
|
1066
|
-
throw new Error('_createTransportProvider: transport.externalUrl "auto" requires managed: true');
|
|
1067
|
-
}
|
|
1068
|
-
let resolveExternalUrlOnStart;
|
|
1069
|
-
if (cfg.externalUrl === 'auto') {
|
|
1070
|
-
const hsDir = cfg.managedOptions?.hiddenServiceDir;
|
|
1071
|
-
if (!hsDir) {
|
|
1072
|
-
throw new Error('_createTransportProvider: transport.externalUrl "auto" requires managedOptions.hiddenServiceDir');
|
|
1073
|
-
}
|
|
1074
|
-
const hostnameReadDeadlineMs = cfg.managedOptions?.startupTimeoutMs ?? 30_000;
|
|
1075
|
-
const HIDDEN_SERVICE_HOSTNAME_RE = /^[a-z2-7]{16}(?:[a-z2-7]{40})?\.(?:anon|onion)$/;
|
|
1076
|
-
resolveExternalUrlOnStart = async () => {
|
|
1077
|
-
const hostnameFile = nodePath.join(hsDir, 'hostname');
|
|
1078
|
-
const deadline = Date.now() + hostnameReadDeadlineMs;
|
|
1079
|
-
let lastErr;
|
|
1080
|
-
while (Date.now() < deadline) {
|
|
1081
|
-
try {
|
|
1082
|
-
const raw = await fs_1.promises.readFile(hostnameFile, 'utf8');
|
|
1083
|
-
const firstLine = raw.split(/\r?\n/, 1)[0]?.trim() ?? '';
|
|
1084
|
-
const hostname = firstLine;
|
|
1085
|
-
if (!hostname) {
|
|
1086
|
-
lastErr = new Error('hostname file is empty');
|
|
1087
|
-
}
|
|
1088
|
-
else if (!HIDDEN_SERVICE_HOSTNAME_RE.test(hostname)) {
|
|
1089
|
-
lastErr = new Error(`hostname file contents did not match the expected hidden service format ` +
|
|
1090
|
-
`(length=${hostname.length}); ignoring and retrying`);
|
|
1091
|
-
}
|
|
1092
|
-
else {
|
|
1093
|
-
return `wss://${hostname}/btp`;
|
|
1094
|
-
}
|
|
1095
|
-
}
|
|
1096
|
-
catch (err) {
|
|
1097
|
-
lastErr = err;
|
|
1098
|
-
}
|
|
1099
|
-
await new Promise((r) => setTimeout(r, 250));
|
|
1100
|
-
}
|
|
1101
|
-
const reason = lastErr instanceof Error ? lastErr.message : String(lastErr ?? 'unknown');
|
|
1102
|
-
throw new Error(`hidden service hostname file "${hostnameFile}" did not become readable ` +
|
|
1103
|
-
`within ${hostnameReadDeadlineMs}ms (last error: ${reason})`);
|
|
1104
|
-
};
|
|
1105
|
-
}
|
|
1106
|
-
return new transport_1.SocksTransportProvider({
|
|
1107
|
-
socksProxy: cfg.socksProxy,
|
|
1108
|
-
externalUrl,
|
|
1109
|
-
logger: this._logger,
|
|
1110
|
-
managedClient,
|
|
1111
|
-
resolveExternalUrlOnStart,
|
|
1112
|
-
});
|
|
1113
|
-
}
|
|
1114
|
-
const _exhaustive = cfg;
|
|
1115
|
-
throw new Error(`Unsupported transport type: ${JSON.stringify(_exhaustive)} ` +
|
|
1116
|
-
'(Story 35.4 _createTransportProvider exhaustiveness guard)');
|
|
1176
|
+
_createTransportProvider(_cfg) {
|
|
1177
|
+
const externalUrl = `ws://localhost:${this._config.btpServerPort}`;
|
|
1178
|
+
this._logger.debug({ event: 'direct_transport_external_url_synthesized', externalUrl }, 'DirectTransportProvider externalUrl synthesized from btpServerPort (local placeholder)');
|
|
1179
|
+
return new transport_1.DirectTransportProvider(externalUrl);
|
|
1117
1180
|
}
|
|
1118
1181
|
get paymentChannelSDK() {
|
|
1119
1182
|
return this._paymentChannelSDK;
|
|
@@ -1226,29 +1289,38 @@ class ConnectorNode {
|
|
|
1226
1289
|
if (!this._btpServerStarted) {
|
|
1227
1290
|
throw new config_loader_1.ConnectorNotStartedError('Connector is not started. Call start() before registerPeer().');
|
|
1228
1291
|
}
|
|
1292
|
+
const peerProtocol = config.peerProtocol ?? 'btp';
|
|
1293
|
+
if (peerProtocol !== 'btp' && peerProtocol !== 'ilp-http') {
|
|
1294
|
+
throw new Error(`Invalid peerProtocol: must be 'btp' or 'ilp-http' (got '${peerProtocol}')`);
|
|
1295
|
+
}
|
|
1229
1296
|
if (!config.id || typeof config.id !== 'string') {
|
|
1230
1297
|
throw new Error('Missing or invalid peer id');
|
|
1231
1298
|
}
|
|
1232
|
-
if (!config.url || typeof config.url !== 'string') {
|
|
1233
|
-
throw new Error('Missing or invalid peer url');
|
|
1234
|
-
}
|
|
1235
1299
|
if (config.authToken === undefined ||
|
|
1236
1300
|
config.authToken === null ||
|
|
1237
1301
|
typeof config.authToken !== 'string') {
|
|
1238
1302
|
throw new Error('authToken must be a string (can be empty for no auth)');
|
|
1239
1303
|
}
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
|
|
1304
|
+
if (peerProtocol === 'ilp-http') {
|
|
1305
|
+
if (!config.httpUrl || typeof config.httpUrl !== 'string') {
|
|
1306
|
+
throw new Error("peerProtocol 'ilp-http' requires httpUrl (http(s) endpoint)");
|
|
1307
|
+
}
|
|
1308
|
+
if (!/^https?:\/\/.+/.test(config.httpUrl)) {
|
|
1309
|
+
throw new Error('httpUrl must start with http:// or https://');
|
|
1310
|
+
}
|
|
1244
1311
|
}
|
|
1245
|
-
|
|
1246
|
-
config.
|
|
1247
|
-
|
|
1248
|
-
|
|
1312
|
+
else {
|
|
1313
|
+
if (!config.url || typeof config.url !== 'string') {
|
|
1314
|
+
throw new Error('Missing or invalid peer url');
|
|
1315
|
+
}
|
|
1316
|
+
const PLAIN_WS_PREFIX = 'ws' + '://';
|
|
1317
|
+
const SECURE_WS_PREFIX = 'wss' + '://';
|
|
1318
|
+
if (!config.url.startsWith(PLAIN_WS_PREFIX) && !config.url.startsWith(SECURE_WS_PREFIX)) {
|
|
1319
|
+
throw new Error(`URL must start with ${PLAIN_WS_PREFIX} or ${SECURE_WS_PREFIX}`);
|
|
1320
|
+
}
|
|
1249
1321
|
}
|
|
1250
|
-
if (config.transport
|
|
1251
|
-
throw new Error(
|
|
1322
|
+
if (config.transport !== undefined && config.transport !== 'direct') {
|
|
1323
|
+
throw new Error(`Invalid transport: must be 'direct' (got '${String(config.transport)}')`);
|
|
1252
1324
|
}
|
|
1253
1325
|
if (config.relation !== undefined &&
|
|
1254
1326
|
config.relation !== 'parent' &&
|
|
@@ -1286,33 +1358,53 @@ class ConnectorNode {
|
|
|
1286
1358
|
throw new Error(relationValidation.error);
|
|
1287
1359
|
}
|
|
1288
1360
|
}
|
|
1289
|
-
const existingPeers =
|
|
1361
|
+
const existingPeers = peerProtocol === 'ilp-http'
|
|
1362
|
+
? this._httpPeerClientManager.getPeerIds()
|
|
1363
|
+
: this._btpClientManager.getPeerIds();
|
|
1290
1364
|
const isUpdate = existingPeers.includes(config.id);
|
|
1291
1365
|
if (!isUpdate) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1366
|
+
if (peerProtocol === 'ilp-http') {
|
|
1367
|
+
const httpPeer = {
|
|
1368
|
+
id: config.id,
|
|
1369
|
+
httpUrl: config.httpUrl,
|
|
1370
|
+
httpPath: config.httpPath,
|
|
1371
|
+
authToken: config.authToken,
|
|
1372
|
+
httpTimeoutMs: config.httpTimeoutMs,
|
|
1373
|
+
};
|
|
1374
|
+
await this._httpPeerClientManager.addPeer(httpPeer);
|
|
1375
|
+
this._ilpMetrics.registerPeer(config.id);
|
|
1376
|
+
this._logger.info({ event: 'peer_registered', peerId: config.id, peerProtocol, httpUrl: config.httpUrl }, `Registered ILP-over-HTTP peer: ${config.id}`);
|
|
1377
|
+
}
|
|
1378
|
+
else {
|
|
1379
|
+
const peer = {
|
|
1380
|
+
id: config.id,
|
|
1381
|
+
url: config.url,
|
|
1382
|
+
authToken: config.authToken,
|
|
1383
|
+
connected: false,
|
|
1384
|
+
lastSeen: new Date(),
|
|
1385
|
+
transport: config.transport,
|
|
1386
|
+
};
|
|
1387
|
+
await this._btpClientManager.addPeer(peer);
|
|
1388
|
+
this._ilpMetrics.registerPeer(config.id);
|
|
1389
|
+
this._logger.info({
|
|
1390
|
+
event: 'peer_registered',
|
|
1391
|
+
peerId: config.id,
|
|
1392
|
+
url: config.url,
|
|
1393
|
+
transport: config.transport ?? null,
|
|
1394
|
+
}, `Registered peer: ${config.id}`);
|
|
1395
|
+
}
|
|
1308
1396
|
}
|
|
1309
1397
|
else {
|
|
1310
1398
|
this._logger.info({
|
|
1311
1399
|
event: 'peer_reregistered',
|
|
1312
1400
|
peerId: config.id,
|
|
1313
|
-
|
|
1401
|
+
peerProtocol,
|
|
1402
|
+
transport: peerProtocol === 'ilp-http'
|
|
1403
|
+
? null
|
|
1404
|
+
: (this._btpClientManager.getPeerTransport(config.id) ?? null),
|
|
1314
1405
|
}, `Re-registering peer: ${config.id}`);
|
|
1315
1406
|
}
|
|
1407
|
+
this._packetHandler.setPeerProtocol(config.id, peerProtocol);
|
|
1316
1408
|
if (effectiveRoutes) {
|
|
1317
1409
|
for (const route of effectiveRoutes) {
|
|
1318
1410
|
this._routingTable.addRoute(route.prefix, config.id, route.priority ?? 0);
|
|
@@ -1334,7 +1426,9 @@ class ConnectorNode {
|
|
|
1334
1426
|
});
|
|
1335
1427
|
const routes = this._routingTable.getAllRoutes();
|
|
1336
1428
|
const peerRoutes = routes.filter((r) => r.nextHop === config.id);
|
|
1337
|
-
const connected =
|
|
1429
|
+
const connected = peerProtocol === 'ilp-http'
|
|
1430
|
+
? this._httpPeerClientManager.isConnected(config.id)
|
|
1431
|
+
: this._btpClientManager.isConnected(config.id);
|
|
1338
1432
|
const peerInfo = {
|
|
1339
1433
|
id: config.id,
|
|
1340
1434
|
connected,
|
|
@@ -1498,11 +1592,13 @@ class ConnectorNode {
|
|
|
1498
1592
|
});
|
|
1499
1593
|
}
|
|
1500
1594
|
for (const route of this._config.routes) {
|
|
1595
|
+
const termination = (0, types_1.toRouteTermination)(route);
|
|
1501
1596
|
this._registryStore.saveRoute({
|
|
1502
1597
|
prefix: route.prefix,
|
|
1503
1598
|
nextHop: route.nextHop,
|
|
1504
1599
|
priority: route.priority ?? 0,
|
|
1505
1600
|
source: 'config',
|
|
1601
|
+
terminationJson: termination ? JSON.stringify(termination) : undefined,
|
|
1506
1602
|
});
|
|
1507
1603
|
}
|
|
1508
1604
|
const existingPeerIds = new Set(this._btpClientManager.getPeerIds());
|
|
@@ -1544,6 +1640,18 @@ class ConnectorNode {
|
|
|
1544
1640
|
nextHop: route.nextHop,
|
|
1545
1641
|
priority: route.priority,
|
|
1546
1642
|
});
|
|
1643
|
+
if (route.terminationJson) {
|
|
1644
|
+
try {
|
|
1645
|
+
this._routeTerminationRegistry.set(route.prefix, JSON.parse(route.terminationJson));
|
|
1646
|
+
}
|
|
1647
|
+
catch (parseError) {
|
|
1648
|
+
this._logger.warn({
|
|
1649
|
+
event: 'registry_route_termination_replay_failed',
|
|
1650
|
+
prefix: route.prefix,
|
|
1651
|
+
error: parseError instanceof Error ? parseError.message : String(parseError),
|
|
1652
|
+
}, `Failed to restore persisted route termination: ${route.prefix}`);
|
|
1653
|
+
}
|
|
1654
|
+
}
|
|
1547
1655
|
replayedRoutes++;
|
|
1548
1656
|
}
|
|
1549
1657
|
catch (error) {
|