@koralabs/kora-labs-common 6.18.0 → 6.18.2
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.
|
@@ -15,7 +15,11 @@ export declare const statedWaitMs: (headers: HeaderReader | undefined, body: unk
|
|
|
15
15
|
/** Record that `key` must not be called for `waitMs` (only ever extends an existing block). */
|
|
16
16
|
export declare const recordRateLimit: (key: string, waitMs: number, now?: number) => void;
|
|
17
17
|
export declare const rateLimitWaitRemainingMs: (key: string, now?: number) => number;
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Wait out a recorded limit before calling `key`; throw (returning the wait) when it exceeds `maxWaitMs`.
|
|
20
|
+
* A timer runs on the monotonic clock while the block is wall-clock ms (Date.now()), so it can fire a
|
|
21
|
+
* millisecond or more before Date.now() reaches the stated time: re-check and keep waiting until it has.
|
|
22
|
+
*/
|
|
19
23
|
export declare const waitForRateLimit: (key: string, maxWaitMs: number) => Promise<void>;
|
|
20
24
|
/** Test seam: forget every recorded limit. */
|
|
21
25
|
export declare const resetRateLimits: () => void;
|
|
@@ -86,14 +86,17 @@ exports.recordRateLimit = recordRateLimit;
|
|
|
86
86
|
const rateLimitWaitRemainingMs = (key, now = Date.now()) => { var _a; return Math.max(0, ((_a = blockedUntilByKey.get(key)) !== null && _a !== void 0 ? _a : 0) - now); };
|
|
87
87
|
exports.rateLimitWaitRemainingMs = rateLimitWaitRemainingMs;
|
|
88
88
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
89
|
-
/**
|
|
89
|
+
/**
|
|
90
|
+
* Wait out a recorded limit before calling `key`; throw (returning the wait) when it exceeds `maxWaitMs`.
|
|
91
|
+
* A timer runs on the monotonic clock while the block is wall-clock ms (Date.now()), so it can fire a
|
|
92
|
+
* millisecond or more before Date.now() reaches the stated time: re-check and keep waiting until it has.
|
|
93
|
+
*/
|
|
90
94
|
const waitForRateLimit = async (key, maxWaitMs) => {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
await sleep(remaining);
|
|
95
|
+
for (let remaining = (0, exports.rateLimitWaitRemainingMs)(key); remaining > 0; remaining = (0, exports.rateLimitWaitRemainingMs)(key)) {
|
|
96
|
+
if (remaining > maxWaitMs)
|
|
97
|
+
throw new RateLimitedError(key, remaining);
|
|
98
|
+
await sleep(remaining);
|
|
99
|
+
}
|
|
97
100
|
};
|
|
98
101
|
exports.waitForRateLimit = waitForRateLimit;
|
|
99
102
|
/** Test seam: forget every recorded limit. */
|
package/package.json
CHANGED
package/testing/onChain.d.ts
CHANGED
|
@@ -33,7 +33,12 @@ export interface TxConfirmation {
|
|
|
33
33
|
block?: string;
|
|
34
34
|
validContract?: boolean;
|
|
35
35
|
}
|
|
36
|
-
/**
|
|
36
|
+
/**
|
|
37
|
+
* Poll until the tx is in a block AND Blockfrost serves its UTxOs. Right after inclusion Blockfrost can
|
|
38
|
+
* answer /txs/<hash> while /txs/<hash>/utxos still 404s (seen on preview: the live suite's reads right
|
|
39
|
+
* after "confirmed" failed), so "confirmed" means every follow-up read of the tx will answer.
|
|
40
|
+
* A tx in a block with `valid_contract: false` is NOT a success.
|
|
41
|
+
*/
|
|
37
42
|
export declare const waitForTxConfirmation: (chain: ChainConfig, txHash: string, timeoutMs?: number, pollMs?: number) => Promise<TxConfirmation>;
|
|
38
43
|
/** Poll a tx output until it is spent; returns the spending tx hash, or null on timeout. */
|
|
39
44
|
export declare const waitForOutputConsumed: (chain: ChainConfig, txHash: string, outputIndex: number, timeoutMs: number, pollMs?: number) => Promise<string | null>;
|
package/testing/onChain.js
CHANGED
|
@@ -28,17 +28,23 @@ const fetchTxUtxos = (chain, txHash) => getJson(chain, `/txs/${txHash}/utxos`);
|
|
|
28
28
|
exports.fetchTxUtxos = fetchTxUtxos;
|
|
29
29
|
const lovelaceOf = (amount) => { var _a, _b; return BigInt((_b = (_a = amount.find((a) => a.unit === 'lovelace')) === null || _a === void 0 ? void 0 : _a.quantity) !== null && _b !== void 0 ? _b : '0'); };
|
|
30
30
|
exports.lovelaceOf = lovelaceOf;
|
|
31
|
-
/**
|
|
31
|
+
/**
|
|
32
|
+
* Poll until the tx is in a block AND Blockfrost serves its UTxOs. Right after inclusion Blockfrost can
|
|
33
|
+
* answer /txs/<hash> while /txs/<hash>/utxos still 404s (seen on preview: the live suite's reads right
|
|
34
|
+
* after "confirmed" failed), so "confirmed" means every follow-up read of the tx will answer.
|
|
35
|
+
* A tx in a block with `valid_contract: false` is NOT a success.
|
|
36
|
+
*/
|
|
32
37
|
const waitForTxConfirmation = async (chain, txHash, timeoutMs = 180000, pollMs = 5000) => {
|
|
33
38
|
const start = Date.now();
|
|
39
|
+
// A transient provider failure is another poll; a rate limit too long to sit out is returned.
|
|
40
|
+
const poll = (path) => (0, blockfrost_1.blockfrostGet)(chain, path).catch((error) => {
|
|
41
|
+
if (error instanceof rateLimit_1.RateLimitedError)
|
|
42
|
+
throw error;
|
|
43
|
+
return null;
|
|
44
|
+
});
|
|
34
45
|
for (;;) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
if (error instanceof rateLimit_1.RateLimitedError)
|
|
38
|
-
throw error;
|
|
39
|
-
return null;
|
|
40
|
-
});
|
|
41
|
-
if (data)
|
|
46
|
+
const data = await poll(`/txs/${txHash}`);
|
|
47
|
+
if (data && (await poll(`/txs/${txHash}/utxos`)))
|
|
42
48
|
return { confirmed: true, block: data.block, validContract: data.valid_contract };
|
|
43
49
|
if (Date.now() - start >= timeoutMs)
|
|
44
50
|
return { confirmed: false };
|