@bithomp/xrpl-api 3.7.2 → 3.7.4

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/lib/client.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Connection, ConnectionOptions } from "./connection";
2
+ import { LedgerIndex } from "./models/ledger";
2
3
  export * from "./ledger";
3
4
  export declare let feeCushion: number;
4
5
  export declare let logger: any;
@@ -21,3 +22,4 @@ export declare function connect(): Promise<void>;
21
22
  export declare function disconnect(): Promise<void>;
22
23
  export declare function getNativeCurrency(): string;
23
24
  export declare function findConnection(type?: string, url?: string, strongFilter?: boolean, hash?: string, networkID?: number): Connection | null;
25
+ export declare function findConnectionByLedger(ledgerIndex?: LedgerIndex, ledgerHash?: string, networkID?: number): Connection | null;
package/lib/client.js CHANGED
@@ -20,6 +20,7 @@ exports.connect = connect;
20
20
  exports.disconnect = disconnect;
21
21
  exports.getNativeCurrency = getNativeCurrency;
22
22
  exports.findConnection = findConnection;
23
+ exports.findConnectionByLedger = findConnectionByLedger;
23
24
  const connection_1 = require("./connection");
24
25
  const common_1 = require("./common");
25
26
  __exportStar(require("./ledger"), exports);
@@ -149,6 +150,37 @@ function findConnection(type, url, strongFilter, hash, networkID) {
149
150
  connections = connections.sort(sortHelperConnections);
150
151
  return connections[0];
151
152
  }
153
+ function findConnectionByLedger(ledgerIndex, ledgerHash, networkID) {
154
+ if (ledgerHash) {
155
+ return findConnection("history", undefined, false, undefined, networkID);
156
+ }
157
+ if (typeof ledgerIndex === "string" || ledgerIndex === undefined) {
158
+ return findConnection(undefined, undefined, false, undefined, networkID);
159
+ }
160
+ const availableConnections = clientConnections.filter((con) => {
161
+ if (!con.isConnected()) {
162
+ return false;
163
+ }
164
+ if (typeof networkID === "number" && typeof con.getNetworkID() === "number") {
165
+ if (con.getNetworkID() !== networkID) {
166
+ return false;
167
+ }
168
+ }
169
+ return con.isLedgerIndexPresent(ledgerIndex);
170
+ });
171
+ if (availableConnections.length === 0) {
172
+ return findConnection(undefined, undefined, false, undefined, networkID);
173
+ }
174
+ else if (availableConnections.length === 1) {
175
+ return availableConnections[0];
176
+ }
177
+ if (loadBalancing) {
178
+ const index = Math.floor(Math.random() * availableConnections.length);
179
+ return availableConnections[index];
180
+ }
181
+ const sortedConnections = availableConnections.sort(sortHelperConnections);
182
+ return sortedConnections[0];
183
+ }
152
184
  function sortHelperConnections(a, b) {
153
185
  if (a.getLatencyMs() < b.getLatencyMs()) {
154
186
  return -1;
@@ -57,6 +57,7 @@ declare class Connection extends EventEmitter {
57
57
  getLatencyMs(): number;
58
58
  getNetworkID(): number | undefined;
59
59
  isLedgerIndexAvailable(ledgerIndex: any): boolean;
60
+ isLedgerIndexPresent(ledgerIndex: any): boolean;
60
61
  private updateLatency;
61
62
  private reconnect;
62
63
  private removeClient;
package/lib/connection.js CHANGED
@@ -102,8 +102,9 @@ class Connection extends events_1.EventEmitter {
102
102
  url: this.url,
103
103
  error: err?.message || err?.name || err,
104
104
  });
105
+ this.removeClient();
105
106
  }
106
- this.connectionValidation();
107
+ this.connectionValidation("connect");
107
108
  }
108
109
  async disconnect() {
109
110
  this.logger?.debug({
@@ -125,7 +126,16 @@ class Connection extends events_1.EventEmitter {
125
126
  const result = await this._request(request, options);
126
127
  let validResponse = true;
127
128
  if (result?.error) {
128
- if (result.error === "timeout") {
129
+ if (result.error === "slowDown" || result.error === "Unexpected server response: 429") {
130
+ this.logger?.debug({
131
+ service: "Bithomp::XRPL::Connection",
132
+ function: "request",
133
+ url: this.url,
134
+ error: `Received slowdown error, reconnecting...`,
135
+ });
136
+ validResponse = false;
137
+ }
138
+ else if (result.error === "timeout") {
129
139
  const timeouts = this.latency.filter((info) => info.delta >= this.timeout).length;
130
140
  if (timeouts >= 3) {
131
141
  this.logger?.debug({
@@ -135,10 +145,9 @@ class Connection extends events_1.EventEmitter {
135
145
  error: `Too many timeouts (${timeouts}) in last ${this.latency.length} requests, reconnecting...`,
136
146
  });
137
147
  validResponse = false;
138
- this.removeClient();
139
148
  }
140
149
  }
141
- else if (result.error.startsWith("websocket was closed")) {
150
+ else if (result.error.toLowerCase().startsWith("websocket was closed")) {
142
151
  this.logger?.debug({
143
152
  service: "Bithomp::XRPL::Connection",
144
153
  function: "request",
@@ -146,11 +155,13 @@ class Connection extends events_1.EventEmitter {
146
155
  error: "Websocket was closed, reconnecting...",
147
156
  });
148
157
  validResponse = false;
149
- this.removeClient();
150
158
  }
151
159
  }
152
160
  if (validResponse) {
153
- this.connectionValidation();
161
+ this.connectionValidation("request");
162
+ }
163
+ else {
164
+ this.removeClient();
154
165
  }
155
166
  return result;
156
167
  }
@@ -259,6 +270,24 @@ class Connection extends events_1.EventEmitter {
259
270
  }
260
271
  return true;
261
272
  }
273
+ isLedgerIndexPresent(ledgerIndex) {
274
+ if (typeof ledgerIndex !== "number") {
275
+ return true;
276
+ }
277
+ if (!this.serverInfo?.complete_ledgers) {
278
+ return false;
279
+ }
280
+ const completeLedgers = this.serverInfo.complete_ledgers.split("-");
281
+ if (completeLedgers.length !== 2) {
282
+ return true;
283
+ }
284
+ completeLedgers[0] = parseInt(completeLedgers[0], 10);
285
+ completeLedgers[1] = parseInt(completeLedgers[1], 10);
286
+ if (ledgerIndex < completeLedgers[0] || ledgerIndex > completeLedgers[1]) {
287
+ return false;
288
+ }
289
+ return true;
290
+ }
262
291
  updateLatency(delta) {
263
292
  this.latency.push({
264
293
  timestamp: new Date(),
@@ -276,7 +305,6 @@ class Connection extends events_1.EventEmitter {
276
305
  if (!this.shutdown) {
277
306
  this.emit("reconnect");
278
307
  try {
279
- this.emit("disconnected", 1000);
280
308
  this.removeClient();
281
309
  this.resetTypes();
282
310
  this.serverInfoUpdating = false;
@@ -293,15 +321,16 @@ class Connection extends events_1.EventEmitter {
293
321
  error: e.message,
294
322
  });
295
323
  }
296
- this.connectionValidation();
324
+ this.connectionValidation("reconnect");
297
325
  }
298
326
  }
299
- removeClient() {
327
+ removeClient(code = 1000) {
300
328
  try {
301
329
  if (this.client) {
302
330
  this.client.removeAllListeners();
303
331
  this.client.disconnect();
304
332
  this.client = undefined;
333
+ this.emit("disconnected", code);
305
334
  }
306
335
  }
307
336
  catch (_err) {
@@ -327,9 +356,10 @@ class Connection extends events_1.EventEmitter {
327
356
  code,
328
357
  url: this.url,
329
358
  });
330
- this.onlineSince = 0;
331
- this.serverInfo = null;
332
- this.streamsSubscribed = false;
359
+ if (this.client) {
360
+ this.client.removeAllListeners();
361
+ this.client = undefined;
362
+ }
333
363
  this.emit("disconnected", code);
334
364
  });
335
365
  this.client.on("error", (source, message, error) => {
@@ -351,7 +381,6 @@ class Connection extends events_1.EventEmitter {
351
381
  error: err?.message || err?.name || err,
352
382
  });
353
383
  }
354
- this.connectionValidation();
355
384
  });
356
385
  this.client.on("ledgerClosed", (ledgerStream) => {
357
386
  this.onLedgerClosed(ledgerStream);
@@ -466,7 +495,7 @@ class Connection extends events_1.EventEmitter {
466
495
  request.accounts = accounts;
467
496
  }
468
497
  const result = await this.request(request, { skip_subscription_update: true });
469
- if (result.result) {
498
+ if (result.result && !result.error) {
470
499
  this.streamsSubscribed = true;
471
500
  }
472
501
  return result;
@@ -510,7 +539,7 @@ class Connection extends events_1.EventEmitter {
510
539
  else {
511
540
  this.updateServerInfo();
512
541
  }
513
- this.connectionValidation();
542
+ this.connectionValidation("ledgerClosed");
514
543
  }
515
544
  async updateServerInfo() {
516
545
  if (this.serverInfoUpdating || this.shutdown) {
@@ -538,10 +567,11 @@ class Connection extends events_1.EventEmitter {
538
567
  }
539
568
  this.serverInfoUpdating = false;
540
569
  }
541
- connectionValidation() {
570
+ connectionValidation(event) {
542
571
  this.logger?.debug({
543
572
  service: "Bithomp::XRPL::Connection",
544
573
  function: "connectionValidation",
574
+ event,
545
575
  url: this.url,
546
576
  shutdown: this.shutdown,
547
577
  });
@@ -549,17 +579,16 @@ class Connection extends events_1.EventEmitter {
549
579
  clearTimeout(this.connectionWatchTimer);
550
580
  this.connectionWatchTimer = null;
551
581
  }
552
- if (!this.shutdown) {
553
- if (this.streamsSubscribed === false) {
554
- this.subscribe();
555
- }
556
- if (this.serverInfo === null && this.isConnected()) {
557
- this.updateServerInfo();
558
- }
559
- this.connectionWatchTimer = setTimeout(this.bindConnectionWatchTimeout, LEDGER_CLOSED_TIMEOUT);
560
- }
561
- else {
582
+ if (this.shutdown) {
562
583
  this.removeClient();
584
+ return;
585
+ }
586
+ this.connectionWatchTimer = setTimeout(this.bindConnectionWatchTimeout, LEDGER_CLOSED_TIMEOUT);
587
+ if (this.streamsSubscribed === false) {
588
+ this.subscribe();
589
+ }
590
+ if (this.serverInfo === null && this.isConnected()) {
591
+ this.updateServerInfo();
563
592
  }
564
593
  }
565
594
  async connectionWatchTimeout() {
@@ -582,7 +611,7 @@ class Connection extends events_1.EventEmitter {
582
611
  url: this.url,
583
612
  error: e.message,
584
613
  });
585
- this.connectionValidation();
614
+ this.connectionValidation("connectionWatchTimeout");
586
615
  }
587
616
  }
588
617
  }
@@ -40,7 +40,7 @@ const ledger_1 = require("../parse/ledger/ledger");
40
40
  const utils_1 = require("../common/utils");
41
41
  async function getLedger(options = {}) {
42
42
  const formatted = options.legacy === true || options.formatted === true;
43
- const connection = options.connection || Client.findConnection("history");
43
+ const connection = options.connection || Client.findConnectionByLedger(options.ledgerIndex, options.ledgerHash);
44
44
  if (!connection) {
45
45
  throw new Error("There is no connection");
46
46
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bithomp/xrpl-api",
3
- "version": "3.7.2",
3
+ "version": "3.7.4",
4
4
  "description": "A Bithomp JavaScript/TypeScript library for interacting with the XRP Ledger",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
@@ -42,7 +42,7 @@
42
42
  "format": "prettier --write \"src/**/*.ts\" \"src/**/*.js\"",
43
43
  "lint": "eslint",
44
44
  "prepare": "npm run build",
45
- "prepublishOnly": "npm test && npm run lint",
45
+ "-prepublishOnly": "npm test && npm run lint",
46
46
  "preversion": "npm run lint",
47
47
  "version": "npm run format && git add -A src",
48
48
  "postversion": "git push && git push --tags"
@@ -51,7 +51,7 @@
51
51
  "lib/**/*"
52
52
  ],
53
53
  "dependencies": {
54
- "axios": "^1.13.1",
54
+ "axios": "^1.13.2",
55
55
  "base-x": "^5.0.1",
56
56
  "bignumber.js": "^9.3.1",
57
57
  "elliptic": "^6.6.1",
@@ -73,13 +73,13 @@
73
73
  "@typescript-eslint/parser": "^8.46.2",
74
74
  "chai": "^6.2.0",
75
75
  "chai-as-promised": "^8.0.2",
76
- "eslint": "^9.39.0",
76
+ "eslint": "^9.39.1",
77
77
  "eslint-config-prettier": "^10.1.8",
78
78
  "eslint-plugin-chai-friendly": "^1.1.0",
79
79
  "eslint-plugin-import": "^2.32.0",
80
80
  "eslint-plugin-n": "^17.23.1",
81
81
  "eslint-plugin-promise": "^7.2.1",
82
- "mocha": "^11.7.4",
82
+ "mocha": "^11.7.5",
83
83
  "nconf": "^0.13.0",
84
84
  "ts-jest": "^29.4.5",
85
85
  "ts-node": "^10.9.2",