@solana/rpc-transport-http 2.0.0-experimental.00fa195

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/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2023 Solana Labs, Inc
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,244 @@
1
+ [![npm][npm-image]][npm-url]
2
+ [![npm-downloads][npm-downloads-image]][npm-url]
3
+ [![semantic-release][semantic-release-image]][semantic-release-url]
4
+ <br />
5
+ [![code-style-prettier][code-style-prettier-image]][code-style-prettier-url]
6
+
7
+ [code-style-prettier-image]: https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square
8
+ [code-style-prettier-url]: https://github.com/prettier/prettier
9
+ [npm-downloads-image]: https://img.shields.io/npm/dm/@solana/rpc-transport-http/experimental.svg?style=flat
10
+ [npm-image]: https://img.shields.io/npm/v/@solana/rpc-transport-http/experimental.svg?style=flat
11
+ [npm-url]: https://www.npmjs.com/package/@solana/rpc-transport-http/v/experimental
12
+ [semantic-release-image]: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg
13
+ [semantic-release-url]: https://github.com/semantic-release/semantic-release
14
+
15
+ # @solana/rpc-transport-http
16
+
17
+ This package allows developers to create custom RPC transports. With this library, one can implement highly specialized functionality for leveraging multiple transports, attempting/handling retries, and more.
18
+
19
+ ## Functions
20
+
21
+ ### `createHttpTransport()`
22
+
23
+ Call this to create a function that conforms to the `RpcTransport` interface (see `@solana/rpc-spec`). You can use that function in your programs to make `POST` requests with headers suitable for sending JSON data to a server.
24
+
25
+ ```ts
26
+ import { createHttpTransport } from '@solana/rpc-transport-http';
27
+
28
+ const transport = createHttpTransport({ url: 'https://api.mainnet-beta.solana.com' });
29
+ const response = await transport({
30
+ payload: { id: 1, jsonrpc: '2.0', method: 'getSlot' },
31
+ });
32
+ ```
33
+
34
+ #### Config
35
+
36
+ ##### `dispatcher_NODE_ONLY`
37
+
38
+ In Node environments you can tune how requests are dispatched to the network. Use this config parameter to install a [`undici.Dispatcher`](https://undici.nodejs.org/#/docs/api/Agent) in your transport.
39
+
40
+ ```ts
41
+ import { createHttpTransport } from '@solana/rpc-transport-http';
42
+ import { Agent, BalancedPool } from 'undici';
43
+
44
+ // Create a dispatcher that, when called with a special URL, creates a round-robin pool of RPCs.
45
+ const dispatcher = new Agent({
46
+ factory(origin, opts) {
47
+ if (origin === 'https://mypool') {
48
+ const upstreams = [
49
+ 'https://api.mainnet-beta.solana.com',
50
+ 'https://mainnet.helius-rpc.com',
51
+ 'https://several-neat-iguana.quiknode.pro',
52
+ ];
53
+ return new BalancedPool(upstreams, {
54
+ ...opts,
55
+ bodyTimeout: 60e3,
56
+ headersTimeout: 5e3,
57
+ keepAliveTimeout: 19e3,
58
+ });
59
+ } else {
60
+ return new Pool(origin, opts);
61
+ }
62
+ },
63
+ });
64
+ const transport = createHttpTransport({
65
+ dispatcher_NODE_ONLY: dispatcher,
66
+ url: 'https://mypool',
67
+ });
68
+ let id = 0;
69
+ const balances = await Promise.allSettled(
70
+ accounts.map(account =>
71
+ transport({
72
+ payload: {
73
+ id: ++id,
74
+ jsonrpc: '2.0',
75
+ method: 'getBalance',
76
+ params: [account],
77
+ },
78
+ }),
79
+ ),
80
+ );
81
+ ```
82
+
83
+ ##### `headers`
84
+
85
+ An object of headers to set on the request. Avoid [forbidden headers](https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name). Additionally, the headers `Accept`, `Content-Length`, and `Content-Type` are disallowed.
86
+
87
+ ```ts
88
+ import { createHttpTransport } from '@solana/rpc-transport-http';
89
+
90
+ const transport = createHttpTransport({
91
+ headers: {
92
+ // Authorize with the RPC using a bearer token
93
+ Authorization: `Bearer ${process.env.RPC_AUTH_TOKEN}`,
94
+ },
95
+ url: 'https://several-neat-iguana.quiknode.pro',
96
+ });
97
+ ```
98
+
99
+ ##### `url`
100
+
101
+ A string representing the target endpoint. In Node, it must be an absolute URL using the `http` or `https` protocol.
102
+
103
+ ## Augmenting Transports
104
+
105
+ Using this core transport, you can implement specialized functionality for leveraging multiple transports, attempting/handling retries, and more.
106
+
107
+ ### Round Robin
108
+
109
+ Here’s an example of how someone might implement a “round robin” approach to distribute requests to multiple transports:
110
+
111
+ ```ts
112
+ import { RpcTransport } from '@solana/rpc-spec';
113
+ import { createHttpTransport } from '@solana/rpc-transport-http';
114
+
115
+ // Create a transport for each RPC server
116
+ const transports = [
117
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-1.com' }),
118
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-2.com' }),
119
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-3.com' }),
120
+ ];
121
+
122
+ // Create a wrapper transport that distributes requests to them
123
+ let nextTransport = 0;
124
+ async function roundRobinTransport<TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> {
125
+ const transport = transports[nextTransport];
126
+ nextTransport = (nextTransport + 1) % transports.length;
127
+ return await transport(...args);
128
+ }
129
+ ```
130
+
131
+ ### Sharding
132
+
133
+ Another example of a possible customization for a transport is to shard requests deterministically among a set of servers. Here’s an example:
134
+
135
+ Perhaps your application needs to make a large number of requests, or needs to fan request for different methods out to different servers. Here’s an example of an implementation that does the latter:
136
+
137
+ ```ts
138
+ import { RpcTransport } from '@solana/rpc-spec';
139
+ import { createHttpTransport } from '@solana/rpc-transport-http';
140
+
141
+ // Create multiple transports
142
+ const transportA = createHttpTransport({ url: 'https://mainnet-beta.my-server-1.com' });
143
+ const transportB = createHttpTransport({ url: 'https://mainnet-beta.my-server-2.com' });
144
+ const transportC = createHttpTransport({ url: 'https://mainnet-beta.my-server-3.com' });
145
+ const transportD = createHttpTransport({ url: 'https://mainnet-beta.my-server-4.com' });
146
+
147
+ // Function to determine which shard to use based on the request method
148
+ function selectShard(method: string): RpcTransport {
149
+ switch (method) {
150
+ case 'getAccountInfo':
151
+ case 'getBalance':
152
+ return transportA;
153
+ case 'getTransaction':
154
+ case 'getRecentBlockhash':
155
+ return transportB;
156
+ case 'sendTransaction':
157
+ return transportC;
158
+ default:
159
+ return transportD;
160
+ }
161
+ }
162
+
163
+ async function shardingTransport<TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> {
164
+ const payload = args[0].payload as { method: string };
165
+ const selectedTransport = selectShard(payload.method);
166
+ return await selectedTransport(...args);
167
+ }
168
+ ```
169
+
170
+ ### Retry Logic
171
+
172
+ The transport library can also be used to implement custom retry logic on any request:
173
+
174
+ ```ts
175
+ import { RpcTransport } from '@solana/rpc-spec';
176
+ import { createHttpTransport } from '@solana/rpc-transport-http';
177
+
178
+ // Set the maximum number of attempts to retry a request
179
+ const MAX_ATTEMPTS = 4;
180
+
181
+ // Create the default transport
182
+ const defaultTransport = createHttpTransport({ url: 'https://mainnet-beta.my-server-1.com' });
183
+
184
+ // Sleep function to wait for a given number of milliseconds
185
+ function sleep(ms: number): Promise<void> {
186
+ return new Promise(resolve => setTimeout(resolve, ms));
187
+ }
188
+
189
+ // Calculate the delay for a given attempt
190
+ function calculateRetryDelay(attempt: number): number {
191
+ // Exponential backoff with a maximum of 1.5 seconds
192
+ return Math.min(100 * Math.pow(2, attempt), 1500);
193
+ }
194
+
195
+ // A retrying transport that will retry up to `MAX_ATTEMPTS` times before failing
196
+ async function retryingTransport<TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> {
197
+ let requestError;
198
+ for (let attempts = 0; attempts < MAX_ATTEMPTS; attempts++) {
199
+ try {
200
+ return await defaultTransport(...args);
201
+ } catch (err) {
202
+ requestError = err;
203
+ // Only sleep if we have more attempts remaining
204
+ if (attempts < MAX_ATTEMPTS - 1) {
205
+ const retryDelay = calculateRetryDelay(attempts);
206
+ await sleep(retryDelay);
207
+ }
208
+ }
209
+ }
210
+ throw requestError;
211
+ }
212
+ ```
213
+
214
+ ### Failover
215
+
216
+ Here’s an example of some failover logic integrated into a transport:
217
+
218
+ ```ts
219
+ import { RpcTransport } from '@solana/rpc-spec';
220
+ import { createHttpTransport } from '@solana/rpc-transport-http';
221
+
222
+ // Create a transport for each RPC server
223
+ const transports = [
224
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-1.com' }),
225
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-2.com' }),
226
+ createHttpTransport({ url: 'https://mainnet-beta.my-server-2.com' }),
227
+ ];
228
+
229
+ // A failover transport that will try each transport in order until one succeeds before failing
230
+ async function failoverTransport<TResponse>(...args: Parameters<RpcTransport>): Promise<TResponse> {
231
+ let requestError;
232
+
233
+ for (const transport of transports) {
234
+ try {
235
+ return await transport(...args);
236
+ } catch (err) {
237
+ requestError = err;
238
+ console.error(err);
239
+ }
240
+ }
241
+ throw requestError;
242
+ }
243
+
244
+ ```
@@ -0,0 +1,108 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@solana/errors');
4
+
5
+ // ../build-scripts/env-shim.ts
6
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
7
+ var DISALLOWED_HEADERS = {
8
+ accept: true,
9
+ "content-length": true,
10
+ "content-type": true
11
+ };
12
+ var FORBIDDEN_HEADERS = {
13
+ "accept-charset": true,
14
+ "accept-encoding": true,
15
+ "access-control-request-headers": true,
16
+ "access-control-request-method": true,
17
+ connection: true,
18
+ "content-length": true,
19
+ cookie: true,
20
+ date: true,
21
+ dnt: true,
22
+ expect: true,
23
+ host: true,
24
+ "keep-alive": true,
25
+ origin: true,
26
+ "permissions-policy": true,
27
+ // Prefix matching is implemented in code, below.
28
+ // 'proxy-': true,
29
+ // 'sec-': true,
30
+ referer: true,
31
+ te: true,
32
+ trailer: true,
33
+ "transfer-encoding": true,
34
+ upgrade: true,
35
+ via: true
36
+ };
37
+ function assertIsAllowedHttpRequestHeaders(headers) {
38
+ const badHeaders = Object.keys(headers).filter((headerName) => {
39
+ const lowercaseHeaderName = headerName.toLowerCase();
40
+ return DISALLOWED_HEADERS[headerName.toLowerCase()] === true || FORBIDDEN_HEADERS[headerName.toLowerCase()] === true || lowercaseHeaderName.startsWith("proxy-") || lowercaseHeaderName.startsWith("sec-");
41
+ });
42
+ if (badHeaders.length > 0) {
43
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {
44
+ headers: badHeaders
45
+ });
46
+ }
47
+ }
48
+ function normalizeHeaders(headers) {
49
+ const out = {};
50
+ for (const headerName in headers) {
51
+ out[headerName.toLowerCase()] = headers[headerName];
52
+ }
53
+ return out;
54
+ }
55
+
56
+ // src/http-transport.ts
57
+ var didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;
58
+ function warnDispatcherWasSuppliedInNonNodeEnvironment() {
59
+ if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {
60
+ return;
61
+ }
62
+ didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;
63
+ console.warn(
64
+ "You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored because Undici dispatchers only work in Node environments. To eliminate this warning, omit the `dispatcher_NODE_ONLY` property from your config when running in a non-Node environment."
65
+ );
66
+ }
67
+ function createHttpTransport(config) {
68
+ if (__DEV__ && true && "dispatcher_NODE_ONLY" in config) {
69
+ warnDispatcherWasSuppliedInNonNodeEnvironment();
70
+ }
71
+ const { headers, url } = config;
72
+ if (__DEV__ && headers) {
73
+ assertIsAllowedHttpRequestHeaders(headers);
74
+ }
75
+ let dispatcherConfig;
76
+ const customHeaders = headers && normalizeHeaders(headers);
77
+ return async function makeHttpRequest({
78
+ payload,
79
+ signal
80
+ }) {
81
+ const body = JSON.stringify(payload);
82
+ const requestInfo = {
83
+ ...dispatcherConfig,
84
+ body,
85
+ headers: {
86
+ ...customHeaders,
87
+ // Keep these headers lowercase so they will override any user-supplied headers above.
88
+ accept: "application/json",
89
+ "content-length": body.length.toString(),
90
+ "content-type": "application/json; charset=utf-8"
91
+ },
92
+ method: "POST",
93
+ signal
94
+ };
95
+ const response = await fetch(url, requestInfo);
96
+ if (!response.ok) {
97
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
98
+ message: response.statusText,
99
+ statusCode: response.status
100
+ });
101
+ }
102
+ return await response.json();
103
+ };
104
+ }
105
+
106
+ exports.createHttpTransport = createHttpTransport;
107
+ //# sourceMappingURL=out.js.map
108
+ //# sourceMappingURL=index.browser.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../build-scripts/env-shim.ts","../src/http-transport.ts","../src/http-transport-headers.ts"],"names":["SolanaError"],"mappings":";AACO,IAAM,UAA2B,uBAAO,QAAgB,KAAU,EAAE,aAAa,eAAe;;;ACDvG,SAAS,yCAAyC,eAAAA,oBAAmB;;;ACArE,SAAS,oDAAoD,mBAAmB;AA2ChF,IAAM,qBAA8C;AAAA,EAChD,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AACpB;AAEA,IAAM,oBAA6C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,sBAAsB;AAAA;AAAA;AAAA;AAAA,EAItB,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,KAAK;AACT;AAEO,SAAS,kCACZ,SAC4C;AAC5C,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,OAAO,gBAAc;AACzD,UAAM,sBAAsB,WAAW,YAAY;AACnD,WACI,mBAAmB,WAAW,YAAY,CAAC,MAAM,QACjD,kBAAkB,WAAW,YAAY,CAAC,MAAM,QAChD,oBAAoB,WAAW,QAAQ,KACvC,oBAAoB,WAAW,MAAM;AAAA,EAE7C,CAAC;AACD,MAAI,WAAW,SAAS,GAAG;AACvB,UAAM,IAAI,YAAY,oDAAoD;AAAA,MACtE,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AACJ;AAMO,SAAS,iBACZ,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;;;AD1FA,IAAI,mDAAmD;AACvD,SAAS,gDAAgD;AACrD,MAAI,kDAAkD;AAClD;AAAA,EACJ;AACA,qDAAmD;AACnD,UAAQ;AAAA,IACJ;AAAA,EAIJ;AACJ;AAEO,SAAS,oBAAoB,QAA8B;AAC9D,MAAI,WAAW,QAAe,0BAA0B,QAAQ;AAC5D,kDAA8C;AAAA,EAClD;AACA,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,MAAI,WAAW,SAAS;AACpB,sCAAkC,OAAO;AAAA,EAC7C;AACA,MAAI;AACJ,MAAI,OAAgD;AAChD,uBAAmB,EAAE,YAAY,OAAO,qBAAqB;AAAA,EACjE;AACA,QAAM,gBAAgB,WAAW,iBAAiB,OAAO;AACzD,SAAO,eAAe,gBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,EACJ,GAAoD;AAChD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,UAAM,cAAc;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,QACL,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,QACR,kBAAkB,KAAK,OAAO,SAAS;AAAA,QACvC,gBAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACJ;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAIA,aAAY,yCAAyC;AAAA,QAC3D,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACzB,CAAC;AAAA,IACL;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AACJ","sourcesContent":["// Clever obfuscation to prevent the build system from inlining the value of `NODE_ENV`\nexport const __DEV__ = /* @__PURE__ */ (() => (process as any)['en' + 'v'].NODE_ENV === 'development')();\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SolanaError } from '@solana/errors';\nimport { RpcTransport } from '@solana/rpc-spec';\nimport type Dispatcher from 'undici/types/dispatcher';\n\nimport {\n AllowedHttpRequestHeaders,\n assertIsAllowedHttpRequestHeaders,\n normalizeHeaders,\n} from './http-transport-headers';\n\ntype Config = Readonly<{\n dispatcher_NODE_ONLY?: Dispatcher;\n headers?: AllowedHttpRequestHeaders;\n url: string;\n}>;\n\nlet didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;\nfunction warnDispatcherWasSuppliedInNonNodeEnvironment() {\n if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {\n return;\n }\n didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;\n console.warn(\n 'You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored ' +\n 'because Undici dispatchers only work in Node environments. To eliminate this ' +\n 'warning, omit the `dispatcher_NODE_ONLY` property from your config when running in ' +\n 'a non-Node environment.',\n );\n}\n\nexport function createHttpTransport(config: Config): RpcTransport {\n if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n warnDispatcherWasSuppliedInNonNodeEnvironment();\n }\n const { headers, url } = config;\n if (__DEV__ && headers) {\n assertIsAllowedHttpRequestHeaders(headers);\n }\n let dispatcherConfig: { dispatcher: Dispatcher | undefined } | undefined;\n if (__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };\n }\n const customHeaders = headers && normalizeHeaders(headers);\n return async function makeHttpRequest<TResponse>({\n payload,\n signal,\n }: Parameters<RpcTransport>[0]): Promise<TResponse> {\n const body = JSON.stringify(payload);\n const requestInfo = {\n ...dispatcherConfig,\n body,\n headers: {\n ...customHeaders,\n // Keep these headers lowercase so they will override any user-supplied headers above.\n accept: 'application/json',\n 'content-length': body.length.toString(),\n 'content-type': 'application/json; charset=utf-8',\n },\n method: 'POST',\n signal,\n };\n const response = await fetch(url, requestInfo);\n if (!response.ok) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {\n message: response.statusText,\n statusCode: response.status,\n });\n }\n return (await response.json()) as TResponse;\n };\n}\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, SolanaError } from '@solana/errors';\n\nexport type AllowedHttpRequestHeaders = Readonly<\n {\n // Someone can still sneak a forbidden header past Typescript if they do something like\n // fOo-BaR, but at that point they deserve the runtime failure.\n [K in DisallowedHeaders | ForbiddenHeaders as\n | Capitalize<Lowercase<K>> // `Foo-bar`\n | K // `Foo-Bar`\n | Lowercase<K> // `foo-bar`\n | Uncapitalize<K> // `foo-Bar`\n // `FOO-BAR`\n | Uppercase<K>]?: never;\n } & { [headerName: string]: string }\n>;\n// These are headers that we simply don't allow the developer to override because they're\n// fundamental to the operation of the JSON-RPC transport.\ntype DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';\ntype ForbiddenHeaders =\n | 'Accept-Charset'\n | 'Accept-Encoding'\n | 'Access-Control-Request-Headers'\n | 'Access-Control-Request-Method'\n | 'Connection'\n | 'Content-Length'\n | 'Cookie'\n | 'Date'\n | 'DNT'\n | 'Expect'\n | 'Host'\n | 'Keep-Alive'\n | 'Origin'\n | 'Permissions-Policy'\n | 'Referer'\n | 'TE'\n | 'Trailer'\n | 'Transfer-Encoding'\n | 'Upgrade'\n | 'Via'\n | `Proxy-${string}`\n | `Sec-${string}`;\n\n// These are headers which are fundamental to the JSON-RPC transport, and must not be modified.\nconst DISALLOWED_HEADERS: Record<string, boolean> = {\n accept: true,\n 'content-length': true,\n 'content-type': true,\n};\n// https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\nconst FORBIDDEN_HEADERS: Record<string, boolean> = {\n 'accept-charset': true,\n 'accept-encoding': true,\n 'access-control-request-headers': true,\n 'access-control-request-method': true,\n connection: true,\n 'content-length': true,\n cookie: true,\n date: true,\n dnt: true,\n expect: true,\n host: true,\n 'keep-alive': true,\n origin: true,\n 'permissions-policy': true,\n // Prefix matching is implemented in code, below.\n // 'proxy-': true,\n // 'sec-': true,\n referer: true,\n te: true,\n trailer: true,\n 'transfer-encoding': true,\n upgrade: true,\n via: true,\n};\n\nexport function assertIsAllowedHttpRequestHeaders(\n headers: Record<string, string>,\n): asserts headers is AllowedHttpRequestHeaders {\n const badHeaders = Object.keys(headers).filter(headerName => {\n const lowercaseHeaderName = headerName.toLowerCase();\n return (\n DISALLOWED_HEADERS[headerName.toLowerCase()] === true ||\n FORBIDDEN_HEADERS[headerName.toLowerCase()] === true ||\n lowercaseHeaderName.startsWith('proxy-') ||\n lowercaseHeaderName.startsWith('sec-')\n );\n });\n if (badHeaders.length > 0) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {\n headers: badHeaders,\n });\n }\n}\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers, such as those defined\n * in the `DisallowedHeaders` type.\n */\nexport function normalizeHeaders<T extends Record<string, string>>(\n headers: T,\n): { [K in string & keyof T 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 string & keyof T as Lowercase<K>]: T[K] };\n}\n"]}
@@ -0,0 +1,106 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN } from '@solana/errors';
2
+
3
+ // ../build-scripts/env-shim.ts
4
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
5
+ var DISALLOWED_HEADERS = {
6
+ accept: true,
7
+ "content-length": true,
8
+ "content-type": true
9
+ };
10
+ var FORBIDDEN_HEADERS = {
11
+ "accept-charset": true,
12
+ "accept-encoding": true,
13
+ "access-control-request-headers": true,
14
+ "access-control-request-method": true,
15
+ connection: true,
16
+ "content-length": true,
17
+ cookie: true,
18
+ date: true,
19
+ dnt: true,
20
+ expect: true,
21
+ host: true,
22
+ "keep-alive": true,
23
+ origin: true,
24
+ "permissions-policy": true,
25
+ // Prefix matching is implemented in code, below.
26
+ // 'proxy-': true,
27
+ // 'sec-': true,
28
+ referer: true,
29
+ te: true,
30
+ trailer: true,
31
+ "transfer-encoding": true,
32
+ upgrade: true,
33
+ via: true
34
+ };
35
+ function assertIsAllowedHttpRequestHeaders(headers) {
36
+ const badHeaders = Object.keys(headers).filter((headerName) => {
37
+ const lowercaseHeaderName = headerName.toLowerCase();
38
+ return DISALLOWED_HEADERS[headerName.toLowerCase()] === true || FORBIDDEN_HEADERS[headerName.toLowerCase()] === true || lowercaseHeaderName.startsWith("proxy-") || lowercaseHeaderName.startsWith("sec-");
39
+ });
40
+ if (badHeaders.length > 0) {
41
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {
42
+ headers: badHeaders
43
+ });
44
+ }
45
+ }
46
+ function normalizeHeaders(headers) {
47
+ const out = {};
48
+ for (const headerName in headers) {
49
+ out[headerName.toLowerCase()] = headers[headerName];
50
+ }
51
+ return out;
52
+ }
53
+
54
+ // src/http-transport.ts
55
+ var didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;
56
+ function warnDispatcherWasSuppliedInNonNodeEnvironment() {
57
+ if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {
58
+ return;
59
+ }
60
+ didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;
61
+ console.warn(
62
+ "You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored because Undici dispatchers only work in Node environments. To eliminate this warning, omit the `dispatcher_NODE_ONLY` property from your config when running in a non-Node environment."
63
+ );
64
+ }
65
+ function createHttpTransport(config) {
66
+ if (__DEV__ && true && "dispatcher_NODE_ONLY" in config) {
67
+ warnDispatcherWasSuppliedInNonNodeEnvironment();
68
+ }
69
+ const { headers, url } = config;
70
+ if (__DEV__ && headers) {
71
+ assertIsAllowedHttpRequestHeaders(headers);
72
+ }
73
+ let dispatcherConfig;
74
+ const customHeaders = headers && normalizeHeaders(headers);
75
+ return async function makeHttpRequest({
76
+ payload,
77
+ signal
78
+ }) {
79
+ const body = JSON.stringify(payload);
80
+ const requestInfo = {
81
+ ...dispatcherConfig,
82
+ body,
83
+ headers: {
84
+ ...customHeaders,
85
+ // Keep these headers lowercase so they will override any user-supplied headers above.
86
+ accept: "application/json",
87
+ "content-length": body.length.toString(),
88
+ "content-type": "application/json; charset=utf-8"
89
+ },
90
+ method: "POST",
91
+ signal
92
+ };
93
+ const response = await fetch(url, requestInfo);
94
+ if (!response.ok) {
95
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
96
+ message: response.statusText,
97
+ statusCode: response.status
98
+ });
99
+ }
100
+ return await response.json();
101
+ };
102
+ }
103
+
104
+ export { createHttpTransport };
105
+ //# sourceMappingURL=out.js.map
106
+ //# sourceMappingURL=index.browser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../build-scripts/env-shim.ts","../src/http-transport.ts","../src/http-transport-headers.ts"],"names":["SolanaError"],"mappings":";AACO,IAAM,UAA2B,uBAAO,QAAgB,KAAU,EAAE,aAAa,eAAe;;;ACDvG,SAAS,yCAAyC,eAAAA,oBAAmB;;;ACArE,SAAS,oDAAoD,mBAAmB;AA2ChF,IAAM,qBAA8C;AAAA,EAChD,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AACpB;AAEA,IAAM,oBAA6C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,sBAAsB;AAAA;AAAA;AAAA;AAAA,EAItB,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,KAAK;AACT;AAEO,SAAS,kCACZ,SAC4C;AAC5C,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,OAAO,gBAAc;AACzD,UAAM,sBAAsB,WAAW,YAAY;AACnD,WACI,mBAAmB,WAAW,YAAY,CAAC,MAAM,QACjD,kBAAkB,WAAW,YAAY,CAAC,MAAM,QAChD,oBAAoB,WAAW,QAAQ,KACvC,oBAAoB,WAAW,MAAM;AAAA,EAE7C,CAAC;AACD,MAAI,WAAW,SAAS,GAAG;AACvB,UAAM,IAAI,YAAY,oDAAoD;AAAA,MACtE,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AACJ;AAMO,SAAS,iBACZ,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;;;AD1FA,IAAI,mDAAmD;AACvD,SAAS,gDAAgD;AACrD,MAAI,kDAAkD;AAClD;AAAA,EACJ;AACA,qDAAmD;AACnD,UAAQ;AAAA,IACJ;AAAA,EAIJ;AACJ;AAEO,SAAS,oBAAoB,QAA8B;AAC9D,MAAI,WAAW,QAAe,0BAA0B,QAAQ;AAC5D,kDAA8C;AAAA,EAClD;AACA,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,MAAI,WAAW,SAAS;AACpB,sCAAkC,OAAO;AAAA,EAC7C;AACA,MAAI;AACJ,MAAI,OAAgD;AAChD,uBAAmB,EAAE,YAAY,OAAO,qBAAqB;AAAA,EACjE;AACA,QAAM,gBAAgB,WAAW,iBAAiB,OAAO;AACzD,SAAO,eAAe,gBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,EACJ,GAAoD;AAChD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,UAAM,cAAc;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,QACL,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,QACR,kBAAkB,KAAK,OAAO,SAAS;AAAA,QACvC,gBAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACJ;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAIA,aAAY,yCAAyC;AAAA,QAC3D,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACzB,CAAC;AAAA,IACL;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AACJ","sourcesContent":["// Clever obfuscation to prevent the build system from inlining the value of `NODE_ENV`\nexport const __DEV__ = /* @__PURE__ */ (() => (process as any)['en' + 'v'].NODE_ENV === 'development')();\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SolanaError } from '@solana/errors';\nimport { RpcTransport } from '@solana/rpc-spec';\nimport type Dispatcher from 'undici/types/dispatcher';\n\nimport {\n AllowedHttpRequestHeaders,\n assertIsAllowedHttpRequestHeaders,\n normalizeHeaders,\n} from './http-transport-headers';\n\ntype Config = Readonly<{\n dispatcher_NODE_ONLY?: Dispatcher;\n headers?: AllowedHttpRequestHeaders;\n url: string;\n}>;\n\nlet didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;\nfunction warnDispatcherWasSuppliedInNonNodeEnvironment() {\n if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {\n return;\n }\n didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;\n console.warn(\n 'You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored ' +\n 'because Undici dispatchers only work in Node environments. To eliminate this ' +\n 'warning, omit the `dispatcher_NODE_ONLY` property from your config when running in ' +\n 'a non-Node environment.',\n );\n}\n\nexport function createHttpTransport(config: Config): RpcTransport {\n if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n warnDispatcherWasSuppliedInNonNodeEnvironment();\n }\n const { headers, url } = config;\n if (__DEV__ && headers) {\n assertIsAllowedHttpRequestHeaders(headers);\n }\n let dispatcherConfig: { dispatcher: Dispatcher | undefined } | undefined;\n if (__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };\n }\n const customHeaders = headers && normalizeHeaders(headers);\n return async function makeHttpRequest<TResponse>({\n payload,\n signal,\n }: Parameters<RpcTransport>[0]): Promise<TResponse> {\n const body = JSON.stringify(payload);\n const requestInfo = {\n ...dispatcherConfig,\n body,\n headers: {\n ...customHeaders,\n // Keep these headers lowercase so they will override any user-supplied headers above.\n accept: 'application/json',\n 'content-length': body.length.toString(),\n 'content-type': 'application/json; charset=utf-8',\n },\n method: 'POST',\n signal,\n };\n const response = await fetch(url, requestInfo);\n if (!response.ok) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {\n message: response.statusText,\n statusCode: response.status,\n });\n }\n return (await response.json()) as TResponse;\n };\n}\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, SolanaError } from '@solana/errors';\n\nexport type AllowedHttpRequestHeaders = Readonly<\n {\n // Someone can still sneak a forbidden header past Typescript if they do something like\n // fOo-BaR, but at that point they deserve the runtime failure.\n [K in DisallowedHeaders | ForbiddenHeaders as\n | Capitalize<Lowercase<K>> // `Foo-bar`\n | K // `Foo-Bar`\n | Lowercase<K> // `foo-bar`\n | Uncapitalize<K> // `foo-Bar`\n // `FOO-BAR`\n | Uppercase<K>]?: never;\n } & { [headerName: string]: string }\n>;\n// These are headers that we simply don't allow the developer to override because they're\n// fundamental to the operation of the JSON-RPC transport.\ntype DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';\ntype ForbiddenHeaders =\n | 'Accept-Charset'\n | 'Accept-Encoding'\n | 'Access-Control-Request-Headers'\n | 'Access-Control-Request-Method'\n | 'Connection'\n | 'Content-Length'\n | 'Cookie'\n | 'Date'\n | 'DNT'\n | 'Expect'\n | 'Host'\n | 'Keep-Alive'\n | 'Origin'\n | 'Permissions-Policy'\n | 'Referer'\n | 'TE'\n | 'Trailer'\n | 'Transfer-Encoding'\n | 'Upgrade'\n | 'Via'\n | `Proxy-${string}`\n | `Sec-${string}`;\n\n// These are headers which are fundamental to the JSON-RPC transport, and must not be modified.\nconst DISALLOWED_HEADERS: Record<string, boolean> = {\n accept: true,\n 'content-length': true,\n 'content-type': true,\n};\n// https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\nconst FORBIDDEN_HEADERS: Record<string, boolean> = {\n 'accept-charset': true,\n 'accept-encoding': true,\n 'access-control-request-headers': true,\n 'access-control-request-method': true,\n connection: true,\n 'content-length': true,\n cookie: true,\n date: true,\n dnt: true,\n expect: true,\n host: true,\n 'keep-alive': true,\n origin: true,\n 'permissions-policy': true,\n // Prefix matching is implemented in code, below.\n // 'proxy-': true,\n // 'sec-': true,\n referer: true,\n te: true,\n trailer: true,\n 'transfer-encoding': true,\n upgrade: true,\n via: true,\n};\n\nexport function assertIsAllowedHttpRequestHeaders(\n headers: Record<string, string>,\n): asserts headers is AllowedHttpRequestHeaders {\n const badHeaders = Object.keys(headers).filter(headerName => {\n const lowercaseHeaderName = headerName.toLowerCase();\n return (\n DISALLOWED_HEADERS[headerName.toLowerCase()] === true ||\n FORBIDDEN_HEADERS[headerName.toLowerCase()] === true ||\n lowercaseHeaderName.startsWith('proxy-') ||\n lowercaseHeaderName.startsWith('sec-')\n );\n });\n if (badHeaders.length > 0) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {\n headers: badHeaders,\n });\n }\n}\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers, such as those defined\n * in the `DisallowedHeaders` type.\n */\nexport function normalizeHeaders<T extends Record<string, string>>(\n headers: T,\n): { [K in string & keyof T 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 string & keyof T as Lowercase<K>]: T[K] };\n}\n"]}
@@ -0,0 +1,106 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN } from '@solana/errors';
2
+
3
+ // ../build-scripts/env-shim.ts
4
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
5
+ var DISALLOWED_HEADERS = {
6
+ accept: true,
7
+ "content-length": true,
8
+ "content-type": true
9
+ };
10
+ var FORBIDDEN_HEADERS = {
11
+ "accept-charset": true,
12
+ "accept-encoding": true,
13
+ "access-control-request-headers": true,
14
+ "access-control-request-method": true,
15
+ connection: true,
16
+ "content-length": true,
17
+ cookie: true,
18
+ date: true,
19
+ dnt: true,
20
+ expect: true,
21
+ host: true,
22
+ "keep-alive": true,
23
+ origin: true,
24
+ "permissions-policy": true,
25
+ // Prefix matching is implemented in code, below.
26
+ // 'proxy-': true,
27
+ // 'sec-': true,
28
+ referer: true,
29
+ te: true,
30
+ trailer: true,
31
+ "transfer-encoding": true,
32
+ upgrade: true,
33
+ via: true
34
+ };
35
+ function assertIsAllowedHttpRequestHeaders(headers) {
36
+ const badHeaders = Object.keys(headers).filter((headerName) => {
37
+ const lowercaseHeaderName = headerName.toLowerCase();
38
+ return DISALLOWED_HEADERS[headerName.toLowerCase()] === true || FORBIDDEN_HEADERS[headerName.toLowerCase()] === true || lowercaseHeaderName.startsWith("proxy-") || lowercaseHeaderName.startsWith("sec-");
39
+ });
40
+ if (badHeaders.length > 0) {
41
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {
42
+ headers: badHeaders
43
+ });
44
+ }
45
+ }
46
+ function normalizeHeaders(headers) {
47
+ const out = {};
48
+ for (const headerName in headers) {
49
+ out[headerName.toLowerCase()] = headers[headerName];
50
+ }
51
+ return out;
52
+ }
53
+
54
+ // src/http-transport.ts
55
+ var didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;
56
+ function warnDispatcherWasSuppliedInNonNodeEnvironment() {
57
+ if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {
58
+ return;
59
+ }
60
+ didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;
61
+ console.warn(
62
+ "You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored because Undici dispatchers only work in Node environments. To eliminate this warning, omit the `dispatcher_NODE_ONLY` property from your config when running in a non-Node environment."
63
+ );
64
+ }
65
+ function createHttpTransport(config) {
66
+ if (__DEV__ && true && "dispatcher_NODE_ONLY" in config) {
67
+ warnDispatcherWasSuppliedInNonNodeEnvironment();
68
+ }
69
+ const { headers, url } = config;
70
+ if (__DEV__ && headers) {
71
+ assertIsAllowedHttpRequestHeaders(headers);
72
+ }
73
+ let dispatcherConfig;
74
+ const customHeaders = headers && normalizeHeaders(headers);
75
+ return async function makeHttpRequest({
76
+ payload,
77
+ signal
78
+ }) {
79
+ const body = JSON.stringify(payload);
80
+ const requestInfo = {
81
+ ...dispatcherConfig,
82
+ body,
83
+ headers: {
84
+ ...customHeaders,
85
+ // Keep these headers lowercase so they will override any user-supplied headers above.
86
+ accept: "application/json",
87
+ "content-length": body.length.toString(),
88
+ "content-type": "application/json; charset=utf-8"
89
+ },
90
+ method: "POST",
91
+ signal
92
+ };
93
+ const response = await fetch(url, requestInfo);
94
+ if (!response.ok) {
95
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
96
+ message: response.statusText,
97
+ statusCode: response.status
98
+ });
99
+ }
100
+ return await response.json();
101
+ };
102
+ }
103
+
104
+ export { createHttpTransport };
105
+ //# sourceMappingURL=out.js.map
106
+ //# sourceMappingURL=index.native.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../build-scripts/env-shim.ts","../src/http-transport.ts","../src/http-transport-headers.ts"],"names":["SolanaError"],"mappings":";AACO,IAAM,UAA2B,uBAAO,QAAgB,KAAU,EAAE,aAAa,eAAe;;;ACDvG,SAAS,yCAAyC,eAAAA,oBAAmB;;;ACArE,SAAS,oDAAoD,mBAAmB;AA2ChF,IAAM,qBAA8C;AAAA,EAChD,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AACpB;AAEA,IAAM,oBAA6C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,sBAAsB;AAAA;AAAA;AAAA;AAAA,EAItB,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,KAAK;AACT;AAEO,SAAS,kCACZ,SAC4C;AAC5C,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,OAAO,gBAAc;AACzD,UAAM,sBAAsB,WAAW,YAAY;AACnD,WACI,mBAAmB,WAAW,YAAY,CAAC,MAAM,QACjD,kBAAkB,WAAW,YAAY,CAAC,MAAM,QAChD,oBAAoB,WAAW,QAAQ,KACvC,oBAAoB,WAAW,MAAM;AAAA,EAE7C,CAAC;AACD,MAAI,WAAW,SAAS,GAAG;AACvB,UAAM,IAAI,YAAY,oDAAoD;AAAA,MACtE,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AACJ;AAMO,SAAS,iBACZ,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;;;AD1FA,IAAI,mDAAmD;AACvD,SAAS,gDAAgD;AACrD,MAAI,kDAAkD;AAClD;AAAA,EACJ;AACA,qDAAmD;AACnD,UAAQ;AAAA,IACJ;AAAA,EAIJ;AACJ;AAEO,SAAS,oBAAoB,QAA8B;AAC9D,MAAI,WAAW,QAAe,0BAA0B,QAAQ;AAC5D,kDAA8C;AAAA,EAClD;AACA,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,MAAI,WAAW,SAAS;AACpB,sCAAkC,OAAO;AAAA,EAC7C;AACA,MAAI;AACJ,MAAI,OAAgD;AAChD,uBAAmB,EAAE,YAAY,OAAO,qBAAqB;AAAA,EACjE;AACA,QAAM,gBAAgB,WAAW,iBAAiB,OAAO;AACzD,SAAO,eAAe,gBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,EACJ,GAAoD;AAChD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,UAAM,cAAc;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,QACL,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,QACR,kBAAkB,KAAK,OAAO,SAAS;AAAA,QACvC,gBAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACJ;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAIA,aAAY,yCAAyC;AAAA,QAC3D,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACzB,CAAC;AAAA,IACL;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AACJ","sourcesContent":["// Clever obfuscation to prevent the build system from inlining the value of `NODE_ENV`\nexport const __DEV__ = /* @__PURE__ */ (() => (process as any)['en' + 'v'].NODE_ENV === 'development')();\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SolanaError } from '@solana/errors';\nimport { RpcTransport } from '@solana/rpc-spec';\nimport type Dispatcher from 'undici/types/dispatcher';\n\nimport {\n AllowedHttpRequestHeaders,\n assertIsAllowedHttpRequestHeaders,\n normalizeHeaders,\n} from './http-transport-headers';\n\ntype Config = Readonly<{\n dispatcher_NODE_ONLY?: Dispatcher;\n headers?: AllowedHttpRequestHeaders;\n url: string;\n}>;\n\nlet didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;\nfunction warnDispatcherWasSuppliedInNonNodeEnvironment() {\n if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {\n return;\n }\n didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;\n console.warn(\n 'You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored ' +\n 'because Undici dispatchers only work in Node environments. To eliminate this ' +\n 'warning, omit the `dispatcher_NODE_ONLY` property from your config when running in ' +\n 'a non-Node environment.',\n );\n}\n\nexport function createHttpTransport(config: Config): RpcTransport {\n if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n warnDispatcherWasSuppliedInNonNodeEnvironment();\n }\n const { headers, url } = config;\n if (__DEV__ && headers) {\n assertIsAllowedHttpRequestHeaders(headers);\n }\n let dispatcherConfig: { dispatcher: Dispatcher | undefined } | undefined;\n if (__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };\n }\n const customHeaders = headers && normalizeHeaders(headers);\n return async function makeHttpRequest<TResponse>({\n payload,\n signal,\n }: Parameters<RpcTransport>[0]): Promise<TResponse> {\n const body = JSON.stringify(payload);\n const requestInfo = {\n ...dispatcherConfig,\n body,\n headers: {\n ...customHeaders,\n // Keep these headers lowercase so they will override any user-supplied headers above.\n accept: 'application/json',\n 'content-length': body.length.toString(),\n 'content-type': 'application/json; charset=utf-8',\n },\n method: 'POST',\n signal,\n };\n const response = await fetch(url, requestInfo);\n if (!response.ok) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {\n message: response.statusText,\n statusCode: response.status,\n });\n }\n return (await response.json()) as TResponse;\n };\n}\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, SolanaError } from '@solana/errors';\n\nexport type AllowedHttpRequestHeaders = Readonly<\n {\n // Someone can still sneak a forbidden header past Typescript if they do something like\n // fOo-BaR, but at that point they deserve the runtime failure.\n [K in DisallowedHeaders | ForbiddenHeaders as\n | Capitalize<Lowercase<K>> // `Foo-bar`\n | K // `Foo-Bar`\n | Lowercase<K> // `foo-bar`\n | Uncapitalize<K> // `foo-Bar`\n // `FOO-BAR`\n | Uppercase<K>]?: never;\n } & { [headerName: string]: string }\n>;\n// These are headers that we simply don't allow the developer to override because they're\n// fundamental to the operation of the JSON-RPC transport.\ntype DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';\ntype ForbiddenHeaders =\n | 'Accept-Charset'\n | 'Accept-Encoding'\n | 'Access-Control-Request-Headers'\n | 'Access-Control-Request-Method'\n | 'Connection'\n | 'Content-Length'\n | 'Cookie'\n | 'Date'\n | 'DNT'\n | 'Expect'\n | 'Host'\n | 'Keep-Alive'\n | 'Origin'\n | 'Permissions-Policy'\n | 'Referer'\n | 'TE'\n | 'Trailer'\n | 'Transfer-Encoding'\n | 'Upgrade'\n | 'Via'\n | `Proxy-${string}`\n | `Sec-${string}`;\n\n// These are headers which are fundamental to the JSON-RPC transport, and must not be modified.\nconst DISALLOWED_HEADERS: Record<string, boolean> = {\n accept: true,\n 'content-length': true,\n 'content-type': true,\n};\n// https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\nconst FORBIDDEN_HEADERS: Record<string, boolean> = {\n 'accept-charset': true,\n 'accept-encoding': true,\n 'access-control-request-headers': true,\n 'access-control-request-method': true,\n connection: true,\n 'content-length': true,\n cookie: true,\n date: true,\n dnt: true,\n expect: true,\n host: true,\n 'keep-alive': true,\n origin: true,\n 'permissions-policy': true,\n // Prefix matching is implemented in code, below.\n // 'proxy-': true,\n // 'sec-': true,\n referer: true,\n te: true,\n trailer: true,\n 'transfer-encoding': true,\n upgrade: true,\n via: true,\n};\n\nexport function assertIsAllowedHttpRequestHeaders(\n headers: Record<string, string>,\n): asserts headers is AllowedHttpRequestHeaders {\n const badHeaders = Object.keys(headers).filter(headerName => {\n const lowercaseHeaderName = headerName.toLowerCase();\n return (\n DISALLOWED_HEADERS[headerName.toLowerCase()] === true ||\n FORBIDDEN_HEADERS[headerName.toLowerCase()] === true ||\n lowercaseHeaderName.startsWith('proxy-') ||\n lowercaseHeaderName.startsWith('sec-')\n );\n });\n if (badHeaders.length > 0) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {\n headers: badHeaders,\n });\n }\n}\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers, such as those defined\n * in the `DisallowedHeaders` type.\n */\nexport function normalizeHeaders<T extends Record<string, string>>(\n headers: T,\n): { [K in string & keyof T 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 string & keyof T as Lowercase<K>]: T[K] };\n}\n"]}
@@ -0,0 +1,101 @@
1
+ 'use strict';
2
+
3
+ var errors = require('@solana/errors');
4
+
5
+ // ../build-scripts/env-shim.ts
6
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
7
+ var DISALLOWED_HEADERS = {
8
+ accept: true,
9
+ "content-length": true,
10
+ "content-type": true
11
+ };
12
+ var FORBIDDEN_HEADERS = {
13
+ "accept-charset": true,
14
+ "accept-encoding": true,
15
+ "access-control-request-headers": true,
16
+ "access-control-request-method": true,
17
+ connection: true,
18
+ "content-length": true,
19
+ cookie: true,
20
+ date: true,
21
+ dnt: true,
22
+ expect: true,
23
+ host: true,
24
+ "keep-alive": true,
25
+ origin: true,
26
+ "permissions-policy": true,
27
+ // Prefix matching is implemented in code, below.
28
+ // 'proxy-': true,
29
+ // 'sec-': true,
30
+ referer: true,
31
+ te: true,
32
+ trailer: true,
33
+ "transfer-encoding": true,
34
+ upgrade: true,
35
+ via: true
36
+ };
37
+ function assertIsAllowedHttpRequestHeaders(headers) {
38
+ const badHeaders = Object.keys(headers).filter((headerName) => {
39
+ const lowercaseHeaderName = headerName.toLowerCase();
40
+ return DISALLOWED_HEADERS[headerName.toLowerCase()] === true || FORBIDDEN_HEADERS[headerName.toLowerCase()] === true || lowercaseHeaderName.startsWith("proxy-") || lowercaseHeaderName.startsWith("sec-");
41
+ });
42
+ if (badHeaders.length > 0) {
43
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {
44
+ headers: badHeaders
45
+ });
46
+ }
47
+ }
48
+ function normalizeHeaders(headers) {
49
+ const out = {};
50
+ for (const headerName in headers) {
51
+ out[headerName.toLowerCase()] = headers[headerName];
52
+ }
53
+ return out;
54
+ }
55
+
56
+ // src/http-transport.ts
57
+ function createHttpTransport(config) {
58
+ if (__DEV__ && false) {
59
+ warnDispatcherWasSuppliedInNonNodeEnvironment();
60
+ }
61
+ const { headers, url } = config;
62
+ if (__DEV__ && headers) {
63
+ assertIsAllowedHttpRequestHeaders(headers);
64
+ }
65
+ let dispatcherConfig;
66
+ if ("dispatcher_NODE_ONLY" in config) {
67
+ dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };
68
+ }
69
+ const customHeaders = headers && normalizeHeaders(headers);
70
+ return async function makeHttpRequest({
71
+ payload,
72
+ signal
73
+ }) {
74
+ const body = JSON.stringify(payload);
75
+ const requestInfo = {
76
+ ...dispatcherConfig,
77
+ body,
78
+ headers: {
79
+ ...customHeaders,
80
+ // Keep these headers lowercase so they will override any user-supplied headers above.
81
+ accept: "application/json",
82
+ "content-length": body.length.toString(),
83
+ "content-type": "application/json; charset=utf-8"
84
+ },
85
+ method: "POST",
86
+ signal
87
+ };
88
+ const response = await fetch(url, requestInfo);
89
+ if (!response.ok) {
90
+ throw new errors.SolanaError(errors.SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
91
+ message: response.statusText,
92
+ statusCode: response.status
93
+ });
94
+ }
95
+ return await response.json();
96
+ };
97
+ }
98
+
99
+ exports.createHttpTransport = createHttpTransport;
100
+ //# sourceMappingURL=out.js.map
101
+ //# sourceMappingURL=index.node.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../build-scripts/env-shim.ts","../src/http-transport.ts","../src/http-transport-headers.ts"],"names":["SolanaError"],"mappings":";AACO,IAAM,UAA2B,uBAAO,QAAgB,KAAU,EAAE,aAAa,eAAe;;;ACDvG,SAAS,yCAAyC,eAAAA,oBAAmB;;;ACArE,SAAS,oDAAoD,mBAAmB;AA2ChF,IAAM,qBAA8C;AAAA,EAChD,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AACpB;AAEA,IAAM,oBAA6C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,sBAAsB;AAAA;AAAA;AAAA;AAAA,EAItB,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,KAAK;AACT;AAEO,SAAS,kCACZ,SAC4C;AAC5C,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,OAAO,gBAAc;AACzD,UAAM,sBAAsB,WAAW,YAAY;AACnD,WACI,mBAAmB,WAAW,YAAY,CAAC,MAAM,QACjD,kBAAkB,WAAW,YAAY,CAAC,MAAM,QAChD,oBAAoB,WAAW,QAAQ,KACvC,oBAAoB,WAAW,MAAM;AAAA,EAE7C,CAAC;AACD,MAAI,WAAW,SAAS,GAAG;AACvB,UAAM,IAAI,YAAY,oDAAoD;AAAA,MACtE,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AACJ;AAMO,SAAS,iBACZ,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;;;AD5EO,SAAS,oBAAoB,QAA8B;AAC9D,MAAI,WAAW,OAAiD;AAC5D,kDAA8C;AAAA,EAClD;AACA,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,MAAI,WAAW,SAAS;AACpB,sCAAkC,OAAO;AAAA,EAC7C;AACA,MAAI;AACJ,MAAkB,0BAA0B,QAAQ;AAChD,uBAAmB,EAAE,YAAY,OAAO,qBAAqB;AAAA,EACjE;AACA,QAAM,gBAAgB,WAAW,iBAAiB,OAAO;AACzD,SAAO,eAAe,gBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,EACJ,GAAoD;AAChD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,UAAM,cAAc;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,QACL,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,QACR,kBAAkB,KAAK,OAAO,SAAS;AAAA,QACvC,gBAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACJ;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAIA,aAAY,yCAAyC;AAAA,QAC3D,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACzB,CAAC;AAAA,IACL;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AACJ","sourcesContent":["// Clever obfuscation to prevent the build system from inlining the value of `NODE_ENV`\nexport const __DEV__ = /* @__PURE__ */ (() => (process as any)['en' + 'v'].NODE_ENV === 'development')();\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SolanaError } from '@solana/errors';\nimport { RpcTransport } from '@solana/rpc-spec';\nimport type Dispatcher from 'undici/types/dispatcher';\n\nimport {\n AllowedHttpRequestHeaders,\n assertIsAllowedHttpRequestHeaders,\n normalizeHeaders,\n} from './http-transport-headers';\n\ntype Config = Readonly<{\n dispatcher_NODE_ONLY?: Dispatcher;\n headers?: AllowedHttpRequestHeaders;\n url: string;\n}>;\n\nlet didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;\nfunction warnDispatcherWasSuppliedInNonNodeEnvironment() {\n if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {\n return;\n }\n didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;\n console.warn(\n 'You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored ' +\n 'because Undici dispatchers only work in Node environments. To eliminate this ' +\n 'warning, omit the `dispatcher_NODE_ONLY` property from your config when running in ' +\n 'a non-Node environment.',\n );\n}\n\nexport function createHttpTransport(config: Config): RpcTransport {\n if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n warnDispatcherWasSuppliedInNonNodeEnvironment();\n }\n const { headers, url } = config;\n if (__DEV__ && headers) {\n assertIsAllowedHttpRequestHeaders(headers);\n }\n let dispatcherConfig: { dispatcher: Dispatcher | undefined } | undefined;\n if (__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };\n }\n const customHeaders = headers && normalizeHeaders(headers);\n return async function makeHttpRequest<TResponse>({\n payload,\n signal,\n }: Parameters<RpcTransport>[0]): Promise<TResponse> {\n const body = JSON.stringify(payload);\n const requestInfo = {\n ...dispatcherConfig,\n body,\n headers: {\n ...customHeaders,\n // Keep these headers lowercase so they will override any user-supplied headers above.\n accept: 'application/json',\n 'content-length': body.length.toString(),\n 'content-type': 'application/json; charset=utf-8',\n },\n method: 'POST',\n signal,\n };\n const response = await fetch(url, requestInfo);\n if (!response.ok) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {\n message: response.statusText,\n statusCode: response.status,\n });\n }\n return (await response.json()) as TResponse;\n };\n}\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, SolanaError } from '@solana/errors';\n\nexport type AllowedHttpRequestHeaders = Readonly<\n {\n // Someone can still sneak a forbidden header past Typescript if they do something like\n // fOo-BaR, but at that point they deserve the runtime failure.\n [K in DisallowedHeaders | ForbiddenHeaders as\n | Capitalize<Lowercase<K>> // `Foo-bar`\n | K // `Foo-Bar`\n | Lowercase<K> // `foo-bar`\n | Uncapitalize<K> // `foo-Bar`\n // `FOO-BAR`\n | Uppercase<K>]?: never;\n } & { [headerName: string]: string }\n>;\n// These are headers that we simply don't allow the developer to override because they're\n// fundamental to the operation of the JSON-RPC transport.\ntype DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';\ntype ForbiddenHeaders =\n | 'Accept-Charset'\n | 'Accept-Encoding'\n | 'Access-Control-Request-Headers'\n | 'Access-Control-Request-Method'\n | 'Connection'\n | 'Content-Length'\n | 'Cookie'\n | 'Date'\n | 'DNT'\n | 'Expect'\n | 'Host'\n | 'Keep-Alive'\n | 'Origin'\n | 'Permissions-Policy'\n | 'Referer'\n | 'TE'\n | 'Trailer'\n | 'Transfer-Encoding'\n | 'Upgrade'\n | 'Via'\n | `Proxy-${string}`\n | `Sec-${string}`;\n\n// These are headers which are fundamental to the JSON-RPC transport, and must not be modified.\nconst DISALLOWED_HEADERS: Record<string, boolean> = {\n accept: true,\n 'content-length': true,\n 'content-type': true,\n};\n// https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\nconst FORBIDDEN_HEADERS: Record<string, boolean> = {\n 'accept-charset': true,\n 'accept-encoding': true,\n 'access-control-request-headers': true,\n 'access-control-request-method': true,\n connection: true,\n 'content-length': true,\n cookie: true,\n date: true,\n dnt: true,\n expect: true,\n host: true,\n 'keep-alive': true,\n origin: true,\n 'permissions-policy': true,\n // Prefix matching is implemented in code, below.\n // 'proxy-': true,\n // 'sec-': true,\n referer: true,\n te: true,\n trailer: true,\n 'transfer-encoding': true,\n upgrade: true,\n via: true,\n};\n\nexport function assertIsAllowedHttpRequestHeaders(\n headers: Record<string, string>,\n): asserts headers is AllowedHttpRequestHeaders {\n const badHeaders = Object.keys(headers).filter(headerName => {\n const lowercaseHeaderName = headerName.toLowerCase();\n return (\n DISALLOWED_HEADERS[headerName.toLowerCase()] === true ||\n FORBIDDEN_HEADERS[headerName.toLowerCase()] === true ||\n lowercaseHeaderName.startsWith('proxy-') ||\n lowercaseHeaderName.startsWith('sec-')\n );\n });\n if (badHeaders.length > 0) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {\n headers: badHeaders,\n });\n }\n}\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers, such as those defined\n * in the `DisallowedHeaders` type.\n */\nexport function normalizeHeaders<T extends Record<string, string>>(\n headers: T,\n): { [K in string & keyof T 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 string & keyof T as Lowercase<K>]: T[K] };\n}\n"]}
@@ -0,0 +1,99 @@
1
+ import { SolanaError, SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN } from '@solana/errors';
2
+
3
+ // ../build-scripts/env-shim.ts
4
+ var __DEV__ = /* @__PURE__ */ (() => process["env"].NODE_ENV === "development")();
5
+ var DISALLOWED_HEADERS = {
6
+ accept: true,
7
+ "content-length": true,
8
+ "content-type": true
9
+ };
10
+ var FORBIDDEN_HEADERS = {
11
+ "accept-charset": true,
12
+ "accept-encoding": true,
13
+ "access-control-request-headers": true,
14
+ "access-control-request-method": true,
15
+ connection: true,
16
+ "content-length": true,
17
+ cookie: true,
18
+ date: true,
19
+ dnt: true,
20
+ expect: true,
21
+ host: true,
22
+ "keep-alive": true,
23
+ origin: true,
24
+ "permissions-policy": true,
25
+ // Prefix matching is implemented in code, below.
26
+ // 'proxy-': true,
27
+ // 'sec-': true,
28
+ referer: true,
29
+ te: true,
30
+ trailer: true,
31
+ "transfer-encoding": true,
32
+ upgrade: true,
33
+ via: true
34
+ };
35
+ function assertIsAllowedHttpRequestHeaders(headers) {
36
+ const badHeaders = Object.keys(headers).filter((headerName) => {
37
+ const lowercaseHeaderName = headerName.toLowerCase();
38
+ return DISALLOWED_HEADERS[headerName.toLowerCase()] === true || FORBIDDEN_HEADERS[headerName.toLowerCase()] === true || lowercaseHeaderName.startsWith("proxy-") || lowercaseHeaderName.startsWith("sec-");
39
+ });
40
+ if (badHeaders.length > 0) {
41
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {
42
+ headers: badHeaders
43
+ });
44
+ }
45
+ }
46
+ function normalizeHeaders(headers) {
47
+ const out = {};
48
+ for (const headerName in headers) {
49
+ out[headerName.toLowerCase()] = headers[headerName];
50
+ }
51
+ return out;
52
+ }
53
+
54
+ // src/http-transport.ts
55
+ function createHttpTransport(config) {
56
+ if (__DEV__ && false) {
57
+ warnDispatcherWasSuppliedInNonNodeEnvironment();
58
+ }
59
+ const { headers, url } = config;
60
+ if (__DEV__ && headers) {
61
+ assertIsAllowedHttpRequestHeaders(headers);
62
+ }
63
+ let dispatcherConfig;
64
+ if ("dispatcher_NODE_ONLY" in config) {
65
+ dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };
66
+ }
67
+ const customHeaders = headers && normalizeHeaders(headers);
68
+ return async function makeHttpRequest({
69
+ payload,
70
+ signal
71
+ }) {
72
+ const body = JSON.stringify(payload);
73
+ const requestInfo = {
74
+ ...dispatcherConfig,
75
+ body,
76
+ headers: {
77
+ ...customHeaders,
78
+ // Keep these headers lowercase so they will override any user-supplied headers above.
79
+ accept: "application/json",
80
+ "content-length": body.length.toString(),
81
+ "content-type": "application/json; charset=utf-8"
82
+ },
83
+ method: "POST",
84
+ signal
85
+ };
86
+ const response = await fetch(url, requestInfo);
87
+ if (!response.ok) {
88
+ throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
89
+ message: response.statusText,
90
+ statusCode: response.status
91
+ });
92
+ }
93
+ return await response.json();
94
+ };
95
+ }
96
+
97
+ export { createHttpTransport };
98
+ //# sourceMappingURL=out.js.map
99
+ //# sourceMappingURL=index.node.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../build-scripts/env-shim.ts","../src/http-transport.ts","../src/http-transport-headers.ts"],"names":["SolanaError"],"mappings":";AACO,IAAM,UAA2B,uBAAO,QAAgB,KAAU,EAAE,aAAa,eAAe;;;ACDvG,SAAS,yCAAyC,eAAAA,oBAAmB;;;ACArE,SAAS,oDAAoD,mBAAmB;AA2ChF,IAAM,qBAA8C;AAAA,EAChD,QAAQ;AAAA,EACR,kBAAkB;AAAA,EAClB,gBAAgB;AACpB;AAEA,IAAM,oBAA6C;AAAA,EAC/C,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,kCAAkC;AAAA,EAClC,iCAAiC;AAAA,EACjC,YAAY;AAAA,EACZ,kBAAkB;AAAA,EAClB,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,KAAK;AAAA,EACL,QAAQ;AAAA,EACR,MAAM;AAAA,EACN,cAAc;AAAA,EACd,QAAQ;AAAA,EACR,sBAAsB;AAAA;AAAA;AAAA;AAAA,EAItB,SAAS;AAAA,EACT,IAAI;AAAA,EACJ,SAAS;AAAA,EACT,qBAAqB;AAAA,EACrB,SAAS;AAAA,EACT,KAAK;AACT;AAEO,SAAS,kCACZ,SAC4C;AAC5C,QAAM,aAAa,OAAO,KAAK,OAAO,EAAE,OAAO,gBAAc;AACzD,UAAM,sBAAsB,WAAW,YAAY;AACnD,WACI,mBAAmB,WAAW,YAAY,CAAC,MAAM,QACjD,kBAAkB,WAAW,YAAY,CAAC,MAAM,QAChD,oBAAoB,WAAW,QAAQ,KACvC,oBAAoB,WAAW,MAAM;AAAA,EAE7C,CAAC;AACD,MAAI,WAAW,SAAS,GAAG;AACvB,UAAM,IAAI,YAAY,oDAAoD;AAAA,MACtE,SAAS;AAAA,IACb,CAAC;AAAA,EACL;AACJ;AAMO,SAAS,iBACZ,SACiD;AACjD,QAAM,MAA8B,CAAC;AACrC,aAAW,cAAc,SAAS;AAC9B,QAAI,WAAW,YAAY,CAAC,IAAI,QAAQ,UAAU;AAAA,EACtD;AACA,SAAO;AACX;;;AD5EO,SAAS,oBAAoB,QAA8B;AAC9D,MAAI,WAAW,OAAiD;AAC5D,kDAA8C;AAAA,EAClD;AACA,QAAM,EAAE,SAAS,IAAI,IAAI;AACzB,MAAI,WAAW,SAAS;AACpB,sCAAkC,OAAO;AAAA,EAC7C;AACA,MAAI;AACJ,MAAkB,0BAA0B,QAAQ;AAChD,uBAAmB,EAAE,YAAY,OAAO,qBAAqB;AAAA,EACjE;AACA,QAAM,gBAAgB,WAAW,iBAAiB,OAAO;AACzD,SAAO,eAAe,gBAA2B;AAAA,IAC7C;AAAA,IACA;AAAA,EACJ,GAAoD;AAChD,UAAM,OAAO,KAAK,UAAU,OAAO;AACnC,UAAM,cAAc;AAAA,MAChB,GAAG;AAAA,MACH;AAAA,MACA,SAAS;AAAA,QACL,GAAG;AAAA;AAAA,QAEH,QAAQ;AAAA,QACR,kBAAkB,KAAK,OAAO,SAAS;AAAA,QACvC,gBAAgB;AAAA,MACpB;AAAA,MACA,QAAQ;AAAA,MACR;AAAA,IACJ;AACA,UAAM,WAAW,MAAM,MAAM,KAAK,WAAW;AAC7C,QAAI,CAAC,SAAS,IAAI;AACd,YAAM,IAAIA,aAAY,yCAAyC;AAAA,QAC3D,SAAS,SAAS;AAAA,QAClB,YAAY,SAAS;AAAA,MACzB,CAAC;AAAA,IACL;AACA,WAAQ,MAAM,SAAS,KAAK;AAAA,EAChC;AACJ","sourcesContent":["// Clever obfuscation to prevent the build system from inlining the value of `NODE_ENV`\nexport const __DEV__ = /* @__PURE__ */ (() => (process as any)['en' + 'v'].NODE_ENV === 'development')();\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, SolanaError } from '@solana/errors';\nimport { RpcTransport } from '@solana/rpc-spec';\nimport type Dispatcher from 'undici/types/dispatcher';\n\nimport {\n AllowedHttpRequestHeaders,\n assertIsAllowedHttpRequestHeaders,\n normalizeHeaders,\n} from './http-transport-headers';\n\ntype Config = Readonly<{\n dispatcher_NODE_ONLY?: Dispatcher;\n headers?: AllowedHttpRequestHeaders;\n url: string;\n}>;\n\nlet didWarnDispatcherWasSuppliedInNonNodeEnvironment = false;\nfunction warnDispatcherWasSuppliedInNonNodeEnvironment() {\n if (didWarnDispatcherWasSuppliedInNonNodeEnvironment) {\n return;\n }\n didWarnDispatcherWasSuppliedInNonNodeEnvironment = true;\n console.warn(\n 'You have supplied a `Dispatcher` to `createHttpTransport()`. It has been ignored ' +\n 'because Undici dispatchers only work in Node environments. To eliminate this ' +\n 'warning, omit the `dispatcher_NODE_ONLY` property from your config when running in ' +\n 'a non-Node environment.',\n );\n}\n\nexport function createHttpTransport(config: Config): RpcTransport {\n if (__DEV__ && !__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n warnDispatcherWasSuppliedInNonNodeEnvironment();\n }\n const { headers, url } = config;\n if (__DEV__ && headers) {\n assertIsAllowedHttpRequestHeaders(headers);\n }\n let dispatcherConfig: { dispatcher: Dispatcher | undefined } | undefined;\n if (__NODEJS__ && 'dispatcher_NODE_ONLY' in config) {\n dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };\n }\n const customHeaders = headers && normalizeHeaders(headers);\n return async function makeHttpRequest<TResponse>({\n payload,\n signal,\n }: Parameters<RpcTransport>[0]): Promise<TResponse> {\n const body = JSON.stringify(payload);\n const requestInfo = {\n ...dispatcherConfig,\n body,\n headers: {\n ...customHeaders,\n // Keep these headers lowercase so they will override any user-supplied headers above.\n accept: 'application/json',\n 'content-length': body.length.toString(),\n 'content-type': 'application/json; charset=utf-8',\n },\n method: 'POST',\n signal,\n };\n const response = await fetch(url, requestInfo);\n if (!response.ok) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {\n message: response.statusText,\n statusCode: response.status,\n });\n }\n return (await response.json()) as TResponse;\n };\n}\n","import { SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, SolanaError } from '@solana/errors';\n\nexport type AllowedHttpRequestHeaders = Readonly<\n {\n // Someone can still sneak a forbidden header past Typescript if they do something like\n // fOo-BaR, but at that point they deserve the runtime failure.\n [K in DisallowedHeaders | ForbiddenHeaders as\n | Capitalize<Lowercase<K>> // `Foo-bar`\n | K // `Foo-Bar`\n | Lowercase<K> // `foo-bar`\n | Uncapitalize<K> // `foo-Bar`\n // `FOO-BAR`\n | Uppercase<K>]?: never;\n } & { [headerName: string]: string }\n>;\n// These are headers that we simply don't allow the developer to override because they're\n// fundamental to the operation of the JSON-RPC transport.\ntype DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';\ntype ForbiddenHeaders =\n | 'Accept-Charset'\n | 'Accept-Encoding'\n | 'Access-Control-Request-Headers'\n | 'Access-Control-Request-Method'\n | 'Connection'\n | 'Content-Length'\n | 'Cookie'\n | 'Date'\n | 'DNT'\n | 'Expect'\n | 'Host'\n | 'Keep-Alive'\n | 'Origin'\n | 'Permissions-Policy'\n | 'Referer'\n | 'TE'\n | 'Trailer'\n | 'Transfer-Encoding'\n | 'Upgrade'\n | 'Via'\n | `Proxy-${string}`\n | `Sec-${string}`;\n\n// These are headers which are fundamental to the JSON-RPC transport, and must not be modified.\nconst DISALLOWED_HEADERS: Record<string, boolean> = {\n accept: true,\n 'content-length': true,\n 'content-type': true,\n};\n// https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name\nconst FORBIDDEN_HEADERS: Record<string, boolean> = {\n 'accept-charset': true,\n 'accept-encoding': true,\n 'access-control-request-headers': true,\n 'access-control-request-method': true,\n connection: true,\n 'content-length': true,\n cookie: true,\n date: true,\n dnt: true,\n expect: true,\n host: true,\n 'keep-alive': true,\n origin: true,\n 'permissions-policy': true,\n // Prefix matching is implemented in code, below.\n // 'proxy-': true,\n // 'sec-': true,\n referer: true,\n te: true,\n trailer: true,\n 'transfer-encoding': true,\n upgrade: true,\n via: true,\n};\n\nexport function assertIsAllowedHttpRequestHeaders(\n headers: Record<string, string>,\n): asserts headers is AllowedHttpRequestHeaders {\n const badHeaders = Object.keys(headers).filter(headerName => {\n const lowercaseHeaderName = headerName.toLowerCase();\n return (\n DISALLOWED_HEADERS[headerName.toLowerCase()] === true ||\n FORBIDDEN_HEADERS[headerName.toLowerCase()] === true ||\n lowercaseHeaderName.startsWith('proxy-') ||\n lowercaseHeaderName.startsWith('sec-')\n );\n });\n if (badHeaders.length > 0) {\n throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_HEADER_FORBIDDEN, {\n headers: badHeaders,\n });\n }\n}\n\n/**\n * Lowercasing header names makes it easier to override user-supplied headers, such as those defined\n * in the `DisallowedHeaders` type.\n */\nexport function normalizeHeaders<T extends Record<string, string>>(\n headers: T,\n): { [K in string & keyof T 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 string & keyof T as Lowercase<K>]: T[K] };\n}\n"]}
@@ -0,0 +1,17 @@
1
+ export type AllowedHttpRequestHeaders = Readonly<{
2
+ [K in DisallowedHeaders | ForbiddenHeaders as Capitalize<Lowercase<K>> | K | Lowercase<K> | Uncapitalize<K> | Uppercase<K>]?: never;
3
+ } & {
4
+ [headerName: string]: string;
5
+ }>;
6
+ type DisallowedHeaders = 'Accept' | 'Content-Length' | 'Content-Type' | 'Solana-Client';
7
+ type ForbiddenHeaders = 'Accept-Charset' | 'Accept-Encoding' | 'Access-Control-Request-Headers' | 'Access-Control-Request-Method' | 'Connection' | 'Content-Length' | 'Cookie' | 'Date' | 'DNT' | 'Expect' | 'Host' | 'Keep-Alive' | 'Origin' | 'Permissions-Policy' | 'Referer' | 'TE' | 'Trailer' | 'Transfer-Encoding' | 'Upgrade' | 'Via' | `Proxy-${string}` | `Sec-${string}`;
8
+ export declare function assertIsAllowedHttpRequestHeaders(headers: Record<string, string>): asserts headers is AllowedHttpRequestHeaders;
9
+ /**
10
+ * Lowercasing header names makes it easier to override user-supplied headers, such as those defined
11
+ * in the `DisallowedHeaders` type.
12
+ */
13
+ export declare function normalizeHeaders<T extends Record<string, string>>(headers: T): {
14
+ [K in string & keyof T as Lowercase<K>]: T[K];
15
+ };
16
+ export {};
17
+ //# sourceMappingURL=http-transport-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-transport-headers.d.ts","sourceRoot":"","sources":["../../src/http-transport-headers.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,yBAAyB,GAAG,QAAQ,CAC5C;KAGK,CAAC,IAAI,iBAAiB,GAAG,gBAAgB,IACpC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,GACxB,CAAC,GACD,SAAS,CAAC,CAAC,CAAC,GACZ,YAAY,CAAC,CAAC,CAAC,GAEf,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,KAAK;CAC9B,GAAG;IAAE,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAAA;CAAE,CACvC,CAAC;AAGF,KAAK,iBAAiB,GAAG,QAAQ,GAAG,gBAAgB,GAAG,cAAc,GAAG,eAAe,CAAC;AACxF,KAAK,gBAAgB,GACf,gBAAgB,GAChB,iBAAiB,GACjB,gCAAgC,GAChC,+BAA+B,GAC/B,YAAY,GACZ,gBAAgB,GAChB,QAAQ,GACR,MAAM,GACN,KAAK,GACL,QAAQ,GACR,MAAM,GACN,YAAY,GACZ,QAAQ,GACR,oBAAoB,GACpB,SAAS,GACT,IAAI,GACJ,SAAS,GACT,mBAAmB,GACnB,SAAS,GACT,KAAK,GACL,SAAS,MAAM,EAAE,GACjB,OAAO,MAAM,EAAE,CAAC;AAmCtB,wBAAgB,iCAAiC,CAC7C,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAChC,OAAO,CAAC,OAAO,IAAI,yBAAyB,CAe9C;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC7D,OAAO,EAAE,CAAC,GACX;KAAG,CAAC,IAAI,MAAM,GAAG,MAAM,CAAC,IAAI,SAAS,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAMnD"}
@@ -0,0 +1,11 @@
1
+ import { RpcTransport } from '@solana/rpc-spec';
2
+ import type Dispatcher from 'undici/types/dispatcher';
3
+ import { AllowedHttpRequestHeaders } from './http-transport-headers.js';
4
+ type Config = Readonly<{
5
+ dispatcher_NODE_ONLY?: Dispatcher;
6
+ headers?: AllowedHttpRequestHeaders;
7
+ url: string;
8
+ }>;
9
+ export declare function createHttpTransport(config: Config): RpcTransport;
10
+ export {};
11
+ //# sourceMappingURL=http-transport.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-transport.d.ts","sourceRoot":"","sources":["../../src/http-transport.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChD,OAAO,KAAK,UAAU,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EACH,yBAAyB,EAG5B,MAAM,0BAA0B,CAAC;AAElC,KAAK,MAAM,GAAG,QAAQ,CAAC;IACnB,oBAAoB,CAAC,EAAE,UAAU,CAAC;IAClC,OAAO,CAAC,EAAE,yBAAyB,CAAC;IACpC,GAAG,EAAE,MAAM,CAAC;CACf,CAAC,CAAC;AAgBH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAwChE"}
@@ -0,0 +1,2 @@
1
+ export * from './http-transport.js';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,kBAAkB,CAAC"}
package/package.json ADDED
@@ -0,0 +1,78 @@
1
+ {
2
+ "name": "@solana/rpc-transport-http",
3
+ "version": "2.0.0-experimental.00fa195",
4
+ "description": "An RPC transport that uses HTTP requests",
5
+ "exports": {
6
+ "browser": {
7
+ "import": "./dist/index.browser.js",
8
+ "require": "./dist/index.browser.cjs"
9
+ },
10
+ "node": {
11
+ "import": "./dist/index.node.js",
12
+ "require": "./dist/index.node.cjs"
13
+ },
14
+ "react-native": "./dist/index.native.js",
15
+ "types": "./dist/types/index.d.ts"
16
+ },
17
+ "browser": {
18
+ "./dist/index.node.cjs": "./dist/index.browser.cjs",
19
+ "./dist/index.node.js": "./dist/index.browser.js"
20
+ },
21
+ "main": "./dist/index.node.cjs",
22
+ "module": "./dist/index.node.js",
23
+ "react-native": "./dist/index.native.js",
24
+ "types": "./dist/types/index.d.ts",
25
+ "type": "module",
26
+ "files": [
27
+ "./dist/"
28
+ ],
29
+ "sideEffects": false,
30
+ "keywords": [
31
+ "blockchain",
32
+ "solana",
33
+ "web3"
34
+ ],
35
+ "author": "Solana Labs Maintainers <maintainers@solanalabs.com>",
36
+ "license": "MIT",
37
+ "repository": {
38
+ "type": "git",
39
+ "url": "https://github.com/solana-labs/solana-web3.js"
40
+ },
41
+ "bugs": {
42
+ "url": "http://github.com/solana-labs/solana-web3.js/issues"
43
+ },
44
+ "browserslist": [
45
+ "supports bigint and not dead",
46
+ "maintained node versions"
47
+ ],
48
+ "dependencies": {
49
+ "undici": "^6.6.2",
50
+ "@solana/errors": "2.0.0-experimental.00fa195",
51
+ "@solana/rpc-spec": "2.0.0-experimental.00fa195"
52
+ },
53
+ "bundlewatch": {
54
+ "defaultCompression": "gzip",
55
+ "files": [
56
+ {
57
+ "path": "./dist/index*.js"
58
+ }
59
+ ]
60
+ },
61
+ "scripts": {
62
+ "benchmark": "./src/__benchmarks__/run.ts",
63
+ "compile:js": "tsup --config build-scripts/tsup.config.package.ts",
64
+ "compile:typedefs": "tsc -p ./tsconfig.declarations.json && node ../../node_modules/@solana/build-scripts/add-js-extension-to-types.mjs",
65
+ "dev": "jest -c ../../node_modules/@solana/test-config/jest-dev.config.ts --rootDir . --watch",
66
+ "publish-impl": "npm view $npm_package_name@$npm_package_version > /dev/null 2>&1 || pnpm publish --tag experimental --access public --no-git-checks",
67
+ "publish-packages": "pnpm prepublishOnly && pnpm publish-impl",
68
+ "style:fix": "pnpm eslint --fix src/* && pnpm prettier -w src/* package.json",
69
+ "test:lint": "jest -c ../../node_modules/@solana/test-config/jest-lint.config.ts --rootDir . --silent",
70
+ "test:prettier": "jest -c ../../node_modules/@solana/test-config/jest-prettier.config.ts --rootDir . --silent",
71
+ "test:treeshakability:browser": "agadoo dist/index.browser.js",
72
+ "test:treeshakability:native": "agadoo dist/index.native.js",
73
+ "test:treeshakability:node": "agadoo dist/index.node.js",
74
+ "test:typecheck": "tsc --noEmit",
75
+ "test:unit:browser": "jest -c ../../node_modules/@solana/test-config/jest-unit.config.browser.ts --rootDir . --silent",
76
+ "test:unit:node": "jest -c ../../node_modules/@solana/test-config/jest-unit.config.node.ts --rootDir . --silent"
77
+ }
78
+ }