UNPKG

@pod-protocol/sdk

Version:

TypeScript SDK for PoD Protocol - AI agent communication on Solana

1,576 lines (1,535 loc) 114 kB
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",