@solana/web3.js 2.0.0-experimental.d16acbd → 2.0.0-experimental.d2e0117

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.
@@ -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,16 +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 };
@@ -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":";AAAA,cAAc;;;ACAd,SAAS,0BAA4C;AACrD,SAAS,qBAAqB;;;ACDvB,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;;;AClCO,IAAM,qBAAwE;AAAA,EACjF,kBAAkB,YAAY,SAAS,OAAO;AAC1C,UAAM,IAAI,kCAAkC,YAAY,SAAS,KAAK;AAAA,EAC1E;AACJ;;;AFFO,SAAS,gBAAgB,QAAiF;AAC7G,SAAO,cAAgC;AAAA,IACnC,GAAG;AAAA,IACH,KAAK,mBAAmB,kBAAkB;AAAA,EAC9C,CAAC;AACL;;;AGXA,SAAS,2BAA2B;;;ACU7B,SAAS,qCACZ,WACA,qBACa;AACb,MAAI;AACJ,SAAO,eAAe,yBAClB,QACkB;AAClB,UAAM,EAAE,SAAS,OAAO,IAAI;AAC5B,UAAM,mBAAmB,oBAAoB,OAAO;AACpD,QAAI,qBAAqB,QAAW;AAChC,aAAO,MAAM,UAAU,MAAM;AAAA,IACjC;AACA,QAAI,CAAC,qCAAqC;AACtC,cAAQ,QAAQ,EAAE,KAAK,MAAM;AACzB,8CAAsC;AAAA,MAC1C,CAAC;AACD,4CAAsC,CAAC;AAAA,IAC3C;AACA,QAAI,oCAAoC,gBAAgB,KAAK,MAAM;AAC/D,YAAM,kBAAkB,IAAI,gBAAgB;AAC5C,0CAAoC,gBAAgB,IAAI;AAAA,QACpD;AAAA,QACA,cAAc;AAAA,QACd,iBAAiB,UAAqB;AAAA,UAClC,GAAG;AAAA,UACH,QAAQ,gBAAgB;AAAA,QAC5B,CAAC;AAAA,MACL;AAAA,IACJ;AACA,UAAM,mBAAmB,oCAAoC,gBAAgB;AAC7E,qBAAiB;AACjB,QAAI,QAAQ;AACR,YAAM,kBAAkB,iBAAiB;AACzC,aAAO,MAAM,IAAI,QAAmB,CAAC,SAAS,WAAW;AACrD,cAAM,cAAc,CAAC,MAAoC;AACrD,iBAAO,oBAAoB,SAAS,WAAW;AAC/C,2BAAiB,gBAAgB;AACjC,cAAI,iBAAiB,iBAAiB,GAAG;AACrC,kBAAM,kBAAkB,iBAAiB;AACzC,4BAAgB,MAAM;AAAA,UAC1B;AACA,gBAAM,aAAa,IAAI,aAAc,EAAE,OAAuB,QAAQ,YAAY;AAClF,iBAAO,UAAU;AAAA,QACrB;AACA,eAAO,iBAAiB,SAAS,WAAW;AAC5C,wBAAgB,KAAK,OAAO,EAAE,QAAQ,MAAM;AACxC,iBAAO,oBAAoB,SAAS,WAAW;AAAA,QACnD,CAAC;AAAA,MACL,CAAC;AAAA,IACL,OAAO;AACH,aAAQ,MAAM,iBAAiB;AAAA,IACnC;AAAA,EACJ;AACJ;;;AC9DA,OAAO,yBAAyB;AAEzB,SAAS,oCAAoC,SAAsC;AACtF,MAAI,WAAW,QAAQ,OAAO,YAAY,YAAY,MAAM,QAAQ,OAAO,GAAG;AAC1E;AAAA,EACJ;AACA,MAAI,aAAa,WAAW,QAAQ,YAAY,SAAS,YAAY,WAAW,YAAY,SAAS;AACjG,WAAO,oBAAoB,CAAC,QAAQ,QAAQ,QAAQ,MAAM,CAAC;AAAA,EAC/D;AACJ;;;AFFA,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;AAAA,IACH,oBAAoB;AAAA,MAChB,GAAG;AAAA,MACH,SAAS;AAAA,QACL,GAAI,OAAO,UAAU,iBAAiB,OAAO,OAAO,IAAI;AAAA,QACxD,GAAI;AAAA;AAAA,UAEA,iBAAiB,MAAM,yBAAiB;AAAA,QAC5C;AAAA,MACJ;AAAA,IACJ,CAAC;AAAA,IACD;AAAA,EACJ;AACJ","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
 
@@ -238,7 +315,13 @@ this.globalThis.solanaWeb3 = (function (exports) {
238
315
  }
239
316
  var KEYPATH_WILDCARD = {};
240
317
  var ALLOWED_NUMERIC_KEYPATHS = {
241
- getInflationReward: [[KEYPATH_WILDCARD, "commission"]]
318
+ getBlockTime: [[]],
319
+ getInflationReward: [[KEYPATH_WILDCARD, "commission"]],
320
+ getRecentPerformanceSamples: [[KEYPATH_WILDCARD, "samplePeriodSecs"]],
321
+ getVoteAccounts: [
322
+ ["current", KEYPATH_WILDCARD, "commission"],
323
+ ["delinquent", KEYPATH_WILDCARD, "commission"]
324
+ ]
242
325
  };
243
326
  function getNextAllowedKeypaths(keyPaths, property) {
244
327
  return keyPaths.filter((keyPath) => keyPath[0] === KEYPATH_WILDCARD && typeof property === "number" || keyPath[0] === property).map((keyPath) => keyPath.slice(1));
@@ -295,46 +378,6 @@ this.globalThis.solanaWeb3 = (function (exports) {
295
378
  });
296
379
  }
297
380
 
298
- // src/rpc-default-config.ts
299
- init_env_shim();
300
-
301
- // src/rpc-integer-overflow-error.ts
302
- init_env_shim();
303
- var SolanaJsonRpcIntegerOverflowError = class extends Error {
304
- constructor(methodName, keyPath, value) {
305
- const argPosition = (typeof keyPath[0] === "number" ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;
306
- let ordinal = "";
307
- const lastDigit = argPosition % 10;
308
- const lastTwoDigits = argPosition % 100;
309
- if (lastDigit == 1 && lastTwoDigits != 11) {
310
- ordinal = argPosition + "st";
311
- } else if (lastDigit == 2 && lastTwoDigits != 12) {
312
- ordinal = argPosition + "nd";
313
- } else if (lastDigit == 3 && lastTwoDigits != 13) {
314
- ordinal = argPosition + "rd";
315
- } else {
316
- ordinal = argPosition + "th";
317
- }
318
- const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : null;
319
- super(
320
- `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\`.`
321
- );
322
- this.keyPath = keyPath;
323
- this.methodName = methodName;
324
- this.value = value;
325
- }
326
- get name() {
327
- return "SolanaJsonRpcIntegerOverflowError";
328
- }
329
- };
330
-
331
- // src/rpc-default-config.ts
332
- var DEFAULT_RPC_CONFIG = {
333
- onIntegerOverflow(methodName, keyPath, value) {
334
- throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
335
- }
336
- };
337
-
338
381
  // ../rpc-transport/dist/index.browser.js
339
382
  init_env_shim();
340
383
  var SolanaJsonRpcError = class extends Error {
@@ -400,6 +443,7 @@ this.globalThis.solanaWeb3 = (function (exports) {
400
443
  function createJsonRpc(rpcConfig) {
401
444
  return makeProxy(rpcConfig);
402
445
  }
446
+ var e = globalThis.fetch;
403
447
  var SolanaHttpError = class extends Error {
404
448
  constructor(details) {
405
449
  super(`HTTP error (${details.statusCode}): ${details.message}`);
@@ -458,7 +502,6 @@ this.globalThis.solanaWeb3 = (function (exports) {
458
502
  }
459
503
  return out;
460
504
  }
461
- var e = globalThis.fetch;
462
505
  function createHttpTransport({ httpAgentNodeOnly, headers, url }) {
463
506
  if (headers) {
464
507
  assertIsAllowedHttpRequestHeaders(headers);
@@ -499,6 +542,46 @@ this.globalThis.solanaWeb3 = (function (exports) {
499
542
  };
500
543
  }
501
544
 
545
+ // src/rpc-default-config.ts
546
+ init_env_shim();
547
+
548
+ // src/rpc-integer-overflow-error.ts
549
+ init_env_shim();
550
+ var SolanaJsonRpcIntegerOverflowError = class extends Error {
551
+ constructor(methodName, keyPath, value) {
552
+ const argPosition = (typeof keyPath[0] === "number" ? keyPath[0] : parseInt(keyPath[0], 10)) + 1;
553
+ let ordinal = "";
554
+ const lastDigit = argPosition % 10;
555
+ const lastTwoDigits = argPosition % 100;
556
+ if (lastDigit == 1 && lastTwoDigits != 11) {
557
+ ordinal = argPosition + "st";
558
+ } else if (lastDigit == 2 && lastTwoDigits != 12) {
559
+ ordinal = argPosition + "nd";
560
+ } else if (lastDigit == 3 && lastTwoDigits != 13) {
561
+ ordinal = argPosition + "rd";
562
+ } else {
563
+ ordinal = argPosition + "th";
564
+ }
565
+ const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : null;
566
+ super(
567
+ `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\`.`
568
+ );
569
+ this.keyPath = keyPath;
570
+ this.methodName = methodName;
571
+ this.value = value;
572
+ }
573
+ get name() {
574
+ return "SolanaJsonRpcIntegerOverflowError";
575
+ }
576
+ };
577
+
578
+ // src/rpc-default-config.ts
579
+ var DEFAULT_RPC_CONFIG = {
580
+ onIntegerOverflow(methodName, keyPath, value) {
581
+ throw new SolanaJsonRpcIntegerOverflowError(methodName, keyPath, value);
582
+ }
583
+ };
584
+
502
585
  // src/rpc.ts
503
586
  function createSolanaRpc(config) {
504
587
  return createJsonRpc({
@@ -509,6 +592,73 @@ this.globalThis.solanaWeb3 = (function (exports) {
509
592
 
510
593
  // src/rpc-transport.ts
511
594
  init_env_shim();
595
+
596
+ // src/rpc-request-coalescer.ts
597
+ init_env_shim();
598
+ function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
599
+ let coalescedRequestsByDeduplicationKey;
600
+ return async function makeCoalescedHttpRequest(config) {
601
+ const { payload, signal } = config;
602
+ const deduplicationKey = getDeduplicationKey(payload);
603
+ if (deduplicationKey === void 0) {
604
+ return await transport(config);
605
+ }
606
+ if (!coalescedRequestsByDeduplicationKey) {
607
+ Promise.resolve().then(() => {
608
+ coalescedRequestsByDeduplicationKey = void 0;
609
+ });
610
+ coalescedRequestsByDeduplicationKey = {};
611
+ }
612
+ if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {
613
+ const abortController = new AbortController();
614
+ coalescedRequestsByDeduplicationKey[deduplicationKey] = {
615
+ abortController,
616
+ numConsumers: 0,
617
+ responsePromise: transport({
618
+ ...config,
619
+ signal: abortController.signal
620
+ })
621
+ };
622
+ }
623
+ const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];
624
+ coalescedRequest.numConsumers++;
625
+ if (signal) {
626
+ const responsePromise = coalescedRequest.responsePromise;
627
+ return await new Promise((resolve, reject) => {
628
+ const handleAbort = (e2) => {
629
+ signal.removeEventListener("abort", handleAbort);
630
+ coalescedRequest.numConsumers -= 1;
631
+ if (coalescedRequest.numConsumers === 0) {
632
+ const abortController = coalescedRequest.abortController;
633
+ abortController.abort();
634
+ }
635
+ const abortError = new DOMException(e2.target.reason, "AbortError");
636
+ reject(abortError);
637
+ };
638
+ signal.addEventListener("abort", handleAbort);
639
+ responsePromise.then(resolve).finally(() => {
640
+ signal.removeEventListener("abort", handleAbort);
641
+ });
642
+ });
643
+ } else {
644
+ return await coalescedRequest.responsePromise;
645
+ }
646
+ };
647
+ }
648
+
649
+ // src/rpc-request-deduplication.ts
650
+ init_env_shim();
651
+ var import_fast_stable_stringify = __toESM(require_fast_stable_stringify(), 1);
652
+ function getSolanaRpcPayloadDeduplicationKey(payload) {
653
+ if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
654
+ return;
655
+ }
656
+ if ("jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && "params" in payload) {
657
+ return (0, import_fast_stable_stringify.default)([payload.method, payload.params]);
658
+ }
659
+ }
660
+
661
+ // src/rpc-transport.ts
512
662
  function normalizeHeaders2(headers) {
513
663
  const out = {};
514
664
  for (const headerName in headers) {
@@ -517,16 +667,19 @@ this.globalThis.solanaWeb3 = (function (exports) {
517
667
  return out;
518
668
  }
519
669
  function createDefaultRpcTransport(config) {
520
- return createHttpTransport({
521
- ...config,
522
- headers: {
523
- ...config.headers ? normalizeHeaders2(config.headers) : void 0,
524
- ...{
525
- // Keep these headers lowercase so they will override any user-supplied headers above.
526
- "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
670
+ return getRpcTransportWithRequestCoalescing(
671
+ createHttpTransport({
672
+ ...config,
673
+ headers: {
674
+ ...config.headers ? normalizeHeaders2(config.headers) : void 0,
675
+ ...{
676
+ // Keep these headers lowercase so they will override any user-supplied headers above.
677
+ "solana-client": `js/${"2.0.0-development"}` ?? "UNKNOWN"
678
+ }
527
679
  }
528
- }
529
- });
680
+ }),
681
+ getSolanaRpcPayloadDeduplicationKey
682
+ );
530
683
  }
531
684
 
532
685
  exports.assertIsBase58EncodedAddress = assertIsBase58EncodedAddress;