@fleet-sdk/blockchain-providers 0.6.1 → 0.6.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +13 -0
- package/dist/index.d.mts +10 -6
- package/dist/index.d.ts +10 -6
- package/dist/index.js +59 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +59 -35
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/ergo-graphql/ergoGraphQLProvider.ts +49 -36
- package/src/types/blockchainProvider.ts +3 -3
- package/src/utils/_tests.ts +0 -2
- package/src/utils/networking.ts +18 -4
@@ -58,6 +58,8 @@ import {
|
|
58
58
|
UNCONF_TX_QUERY
|
59
59
|
} from "./queries";
|
60
60
|
|
61
|
+
type SkipAndTake = { skip?: number; take?: number };
|
62
|
+
|
61
63
|
export type GraphQLBoxWhere = BoxWhere & {
|
62
64
|
/** Base16-encoded ErgoTrees */
|
63
65
|
ergoTrees?: HexString[];
|
@@ -152,15 +154,18 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
152
154
|
return this as unknown as ErgoGraphQLProvider<M>;
|
153
155
|
}
|
154
156
|
|
155
|
-
async *streamBoxes(
|
157
|
+
async *streamBoxes(
|
158
|
+
query: GraphQLBoxQuery & SkipAndTake
|
159
|
+
): AsyncGenerator<ChainProviderBox<I>[]> {
|
156
160
|
if (isEmpty(query.where)) {
|
157
161
|
throw new Error("Cannot fetch unspent boxes without a where clause.");
|
158
162
|
}
|
159
163
|
|
160
164
|
const notBeingSpent = (box: GQLBox) => !box.beingSpent;
|
161
165
|
const returnedBoxIds = new Set<string>();
|
162
|
-
const {
|
163
|
-
const
|
166
|
+
const { from, take } = query;
|
167
|
+
const pageSize = take ?? PAGE_SIZE;
|
168
|
+
const queries = buildGqlBoxQueries(query);
|
164
169
|
const isMempoolAware = from !== "blockchain";
|
165
170
|
|
166
171
|
for (const query of queries) {
|
@@ -180,7 +185,7 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
180
185
|
boxes = boxes.concat(confirmedBoxes);
|
181
186
|
}
|
182
187
|
|
183
|
-
inclChain = data.boxes.length ===
|
188
|
+
inclChain = data.boxes.length === pageSize;
|
184
189
|
}
|
185
190
|
|
186
191
|
if (isMempoolAware && hasMempool(data)) {
|
@@ -191,7 +196,7 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
191
196
|
boxes = boxes.concat(mempoolBoxes);
|
192
197
|
}
|
193
198
|
|
194
|
-
inclPool = data.mempool.boxes.length ===
|
199
|
+
inclPool = data.mempool.boxes.length === pageSize;
|
195
200
|
}
|
196
201
|
|
197
202
|
if (some(boxes)) {
|
@@ -208,7 +213,7 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
208
213
|
}
|
209
214
|
}
|
210
215
|
|
211
|
-
if (inclChain || inclPool) query.skip +=
|
216
|
+
if (inclChain || inclPool) query.skip += pageSize;
|
212
217
|
}
|
213
218
|
}
|
214
219
|
}
|
@@ -220,9 +225,10 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
220
225
|
}
|
221
226
|
|
222
227
|
async *streamUnconfirmedTransactions(
|
223
|
-
query: TransactionQuery<GraphQLUnconfirmedTransactionWhere>
|
224
|
-
):
|
225
|
-
const
|
228
|
+
query: TransactionQuery<GraphQLUnconfirmedTransactionWhere> & SkipAndTake
|
229
|
+
): AsyncGenerator<ChainProviderUnconfirmedTransaction<I>[]> {
|
230
|
+
const pageSize = query.take ?? PAGE_SIZE;
|
231
|
+
const queries = buildGqlUnconfirmedTxQueries(query);
|
226
232
|
|
227
233
|
for (const query of queries) {
|
228
234
|
let keepFetching = true;
|
@@ -234,8 +240,8 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
234
240
|
);
|
235
241
|
}
|
236
242
|
|
237
|
-
keepFetching = response.data?.mempool?.transactions?.length ===
|
238
|
-
if (keepFetching) query.skip +=
|
243
|
+
keepFetching = response.data?.mempool?.transactions?.length === pageSize;
|
244
|
+
if (keepFetching) query.skip += pageSize;
|
239
245
|
}
|
240
246
|
}
|
241
247
|
}
|
@@ -252,9 +258,10 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
252
258
|
}
|
253
259
|
|
254
260
|
async *streamConfirmedTransactions(
|
255
|
-
query: TransactionQuery<GraphQLConfirmedTransactionWhere>
|
256
|
-
):
|
257
|
-
const
|
261
|
+
query: TransactionQuery<GraphQLConfirmedTransactionWhere> & SkipAndTake
|
262
|
+
): AsyncGenerator<ChainProviderConfirmedTransaction<I>[]> {
|
263
|
+
const pageSize = query.take ?? PAGE_SIZE;
|
264
|
+
const queries = buildGqlConfirmedTxQueries(query);
|
258
265
|
|
259
266
|
for (const query of queries) {
|
260
267
|
let keepFetching = true;
|
@@ -266,8 +273,8 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
266
273
|
);
|
267
274
|
}
|
268
275
|
|
269
|
-
keepFetching = response.data?.transactions?.length ===
|
270
|
-
if (keepFetching) query.skip +=
|
276
|
+
keepFetching = response.data?.transactions?.length === pageSize;
|
277
|
+
if (keepFetching) query.skip += pageSize;
|
271
278
|
}
|
272
279
|
}
|
273
280
|
}
|
@@ -334,11 +341,11 @@ export class ErgoGraphQLProvider<I = bigint> implements IBlockchainProvider<I> {
|
|
334
341
|
}
|
335
342
|
}
|
336
343
|
|
337
|
-
function buildGqlBoxQueries(
|
344
|
+
function buildGqlBoxQueries(query: GraphQLBoxQuery & SkipAndTake) {
|
338
345
|
const ergoTrees = uniq(
|
339
346
|
[
|
340
|
-
merge(where.ergoTrees, where.ergoTree) ?? [],
|
341
|
-
merge(where.addresses, where.address)?.map((a) =>
|
347
|
+
merge(query.where.ergoTrees, query.where.ergoTree) ?? [],
|
348
|
+
merge(query.where.addresses, query.where.address)?.map((a) =>
|
342
349
|
typeof a === "string" ? ErgoAddress.decode(a).ergoTree : a.ergoTree
|
343
350
|
) ?? []
|
344
351
|
].flat()
|
@@ -346,22 +353,24 @@ function buildGqlBoxQueries(where: GraphQLBoxWhere) {
|
|
346
353
|
|
347
354
|
return chunk(ergoTrees, MAX_ARGS).map((chunk) => ({
|
348
355
|
spent: false,
|
349
|
-
boxIds: where.boxId ? [where.boxId] : undefined,
|
356
|
+
boxIds: query.where.boxId ? [query.where.boxId] : undefined,
|
350
357
|
ergoTrees: chunk,
|
351
|
-
ergoTreeTemplateHash: where.templateHash,
|
352
|
-
tokenId: where.tokenId,
|
353
|
-
skip: 0,
|
354
|
-
take: PAGE_SIZE
|
358
|
+
ergoTreeTemplateHash: query.where.templateHash,
|
359
|
+
tokenId: query.where.tokenId,
|
360
|
+
skip: query.skip ?? 0,
|
361
|
+
take: query.take ?? PAGE_SIZE
|
355
362
|
}));
|
356
363
|
}
|
357
364
|
|
358
|
-
function buildGqlUnconfirmedTxQueries(
|
365
|
+
function buildGqlUnconfirmedTxQueries(
|
366
|
+
query: TransactionQuery<GraphQLUnconfirmedTransactionWhere> & SkipAndTake
|
367
|
+
) {
|
359
368
|
const addresses = uniq(
|
360
369
|
[
|
361
|
-
merge(where.addresses, where.address)?.map((address): string =>
|
370
|
+
merge(query.where.addresses, query.where.address)?.map((address): string =>
|
362
371
|
typeof address === "string" ? address : address.encode()
|
363
372
|
) ?? [],
|
364
|
-
merge(where.ergoTrees, where.ergoTree)?.map((tree) =>
|
373
|
+
merge(query.where.ergoTrees, query.where.ergoTree)?.map((tree) =>
|
365
374
|
ErgoAddress.fromErgoTree(tree).encode()
|
366
375
|
) ?? []
|
367
376
|
].flat()
|
@@ -369,18 +378,22 @@ function buildGqlUnconfirmedTxQueries(where: GraphQLConfirmedTransactionWhere) {
|
|
369
378
|
|
370
379
|
return chunk(addresses, MAX_ARGS).map((chunk) => ({
|
371
380
|
addresses: chunk.length ? chunk : undefined,
|
372
|
-
transactionIds: where.transactionId ? [where.transactionId] : undefined,
|
373
|
-
skip: 0,
|
374
|
-
take: PAGE_SIZE
|
381
|
+
transactionIds: query.where.transactionId ? [query.where.transactionId] : undefined,
|
382
|
+
skip: query.skip ?? 0,
|
383
|
+
take: query.take ?? PAGE_SIZE
|
375
384
|
}));
|
376
385
|
}
|
377
386
|
|
378
|
-
function buildGqlConfirmedTxQueries(
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
387
|
+
function buildGqlConfirmedTxQueries(
|
388
|
+
query: TransactionQuery<GraphQLConfirmedTransactionWhere> & SkipAndTake
|
389
|
+
) {
|
390
|
+
return buildGqlUnconfirmedTxQueries(
|
391
|
+
query as TransactionQuery<GraphQLUnconfirmedTransactionWhere>
|
392
|
+
).map((q) => ({
|
393
|
+
...q,
|
394
|
+
headerId: query.where.headerId,
|
395
|
+
minHeight: query.where.minHeight,
|
396
|
+
onlyRelevantOutputs: query.where.onlyRelevantOutputs
|
384
397
|
}));
|
385
398
|
}
|
386
399
|
|
@@ -142,14 +142,14 @@ export interface IBlockchainProvider<I> {
|
|
142
142
|
/**
|
143
143
|
* Stream boxes.
|
144
144
|
*/
|
145
|
-
streamBoxes(query: BoxQuery<BoxWhere>):
|
145
|
+
streamBoxes(query: BoxQuery<BoxWhere>): AsyncGenerator<ChainProviderBox<I>[]>;
|
146
146
|
|
147
147
|
/**
|
148
148
|
* Stream unconfirmed transactions
|
149
149
|
*/
|
150
150
|
streamUnconfirmedTransactions(
|
151
151
|
query: TransactionQuery<UnconfirmedTransactionWhere>
|
152
|
-
):
|
152
|
+
): AsyncGenerator<ChainProviderUnconfirmedTransaction<I>[]>;
|
153
153
|
|
154
154
|
/**
|
155
155
|
* Get unconfirmed transactions
|
@@ -163,7 +163,7 @@ export interface IBlockchainProvider<I> {
|
|
163
163
|
*/
|
164
164
|
streamConfirmedTransactions(
|
165
165
|
query: TransactionQuery<ConfirmedTransactionWhere>
|
166
|
-
):
|
166
|
+
): AsyncGenerator<ChainProviderConfirmedTransaction<I>[]>;
|
167
167
|
|
168
168
|
/**
|
169
169
|
* Get confirmed transactions
|
package/src/utils/_tests.ts
CHANGED
package/src/utils/networking.ts
CHANGED
@@ -17,6 +17,18 @@ export type FetchOptions = {
|
|
17
17
|
httpOptions?: RequestInit;
|
18
18
|
};
|
19
19
|
|
20
|
+
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Status
|
21
|
+
const RETRY_STATUS_CODES = new Set([
|
22
|
+
408, // Request Timeout
|
23
|
+
409, // Conflict
|
24
|
+
425, // Too Early (Experimental)
|
25
|
+
429, // Too Many Requests
|
26
|
+
500, // Internal Server Error
|
27
|
+
502, // Bad Gateway
|
28
|
+
503, // Service Unavailable
|
29
|
+
504 // Gateway Timeout
|
30
|
+
]);
|
31
|
+
|
20
32
|
export async function request<T>(path: string, opt?: Partial<FetchOptions>): Promise<T> {
|
21
33
|
const url = buildURL(path, opt?.query, opt?.base);
|
22
34
|
|
@@ -24,10 +36,12 @@ export async function request<T>(path: string, opt?: Partial<FetchOptions>): Pro
|
|
24
36
|
if (opt?.retry) {
|
25
37
|
const routes = some(opt.retry.fallbacks) ? [url, ...opt.retry.fallbacks] : [url];
|
26
38
|
const attempts = opt.retry.attempts;
|
27
|
-
response = await exponentialRetry(
|
28
|
-
|
29
|
-
|
30
|
-
|
39
|
+
response = await exponentialRetry(async (r) => {
|
40
|
+
const response = await fetch(resolveUrl(routes, attempts - r), opt.httpOptions);
|
41
|
+
if (RETRY_STATUS_CODES.has(response.status)) throw new Error(response.statusText);
|
42
|
+
|
43
|
+
return response;
|
44
|
+
}, opt.retry);
|
31
45
|
} else {
|
32
46
|
response = await fetch(url, opt?.httpOptions);
|
33
47
|
}
|