@pod-protocol/sdk
Version:
TypeScript SDK for PoD Protocol - AI agent communication on Solana
1,576 lines (1,535 loc) • 114 kB
JavaScript
import { S as SolanaError, V as SOLANA_ERROR__RPC__API_PLAN_MISSING_FOR_RPC_METHOD, W as getSolanaErrorFromJsonRpcError, X as SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, Y as SOLANA_ERROR__RPC__INTEGER_OVERFLOW, Z as safeCaptureStackTrace, _ as SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_STATE_MISSING, $ as SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_MUST_NOT_POLL_BEFORE_RESOLVING_EXISTING_MESSAGE_PROMISE, a0 as SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN, a1 as SOLANA_ERROR__RPC_SUBSCRIPTIONS__EXPECTED_SERVER_SUBSCRIPTION_ID, a2 as SOLANA_ERROR__INVARIANT_VIOLATION__DATA_PUBLISHER_CHANNEL_UNIMPLEMENTED, a3 as SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CONNECTION_CLOSED, a4 as SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_FAILED_TO_CONNECT, a5 as SOLANA_ERROR__RPC_SUBSCRIPTIONS__CHANNEL_CLOSED_BEFORE_MESSAGE_BUFFERED, y as isSolanaError, N as ErrorCode, O as address } from './types-CllXlTfL.js';
import { setMaxListeners } from 'node:events';
import e2 from 'ws';
// src/pipe.ts
function pipe(init, ...fns) {
return fns.reduce((acc, fn) => fn(acc), init);
}
// src/parse-json-with-bigints.ts
function parseJsonWithBigInts(json) {
return JSON.parse(wrapIntegersInBigIntValueObject(json), (_, value) => {
return isBigIntValueObject(value) ? unwrapBigIntValueObject(value) : value;
});
}
function wrapIntegersInBigIntValueObject(json) {
const out = [];
let inQuote = false;
for (let ii = 0; ii < json.length; ii++) {
let isEscaped = false;
if (json[ii] === "\\") {
out.push(json[ii++]);
isEscaped = !isEscaped;
}
if (json[ii] === '"') {
out.push(json[ii]);
if (!isEscaped) {
inQuote = !inQuote;
}
continue;
}
if (!inQuote) {
const consumedNumber = consumeNumber(json, ii);
if (consumedNumber?.length) {
ii += consumedNumber.length - 1;
if (consumedNumber.match(/\.|[eE]-/)) {
out.push(consumedNumber);
} else {
out.push(wrapBigIntValueObject(consumedNumber));
}
continue;
}
}
out.push(json[ii]);
}
return out.join("");
}
function consumeNumber(json, ii) {
const JSON_NUMBER_REGEX = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/;
if (!json[ii]?.match(/[-\d]/)) {
return null;
}
const numberMatch = json.slice(ii).match(JSON_NUMBER_REGEX);
return numberMatch ? numberMatch[0] : null;
}
function wrapBigIntValueObject(value) {
return `{"$n":"${value}"}`;
}
function unwrapBigIntValueObject({ $n }) {
if ($n.match(/[eE]/)) {
const [units, exponent] = $n.split(/[eE]/);
return BigInt(units) * BigInt(10) ** BigInt(exponent);
}
return BigInt($n);
}
function isBigIntValueObject(value) {
return !!value && typeof value === "object" && "$n" in value && typeof value.$n === "string";
}
// src/rpc-message.ts
var _nextMessageId = 0n;
function getNextMessageId() {
const id = _nextMessageId;
_nextMessageId++;
return id.toString();
}
function createRpcMessage(request) {
return {
id: getNextMessageId(),
jsonrpc: "2.0",
method: request.methodName,
params: request.params
};
}
// src/stringify-json-with-bigints.ts
function stringifyJsonWithBigints(value, space) {
return unwrapBigIntValueObject2(
JSON.stringify(value, (_, v) => typeof v === "bigint" ? wrapBigIntValueObject2(v) : v, space)
);
}
function wrapBigIntValueObject2(value) {
return { $n: `${value}` };
}
function unwrapBigIntValueObject2(value) {
return value.replace(/\{\s*"\$n"\s*:\s*"(-?\d+)"\s*\}/g, "$1");
}
// src/rpc.ts
function createRpc(rpcConfig) {
return makeProxy(rpcConfig);
}
function makeProxy(rpcConfig) {
return new Proxy(rpcConfig.api, {
defineProperty() {
return false;
},
deleteProperty() {
return false;
},
get(target, p, receiver) {
return function(...rawParams) {
const methodName = p.toString();
const getApiPlan = Reflect.get(target, methodName, receiver);
if (!getApiPlan) {
throw new SolanaError(SOLANA_ERROR__RPC__API_PLAN_MISSING_FOR_RPC_METHOD, {
method: methodName,
params: rawParams
});
}
const apiPlan = getApiPlan(...rawParams);
return createPendingRpcRequest(rpcConfig, apiPlan);
};
}
});
}
function createPendingRpcRequest({ transport }, plan) {
return {
async send(options) {
return await plan.execute({ signal: options?.abortSignal, transport });
}
};
}
function createJsonRpcApi(config) {
return new Proxy({}, {
defineProperty() {
return false;
},
deleteProperty() {
return false;
},
get(...args) {
const [_, p] = args;
const methodName = p.toString();
return function(...rawParams) {
const rawRequest = Object.freeze({ methodName, params: rawParams });
const request = config?.requestTransformer ? config?.requestTransformer(rawRequest) : rawRequest;
return Object.freeze({
execute: async ({ signal, transport }) => {
const payload = createRpcMessage(request);
const response = await transport({ payload, signal });
if (!config?.responseTransformer) {
return response;
}
return config.responseTransformer(response, request);
}
});
};
}
});
}
// src/rpc-transport.ts
function isJsonRpcPayload(payload) {
if (payload == null || typeof payload !== "object" || Array.isArray(payload)) {
return false;
}
return "jsonrpc" in payload && payload.jsonrpc === "2.0" && "method" in payload && typeof payload.method === "string" && "params" in payload;
}
// src/request-transformer.ts
// src/request-transformer-bigint-downcast-internal.ts
function downcastNodeToNumberIfBigint(value) {
return typeof value === "bigint" ? (
// FIXME(solana-labs/solana/issues/30341) Create a data type to represent u64 in the Solana
// JSON RPC implementation so that we can throw away this entire patcher instead of unsafely
// downcasting `bigints` to `numbers`.
Number(value)
) : value;
}
// src/tree-traversal.ts
var KEYPATH_WILDCARD = {};
function getTreeWalker(visitors) {
return function traverse(node, state) {
if (Array.isArray(node)) {
return node.map((element, ii) => {
const nextState = {
...state,
keyPath: [...state.keyPath, ii]
};
return traverse(element, nextState);
});
} else if (typeof node === "object" && node !== null) {
const out = {};
for (const propName in node) {
if (!Object.prototype.hasOwnProperty.call(node, propName)) {
continue;
}
const nextState = {
...state,
keyPath: [...state.keyPath, propName]
};
out[propName] = traverse(node[propName], nextState);
}
return out;
} else {
return visitors.reduce((acc, visitNode) => visitNode(acc, state), node);
}
};
}
function getTreeWalkerRequestTransformer(visitors, initialState) {
return (request) => {
const traverse = getTreeWalker(visitors);
return Object.freeze({
...request,
params: traverse(request.params, initialState)
});
};
}
function getTreeWalkerResponseTransformer(visitors, initialState) {
return (json) => getTreeWalker(visitors)(json, initialState);
}
// src/request-transformer-bigint-downcast.ts
function getBigIntDowncastRequestTransformer() {
return getTreeWalkerRequestTransformer([downcastNodeToNumberIfBigint], { keyPath: [] });
}
// src/request-transformer-default-commitment-internal.ts
function applyDefaultCommitment({
commitmentPropertyName,
params,
optionsObjectPositionInParams,
overrideCommitment
}) {
const paramInTargetPosition = params[optionsObjectPositionInParams];
if (
// There's no config.
paramInTargetPosition === void 0 || // There is a config object.
paramInTargetPosition && typeof paramInTargetPosition === "object" && !Array.isArray(paramInTargetPosition)
) {
if (
// The config object already has a commitment set.
paramInTargetPosition && commitmentPropertyName in paramInTargetPosition
) {
if (!paramInTargetPosition[commitmentPropertyName] || paramInTargetPosition[commitmentPropertyName] === "finalized") {
const nextParams = [...params];
const {
[commitmentPropertyName]: _,
// eslint-disable-line @typescript-eslint/no-unused-vars
...rest
} = paramInTargetPosition;
if (Object.keys(rest).length > 0) {
nextParams[optionsObjectPositionInParams] = rest;
} else {
if (optionsObjectPositionInParams === nextParams.length - 1) {
nextParams.length--;
} else {
nextParams[optionsObjectPositionInParams] = void 0;
}
}
return nextParams;
}
} else if (overrideCommitment !== "finalized") {
const nextParams = [...params];
nextParams[optionsObjectPositionInParams] = {
...paramInTargetPosition,
[commitmentPropertyName]: overrideCommitment
};
return nextParams;
}
}
return params;
}
// src/request-transformer-default-commitment.ts
function getDefaultCommitmentRequestTransformer({
defaultCommitment,
optionsObjectPositionByMethod
}) {
return (request) => {
const { params, methodName } = request;
if (!Array.isArray(params)) {
return request;
}
const optionsObjectPositionInParams = optionsObjectPositionByMethod[methodName];
if (optionsObjectPositionInParams == null) {
return request;
}
return Object.freeze({
methodName,
params: applyDefaultCommitment({
commitmentPropertyName: methodName === "sendTransaction" ? "preflightCommitment" : "commitment",
optionsObjectPositionInParams,
overrideCommitment: defaultCommitment,
params
})
});
};
}
// src/request-transformer-integer-overflow-internal.ts
function getIntegerOverflowNodeVisitor(onIntegerOverflow) {
return (value, { keyPath }) => {
if (typeof value === "bigint") {
if (onIntegerOverflow && (value > Number.MAX_SAFE_INTEGER || value < -Number.MAX_SAFE_INTEGER)) {
onIntegerOverflow(keyPath, value);
}
}
return value;
};
}
// src/request-transformer-integer-overflow.ts
function getIntegerOverflowRequestTransformer(onIntegerOverflow) {
return (request) => {
const transformer = getTreeWalkerRequestTransformer(
[getIntegerOverflowNodeVisitor((...args) => onIntegerOverflow(request, ...args))],
{ keyPath: [] }
);
return transformer(request);
};
}
// src/request-transformer-options-object-position-config.ts
var OPTIONS_OBJECT_POSITION_BY_METHOD = {
accountNotifications: 1,
blockNotifications: 1,
getAccountInfo: 1,
getBalance: 1,
getBlock: 1,
getBlockHeight: 0,
getBlockProduction: 0,
getBlocks: 2,
getBlocksWithLimit: 2,
getEpochInfo: 0,
getFeeForMessage: 1,
getInflationGovernor: 0,
getInflationReward: 1,
getLargestAccounts: 0,
getLatestBlockhash: 0,
getLeaderSchedule: 1,
getMinimumBalanceForRentExemption: 1,
getMultipleAccounts: 1,
getProgramAccounts: 1,
getSignaturesForAddress: 1,
getSlot: 0,
getSlotLeader: 0,
getStakeMinimumDelegation: 0,
getSupply: 0,
getTokenAccountBalance: 1,
getTokenAccountsByDelegate: 2,
getTokenAccountsByOwner: 2,
getTokenLargestAccounts: 1,
getTokenSupply: 1,
getTransaction: 1,
getTransactionCount: 0,
getVoteAccounts: 0,
isBlockhashValid: 1,
logsNotifications: 1,
programNotifications: 1,
requestAirdrop: 2,
sendTransaction: 1,
signatureNotifications: 1,
simulateTransaction: 1
};
// src/request-transformer.ts
function getDefaultRequestTransformerForSolanaRpc(config) {
const handleIntegerOverflow = config?.onIntegerOverflow;
return (request) => {
return pipe(
request,
handleIntegerOverflow ? getIntegerOverflowRequestTransformer(handleIntegerOverflow) : (r) => r,
getBigIntDowncastRequestTransformer(),
getDefaultCommitmentRequestTransformer({
defaultCommitment: config?.defaultCommitment,
optionsObjectPositionByMethod: OPTIONS_OBJECT_POSITION_BY_METHOD
})
);
};
}
// src/response-transformer-bigint-upcast-internal.ts
function getBigIntUpcastVisitor(allowedNumericKeyPaths) {
return function upcastNodeToBigIntIfNumber(value, { keyPath }) {
const isInteger = typeof value === "number" && Number.isInteger(value) || typeof value === "bigint";
if (!isInteger) return value;
if (keyPathIsAllowedToBeNumeric(keyPath, allowedNumericKeyPaths)) {
return Number(value);
} else {
return BigInt(value);
}
};
}
function keyPathIsAllowedToBeNumeric(keyPath, allowedNumericKeyPaths) {
return allowedNumericKeyPaths.some((prohibitedKeyPath) => {
if (prohibitedKeyPath.length !== keyPath.length) {
return false;
}
for (let ii = keyPath.length - 1; ii >= 0; ii--) {
const keyPathPart = keyPath[ii];
const prohibitedKeyPathPart = prohibitedKeyPath[ii];
if (prohibitedKeyPathPart !== keyPathPart && (prohibitedKeyPathPart !== KEYPATH_WILDCARD || typeof keyPathPart !== "number")) {
return false;
}
}
return true;
});
}
// src/response-transformer-bigint-upcast.ts
function getBigIntUpcastResponseTransformer(allowedNumericKeyPaths) {
return getTreeWalkerResponseTransformer([getBigIntUpcastVisitor(allowedNumericKeyPaths)], { keyPath: [] });
}
// src/response-transformer-result.ts
function getResultResponseTransformer() {
return (json) => json.result;
}
function getThrowSolanaErrorResponseTransformer() {
return (json) => {
const jsonRpcResponse = json;
if ("error" in jsonRpcResponse) {
throw getSolanaErrorFromJsonRpcError(jsonRpcResponse.error);
}
return jsonRpcResponse;
};
}
// src/response-transformer.ts
function getDefaultResponseTransformerForSolanaRpc(config) {
return (response, request) => {
const methodName = request.methodName;
const keyPaths = config?.allowedNumericKeyPaths && methodName ? config.allowedNumericKeyPaths[methodName] : void 0;
return pipe(
response,
(r) => getThrowSolanaErrorResponseTransformer()(r, request),
(r) => getResultResponseTransformer()(r, request),
(r) => getBigIntUpcastResponseTransformer(keyPaths ?? [])(r, request)
);
};
}
function getDefaultResponseTransformerForSolanaRpcSubscriptions(config) {
return (response, request) => {
const methodName = request.methodName;
const keyPaths = config?.allowedNumericKeyPaths && methodName ? config.allowedNumericKeyPaths[methodName] : void 0;
return pipe(response, (r) => getBigIntUpcastResponseTransformer(keyPaths ?? [])(r, request));
};
}
// src/response-transformer-allowed-numeric-values.ts
var jsonParsedTokenAccountsConfigs = [
// parsed Token/Token22 token account
["data", "parsed", "info", "tokenAmount", "decimals"],
["data", "parsed", "info", "tokenAmount", "uiAmount"],
["data", "parsed", "info", "rentExemptReserve", "decimals"],
["data", "parsed", "info", "rentExemptReserve", "uiAmount"],
["data", "parsed", "info", "delegatedAmount", "decimals"],
["data", "parsed", "info", "delegatedAmount", "uiAmount"],
["data", "parsed", "info", "extensions", KEYPATH_WILDCARD, "state", "olderTransferFee", "transferFeeBasisPoints"],
["data", "parsed", "info", "extensions", KEYPATH_WILDCARD, "state", "newerTransferFee", "transferFeeBasisPoints"],
["data", "parsed", "info", "extensions", KEYPATH_WILDCARD, "state", "preUpdateAverageRate"],
["data", "parsed", "info", "extensions", KEYPATH_WILDCARD, "state", "currentRate"]
];
var jsonParsedAccountsConfigs = [
...jsonParsedTokenAccountsConfigs,
// parsed AddressTableLookup account
["data", "parsed", "info", "lastExtendedSlotStartIndex"],
// parsed Config account
["data", "parsed", "info", "slashPenalty"],
["data", "parsed", "info", "warmupCooldownRate"],
// parsed Token/Token22 mint account
["data", "parsed", "info", "decimals"],
// parsed Token/Token22 multisig account
["data", "parsed", "info", "numRequiredSigners"],
["data", "parsed", "info", "numValidSigners"],
// parsed Stake account
["data", "parsed", "info", "stake", "delegation", "warmupCooldownRate"],
// parsed Sysvar rent account
["data", "parsed", "info", "exemptionThreshold"],
["data", "parsed", "info", "burnPercent"],
// parsed Vote account
["data", "parsed", "info", "commission"],
["data", "parsed", "info", "votes", KEYPATH_WILDCARD, "confirmationCount"]
];
var innerInstructionsConfigs = [
["index"],
["instructions", KEYPATH_WILDCARD, "accounts", KEYPATH_WILDCARD],
["instructions", KEYPATH_WILDCARD, "programIdIndex"],
["instructions", KEYPATH_WILDCARD, "stackHeight"]
];
var messageConfig = [
["addressTableLookups", KEYPATH_WILDCARD, "writableIndexes", KEYPATH_WILDCARD],
["addressTableLookups", KEYPATH_WILDCARD, "readonlyIndexes", KEYPATH_WILDCARD],
["header", "numReadonlySignedAccounts"],
["header", "numReadonlyUnsignedAccounts"],
["header", "numRequiredSignatures"],
["instructions", KEYPATH_WILDCARD, "accounts", KEYPATH_WILDCARD],
["instructions", KEYPATH_WILDCARD, "programIdIndex"],
["instructions", KEYPATH_WILDCARD, "stackHeight"]
];
// src/index.ts
function createSolanaRpcApi(config) {
return createJsonRpcApi({
requestTransformer: getDefaultRequestTransformerForSolanaRpc(config),
responseTransformer: getDefaultResponseTransformerForSolanaRpc({
allowedNumericKeyPaths: getAllowedNumericKeypaths$1()
})
});
}
var memoizedKeypaths$1;
function getAllowedNumericKeypaths$1() {
if (!memoizedKeypaths$1) {
memoizedKeypaths$1 = {
getAccountInfo: jsonParsedAccountsConfigs.map((c) => ["value", ...c]),
getBlock: [
["transactions", KEYPATH_WILDCARD, "meta", "preTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
[
"transactions",
KEYPATH_WILDCARD,
"meta",
"preTokenBalances",
KEYPATH_WILDCARD,
"uiTokenAmount",
"decimals"
],
["transactions", KEYPATH_WILDCARD, "meta", "postTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
[
"transactions",
KEYPATH_WILDCARD,
"meta",
"postTokenBalances",
KEYPATH_WILDCARD,
"uiTokenAmount",
"decimals"
],
["transactions", KEYPATH_WILDCARD, "meta", "rewards", KEYPATH_WILDCARD, "commission"],
...innerInstructionsConfigs.map((c) => [
"transactions",
KEYPATH_WILDCARD,
"meta",
"innerInstructions",
KEYPATH_WILDCARD,
...c
]),
...messageConfig.map((c) => ["transactions", KEYPATH_WILDCARD, "transaction", "message", ...c]),
["rewards", KEYPATH_WILDCARD, "commission"]
],
getClusterNodes: [
[KEYPATH_WILDCARD, "featureSet"],
[KEYPATH_WILDCARD, "shredVersion"]
],
getInflationGovernor: [["initial"], ["foundation"], ["foundationTerm"], ["taper"], ["terminal"]],
getInflationRate: [["foundation"], ["total"], ["validator"]],
getInflationReward: [[KEYPATH_WILDCARD, "commission"]],
getMultipleAccounts: jsonParsedAccountsConfigs.map((c) => ["value", KEYPATH_WILDCARD, ...c]),
getProgramAccounts: jsonParsedAccountsConfigs.flatMap((c) => [
["value", KEYPATH_WILDCARD, "account", ...c],
[KEYPATH_WILDCARD, "account", ...c]
]),
getRecentPerformanceSamples: [[KEYPATH_WILDCARD, "samplePeriodSecs"]],
getTokenAccountBalance: [
["value", "decimals"],
["value", "uiAmount"]
],
getTokenAccountsByDelegate: jsonParsedTokenAccountsConfigs.map((c) => [
"value",
KEYPATH_WILDCARD,
"account",
...c
]),
getTokenAccountsByOwner: jsonParsedTokenAccountsConfigs.map((c) => [
"value",
KEYPATH_WILDCARD,
"account",
...c
]),
getTokenLargestAccounts: [
["value", KEYPATH_WILDCARD, "decimals"],
["value", KEYPATH_WILDCARD, "uiAmount"]
],
getTokenSupply: [
["value", "decimals"],
["value", "uiAmount"]
],
getTransaction: [
["meta", "preTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
["meta", "preTokenBalances", KEYPATH_WILDCARD, "uiTokenAmount", "decimals"],
["meta", "postTokenBalances", KEYPATH_WILDCARD, "accountIndex"],
["meta", "postTokenBalances", KEYPATH_WILDCARD, "uiTokenAmount", "decimals"],
["meta", "rewards", KEYPATH_WILDCARD, "commission"],
...innerInstructionsConfigs.map((c) => ["meta", "innerInstructions", KEYPATH_WILDCARD, ...c]),
...messageConfig.map((c) => ["transaction", "message", ...c])
],
getVersion: [["feature-set"]],
getVoteAccounts: [
["current", KEYPATH_WILDCARD, "commission"],
["delinquent", KEYPATH_WILDCARD, "commission"]
],
simulateTransaction: [
...jsonParsedAccountsConfigs.map((c) => ["value", "accounts", KEYPATH_WILDCARD, ...c]),
...innerInstructionsConfigs.map((c) => ["value", "innerInstructions", KEYPATH_WILDCARD, ...c])
]
};
}
return memoizedKeypaths$1;
}
function normalizeHeaders$1(headers) {
const out = {};
for (const headerName in headers) {
out[headerName.toLowerCase()] = headers[headerName];
}
return out;
}
// src/http-transport.ts
function createHttpTransport(config) {
const { fromJson, headers, toJson, url } = config;
let dispatcherConfig;
if ("dispatcher_NODE_ONLY" in config) {
dispatcherConfig = { dispatcher: config.dispatcher_NODE_ONLY };
}
const customHeaders = headers && normalizeHeaders$1(headers);
return async function makeHttpRequest({
payload,
signal
}) {
const body = toJson ? toJson(payload) : JSON.stringify(payload);
const requestInfo = {
...dispatcherConfig,
body,
headers: {
...customHeaders,
// Keep these headers lowercase so they will override any user-supplied headers above.
accept: "application/json",
"content-length": body.length.toString(),
"content-type": "application/json; charset=utf-8"
},
method: "POST",
signal
};
const response = await fetch(url, requestInfo);
if (!response.ok) {
throw new SolanaError(SOLANA_ERROR__RPC__TRANSPORT_HTTP_ERROR, {
headers: response.headers,
message: response.statusText,
statusCode: response.status
});
}
if (fromJson) {
return fromJson(await response.text(), payload);
}
return await response.json();
};
}
var SOLANA_RPC_METHODS = [
"getAccountInfo",
"getBalance",
"getBlock",
"getBlockCommitment",
"getBlockHeight",
"getBlockProduction",
"getBlocks",
"getBlocksWithLimit",
"getBlockTime",
"getClusterNodes",
"getEpochInfo",
"getEpochSchedule",
"getFeeForMessage",
"getFirstAvailableBlock",
"getGenesisHash",
"getHealth",
"getHighestSnapshotSlot",
"getIdentity",
"getInflationGovernor",
"getInflationRate",
"getInflationReward",
"getLargestAccounts",
"getLatestBlockhash",
"getLeaderSchedule",
"getMaxRetransmitSlot",
"getMaxShredInsertSlot",
"getMinimumBalanceForRentExemption",
"getMultipleAccounts",
"getProgramAccounts",
"getRecentPerformanceSamples",
"getRecentPrioritizationFees",
"getSignaturesForAddress",
"getSignatureStatuses",
"getSlot",
"getSlotLeader",
"getSlotLeaders",
"getStakeMinimumDelegation",
"getSupply",
"getTokenAccountBalance",
"getTokenAccountsByDelegate",
"getTokenAccountsByOwner",
"getTokenLargestAccounts",
"getTokenSupply",
"getTransaction",
"getTransactionCount",
"getVersion",
"getVoteAccounts",
"index",
"isBlockhashValid",
"minimumLedgerSlot",
"requestAirdrop",
"sendTransaction",
"simulateTransaction"
];
function isSolanaRequest(payload) {
return isJsonRpcPayload(payload) && SOLANA_RPC_METHODS.includes(payload.method);
}
// src/http-transport-for-solana-rpc.ts
function createHttpTransportForSolanaRpc(config) {
return createHttpTransport({
...config,
fromJson: (rawResponse, payload) => isSolanaRequest(payload) ? parseJsonWithBigInts(rawResponse) : JSON.parse(rawResponse),
toJson: (payload) => isSolanaRequest(payload) ? stringifyJsonWithBigints(payload) : JSON.stringify(payload)
});
}
// src/index.ts
var objToString = Object.prototype.toString;
var objKeys = Object.keys || function(obj) {
const keys = [];
for (const name in obj) {
keys.push(name);
}
return keys;
};
function stringify(val, isArrayProp) {
let i, max, str, keys, key, propVal, toStr;
if (val === true) {
return "true";
}
if (val === false) {
return "false";
}
switch (typeof val) {
case "object":
if (val === null) {
return null;
} else if ("toJSON" in val && typeof val.toJSON === "function") {
return stringify(val.toJSON(), isArrayProp);
} else {
toStr = objToString.call(val);
if (toStr === "[object Array]") {
str = "[";
max = val.length - 1;
for (i = 0; i < max; i++) {
str += stringify(val[i], true) + ",";
}
if (max > -1) {
str += stringify(val[i], true);
}
return str + "]";
} else if (toStr === "[object Object]") {
keys = objKeys(val).sort();
max = keys.length;
str = "";
i = 0;
while (i < max) {
key = keys[i];
propVal = stringify(val[key], false);
if (propVal !== void 0) {
if (str) {
str += ",";
}
str += JSON.stringify(key) + ":" + propVal;
}
i++;
}
return "{" + str + "}";
} else {
return JSON.stringify(val);
}
}
case "function":
case "undefined":
return isArrayProp ? null : void 0;
case "bigint":
return `${val.toString()}n`;
case "string":
return JSON.stringify(val);
default:
return isFinite(val) ? val : null;
}
}
function index_default(val) {
const returnVal = stringify(val, false);
if (returnVal !== void 0) {
return "" + returnVal;
}
}
// src/index.ts
function createSolanaJsonRpcIntegerOverflowError$1(methodName, keyPath, value) {
let argumentLabel = "";
if (typeof keyPath[0] === "number") {
const argPosition = keyPath[0] + 1;
const lastDigit = argPosition % 10;
const lastTwoDigits = argPosition % 100;
if (lastDigit == 1 && lastTwoDigits != 11) {
argumentLabel = argPosition + "st";
} else if (lastDigit == 2 && lastTwoDigits != 12) {
argumentLabel = argPosition + "nd";
} else if (lastDigit == 3 && lastTwoDigits != 13) {
argumentLabel = argPosition + "rd";
} else {
argumentLabel = argPosition + "th";
}
} else {
argumentLabel = `\`${keyPath[0].toString()}\``;
}
const path = keyPath.length > 1 ? keyPath.slice(1).map((pathPart) => typeof pathPart === "number" ? `[${pathPart}]` : pathPart).join(".") : void 0;
const error = new SolanaError(SOLANA_ERROR__RPC__INTEGER_OVERFLOW, {
argumentLabel,
keyPath,
methodName,
optionalPathLabel: path ? ` at path \`${path}\`` : "",
value,
...path !== void 0 ? { path } : void 0
});
safeCaptureStackTrace(error, createSolanaJsonRpcIntegerOverflowError$1);
return error;
}
// src/rpc-default-config.ts
var DEFAULT_RPC_CONFIG = {
defaultCommitment: "confirmed",
onIntegerOverflow(request, keyPath, value) {
throw createSolanaJsonRpcIntegerOverflowError$1(request.methodName, keyPath, value);
}
};
var e$3 = class e extends globalThis.AbortController {
constructor(...t) {
super(...t), setMaxListeners(Number.MAX_SAFE_INTEGER, this.signal);
}
};
// src/rpc-request-coalescer.ts
var EXPLICIT_ABORT_TOKEN$1;
function createExplicitAbortToken$1() {
return {};
}
function getRpcTransportWithRequestCoalescing(transport, getDeduplicationKey) {
let coalescedRequestsByDeduplicationKey;
return async function makeCoalescedHttpRequest(request) {
const { payload, signal } = request;
const deduplicationKey = getDeduplicationKey(payload);
if (deduplicationKey === void 0) {
return await transport(request);
}
if (!coalescedRequestsByDeduplicationKey) {
queueMicrotask(() => {
coalescedRequestsByDeduplicationKey = void 0;
});
coalescedRequestsByDeduplicationKey = {};
}
if (coalescedRequestsByDeduplicationKey[deduplicationKey] == null) {
const abortController = new e$3();
const responsePromise = (async () => {
try {
return await transport({
...request,
signal: abortController.signal
});
} catch (e2) {
if (e2 === (EXPLICIT_ABORT_TOKEN$1 ||= createExplicitAbortToken$1())) {
return;
}
throw e2;
}
})();
coalescedRequestsByDeduplicationKey[deduplicationKey] = {
abortController,
numConsumers: 0,
responsePromise
};
}
const coalescedRequest = coalescedRequestsByDeduplicationKey[deduplicationKey];
coalescedRequest.numConsumers++;
if (signal) {
const responsePromise = coalescedRequest.responsePromise;
return await new Promise((resolve, reject) => {
const handleAbort = (e2) => {
signal.removeEventListener("abort", handleAbort);
coalescedRequest.numConsumers -= 1;
queueMicrotask(() => {
if (coalescedRequest.numConsumers === 0) {
const abortController = coalescedRequest.abortController;
abortController.abort(EXPLICIT_ABORT_TOKEN$1 ||= createExplicitAbortToken$1());
}
});
reject(e2.target.reason);
};
signal.addEventListener("abort", handleAbort);
responsePromise.then(resolve).catch(reject).finally(() => {
signal.removeEventListener("abort", handleAbort);
});
});
} else {
return await coalescedRequest.responsePromise;
}
};
}
function getSolanaRpcPayloadDeduplicationKey(payload) {
return isJsonRpcPayload(payload) ? index_default([payload.method, payload.params]) : void 0;
}
// src/rpc-transport.ts
function normalizeHeaders(headers) {
const out = {};
for (const headerName in headers) {
out[headerName.toLowerCase()] = headers[headerName];
}
return out;
}
function createDefaultRpcTransport(config) {
return pipe(
createHttpTransportForSolanaRpc({
...config,
headers: {
...{
// Keep these headers lowercase so they will be overridden by any user-supplied headers below.
"accept-encoding": (
// Natively supported by Node LTS v20.18.0 and above.
"br,gzip,deflate"
)
// Brotli, gzip, and Deflate, in that order.
},
...config.headers ? normalizeHeaders(config.headers) : void 0,
...{
// Keep these headers lowercase so they will override any user-supplied headers above.
"solana-client": `js/${"2.1.1"}`
}
}
}),
(transport) => getRpcTransportWithRequestCoalescing(transport, getSolanaRpcPayloadDeduplicationKey)
);
}
// src/rpc.ts
function createSolanaRpc(clusterUrl, config) {
return createSolanaRpcFromTransport(createDefaultRpcTransport({ url: clusterUrl, ...config }));
}
function createSolanaRpcFromTransport(transport) {
return createRpc({
api: createSolanaRpcApi(DEFAULT_RPC_CONFIG),
transport
});
}
// src/async-iterable.ts
var e$2 = class e extends globalThis.AbortController {
constructor(...t) {
super(...t), setMaxListeners(Number.MAX_SAFE_INTEGER, this.signal);
}
};
var s$1 = class s extends globalThis.EventTarget {
constructor(...t) {
super(...t), setMaxListeners(Number.MAX_SAFE_INTEGER, this);
}
};
// src/async-iterable.ts
var EXPLICIT_ABORT_TOKEN;
function createExplicitAbortToken() {
return Symbol(
void 0
);
}
var UNINITIALIZED = Symbol();
function createAsyncIterableFromDataPublisher({
abortSignal,
dataChannelName,
dataPublisher,
errorChannelName
}) {
const iteratorState = /* @__PURE__ */ new Map();
function publishErrorToAllIterators(reason) {
for (const [iteratorKey, state] of iteratorState.entries()) {
if (state.__hasPolled) {
iteratorState.delete(iteratorKey);
state.onError(reason);
} else {
state.publishQueue.push({
__type: 1 /* ERROR */,
err: reason
});
}
}
}
const abortController = new e$2();
abortSignal.addEventListener("abort", () => {
abortController.abort();
publishErrorToAllIterators(EXPLICIT_ABORT_TOKEN ||= createExplicitAbortToken());
});
const options = { signal: abortController.signal };
let firstError = UNINITIALIZED;
dataPublisher.on(
errorChannelName,
(err) => {
if (firstError === UNINITIALIZED) {
firstError = err;
abortController.abort();
publishErrorToAllIterators(err);
}
},
options
);
dataPublisher.on(
dataChannelName,
(data) => {
iteratorState.forEach((state, iteratorKey) => {
if (state.__hasPolled) {
const { onData } = state;
iteratorState.set(iteratorKey, { __hasPolled: false, publishQueue: [] });
onData(data);
} else {
state.publishQueue.push({
__type: 0 /* DATA */,
data
});
}
});
},
options
);
return {
async *[Symbol.asyncIterator]() {
if (abortSignal.aborted) {
return;
}
if (firstError !== UNINITIALIZED) {
throw firstError;
}
const iteratorKey = Symbol();
iteratorState.set(iteratorKey, { __hasPolled: false, publishQueue: [] });
try {
while (true) {
const state = iteratorState.get(iteratorKey);
if (!state) {
throw new SolanaError(SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_STATE_MISSING);
}
if (state.__hasPolled) {
throw new SolanaError(
SOLANA_ERROR__INVARIANT_VIOLATION__SUBSCRIPTION_ITERATOR_MUST_NOT_POLL_BEFORE_RESOLVING_EXISTING_MESSAGE_PROMISE
);
}
const publishQueue = state.publishQueue;
try {
if (publishQueue.length) {
state.publishQueue = [];
for (const item of publishQueue) {
if (item.__type === 0 /* DATA */) {
yield item.data;
} else {
throw item.err;
}
}
} else {
yield await new Promise((resolve, reject) => {
iteratorState.set(iteratorKey, {
__hasPolled: true,
onData: resolve,
onError: reject
});
});
}
} catch (e2) {
if (e2 === (EXPLICIT_ABORT_TOKEN ||= createExplicitAbortToken())) {
return;
} else {
throw e2;
}
}
}
} finally {
iteratorState.delete(iteratorKey);
}
}
};
}
// src/data-publisher.ts
function getDataPublisherFromEventEmitter(eventEmitter) {
return {
on(channelName, subscriber, options) {
function innerListener(ev) {
if (ev instanceof CustomEvent) {
const data = ev.detail;
subscriber(data);
} else {
subscriber();
}
}
eventEmitter.addEventListener(channelName, innerListener, options);
return () => {
eventEmitter.removeEventListener(channelName, innerListener);
};
}
};
}
// src/demultiplex.ts
function demultiplexDataPublisher(publisher, sourceChannelName, messageTransformer) {
let innerPublisherState;
const eventTarget = new s$1();
const demultiplexedDataPublisher = getDataPublisherFromEventEmitter(eventTarget);
return {
...demultiplexedDataPublisher,
on(channelName, subscriber, options) {
if (!innerPublisherState) {
const innerPublisherUnsubscribe = publisher.on(sourceChannelName, (sourceMessage) => {
const transformResult = messageTransformer(sourceMessage);
if (!transformResult) {
return;
}
const [destinationChannelName, message] = transformResult;
eventTarget.dispatchEvent(
new CustomEvent(destinationChannelName, {
detail: message
})
);
});
innerPublisherState = {
dispose: innerPublisherUnsubscribe,
numSubscribers: 0
};
}
innerPublisherState.numSubscribers++;
const unsubscribe = demultiplexedDataPublisher.on(channelName, subscriber, options);
let isActive = true;
function handleUnsubscribe() {
if (!isActive) {
return;
}
isActive = false;
options?.signal.removeEventListener("abort", handleUnsubscribe);
innerPublisherState.numSubscribers--;
if (innerPublisherState.numSubscribers === 0) {
innerPublisherState.dispose();
innerPublisherState = void 0;
}
unsubscribe();
}
options?.signal.addEventListener("abort", handleUnsubscribe);
return handleUnsubscribe;
}
};
}
// src/race.ts
function isObject(value) {
return value !== null && (typeof value === "object" || typeof value === "function");
}
function addRaceContender(contender) {
const deferreds = /* @__PURE__ */ new Set();
const record = { deferreds, settled: false };
Promise.resolve(contender).then(
(value) => {
for (const { resolve } of deferreds) {
resolve(value);
}
deferreds.clear();
record.settled = true;
},
(err) => {
for (const { reject } of deferreds) {
reject(err);
}
deferreds.clear();
record.settled = true;
}
);
return record;
}
var wm = /* @__PURE__ */ new WeakMap();
async function safeRace(contenders) {
let deferred;
const result = new Promise((resolve, reject) => {
deferred = { reject, resolve };
for (const contender of contenders) {
if (!isObject(contender)) {
Promise.resolve(contender).then(resolve, reject);
continue;
}
let record = wm.get(contender);
if (record === void 0) {
record = addRaceContender(contender);
record.deferreds.add(deferred);
wm.set(contender, record);
} else if (record.settled) {
Promise.resolve(contender).then(resolve, reject);
} else {
record.deferreds.add(deferred);
}
}
});
return await result.finally(() => {
for (const contender of contenders) {
if (isObject(contender)) {
const record = wm.get(contender);
record.deferreds.delete(deferred);
}
}
});
}
// src/rpc-subscriptions.ts
function createSubscriptionRpc(rpcConfig) {
return new Proxy(rpcConfig.api, {
defineProperty() {
return false;
},
deleteProperty() {
return false;
},
get(target, p, receiver) {
return function(...rawParams) {
const notificationName = p.toString();
const createRpcSubscriptionPlan = Reflect.get(target, notificationName, receiver);
if (!createRpcSubscriptionPlan) {
throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS__CANNOT_CREATE_SUBSCRIPTION_PLAN, {
notificationName
});
}
const subscriptionPlan = createRpcSubscriptionPlan(...rawParams);
return createPendingRpcSubscription(rpcConfig.transport, subscriptionPlan);
};
}
});
}
function createPendingRpcSubscription(transport, subscriptionsPlan) {
return {
async subscribe({ abortSignal }) {
const notificationsDataPublisher = await transport({
signal: abortSignal,
...subscriptionsPlan
});
return createAsyncIterableFromDataPublisher({
abortSignal,
dataChannelName: "notification",
dataPublisher: notificationsDataPublisher,
errorChannelName: "error"
});
}
};
}
// src/rpc-subscriptions-api.ts
function createRpcSubscriptionsApi(config) {
return new Proxy({}, {
defineProperty() {
return false;
},
deleteProperty() {
return false;
},
get(...args) {
const [_, p] = args;
const methodName = p.toString();
return function(...params) {
const rawRequest = { methodName, params };
const request = config.requestTransformer ? config.requestTransformer(rawRequest) : rawRequest;
return {
execute(planConfig) {
return config.planExecutor({ ...planConfig, request });
},
request
};
};
}
});
}
// src/rpc-subscriptions-channel.ts
function transformChannelInboundMessages(channel, transform) {
return Object.freeze({
...channel,
on(type, subscriber, options) {
if (type !== "message") {
return channel.on(
type,
subscriber,
options
);
}
return channel.on(
"message",
(message) => subscriber(transform(message)),
options
);
}
});
}
function transformChannelOutboundMessages(channel, transform) {
return Object.freeze({
...channel,
send: (message) => channel.send(transform(message))
});
}
var e$1 = class e extends globalThis.AbortController {
constructor(...t) {
super(...t), setMaxListeners(Number.MAX_SAFE_INTEGER, this.signal);
}
};
var subscriberCountBySubscriptionIdByChannel = /* @__PURE__ */ new WeakMap();
function decrementSubscriberCountAndReturnNewCount(channel, subscriptionId) {
return augmentSubscriberCountAndReturnNewCount(-1, channel, subscriptionId);
}
function incrementSubscriberCount(channel, subscriptionId) {
augmentSubscriberCountAndReturnNewCount(1, channel, subscriptionId);
}
function augmentSubscriberCountAndReturnNewCount(amount, channel, subscriptionId) {
if (subscriptionId === void 0) {
return;
}
let subscriberCountBySubscriptionId = subscriberCountBySubscriptionIdByChannel.get(channel);
if (!subscriberCountBySubscriptionId && amount > 0) {
subscriberCountBySubscriptionIdByChannel.set(
channel,
subscriberCountBySubscriptionId = { [subscriptionId]: 0 }
);
}
if (subscriberCountBySubscriptionId?.[subscriptionId] !== void 0) {
return subscriberCountBySubscriptionId[subscriptionId] = amount + subscriberCountBySubscriptionId[subscriptionId];
}
}
var cache = /* @__PURE__ */ new WeakMap();
function getMemoizedDemultiplexedNotificationPublisherFromChannelAndResponseTransformer(channel, subscribeRequest, responseTransformer) {
let publisherByResponseTransformer = cache.get(channel);
if (!publisherByResponseTransformer) {
cache.set(channel, publisherByResponseTransformer = /* @__PURE__ */ new WeakMap());
}
const responseTransformerKey = responseTransformer ?? channel;
let publisher = publisherByResponseTransformer.get(responseTransformerKey);
if (!publisher) {
publisherByResponseTransformer.set(
responseTransformerKey,
publisher = demultiplexDataPublisher(channel, "message", (rawMessage) => {
const message = rawMessage;
if (!("method" in message)) {
return;
}
const transformedNotification = responseTransformer ? responseTransformer(message.params.result, subscribeRequest) : message.params.result;
return [`notification:${message.params.subscription}`, transformedNotification];
})
);
}
return publisher;
}
async function executeRpcPubSubSubscriptionPlan({
channel,
responseTransformer,
signal,
subscribeRequest,
unsubscribeMethodName
}) {
let subscriptionId;
channel.on(
"error",
() => {
subscriptionId = void 0;
subscriberCountBySubscriptionIdByChannel.delete(channel);
},
{ signal }
);
const abortPromise = new Promise((_, reject) => {
function handleAbort() {
if (decrementSubscriberCountAndReturnNewCount(channel, subscriptionId) === 0) {
const unsubscribePayload = createRpcMessage({
methodName: unsubscribeMethodName,
params: [subscriptionId]
});
subscriptionId = void 0;
channel.send(unsubscribePayload).catch(() => {
});
}
reject(this.reason);
}
if (signal.aborted) {
handleAbort.call(signal);
} else {
signal.addEventListener("abort", handleAbort);
}
});
const subscribePayload = createRpcMessage(subscribeRequest);
await channel.send(subscribePayload);
const subscriptionIdPromise = new Promise((resolve, reject) => {
const abortController = new e$1();
signal.addEventListener("abort", abortController.abort.bind(abortController));
const options = { signal: abortController.signal };
channel.on(
"error",
(err) => {
abortController.abort();
reject(err);
},
options
);
channel.on(
"message",
(message) => {
if (message && typeof message === "object" && "id" in message && message.id === subscribePayload.id) {
abortController.abort();
if ("error" in message) {
reject(getSolanaErrorFromJsonRpcError(message.error));
} else {
resolve(message.result);
}
}
},
options
);
});
subscriptionId = await safeRace([abortPromise, subscriptionIdPromise]);
if (subscriptionId == null) {
throw new SolanaError(SOLANA_ERROR__RPC_SUBSCRIPTIONS__EXPECTED_SERVER_SUBSCRIPTION_ID);
}
incrementSubscriberCount(channel, subscriptionId);
const notificationPublisher = getMemoizedDemultiplexedNotificationPublisherFromChannelAndResponseTransformer(
channel,
subscribeRequest,
responseTransformer
);
const notificationKey = `notification:${subscriptionId}`;
return {
on(type, listener, options) {
switch (type) {
case "notification":
return notificationPublisher.on(
notificationKey,
listener,
options
);
case "error":
return channel.on(
"error",
listener,
options
);
default:
throw new SolanaError(SOLANA_ERROR__INVARIANT_VIOLATION__DATA_PUBLISHER_CHANNEL_UNIMPLEMENTED, {
channelName: type,
supportedChannelNames: ["notification", "error"]
});
}
}
};
}
// src/index.ts
function createSolanaRpcSubscriptionsApi_INTERNAL(config) {
const requestTransformer = getDefaultRequestTransformerForSolanaRpc(config);
const responseTransformer = getDefaultResponseTransformerForSolanaRpcSubscriptions({
allowedNumericKeyPaths: getAllowedNumericKeypaths()
});
return createRpcSubscriptionsApi({
planExecutor({ request, ...rest }) {
return executeRpcPubSubSubscriptionPlan({
...rest,
responseTransformer,
subscribeRequest: { ...request, methodName: request.methodName.replace(/Notifications$/, "Subscribe") },
unsubscribeMethodName: request.methodName.replace(/Notifications$/, "Unsubscribe")
});
},
requestTransformer
});
}
function createSolanaRpcSubscriptionsApi(config) {
return createSolanaRpcSubscriptionsApi_INTERNAL(config);
}
var memoizedKeypaths;
function getAllowedNumericKeypaths() {
if (!memoizedKeypaths) {
memoizedKeypaths = {
accountNotifications: jsonParsedAccountsConfigs.map((c) => ["value", ...c]),
blockNotifications: [
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"preTokenBalances",
KEYPATH_WILDCARD,
"accountIndex"
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"preTokenBalances",
KEYPATH_WILDCARD,
"uiTokenAmount",
"decimals"
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"postTokenBalances",
KEYPATH_WILDCARD,
"accountIndex"
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"postTokenBalances",
KEYPATH_WILDCARD,
"uiTokenAmount",
"decimals"
],
["value", "block", "transactions", KEYPATH_WILDCARD, "meta", "rewards", KEYPATH_WILDCARD, "commission"],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"innerInstructions",
KEYPATH_WILDCARD,
"index"
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"innerInstructions",
KEYPATH_WILDCARD,
"instructions",
KEYPATH_WILDCARD,
"programIdIndex"
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"meta",
"innerInstructions",
KEYPATH_WILDCARD,
"instructions",
KEYPATH_WILDCARD,
"accounts",
KEYPATH_WILDCARD
],
[
"value",
"block",
"transactions",
KEYPATH_WILDCARD,
"transaction",
"message",
"addressTableLookups",
KEYPATH_WILDCARD,
"writableIndexes",