@solana/rpc-subscriptions 2.0.0-20241006045741
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 +20 -0
- package/README.md +54 -0
- package/dist/index.browser.cjs +358 -0
- package/dist/index.browser.cjs.map +1 -0
- package/dist/index.browser.mjs +339 -0
- package/dist/index.browser.mjs.map +1 -0
- package/dist/index.native.mjs +322 -0
- package/dist/index.native.mjs.map +1 -0
- package/dist/index.node.cjs +341 -0
- package/dist/index.node.cjs.map +1 -0
- package/dist/index.node.mjs +322 -0
- package/dist/index.node.mjs.map +1 -0
- package/dist/types/index.d.ts +9 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/rpc-default-config.d.ts +3 -0
- package/dist/types/rpc-default-config.d.ts.map +1 -0
- package/dist/types/rpc-integer-overflow-error.d.ts +4 -0
- package/dist/types/rpc-integer-overflow-error.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-autopinger.d.ts +9 -0
- package/dist/types/rpc-subscriptions-autopinger.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-channel-pool-internal.d.ts +13 -0
- package/dist/types/rpc-subscriptions-channel-pool-internal.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-channel-pool.d.ts +8 -0
- package/dist/types/rpc-subscriptions-channel-pool.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-channel.d.ts +11 -0
- package/dist/types/rpc-subscriptions-channel.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-clusters.d.ts +46 -0
- package/dist/types/rpc-subscriptions-clusters.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-coalescer.d.ts +3 -0
- package/dist/types/rpc-subscriptions-coalescer.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-json.d.ts +3 -0
- package/dist/types/rpc-subscriptions-json.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions-transport.d.ts +9 -0
- package/dist/types/rpc-subscriptions-transport.d.ts.map +1 -0
- package/dist/types/rpc-subscriptions.d.ts +13 -0
- package/dist/types/rpc-subscriptions.d.ts.map +1 -0
- package/package.json +94 -0
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,54 @@
|
|
|
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-subscriptions/rc.svg?style=flat
|
|
10
|
+
[npm-image]: https://img.shields.io/npm/v/@solana/rpc-subscriptions/rc.svg?style=flat
|
|
11
|
+
[npm-url]: https://www.npmjs.com/package/@solana/rpc-subscriptions/v/rc
|
|
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-subscriptions
|
|
16
|
+
|
|
17
|
+
This package contains types that implement RPC subscriptions as required by the Solana RPC. Additionally, it incorporates some useful defaults that make working with subscriptions easier, more performant, and more reliable. It can be used standalone, but it is also exported as part of the Solana JavaScript SDK [`@solana/web3.js@rc`](https://github.com/solana-labs/solana-web3.js/tree/master/packages/library).
|
|
18
|
+
|
|
19
|
+
## Functions
|
|
20
|
+
|
|
21
|
+
### `createDefaultRpcSubscriptionsChannelCreator(config)`
|
|
22
|
+
|
|
23
|
+
Creates a function that returns new subscription channels when called.
|
|
24
|
+
|
|
25
|
+
#### Arguments
|
|
26
|
+
|
|
27
|
+
A config object with the following properties:
|
|
28
|
+
|
|
29
|
+
- `intervalMs`: The number of milliseconds to wait since the last message sent or received over the channel before sending a ping message to keep the channel open.
|
|
30
|
+
- `maxSubscriptionsPerChannel`: The number of subscribers that may share a channel before a new channel must be created. Set this to the maximum number of subscriptions that your RPC provider recommends making over a single connection.
|
|
31
|
+
- `minChannels`: The number of channels to create before reusing a channel for a new subscription.
|
|
32
|
+
- `sendBufferHighWatermark`: The number of bytes of data to admint into the `WebSocket` buffer before buffering data on the client. -`url`: The URL of the web socket server. Must use the `ws` or `wss` protocols.
|
|
33
|
+
|
|
34
|
+
### `getChannelPoolingChannelCreator(createChannel, { maxSubscriptionsPerChannel, minChannels })`
|
|
35
|
+
|
|
36
|
+
Given a channel creator, will return a new channel creator with the following behavior.
|
|
37
|
+
|
|
38
|
+
1. When called, returns an `RpcSubscriptionsChannel`. Adds that channel to a pool.
|
|
39
|
+
2. When called again, creates and returns new `RpcSubscriptionChannels` up to the number specified by `minChannels`.
|
|
40
|
+
3. When `minChannels` channels have been created, subsequent calls vend whichever existing channel from the pool has the fewest subscribers, or the next one in rotation in the event of a tie.
|
|
41
|
+
4. Once all channels carry the number of subscribers specified by the number `maxSubscriptionsPerChannel`, new channels in excess of `minChannel` will be created, returned, and added to the pool.
|
|
42
|
+
5. A channel will be destroyed once all of its subscribers' abort signals fire.
|
|
43
|
+
|
|
44
|
+
### `getRpcSubscriptionsChannelWithJSONSerialization(channel)`
|
|
45
|
+
|
|
46
|
+
Given an `RpcSubscriptionsChannel`, will return a new channel that parses data published to the `'message'` channel as JSON, and JSON-stringifies messages sent via the `send(message)` method.
|
|
47
|
+
|
|
48
|
+
### `getRpcSubscriptionsChannelWithAutoping(channel)`
|
|
49
|
+
|
|
50
|
+
Given an `RpcSubscriptionsChannel`, will return a new channel that sends a ping message to the inner channel if a message has not been sent or received in the last `intervalMs`. In web browsers, this implementation sends no ping when the network is down, and sends a ping immediately upon the network coming back up.
|
|
51
|
+
|
|
52
|
+
### `getRpcSubscriptionsTransportWithSubscriptionCoalescing(transport)`
|
|
53
|
+
|
|
54
|
+
Given an `RpcSubscriptionsTransport`, will return a new transport that coalesces identical subscriptions into a single subscription request to the server. The determination of whether a subscription is the same as another is based on the `subscriptionConfigurationHash` returned by its `RpcSubscriptionsPlan`. The subscription will only be aborted once all subscribers abort, or there is an error.
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var rpcSubscriptionsApi = require('@solana/rpc-subscriptions-api');
|
|
4
|
+
var rpcSubscriptionsSpec = require('@solana/rpc-subscriptions-spec');
|
|
5
|
+
var errors = require('@solana/errors');
|
|
6
|
+
var rpcSubscriptionsChannelWebsocket = require('@solana/rpc-subscriptions-channel-websocket');
|
|
7
|
+
var functional = require('@solana/functional');
|
|
8
|
+
|
|
9
|
+
// src/index.ts
|
|
10
|
+
function createSolanaJsonRpcIntegerOverflowError(methodName, keyPath, value) {
|
|
11
|
+
let argumentLabel = "";
|
|
12
|
+
if (typeof keyPath[0] === "number") {
|
|
13
|
+
const argPosition = keyPath[0] + 1;
|
|
14
|
+
const lastDigit = argPosition % 10;
|
|
15
|
+
const lastTwoDigits = argPosition % 100;
|
|
16
|
+
if (lastDigit == 1 && lastTwoDigits != 11) {
|
|
17
|
+
argumentLabel = argPosition + "st";
|
|
18
|
+
} else if (lastDigit == 2 && lastTwoDigits != 12) {
|
|
19
|
+
argumentLabel = argPosition + "nd";
|
|
20
|
+
} else if (lastDigit == 3 && lastTwoDigits != 13) {
|
|
21
|
+
argumentLabel = argPosition + "rd";
|
|
22
|
+
} else {
|
|
23
|
+
argumentLabel = argPosition + "th";
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
argumentLabel = `\`${keyPath[0].toString()}\``;
|
|
27
|
+
}
|
|
28
|
+
const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
|
|
29
|
+
const error = new errors.SolanaError(errors.SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
|
|
30
|
+
argumentLabel,
|
|
31
|
+
keyPath,
|
|
32
|
+
methodName,
|
|
33
|
+
optionalPathLabel: path ? ` at path \`${path}\`` : "",
|
|
34
|
+
value,
|
|
35
|
+
...path !== void 0 ? { path } : void 0
|
|
36
|
+
});
|
|
37
|
+
errors.safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError);
|
|
38
|
+
return error;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// src/rpc-default-config.ts
|
|
42
|
+
var DEFAULT_RPC_SUBSCRIPTIONS_CONFIG = {
|
|
43
|
+
defaultCommitment: "confirmed",
|
|
44
|
+
onIntegerOverflow(request, keyPath, value) {
|
|
45
|
+
throw createSolanaJsonRpcIntegerOverflowError(request.methodName, keyPath, value);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/rpc-subscriptions-autopinger.ts
|
|
50
|
+
var PING_PAYLOAD = {
|
|
51
|
+
jsonrpc: "2.0",
|
|
52
|
+
method: "ping"
|
|
53
|
+
};
|
|
54
|
+
function getRpcSubscriptionsChannelWithAutoping({
|
|
55
|
+
abortSignal: callerAbortSignal,
|
|
56
|
+
channel,
|
|
57
|
+
intervalMs
|
|
58
|
+
}) {
|
|
59
|
+
let intervalId;
|
|
60
|
+
function sendPing() {
|
|
61
|
+
channel.send(PING_PAYLOAD);
|
|
62
|
+
}
|
|
63
|
+
function restartPingTimer() {
|
|
64
|
+
clearInterval(intervalId);
|
|
65
|
+
intervalId = setInterval(sendPing, intervalMs);
|
|
66
|
+
}
|
|
67
|
+
const pingerAbortController = new AbortController();
|
|
68
|
+
pingerAbortController.signal.addEventListener("abort", () => {
|
|
69
|
+
clearInterval(intervalId);
|
|
70
|
+
});
|
|
71
|
+
callerAbortSignal.addEventListener("abort", () => {
|
|
72
|
+
pingerAbortController.abort();
|
|
73
|
+
});
|
|
74
|
+
channel.on(
|
|
75
|
+
"error",
|
|
76
|
+
() => {
|
|
77
|
+
pingerAbortController.abort();
|
|
78
|
+
},
|
|
79
|
+
{ signal: pingerAbortController.signal }
|
|
80
|
+
);
|
|
81
|
+
channel.on("message", restartPingTimer, { signal: pingerAbortController.signal });
|
|
82
|
+
if (globalThis.navigator.onLine) {
|
|
83
|
+
restartPingTimer();
|
|
84
|
+
}
|
|
85
|
+
{
|
|
86
|
+
globalThis.window.addEventListener(
|
|
87
|
+
"offline",
|
|
88
|
+
function handleOffline() {
|
|
89
|
+
clearInterval(intervalId);
|
|
90
|
+
},
|
|
91
|
+
{ signal: pingerAbortController.signal }
|
|
92
|
+
);
|
|
93
|
+
globalThis.window.addEventListener(
|
|
94
|
+
"online",
|
|
95
|
+
function handleOnline() {
|
|
96
|
+
sendPing();
|
|
97
|
+
restartPingTimer();
|
|
98
|
+
},
|
|
99
|
+
{ signal: pingerAbortController.signal }
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
...channel,
|
|
104
|
+
send(...args) {
|
|
105
|
+
if (!pingerAbortController.signal.aborted) {
|
|
106
|
+
restartPingTimer();
|
|
107
|
+
}
|
|
108
|
+
return channel.send(...args);
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// src/rpc-subscriptions-channel-pool-internal.ts
|
|
114
|
+
function createChannelPool() {
|
|
115
|
+
return {
|
|
116
|
+
entries: [],
|
|
117
|
+
freeChannelIndex: -1
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// src/rpc-subscriptions-channel-pool.ts
|
|
122
|
+
function getChannelPoolingChannelCreator(createChannel, { maxSubscriptionsPerChannel, minChannels }) {
|
|
123
|
+
const pool = createChannelPool();
|
|
124
|
+
function recomputeFreeChannelIndex() {
|
|
125
|
+
if (pool.entries.length < minChannels) {
|
|
126
|
+
pool.freeChannelIndex = -1;
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
let mostFreeChannel;
|
|
130
|
+
for (let ii = 0; ii < pool.entries.length; ii++) {
|
|
131
|
+
const nextPoolIndex = (pool.freeChannelIndex + ii + 2) % pool.entries.length;
|
|
132
|
+
const nextPoolEntry = (
|
|
133
|
+
// Start from the item two positions after the current item. This way, the
|
|
134
|
+
// search will finish on the item after the current one. This ensures that, if
|
|
135
|
+
// any channels tie for having the most capacity, the one that will be chosen is
|
|
136
|
+
// the one immediately to the current one's right (wrapping around).
|
|
137
|
+
pool.entries[nextPoolIndex]
|
|
138
|
+
);
|
|
139
|
+
if (nextPoolEntry.subscriptionCount < maxSubscriptionsPerChannel && (!mostFreeChannel || mostFreeChannel.subscriptionCount >= nextPoolEntry.subscriptionCount)) {
|
|
140
|
+
mostFreeChannel = {
|
|
141
|
+
poolIndex: nextPoolIndex,
|
|
142
|
+
subscriptionCount: nextPoolEntry.subscriptionCount
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
pool.freeChannelIndex = mostFreeChannel?.poolIndex ?? -1;
|
|
147
|
+
}
|
|
148
|
+
return function getExistingChannelWithMostCapacityOrCreateChannel({ abortSignal }) {
|
|
149
|
+
let poolEntry;
|
|
150
|
+
function destroyPoolEntry() {
|
|
151
|
+
const index = pool.entries.findIndex((entry) => entry === poolEntry);
|
|
152
|
+
pool.entries.splice(index, 1);
|
|
153
|
+
poolEntry.dispose();
|
|
154
|
+
recomputeFreeChannelIndex();
|
|
155
|
+
}
|
|
156
|
+
if (pool.freeChannelIndex === -1) {
|
|
157
|
+
const abortController = new AbortController();
|
|
158
|
+
const newChannelPromise = createChannel({ abortSignal: abortController.signal });
|
|
159
|
+
newChannelPromise.then((newChannel) => {
|
|
160
|
+
newChannel.on("error", destroyPoolEntry, { signal: abortController.signal });
|
|
161
|
+
}).catch(destroyPoolEntry);
|
|
162
|
+
poolEntry = {
|
|
163
|
+
channel: newChannelPromise,
|
|
164
|
+
dispose() {
|
|
165
|
+
abortController.abort();
|
|
166
|
+
},
|
|
167
|
+
subscriptionCount: 0
|
|
168
|
+
};
|
|
169
|
+
pool.entries.push(poolEntry);
|
|
170
|
+
} else {
|
|
171
|
+
poolEntry = pool.entries[pool.freeChannelIndex];
|
|
172
|
+
}
|
|
173
|
+
poolEntry.subscriptionCount++;
|
|
174
|
+
abortSignal.addEventListener("abort", function destroyConsumer() {
|
|
175
|
+
poolEntry.subscriptionCount--;
|
|
176
|
+
if (poolEntry.subscriptionCount === 0) {
|
|
177
|
+
destroyPoolEntry();
|
|
178
|
+
} else if (pool.freeChannelIndex !== -1) {
|
|
179
|
+
pool.freeChannelIndex--;
|
|
180
|
+
recomputeFreeChannelIndex();
|
|
181
|
+
}
|
|
182
|
+
});
|
|
183
|
+
recomputeFreeChannelIndex();
|
|
184
|
+
return poolEntry.channel;
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/rpc-subscriptions-json.ts
|
|
189
|
+
function getRpcSubscriptionsChannelWithJSONSerialization(channel) {
|
|
190
|
+
return Object.freeze({
|
|
191
|
+
...channel,
|
|
192
|
+
on(type, listener, options) {
|
|
193
|
+
if (type !== "message") {
|
|
194
|
+
return channel.on(type, listener, options);
|
|
195
|
+
}
|
|
196
|
+
return channel.on(
|
|
197
|
+
"message",
|
|
198
|
+
function deserializingListener(message) {
|
|
199
|
+
const deserializedMessage = JSON.parse(message);
|
|
200
|
+
listener(deserializedMessage);
|
|
201
|
+
},
|
|
202
|
+
options
|
|
203
|
+
);
|
|
204
|
+
},
|
|
205
|
+
send(message) {
|
|
206
|
+
const serializedMessage = JSON.stringify(message);
|
|
207
|
+
return channel.send(serializedMessage);
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// src/rpc-subscriptions-channel.ts
|
|
213
|
+
function createDefaultRpcSubscriptionsChannelCreator(config) {
|
|
214
|
+
if (/^wss?:/i.test(config.url) === false) {
|
|
215
|
+
const protocolMatch = config.url.match(/^([^:]+):/);
|
|
216
|
+
throw new DOMException(
|
|
217
|
+
protocolMatch ? `Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or 'wss'. '${protocolMatch[1]}:' is not allowed.` : `Failed to construct 'WebSocket': The URL '${config.url}' is invalid.`
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
const { intervalMs, ...rest } = config;
|
|
221
|
+
const createDefaultRpcSubscriptionsChannel = ({ abortSignal }) => {
|
|
222
|
+
return rpcSubscriptionsChannelWebsocket.createWebSocketChannel({
|
|
223
|
+
...rest,
|
|
224
|
+
sendBufferHighWatermark: config.sendBufferHighWatermark ?? // Let 128KB of data into the WebSocket buffer before buffering it in the app.
|
|
225
|
+
131072,
|
|
226
|
+
signal: abortSignal
|
|
227
|
+
}).then(getRpcSubscriptionsChannelWithJSONSerialization).then(
|
|
228
|
+
(channel) => getRpcSubscriptionsChannelWithAutoping({
|
|
229
|
+
abortSignal,
|
|
230
|
+
channel,
|
|
231
|
+
intervalMs: intervalMs ?? 5e3
|
|
232
|
+
})
|
|
233
|
+
);
|
|
234
|
+
};
|
|
235
|
+
return getChannelPoolingChannelCreator(createDefaultRpcSubscriptionsChannel, {
|
|
236
|
+
maxSubscriptionsPerChannel: config.maxSubscriptionsPerChannel ?? // TODO: Determine this experimentally
|
|
237
|
+
1e3,
|
|
238
|
+
minChannels: config.minChannels ?? 1
|
|
239
|
+
});
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// src/rpc-subscriptions-coalescer.ts
|
|
243
|
+
function getRpcSubscriptionsTransportWithSubscriptionCoalescing(transport) {
|
|
244
|
+
const cache = /* @__PURE__ */ new Map();
|
|
245
|
+
return function rpcSubscriptionsTransportWithSubscriptionCoalescing(config) {
|
|
246
|
+
const { subscriptionConfigurationHash, signal } = config;
|
|
247
|
+
if (subscriptionConfigurationHash === void 0) {
|
|
248
|
+
return transport(config);
|
|
249
|
+
}
|
|
250
|
+
let cachedDataPublisherPromise = cache.get(subscriptionConfigurationHash);
|
|
251
|
+
if (!cachedDataPublisherPromise) {
|
|
252
|
+
const abortController = new AbortController();
|
|
253
|
+
const dataPublisherPromise = transport({
|
|
254
|
+
...config,
|
|
255
|
+
signal: abortController.signal
|
|
256
|
+
});
|
|
257
|
+
dataPublisherPromise.then((dataPublisher) => {
|
|
258
|
+
dataPublisher.on(
|
|
259
|
+
"error",
|
|
260
|
+
() => {
|
|
261
|
+
cache.delete(subscriptionConfigurationHash);
|
|
262
|
+
abortController.abort();
|
|
263
|
+
},
|
|
264
|
+
{ signal: abortController.signal }
|
|
265
|
+
);
|
|
266
|
+
});
|
|
267
|
+
cache.set(
|
|
268
|
+
subscriptionConfigurationHash,
|
|
269
|
+
cachedDataPublisherPromise = {
|
|
270
|
+
abortController,
|
|
271
|
+
dataPublisherPromise,
|
|
272
|
+
numSubscribers: 0
|
|
273
|
+
}
|
|
274
|
+
);
|
|
275
|
+
}
|
|
276
|
+
cachedDataPublisherPromise.numSubscribers++;
|
|
277
|
+
signal.addEventListener(
|
|
278
|
+
"abort",
|
|
279
|
+
() => {
|
|
280
|
+
cachedDataPublisherPromise.numSubscribers--;
|
|
281
|
+
if (cachedDataPublisherPromise.numSubscribers === 0) {
|
|
282
|
+
queueMicrotask(() => {
|
|
283
|
+
if (cachedDataPublisherPromise.numSubscribers === 0) {
|
|
284
|
+
cache.delete(subscriptionConfigurationHash);
|
|
285
|
+
cachedDataPublisherPromise.abortController.abort();
|
|
286
|
+
}
|
|
287
|
+
});
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
{ signal: cachedDataPublisherPromise.abortController.signal }
|
|
291
|
+
);
|
|
292
|
+
return cachedDataPublisherPromise.dataPublisherPromise;
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// src/rpc-subscriptions-transport.ts
|
|
297
|
+
function createDefaultRpcSubscriptionsTransport({
|
|
298
|
+
createChannel
|
|
299
|
+
}) {
|
|
300
|
+
return functional.pipe(
|
|
301
|
+
createRpcSubscriptionsTransportFromChannelCreator(
|
|
302
|
+
createChannel
|
|
303
|
+
),
|
|
304
|
+
(transport) => getRpcSubscriptionsTransportWithSubscriptionCoalescing(transport)
|
|
305
|
+
);
|
|
306
|
+
}
|
|
307
|
+
function createRpcSubscriptionsTransportFromChannelCreator(createChannel) {
|
|
308
|
+
return async ({ executeSubscriptionPlan, signal }) => {
|
|
309
|
+
const channel = await createChannel({ abortSignal: signal });
|
|
310
|
+
return await executeSubscriptionPlan({ channel, signal });
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// src/rpc-subscriptions.ts
|
|
315
|
+
function createSolanaRpcSubscriptionsImpl(clusterUrl, config) {
|
|
316
|
+
const transport = createDefaultRpcSubscriptionsTransport({
|
|
317
|
+
createChannel: createDefaultRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl })
|
|
318
|
+
});
|
|
319
|
+
return createSolanaRpcSubscriptionsFromTransport(transport);
|
|
320
|
+
}
|
|
321
|
+
function createSolanaRpcSubscriptions(clusterUrl, config) {
|
|
322
|
+
return createSolanaRpcSubscriptionsImpl(clusterUrl, config);
|
|
323
|
+
}
|
|
324
|
+
function createSolanaRpcSubscriptions_UNSTABLE(clusterUrl, config) {
|
|
325
|
+
return createSolanaRpcSubscriptionsImpl(
|
|
326
|
+
clusterUrl,
|
|
327
|
+
config
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
function createSolanaRpcSubscriptionsFromTransport(transport) {
|
|
331
|
+
return rpcSubscriptionsSpec.createSubscriptionRpc({
|
|
332
|
+
api: rpcSubscriptionsApi.createSolanaRpcSubscriptionsApi(DEFAULT_RPC_SUBSCRIPTIONS_CONFIG),
|
|
333
|
+
transport
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
exports.DEFAULT_RPC_SUBSCRIPTIONS_CONFIG = DEFAULT_RPC_SUBSCRIPTIONS_CONFIG;
|
|
338
|
+
exports.createDefaultRpcSubscriptionsChannelCreator = createDefaultRpcSubscriptionsChannelCreator;
|
|
339
|
+
exports.createDefaultRpcSubscriptionsTransport = createDefaultRpcSubscriptionsTransport;
|
|
340
|
+
exports.createRpcSubscriptionsTransportFromChannelCreator = createRpcSubscriptionsTransportFromChannelCreator;
|
|
341
|
+
exports.createSolanaRpcSubscriptions = createSolanaRpcSubscriptions;
|
|
342
|
+
exports.createSolanaRpcSubscriptionsFromTransport = createSolanaRpcSubscriptionsFromTransport;
|
|
343
|
+
exports.createSolanaRpcSubscriptions_UNSTABLE = createSolanaRpcSubscriptions_UNSTABLE;
|
|
344
|
+
exports.getRpcSubscriptionsChannelWithJSONSerialization = getRpcSubscriptionsChannelWithJSONSerialization;
|
|
345
|
+
Object.keys(rpcSubscriptionsApi).forEach(function (k) {
|
|
346
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
347
|
+
enumerable: true,
|
|
348
|
+
get: function () { return rpcSubscriptionsApi[k]; }
|
|
349
|
+
});
|
|
350
|
+
});
|
|
351
|
+
Object.keys(rpcSubscriptionsSpec).forEach(function (k) {
|
|
352
|
+
if (k !== 'default' && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
|
|
353
|
+
enumerable: true,
|
|
354
|
+
get: function () { return rpcSubscriptionsSpec[k]; }
|
|
355
|
+
});
|
|
356
|
+
});
|
|
357
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
358
|
+
//# sourceMappingURL=index.browser.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rpc-integer-overflow-error.ts","../src/rpc-default-config.ts","../src/rpc-subscriptions-autopinger.ts","../src/rpc-subscriptions-channel-pool-internal.ts","../src/rpc-subscriptions-channel-pool.ts","../src/rpc-subscriptions-json.ts","../src/rpc-subscriptions-channel.ts","../src/rpc-subscriptions-coalescer.ts","../src/rpc-subscriptions-transport.ts","../src/rpc-subscriptions.ts"],"names":["SolanaError","SOLANA_ERROR__RPC__INTEGER_OVERFLOW","safeCaptureStackTrace","createWebSocketChannel","pipe","createSubscriptionRpc","createSolanaRpcSubscriptionsApi"],"mappings":"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","file":"index.browser.cjs","sourcesContent":["import { safeCaptureStackTrace, SOLANA_ERROR__RPC__INTEGER_OVERFLOW, SolanaError } from '@solana/errors';\nimport type { KeyPath } from '@solana/rpc-transformers';\n\nexport function createSolanaJsonRpcIntegerOverflowError(\n methodName: string,\n keyPath: KeyPath,\n value: bigint,\n): SolanaError<typeof SOLANA_ERROR__RPC__INTEGER_OVERFLOW> {\n let argumentLabel = '';\n if (typeof keyPath[0] === 'number') {\n const argPosition = keyPath[0] + 1;\n const lastDigit = argPosition % 10;\n const lastTwoDigits = argPosition % 100;\n if (lastDigit == 1 && lastTwoDigits != 11) {\n argumentLabel = argPosition + 'st';\n } else if (lastDigit == 2 && lastTwoDigits != 12) {\n argumentLabel = argPosition + 'nd';\n } else if (lastDigit == 3 && lastTwoDigits != 13) {\n argumentLabel = argPosition + 'rd';\n } else {\n argumentLabel = argPosition + 'th';\n }\n } else {\n argumentLabel = `\\`${keyPath[0].toString()}\\``;\n }\n const path =\n keyPath.length > 1\n ? keyPath\n .slice(1)\n .map(pathPart => (typeof pathPart === 'number' ? `[${pathPart}]` : pathPart))\n .join('.')\n : undefined;\n const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {\n argumentLabel,\n keyPath: keyPath as readonly (number | string | symbol)[],\n methodName,\n optionalPathLabel: path ? ` at path \\`${path}\\`` : '',\n value,\n ...(path !== undefined ? { path } : undefined),\n });\n safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError);\n return error;\n}\n","import type { createSolanaRpcSubscriptionsApi } from '@solana/rpc-subscriptions-api';\n\nimport { createSolanaJsonRpcIntegerOverflowError } from './rpc-integer-overflow-error';\n\nexport const DEFAULT_RPC_SUBSCRIPTIONS_CONFIG: Partial<\n NonNullable<Parameters<typeof createSolanaRpcSubscriptionsApi>[0]>\n> = {\n defaultCommitment: 'confirmed',\n onIntegerOverflow(request, keyPath, value) {\n throw createSolanaJsonRpcIntegerOverflowError(request.methodName, keyPath, value);\n },\n};\n","import type { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec';\n\ntype Config<TChannel extends RpcSubscriptionsChannel<unknown, unknown>> = Readonly<{\n abortSignal: AbortSignal;\n channel: TChannel;\n intervalMs: number;\n}>;\n\nconst PING_PAYLOAD = {\n jsonrpc: '2.0',\n method: 'ping',\n} as const;\n\nexport function getRpcSubscriptionsChannelWithAutoping<TChannel extends RpcSubscriptionsChannel<object, unknown>>({\n abortSignal: callerAbortSignal,\n channel,\n intervalMs,\n}: Config<TChannel>): TChannel {\n let intervalId: ReturnType<typeof setInterval> | undefined;\n function sendPing() {\n channel.send(PING_PAYLOAD);\n }\n function restartPingTimer() {\n clearInterval(intervalId);\n intervalId = setInterval(sendPing, intervalMs);\n }\n const pingerAbortController = new AbortController();\n pingerAbortController.signal.addEventListener('abort', () => {\n clearInterval(intervalId);\n });\n callerAbortSignal.addEventListener('abort', () => {\n pingerAbortController.abort();\n });\n channel.on(\n 'error',\n () => {\n pingerAbortController.abort();\n },\n { signal: pingerAbortController.signal },\n );\n channel.on('message', restartPingTimer, { signal: pingerAbortController.signal });\n if (!__BROWSER__ || globalThis.navigator.onLine) {\n restartPingTimer();\n }\n if (__BROWSER__) {\n globalThis.window.addEventListener(\n 'offline',\n function handleOffline() {\n clearInterval(intervalId);\n },\n { signal: pingerAbortController.signal },\n );\n globalThis.window.addEventListener(\n 'online',\n function handleOnline() {\n sendPing();\n restartPingTimer();\n },\n { signal: pingerAbortController.signal },\n );\n }\n return {\n ...channel,\n send(...args) {\n if (!pingerAbortController.signal.aborted) {\n restartPingTimer();\n }\n return channel.send(...args);\n },\n };\n}\n","import { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec';\n\nexport type ChannelPoolEntry = {\n channel: PromiseLike<RpcSubscriptionsChannel<unknown, unknown>> | RpcSubscriptionsChannel<unknown, unknown>;\n readonly dispose: () => void;\n subscriptionCount: number;\n};\n\ntype ChannelPool = { readonly entries: ChannelPoolEntry[]; freeChannelIndex: number };\n\nexport function createChannelPool(): ChannelPool {\n return {\n entries: [],\n freeChannelIndex: -1,\n };\n}\n","import { RpcSubscriptionsChannelCreator } from '@solana/rpc-subscriptions-spec';\n\nimport { ChannelPoolEntry, createChannelPool } from './rpc-subscriptions-channel-pool-internal';\n\ntype Config = Readonly<{\n maxSubscriptionsPerChannel: number;\n minChannels: number;\n}>;\n\nexport function getChannelPoolingChannelCreator<\n TChannelCreator extends RpcSubscriptionsChannelCreator<unknown, unknown>,\n>(createChannel: TChannelCreator, { maxSubscriptionsPerChannel, minChannels }: Config): TChannelCreator {\n const pool = createChannelPool();\n /**\n * This function advances the free channel index to the pool entry with the most capacity. It\n * sets the index to `-1` if all channels are full.\n */\n function recomputeFreeChannelIndex() {\n if (pool.entries.length < minChannels) {\n // Don't set the free channel index until the pool fills up; we want to keep creating\n // channels before we start rotating among them.\n pool.freeChannelIndex = -1;\n return;\n }\n let mostFreeChannel: Readonly<{ poolIndex: number; subscriptionCount: number }> | undefined;\n for (let ii = 0; ii < pool.entries.length; ii++) {\n const nextPoolIndex = (pool.freeChannelIndex + ii + 2) % pool.entries.length;\n const nextPoolEntry =\n // Start from the item two positions after the current item. This way, the\n // search will finish on the item after the current one. This ensures that, if\n // any channels tie for having the most capacity, the one that will be chosen is\n // the one immediately to the current one's right (wrapping around).\n pool.entries[nextPoolIndex];\n if (\n nextPoolEntry.subscriptionCount < maxSubscriptionsPerChannel &&\n (!mostFreeChannel || mostFreeChannel.subscriptionCount >= nextPoolEntry.subscriptionCount)\n ) {\n mostFreeChannel = {\n poolIndex: nextPoolIndex,\n subscriptionCount: nextPoolEntry.subscriptionCount,\n };\n }\n }\n pool.freeChannelIndex = mostFreeChannel?.poolIndex ?? -1;\n }\n return function getExistingChannelWithMostCapacityOrCreateChannel({ abortSignal }) {\n let poolEntry: ChannelPoolEntry;\n function destroyPoolEntry() {\n const index = pool.entries.findIndex(entry => entry === poolEntry);\n pool.entries.splice(index, 1);\n poolEntry.dispose();\n recomputeFreeChannelIndex();\n }\n if (pool.freeChannelIndex === -1) {\n const abortController = new AbortController();\n const newChannelPromise = createChannel({ abortSignal: abortController.signal });\n newChannelPromise\n .then(newChannel => {\n newChannel.on('error', destroyPoolEntry, { signal: abortController.signal });\n })\n .catch(destroyPoolEntry);\n poolEntry = {\n channel: newChannelPromise,\n dispose() {\n abortController.abort();\n },\n subscriptionCount: 0,\n };\n pool.entries.push(poolEntry);\n } else {\n poolEntry = pool.entries[pool.freeChannelIndex];\n }\n /**\n * A note about subscription counts.\n * Because of https://github.com/solana-labs/solana/pull/18943, two subscriptions for\n * materially the same notification will be coalesced on the server. This means they will be\n * assigned the same subscription id, and will occupy one subscription slot. We can't tell,\n * from here, whether a subscription will be treated in this way or not, so we\n * unconditionally increment the subscription count every time a subscription request is\n * made. This may result in subscription channels being treated as out-of-capacity when in\n * fact they are not.\n */\n poolEntry.subscriptionCount++;\n abortSignal.addEventListener('abort', function destroyConsumer() {\n poolEntry.subscriptionCount--;\n if (poolEntry.subscriptionCount === 0) {\n destroyPoolEntry();\n } else if (pool.freeChannelIndex !== -1) {\n // Back the free channel index up one position, and recompute it.\n pool.freeChannelIndex--;\n recomputeFreeChannelIndex();\n }\n });\n recomputeFreeChannelIndex();\n return poolEntry.channel;\n } as TChannelCreator;\n}\n","import { RpcSubscriptionsChannel } from '@solana/rpc-subscriptions-spec';\n\nexport function getRpcSubscriptionsChannelWithJSONSerialization(\n channel: RpcSubscriptionsChannel<string, string>,\n): RpcSubscriptionsChannel<unknown, unknown> {\n return Object.freeze({\n ...channel,\n on(type, listener, options) {\n if (type !== 'message') {\n return channel.on(type, listener, options);\n }\n return channel.on(\n 'message',\n function deserializingListener(message: string) {\n const deserializedMessage = JSON.parse(message);\n listener(deserializedMessage);\n },\n options,\n );\n },\n send(message) {\n const serializedMessage = JSON.stringify(message);\n return channel.send(serializedMessage);\n },\n } as RpcSubscriptionsChannel<unknown, unknown>);\n}\n","import { createWebSocketChannel } from '@solana/rpc-subscriptions-channel-websocket';\nimport type { ClusterUrl } from '@solana/rpc-types';\n\nimport { getRpcSubscriptionsChannelWithAutoping } from './rpc-subscriptions-autopinger';\nimport { getChannelPoolingChannelCreator } from './rpc-subscriptions-channel-pool';\nimport { RpcSubscriptionsChannelCreatorFromClusterUrl } from './rpc-subscriptions-clusters';\nimport { getRpcSubscriptionsChannelWithJSONSerialization } from './rpc-subscriptions-json';\n\nexport type DefaultRpcSubscriptionsChannelConfig<TClusterUrl extends ClusterUrl> = Readonly<{\n intervalMs?: number;\n maxSubscriptionsPerChannel?: number;\n minChannels?: number;\n sendBufferHighWatermark?: number;\n url: TClusterUrl;\n}>;\n\nexport function createDefaultRpcSubscriptionsChannelCreator<TClusterUrl extends ClusterUrl>(\n config: DefaultRpcSubscriptionsChannelConfig<TClusterUrl>,\n): RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown> {\n if (/^wss?:/i.test(config.url) === false) {\n const protocolMatch = config.url.match(/^([^:]+):/);\n throw new DOMException(\n protocolMatch\n ? \"Failed to construct 'WebSocket': The URL's scheme must be either 'ws' or \" +\n `'wss'. '${protocolMatch[1]}:' is not allowed.`\n : `Failed to construct 'WebSocket': The URL '${config.url}' is invalid.`,\n );\n }\n const { intervalMs, ...rest } = config;\n const createDefaultRpcSubscriptionsChannel = (({ abortSignal }) => {\n return createWebSocketChannel({\n ...rest,\n sendBufferHighWatermark:\n config.sendBufferHighWatermark ??\n // Let 128KB of data into the WebSocket buffer before buffering it in the app.\n 131_072,\n signal: abortSignal,\n })\n .then(getRpcSubscriptionsChannelWithJSONSerialization)\n .then(channel =>\n getRpcSubscriptionsChannelWithAutoping({\n abortSignal,\n channel,\n intervalMs: intervalMs ?? 5_000,\n }),\n );\n }) as RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown>;\n return getChannelPoolingChannelCreator(createDefaultRpcSubscriptionsChannel, {\n maxSubscriptionsPerChannel:\n config.maxSubscriptionsPerChannel ??\n // TODO: Determine this experimentally\n 1_000,\n minChannels: config.minChannels ?? 1,\n });\n}\n","import { RpcSubscriptionsTransport } from '@solana/rpc-subscriptions-spec';\nimport { DataPublisher } from '@solana/subscribable';\n\ntype CacheEntry = {\n readonly abortController: AbortController;\n readonly dataPublisherPromise: Promise<DataPublisher>;\n numSubscribers: number;\n};\n\nexport function getRpcSubscriptionsTransportWithSubscriptionCoalescing<TTransport extends RpcSubscriptionsTransport>(\n transport: TTransport,\n): TTransport {\n const cache = new Map<string, CacheEntry>();\n return function rpcSubscriptionsTransportWithSubscriptionCoalescing(config) {\n const { subscriptionConfigurationHash, signal } = config;\n if (subscriptionConfigurationHash === undefined) {\n return transport(config);\n }\n let cachedDataPublisherPromise = cache.get(subscriptionConfigurationHash);\n if (!cachedDataPublisherPromise) {\n const abortController = new AbortController();\n const dataPublisherPromise = transport({\n ...config,\n signal: abortController.signal,\n });\n dataPublisherPromise.then(dataPublisher => {\n dataPublisher.on(\n 'error',\n () => {\n cache.delete(subscriptionConfigurationHash);\n abortController.abort();\n },\n { signal: abortController.signal },\n );\n });\n cache.set(\n subscriptionConfigurationHash,\n (cachedDataPublisherPromise = {\n abortController,\n dataPublisherPromise,\n numSubscribers: 0,\n }),\n );\n }\n cachedDataPublisherPromise.numSubscribers++;\n signal.addEventListener(\n 'abort',\n () => {\n cachedDataPublisherPromise.numSubscribers--;\n if (cachedDataPublisherPromise.numSubscribers === 0) {\n queueMicrotask(() => {\n if (cachedDataPublisherPromise.numSubscribers === 0) {\n cache.delete(subscriptionConfigurationHash);\n cachedDataPublisherPromise.abortController.abort();\n }\n });\n }\n },\n { signal: cachedDataPublisherPromise.abortController.signal },\n );\n return cachedDataPublisherPromise.dataPublisherPromise;\n } as TTransport;\n}\n","import { pipe } from '@solana/functional';\nimport { RpcSubscriptionsChannelCreator, RpcSubscriptionsTransport } from '@solana/rpc-subscriptions-spec';\nimport { ClusterUrl } from '@solana/rpc-types';\n\nimport {\n RpcSubscriptionsChannelCreatorDevnet,\n RpcSubscriptionsChannelCreatorFromClusterUrl,\n RpcSubscriptionsChannelCreatorMainnet,\n RpcSubscriptionsChannelCreatorTestnet,\n RpcSubscriptionsTransportDevnet,\n RpcSubscriptionsTransportFromClusterUrl,\n RpcSubscriptionsTransportMainnet,\n RpcSubscriptionsTransportTestnet,\n} from './rpc-subscriptions-clusters';\nimport { getRpcSubscriptionsTransportWithSubscriptionCoalescing } from './rpc-subscriptions-coalescer';\n\nexport type DefaultRpcSubscriptionsTransportConfig<TClusterUrl extends ClusterUrl> = Readonly<{\n createChannel: RpcSubscriptionsChannelCreatorFromClusterUrl<TClusterUrl, unknown, unknown>;\n}>;\n\nexport function createDefaultRpcSubscriptionsTransport<TClusterUrl extends ClusterUrl>({\n createChannel,\n}: DefaultRpcSubscriptionsTransportConfig<TClusterUrl>) {\n return pipe(\n createRpcSubscriptionsTransportFromChannelCreator(\n createChannel,\n ) as RpcSubscriptionsTransport as RpcSubscriptionsTransportFromClusterUrl<TClusterUrl>,\n transport => getRpcSubscriptionsTransportWithSubscriptionCoalescing(transport),\n );\n}\n\nexport function createRpcSubscriptionsTransportFromChannelCreator<\n TChannelCreator extends RpcSubscriptionsChannelCreator<TOutboundMessage, TInboundMessage>,\n TInboundMessage,\n TOutboundMessage,\n>(createChannel: TChannelCreator) {\n return (async ({ executeSubscriptionPlan, signal }) => {\n const channel = await createChannel({ abortSignal: signal });\n return await executeSubscriptionPlan({ channel, signal });\n }) as TChannelCreator extends RpcSubscriptionsChannelCreatorDevnet<TOutboundMessage, TInboundMessage>\n ? RpcSubscriptionsTransportDevnet\n : TChannelCreator extends RpcSubscriptionsChannelCreatorTestnet<TOutboundMessage, TInboundMessage>\n ? RpcSubscriptionsTransportTestnet\n : TChannelCreator extends RpcSubscriptionsChannelCreatorMainnet<TOutboundMessage, TInboundMessage>\n ? RpcSubscriptionsTransportMainnet\n : RpcSubscriptionsTransport;\n}\n","import type { SolanaRpcSubscriptionsApi, SolanaRpcSubscriptionsApiUnstable } from '@solana/rpc-subscriptions-api';\nimport { createSolanaRpcSubscriptionsApi } from '@solana/rpc-subscriptions-api';\nimport {\n createSubscriptionRpc,\n RpcSubscriptionsApiMethods,\n type RpcSubscriptionsTransport,\n} from '@solana/rpc-subscriptions-spec';\nimport { ClusterUrl } from '@solana/rpc-types';\n\nimport { DEFAULT_RPC_SUBSCRIPTIONS_CONFIG } from './rpc-default-config';\nimport {\n createDefaultRpcSubscriptionsChannelCreator,\n DefaultRpcSubscriptionsChannelConfig,\n} from './rpc-subscriptions-channel';\nimport type { RpcSubscriptionsFromTransport } from './rpc-subscriptions-clusters';\nimport {\n createDefaultRpcSubscriptionsTransport,\n DefaultRpcSubscriptionsTransportConfig,\n} from './rpc-subscriptions-transport';\n\ninterface DefaultRpcSubscriptionsConfig<TClusterUrl extends ClusterUrl>\n extends DefaultRpcSubscriptionsTransportConfig<TClusterUrl>,\n DefaultRpcSubscriptionsChannelConfig<TClusterUrl> {}\n\nfunction createSolanaRpcSubscriptionsImpl<TClusterUrl extends ClusterUrl, TApi extends RpcSubscriptionsApiMethods>(\n clusterUrl: TClusterUrl,\n config?: Omit<DefaultRpcSubscriptionsConfig<TClusterUrl>, 'url'>,\n) {\n const transport = createDefaultRpcSubscriptionsTransport({\n createChannel: createDefaultRpcSubscriptionsChannelCreator({ ...config, url: clusterUrl }),\n });\n return createSolanaRpcSubscriptionsFromTransport<typeof transport, TApi>(transport);\n}\n\nexport function createSolanaRpcSubscriptions<TClusterUrl extends ClusterUrl>(\n clusterUrl: TClusterUrl,\n config?: Omit<DefaultRpcSubscriptionsConfig<TClusterUrl>, 'url'>,\n) {\n return createSolanaRpcSubscriptionsImpl<TClusterUrl, SolanaRpcSubscriptionsApi>(clusterUrl, config);\n}\n\nexport function createSolanaRpcSubscriptions_UNSTABLE<TClusterUrl extends ClusterUrl>(\n clusterUrl: TClusterUrl,\n config?: Omit<DefaultRpcSubscriptionsTransportConfig<TClusterUrl>, 'url'>,\n) {\n return createSolanaRpcSubscriptionsImpl<TClusterUrl, SolanaRpcSubscriptionsApi & SolanaRpcSubscriptionsApiUnstable>(\n clusterUrl,\n config,\n );\n}\n\nexport function createSolanaRpcSubscriptionsFromTransport<\n TTransport extends RpcSubscriptionsTransport,\n TApi extends RpcSubscriptionsApiMethods = SolanaRpcSubscriptionsApi,\n>(transport: TTransport) {\n return createSubscriptionRpc({\n api: createSolanaRpcSubscriptionsApi<TApi>(DEFAULT_RPC_SUBSCRIPTIONS_CONFIG),\n transport,\n }) as RpcSubscriptionsFromTransport<TApi, TTransport>;\n}\n"]}
|