@solana/web3.js 1.69.0 → 1.70.0-pr-29130

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solana/web3.js",
3
- "version": "1.69.0",
3
+ "version": "1.70.0-pr-29130",
4
4
  "description": "Solana Javascript API",
5
5
  "keywords": [
6
6
  "api",
@@ -51,7 +51,7 @@
51
51
  "pretty": "prettier --check '{,{src,test}/**/}*.{j,t}s'",
52
52
  "pretty:fix": "prettier --write '{,{src,test}/**/}*.{j,t}s'",
53
53
  "re": "semantic-release --repository-url git@github.com:solana-labs/solana-web3.js.git",
54
- "test": "cross-env TS_NODE_COMPILER_OPTIONS='{ \"module\": \"commonjs\", \"target\": \"es2019\" }' ts-mocha --require esm './test/**/*.test.ts'",
54
+ "test": "cross-env NODE_ENV=test TS_NODE_COMPILER_OPTIONS='{ \"module\": \"commonjs\", \"target\": \"es2019\" }' ts-mocha --require esm './test/**/*.test.ts'",
55
55
  "test:cover": "nyc --reporter=lcov npm run test",
56
56
  "test:live": "TEST_LIVE=1 npm run test",
57
57
  "test:live-with-test-validator": "start-server-and-test 'solana-test-validator --reset --quiet' http://localhost:8899/health test:live"
@@ -62,6 +62,7 @@
62
62
  "@noble/hashes": "^1.1.2",
63
63
  "@noble/secp256k1": "^1.6.3",
64
64
  "@solana/buffer-layout": "^4.0.0",
65
+ "agentkeepalive": "^4.2.1",
65
66
  "bigint-buffer": "^1.1.5",
66
67
  "bn.js": "^5.0.0",
67
68
  "borsh": "^0.7.0",
package/src/connection.ts CHANGED
@@ -1,7 +1,10 @@
1
+ import Agent from 'agentkeepalive';
1
2
  import bs58 from 'bs58';
2
3
  import {Buffer} from 'buffer';
3
4
  // @ts-ignore
4
5
  import fastStableStringify from 'fast-stable-stringify';
6
+ import type {Agent as HttpAgent} from 'http';
7
+ import {Agent as HttpsAgent} from 'https';
5
8
  import {
6
9
  type as pick,
7
10
  number,
@@ -25,7 +28,6 @@ import {Client as RpcWebSocketClient} from 'rpc-websockets';
25
28
  import RpcClient from 'jayson/lib/client/browser';
26
29
  import {JSONRPCError} from 'jayson';
27
30
 
28
- import {AgentManager} from './agent-manager';
29
31
  import {EpochSchedule} from './epoch-schedule';
30
32
  import {SendTransactionError, SolanaJSONRPCError} from './errors';
31
33
  import fetchImpl, {Response} from './fetch-impl';
@@ -1450,11 +1452,49 @@ function createRpcClient(
1450
1452
  customFetch?: FetchFn,
1451
1453
  fetchMiddleware?: FetchMiddleware,
1452
1454
  disableRetryOnRateLimit?: boolean,
1455
+ httpAgent?: HttpAgent | HttpsAgent | false,
1453
1456
  ): RpcClient {
1454
1457
  const fetch = customFetch ? customFetch : fetchImpl;
1455
- let agentManager: AgentManager | undefined;
1456
- if (!process.env.BROWSER) {
1457
- agentManager = new AgentManager(url.startsWith('https:') /* useHttps */);
1458
+ let agent: HttpAgent | HttpsAgent | undefined;
1459
+ if (process.env.BROWSER) {
1460
+ if (httpAgent != null) {
1461
+ console.warn(
1462
+ 'You have supplied an `httpAgent` when creating a `Connection` in a browser environment.' +
1463
+ 'It has been ignored; `httpAgent` is only used in Node environments.',
1464
+ );
1465
+ }
1466
+ } else {
1467
+ if (httpAgent == null) {
1468
+ if (process.env.NODE_ENV !== 'test') {
1469
+ agent = new Agent({
1470
+ // One second fewer than the Solana RPC's keepalive timeout.
1471
+ // Read more: https://github.com/solana-labs/solana/issues/27859#issuecomment-1340097889
1472
+ freeSocketTimeout: 19000,
1473
+ keepAlive: true,
1474
+ maxSockets: 25,
1475
+ });
1476
+ }
1477
+ } else {
1478
+ if (httpAgent !== false) {
1479
+ const isHttps = url.startsWith('https:');
1480
+ if (isHttps && !(httpAgent instanceof HttpsAgent)) {
1481
+ throw new Error(
1482
+ 'The endpoint `' +
1483
+ url +
1484
+ '` can only be paired with an `https.Agent`. You have, instead, supplied an ' +
1485
+ '`http.Agent` through `httpAgent`.',
1486
+ );
1487
+ } else if (!isHttps && httpAgent instanceof HttpsAgent) {
1488
+ throw new Error(
1489
+ 'The endpoint `' +
1490
+ url +
1491
+ '` can only be paired with an `http.Agent`. You have, instead, supplied an ' +
1492
+ '`https.Agent` through `httpAgent`.',
1493
+ );
1494
+ }
1495
+ agent = httpAgent;
1496
+ }
1497
+ }
1458
1498
  }
1459
1499
 
1460
1500
  let fetchWithMiddleware: FetchFn | undefined;
@@ -1477,7 +1517,6 @@ function createRpcClient(
1477
1517
  }
1478
1518
 
1479
1519
  const clientBrowser = new RpcClient(async (request, callback) => {
1480
- const agent = agentManager ? agentManager.requestStart() : undefined;
1481
1520
  const options = {
1482
1521
  method: 'POST',
1483
1522
  body: request,
@@ -1527,8 +1566,6 @@ function createRpcClient(
1527
1566
  }
1528
1567
  } catch (err) {
1529
1568
  if (err instanceof Error) callback(err);
1530
- } finally {
1531
- agentManager && agentManager.requestEnd();
1532
1569
  }
1533
1570
  }, {});
1534
1571
 
@@ -2855,6 +2892,12 @@ export type FetchMiddleware = (
2855
2892
  * Configuration for instantiating a Connection
2856
2893
  */
2857
2894
  export type ConnectionConfig = {
2895
+ /**
2896
+ * An `http.Agent` that will be used to manage socket connections (eg. to implement connection
2897
+ * persistence). Set this to `false` to create a connection that uses no agent. This applies to
2898
+ * Node environments only.
2899
+ */
2900
+ httpAgent?: HttpAgent | HttpsAgent | false;
2858
2901
  /** Optional commitment level */
2859
2902
  commitment?: Commitment;
2860
2903
  /** Optional endpoint URL to the fullnode JSON RPC PubSub WebSocket Endpoint */
@@ -2972,6 +3015,7 @@ export class Connection {
2972
3015
  let fetch;
2973
3016
  let fetchMiddleware;
2974
3017
  let disableRetryOnRateLimit;
3018
+ let httpAgent;
2975
3019
  if (commitmentOrConfig && typeof commitmentOrConfig === 'string') {
2976
3020
  this._commitment = commitmentOrConfig;
2977
3021
  } else if (commitmentOrConfig) {
@@ -2983,6 +3027,7 @@ export class Connection {
2983
3027
  fetch = commitmentOrConfig.fetch;
2984
3028
  fetchMiddleware = commitmentOrConfig.fetchMiddleware;
2985
3029
  disableRetryOnRateLimit = commitmentOrConfig.disableRetryOnRateLimit;
3030
+ httpAgent = commitmentOrConfig.httpAgent;
2986
3031
  }
2987
3032
 
2988
3033
  this._rpcEndpoint = assertEndpointUrl(endpoint);
@@ -2994,6 +3039,7 @@ export class Connection {
2994
3039
  fetch,
2995
3040
  fetchMiddleware,
2996
3041
  disableRetryOnRateLimit,
3042
+ httpAgent,
2997
3043
  );
2998
3044
  this._rpcRequest = createRpcRequest(this._rpcClient);
2999
3045
  this._rpcBatchRequest = createRpcBatchRequest(this._rpcClient);
@@ -1,44 +0,0 @@
1
- import http from 'http';
2
- import https from 'https';
3
-
4
- export const DESTROY_TIMEOUT_MS = 5000;
5
-
6
- export class AgentManager {
7
- _agent: http.Agent | https.Agent;
8
- _activeRequests = 0;
9
- _destroyTimeout: ReturnType<typeof setTimeout> | null = null;
10
- _useHttps: boolean;
11
-
12
- static _newAgent(useHttps: boolean): http.Agent | https.Agent {
13
- const options = {keepAlive: true, maxSockets: 25};
14
- if (useHttps) {
15
- return new https.Agent(options);
16
- } else {
17
- return new http.Agent(options);
18
- }
19
- }
20
-
21
- constructor(useHttps?: boolean) {
22
- this._useHttps = useHttps === true;
23
- this._agent = AgentManager._newAgent(this._useHttps);
24
- }
25
-
26
- requestStart(): http.Agent | https.Agent {
27
- this._activeRequests++;
28
- if (this._destroyTimeout !== null) {
29
- clearTimeout(this._destroyTimeout);
30
- this._destroyTimeout = null;
31
- }
32
- return this._agent;
33
- }
34
-
35
- requestEnd() {
36
- this._activeRequests--;
37
- if (this._activeRequests === 0 && this._destroyTimeout === null) {
38
- this._destroyTimeout = setTimeout(() => {
39
- this._agent.destroy();
40
- this._agent = AgentManager._newAgent(this._useHttps);
41
- }, DESTROY_TIMEOUT_MS);
42
- }
43
- }
44
- }