@w3lib/solana-batch-call 0.0.0-stage → 0.2.0

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.
Files changed (49) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/LICENSE +21 -0
  3. package/README.md +270 -2
  4. package/dist/address.d.ts +20 -0
  5. package/dist/address.d.ts.map +1 -0
  6. package/dist/address.js +120 -0
  7. package/dist/address.js.map +1 -0
  8. package/dist/client.d.ts +190 -0
  9. package/dist/client.d.ts.map +1 -0
  10. package/dist/client.js +971 -0
  11. package/dist/client.js.map +1 -0
  12. package/dist/constants.d.ts +21 -0
  13. package/dist/constants.d.ts.map +1 -0
  14. package/dist/constants.js +35 -0
  15. package/dist/constants.js.map +1 -0
  16. package/dist/index.d.ts +9 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +9 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/layout.d.ts +84 -0
  21. package/dist/layout.d.ts.map +1 -0
  22. package/dist/layout.js +237 -0
  23. package/dist/layout.js.map +1 -0
  24. package/dist/rpc.d.ts +115 -0
  25. package/dist/rpc.d.ts.map +1 -0
  26. package/dist/rpc.js +458 -0
  27. package/dist/rpc.js.map +1 -0
  28. package/dist/shortcuts.d.ts +93 -0
  29. package/dist/shortcuts.d.ts.map +1 -0
  30. package/dist/shortcuts.js +281 -0
  31. package/dist/shortcuts.js.map +1 -0
  32. package/dist/source.d.ts +35 -0
  33. package/dist/source.d.ts.map +1 -0
  34. package/dist/source.js +124 -0
  35. package/dist/source.js.map +1 -0
  36. package/dist/types.d.ts +155 -0
  37. package/dist/types.d.ts.map +1 -0
  38. package/dist/types.js +2 -0
  39. package/dist/types.js.map +1 -0
  40. package/package.json +60 -4
  41. package/src/address.ts +134 -0
  42. package/src/client.ts +1298 -0
  43. package/src/constants.ts +41 -0
  44. package/src/index.ts +98 -0
  45. package/src/layout.ts +320 -0
  46. package/src/rpc.ts +549 -0
  47. package/src/shortcuts.ts +367 -0
  48. package/src/source.ts +149 -0
  49. package/src/types.ts +164 -0
@@ -0,0 +1,190 @@
1
+ import { type Cluster } from './constants.js';
2
+ import { type AccountInfo } from './layout.js';
3
+ import { type RpcTransport } from './rpc.js';
4
+ import { type RpcSource, type SourceOptions } from './source.js';
5
+ import { type Commitment, type DefaultTokenField, type NftDetails, type NftOwner, type OwnedToken, type SolBalance, type TokenBalance, type TokenDetails, type TokenField, type TokenProgramOption } from './types.js';
6
+ export interface ClientConfig extends SourceOptions {
7
+ /** 网络。不传 provider 时用于选择内置节点(默认 mainnet);传了 provider 时用于校验节点所在网络 */
8
+ cluster?: Cluster;
9
+ /** 默认 'confirmed' */
10
+ commitment?: Commitment;
11
+ /**
12
+ * 视为原生 SOL 的 mint,默认 [So111…112(Wrapped SOL), 11111…1(System Program)]。
13
+ * 可以包含非 Solana 地址(如 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE),作为调用方自己的“主币”标识:
14
+ * balances / tokens 遇到它时按 SOL 返回,token 原样带回(这是支持的用法,不会做地址校验)
15
+ */
16
+ nativeMints?: readonly string[];
17
+ }
18
+ /** 所有查询共用:取消 */
19
+ export interface RequestOptions {
20
+ /**
21
+ * 取消查询:已取消时直接 reject(不发请求);中途取消时立即 reject(reason 为 signal.reason)。
22
+ * 已经发出、和其他查询合并在一起的底层请求会继续完成(结果给其他调用方),不会中断
23
+ */
24
+ signal?: AbortSignal;
25
+ }
26
+ /** 读余额类查询共用:指定最低 slot、返回读取时的 slot */
27
+ export interface SlotOptions {
28
+ /**
29
+ * 最低 slot:节点高度不到这个 slot 时(如刚成交、公共节点还落后一两个 slot)换下一个节点;
30
+ * 所有节点都不够时每 500ms 重试,最多约 10 秒后抛错。传了它时结果项带 slot
31
+ */
32
+ minContextSlot?: number;
33
+ /** 结果项带 slot(读取时节点的 context.slot;一次查询发了多个请求时取最小的)。默认 false */
34
+ withSlot?: boolean;
35
+ }
36
+ export interface BalancesOptions extends RequestOptions, SlotOptions {
37
+ /** 同时返回 symbol(代币查一次后缓存,主币为 SOL)。默认 false */
38
+ symbol?: boolean;
39
+ /**
40
+ * 用 getTokenAccountsByOwner 扫描持有人的全部代币账户(含非 ATA 账户、同一代币的多个账户合计)。
41
+ * 不传 mints 时总是扫描。注意:免费公共节点大多不支持这个方法,需要自己的节点。
42
+ */
43
+ scan?: boolean;
44
+ /**
45
+ * 指定 mints 时统计哪些代币账户(不传 mints 或 scan: true 时不起作用,总是统计全部账户):
46
+ * - 'ata'(默认):只看关联代币账户(ATA),本地推导地址 + getMultipleAccounts,免费节点也能用
47
+ * - 'all':每个代币发一次按 mint 过滤的 getTokenAccountsByOwner(同一 tick 发出,合并成批量请求),统计该代币的全部账户并合计。
48
+ * 只关心少数几个代币、又要算上非 ATA 账户时比 scan 轻得多;同样需要支持索引方法的节点
49
+ */
50
+ accounts?: 'ata' | 'all';
51
+ /**
52
+ * 只返回这些类型的代币:'spl'(SPL Token)、'token-2022',也可以传程序地址。默认两种都返回。
53
+ * 如传 ['spl']:结果里不含 Token-2022 代币(扫描时也不再请求 Token-2022 的代币账户)。主币 SOL 不受影响
54
+ */
55
+ tokenPrograms?: readonly TokenProgramOption[];
56
+ }
57
+ export interface OwnerTokensOptions extends RequestOptions, SlotOptions {
58
+ /** 只返回这些类型的代币:'spl'、'token-2022' 或程序地址,默认两种都返回;主币 SOL 不受影响(用 includeNative 控制) */
59
+ tokenPrograms?: readonly TokenProgramOption[];
60
+ /** 返回 name / symbol(代币查一次后缓存)。默认 true */
61
+ metadata?: boolean;
62
+ /** 第一项返回 SOL。默认 true */
63
+ includeNative?: boolean;
64
+ /** 包含余额为 0 的代币账户(如已清空但未关闭的 ATA)。默认 false */
65
+ includeZero?: boolean;
66
+ /** 包含 NFT(精度 0 且数量 1)。默认 false */
67
+ includeNfts?: boolean;
68
+ }
69
+ export interface TokensOptions<F extends TokenField = DefaultTokenField> extends RequestOptions {
70
+ /** 要返回的字段,默认 ['name', 'symbol', 'decimals'] */
71
+ fields?: readonly F[];
72
+ }
73
+ /** accounts() 的参数 */
74
+ export interface AccountsOptions extends RequestOptions {
75
+ /** 最低 slot,见 SlotOptions.minContextSlot */
76
+ minContextSlot?: number;
77
+ }
78
+ /** solBalances() 的参数 */
79
+ export interface SolBalancesOptions extends RequestOptions, SlotOptions {
80
+ }
81
+ /** multiBalances() 的单项:一个钱包和要查的代币 */
82
+ export interface BalanceQuery {
83
+ owner: string;
84
+ mints: readonly string[];
85
+ }
86
+ /** 测试用:清空代币信息缓存 */
87
+ export declare function resetTokenMetaCache(): void;
88
+ /** exportTokenMetaCache() 的结果,可以 JSON 序列化 */
89
+ export interface TokenMetaSnapshot {
90
+ version: 1;
91
+ /** [网络:mint, 信息];namesAt 是 name / symbol 的写入时间(毫秒时间戳),导入后继续按 1 小时过期 */
92
+ entries: Array<[string, {
93
+ decimals?: number;
94
+ tokenProgram?: string;
95
+ name?: string | null;
96
+ symbol?: string | null;
97
+ namesAt?: number;
98
+ }]>;
99
+ }
100
+ /**
101
+ * 导出代币信息缓存(decimals / 所属程序 / name / symbol),用于持久化:刷新页面后导入,不必重查 decimals。
102
+ * 只导出按网络共享的条目(自定义节点且没指定 cluster 的客户端,缓存只在该客户端内,不导出)。
103
+ * maxEntries:只导出最近写入的这么多条
104
+ */
105
+ export declare function exportTokenMetaCache(maxEntries?: number): TokenMetaSnapshot;
106
+ /** 导入 exportTokenMetaCache() 的结果;格式不对的条目跳过,内存里已有的条目不覆盖 */
107
+ export declare function importTokenMetaCache(snapshot: unknown): void;
108
+ export interface PersistTokenMetaOptions {
109
+ /** 存储的键,默认 'w3lib:solana-token-meta' */
110
+ key?: string;
111
+ /** 最多保存多少条(最近写入的优先),默认 5000 */
112
+ maxEntries?: number;
113
+ }
114
+ /**
115
+ * 把代币信息缓存持久化到同步的键值存储(如 localStorage):调用时读入,之后缓存有写入就防抖(约 1 秒)整体写回。
116
+ * 返回停止函数(会立即写回还没写的变化)。读到格式不对的数据会丢弃;写入失败(如存储已满)忽略。
117
+ *
118
+ * ```ts
119
+ * persistTokenMetaCache(localStorage) // 刷新页面后 decimals 不必重查
120
+ * ```
121
+ */
122
+ export declare function persistTokenMetaCache(store: {
123
+ getItem(key: string): string | null;
124
+ setItem(key: string, value: string): void;
125
+ }, options?: PersistTokenMetaOptions): () => void;
126
+ export declare class SolanaClient {
127
+ #private;
128
+ readonly transport: RpcTransport;
129
+ constructor(provider?: RpcSource | readonly RpcSource[], config?: ClientConfig);
130
+ /** 节点所在网络(按创世区块哈希识别);不是 mainnet / devnet / testnet 时为 null */
131
+ getCluster(): Promise<Cluster | null>;
132
+ /** 直接发 JSON-RPC 调用(同样参与自动合并与故障切换) */
133
+ request<T = unknown>(method: string, params?: readonly unknown[], options?: RequestOptions): Promise<T>;
134
+ /**
135
+ * 批量读取账户(getMultipleAccounts,按 100 个一组,去重),结果与 addresses 一一对应。
136
+ * 账户不存在或地址非法时为 null。
137
+ */
138
+ accounts(addresses: readonly string[], options?: AccountsOptions): Promise<(AccountInfo | null)[]>;
139
+ /** 批量查多个地址的 SOL 余额(一次 getMultipleAccounts;账户不存在视为 0) */
140
+ solBalances(addresses: readonly string[], options?: SolBalancesOptions): Promise<SolBalance[]>;
141
+ /**
142
+ * 批量查余额(主币 SOL + SPL Token + Token-2022),返回原始余额、decimals 和换算后的数值。
143
+ *
144
+ * - 传 mints:本地推导 ATA,与主币账户、mint 账户一起用 getMultipleAccounts 一次读完,免费节点也能用
145
+ * - 传 mints 且 accounts: 'all':每个代币按 mint 过滤查 getTokenAccountsByOwner,统计全部代币账户(含非 ATA)
146
+ * - 不传 mints(或 scan: true):用 getTokenAccountsByOwner 扫描全部代币账户,返回所有余额大于 0 的代币
147
+ * - 失败项(success: false)带 error:invalid-address(mint 地址非法)/ not-found(mint 不存在)/ not-token(不是代币 mint)
148
+ * - tokenPrograms:只返回这些类型的代币,如 ['spl'] 不含 Token-2022(传了 mints 时,结果里去掉不符合的代币)
149
+ * - minContextSlot / withSlot:要求节点高度、返回读取时的 slot,见 SlotOptions
150
+ */
151
+ balances(owner: string, mints?: readonly string[], options?: BalancesOptions): Promise<TokenBalance[]>;
152
+ /**
153
+ * 多个钱包一次查(如多钱包的持仓列表),结果与 queries 一一对应。
154
+ * ATA 模式(默认)下所有钱包的账户合并成一次(按 100 个一组的)getMultipleAccounts;
155
+ * scan / accounts: 'all' 时每个钱包各自查询(同一 tick 发出,合并成批量请求)。其他选项与 balances() 相同;
156
+ * withSlot 时所有钱包的结果带同一个 slot(整次查询的最小值)。任一 owner 非法时报错
157
+ *
158
+ * ```ts
159
+ * await sol.multiBalances([{ owner: a, mints: [NATIVE_MINT, USDC] }, { owner: b, mints: [USDC] }])
160
+ * ```
161
+ */
162
+ multiBalances(queries: readonly BalanceQuery[], options?: BalancesOptions): Promise<TokenBalance[][]>;
163
+ /**
164
+ * 列出持有人拥有的全部代币(SOL 在第一位),带 name / symbol,适合做资产列表。
165
+ * 需要支持 getTokenAccountsByOwner 的节点(免费公共节点大多不支持)。
166
+ *
167
+ * - 默认不含 NFT(精度 0 且数量 1)和余额为 0 的代币账户(如已清空的 ATA),可用 includeNfts / includeZero 打开
168
+ * - accounts 是该代币的代币账户数量;大于 1 时余额为所有账户的合计
169
+ * - 顺序:SOL,然后 SPL Token 的代币,再然后 Token-2022 的代币(各自按节点返回的顺序;没有价格信息,不按价值排序)
170
+ * - tokenPrograms: ['spl'] 时不含 Token-2022 代币
171
+ * - withSlot 的 slot 只算余额扫描(元数据读取不计入)
172
+ */
173
+ ownerTokens(owner: string, options?: OwnerTokensOptions): Promise<OwnedToken[]>;
174
+ /**
175
+ * 批量查代币详情(一次 getMultipleAccounts),可以选择返回哪些字段。
176
+ * name / symbol / uri 优先取 Token-2022 TokenMetadata 扩展,其次 Metaplex 元数据。
177
+ * transferFee:Token-2022 转账手续费,请求时会顺带发一次 getEpochInfo(同一个批量请求里)选出当前生效的配置
178
+ */
179
+ tokens<const F extends TokenField = DefaultTokenField>(mints: readonly string[], options?: TokensOptions<F>): Promise<TokenDetails<F>[]>;
180
+ /** 批量查 NFT 元数据(Metaplex;Token-2022 NFT 取 TokenMetadata 扩展),一次 getMultipleAccounts */
181
+ nfts(mints: readonly string[], options?: RequestOptions): Promise<NftDetails[]>;
182
+ /**
183
+ * 批量查 NFT 持有人:getTokenLargestAccounts(合并成一个批量请求)+ 一次 getMultipleAccounts。
184
+ * 节点拒绝的 mint(不存在 / 不是代币)在同一次 getMultipleAccounts 里读 mint 账户区分原因
185
+ */
186
+ nftOwners(mints: readonly string[], options?: RequestOptions): Promise<NftOwner[]>;
187
+ /** 查某地址持有的全部 NFT(扫描代币账户:数量 1、精度 0),再批量读元数据。需要支持 getTokenAccountsByOwner 的节点 */
188
+ ownerNfts(owner: string, options?: RequestOptions): Promise<NftDetails[]>;
189
+ }
190
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}