@solana/web3.js 2.0.0-experimental.a3f93f3 → 2.0.0-experimental.ac2f09a

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 CHANGED
@@ -62,8 +62,9 @@ const devnetRpc = createSolanaRpc({ transport: devnetTransport });
62
62
  Now, you can use it to call methods on your RPC server. For instance, here is how you would fetch an account's balance.
63
63
 
64
64
  ```ts
65
- const balanceInLamports = await devnetRpc.getBalance('11111111111111111111111111111111' as Base58EncodedAddress);
66
- console.log('Balance of account 11111111111111111111111111111111 in Lamports', balanceInLamports);
65
+ const systemProgramAddress = '11111111111111111111111111111111' as Base58EncodedAddress;
66
+ const balanceInLamports = await devnetRpc.getBalance(systemProgramAddress).send();
67
+ console.log('Balance of System Program account in Lamports', balanceInLamports);
67
68
  ```
68
69
 
69
70
  ### Transactions
@@ -90,7 +91,7 @@ function handleSubmit() {
90
91
  // Typescript will upcast `address` to `Base58EncodedAddress`.
91
92
  assertIsBase58EncodedAddress(address);
92
93
  // At this point, `address` is a `Base58EncodedAddress` that can be used with the RPC.
93
- const balanceInLamports = await rpc.getBalance(address);
94
+ const balanceInLamports = await rpc.getBalance(address).send();
94
95
  } catch (e) {
95
96
  // `address` turned out not to be a base58-encoded address
96
97
  }
@@ -3,6 +3,11 @@
3
3
  var keys = require('@solana/keys');
4
4
  var rpcCore = require('@solana/rpc-core');
5
5
  var rpcTransport = require('@solana/rpc-transport');
6
+ var fastStableStringify = require('fast-stable-stringify');
7
+
8
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+
10
+ var fastStableStringify__default = /*#__PURE__*/_interopDefault(fastStableStringify);
6
11
 
7
12
  // src/index.ts
8
13
 
@@ -41,12 +46,76 @@ var DEFAULT_RPC_CONFIG = {
41
46
  throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
42
47
  }
43
48
  };
49
+
50
+ // src/rpc.ts
44
51
  function createSolanaRpc(config) {
45
52
  return rpcTransport.createJsonRpc({
46
53
  ...config,
47
54
  api: rpcCore.createSolanaRpcApi(DEFAULT_RPC_CONFIG)
48
55
  });
49
56
  }
57
+
58
+ // src/rpc-request-coalescer.ts
59
+ function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
60
+ let coalescedRequestsByDeduplicationKey;
61
+ return async function makeCoalescedHttpRequest(config) {
62
+ const { payload, signal } = config;
63
+ const deduplicationKey = getDeduplicationKey(payload);
64
+ if (deduplicationKey === void 0) {
65
+ return await transport(config);
66
+ }
67
+ if (!coalescedRequestsByDeduplicationKey) {
68
+ Promise.resolve().then(() => {
69
+ coalescedRequestsByDeduplicationKey = void 0;
70
+ });
71
+ coalescedRequestsByDeduplicationKey = {};
72
+ }
73
+ if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {
74
+ const abortController = new AbortController();
75
+ coalescedRequestsByDeduplicationKey[deduplicationKey] = {
76
+ abortController,
77
+ numConsumers: 0,
78
+ responsePromise: transport({
79
+ ...config,
80
+ signal: abortController.signal
81
+ })
82
+ };
83
+ }
84
+ const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];
85
+ coalescedRequest.numConsumers++;
86
+ if (signal) {
87
+ const responsePromise = coalescedRequest.responsePromise;
88
+ return await new Promise((resolve, reject) => {
89
+ const handleAbort = (e) => {
90
+ signal.removeEventListener("abort", handleAbort);
91
+ coalescedRequest.numConsumers -= 1;
92
+ if (coalescedRequest.numConsumers === 0) {
93
+ const abortController = coalescedRequest.abortController;
94
+ abortController.abort();
95
+ }
96
+ const abortError = new DOMException(e.target.reason, "AbortError");
97
+ reject(abortError);
98
+ };
99
+ signal.addEventListener("abort", handleAbort);
100
+ responsePromise.then(resolve).finally(() => {
101
+ signal.removeEventListener("abort", handleAbort);
102
+ });
103
+ });
104
+ } else {
105
+ return await coalescedRequest.responsePromise;
106
+ }
107
+ };
108
+ }
109
+ function getSolanaRpcPayloadDeduplicationKey(payload) {
110
+ if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
111
+ return;
112
+ }
113
+ if ("jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && "params" in payload) {
114
+ return fastStableStringify__default.default([payload.method, payload.params]);
115
+ }
116
+ }
117
+
118
+ // src/rpc-transport.ts
50
119
  function normalizeHeaders(headers) {
51
120
  const out = {};
52
121
  for (const headerName in headers) {
@@ -55,16 +124,19 @@ function normalizeHeaders(headers) {
55
124
  return out;
56
125
  }
57
126
  function createDefaultRpcTransport(config) {
58
- return rpcTransport.createHttpTransport({
59
- ...config,
60
- headers: {
61
- ...config.headers ? normalizeHeaders(config.headers) : void 0,
62
- ...{
63
- // Keep these headers lowercase so they will override any user-supplied headers above.
64
- "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
127
+ return getRpcTransportWithRequestCoalescing(
128
+ rpcTransport.createHttpTransport({
129
+ ...config,
130
+ headers: {
131
+ ...config.headers ? normalizeHeaders(config.headers) : void 0,
132
+ ...{
133
+ // Keep these headers lowercase so they will override any user-supplied headers above.
134
+ "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
135
+ }
65
136
  }
66
- }
67
- });
137
+ }),
138
+ getSolanaRpcPayloadDeduplicationKey
139
+ );
68
140
  }
69
141
 
70
142
  exports.createDefaultRpcTransport = createDefaultRpcTransport;
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/rpc.ts","../src/rpc-integer-overflow-error.ts","../src/rpc-default-config.ts","../src/rpc-transport.ts"],"names":[],"mappings":";AAAA,cAAc;;;ACAd,SAA2B,0BAA0B;;;ACA9C,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAIzD,YAAY,YAAoB,SAA8B,OAAe;AACzE,UAAM,eAAe,OAAO,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,IAAI,SAAS,QAAQ,CAAC,GAAG,EAAE,KAAK;AAC/F,QAAI,UAAU;AACd,UAAM,YAAY,cAAc;AAChC,UAAM,gBAAgB,cAAc;AACpC,QAAI,aAAa,KAAK,iBAAiB,IAAI;AACvC,gBAAU,cAAc;AAAA,IAC5B,WAAW,aAAa,KAAK,iBAAiB,IAAI;AAC9C,gBAAU,cAAc;AAAA,IAC5B,WAAW,aAAa,KAAK,iBAAiB,IAAI;AAC9C,gBAAU,cAAc;AAAA,IAC5B,OAAO;AACH,gBAAU,cAAc;AAAA,IAC5B;AACA,UAAM,OACF,QAAQ,SAAS,IACX,QACK,MAAM,CAAC,EACP,IAAI,cAAa,OAAO,aAAa,WAAW,IAAI,cAAc,QAAS,EAC3E,KAAK,GAAG,IACb;AACV;AAAA,MACI,OAAO,6BAA6B,0BAC7B,OAAO,cAAc,WAAW,YAAY;AAAA,IAGvD;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,QAAQ;AAAA,EACjB;AAAA,EACA,IAAI,OAAO;AACP,WAAO;AAAA,EACX;AACJ;;;ACnCO,IAAM,qBAAwE;AAAA,EACjF,kBAAkB,YAAY,SAAS,OAAO;AAC1C,UAAM,IAAI,kCAAkC,YAAY,SAAS,KAAK;AAAA,EAC1E;AACJ;;;AFJA,SAAS,qBAAqB;AAGvB,SAAS,gBAAgB,QAAiF;AAC7G,SAAO,cAAgC;AAAA,IACnC,GAAG;AAAA,IACH,KAAK,mBAAmB,kBAAkB;AAAA,EAC9C,CAAC;AACL;;;AGXA,SAAS,2BAA2B;AAMpC,SAAS,iBACL,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;AAEO,SAAS,0BAA0B,QAAkE;AACxG,SAAO,oBAAoB;AAAA,IACvB,GAAG;AAAA,IACH,SAAS;AAAA,MACL,GAAI,OAAO,UAAU,iBAAiB,OAAO,OAAO,IAAI;AAAA,MACxD,GAAI;AAAA;AAAA,QAEA,iBAAiB,MAAM,yBAAiB;AAAA,MAC5C;AAAA,IACJ;AAAA,EACJ,CAAC;AACL","sourcesContent":["export * from '@solana/keys';\nexport * from './rpc';\nexport * from './rpc-transport';\n","import { SolanaRpcMethods, createSolanaRpcApi } from '@solana/rpc-core';\nimport { DEFAULT_RPC_CONFIG } from './rpc-default-config';\n\nimport { createJsonRpc } from '@solana/rpc-transport';\nimport type { Rpc } from '@solana/rpc-transport/dist/types/json-rpc-types';\n\nexport function createSolanaRpc(config: Omit<Parameters<typeof createJsonRpc>[0], 'api'>): Rpc<SolanaRpcMethods> {\n return createJsonRpc<SolanaRpcMethods>({\n ...config,\n api: createSolanaRpcApi(DEFAULT_RPC_CONFIG),\n });\n}\n","export class SolanaJsonRpcIntegerOverflowError extends Error {\n readonly methodName: string;\n readonly keyPath: (number | string)[];\n readonly value: bigint;\n constructor(methodName: string, keyPath: (number | string)[], value: bigint) {\n const argPosition = (typeof keyPath[0] === 'number' ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;\n let ordinal = '';\n const lastDigit = argPosition % 10;\n const lastTwoDigits = argPosition % 100;\n if (lastDigit == 1 && lastTwoDigits != 11) {\n ordinal = argPosition + 'st';\n } else if (lastDigit == 2 && lastTwoDigits != 12) {\n ordinal = argPosition + 'nd';\n } else if (lastDigit == 3 && lastTwoDigits != 13) {\n ordinal = argPosition + 'rd';\n } else {\n ordinal = argPosition + 'th';\n }\n const path =\n keyPath.length > 1\n ? keyPath\n .slice(1)\n .map(pathPart => (typeof pathPart === 'number' ? `[${pathPart}]` : pathPart))\n .join('.')\n : null;\n super(\n `The ${ordinal} argument to the \\`${methodName}\\` RPC method` +\n `${path ? ` at path \\`${path}\\`` : ''} was \\`${value}\\`. This number is ` +\n 'unsafe for use with the Solana JSON-RPC because it exceeds ' +\n '`Number.MAX_SAFE_INTEGER`.'\n );\n this.keyPath = keyPath;\n this.methodName = methodName;\n this.value = value;\n }\n get name() {\n return 'SolanaJsonRpcIntegerOverflowError';\n }\n}\n","import { createSolanaRpcApi } from '@solana/rpc-core';\nimport { SolanaJsonRpcIntegerOverflowError } from './rpc-integer-overflow-error';\n\nexport const DEFAULT_RPC_CONFIG: Partial<Parameters<typeof createSolanaRpcApi>[0]> = {\n onIntegerOverflow(methodName, keyPath, value) {\n throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);\n },\n};\n","import { createHttpTransport } from '@solana/rpc-transport';\nimport { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers.\n */\nfunction normalizeHeaders<T extends Record<string, string>>(\n headers: T\n): { [K in keyof T & string as Lowercase<K>]: T[K] } {\n const out: Record<string, string> = {};\n for (const headerName in headers) {\n out[headerName.toLowerCase()] = headers[headerName];\n }\n return out as { [K in keyof T & string as Lowercase<K>]: T[K] };\n}\n\nexport function createDefaultRpcTransport(config: Parameters<typeof createHttpTransport>[0]): IRpcTransport {\n return createHttpTransport({\n ...config,\n headers: {\n ...(config.headers ? normalizeHeaders(config.headers) : undefined),\n ...({\n // Keep these headers lowercase so they will override any user-supplied headers above.\n 'solana-client': `js/${__VERSION__}` ?? 'UNKNOWN',\n } as { [overrideHeader: string]: string }),\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/rpc.ts","../src/rpc-integer-overflow-error.ts","../src/rpc-default-config.ts","../src/rpc-transport.ts","../src/rpc-request-coalescer.ts","../src/rpc-request-deduplication.ts"],"names":[],"mappings":"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","sourcesContent":["export * from '@solana/keys';\nexport * from './rpc';\nexport * from './rpc-transport';\n","import { createSolanaRpcApi, SolanaRpcMethods } from '@solana/rpc-core';\nimport { createJsonRpc } from '@solana/rpc-transport';\nimport type { Rpc } from '@solana/rpc-transport/dist/types/json-rpc-types';\n\nimport { DEFAULT_RPC_CONFIG } from './rpc-default-config';\n\nexport function createSolanaRpc(config: Omit<Parameters<typeof createJsonRpc>[0], 'api'>): Rpc<SolanaRpcMethods> {\n return createJsonRpc<SolanaRpcMethods>({\n ...config,\n api: createSolanaRpcApi(DEFAULT_RPC_CONFIG),\n });\n}\n","export class SolanaJsonRpcIntegerOverflowError extends Error {\n readonly methodName: string;\n readonly keyPath: (number | string)[];\n readonly value: bigint;\n constructor(methodName: string, keyPath: (number | string)[], value: bigint) {\n const argPosition = (typeof keyPath[0] === 'number' ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;\n let ordinal = '';\n const lastDigit = argPosition % 10;\n const lastTwoDigits = argPosition % 100;\n if (lastDigit == 1 && lastTwoDigits != 11) {\n ordinal = argPosition + 'st';\n } else if (lastDigit == 2 && lastTwoDigits != 12) {\n ordinal = argPosition + 'nd';\n } else if (lastDigit == 3 && lastTwoDigits != 13) {\n ordinal = argPosition + 'rd';\n } else {\n ordinal = argPosition + 'th';\n }\n const path =\n keyPath.length > 1\n ? keyPath\n .slice(1)\n .map(pathPart => (typeof pathPart === 'number' ? `[${pathPart}]` : pathPart))\n .join('.')\n : null;\n super(\n `The ${ordinal} argument to the \\`${methodName}\\` RPC method` +\n `${path ? ` at path \\`${path}\\`` : ''} was \\`${value}\\`. This number is ` +\n 'unsafe for use with the Solana JSON-RPC because it exceeds ' +\n '`Number.MAX_SAFE_INTEGER`.'\n );\n this.keyPath = keyPath;\n this.methodName = methodName;\n this.value = value;\n }\n get name() {\n return 'SolanaJsonRpcIntegerOverflowError';\n }\n}\n","import { createSolanaRpcApi } from '@solana/rpc-core';\n\nimport { SolanaJsonRpcIntegerOverflowError } from './rpc-integer-overflow-error';\n\nexport const DEFAULT_RPC_CONFIG: Partial<Parameters<typeof createSolanaRpcApi>[0]> = {\n onIntegerOverflow(methodName, keyPath, value) {\n throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);\n },\n};\n","import { createHttpTransport } from '@solana/rpc-transport';\nimport { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\nimport { getRpcTransportWithRequestCoalescing } from './rpc-request-coalescer';\nimport { getSolanaRpcPayloadDeduplicationKey } from './rpc-request-deduplication';\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers.\n */\nfunction normalizeHeaders<T extends Record<string, string>>(\n headers: T\n): { [K in keyof T & string as Lowercase<K>]: T[K] } {\n const out: Record<string, string> = {};\n for (const headerName in headers) {\n out[headerName.toLowerCase()] = headers[headerName];\n }\n return out as { [K in keyof T & string as Lowercase<K>]: T[K] };\n}\n\nexport function createDefaultRpcTransport(config: Parameters<typeof createHttpTransport>[0]): IRpcTransport {\n return getRpcTransportWithRequestCoalescing(\n createHttpTransport({\n ...config,\n headers: {\n ...(config.headers ? normalizeHeaders(config.headers) : undefined),\n ...({\n // Keep these headers lowercase so they will override any user-supplied headers above.\n 'solana-client': `js/${__VERSION__}` ?? 'UNKNOWN',\n } as { [overrideHeader: string]: string }),\n },\n }),\n getSolanaRpcPayloadDeduplicationKey\n );\n}\n","import { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\ntype CoalescedRequest = {\n readonly abortController: AbortController;\n numConsumers: number;\n readonly responsePromise: Promise<unknown>;\n};\n\ntype GetDeduplicationKeyFn = (payload: unknown) => string | undefined;\n\nexport function getRpcTransportWithRequestCoalescing(\n transport: IRpcTransport,\n getDeduplicationKey: GetDeduplicationKeyFn\n): IRpcTransport {\n let coalescedRequestsByDeduplicationKey: Record<string, CoalescedRequest> | undefined;\n return async function makeCoalescedHttpRequest<TResponse>(\n config: Parameters<IRpcTransport>[0]\n ): Promise<TResponse> {\n const { payload, signal } = config;\n const deduplicationKey = getDeduplicationKey(payload);\n if (deduplicationKey === undefined) {\n return await transport(config);\n }\n if (!coalescedRequestsByDeduplicationKey) {\n Promise.resolve().then(() => {\n coalescedRequestsByDeduplicationKey = undefined;\n });\n coalescedRequestsByDeduplicationKey = {};\n }\n if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {\n const abortController = new AbortController();\n coalescedRequestsByDeduplicationKey[deduplicationKey] = {\n abortController,\n numConsumers: 0,\n responsePromise: transport<TResponse>({\n ...config,\n signal: abortController.signal,\n }),\n };\n }\n const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];\n coalescedRequest.numConsumers++;\n if (signal) {\n const responsePromise = coalescedRequest.responsePromise as Promise<TResponse>;\n return await new Promise<TResponse>((resolve, reject) => {\n const handleAbort = (e: AbortSignalEventMap['abort']) => {\n signal.removeEventListener('abort', handleAbort);\n coalescedRequest.numConsumers -= 1;\n if (coalescedRequest.numConsumers === 0) {\n const abortController = coalescedRequest.abortController;\n abortController.abort();\n }\n const abortError = new DOMException((e.target as AbortSignal).reason, 'AbortError');\n reject(abortError);\n };\n signal.addEventListener('abort', handleAbort);\n responsePromise.then(resolve).finally(() => {\n signal.removeEventListener('abort', handleAbort);\n });\n });\n } else {\n return (await coalescedRequest.responsePromise) as TResponse;\n }\n };\n}\n","// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport fastStableStringify from 'fast-stable-stringify';\n\nexport function getSolanaRpcPayloadDeduplicationKey(payload: unknown): string | undefined {\n if (payload == null || typeof payload !== 'object' || Array.isArray(payload)) {\n return;\n }\n if ('jsonrpc' in payload && payload.jsonrpc === '2.0' && 'method' in payload && 'params' in payload) {\n return fastStableStringify([payload.method, payload.params]);\n }\n}\n"]}
@@ -1,6 +1,7 @@
1
1
  export * from '@solana/keys';
2
2
  import { createSolanaRpcApi } from '@solana/rpc-core';
3
3
  import { createJsonRpc, createHttpTransport } from '@solana/rpc-transport';
4
+ import fastStableStringify from 'fast-stable-stringify';
4
5
 
5
6
  // src/index.ts
6
7
 
@@ -39,12 +40,76 @@ var DEFAULT_RPC_CONFIG = {
39
40
  throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
40
41
  }
41
42
  };
43
+
44
+ // src/rpc.ts
42
45
  function createSolanaRpc(config) {
43
46
  return createJsonRpc({
44
47
  ...config,
45
48
  api: createSolanaRpcApi(DEFAULT_RPC_CONFIG)
46
49
  });
47
50
  }
51
+
52
+ // src/rpc-request-coalescer.ts
53
+ function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
54
+ let coalescedRequestsByDeduplicationKey;
55
+ return async function makeCoalescedHttpRequest(config) {
56
+ const { payload, signal } = config;
57
+ const deduplicationKey = getDeduplicationKey(payload);
58
+ if (deduplicationKey === void 0) {
59
+ return await transport(config);
60
+ }
61
+ if (!coalescedRequestsByDeduplicationKey) {
62
+ Promise.resolve().then(() => {
63
+ coalescedRequestsByDeduplicationKey = void 0;
64
+ });
65
+ coalescedRequestsByDeduplicationKey = {};
66
+ }
67
+ if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {
68
+ const abortController = new AbortController();
69
+ coalescedRequestsByDeduplicationKey[deduplicationKey] = {
70
+ abortController,
71
+ numConsumers: 0,
72
+ responsePromise: transport({
73
+ ...config,
74
+ signal: abortController.signal
75
+ })
76
+ };
77
+ }
78
+ const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];
79
+ coalescedRequest.numConsumers++;
80
+ if (signal) {
81
+ const responsePromise = coalescedRequest.responsePromise;
82
+ return await new Promise((resolve, reject) => {
83
+ const handleAbort = (e) => {
84
+ signal.removeEventListener("abort", handleAbort);
85
+ coalescedRequest.numConsumers -= 1;
86
+ if (coalescedRequest.numConsumers === 0) {
87
+ const abortController = coalescedRequest.abortController;
88
+ abortController.abort();
89
+ }
90
+ const abortError = new DOMException(e.target.reason, "AbortError");
91
+ reject(abortError);
92
+ };
93
+ signal.addEventListener("abort", handleAbort);
94
+ responsePromise.then(resolve).finally(() => {
95
+ signal.removeEventListener("abort", handleAbort);
96
+ });
97
+ });
98
+ } else {
99
+ return await coalescedRequest.responsePromise;
100
+ }
101
+ };
102
+ }
103
+ function getSolanaRpcPayloadDeduplicationKey(payload) {
104
+ if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
105
+ return;
106
+ }
107
+ if ("jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && "params" in payload) {
108
+ return fastStableStringify([payload.method, payload.params]);
109
+ }
110
+ }
111
+
112
+ // src/rpc-transport.ts
48
113
  function normalizeHeaders(headers) {
49
114
  const out = {};
50
115
  for (const headerName in headers) {
@@ -53,18 +118,19 @@ function normalizeHeaders(headers) {
53
118
  return out;
54
119
  }
55
120
  function createDefaultRpcTransport(config) {
56
- return createHttpTransport({
57
- ...config,
58
- headers: {
59
- ...config.headers ? normalizeHeaders(config.headers) : void 0,
60
- ...{
61
- // Keep these headers lowercase so they will override any user-supplied headers above.
62
- "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
121
+ return getRpcTransportWithRequestCoalescing(
122
+ createHttpTransport({
123
+ ...config,
124
+ headers: {
125
+ ...config.headers ? normalizeHeaders(config.headers) : void 0,
126
+ ...{
127
+ // Keep these headers lowercase so they will override any user-supplied headers above.
128
+ "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
129
+ }
63
130
  }
64
- }
65
- });
131
+ }),
132
+ getSolanaRpcPayloadDeduplicationKey
133
+ );
66
134
  }
67
135
 
68
136
  export { createDefaultRpcTransport, createSolanaRpc };
69
- //# sourceMappingURL=out.js.map
70
- //# sourceMappingURL=index.browser.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/rpc.ts","../src/rpc-integer-overflow-error.ts","../src/rpc-default-config.ts","../src/rpc-transport.ts"],"names":[],"mappings":";AAAA,cAAc;;;ACAd,SAA2B,0BAA0B;;;ACA9C,IAAM,oCAAN,cAAgD,MAAM;AAAA,EAIzD,YAAY,YAAoB,SAA8B,OAAe;AACzE,UAAM,eAAe,OAAO,QAAQ,CAAC,MAAM,WAAW,QAAQ,CAAC,IAAI,SAAS,QAAQ,CAAC,GAAG,EAAE,KAAK;AAC/F,QAAI,UAAU;AACd,UAAM,YAAY,cAAc;AAChC,UAAM,gBAAgB,cAAc;AACpC,QAAI,aAAa,KAAK,iBAAiB,IAAI;AACvC,gBAAU,cAAc;AAAA,IAC5B,WAAW,aAAa,KAAK,iBAAiB,IAAI;AAC9C,gBAAU,cAAc;AAAA,IAC5B,WAAW,aAAa,KAAK,iBAAiB,IAAI;AAC9C,gBAAU,cAAc;AAAA,IAC5B,OAAO;AACH,gBAAU,cAAc;AAAA,IAC5B;AACA,UAAM,OACF,QAAQ,SAAS,IACX,QACK,MAAM,CAAC,EACP,IAAI,cAAa,OAAO,aAAa,WAAW,IAAI,cAAc,QAAS,EAC3E,KAAK,GAAG,IACb;AACV;AAAA,MACI,OAAO,6BAA6B,0BAC7B,OAAO,cAAc,WAAW,YAAY;AAAA,IAGvD;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,QAAQ;AAAA,EACjB;AAAA,EACA,IAAI,OAAO;AACP,WAAO;AAAA,EACX;AACJ;;;ACnCO,IAAM,qBAAwE;AAAA,EACjF,kBAAkB,YAAY,SAAS,OAAO;AAC1C,UAAM,IAAI,kCAAkC,YAAY,SAAS,KAAK;AAAA,EAC1E;AACJ;;;AFJA,SAAS,qBAAqB;AAGvB,SAAS,gBAAgB,QAAiF;AAC7G,SAAO,cAAgC;AAAA,IACnC,GAAG;AAAA,IACH,KAAK,mBAAmB,kBAAkB;AAAA,EAC9C,CAAC;AACL;;;AGXA,SAAS,2BAA2B;AAMpC,SAAS,iBACL,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;AAEO,SAAS,0BAA0B,QAAkE;AACxG,SAAO,oBAAoB;AAAA,IACvB,GAAG;AAAA,IACH,SAAS;AAAA,MACL,GAAI,OAAO,UAAU,iBAAiB,OAAO,OAAO,IAAI;AAAA,MACxD,GAAI;AAAA;AAAA,QAEA,iBAAiB,MAAM,yBAAiB;AAAA,MAC5C;AAAA,IACJ;AAAA,EACJ,CAAC;AACL","sourcesContent":["export * from '@solana/keys';\nexport * from './rpc';\nexport * from './rpc-transport';\n","import { SolanaRpcMethods, createSolanaRpcApi } from '@solana/rpc-core';\nimport { DEFAULT_RPC_CONFIG } from './rpc-default-config';\n\nimport { createJsonRpc } from '@solana/rpc-transport';\nimport type { Rpc } from '@solana/rpc-transport/dist/types/json-rpc-types';\n\nexport function createSolanaRpc(config: Omit<Parameters<typeof createJsonRpc>[0], 'api'>): Rpc<SolanaRpcMethods> {\n return createJsonRpc<SolanaRpcMethods>({\n ...config,\n api: createSolanaRpcApi(DEFAULT_RPC_CONFIG),\n });\n}\n","export class SolanaJsonRpcIntegerOverflowError extends Error {\n readonly methodName: string;\n readonly keyPath: (number | string)[];\n readonly value: bigint;\n constructor(methodName: string, keyPath: (number | string)[], value: bigint) {\n const argPosition = (typeof keyPath[0] === 'number' ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;\n let ordinal = '';\n const lastDigit = argPosition % 10;\n const lastTwoDigits = argPosition % 100;\n if (lastDigit == 1 && lastTwoDigits != 11) {\n ordinal = argPosition + 'st';\n } else if (lastDigit == 2 && lastTwoDigits != 12) {\n ordinal = argPosition + 'nd';\n } else if (lastDigit == 3 && lastTwoDigits != 13) {\n ordinal = argPosition + 'rd';\n } else {\n ordinal = argPosition + 'th';\n }\n const path =\n keyPath.length > 1\n ? keyPath\n .slice(1)\n .map(pathPart => (typeof pathPart === 'number' ? `[${pathPart}]` : pathPart))\n .join('.')\n : null;\n super(\n `The ${ordinal} argument to the \\`${methodName}\\` RPC method` +\n `${path ? ` at path \\`${path}\\`` : ''} was \\`${value}\\`. This number is ` +\n 'unsafe for use with the Solana JSON-RPC because it exceeds ' +\n '`Number.MAX_SAFE_INTEGER`.'\n );\n this.keyPath = keyPath;\n this.methodName = methodName;\n this.value = value;\n }\n get name() {\n return 'SolanaJsonRpcIntegerOverflowError';\n }\n}\n","import { createSolanaRpcApi } from '@solana/rpc-core';\nimport { SolanaJsonRpcIntegerOverflowError } from './rpc-integer-overflow-error';\n\nexport const DEFAULT_RPC_CONFIG: Partial<Parameters<typeof createSolanaRpcApi>[0]> = {\n onIntegerOverflow(methodName, keyPath, value) {\n throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);\n },\n};\n","import { createHttpTransport } from '@solana/rpc-transport';\nimport { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers.\n */\nfunction normalizeHeaders<T extends Record<string, string>>(\n headers: T\n): { [K in keyof T & string as Lowercase<K>]: T[K] } {\n const out: Record<string, string> = {};\n for (const headerName in headers) {\n out[headerName.toLowerCase()] = headers[headerName];\n }\n return out as { [K in keyof T & string as Lowercase<K>]: T[K] };\n}\n\nexport function createDefaultRpcTransport(config: Parameters<typeof createHttpTransport>[0]): IRpcTransport {\n return createHttpTransport({\n ...config,\n headers: {\n ...(config.headers ? normalizeHeaders(config.headers) : undefined),\n ...({\n // Keep these headers lowercase so they will override any user-supplied headers above.\n 'solana-client': `js/${__VERSION__}` ?? 'UNKNOWN',\n } as { [overrideHeader: string]: string }),\n },\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/rpc.ts","../src/rpc-integer-overflow-error.ts","../src/rpc-default-config.ts","../src/rpc-transport.ts","../src/rpc-request-coalescer.ts","../src/rpc-request-deduplication.ts"],"names":[],"mappings":"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","sourcesContent":["export * from '@solana/keys';\nexport * from './rpc';\nexport * from './rpc-transport';\n","import { createSolanaRpcApi, SolanaRpcMethods } from '@solana/rpc-core';\nimport { createJsonRpc } from '@solana/rpc-transport';\nimport type { Rpc } from '@solana/rpc-transport/dist/types/json-rpc-types';\n\nimport { DEFAULT_RPC_CONFIG } from './rpc-default-config';\n\nexport function createSolanaRpc(config: Omit<Parameters<typeof createJsonRpc>[0], 'api'>): Rpc<SolanaRpcMethods> {\n return createJsonRpc<SolanaRpcMethods>({\n ...config,\n api: createSolanaRpcApi(DEFAULT_RPC_CONFIG),\n });\n}\n","export class SolanaJsonRpcIntegerOverflowError extends Error {\n readonly methodName: string;\n readonly keyPath: (number | string)[];\n readonly value: bigint;\n constructor(methodName: string, keyPath: (number | string)[], value: bigint) {\n const argPosition = (typeof keyPath[0] === 'number' ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;\n let ordinal = '';\n const lastDigit = argPosition % 10;\n const lastTwoDigits = argPosition % 100;\n if (lastDigit == 1 && lastTwoDigits != 11) {\n ordinal = argPosition + 'st';\n } else if (lastDigit == 2 && lastTwoDigits != 12) {\n ordinal = argPosition + 'nd';\n } else if (lastDigit == 3 && lastTwoDigits != 13) {\n ordinal = argPosition + 'rd';\n } else {\n ordinal = argPosition + 'th';\n }\n const path =\n keyPath.length > 1\n ? keyPath\n .slice(1)\n .map(pathPart => (typeof pathPart === 'number' ? `[${pathPart}]` : pathPart))\n .join('.')\n : null;\n super(\n `The ${ordinal} argument to the \\`${methodName}\\` RPC method` +\n `${path ? ` at path \\`${path}\\`` : ''} was \\`${value}\\`. This number is ` +\n 'unsafe for use with the Solana JSON-RPC because it exceeds ' +\n '`Number.MAX_SAFE_INTEGER`.'\n );\n this.keyPath = keyPath;\n this.methodName = methodName;\n this.value = value;\n }\n get name() {\n return 'SolanaJsonRpcIntegerOverflowError';\n }\n}\n","import { createSolanaRpcApi } from '@solana/rpc-core';\n\nimport { SolanaJsonRpcIntegerOverflowError } from './rpc-integer-overflow-error';\n\nexport const DEFAULT_RPC_CONFIG: Partial<Parameters<typeof createSolanaRpcApi>[0]> = {\n onIntegerOverflow(methodName, keyPath, value) {\n throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);\n },\n};\n","import { createHttpTransport } from '@solana/rpc-transport';\nimport { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\nimport { getRpcTransportWithRequestCoalescing } from './rpc-request-coalescer';\nimport { getSolanaRpcPayloadDeduplicationKey } from './rpc-request-deduplication';\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers.\n */\nfunction normalizeHeaders<T extends Record<string, string>>(\n headers: T\n): { [K in keyof T & string as Lowercase<K>]: T[K] } {\n const out: Record<string, string> = {};\n for (const headerName in headers) {\n out[headerName.toLowerCase()] = headers[headerName];\n }\n return out as { [K in keyof T & string as Lowercase<K>]: T[K] };\n}\n\nexport function createDefaultRpcTransport(config: Parameters<typeof createHttpTransport>[0]): IRpcTransport {\n return getRpcTransportWithRequestCoalescing(\n createHttpTransport({\n ...config,\n headers: {\n ...(config.headers ? normalizeHeaders(config.headers) : undefined),\n ...({\n // Keep these headers lowercase so they will override any user-supplied headers above.\n 'solana-client': `js/${__VERSION__}` ?? 'UNKNOWN',\n } as { [overrideHeader: string]: string }),\n },\n }),\n getSolanaRpcPayloadDeduplicationKey\n );\n}\n","import { IRpcTransport } from '@solana/rpc-transport/dist/types/transports/transport-types';\n\ntype CoalescedRequest = {\n readonly abortController: AbortController;\n numConsumers: number;\n readonly responsePromise: Promise<unknown>;\n};\n\ntype GetDeduplicationKeyFn = (payload: unknown) => string | undefined;\n\nexport function getRpcTransportWithRequestCoalescing(\n transport: IRpcTransport,\n getDeduplicationKey: GetDeduplicationKeyFn\n): IRpcTransport {\n let coalescedRequestsByDeduplicationKey: Record<string, CoalescedRequest> | undefined;\n return async function makeCoalescedHttpRequest<TResponse>(\n config: Parameters<IRpcTransport>[0]\n ): Promise<TResponse> {\n const { payload, signal } = config;\n const deduplicationKey = getDeduplicationKey(payload);\n if (deduplicationKey === undefined) {\n return await transport(config);\n }\n if (!coalescedRequestsByDeduplicationKey) {\n Promise.resolve().then(() => {\n coalescedRequestsByDeduplicationKey = undefined;\n });\n coalescedRequestsByDeduplicationKey = {};\n }\n if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {\n const abortController = new AbortController();\n coalescedRequestsByDeduplicationKey[deduplicationKey] = {\n abortController,\n numConsumers: 0,\n responsePromise: transport<TResponse>({\n ...config,\n signal: abortController.signal,\n }),\n };\n }\n const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];\n coalescedRequest.numConsumers++;\n if (signal) {\n const responsePromise = coalescedRequest.responsePromise as Promise<TResponse>;\n return await new Promise<TResponse>((resolve, reject) => {\n const handleAbort = (e: AbortSignalEventMap['abort']) => {\n signal.removeEventListener('abort', handleAbort);\n coalescedRequest.numConsumers -= 1;\n if (coalescedRequest.numConsumers === 0) {\n const abortController = coalescedRequest.abortController;\n abortController.abort();\n }\n const abortError = new DOMException((e.target as AbortSignal).reason, 'AbortError');\n reject(abortError);\n };\n signal.addEventListener('abort', handleAbort);\n responsePromise.then(resolve).finally(() => {\n signal.removeEventListener('abort', handleAbort);\n });\n });\n } else {\n return (await coalescedRequest.responsePromise) as TResponse;\n }\n };\n}\n","// eslint-disable-next-line @typescript-eslint/ban-ts-comment\n// @ts-ignore\nimport fastStableStringify from 'fast-stable-stringify';\n\nexport function getSolanaRpcPayloadDeduplicationKey(payload: unknown): string | undefined {\n if (payload == null || typeof payload !== 'object' || Array.isArray(payload)) {\n return;\n }\n if ('jsonrpc' in payload && payload.jsonrpc === '2.0' && 'method' in payload && 'params' in payload) {\n return fastStableStringify([payload.method, payload.params]);\n }\n}\n"]}
@@ -178,6 +178,83 @@ this.globalThis.solanaWeb3 = (function (exports) {
178
178
  }
179
179
  });
180
180
 
181
+ // ../../node_modules/.pnpm/fast-stable-stringify@1.0.0/node_modules/fast-stable-stringify/index.js
182
+ var require_fast_stable_stringify = __commonJS({
183
+ "../../node_modules/.pnpm/fast-stable-stringify@1.0.0/node_modules/fast-stable-stringify/index.js"(exports, module) {
184
+ init_env_shim();
185
+ var objToString = Object.prototype.toString;
186
+ var objKeys = Object.keys || function(obj) {
187
+ var keys = [];
188
+ for (var name in obj) {
189
+ keys.push(name);
190
+ }
191
+ return keys;
192
+ };
193
+ function stringify(val, isArrayProp) {
194
+ var i, max, str, keys, key, propVal, toStr;
195
+ if (val === true) {
196
+ return "true";
197
+ }
198
+ if (val === false) {
199
+ return "false";
200
+ }
201
+ switch (typeof val) {
202
+ case "object":
203
+ if (val === null) {
204
+ return null;
205
+ } else if (val.toJSON && typeof val.toJSON === "function") {
206
+ return stringify(val.toJSON(), isArrayProp);
207
+ } else {
208
+ toStr = objToString.call(val);
209
+ if (toStr === "[object Array]") {
210
+ str = "[";
211
+ max = val.length - 1;
212
+ for (i = 0; i < max; i++) {
213
+ str += stringify(val[i], true) + ",";
214
+ }
215
+ if (max > -1) {
216
+ str += stringify(val[i], true);
217
+ }
218
+ return str + "]";
219
+ } else if (toStr === "[object Object]") {
220
+ keys = objKeys(val).sort();
221
+ max = keys.length;
222
+ str = "";
223
+ i = 0;
224
+ while (i < max) {
225
+ key = keys[i];
226
+ propVal = stringify(val[key], false);
227
+ if (propVal !== void 0) {
228
+ if (str) {
229
+ str += ",";
230
+ }
231
+ str += JSON.stringify(key) + ":" + propVal;
232
+ }
233
+ i++;
234
+ }
235
+ return "{" + str + "}";
236
+ } else {
237
+ return JSON.stringify(val);
238
+ }
239
+ }
240
+ case "function":
241
+ case "undefined":
242
+ return isArrayProp ? null : void 0;
243
+ case "string":
244
+ return JSON.stringify(val);
245
+ default:
246
+ return isFinite(val) ? val : null;
247
+ }
248
+ }
249
+ module.exports = function(val) {
250
+ var returnVal = stringify(val, false);
251
+ if (returnVal !== void 0) {
252
+ return "" + returnVal;
253
+ }
254
+ };
255
+ }
256
+ });
257
+
181
258
  // src/index.ts
182
259
  init_env_shim();
183
260
 
@@ -210,6 +287,7 @@ this.globalThis.solanaWeb3 = (function (exports) {
210
287
 
211
288
  // ../rpc-core/dist/index.browser.js
212
289
  init_env_shim();
290
+ __toESM(require_bs58(), 1);
213
291
  function visitNode(value, keyPath, onIntegerOverflow) {
214
292
  if (Array.isArray(value)) {
215
293
  return value.map(
@@ -237,7 +315,30 @@ this.globalThis.solanaWeb3 = (function (exports) {
237
315
  }
238
316
  var KEYPATH_WILDCARD = {};
239
317
  var ALLOWED_NUMERIC_KEYPATHS = {
240
- getInflationReward: [[KEYPATH_WILDCARD, "commission"]]
318
+ getBlockTime: [[]],
319
+ getInflationReward: [[KEYPATH_WILDCARD, "commission"]],
320
+ getRecentPerformanceSamples: [[KEYPATH_WILDCARD, "samplePeriodSecs"]],
321
+ getTransaction: [
322
+ ["meta", "preTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
323
+ ["meta", "preTokenBalances", KEYPATH_WILDCARD, "uiTokenAmount", "decimals"],
324
+ ["meta", "postTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
325
+ ["meta", "postTokenBalances", KEYPATH_WILDCARD, "uiTokenAmount", "decimals"],
326
+ ["meta", "rewards", KEYPATH_WILDCARD, "commission"],
327
+ ["meta", "innerInstructions", KEYPATH_WILDCARD, "index"],
328
+ ["meta", "innerInstructions", KEYPATH_WILDCARD, "instructions", KEYPATH_WILDCARD, "programIdIndex"],
329
+ ["meta", "innerInstructions", KEYPATH_WILDCARD, "instructions", KEYPATH_WILDCARD, "accounts", KEYPATH_WILDCARD],
330
+ ["transaction", "message", "addressTableLookups", KEYPATH_WILDCARD, "writableIndexes", KEYPATH_WILDCARD],
331
+ ["transaction", "message", "addressTableLookups", KEYPATH_WILDCARD, "readonlyIndexes", KEYPATH_WILDCARD],
332
+ ["transaction", "message", "instructions", KEYPATH_WILDCARD, "programIdIndex"],
333
+ ["transaction", "message", "instructions", KEYPATH_WILDCARD, "accounts", KEYPATH_WILDCARD],
334
+ ["transaction", "message", "header", "numReadonlySignedAccounts"],
335
+ ["transaction", "message", "header", "numReadonlyUnsignedAccounts"],
336
+ ["transaction", "message", "header", "numRequiredSignatures"]
337
+ ],
338
+ getVoteAccounts: [
339
+ ["current", KEYPATH_WILDCARD, "commission"],
340
+ ["delinquent", KEYPATH_WILDCARD, "commission"]
341
+ ]
241
342
  };
242
343
  function getNextAllowedKeypaths(keyPaths, property) {
243
344
  return keyPaths.filter((keyPath) => keyPath[0] === KEYPATH_WILDCARD && typeof property === "number" || keyPath[0] === property).map((keyPath) => keyPath.slice(1));
@@ -294,46 +395,6 @@ this.globalThis.solanaWeb3 = (function (exports) {
294
395
  });
295
396
  }
296
397
 
297
- // src/rpc-default-config.ts
298
- init_env_shim();
299
-
300
- // src/rpc-integer-overflow-error.ts
301
- init_env_shim();
302
- var SolanaJsonRpcIntegerOverflowError = class extends Error {
303
- constructor(methodName, keyPath, value) {
304
- const argPosition = (typeof keyPath[0] === "number" ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;
305
- let ordinal = "";
306
- const lastDigit = argPosition % 10;
307
- const lastTwoDigits = argPosition % 100;
308
- if (lastDigit == 1 && lastTwoDigits != 11) {
309
- ordinal = argPosition + "st";
310
- } else if (lastDigit == 2 && lastTwoDigits != 12) {
311
- ordinal = argPosition + "nd";
312
- } else if (lastDigit == 3 && lastTwoDigits != 13) {
313
- ordinal = argPosition + "rd";
314
- } else {
315
- ordinal = argPosition + "th";
316
- }
317
- const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : null;
318
- super(
319
- `The ${ordinal} argument to the \`${methodName}\` RPC method${path ? ` at path \`${path}\`` : ""} was \`${value}\`. This number is unsafe for use with the Solana JSON-RPC because it exceeds \`Number.MAX_SAFE_INTEGER\`.`
320
- );
321
- this.keyPath = keyPath;
322
- this.methodName = methodName;
323
- this.value = value;
324
- }
325
- get name() {
326
- return "SolanaJsonRpcIntegerOverflowError";
327
- }
328
- };
329
-
330
- // src/rpc-default-config.ts
331
- var DEFAULT_RPC_CONFIG = {
332
- onIntegerOverflow(methodName, keyPath, value) {
333
- throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
334
- }
335
- };
336
-
337
398
  // ../rpc-transport/dist/index.browser.js
338
399
  init_env_shim();
339
400
  var SolanaJsonRpcError = class extends Error {
@@ -399,6 +460,7 @@ this.globalThis.solanaWeb3 = (function (exports) {
399
460
  function createJsonRpc(rpcConfig) {
400
461
  return makeProxy(rpcConfig);
401
462
  }
463
+ var e = globalThis.fetch;
402
464
  var SolanaHttpError = class extends Error {
403
465
  constructor(details) {
404
466
  super(`HTTP error (${details.statusCode}): ${details.message}`);
@@ -457,7 +519,6 @@ this.globalThis.solanaWeb3 = (function (exports) {
457
519
  }
458
520
  return out;
459
521
  }
460
- var e = globalThis.fetch;
461
522
  function createHttpTransport({ httpAgentNodeOnly, headers, url }) {
462
523
  if (headers) {
463
524
  assertIsAllowedHttpRequestHeaders(headers);
@@ -498,6 +559,46 @@ this.globalThis.solanaWeb3 = (function (exports) {
498
559
  };
499
560
  }
500
561
 
562
+ // src/rpc-default-config.ts
563
+ init_env_shim();
564
+
565
+ // src/rpc-integer-overflow-error.ts
566
+ init_env_shim();
567
+ var SolanaJsonRpcIntegerOverflowError = class extends Error {
568
+ constructor(methodName, keyPath, value) {
569
+ const argPosition = (typeof keyPath[0] === "number" ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;
570
+ let ordinal = "";
571
+ const lastDigit = argPosition % 10;
572
+ const lastTwoDigits = argPosition % 100;
573
+ if (lastDigit == 1 && lastTwoDigits != 11) {
574
+ ordinal = argPosition + "st";
575
+ } else if (lastDigit == 2 && lastTwoDigits != 12) {
576
+ ordinal = argPosition + "nd";
577
+ } else if (lastDigit == 3 && lastTwoDigits != 13) {
578
+ ordinal = argPosition + "rd";
579
+ } else {
580
+ ordinal = argPosition + "th";
581
+ }
582
+ const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : null;
583
+ super(
584
+ `The ${ordinal} argument to the \`${methodName}\` RPC method${path ? ` at path \`${path}\`` : ""} was \`${value}\`. This number is unsafe for use with the Solana JSON-RPC because it exceeds \`Number.MAX_SAFE_INTEGER\`.`
585
+ );
586
+ this.keyPath = keyPath;
587
+ this.methodName = methodName;
588
+ this.value = value;
589
+ }
590
+ get name() {
591
+ return "SolanaJsonRpcIntegerOverflowError";
592
+ }
593
+ };
594
+
595
+ // src/rpc-default-config.ts
596
+ var DEFAULT_RPC_CONFIG = {
597
+ onIntegerOverflow(methodName, keyPath, value) {
598
+ throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
599
+ }
600
+ };
601
+
501
602
  // src/rpc.ts
502
603
  function createSolanaRpc(config) {
503
604
  return createJsonRpc({
@@ -508,6 +609,73 @@ this.globalThis.solanaWeb3 = (function (exports) {
508
609
 
509
610
  // src/rpc-transport.ts
510
611
  init_env_shim();
612
+
613
+ // src/rpc-request-coalescer.ts
614
+ init_env_shim();
615
+ function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
616
+ let coalescedRequestsByDeduplicationKey;
617
+ return async function makeCoalescedHttpRequest(config) {
618
+ const { payload, signal } = config;
619
+ const deduplicationKey = getDeduplicationKey(payload);
620
+ if (deduplicationKey === void 0) {
621
+ return await transport(config);
622
+ }
623
+ if (!coalescedRequestsByDeduplicationKey) {
624
+ Promise.resolve().then(() => {
625
+ coalescedRequestsByDeduplicationKey = void 0;
626
+ });
627
+ coalescedRequestsByDeduplicationKey = {};
628
+ }
629
+ if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {
630
+ const abortController = new AbortController();
631
+ coalescedRequestsByDeduplicationKey[deduplicationKey] = {
632
+ abortController,
633
+ numConsumers: 0,
634
+ responsePromise: transport({
635
+ ...config,
636
+ signal: abortController.signal
637
+ })
638
+ };
639
+ }
640
+ const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];
641
+ coalescedRequest.numConsumers++;
642
+ if (signal) {
643
+ const responsePromise = coalescedRequest.responsePromise;
644
+ return await new Promise((resolve, reject) => {
645
+ const handleAbort = (e2) => {
646
+ signal.removeEventListener("abort", handleAbort);
647
+ coalescedRequest.numConsumers -= 1;
648
+ if (coalescedRequest.numConsumers === 0) {
649
+ const abortController = coalescedRequest.abortController;
650
+ abortController.abort();
651
+ }
652
+ const abortError = new DOMException(e2.target.reason, "AbortError");
653
+ reject(abortError);
654
+ };
655
+ signal.addEventListener("abort", handleAbort);
656
+ responsePromise.then(resolve).finally(() => {
657
+ signal.removeEventListener("abort", handleAbort);
658
+ });
659
+ });
660
+ } else {
661
+ return await coalescedRequest.responsePromise;
662
+ }
663
+ };
664
+ }
665
+
666
+ // src/rpc-request-deduplication.ts
667
+ init_env_shim();
668
+ var import_fast_stable_stringify = __toESM(require_fast_stable_stringify(), 1);
669
+ function getSolanaRpcPayloadDeduplicationKey(payload) {
670
+ if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
671
+ return;
672
+ }
673
+ if ("jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && "params" in payload) {
674
+ return (0, import_fast_stable_stringify.default)([payload.method, payload.params]);
675
+ }
676
+ }
677
+
678
+ // src/rpc-transport.ts
511
679
  function normalizeHeaders2(headers) {
512
680
  const out = {};
513
681
  for (const headerName in headers) {
@@ -516,16 +684,19 @@ this.globalThis.solanaWeb3 = (function (exports) {
516
684
  return out;
517
685
  }
518
686
  function createDefaultRpcTransport(config) {
519
- return createHttpTransport({
520
- ...config,
521
- headers: {
522
- ...config.headers ? normalizeHeaders2(config.headers) : void 0,
523
- ...{
524
- // Keep these headers lowercase so they will override any user-supplied headers above.
525
- "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
687
+ return getRpcTransportWithRequestCoalescing(
688
+ createHttpTransport({
689
+ ...config,
690
+ headers: {
691
+ ...config.headers ? normalizeHeaders2(config.headers) : void 0,
692
+ ...{
693
+ // Keep these headers lowercase so they will override any user-supplied headers above.
694
+ "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
695
+ }
526
696
  }
527
- }
528
- });
697
+ }),
698
+ getSolanaRpcPayloadDeduplicationKey
699
+ );
529
700
  }
530
701
 
531
702
  exports.assertIsBase58EncodedAddress = assertIsBase58EncodedAddress;