@dedot/api 0.15.2 → 0.15.3-next.65898ecf.10

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 (47) hide show
  1. package/chaintypes/substrate/index.d.ts +21 -1
  2. package/chaintypes/substrate/index.js +0 -1
  3. package/cjs/chaintypes/substrate/index.js +0 -1
  4. package/cjs/client/DedotClient.js +39 -6
  5. package/cjs/executor/Executor.js +1 -0
  6. package/cjs/executor/v2/StorageQueryExecutorV2.js +1 -3
  7. package/cjs/executor/v2/TxExecutorV2.js +5 -3
  8. package/cjs/json-rpc/group/Archive.js +226 -0
  9. package/cjs/json-rpc/group/ChainHead/ChainHead.js +121 -44
  10. package/cjs/json-rpc/group/ChainHead/error.js +5 -0
  11. package/cjs/json-rpc/group/index.js +1 -0
  12. package/cjs/json-rpc/subscriptionsInfo.js +4 -0
  13. package/cjs/storage/LegacyStorageQuery.js +5 -0
  14. package/cjs/storage/NewStorageQuery.js +5 -0
  15. package/client/BaseSubstrateClient.d.ts +3 -3
  16. package/client/DedotClient.d.ts +6 -4
  17. package/client/DedotClient.js +42 -9
  18. package/client/LegacyClient.d.ts +2 -2
  19. package/executor/Executor.d.ts +5 -5
  20. package/executor/Executor.js +1 -0
  21. package/executor/StorageQueryExecutor.d.ts +2 -2
  22. package/executor/v2/RuntimeApiExecutorV2.d.ts +2 -2
  23. package/executor/v2/StorageQueryExecutorV2.d.ts +4 -4
  24. package/executor/v2/StorageQueryExecutorV2.js +1 -3
  25. package/executor/v2/TxExecutorV2.d.ts +2 -1
  26. package/executor/v2/TxExecutorV2.js +5 -3
  27. package/executor/v2/ViewFunctionExecutorV2.d.ts +2 -2
  28. package/extrinsic/extensions/SignedExtension.d.ts +3 -3
  29. package/extrinsic/submittable/BaseSubmittableExtrinsic.d.ts +2 -2
  30. package/extrinsic/submittable/SubmittableExtrinsicV2.d.ts +2 -2
  31. package/json-rpc/group/Archive.d.ts +134 -0
  32. package/json-rpc/group/Archive.js +222 -0
  33. package/json-rpc/group/ChainHead/ChainHead.d.ts +10 -0
  34. package/json-rpc/group/ChainHead/ChainHead.js +121 -44
  35. package/json-rpc/group/ChainHead/error.d.ts +3 -0
  36. package/json-rpc/group/ChainHead/error.js +5 -0
  37. package/json-rpc/group/index.d.ts +1 -0
  38. package/json-rpc/group/index.js +1 -0
  39. package/json-rpc/subscriptionsInfo.js +4 -0
  40. package/package.json +9 -9
  41. package/storage/BaseStorageQuery.d.ts +5 -6
  42. package/storage/LegacyStorageQuery.d.ts +4 -3
  43. package/storage/LegacyStorageQuery.js +5 -0
  44. package/storage/NewStorageQuery.d.ts +5 -4
  45. package/storage/NewStorageQuery.js +5 -0
  46. package/storage/QueryableStorage.d.ts +2 -2
  47. package/types.d.ts +10 -5
@@ -0,0 +1,222 @@
1
+ import { DedotError } from '@dedot/utils';
2
+ import { JsonRpcGroup } from './JsonRpcGroup.js';
3
+ /**
4
+ * @name Archive
5
+ * Archive JSON-RPC methods for accessing historical blockchain data.
6
+ * Functions with the `archive` prefix allow obtaining the state of the chain
7
+ * at any point in the present or in the past.
8
+ *
9
+ * JSON-RPC V2: https://paritytech.github.io/json-rpc-interface-spec/api/archive.html
10
+ */
11
+ export class Archive extends JsonRpcGroup {
12
+ #genesisHash;
13
+ #cache;
14
+ constructor(client, options) {
15
+ super(client, { prefix: 'archive', supportedVersions: ['unstable', 'v1'], ...options });
16
+ this.#cache = new Map();
17
+ }
18
+ /**
19
+ * Retrieves the body (list of transactions) of a given block.
20
+ * Returns an array of strings containing the hexadecimal-encoded SCALE-codec-encoded
21
+ * transactions in that block. If no block with that hash is found, null.
22
+ *
23
+ * @param hash - The block hash (optional, defaults to current finalized block)
24
+ * @returns Array of transaction hashes or null if block not found
25
+ *
26
+ * @example
27
+ * ```typescript
28
+ * // Get transactions from current finalized block
29
+ * const transactions = await archive.body();
30
+ *
31
+ * // Get transactions from specific block
32
+ * const transactions = await archive.body('0x1234...');
33
+ * ```
34
+ */
35
+ async body(hash) {
36
+ const blockHash = hash || (await this.finalizedHash());
37
+ const cacheKey = `${blockHash}::body`;
38
+ if (this.#cache.has(cacheKey)) {
39
+ return this.#cache.get(cacheKey);
40
+ }
41
+ const result = await this.send('body', blockHash);
42
+ this.#cache.set(cacheKey, result);
43
+ return result;
44
+ }
45
+ /**
46
+ * Get the chain's genesis hash.
47
+ * Returns a string containing the hexadecimal-encoded hash of the genesis block of the chain.
48
+ * This value is cached after the first call.
49
+ *
50
+ * @returns The genesis block hash
51
+ */
52
+ async genesisHash() {
53
+ if (!this.#genesisHash) {
54
+ this.#genesisHash = await this.send('genesisHash');
55
+ }
56
+ return this.#genesisHash;
57
+ }
58
+ /**
59
+ * Get the block's header.
60
+ * Returns a string containing the hexadecimal-encoded SCALE-codec encoding header of the block.
61
+ *
62
+ * @param hash - The block hash (optional, defaults to current finalized block)
63
+ * @returns The encoded block header or null if block not found
64
+ *
65
+ * @example
66
+ * ```typescript
67
+ * // Get header of current finalized block
68
+ * const header = await archive.header();
69
+ *
70
+ * // Get header of specific block
71
+ * const header = await archive.header('0x1234...');
72
+ * ```
73
+ */
74
+ async header(hash) {
75
+ const blockHash = hash || (await this.finalizedHash());
76
+ const cacheKey = `${blockHash}::header`;
77
+ if (this.#cache.has(cacheKey)) {
78
+ return this.#cache.get(cacheKey);
79
+ }
80
+ const result = await this.send('header', blockHash);
81
+ this.#cache.set(cacheKey, result);
82
+ return result;
83
+ }
84
+ /**
85
+ * Get the height of the current finalized block.
86
+ * Returns an integer height of the current finalized block of the chain.
87
+ *
88
+ * @returns The height of the finalized block
89
+ */
90
+ async finalizedHeight() {
91
+ return this.send('finalizedHeight');
92
+ }
93
+ /**
94
+ * Get the hash of the current finalized block.
95
+ * Returns a string containing the hexadecimal-encoded hash of the current finalized block.
96
+ * This is a convenience method that combines finalizedHeight() and hashByHeight().
97
+ *
98
+ * @returns The hash of the current finalized block
99
+ */
100
+ async finalizedHash() {
101
+ const height = await this.finalizedHeight();
102
+ const hashes = await this.hashByHeight(height);
103
+ if (hashes.length === 0) {
104
+ throw new Error(`No block found at finalized height ${height}`);
105
+ }
106
+ return hashes[0];
107
+ }
108
+ /**
109
+ * Get the hashes of blocks from the given height.
110
+ * Returns an array (possibly empty) of strings containing hexadecimal-encoded hashes of block headers.
111
+ *
112
+ * Note: For heights <= finalized height, there is guaranteed to be one block.
113
+ * For heights > finalized height, there may be zero, one or multiple blocks depending on forks.
114
+ *
115
+ * @param height - The block height
116
+ * @returns Array of block hashes at the given height
117
+ */
118
+ async hashByHeight(height) {
119
+ return this.send('hashByHeight', height);
120
+ }
121
+ /**
122
+ * Call into the Runtime API at a specified block's state.
123
+ *
124
+ * @param func - The runtime API function to call
125
+ * @param params - The parameters for the function call (SCALE-encoded)
126
+ * @param hash - The block hash (optional, defaults to current finalized block)
127
+ * @returns The result of the runtime call
128
+ *
129
+ * @example
130
+ * ```typescript
131
+ * // Call Core_version on current finalized block
132
+ * const version = await archive.call('Core_version', '0x');
133
+ *
134
+ * // Call Core_version on specific block
135
+ * const version = await archive.call('Core_version', '0x', '0x1234...');
136
+ * ```
137
+ */
138
+ async call(func, params, hash) {
139
+ const blockHash = hash || (await this.finalizedHash());
140
+ const cacheKey = `${blockHash}::call::${func}::${params}`;
141
+ if (this.#cache.has(cacheKey)) {
142
+ return this.#cache.get(cacheKey);
143
+ }
144
+ const result = await this.send('call', blockHash, func, params);
145
+ if (!result.success) {
146
+ throw new DedotError(result.error);
147
+ }
148
+ this.#cache.set(cacheKey, result.value);
149
+ return result.value;
150
+ }
151
+ /**
152
+ * Returns storage entries at a specific block's state via subscription.
153
+ *
154
+ * @param items - Array of storage queries with optional pagination
155
+ * @param childTrie - Optional child trie key
156
+ * @param callback - Callback to receive storage events
157
+ * @param hash - The block hash (optional, defaults to current finalized block)
158
+ * @returns Unsubscribe function
159
+ */
160
+ async #storageSubscription(items, childTrie, callback, hash) {
161
+ const blockHash = hash || (await this.finalizedHash());
162
+ return this.send('storage', blockHash, items, childTrie, callback);
163
+ }
164
+ /**
165
+ * Returns storage entries at a specific block's state.
166
+ * This method collects all storage events and returns them as a single result.
167
+ *
168
+ * @param items - Array of storage queries with optional pagination
169
+ * @param childTrie - Optional child trie key
170
+ * @param hash - The block hash (optional, defaults to current finalized block)
171
+ * @returns Storage results array
172
+ *
173
+ * @example
174
+ * ```typescript
175
+ * // Query storage from current finalized block
176
+ * const results = await archive.storage([{ key: '0x1234', type: 'value' }]);
177
+ *
178
+ * // Query storage from specific block
179
+ * const results = await archive.storage([{ key: '0x1234', type: 'value' }], null, '0xabcd...');
180
+ * ```
181
+ */
182
+ async storage(items, childTrie, hash) {
183
+ return new Promise(async (resolve, reject) => {
184
+ const results = [];
185
+ const blockHash = hash || (await this.finalizedHash());
186
+ // Generate cache key
187
+ const cacheKey = `${blockHash}::storage::${JSON.stringify(items)}::${childTrie ?? null}`;
188
+ // Check cache
189
+ if (this.#cache.has(cacheKey)) {
190
+ return resolve(this.#cache.get(cacheKey));
191
+ }
192
+ this.#storageSubscription(items, childTrie || null, (event) => {
193
+ switch (event.event) {
194
+ case 'storage':
195
+ results.push(event);
196
+ break;
197
+ case 'storageDone':
198
+ // Set cache after successful completion
199
+ this.#cache.set(cacheKey, results);
200
+ resolve(results);
201
+ break;
202
+ case 'storageError':
203
+ reject(new DedotError(event.error));
204
+ break;
205
+ }
206
+ }, blockHash).catch(reject);
207
+ });
208
+ }
209
+ /**
210
+ * Clears the internal cache used for storing archive query results.
211
+ * This can be useful for memory management or when you want to force fresh data retrieval.
212
+ *
213
+ * @example
214
+ * ```typescript
215
+ * // Clear all cached results
216
+ * archive.clearCache();
217
+ * ```
218
+ */
219
+ clearCache() {
220
+ this.#cache.clear();
221
+ }
222
+ }
@@ -2,6 +2,7 @@ import { BlockHash, Option } from '@dedot/codecs';
2
2
  import type { ChainHeadRuntimeVersion, OperationId, StorageQuery, StorageResult } from '@dedot/types/json-rpc';
3
3
  import { Deferred, HexString } from '@dedot/utils';
4
4
  import type { IJsonRpcClient } from '../../../types.js';
5
+ import { Archive } from '../Archive.js';
5
6
  import { JsonRpcGroup, type JsonRpcGroupOptions } from '../JsonRpcGroup.js';
6
7
  export type OperationHandler<T = any> = {
7
8
  operationId: OperationId;
@@ -20,6 +21,15 @@ export declare const MIN_FINALIZED_QUEUE_SIZE = 10;
20
21
  export declare class ChainHead extends JsonRpcGroup<ChainHeadEvent> {
21
22
  #private;
22
23
  constructor(client: IJsonRpcClient, options?: Partial<JsonRpcGroupOptions>);
24
+ /**
25
+ * Attach an Archive instance as fallback for operations that fail due to unpinned blocks.
26
+ * When a ChainHeadBlockNotPinnedError occurs, the operation will automatically fallback
27
+ * to the Archive API to attempt to retrieve the data from historical blocks.
28
+ *
29
+ * @param archive - Archive instance to use as fallback
30
+ * @returns this ChainHead instance for method chaining
31
+ */
32
+ withArchive(archive: Archive): this;
23
33
  runtimeVersion(): Promise<ChainHeadRuntimeVersion>;
24
34
  bestRuntimeVersion(): Promise<ChainHeadRuntimeVersion>;
25
35
  finalizedHash(): Promise<BlockHash>;
@@ -20,6 +20,17 @@ export class ChainHead extends JsonRpcGroup {
20
20
  #blockUsage;
21
21
  #cache;
22
22
  #operationQueue;
23
+ /**
24
+ * Archive instance used as fallback when ChainHead blocks are not pinned.
25
+ *
26
+ * When ChainHead operations fail with ChainHeadBlockNotPinnedError, the system
27
+ * automatically attempts the same operation using the Archive API. This provides
28
+ * seamless access to historical blockchain data even when blocks are no longer
29
+ * maintained in the ChainHead's pinned block set.
30
+ *
31
+ * @private
32
+ */
33
+ #archive;
23
34
  constructor(client, options) {
24
35
  super(client, { prefix: 'chainHead', supportedVersions: ['unstable', 'v1'], ...options });
25
36
  this.#handlers = {};
@@ -33,6 +44,18 @@ export class ChainHead extends JsonRpcGroup {
33
44
  // This helps us to not accidentally putting too much stress on the JSON-RPC server, especially smoldot/light-client
34
45
  this.#operationQueue = new ThrottleQueue(this.#__unsafe__isSmoldot() ? 25 : 250);
35
46
  }
47
+ /**
48
+ * Attach an Archive instance as fallback for operations that fail due to unpinned blocks.
49
+ * When a ChainHeadBlockNotPinnedError occurs, the operation will automatically fallback
50
+ * to the Archive API to attempt to retrieve the data from historical blocks.
51
+ *
52
+ * @param archive - Archive instance to use as fallback
53
+ * @returns this ChainHead instance for method chaining
54
+ */
55
+ withArchive(archive) {
56
+ this.#archive = archive;
57
+ return this;
58
+ }
36
59
  async runtimeVersion() {
37
60
  await this.#ensureFollowed();
38
61
  return this.#finalizedRuntime;
@@ -341,11 +364,39 @@ export class ChainHead extends JsonRpcGroup {
341
364
  return hash;
342
365
  }
343
366
  else {
344
- throw new ChainHeadBlockNotPinnedError(`Block hash ${hash} is not pinned`);
367
+ throw new ChainHeadBlockNotPinnedError(`Block hash ${hash} is not pinned`, hash);
345
368
  }
346
369
  }
347
370
  return ensurePresence(this.#bestHash || this.#finalizedHash);
348
371
  }
372
+ /**
373
+ * Executes a ChainHead operation with automatic Archive fallback.
374
+ *
375
+ * This method first attempts the primary ChainHead operation. If it fails with
376
+ * ChainHeadBlockNotPinnedError (indicating the block is no longer pinned), and
377
+ * an Archive instance is available, it automatically retries the operation using
378
+ * the Archive API.
379
+ *
380
+ * @param operation - Primary ChainHead operation to attempt
381
+ * @param fallback - Archive operation to fallback to
382
+ * @param hash - Block hash being accessed (for logging)
383
+ * @returns Result from either ChainHead or Archive operation
384
+ * @throws Original error if not a pinning error or no Archive available
385
+ * @private
386
+ */
387
+ async #tryWithArchive(operation, fallback) {
388
+ try {
389
+ return await operation();
390
+ }
391
+ catch (error) {
392
+ if (error instanceof ChainHeadBlockNotPinnedError && this.#archive) {
393
+ const errorHash = error.hash;
394
+ console.warn(`Block ${errorHash} not pinned in ChainHead, falling back to Archive`);
395
+ return await fallback(this.#archive, errorHash);
396
+ }
397
+ throw error;
398
+ }
399
+ }
349
400
  #getOperationHandler(result) {
350
401
  const handler = this.#handlers[result.operationId];
351
402
  if (handler)
@@ -475,21 +526,31 @@ export class ChainHead extends JsonRpcGroup {
475
526
  async body(at) {
476
527
  await this.#ensureFollowed();
477
528
  const shouldRetryOnPrunedBlock = !at;
478
- try {
529
+ const operation = async () => {
479
530
  const atHash = this.#ensurePinnedHash(at);
480
531
  const cacheKey = `${atHash}::body`;
481
532
  if (this.#cache.has(cacheKey)) {
482
533
  return this.#cache.get(cacheKey);
483
534
  }
484
- const operation = async () => {
535
+ const bodyOperation = async () => {
485
536
  await this.#ensureFollowed();
486
537
  const hash = this.#ensurePinnedHash(atHash);
487
538
  const resp = await this.send('body', this.#subscriptionId, hash);
488
539
  return this.#awaitOperation(resp, hash);
489
540
  };
490
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
541
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(bodyOperation, atHash));
491
542
  this.#cache.set(cacheKey, resp);
492
543
  return resp;
544
+ };
545
+ const fallback = async (archive, hash) => {
546
+ const result = await archive.body(hash);
547
+ if (result === undefined) {
548
+ throw new ChainHeadOperationError(`Block ${hash} not found in Archive`);
549
+ }
550
+ return result;
551
+ };
552
+ try {
553
+ return await this.#tryWithArchive(operation, fallback);
493
554
  }
494
555
  catch (e) {
495
556
  if (e instanceof ChainHeadBlockPrunedError && shouldRetryOnPrunedBlock) {
@@ -504,21 +565,25 @@ export class ChainHead extends JsonRpcGroup {
504
565
  async call(func, params = '0x', at) {
505
566
  await this.#ensureFollowed();
506
567
  const shouldRetryOnPrunedBlock = !at;
507
- try {
568
+ const operation = async () => {
508
569
  const atHash = this.#ensurePinnedHash(at);
509
570
  const cacheKey = `${atHash}::call::${func}::${params}`;
510
571
  if (this.#cache.has(cacheKey)) {
511
572
  return this.#cache.get(cacheKey);
512
573
  }
513
- const operation = async () => {
574
+ const callOperation = async () => {
514
575
  await this.#ensureFollowed();
515
576
  const hash = this.#ensurePinnedHash(atHash);
516
577
  const resp = await this.send('call', this.#subscriptionId, hash, func, params);
517
578
  return this.#awaitOperation(resp, hash);
518
579
  };
519
- const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(operation, atHash));
580
+ const resp = await this.#operationQueue.add(() => this.#performOperationWithRetry(callOperation, atHash));
520
581
  this.#cache.set(cacheKey, resp);
521
582
  return resp;
583
+ };
584
+ const fallback = (archive, hash) => archive.call(func, params, hash);
585
+ try {
586
+ return await this.#tryWithArchive(operation, fallback);
522
587
  }
523
588
  catch (e) {
524
589
  if (e instanceof ChainHeadBlockPrunedError && shouldRetryOnPrunedBlock) {
@@ -532,14 +597,18 @@ export class ChainHead extends JsonRpcGroup {
532
597
  */
533
598
  async header(at) {
534
599
  await this.#ensureFollowed();
535
- const hash = this.#ensurePinnedHash(at);
536
- const cacheKey = `${hash}::header`;
537
- if (this.#cache.has(cacheKey)) {
538
- return this.#cache.get(cacheKey);
539
- }
540
- const resp = await this.#getHeader(hash);
541
- this.#cache.set(cacheKey, resp);
542
- return resp;
600
+ const operation = async () => {
601
+ const hash = this.#ensurePinnedHash(at);
602
+ const cacheKey = `${hash}::header`;
603
+ if (this.#cache.has(cacheKey)) {
604
+ return this.#cache.get(cacheKey);
605
+ }
606
+ const resp = await this.#getHeader(hash);
607
+ this.#cache.set(cacheKey, resp);
608
+ return resp;
609
+ };
610
+ const fallback = (archive, errorHash) => archive.header(errorHash);
611
+ return await this.#tryWithArchive(operation, fallback);
543
612
  }
544
613
  async #getHeader(at) {
545
614
  return await this.send('header', this.#subscriptionId, at);
@@ -550,35 +619,46 @@ export class ChainHead extends JsonRpcGroup {
550
619
  async storage(items, childTrie, at) {
551
620
  await this.#ensureFollowed();
552
621
  const shouldRetryOnPrunedBlock = !at;
553
- const hash = this.#ensurePinnedHash(at);
554
- try {
555
- // JSON.stringify(items) might get big, we probably should do a twox hashing in such case
556
- const cacheKey = `${hash}::storage::${JSON.stringify(items)}::${childTrie ?? null}`;
557
- if (this.#cache.has(cacheKey)) {
558
- return this.#cache.get(cacheKey);
559
- }
560
- this.#blockUsage.use(hash);
561
- let results = [];
562
- if (this.#__unsafe__isSmoldot()) {
563
- const fetchItem = async (item) => {
564
- const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
565
- if (newDiscardedItems.length > 0) {
566
- return fetchItem(item);
622
+ const operation = async () => {
623
+ const hash = this.#ensurePinnedHash(at);
624
+ try {
625
+ // JSON.stringify(items) might get big, we probably should do a twox hashing in such case
626
+ const cacheKey = `${hash}::storage::${JSON.stringify(items)}::${childTrie ?? null}`;
627
+ if (this.#cache.has(cacheKey)) {
628
+ return this.#cache.get(cacheKey);
629
+ }
630
+ this.#blockUsage.use(hash);
631
+ let results = [];
632
+ if (this.#__unsafe__isSmoldot()) {
633
+ const fetchItem = async (item) => {
634
+ const [batch, newDiscardedItems] = await this.#getStorage([item], childTrie ?? null, hash);
635
+ if (newDiscardedItems.length > 0) {
636
+ return fetchItem(item);
637
+ }
638
+ return batch;
639
+ };
640
+ results = (await Promise.all(items.map((one) => fetchItem(one)))).flat();
641
+ }
642
+ else {
643
+ let queryItems = items;
644
+ while (queryItems.length > 0) {
645
+ const [newBatch, newDiscardedItems] = await this.#getStorage(queryItems, childTrie ?? null, hash);
646
+ results.push(...newBatch);
647
+ queryItems = newDiscardedItems;
567
648
  }
568
- return batch;
569
- };
570
- results = (await Promise.all(items.map((one) => fetchItem(one)))).flat();
571
- }
572
- else {
573
- let queryItems = items;
574
- while (queryItems.length > 0) {
575
- const [newBatch, newDiscardedItems] = await this.#getStorage(queryItems, childTrie ?? null, hash);
576
- results.push(...newBatch);
577
- queryItems = newDiscardedItems;
578
649
  }
650
+ this.#cache.set(cacheKey, results);
651
+ return results;
652
+ }
653
+ finally {
654
+ this.#blockUsage.release(hash);
579
655
  }
580
- this.#cache.set(cacheKey, results);
581
- return results;
656
+ };
657
+ const fallback = (archive, hash) => {
658
+ return archive.storage(items, childTrie, hash);
659
+ };
660
+ try {
661
+ return await this.#tryWithArchive(operation, fallback);
582
662
  }
583
663
  catch (e) {
584
664
  if (e instanceof ChainHeadBlockPrunedError && shouldRetryOnPrunedBlock) {
@@ -586,9 +666,6 @@ export class ChainHead extends JsonRpcGroup {
586
666
  }
587
667
  throw e;
588
668
  }
589
- finally {
590
- this.#blockUsage.release(hash);
591
- }
592
669
  }
593
670
  async #getStorage(items, childTrie, at) {
594
671
  const operation = () => this.#getStorageOperation(items, childTrie, this.#ensurePinnedHash(at));
@@ -1,3 +1,4 @@
1
+ import { BlockHash } from '@dedot/codecs';
1
2
  import { DedotError } from '@dedot/utils';
2
3
  export declare enum RetryStrategy {
3
4
  NOW = "NOW",// Retry immediately
@@ -49,6 +50,8 @@ export declare class ChainHeadInvalidRuntimeError extends ChainHeadError {
49
50
  }
50
51
  export declare class ChainHeadBlockNotPinnedError extends ChainHeadError {
51
52
  name: string;
53
+ hash: BlockHash;
54
+ constructor(message: string, hash: BlockHash | string);
52
55
  }
53
56
  export declare class ChainHeadBlockPrunedError extends ChainHeadError {
54
57
  name: string;
@@ -50,6 +50,11 @@ export class ChainHeadInvalidRuntimeError extends ChainHeadError {
50
50
  }
51
51
  export class ChainHeadBlockNotPinnedError extends ChainHeadError {
52
52
  name = 'ChainHeadBlockNotPinnedError';
53
+ hash;
54
+ constructor(message, hash) {
55
+ super(message);
56
+ this.hash = hash;
57
+ }
53
58
  }
54
59
  export class ChainHeadBlockPrunedError extends ChainHeadError {
55
60
  name = 'ChainHeadBlockPrunedError';
@@ -1,4 +1,5 @@
1
1
  export * from './JsonRpcGroup.js';
2
+ export * from './Archive.js';
2
3
  export * from './ChainSpec.js';
3
4
  export * from './Transaction.js';
4
5
  export * from './TransactionWatch.js';
@@ -1,4 +1,5 @@
1
1
  export * from './JsonRpcGroup.js';
2
+ export * from './Archive.js';
2
3
  export * from './ChainSpec.js';
3
4
  export * from './Transaction.js';
4
5
  export * from './TransactionWatch.js';
@@ -14,4 +14,8 @@ export const subscriptionsInfo = {
14
14
  'transactionWatch_unstable_unwatch',
15
15
  ],
16
16
  transactionWatch_v1_submitAndWatch: ['transactionWatch_v1_watchEvent', 'transactionWatch_v1_unwatch'],
17
+ archive_v1_storage: ['archive_v1_storageEvent', 'archive_v1_stopStorage'],
18
+ archive_v1_storageDiff: ['archive_v1_storageDiffEvent', 'archive_v1_stopStorageDiff'],
19
+ archive_unstable_storage: ['archive_unstable_storageEvent', 'archive_unstable_stopStorage'],
20
+ archive_unstable_storageDiff: ['archive_unstable_storageDiffEvent', 'archive_unstable_stopStorageDiff'],
17
21
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dedot/api",
3
- "version": "0.15.2",
3
+ "version": "0.15.3-next.65898ecf.10+65898ecf",
4
4
  "description": "A delightful JavaScript/TypeScript client for Polkadot & Substrate",
5
5
  "author": "Thang X. Vu <thang@dedot.dev>",
6
6
  "homepage": "https://dedot.dev",
@@ -13,13 +13,13 @@
13
13
  "type": "module",
14
14
  "sideEffects": false,
15
15
  "dependencies": {
16
- "@dedot/codecs": "0.15.2",
17
- "@dedot/providers": "0.15.2",
18
- "@dedot/runtime-specs": "0.15.2",
19
- "@dedot/shape": "0.15.2",
20
- "@dedot/storage": "0.15.2",
21
- "@dedot/types": "0.15.2",
22
- "@dedot/utils": "0.15.2"
16
+ "@dedot/codecs": "0.15.3-next.65898ecf.10+65898ecf",
17
+ "@dedot/providers": "0.15.3-next.65898ecf.10+65898ecf",
18
+ "@dedot/runtime-specs": "0.15.3-next.65898ecf.10+65898ecf",
19
+ "@dedot/shape": "0.15.3-next.65898ecf.10+65898ecf",
20
+ "@dedot/storage": "0.15.3-next.65898ecf.10+65898ecf",
21
+ "@dedot/types": "0.15.3-next.65898ecf.10+65898ecf",
22
+ "@dedot/utils": "0.15.3-next.65898ecf.10+65898ecf"
23
23
  },
24
24
  "scripts": {
25
25
  "build": "tsc --project tsconfig.build.json && tsc --project tsconfig.build.cjs.json",
@@ -48,7 +48,7 @@
48
48
  "node": ">=18"
49
49
  },
50
50
  "license": "Apache-2.0",
51
- "gitHead": "75231d6888303dcf598cfd31592df13230707cb4",
51
+ "gitHead": "65898ecf2226162fc6632d3f4f64ad5fe1179643",
52
52
  "module": "./index.js",
53
53
  "types": "./index.d.ts"
54
54
  }
@@ -1,7 +1,6 @@
1
+ import { ISubstrateClient, ISubstrateClientAt } from '@dedot/api/types';
1
2
  import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
2
- import type { Callback, RpcVersion, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
3
- import type { SubstrateApi } from '../chaintypes/index.js';
4
- import { BaseSubstrateClient } from '../client/BaseSubstrateClient.js';
3
+ import type { Callback, Unsub } from '@dedot/types';
5
4
  /**
6
5
  * @name BaseStorageQuery
7
6
  * @description
@@ -16,12 +15,12 @@ import { BaseSubstrateClient } from '../client/BaseSubstrateClient.js';
16
15
  * This abstraction eliminates code duplication between different client implementations
17
16
  * and provides a consistent interface for storage operations.
18
17
  */
19
- export declare abstract class BaseStorageQuery<Rv extends RpcVersion, ChainApi extends VersionedGenericSubstrateApi = SubstrateApi, T extends BaseSubstrateClient<Rv, ChainApi> = BaseSubstrateClient<Rv, ChainApi>> {
20
- protected client: T;
18
+ export declare abstract class BaseStorageQuery {
19
+ protected client: ISubstrateClientAt<any> | ISubstrateClient<any, any>;
21
20
  /**
22
21
  * @param client - The substrate client instance
23
22
  */
24
- constructor(client: T);
23
+ protected constructor(client: ISubstrateClientAt<any> | ISubstrateClient<any, any>);
25
24
  /**
26
25
  * Query multiple storage items in a single call
27
26
  *
@@ -1,6 +1,5 @@
1
1
  import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
2
- import type { Callback, RpcLegacy, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
3
- import type { SubstrateApi } from '../chaintypes/index.js';
2
+ import type { Callback, Unsub } from '@dedot/types';
4
3
  import { LegacyClient } from '../client/LegacyClient.js';
5
4
  import { BaseStorageQuery } from './BaseStorageQuery.js';
6
5
  /**
@@ -15,7 +14,9 @@ import { BaseStorageQuery } from './BaseStorageQuery.js';
15
14
  * - Subscriptions using state_subscribeStorage
16
15
  * - Efficient change tracking for subscriptions
17
16
  */
18
- export declare class LegacyStorageQuery<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends BaseStorageQuery<RpcLegacy, ChainApi, LegacyClient<ChainApi>> {
17
+ export declare class LegacyStorageQuery extends BaseStorageQuery {
18
+ protected client: LegacyClient<any>;
19
+ constructor(client: LegacyClient<any>);
19
20
  /**
20
21
  * Query multiple storage items in a single call using state_queryStorageAt
21
22
  *
@@ -12,6 +12,11 @@ import { BaseStorageQuery } from './BaseStorageQuery.js';
12
12
  * - Efficient change tracking for subscriptions
13
13
  */
14
14
  export class LegacyStorageQuery extends BaseStorageQuery {
15
+ client;
16
+ constructor(client) {
17
+ super(client);
18
+ this.client = client;
19
+ }
15
20
  /**
16
21
  * Query multiple storage items in a single call using state_queryStorageAt
17
22
  *
@@ -1,7 +1,6 @@
1
+ import { DedotClient } from '@dedot/api/client';
1
2
  import { BlockHash, StorageData, StorageKey } from '@dedot/codecs';
2
- import type { Callback, RpcV2, Unsub, VersionedGenericSubstrateApi } from '@dedot/types';
3
- import type { SubstrateApi } from '../chaintypes/index.js';
4
- import { DedotClient } from '../client/DedotClient.js';
3
+ import type { Callback, Unsub } from '@dedot/types';
5
4
  import { BaseStorageQuery } from './BaseStorageQuery.js';
6
5
  /**
7
6
  * @name NewStorageQuery
@@ -15,7 +14,9 @@ import { BaseStorageQuery } from './BaseStorageQuery.js';
15
14
  * - Subscriptions using chainHead 'bestBlock' events
16
15
  * - Efficient change detection for subscriptions
17
16
  */
18
- export declare class NewStorageQuery<ChainApi extends VersionedGenericSubstrateApi = SubstrateApi> extends BaseStorageQuery<RpcV2, ChainApi, DedotClient<ChainApi>> {
17
+ export declare class NewStorageQuery extends BaseStorageQuery {
18
+ protected client: DedotClient<any>;
19
+ constructor(client: DedotClient<any>);
19
20
  /**
20
21
  * Query multiple storage items in a single call using chainHead_storage
21
22
  *