diff --git a/apps/alias-server/test/chronik.test.js b/apps/alias-server/test/chronik.test.js --- a/apps/alias-server/test/chronik.test.js +++ b/apps/alias-server/test/chronik.test.js @@ -13,7 +13,9 @@ unconfirmedTxs, unconfirmedTxsAfterConfirmation, } = require('./mocks/txHistoryMocks'); -const { MockChronikClient } = require('../../../modules/mock-chronik-client'); +const { + MockChronikClient, +} = require('../../../modules/mock-chronik-client/dist'); // todo make txsperpage a param and test different values describe('alias-server chronik.js', () => { @@ -31,9 +33,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, allTxHistoryFromChronik); + mockedChronik.setTxHistoryByScript(type, hash, allTxHistoryFromChronik); const result = await getUnprocessedTxHistory( mockedChronik, @@ -59,9 +60,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, allTxHistory); + mockedChronik.setTxHistoryByScript(type, hash, allTxHistory); const result = await getUnprocessedTxHistory( mockedChronik, @@ -86,9 +86,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, allTxHistory); + mockedChronik.setTxHistoryByScript(type, hash, allTxHistory); const result = await getUnprocessedTxHistory( mockedChronik, diff --git a/apps/alias-server/test/chronikWsHandler.test.js b/apps/alias-server/test/chronikWsHandler.test.js --- a/apps/alias-server/test/chronikWsHandler.test.js +++ b/apps/alias-server/test/chronikWsHandler.test.js @@ -10,7 +10,9 @@ initializeWebsocket, parseWebsocketMessage, } = require('../src/chronikWsHandler'); -const { MockChronikClient } = require('../../../modules/mock-chronik-client'); +const { + MockChronikClient, +} = require('../../../modules/mock-chronik-client/dist'); // Mock mongodb const { initializeDb, @@ -86,7 +88,7 @@ const telegramBot = null; const channelId = null; - await initializeWebsocket( + const ws = await initializeWebsocket( mockedChronik, wsTestAddress, db, @@ -96,9 +98,9 @@ ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual(ws.waitForOpenCalled, true); // Confirm subscribe was called - assert.deepEqual(mockedChronik.wsSubscribeCalled, true); + assert.equal(ws.subs.scripts.length, 1); }); it('initializeWebsocket returns expected websocket object for a p2sh address', async function () { const wsTestAddress = @@ -109,7 +111,7 @@ const telegramBot = null; const channelId = null; - await initializeWebsocket( + const ws = await initializeWebsocket( mockedChronik, wsTestAddress, db, @@ -119,9 +121,9 @@ ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual(ws.waitForOpenCalled, true); // Confirm subscribe was called - assert.deepEqual(mockedChronik.wsSubscribeCalled, true); + assert.equal(ws.subs.scripts.length, 1); }); it('parseWebsocketMessage correctly processes a chronik websocket BLK_FINALIZED message if block is avalanche finalized', async function () { // Initialize chronik mock @@ -142,9 +144,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); const result = await parseWebsocketMessage( mockedChronik, @@ -184,9 +185,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); // Initialize mocks for second call to parseWebsocketMessage const nextMockedChronik = new MockChronikClient(); @@ -199,10 +199,9 @@ // Add tx history to nextMockedChronik // Set the script - nextMockedChronik.setScript(type, hash); // Set the mock tx history // For now, assume it's the same as before, i.e. no new txs found - nextMockedChronik.setTxHistory(type, hash, generated.txHistory); + nextMockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); const firstCallPromise = parseWebsocketMessage( mockedChronik, @@ -262,10 +261,7 @@ const mockedChronik = new MockChronikClient(); // Mock chronik response - mockedChronik.setMock('tx', { - input: incomingTxid, - output: pendingTxObject, - }); + mockedChronik.setTx(incomingTxid, pendingTxObject); const result = await parseWebsocketMessage( mockedChronik, db, @@ -303,10 +299,7 @@ const mockedChronik = new MockChronikClient(); // Mock chronik response - mockedChronik.setMock('tx', { - input: incomingTxid, - output: pendingTxObject, - }); + mockedChronik.setTx(incomingTxid, pendingTxObject); const result = await parseWebsocketMessage( mockedChronik, db, diff --git a/apps/alias-server/test/events.test.js b/apps/alias-server/test/events.test.js --- a/apps/alias-server/test/events.test.js +++ b/apps/alias-server/test/events.test.js @@ -12,7 +12,9 @@ handleBlockFinalized, handleAddedToMempool, } = require('../src/events'); -const { MockChronikClient } = require('../../../modules/mock-chronik-client'); +const { + MockChronikClient, +} = require('../../../modules/mock-chronik-client/dist'); // Mock mongodb const { initializeDb, @@ -90,10 +92,7 @@ }; // Tell mockedChronik what response we expect - mockedChronik.setMock('blockchainInfo', { - input: null, - output: mockBlockchaininfoResponse, - }); + mockedChronik.setBlockchainInfo(mockBlockchaininfoResponse); // Add tx history to mockedChronik // Set the script @@ -101,17 +100,15 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); // Mock chronik block call for a finalized chaintip - mockedChronik.setMock('block', { - input: mockBlockchaininfoResponse.tipHash, - output: { - blockInfo: { isFinal: true }, - }, - }); + mockedChronik.setBlock( + mockBlockchaininfoResponse.tipHash, + + { blockInfo: { isFinal: true } }, + ); const db = testDb; const telegramBot = null; @@ -171,10 +168,7 @@ const mockedChronik = new MockChronikClient(); // Tell mockedChronik what response we expect - mockedChronik.setMock('blockchainInfo', { - input: null, - output: new Error('some chronik error'), - }); + mockedChronik.setBlockchainInfo(new Error('some chronik error')); const db = null; const telegramBot = null; @@ -204,17 +198,11 @@ }; // Tell mockedChronik what response we expect - mockedChronik.setMock('blockchainInfo', { - input: null, - output: mockBlockchaininfoResponse, - }); + mockedChronik.setBlockchainInfo(mockBlockchaininfoResponse); // Mock chronik block call for unfinalized chaintip - mockedChronik.setMock('block', { - input: mockBlockchaininfoResponse.tipHash, - output: { - blockInfo: { isFinal: false }, - }, + mockedChronik.setBlock(mockBlockchaininfoResponse.tipHash, { + blockInfo: { isFinal: false }, }); const db = null; @@ -248,9 +236,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); const telegramBot = null; const channelId = null; @@ -289,9 +276,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); const telegramBot = null; const channelId = null; @@ -332,9 +318,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); const telegramBot = null; const channelId = null; @@ -368,10 +353,7 @@ const mockedChronik = new MockChronikClient(); // Mock an error from the chronik.tx call - mockedChronik.setMock('tx', { - input: incomingTxid, - output: new Error('Some chronik error'), - }); + mockedChronik.setTx(incomingTxid, new Error('Some chronik error')); await assert.rejects( async () => { @@ -408,10 +390,7 @@ const mockedChronik = new MockChronikClient(); // Mock chronik response - mockedChronik.setMock('tx', { - input: incomingTxid, - output: pendingTxObject, - }); + mockedChronik.setTx(incomingTxid, pendingTxObject); assert.strictEqual( await handleAddedToMempool( diff --git a/apps/alias-server/test/main.test.js b/apps/alias-server/test/main.test.js --- a/apps/alias-server/test/main.test.js +++ b/apps/alias-server/test/main.test.js @@ -17,7 +17,9 @@ const { MongoClient } = require('mongodb'); const { MongoMemoryServer } = require('mongodb-memory-server'); // Mock chronik -const { MockChronikClient } = require('../../../modules/mock-chronik-client'); +const { + MockChronikClient, +} = require('../../../modules/mock-chronik-client/dist'); const NodeCache = require('node-cache'); describe('alias-server main.js', async function () { @@ -68,17 +70,11 @@ }; // Tell mockedChronik what response we expect - mockedChronik.setMock('blockchainInfo', { - input: null, - output: mockBlockchaininfoResponse, - }); + mockedChronik.setBlockchainInfo(mockBlockchaininfoResponse); // Mock chronik block call for a finalized chaintip - mockedChronik.setMock('block', { - input: mockBlockchaininfoResponse.tipHash, - output: { - blockInfo: { isFinal: true }, - }, + mockedChronik.setBlock(mockBlockchaininfoResponse.tipHash, { + blockInfo: { isFinal: true }, }); // Add tx history to mockedChronik @@ -87,9 +83,8 @@ aliasConstants.registrationAddress, true, ); - mockedChronik.setScript(type, hash); // Set the mock tx history - mockedChronik.setTxHistory(type, hash, generated.txHistory); + mockedChronik.setTxHistoryByScript(type, hash, generated.txHistory); // Define params const chronik = mockedChronik; @@ -107,7 +102,7 @@ returnMocks, ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual(result.aliasWebsocket.waitForOpenCalled, true); // Check that startup was called assert.deepEqual( result.appStartup, diff --git a/apps/ecash-herald/src/main.ts b/apps/ecash-herald/src/main.ts --- a/apps/ecash-herald/src/main.ts +++ b/apps/ecash-herald/src/main.ts @@ -25,7 +25,7 @@ }); // Initialize websocket connection try { - await initializeWebsocket( + return await initializeWebsocket( chronik, telegramBot, telegramChannelId, diff --git a/apps/ecash-herald/test/chronik.test.ts b/apps/ecash-herald/test/chronik.test.ts --- a/apps/ecash-herald/test/chronik.test.ts +++ b/apps/ecash-herald/test/chronik.test.ts @@ -3,7 +3,13 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. import assert from 'assert'; -import { GenesisInfo } from 'chronik-client'; +import { + ChronikClient, + GenesisInfo, + TokenInfo, + Tx, + Block, +} from 'chronik-client'; import { MockChronikClient } from '../../../modules/mock-chronik-client'; import { getTokenInfoMap, @@ -29,14 +35,11 @@ // and build expected result const expectedTokenInfoMap: TokenInfoMap = new Map(); mockTokenCalls.forEach((tokenInfo, tokenId) => { - mockedChronik.setMock('token', { - input: tokenId, - output: tokenInfo, - }); + mockedChronik.setToken(tokenId, tokenInfo); expectedTokenInfoMap.set(tokenId, tokenInfo.genesisInfo); }); const tokenInfoMap = await getTokenInfoMap( - mockedChronik, + mockedChronik as unknown as ChronikClient, new Set([alitaTokenId, bearNipTokenId, powTokenId]), ); @@ -52,15 +55,19 @@ // Create a set of only one token id const tokenIdSet: Set<string> = new Set([alitaTokenId]); - mockedChronik.setMock('token', { - input: alitaTokenId, - output: mockTokenCalls.get(alitaTokenId), - }); + mockedChronik.setToken( + alitaTokenId, + mockTokenCalls.get(alitaTokenId) as TokenInfo, + ); + expectedTokenInfoMap.set( alitaTokenId, mockTokenCalls.get(alitaTokenId)!.genesisInfo as GenesisInfo, ); - const tokenInfoMap = await getTokenInfoMap(mockedChronik, tokenIdSet); + const tokenInfoMap = await getTokenInfoMap( + mockedChronik as unknown as ChronikClient, + tokenIdSet, + ); assert.deepEqual(tokenInfoMap, expectedTokenInfoMap); }); @@ -71,20 +78,17 @@ const tokenIdSet = new Set([alitaTokenId, bearNipTokenId, powTokenId]); // Tell mockedChronik what responses we expect // Include one error response - mockedChronik.setMock('tx', { - input: alitaTokenId, - output: mockTxCalls.get(alitaTokenId), - }); - mockedChronik.setMock('tx', { - input: bearNipTokenId, - output: mockTxCalls.get(bearNipTokenId), - }); - mockedChronik.setMock('tx', { - input: powTokenId, - output: new Error('some error'), - }); + mockedChronik.setTx(alitaTokenId, mockTxCalls.get(alitaTokenId) as Tx); + mockedChronik.setTx( + bearNipTokenId, + mockTxCalls.get(bearNipTokenId) as Tx, + ); + mockedChronik.setTx(powTokenId, mockTxCalls.get(powTokenId) as Tx); - const tokenInfoMap = await getTokenInfoMap(mockedChronik, tokenIdSet); + const tokenInfoMap = await getTokenInfoMap( + mockedChronik as unknown as ChronikClient, + tokenIdSet, + ); assert.strictEqual(tokenInfoMap, false); }); @@ -95,17 +99,11 @@ const setWithNonToken = new Set([alitaTokenId, swapTxid]); // Tell mockedChronik what responses we expect // Include one error response - mockedChronik.setMock('tx', { - input: alitaTokenId, - output: mockTxCalls.get(alitaTokenId), - }); - mockedChronik.setMock('tx', { - input: swapTxid, - output: mockTxCalls.get(swapTxid), - }); + mockedChronik.setTx(alitaTokenId, mockTxCalls.get(alitaTokenId) as Tx); + mockedChronik.setTx(swapTxid, mockTxCalls.get(swapTxid) as Tx); const tokenInfoMap = await getTokenInfoMap( - mockedChronik, + mockedChronik as unknown as ChronikClient, setWithNonToken, ); @@ -122,8 +120,11 @@ ]; // Initialize chronik mock const mockedChronik = new MockChronikClient(); - mockedChronik.setTxHistoryByBlock(MOCK_HEIGHT, MOCK_TXS); - const txsInBlock = await getAllBlockTxs(mockedChronik, MOCK_HEIGHT); + mockedChronik.setTxHistoryByBlock(MOCK_HEIGHT, MOCK_TXS as Tx[]); + const txsInBlock = await getAllBlockTxs( + mockedChronik as unknown as ChronikClient, + MOCK_HEIGHT, + ); assert.deepEqual(txsInBlock, MOCK_TXS); }); it('getAllBlockTxs can get all block txs if a block has more than one page of txs', async function () { @@ -142,9 +143,13 @@ ]; // Initialize chronik mock const mockedChronik = new MockChronikClient(); - mockedChronik.setTxHistoryByBlock(MOCK_HEIGHT, MOCK_TXS); + mockedChronik.setTxHistoryByBlock(MOCK_HEIGHT, MOCK_TXS as Tx[]); // Call with pageSize smaller than tx size - const txsInBlock = await getAllBlockTxs(mockedChronik, MOCK_HEIGHT, 2); + const txsInBlock = await getAllBlockTxs( + mockedChronik as unknown as ChronikClient, + MOCK_HEIGHT, + 2, + ); assert.deepEqual(txsInBlock, MOCK_TXS); }); it('getBlocksAgoFromChaintipByTimestamp will get start and end blockheights for a given timestamp and window if we have fewer than expected blocks in that window', async function () { @@ -153,8 +158,9 @@ // Mock the chaintip const mockChaintip = 800000; - mockedChronik.setMock('blockchainInfo', { - output: { tipHeight: mockChaintip }, + mockedChronik.setBlockchainInfo({ + tipHeight: mockChaintip, + tipHash: 'hash', }); // Arbitrary timestamp to test @@ -169,26 +175,23 @@ mockChaintip - secondsAgo / SECONDS_PER_BLOCK; // Guessed block is older than secondsAgo - mockedChronik.setMock('block', { - input: guessedBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo - 1 } }, - }); + mockedChronik.setBlock(guessedBlockheight, { + blockInfo: { timestamp: now - secondsAgo - 1 }, + } as Block); // Set 2 newer blocks // So this one, at guessedBlockheight + 1, is in the window const expectedStartBlockheight = guessedBlockheight + 1; - mockedChronik.setMock('block', { - input: expectedStartBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo + 2 } }, - }); - mockedChronik.setMock('block', { - input: guessedBlockheight + 2, - output: { blockInfo: { timestamp: now - secondsAgo + 3 } }, - }); + mockedChronik.setBlock(expectedStartBlockheight, { + blockInfo: { timestamp: now - secondsAgo + 2 }, + } as Block); + mockedChronik.setBlock(guessedBlockheight + 2, { + blockInfo: { timestamp: now - secondsAgo + 3 }, + } as Block); assert.deepEqual( await getBlocksAgoFromChaintipByTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, now, secondsAgo, ), @@ -204,8 +207,9 @@ // Mock the chaintip const mockChaintip = 800000; - mockedChronik.setMock('blockchainInfo', { - output: { tipHeight: mockChaintip }, + mockedChronik.setBlockchainInfo({ + tipHeight: mockChaintip, + tipHash: 'hash', }); // Arbitrary timestamp to test @@ -220,26 +224,23 @@ mockChaintip - secondsAgo / SECONDS_PER_BLOCK; // Guessed block is NEWER than secondsAgo - mockedChronik.setMock('block', { - input: guessedBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo + 5 } }, - }); + mockedChronik.setBlock(guessedBlockheight, { + blockInfo: { timestamp: now - secondsAgo + 5 }, + } as Block); // Set 3 older blocks, with 1 still in the window const expectedStartBlockheight = guessedBlockheight - 1; - mockedChronik.setMock('block', { - input: expectedStartBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo + 4 } }, - }); + mockedChronik.setBlock(expectedStartBlockheight, { + blockInfo: { timestamp: now - secondsAgo + 4 }, + } as Block); // Since this block is out of the window, we expect the start height to be proceeding block - mockedChronik.setMock('block', { - input: guessedBlockheight - 2, - output: { blockInfo: { timestamp: now - secondsAgo - 3 } }, - }); + mockedChronik.setBlock(guessedBlockheight - 2, { + blockInfo: { timestamp: now - secondsAgo - 3 }, + } as Block); assert.deepEqual( await getBlocksAgoFromChaintipByTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, now, secondsAgo, ), @@ -255,8 +256,9 @@ // Mock the chaintip const mockChaintip = 800000; - mockedChronik.setMock('blockchainInfo', { - output: { tipHeight: mockChaintip }, + mockedChronik.setBlockchainInfo({ + tipHeight: mockChaintip, + tipHash: 'hash', }); // Arbitrary timestamp to test @@ -271,20 +273,18 @@ mockChaintip - secondsAgo / SECONDS_PER_BLOCK; // Guessed block is exactly secondsAgo - mockedChronik.setMock('block', { - input: guessedBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo } }, - }); + mockedChronik.setBlock(guessedBlockheight, { + blockInfo: { timestamp: now - secondsAgo }, + } as Block); // Set 1 older block - mockedChronik.setMock('block', { - input: guessedBlockheight - 1, - output: { blockInfo: { timestamp: now - secondsAgo - 1 } }, - }); + mockedChronik.setBlock(guessedBlockheight - 1, { + blockInfo: { timestamp: now - secondsAgo - 1 }, + } as Block); assert.deepEqual( await getBlocksAgoFromChaintipByTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, now, secondsAgo, ), @@ -300,8 +300,9 @@ // Mock the chaintip const mockChaintip = 800000; - mockedChronik.setMock('blockchainInfo', { - output: { tipHeight: mockChaintip }, + mockedChronik.setBlockchainInfo({ + tipHeight: mockChaintip, + tipHash: 'hash', }); // Arbitrary timestamp to test @@ -316,23 +317,21 @@ mockChaintip - secondsAgo / SECONDS_PER_BLOCK; // Guessed block is older than secondsAgo - mockedChronik.setMock('block', { - input: guessedBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo - 1 } }, - }); + mockedChronik.setBlock(guessedBlockheight, { + blockInfo: { timestamp: now - secondsAgo - 1 }, + } as Block); // Set 100 newer blocks, all of them still outside the window for (let i = 0; i < 200; i += 1) { - mockedChronik.setMock('block', { - input: guessedBlockheight + 1 + i, - output: { blockInfo: { timestamp: now - secondsAgo - 1 } }, - }); + mockedChronik.setBlock(guessedBlockheight + 1 + i, { + blockInfo: { timestamp: now - secondsAgo - 1 }, + } as Block); } await assert.rejects( async () => { await getBlocksAgoFromChaintipByTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, now, secondsAgo, ); @@ -349,8 +348,9 @@ // Mock the chaintip const mockChaintip = 800000; - mockedChronik.setMock('blockchainInfo', { - output: { tipHeight: mockChaintip }, + mockedChronik.setBlockchainInfo({ + tipHeight: mockChaintip, + tipHash: 'hash', }); // Arbitrary timestamp to test @@ -365,23 +365,21 @@ mockChaintip - secondsAgo / SECONDS_PER_BLOCK; // Guessed block is newer than secondsAgo, i.e. within the window - mockedChronik.setMock('block', { - input: guessedBlockheight, - output: { blockInfo: { timestamp: now - secondsAgo + 5 } }, - }); + mockedChronik.setBlock(guessedBlockheight, { + blockInfo: { timestamp: now - secondsAgo + 5 }, + } as Block); // Set 200 older blocks, all of them still within the window for (let i = 0; i < 200; i += 1) { - mockedChronik.setMock('block', { - input: guessedBlockheight - 1 - i, - output: { blockInfo: { timestamp: now - secondsAgo + 5 } }, - }); + mockedChronik.setBlock(guessedBlockheight - 1 - i, { + blockInfo: { timestamp: now - secondsAgo + 5 }, + } as Block); } await assert.rejects( async () => { await getBlocksAgoFromChaintipByTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, now, secondsAgo, ); diff --git a/apps/ecash-herald/test/chronikWsHandler.test.ts b/apps/ecash-herald/test/chronikWsHandler.test.ts --- a/apps/ecash-herald/test/chronikWsHandler.test.ts +++ b/apps/ecash-herald/test/chronikWsHandler.test.ts @@ -13,12 +13,15 @@ initializeWebsocket, parseWebsocketMessage, } from '../src/chronikWsHandler'; -import { MockChronikClient } from '../../../modules/mock-chronik-client'; +import { + MockChronikClient, + MockWsEndpoint, +} from '../../../modules/mock-chronik-client'; import { MockTelegramBot, mockChannelId } from './mocks/telegramBotMock'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { caching, MemoryCache } from 'cache-manager'; -import { WsMsgClient } from 'chronik-client'; +import { ChronikClient, TokenInfo, WsMsgClient, Tx } from 'chronik-client'; import { StoredMock } from '../src/events'; const block: StoredMock = JSON.parse( JSON.stringify(unrevivedBlock), @@ -41,14 +44,17 @@ const channelId = mockChannelId; const result = await initializeWebsocket( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, memoryCache, ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual( + (result as unknown as MockWsEndpoint).waitForOpenCalled, + true, + ); // Confirm subscribed to blocks assert.deepEqual(result.subs.blocks, true); }); @@ -59,14 +65,17 @@ const channelId = mockChannelId; const result = await initializeWebsocket( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, memoryCache, ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual( + (result as unknown as MockWsEndpoint).waitForOpenCalled, + true, + ); // Confirm subscribed to blocks assert.deepEqual(result.subs.blocks, true); }); @@ -94,7 +103,7 @@ for (let i = 0; i < unsupportedWebsocketMsgs.length; i += 1) { const thisUnsupportedMsg = unsupportedWebsocketMsgs[i]; const result = await parseWebsocketMessage( - mockedChronik, + mockedChronik as unknown as ChronikClient, thisUnsupportedMsg as WsMsgClient, telegramBot, channelId, @@ -125,8 +134,11 @@ const { type, hash } = cashaddr.getTypeAndHashFromOutputScript(outputScript); const { utxos } = info; - mockedChronik.setScript(type, hash); - mockedChronik.setUtxos(type, hash, { outputScript, utxos }); + mockedChronik.setUtxosByScript( + type as 'p2pkh' | 'p2sh', + hash, + utxos, + ); }); // Tell mockedChronik what response we expect for chronik.tx @@ -137,12 +149,9 @@ // Instead of saving all the chronik responses as mocks, which would be very large // Just set them as mocks based on tokenInfoMap, which contains the info we need tokenIds.forEach(tokenId => { - mockedChronik.setMock('token', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setToken(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as TokenInfo); }); } const thisBlockExpectedMsgs = thisBlock.blockSummaryTgMsgs; @@ -182,7 +191,7 @@ ).reply(200, thisBlock.activeStakers); const result = await parseWebsocketMessage( - mockedChronik, + mockedChronik as unknown as ChronikClient, mockWsMsg as WsMsgClient, telegramBot, channelId, @@ -226,18 +235,12 @@ tokenIds.forEach(tokenId => { // If this is the first one, set an error response if (index === 0) { - mockedChronik.setMock('token', { - input: tokenId, - output: new Error('some error'), - }); + mockedChronik.setToken(tokenId, new Error('some error')); } else { index += 1; - mockedChronik.setMock('tx', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setTx(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as unknown as Tx); } }); } @@ -271,7 +274,7 @@ }); const result = await parseWebsocketMessage( - mockedChronik, + mockedChronik as unknown as ChronikClient, mockWsMsg as WsMsgClient, telegramBot, channelId, @@ -318,18 +321,12 @@ tokenIds.forEach(tokenId => { // If this is the first one, set an error response if (index === 0) { - mockedChronik.setMock('token', { - input: tokenId, - output: new Error('some error'), - }); + mockedChronik.setToken(tokenId, new Error('some error')); } else { index += 1; - mockedChronik.setMock('token', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setToken(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as unknown as TokenInfo); } }); } @@ -360,7 +357,7 @@ }); const result = await parseWebsocketMessage( - mockedChronik, + mockedChronik as unknown as ChronikClient, mockWsMsg as WsMsgClient, telegramBot, channelId, @@ -391,7 +388,7 @@ const channelId = mockChannelId; const result = await parseWebsocketMessage( - mockedChronik, + mockedChronik as unknown as ChronikClient, mockWsMsg as WsMsgClient, telegramBot, channelId, diff --git a/apps/ecash-herald/test/events.test.ts b/apps/ecash-herald/test/events.test.ts --- a/apps/ecash-herald/test/events.test.ts +++ b/apps/ecash-herald/test/events.test.ts @@ -20,6 +20,7 @@ import MockAdapter from 'axios-mock-adapter'; import { caching, MemoryCache } from 'cache-manager'; import FakeTimers, { InstalledClock } from '@sinonjs/fake-timers'; +import { ChronikClient, TokenInfo } from 'chronik-client'; const block: StoredMock = JSON.parse( JSON.stringify(unrevivedBlock), jsonReviver, @@ -61,8 +62,11 @@ const { type, hash } = cashaddr.getTypeAndHashFromOutputScript(outputScript); const { utxos } = info; - mockedChronik.setScript(type, hash); - mockedChronik.setUtxos(type, hash, { outputScript, utxos }); + mockedChronik.setUtxosByScript( + type as 'p2pkh' | 'p2sh', + hash, + utxos, + ); }); // Tell mockedChronik what response we expect for chronik.tx @@ -73,12 +77,9 @@ // Instead of saving all the chronik responses as mocks, which would be very large // Just set them as mocks based on tokenInfoMap, which contains the info we need tokenIds.forEach(tokenId => { - mockedChronik.setMock('token', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setToken(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as TokenInfo); }); } @@ -104,7 +105,7 @@ ).reply(200, thisBlock.activeStakers); const result = await handleBlockFinalized( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, thisBlock.parsedBlock.hash, @@ -152,18 +153,12 @@ tokenIds.forEach(tokenId => { // If this is the first one, set an error response if (index === 0) { - mockedChronik.setMock('token', { - input: tokenId, - output: new Error('some error'), - }); + mockedChronik.setToken(tokenId, new Error('some error')); } else { index += 1; - mockedChronik.setMock('token', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setToken(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as TokenInfo); } }); } @@ -182,7 +177,7 @@ mock.onGet(getCoingeckoApiUrl(config)).reply(500, { error: 'error' }); const result = await handleBlockFinalized( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, thisBlock.parsedBlock.hash, @@ -223,7 +218,7 @@ const channelId = mockChannelId; const result = await handleBlockFinalized( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, thisBlock.parsedBlock.hash, @@ -274,18 +269,12 @@ tokenIds.forEach(tokenId => { // If this is the first one, set an error response if (index === 0) { - mockedChronik.setMock('token', { - input: tokenId, - output: new Error('some error'), - }); + mockedChronik.setToken(tokenId, new Error('some error')); } else { index += 1; - mockedChronik.setMock('token', { - input: tokenId, - output: { - genesisInfo: tokenInfoMap.get(tokenId), - }, - }); + mockedChronik.setToken(tokenId, { + genesisInfo: tokenInfoMap.get(tokenId), + } as TokenInfo); } }); } @@ -298,7 +287,7 @@ const channelId = mockChannelId; const result = await handleBlockFinalized( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, thisBlock.parsedBlock.hash, @@ -319,7 +308,7 @@ const channelId = mockChannelId; const result = await handleBlockInvalidated( - mockedChronik, + mockedChronik as unknown as ChronikClient, telegramBot, channelId, thisBlock.blockTxs[0].block!.hash, diff --git a/apps/ecash-herald/test/fixtures/invalidatedBlocks.ts b/apps/ecash-herald/test/fixtures/invalidatedBlocks.ts --- a/apps/ecash-herald/test/fixtures/invalidatedBlocks.ts +++ b/apps/ecash-herald/test/fixtures/invalidatedBlocks.ts @@ -149,7 +149,8 @@ scriptHex: '76a914b03bb6f8567bade53cc3a716e0414c1082a8530088ac', }, mockedBlock: { - 865428: { + height: 865428, + block: { blockInfo: { hash: '00000000000000000692216bd4f235fc2cd98872640ba6a3bec0130cbfe59a14', }, diff --git a/apps/ecash-herald/test/main.test.ts b/apps/ecash-herald/test/main.test.ts --- a/apps/ecash-herald/test/main.test.ts +++ b/apps/ecash-herald/test/main.test.ts @@ -4,8 +4,12 @@ import assert from 'assert'; import { main } from '../src/main'; -import { MockChronikClient } from '../../../modules/mock-chronik-client'; +import { + MockChronikClient, + MockWsEndpoint, +} from '../../../modules/mock-chronik-client'; import { MockTelegramBot, mockChannelId } from './mocks/telegramBotMock'; +import { ChronikClient } from 'chronik-client'; describe('ecash-herald main.js', async function () { it('main() starts the app on successful websocket connection', async function () { @@ -13,9 +17,13 @@ const mockedChronik = new MockChronikClient(); const channelId = mockChannelId; - await main(mockedChronik, new MockTelegramBot(), channelId); + const ws = await main( + mockedChronik as unknown as ChronikClient, + new MockTelegramBot(), + channelId, + ); // Confirm websocket opened - assert.strictEqual(mockedChronik.wsWaitForOpenCalled, true); + assert.strictEqual((ws as MockWsEndpoint).waitForOpenCalled, true); }); }); diff --git a/apps/ecash-herald/test/parse.test.ts b/apps/ecash-herald/test/parse.test.ts --- a/apps/ecash-herald/test/parse.test.ts +++ b/apps/ecash-herald/test/parse.test.ts @@ -13,7 +13,7 @@ import memoFixtures from './mocks/memo'; import { consumeNextPush } from 'ecash-script'; import { MockChronikClient } from '../../../modules/mock-chronik-client'; -import { TxOutput } from 'chronik-client'; +import { Block, ChronikClient, TxOutput } from 'chronik-client'; import { caching } from 'cache-manager'; import { StoredMock } from '../src/events'; import { @@ -338,7 +338,12 @@ } = invalidatedBlocksTestFixtures[i]; const mockedChronik = new MockChronikClient(); - mockedChronik.mockedResponses.block = mockedBlock; + if (typeof mockedBlock.height !== 'undefined') { + mockedChronik.setBlock( + mockedBlock.height, + mockedBlock.block as Block, + ); + } const testMemoryCache = await caching('memory', { max: 100, @@ -348,7 +353,7 @@ assert.strictEqual( await guessRejectReason( - mockedChronik, + mockedChronik as unknown as ChronikClient, height, coinbaseData, testMemoryCache, diff --git a/apps/token-server/src/chronik/clientHandler.test.ts b/apps/token-server/src/chronik/clientHandler.test.ts --- a/apps/token-server/src/chronik/clientHandler.test.ts +++ b/apps/token-server/src/chronik/clientHandler.test.ts @@ -6,6 +6,7 @@ import { MockChronikClient } from '../../../../modules/mock-chronik-client'; import { getHistoryAfterTimestamp } from '../../src/chronik/clientHandler'; import vectors from '../../test/vectors'; +import { ChronikClient } from 'chronik-client'; describe('chronik/clientHandler.js', function () { describe('We can get all tx history from after a given timestamp', function () { @@ -23,12 +24,11 @@ // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(address); mockedChronik.setTxHistoryByAddress(address, mocks.history); it(description, async function () { assert.deepEqual( await getHistoryAfterTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, address, timestamp, pageSize, @@ -44,13 +44,12 @@ // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(address); mockedChronik.setTxHistoryByAddress(address, mocks.history); it(description, async function () { await assert.rejects( getHistoryAfterTimestamp( - mockedChronik, + mockedChronik as unknown as ChronikClient, address, timestamp, pageSize, diff --git a/apps/token-server/src/routes.test.ts b/apps/token-server/src/routes.test.ts --- a/apps/token-server/src/routes.test.ts +++ b/apps/token-server/src/routes.test.ts @@ -25,6 +25,7 @@ import { initializeDb, initialBlacklist } from '../src/db'; import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; +import { ChronikClient, ScriptUtxo, Tx } from 'chronik-client'; // Clone initialBlacklist before initializing the database // initializeDb(initialBlacklist) will modify the entries by adding an "_id" key @@ -74,7 +75,6 @@ // Seen ~ 2x before the amount of time required const eligibleTimeFirstSeen = Math.ceil(Date.now() / 1000) - 2 * config.eligibilityResetSeconds; - mockedChronikClient.setAddress(ELIGIBLE_ADDRESS); mockedChronikClient.setTxHistoryByAddress(ELIGIBLE_ADDRESS, [ { timeFirstSeen: eligibleTimeFirstSeen, @@ -85,39 +85,32 @@ token: { tokenId: config.rewardsTokenId }, }, ], - }, + } as Tx, ]); - mockedChronikClient.setAddress(SERVER_WALLET_ADDRESS); - mockedChronikClient.setUtxosByAddress(SERVER_WALLET_ADDRESS, { - outputScript: SERVER_WALLET_OUTPUTSCRIPT, - utxos: [ - { ...MOCK_SCRIPT_UTXO, value: 10000 }, - { - ...MOCK_SPENDABLE_TOKEN_UTXO, - outpoint: { ...MOCK_OUTPOINT, outIdx: 1 }, - token: { - ...MOCK_UTXO_TOKEN, - tokenId: config.rewardsTokenId, - // Note, can change this to '10' or something less than config.rewardAmountTokenSats - // to test behavior of server if it is out of tokens - // Bad ROI on adding this test outright as we need lots of scripting - // to overcome the need for multiple mocked server wallets - amount: config.rewardAmountTokenSats, - }, + mockedChronikClient.setUtxosByAddress(SERVER_WALLET_ADDRESS, [ + { ...MOCK_SCRIPT_UTXO, value: 10000 }, + { + ...MOCK_SPENDABLE_TOKEN_UTXO, + outpoint: { ...MOCK_OUTPOINT, outIdx: 1 }, + token: { + ...MOCK_UTXO_TOKEN, + tokenId: config.rewardsTokenId, + // Note, can change this to '10' or something less than config.rewardAmountTokenSats + // to test behavior of server if it is out of tokens + // Bad ROI on adding this test outright as we need lots of scripting + // to overcome the need for multiple mocked server wallets + amount: config.rewardAmountTokenSats, }, - ], - }); - mockedChronikClient.setMock('broadcastTx', { - input: '02000000021111111111111111111111111111111111111111111111111111111111111111010000006441aa58606dc2133b1547da04323797794c8ae8a245518c82b6a360db52f9451b33b301eeb18c5851fd98989a7c24b384bfb49c18e37d1ffdf4e6bc42c30575913041210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff111111111111111111111111111111111111111111111111111111111111111100000000644168bf907b93ffc6f1dad8378ca5de1a35e4b3d3fae7f151fed92eabffa301ba01dce9d79108e4a4374414f5ac7364d99ef5ff506ef5a69cc58e91e4871e4f27f541210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff030000000000000000376a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000271022020000000000001976a9146ffbe7c7d7bd01295eb1e371de9550339bdcf9fd88ac68250000000000001976a91476fb100532b1fe23b26930e7001dff7989d2db5588ac00000000', - output: { - txid: '1b3cb86a06c64afdbad89ac3660ee724cbb8a5a1b099763b993d63b1285bb404', }, - }); + ] as ScriptUtxo[]); + mockedChronikClient.setBroadcastTx( + '02000000021111111111111111111111111111111111111111111111111111111111111111010000006441aa58606dc2133b1547da04323797794c8ae8a245518c82b6a360db52f9451b33b301eeb18c5851fd98989a7c24b384bfb49c18e37d1ffdf4e6bc42c30575913041210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff111111111111111111111111111111111111111111111111111111111111111100000000644168bf907b93ffc6f1dad8378ca5de1a35e4b3d3fae7f151fed92eabffa301ba01dce9d79108e4a4374414f5ac7364d99ef5ff506ef5a69cc58e91e4871e4f27f541210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff030000000000000000376a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000271022020000000000001976a9146ffbe7c7d7bd01295eb1e371de9550339bdcf9fd88ac68250000000000001976a91476fb100532b1fe23b26930e7001dff7989d2db5588ac00000000', + '1b3cb86a06c64afdbad89ac3660ee724cbb8a5a1b099763b993d63b1285bb404', + ); // Set an ineligible mock // Seen just now const ineligibleTimeFirstSeen = Math.ceil(Date.now() / 1000); - mockedChronikClient.setAddress(INELIGIBLE_ADDRESS); mockedChronikClient.setTxHistoryByAddress(INELIGIBLE_ADDRESS, [ { timeFirstSeen: ineligibleTimeFirstSeen, @@ -128,10 +121,9 @@ token: { tokenId: config.rewardsTokenId }, }, ], - }, + } as Tx, ]); // Mock chronik throwing an error - mockedChronikClient.setAddress(ERROR_ADDRESS); mockedChronikClient.setTxHistoryByAddress( ERROR_ADDRESS, new Error('some chronik error'), @@ -140,24 +132,22 @@ // Address with no tx history // i.e. eligible for an XEC airdrop const NEW_ADDRESS = 'ecash:qrfkcnzdm0dvkrc20dhcf7qv23vt736ynuujzxnzs6'; - mockedChronikClient.setAddress(NEW_ADDRESS); mockedChronikClient.setTxHistoryByAddress(NEW_ADDRESS, []); // Address with tx history // i.e. not eligible for an XEC airdrop const USED_ADDRESS = 'ecash:qrplfw9x5hrdnra3t42s3543gh3vtg8xgyr4t4lrun'; - mockedChronikClient.setAddress(USED_ADDRESS); - mockedChronikClient.setTxHistoryByAddress(USED_ADDRESS, [{ isTx: true }]); + mockedChronikClient.setTxHistoryByAddress(USED_ADDRESS, [ + { isTx: true }, + ] as unknown as Tx[]); // Mock an XEC airdrop tx const expectedXecAirdropTxid = 'd19c496e82bd160c841968ec0d2b61bf64cb884b002835649594cd973967d33b'; - mockedChronikClient.setMock('broadcastTx', { - input: '02000000011111111111111111111111111111111111111111111111111111111111111111000000006441d51a04ca0cba7e791ceb0d39f19b45162756087e7058cf5dec770cbcabbc89598b5b6f966a3609b01a34b1e5b6853c46f843bd8b3507c0dbd6acc4329182b88841210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff0268100000000000001976a914d36c4c4ddbdacb0f0a7b6f84f80c5458bf47449f88accd150000000000001976a91476fb100532b1fe23b26930e7001dff7989d2db5588ac00000000', - output: { - txid: expectedXecAirdropTxid, - }, - }); + mockedChronikClient.setBroadcastTx( + '02000000011111111111111111111111111111111111111111111111111111111111111111000000006441d51a04ca0cba7e791ceb0d39f19b45162756087e7058cf5dec770cbcabbc89598b5b6f966a3609b01a34b1e5b6853c46f843bd8b3507c0dbd6acc4329182b88841210228363bacbd9e52c1e515e715633fd2376d58671cda418e05685447a4a49b0645ffffffff0268100000000000001976a914d36c4c4ddbdacb0f0a7b6f84f80c5458bf47449f88accd150000000000001976a91476fb100532b1fe23b26930e7001dff7989d2db5588ac00000000', + expectedXecAirdropTxid, + ); // Mock a stub telegram bot const mockedTgBot = { sendPhoto: () => {} }; @@ -179,7 +169,7 @@ app = startExpressServer( TEST_PORT, testDb, - mockedChronikClient, + mockedChronikClient as unknown as ChronikClient, mockedTgBot as unknown as TelegramBot, fs, ecc, @@ -204,7 +194,7 @@ badDbApp = startExpressServer( TEST_PORT_BAD_DB, {} as unknown as Db, - mockedChronikClient, + mockedChronikClient as unknown as ChronikClient, mockedTgBot as unknown as TelegramBot, fs, ecc, diff --git a/apps/token-server/src/transactions.test.ts b/apps/token-server/src/transactions.test.ts --- a/apps/token-server/src/transactions.test.ts +++ b/apps/token-server/src/transactions.test.ts @@ -11,6 +11,7 @@ import { MockChronikClient } from '../../../modules/mock-chronik-client'; import vectors from '../test/vectors'; import { Ecc, initWasm } from 'ecash-lib'; +import { ChronikClient } from 'chronik-client'; describe('transactions.ts', function () { let ecc: Ecc; @@ -84,19 +85,12 @@ } = vector; // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); - mockedChronik.setUtxosByAddress(wallet.address, { - outputScript: 'outputScript', - utxos, - }); - mockedChronik.setMock('broadcastTx', { - input: returned.hex, - output: { txid: returned.response.txid }, - }); + mockedChronik.setUtxosByAddress(wallet.address, utxos); + mockedChronik.setBroadcastTx(returned.hex, returned.response.txid); it(description, async function () { assert.deepEqual( await sendReward( - mockedChronik, + mockedChronik as unknown as ChronikClient, ecc, wallet, tokenId, @@ -119,17 +113,11 @@ } = vector; // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); - mockedChronik.setUtxosByAddress( - wallet.address, - utxos instanceof Error - ? utxos - : { outputScript: 'outputScript', utxos }, - ); + mockedChronik.setUtxosByAddress(wallet.address, utxos); it(description, async function () { await assert.rejects( sendReward( - mockedChronik, + mockedChronik as unknown as ChronikClient, ecc, wallet, tokenId, @@ -154,19 +142,12 @@ } = vector; // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); - mockedChronik.setUtxosByAddress(wallet.address, { - outputScript: 'outputScript', - utxos, - }); - mockedChronik.setMock('broadcastTx', { - input: returned.hex, - output: { txid: returned.response.txid }, - }); + mockedChronik.setUtxosByAddress(wallet.address, utxos); + mockedChronik.setBroadcastTx(returned.hex, returned.response.txid); it(description, async function () { assert.deepEqual( await sendXecAirdrop( - mockedChronik, + mockedChronik as unknown as ChronikClient, ecc, wallet, xecAirdropAmountSats, @@ -187,17 +168,11 @@ } = vector; // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); - mockedChronik.setUtxosByAddress( - wallet.address, - utxos instanceof Error - ? utxos - : { outputScript: 'outputScript', utxos }, - ); + mockedChronik.setUtxosByAddress(wallet.address, utxos); it(description, async function () { await assert.rejects( sendXecAirdrop( - mockedChronik, + mockedChronik as unknown as ChronikClient, ecc, wallet, xecAirdropAmountSats, diff --git a/apps/token-server/src/wallet.test.ts b/apps/token-server/src/wallet.test.ts --- a/apps/token-server/src/wallet.test.ts +++ b/apps/token-server/src/wallet.test.ts @@ -6,6 +6,7 @@ import { getWalletFromSeed, syncWallet } from '../src/wallet'; import vectors from '../test/vectors'; import { MockChronikClient } from '../../../modules/mock-chronik-client'; +import { ChronikClient } from 'chronik-client'; describe('wallet.ts', function () { describe('We can generate an ecash address and its wif from a valid bip39 mnemonic', function () { @@ -30,15 +31,14 @@ // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); - mockedChronik.setUtxosByAddress(wallet.address, { - outputScript: 'outputScript', - utxos: mockUtxos, - }); + mockedChronik.setUtxosByAddress(wallet.address, mockUtxos); it(description, async function () { // We call syncWallet on wallet - await syncWallet(mockedChronik, wallet); + await syncWallet( + mockedChronik as unknown as ChronikClient, + wallet, + ); // The wallet object is now synced, we do not need to rely on it being returned from the function assert.deepEqual(wallet, returned); }); @@ -47,10 +47,15 @@ const { description, wallet, error } = vector; // Set mocks in chronik-client const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(wallet.address); mockedChronik.setUtxosByAddress(wallet.address, error); it(description, async function () { - await assert.rejects(syncWallet(mockedChronik, wallet), error); + await assert.rejects( + syncWallet( + mockedChronik as unknown as ChronikClient, + wallet, + ), + error, + ); }); }); }); diff --git a/apps/token-server/tsconfig.json b/apps/token-server/tsconfig.json --- a/apps/token-server/tsconfig.json +++ b/apps/token-server/tsconfig.json @@ -8,5 +8,5 @@ "strict": true, "alwaysStrict": true, "skipLibCheck": true - }, + } } diff --git a/cashtab/src/chronik/__tests__/index.test.js b/cashtab/src/chronik/__tests__/index.test.js --- a/cashtab/src/chronik/__tests__/index.test.js +++ b/cashtab/src/chronik/__tests__/index.test.js @@ -90,16 +90,10 @@ const mockedChronik = new MockChronikClient(); // Set mock for chronik.token(tokenId) - mockedChronik.setMock('token', { - input: tokenId, - output: tokenInfo, - }); + mockedChronik.setToken(tokenId, tokenInfo); // Set mock for chronik.tx(tokenId) - mockedChronik.setMock('tx', { - input: tokenId, - output: genesisTx, - }); + mockedChronik.setTx(tokenId, genesisTx); it(`getTokenGenesisInfo: ${description}`, async () => { expect( @@ -114,16 +108,10 @@ const mockedChronik = new MockChronikClient(); // Set mock for chronik.token(tokenId) - mockedChronik.setMock('token', { - input: tokenId, - output: tokenInfo, - }); + mockedChronik.setToken(tokenId, tokenInfo); // Set mock for chronik.tx(tokenId) - mockedChronik.setMock('tx', { - input: tokenId, - output: genesisTx, - }); + mockedChronik.setTx(tokenId, genesisTx); it(`getTokenGenesisInfo: ${description}`, async () => { await expect( @@ -139,16 +127,10 @@ for (const tokenId of tokenIds) { const { token, tx } = chronikTokenMocks[tokenId]; // Set mock for chronik.token(tokenId) - mockedChronik.setMock('token', { - input: tokenId, - output: token, - }); + mockedChronik.setToken(tokenId, token); // Set mock for chronik.tx(tokenId) - mockedChronik.setMock('tx', { - input: tokenId, - output: tx, - }); + mockedChronik.setTx(tokenId, tx); } // Initialize an empty token cache @@ -174,16 +156,10 @@ for (const tokenId of tokenIds) { const { token, tx } = chronikTokenMocks[tokenId]; // Set mock for chronik.token(tokenId) - mockedChronik.setMock('token', { - input: tokenId, - output: token, - }); + mockedChronik.setToken(tokenId, token); // Set mock for chronik.tx(tokenId) - mockedChronik.setMock('tx', { - input: tokenId, - output: tx, - }); + mockedChronik.setTx(tokenId, tx); } // Initialize an empty token cache @@ -247,16 +223,8 @@ // Set tx history for all paths const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(defaultAddress); - mockedChronik.setUtxosByAddress(defaultAddress, { - outputScript: 'string', - utxos: [{ value: 546 }], - }); - mockedChronik.setAddress(secondaryAddress); - mockedChronik.setUtxosByAddress(secondaryAddress, { - outputScript: 'string', - utxos: [{ value: 546 }], - }); + mockedChronik.setUtxosByAddress(defaultAddress, [{ value: 546 }]); + mockedChronik.setUtxosByAddress(secondaryAddress, [{ value: 546 }]); expect( await getUtxos(mockedChronik, mockTxHistoryWallet), ).toStrictEqual([ @@ -271,16 +239,10 @@ for (const tokenId of tokenIds) { const { token, tx } = tokensInHistory[tokenId]; // Set mock for chronik.token(tokenId) - mockedChronik.setMock('token', { - input: tokenId, - output: token, - }); + mockedChronik.setToken(tokenId, token); // Set mock for chronik.tx(tokenId) - mockedChronik.setMock('tx', { - input: tokenId, - output: tx, - }); + mockedChronik.setTx(tokenId, tx); } // Revive JSON wallet @@ -292,12 +254,10 @@ const secondaryAddress = mockTxHistoryWallet.paths.get(145).address; // Set tx history for all paths - mockedChronik.setAddress(defaultAddress); mockedChronik.setTxHistoryByAddress( defaultAddress, mockPath1899History, ); - mockedChronik.setAddress(secondaryAddress); mockedChronik.setTxHistoryByAddress( secondaryAddress, mockPath145History, @@ -325,10 +285,7 @@ const mockedChronik = new MockChronikClient(); for (const tokenId of tokenIds) { // Mock an error in getting cached token info - mockedChronik.setMock('token', { - input: tokenId, - output: new Error('Some chronik error'), - }); + mockedChronik.setToken(tokenId, new Error('Some chronik error')); } // Revive JSON wallet @@ -340,12 +297,10 @@ const secondaryAddress = mockTxHistoryWallet.paths.get(145).address; // Set tx history for all paths - mockedChronik.setAddress(defaultAddress); mockedChronik.setTxHistoryByAddress( defaultAddress, mockPath1899History, ); - mockedChronik.setAddress(secondaryAddress); mockedChronik.setTxHistoryByAddress( secondaryAddress, mockPath145History, @@ -375,7 +330,6 @@ const mockedChronik = new MockChronikClient(); const tokenId = '1111111111111111111111111111111111111111111111111111111111111111'; - mockedChronik.setTokenId(tokenId); mockedChronik.setTxHistoryByTokenId(tokenId, [ { txid: 'deadbeef' }, ]); @@ -388,7 +342,6 @@ const mockedChronik = new MockChronikClient(); const tokenId = '1111111111111111111111111111111111111111111111111111111111111111'; - mockedChronik.setTokenId(tokenId); mockedChronik.setTxHistoryByTokenId( tokenId, [ @@ -411,7 +364,6 @@ const mockedChronik = new MockChronikClient(); const tokenId = '1111111111111111111111111111111111111111111111111111111111111111'; - mockedChronik.setTokenId(tokenId); mockedChronik.setTxHistoryByTokenId(tokenId, []); expect( await getAllTxHistoryByTokenId(mockedChronik, tokenId), diff --git a/cashtab/src/components/Agora/Collection/index.test.js b/cashtab/src/components/Agora/Collection/index.test.js --- a/cashtab/src/components/Agora/Collection/index.test.js +++ b/cashtab/src/components/Agora/Collection/index.test.js @@ -152,14 +152,14 @@ heismanCollectionCacheMocks, lkCacheMocks, ]) { - mockedChronik.setMock('token', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.token, - }); - mockedChronik.setMock('tx', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.tx, - }); + mockedChronik.setToken( + tokenCacheMock.token.tokenId, + tokenCacheMock.token, + ); + mockedChronik.setTx( + tokenCacheMock.token.tokenId, + tokenCacheMock.tx, + ); } // Must include CashtabNotification to test notification @@ -239,14 +239,14 @@ heismanCollectionCacheMocks, lkCacheMocks, ]) { - mockedChronik.setMock('token', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.token, - }); - mockedChronik.setMock('tx', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.tx, - }); + mockedChronik.setToken( + tokenCacheMock.token.tokenId, + tokenCacheMock.token, + ); + mockedChronik.setTx( + tokenCacheMock.token.tokenId, + tokenCacheMock.tx, + ); } // Must include CashtabNotification to test notification @@ -326,11 +326,7 @@ '0200000002f7bb552354b6f5076eb2664a8bcbbedc87b42f2ebfcb1480ee0a9141bbae63590000000064418bcbcf63745390a2ccc2a64657dc269db9dabb0e37faf002959ee4b10c688ec944d169e3cab07ab284e2962f97036c864390dd6cd14abfec9064b11529a3221a41210233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afdffffffff404b7bf6dde0308d82d627850eb1a3a2fca61f3275be83b6d579c47ed2550ed301000000f5414687cc36c08199e2f3bb4f36c91d7c54000f764b7fe4503311dbcb3080e64555fb718d12ba26b434c8dcbf511f14ac27c141bb834a0fa475613dc70dee4504ac41004cb0634c6b0000000000000000406a04534c500001410453454e4420be095430a16a024134bea079f235bcd2f79425c42659f9346416f626671f371c08000000000000000008000000000000000100f2052a010000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac7c7eaa7801327f7701207f7588520144807c7ea86f7bbb7501c17e7c67210233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afd68abacffffffff030000000000000000376a04534c500001410453454e4420be095430a16a024134bea079f235bcd2f79425c42659f9346416f626671f371c08000000000000000122020000000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488ac67660600000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488ac00000000'; const mockCancelTxid = 'df0737a3f86e8761e1b00197935c49b8589e20320ced101d640b874f7cded2b2'; - - mockedChronik.setMock('broadcastTx', { - input: mockCancelHex, - output: { txid: mockCancelTxid }, - }); + mockedChronik.setBroadcastTx(mockCancelHex, mockCancelTxid); // Must include CashtabNotification to test notification render( @@ -417,11 +413,7 @@ '0200000002f327f712cf7e629089daa7e76aa6a22d695f09a8019cd6fce640f5d044d2114700000000644176b288e2343af4e8e2420d29aa16571eed88e05b30519f452eaddae4538f5ba2c59408cc58bd367458a8632e36dc7d969588040529c3e61b796467b4f3a6ab574121021e75febb8ae57a8805e80df93732ab7d5d8606377cb30c0f02444809cc085f39ffffffff404b7bf6dde0308d82d627850eb1a3a2fca61f3275be83b6d579c47ed2550ed301000000fd950121023c72addb4fdf09af94f0c94d7fe92a386a7e70cf8a1d85916386bb2535c7b1b140ea428c8709da0aa9a3f3c9e159347b63d813f4c821f8b33ceea43962ab616ef9fd663847058af843fb18e6837669dde335066ed5aacb4ef45882f50f81b371cf4c5a404b7bf6dde0308d82d627850eb1a3a2fca61f3275be83b6d579c47ed2550ed30100000001ac2202000000000000fffffffffc9d8ea3c199bf5bb3c08676d4c6aa244aa4f228b0df15847db7f0458f0031d300000000c10000002222020000000000001976a914f208ef75eb0dd778ea4540cbd966a830c7b94bb088ac514cb0634c6b0000000000000000406a04534c500001410453454e4420be095430a16a024134bea079f235bcd2f79425c42659f9346416f626671f371c08000000000000000008000000000000000100f2052a010000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac7c7eaa7801327f7701207f7588520144807c7ea86f7bbb7501c17e7c67210233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afd68abacffffffff030000000000000000406a04534c500001410453454e4420be095430a16a024134bea079f235bcd2f79425c42659f9346416f626671f371c08000000000000000008000000000000000100f2052a010000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac22020000000000001976a914f208ef75eb0dd778ea4540cbd966a830c7b94bb088ac00000000'; const mockBuyTxid = '031e3291025cf485ec707f9ada7cb6229cb5a23fbcc4fec9c3f6a937d2e52913'; - - mockedChronik.setMock('broadcastTx', { - input: mockBuyHex, - output: { txid: mockBuyTxid }, - }); + mockedChronik.setBroadcastTx(mockBuyHex, mockBuyTxid); // Need to juice the wallet with a big utxo as this NFT is $$$ const affordItUTxo = { diff --git a/cashtab/src/components/Agora/OrderBook/__tests__/index.test.js b/cashtab/src/components/Agora/OrderBook/__tests__/index.test.js --- a/cashtab/src/components/Agora/OrderBook/__tests__/index.test.js +++ b/cashtab/src/components/Agora/OrderBook/__tests__/index.test.js @@ -279,11 +279,7 @@ '0200000002f7bb552354b6f5076eb2664a8bcbbedc87b42f2ebfcb1480ee0a9141bbae63590000000064414e90dfcdd1508f599267d5b761db8268c164567032f6eb597677d010df4e67eb61e29721535f92070d3c77d7679d78a209122aabec6c7f8d536db072b7dda28241210233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afdffffffffbfd08cec4d74b7820cea750b36a0a69d88b6cec3c084caf29e9b866cd8999f6d01000000fdab010441475230075041525449414c4162790797e5a77ccb0326f5e85ad2ec334b17616a636bad4d21a9fa8ec73e6e249443ef7f598a513ee6023bf0f4090300e3f1f37e96c5ea39fe15db0f2f3a56b941004d58014c766a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb10800000000000000000001db4603000000000079150000000000008ec420000000000008b7023e0233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afd08b0caff7f00000000ab7b63817b6ea26976038ec420a2697603db46039700887d94527901377f75789263587e7803db4603965880bc007e7e68587e527903db4603965880bc007e7e825980bc7c7e01007e7b027815930279159657807e041976a914707501557f77a97e0288ac7e7e6b7d02220258800317a9147e024c7672587d807e7e7e01ab7e537901257f7702d6007f5c7f7701207f547f750408b7023e886b7ea97e01877e7c92647500687b8292697e6c6c7b7eaa88520144807c7ea86f7bbb7501c17e7c677501557f7768ad075041525449414c88044147523087ffffffff030000000000000000376a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000271022020000000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488acaf650600000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488ac00000000'; const cancelTxid = '256ffa0a5e18f7c546673ff6c49fb4d483fe2cbae3b1269bc1000c4c6d950fa9'; - - mockedChronik.setMock('broadcastTx', { - input: cancelHex, - output: { txid: cancelTxid }, - }); + mockedChronik.setBroadcastTx(cancelHex, cancelTxid); // Note we must include CashtabNotification to test toastify notification render( @@ -426,11 +422,7 @@ '593640fef02460656cf16385493523091338366a7688e9ce731f40c10000000384c420514d58014c766a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000000000019e17010000000000f70500000000000084c4200000000000ce731f40021e75febb8ae57a8805e80df93732ab7d5d8606377cb30c0f02444809cc085f3908a0a3ff7f00000000ab7b63817b6ea269760384c420a26976039e17019700887d94527901377f75789263587e78039e1701965880bc007e7e68587e5279039e1701965880bc007e7e825980bc7c7e01007e7b02f6059302f7059657807e041976a914707501557f77a97e0288ac7e7e6b7d02220258800317a9147e024c7672587d807e7e7e01ab7e537901257f7702d6007f5c7f7701207f547f7504ce731f40886b7ea97e01877e7c92647500687b8292697e6c6c7b7eaa88520144807c7ea86f7bbb7501c17e7c677501557f7768ad075041525449414c88044147523087fffffffff7bb552354b6f5076eb2664a8bcbbedc87b42f2ebfcb1480ee0a9141bbae6359000000006441ed5b343334ab7603062faac5469e7b8b1513cec8e8730c972f4759e4fed0ef9cbd0a50b944d7e8094192ba99fd5eea6e61f568ba12a6b542deca6eea77761d1841210233f09cd4dc3381162f09975f90866f085350a5ec890d7fba5f6739c9c0ac2afdffffffff050000000000000000496a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000000008000000000000751208000000000000001e007f0500000000001976a914f208ef75eb0dd778ea4540cbd966a830c7b94bb088ac220200000000000017a914211be508fb7608c0a3b3d7a36279894d0450e7378722020000000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488ac9de20000000000001976a91403b830e4b9dce347f3495431e1f9d1005f4b420488acce731f40'; const buyTxid = 'eb298e786a91676f5b88b45d31d3979d6a8f96771ed99a69f3fa1aa1306238b0'; - - mockedChronik.setMock('broadcastTx', { - input: buyHex, - output: { txid: buyTxid }, - }); + mockedChronik.setBroadcastTx(buyHex, buyTxid); // Note we must include CashtabNotification to test toastify notification render( diff --git a/cashtab/src/components/Agora/__tests__/index.test.js b/cashtab/src/components/Agora/__tests__/index.test.js --- a/cashtab/src/components/Agora/__tests__/index.test.js +++ b/cashtab/src/components/Agora/__tests__/index.test.js @@ -60,14 +60,14 @@ bullCacheMocks, scamCacheMocks, ]) { - mockedChronik.setMock('token', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.token, - }); - mockedChronik.setMock('tx', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.tx, - }); + mockedChronik.setToken( + tokenCacheMock.token.tokenId, + tokenCacheMock.token, + ); + mockedChronik.setTx( + tokenCacheMock.token.tokenId, + tokenCacheMock.tx, + ); } // Mock the fetch call to Cashtab's price API @@ -430,10 +430,7 @@ const cancelTxid = 'de8f638c5b11592825ff74f2ec59892f721bc1151486efe86d99a44bf05865bf'; - mockedChronik.setMock('broadcastTx', { - input: cancelHex, - output: { txid: cancelTxid }, - }); + mockedChronik.setBroadcastTx(cancelHex, cancelTxid); render( <CashtabTestWrapper @@ -722,10 +719,7 @@ const buyTxid = '6fbee4e0460e3730f000e2927d69d881b8a536b80fd43b839d32e34c3490ff00'; - mockedChronik.setMock('broadcastTx', { - input: buyHex, - output: { txid: buyTxid }, - }); + mockedChronik.setBroadcastTx(buyHex, buyTxid); render( <CashtabTestWrapper @@ -874,14 +868,14 @@ // Mock chronik calls used to build token cache to show // the user can load a page without having the token info cached for (const tokenCacheMock of [cachetCacheMocks, bullCacheMocks]) { - emptyWalletMockedChronik.setMock('token', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.token, - }); - emptyWalletMockedChronik.setMock('tx', { - input: tokenCacheMock.token.tokenId, - output: tokenCacheMock.tx, - }); + emptyWalletMockedChronik.setToken( + tokenCacheMock.token.tokenId, + tokenCacheMock.token, + ); + emptyWalletMockedChronik.setTx( + tokenCacheMock.token.tokenId, + tokenCacheMock.tx, + ); } render( diff --git a/cashtab/src/components/Airdrop/__tests__/Airdrop.test.js b/cashtab/src/components/Airdrop/__tests__/Airdrop.test.js --- a/cashtab/src/components/Airdrop/__tests__/Airdrop.test.js +++ b/cashtab/src/components/Airdrop/__tests__/Airdrop.test.js @@ -65,20 +65,16 @@ const airdropTokenId = '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e'; // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: airdropTokenId, - output: easterEggTokenChronikTokenDetails, - }); + mockedChronik.setToken( + airdropTokenId, + easterEggTokenChronikTokenDetails, + ); // Set tx mock so we can get its minting address - mockedChronik.setMock('tx', { - input: airdropTokenId, - output: easterEggTokenChronikGenesisTx, - }); + mockedChronik.setTx(airdropTokenId, easterEggTokenChronikGenesisTx); // Mock the chronik.tokenId(formData.tokenId).utxos(); call - mockedChronik.setTokenId(airdropTokenId); - mockedChronik.setUtxosByTokenId(airdropTokenId, tokenUtxos); + mockedChronik.setUtxosByTokenId(airdropTokenId, tokenUtxos.utxos); render(<CashtabTestWrapper chronik={mockedChronik} route="/airdrop" />); @@ -169,20 +165,16 @@ const airdropTokenId = 'bef614aac85c0c866f4d39e4d12a96851267d38d1bca5bdd6488bbd42e28b6b1'; // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: airdropTokenId, - output: decimalsTokenInfo, - }); + mockedChronik.setToken(airdropTokenId, decimalsTokenInfo); // Set tx mock so we can get its minting address - mockedChronik.setMock('tx', { - input: airdropTokenId, - output: decimalsTokenGenesis, - }); + mockedChronik.setTx(airdropTokenId, decimalsTokenGenesis); // Mock the chronik.tokenId(formData.tokenId).utxos(); call - mockedChronik.setTokenId(airdropTokenId); - mockedChronik.setUtxosByTokenId(airdropTokenId, tokenUtxosDecimals); + mockedChronik.setUtxosByTokenId( + airdropTokenId, + tokenUtxosDecimals.utxos, + ); render(<CashtabTestWrapper chronik={mockedChronik} route="/airdrop" />); diff --git a/cashtab/src/components/App/__tests__/App.test.js b/cashtab/src/components/App/__tests__/App.test.js --- a/cashtab/src/components/App/__tests__/App.test.js +++ b/cashtab/src/components/App/__tests__/App.test.js @@ -595,10 +595,10 @@ ); // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: EASTER_EGG_TOKENID, - output: easterEggTokenChronikTokenDetails, - }); + mockedChronik.setToken( + EASTER_EGG_TOKENID, + easterEggTokenChronikTokenDetails, + ); render(<CashtabTestWrapper ecc={ecc} chronik={mockedChronik} />); diff --git a/cashtab/src/components/App/fixtures/helpers.js b/cashtab/src/components/App/fixtures/helpers.js --- a/cashtab/src/components/App/fixtures/helpers.js +++ b/cashtab/src/components/App/fixtures/helpers.js @@ -171,62 +171,50 @@ ) => { // mock chronik endpoint returns const CASHTAB_TESTS_TIPHEIGHT = 800000; - chronikClient.setMock('blockchainInfo', { - output: apiError - ? new Error('Error fetching blockchainInfo') - : { tipHeight: CASHTAB_TESTS_TIPHEIGHT }, - }); - - // Mock scriptutxos to match context - chronikClient.setAddress(wallet.Path1899.cashAddress); - chronikClient.setUtxosByAddress( - wallet.Path1899.cashAddress, - apiError - ? new Error('Error fetching utxos') - : { - outputScript: `76a914${wallet.Path1899.hash160}88ac`, - utxos: wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), - }, - ); - - // We set legacy paths to contain no utxos - chronikClient.setAddress(wallet.Path145.cashAddress); - chronikClient.setUtxosByAddress( - wallet.Path145.cashAddress, - apiError - ? new Error('Error fetching utxos') - : { - outputScript: `76a914${wallet.Path145.hash160}88ac`, - utxos: [], - }, - ); - chronikClient.setAddress(wallet.Path245.cashAddress); - chronikClient.setUtxosByAddress( - wallet.Path245.cashAddress, - apiError - ? new Error('Error fetching utxos') - : { - outputScript: `76a914${wallet.Path245.hash160}88ac`, - utxos: [], - }, - ); - - // TX history mocks - chronikClient.setTxHistoryByAddress( - wallet.Path1899.cashAddress, - apiError - ? new Error('Error fetching history') - : wallet.state.parsedTxHistory, - ); - // We set legacy paths to contain no utxos - chronikClient.setTxHistoryByAddress( - wallet.Path145.cashAddress, - apiError ? new Error('Error fetching history') : [], - ); - chronikClient.setTxHistoryByAddress( - wallet.Path245.cashAddress, - apiError ? new Error('Error fetching history') : [], - ); + if (apiError) { + chronikClient.setBlockchainInfo( + new Error('Error fetching blockchainInfo'), + ); + chronikClient.setUtxosByAddress( + wallet.Path1899.cashAddress, + new Error('Error fetching utxos'), + ); + chronikClient.setTxHistoryByAddress( + wallet.Path1899.cashAddress, + new Error('Error fetching history'), + ); + chronikClient.setUtxosByAddress( + wallet.Path145.cashAddress, + new Error('Error fetching utxos'), + ); + chronikClient.setUtxosByAddress( + wallet.Path245.cashAddress, + new Error('Error fetching utxos'), + ); + // We set legacy paths to contain no utxos + chronikClient.setTxHistoryByAddress( + wallet.Path145.cashAddress, + new Error('Error fetching history'), + ); + chronikClient.setTxHistoryByAddress( + wallet.Path245.cashAddress, + new Error('Error fetching history'), + ); + } else { + chronikClient.setBlockchainInfo({ tipHeight: CASHTAB_TESTS_TIPHEIGHT }); + chronikClient.setUtxosByAddress( + wallet.Path1899.cashAddress, + wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), + ); + chronikClient.setTxHistoryByAddress( + wallet.Path1899.cashAddress, + wallet.state.parsedTxHistory, + ); + chronikClient.setUtxosByAddress(wallet.Path145.cashAddress, []); + chronikClient.setUtxosByAddress(wallet.Path245.cashAddress, []); + chronikClient.setTxHistoryByAddress(wallet.Path145.cashAddress, []); + chronikClient.setTxHistoryByAddress(wallet.Path245.cashAddress, []); + } }; /** @@ -243,11 +231,13 @@ ) => { // mock chronik endpoint returns const CASHTAB_TESTS_TIPHEIGHT = 800000; - chronikClient.setMock('blockchainInfo', { - output: apiError - ? new Error('Error fetching blockchainInfo') - : { tipHeight: CASHTAB_TESTS_TIPHEIGHT }, - }); + if (apiError) { + chronikClient.setBlockchainInfo( + new Error('Error fetching blockchainInfo'), + ); + } else { + chronikClient.setBlockchainInfo({ tipHeight: CASHTAB_TESTS_TIPHEIGHT }); + } // If you are mocking a legacy wallet to test a migration, return prepareMockedChronikCallsForLegacyWallet if (!('paths' in wallet)) { @@ -261,32 +251,31 @@ // Iterate over paths to create chronik mocks for (const path of wallet.paths) { // Mock scriptutxos to match context - chronikClient.setAddress(path.address); - chronikClient.setUtxosByAddress( - path.address, - apiError - ? new Error('Error fetching utxos') - : { - outputScript: `76a914${path.hash}88ac`, - utxos: - path.path === 1899 - ? wallet.state.nonSlpUtxos.concat( - wallet.state.slpUtxos, - ) - : [], - }, - ); - - // Mock tx history - chronikClient.setTxHistoryByAddress( - path.address, - apiError - ? new Error('Error fetching history') - : path.path === 1899 - ? wallet.state.parsedTxHistory - : // No tx history at legacy paths - [], - ); + if (apiError) { + chronikClient.setUtxosByAddress( + path.address, + new Error('Error fetching utxos'), + ); + chronikClient.setTxHistoryByAddress( + path.address, + new Error('Error fetching history'), + ); + } else { + if (path.path === 1899) { + chronikClient.setUtxosByAddress( + path.address, + wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), + ); + chronikClient.setTxHistoryByAddress( + path.address, + wallet.state.parsedTxHistory, + ); + } else { + // No history or utxos at legacy paths + chronikClient.setUtxosByAddress(path.address, []); + chronikClient.setTxHistoryByAddress(path.address, []); + } + } } }; @@ -304,18 +293,20 @@ ) => { // mock chronik endpoint returns const CASHTAB_TESTS_TIPHEIGHT = 800000; - chronikClient.setMock('blockchainInfo', { - output: apiError - ? new Error('Error fetching blockchainInfo') - : { tipHeight: CASHTAB_TESTS_TIPHEIGHT }, - }); - // Mock an avalanche-finalized block details - chronikClient.setMock('block', { - input: CASHTAB_TESTS_TIPHEIGHT, - output: apiError - ? new Error('Error fetching block') - : { blockInfo: { isFinal: true } }, - }); + if (apiError) { + chronikClient.setBlockchainInfo( + new Error('Error fetching blockchainInfo'), + ); + chronikClient.setBlock( + CASHTAB_TESTS_TIPHEIGHT, + new Error('Error fetching block'), + ); + } else { + chronikClient.setBlockchainInfo({ tipHeight: CASHTAB_TESTS_TIPHEIGHT }); + chronikClient.setBlock(CASHTAB_TESTS_TIPHEIGHT, { + blockInfo: { isFinal: true }, + }); + } // Mock token calls // This info is same shape for all wallets supported in these functions @@ -357,10 +348,8 @@ timestamp: 1678408305, }, }; - chronikClient.setMock('token', { - input: tokenId, - output: mockedTokenResponse, - }); + chronikClient.setToken(tokenId, mockedTokenResponse); + const mockedTxResponse = { txid: tokenId, version: 2, @@ -445,10 +434,7 @@ timestamp: 1678408305, }, }; - chronikClient.setMock('tx', { - input: tokenId, - output: mockedTxResponse, - }); + chronikClient.setTx(tokenId, mockedTxResponse); } // If you are mocking a legacy wallet to test a migration, return prepareMockedChronikCallsForLegacyWallet @@ -471,32 +457,30 @@ // Iterate over paths to create chronik mocks wallet.paths.forEach((pathInfo, path) => { // Mock scriptutxos to match context - chronikClient.setAddress(pathInfo.address); - chronikClient.setUtxosByAddress( - pathInfo.address, - apiError - ? new Error('Error fetching utxos') - : { - outputScript: `76a914${pathInfo.hash}88ac`, - utxos: - path === 1899 - ? wallet.state.nonSlpUtxos.concat( - wallet.state.slpUtxos, - ) - : [], - }, - ); - - // Mock tx history - chronikClient.setTxHistoryByAddress( - pathInfo.address, - apiError - ? new Error('Error fetching history') - : path === 1899 - ? wallet.state.parsedTxHistory - : // No tx history at legacy paths - [], - ); + if (apiError) { + chronikClient.setUtxosByAddress( + pathInfo.address, + new Error('Error fetching utxos'), + ); + chronikClient.setTxHistoryByAddress( + pathInfo.address, + new Error('Error fetching history'), + ); + } else { + if (path === 1899) { + chronikClient.setUtxosByAddress( + pathInfo.address, + wallet.state.nonSlpUtxos.concat(wallet.state.slpUtxos), + ); + chronikClient.setTxHistoryByAddress( + pathInfo.address, + wallet.state.parsedTxHistory, + ); + } else { + chronikClient.setUtxosByAddress(pathInfo.address, []); + chronikClient.setTxHistoryByAddress(pathInfo.address, []); + } + } }); }; diff --git a/cashtab/src/components/Configure/__tests__/Configure.test.js b/cashtab/src/components/Configure/__tests__/Configure.test.js --- a/cashtab/src/components/Configure/__tests__/Configure.test.js +++ b/cashtab/src/components/Configure/__tests__/Configure.test.js @@ -144,10 +144,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064416a14b2f97b4b24a409799b68a6da2d34ada9fa0f305eeffe11d9234cd8ee17dcb033de65840107dd52c35207fb2d2a88eadac270e582a8bc7cd66df4437800234121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff027c150000000000001976a9146ffbe7c7d7bd01295eb1e371de9550339bdcf9fd88acdb6c0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '5f334f32bec07b1029ae579460c704e33ba05b91e3bc2bba9ee215bc585cd6ab'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render(<CashtabTestWrapper chronik={mockedChronik} ecc={ecc} />); @@ -239,14 +236,14 @@ ); // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: appConfig.vipTokens.cachet.tokenId, - output: cachetTokenAndTx.token, - }); - mockedChronik.setMock('tx', { - input: appConfig.vipTokens.cachet.tokenId, - output: cachetTokenAndTx.tx, - }); + mockedChronik.setToken( + appConfig.vipTokens.cachet.tokenId, + cachetTokenAndTx.token, + ); + mockedChronik.setTx( + appConfig.vipTokens.cachet.tokenId, + cachetTokenAndTx.tx, + ); render(<CashtabTestWrapper chronik={mockedChronik} ecc={ecc} />); @@ -305,24 +302,21 @@ ); // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: appConfig.vipTokens.cachet.tokenId, - output: cachetTokenAndTx.token, - }); - mockedChronik.setMock('tx', { - input: appConfig.vipTokens.cachet.tokenId, - output: cachetTokenAndTx.tx, - }); + mockedChronik.setToken( + appConfig.vipTokens.cachet.tokenId, + cachetTokenAndTx.token, + ); + mockedChronik.setTx( + appConfig.vipTokens.cachet.tokenId, + cachetTokenAndTx.tx, + ); // Can verify in Electrum that this tx is sent at 1.0 sat/byte const hex = '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441a8ae2e6e418b09c8a189547c7412a551617d2f26e55ee5af787ef9ad3f583f6086995640fc06039a04e113dc3d18ce3c51b817f59d31dbb8193dcfa4b7a862664121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff027c150000000000001976a9146ffbe7c7d7bd01295eb1e371de9550339bdcf9fd88acb96d0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = 'c16de907537369994417459369faad6595842d569b7b4a9544288ac8a4c81dbb'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render(<CashtabTestWrapper chronik={mockedChronik} ecc={ecc} />); @@ -403,24 +397,21 @@ ); // Make sure the app can get this token's genesis info by calling a mock - mockedChronik.setMock('token', { - input: appConfig.vipTokens.grumpy.tokenId, - output: vipTokenChronikTokenMocks.token, - }); - mockedChronik.setMock('tx', { - input: appConfig.vipTokens.grumpy.tokenId, - output: vipTokenChronikTokenMocks.tx, - }); + mockedChronik.setToken( + appConfig.vipTokens.grumpy.tokenId, + vipTokenChronikTokenMocks.token, + ); + mockedChronik.setTx( + appConfig.vipTokens.grumpy.tokenId, + vipTokenChronikTokenMocks.tx, + ); // Can verify in Electrum that this tx is sent at 1.0 sat/byte const hex = '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441a8ae2e6e418b09c8a189547c7412a551617d2f26e55ee5af787ef9ad3f583f6086995640fc06039a04e113dc3d18ce3c51b817f59d31dbb8193dcfa4b7a862664121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff027c150000000000001976a9146ffbe7c7d7bd01295eb1e371de9550339bdcf9fd88acb96d0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = 'c16de907537369994417459369faad6595842d569b7b4a9544288ac8a4c81dbb'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Can verify in Electrum that this tx is sent at 1.0 sat/byte const tokenSendHex = @@ -428,10 +419,7 @@ const tokenSendTxid = 'a9981db09af60875966df3f47a80588d0975fec799c658b702b22633604904d1'; - mockedChronik.setMock('broadcastTx', { - input: tokenSendHex, - output: { txid: tokenSendTxid }, - }); + mockedChronik.setBroadcastTx(tokenSendHex, tokenSendTxid); render(<CashtabTestWrapper chronik={mockedChronik} ecc={ecc} />); diff --git a/cashtab/src/components/Etokens/__tests__/CreateTokenForm.test.js b/cashtab/src/components/Etokens/__tests__/CreateTokenForm.test.js --- a/cashtab/src/components/Etokens/__tests__/CreateTokenForm.test.js +++ b/cashtab/src/components/Etokens/__tests__/CreateTokenForm.test.js @@ -66,10 +66,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a2102000000644199e5a5dcfea45a68137f07bfe749195897767030687bd3f4b4dbcf2b2ddf2711af47b13f376523031b3c3c975a00e12b46d46f057fd5e144b79a95eee71479e84121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000466a04534c500001010747454e4553495303544b450a7465737420746f6b656e1768747470733a2f2f7777772e636173687461622e636f6d4c0001024c0008000000000393870022020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac977f0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '71626fb3bd4be7713096107af225eff0f9243c5374ca50fe3bf9a736e14b9f9c'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mockedChronik} @@ -161,26 +158,16 @@ ); // Mock the not-yet-created token's tokeninfo and utxo calls to test the redirect - mockedChronik.setMock('token', { - input: createdTokenId, - output: MOCK_CHRONIK_TOKEN_CALL, - }); - mockedChronik.setMock('tx', { - input: createdTokenId, - output: MOCK_CHRONIK_GENESIS_TX_CALL, - }); - mockedChronik.setTokenId(createdTokenId); - mockedChronik.setUtxosByTokenId(createdTokenId, { - utxos: [MOCK_UTXO_FOR_BALANCE], - }); + mockedChronik.setToken(createdTokenId, MOCK_CHRONIK_TOKEN_CALL); + mockedChronik.setTx(createdTokenId, MOCK_CHRONIK_GENESIS_TX_CALL); + mockedChronik.setUtxosByTokenId(createdTokenId, [ + MOCK_UTXO_FOR_BALANCE, + ]); // Add tx mock to mockedChronik const hex = '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441ff86eb97dad643075e75ed273334cee9aef1b938436dc350bcb48f73d129ce6a9d9ea40e749303e7bcbd27a082f1ee03080582f00f1ec80f202166bff431a0334121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000466a04534c500001010747454e4553495303544b450a7465737420746f6b656e1768747470733a2f2f7777772e636173687461622e636f6d4c000102010208000000000393870022020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac22020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac307d0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid: createdTokenId }, - }); + mockedChronik.setBroadcastTx(hex, createdTokenId); render( <CashtabTestWrapper chronik={mockedChronik} @@ -271,10 +258,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064415594de73e7f09dc4bd7622b136921d8b883c131559e9ba9212185fb5f7db1fe062715183484097a5f7cf71d75af3b9b3b2768f7e011550893376ef9ec150887b4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff0300000000000000006e6a04534c500001810747454e45534953033448432454686520466f75722048616c662d436f696e73206f66204a696e2d71756120283448432925656e2e77696b6970656469612e6f72672f77696b692f5461692d50616e5f286e6f76656c294c0001004c0008000000000000000422020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac467f0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '4517dc895499f2090ae04eeb28e2d2f0a0790baf99568f7e52436df45ca766c3'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Load component with create-nft-collection route render( @@ -373,26 +357,16 @@ ); // Mock the not-yet-created token's tokeninfo and utxo calls to test the redirect - mockedChronik.setMock('token', { - input: createdTokenId, - output: MOCK_CHRONIK_TOKEN_CALL, - }); - mockedChronik.setMock('tx', { - input: createdTokenId, - output: MOCK_CHRONIK_GENESIS_TX_CALL, - }); - mockedChronik.setTokenId(createdTokenId); - mockedChronik.setUtxosByTokenId(createdTokenId, { - utxos: [MOCK_UTXO_FOR_BALANCE], - }); + mockedChronik.setToken(createdTokenId, MOCK_CHRONIK_TOKEN_CALL); + mockedChronik.setTx(createdTokenId, MOCK_CHRONIK_GENESIS_TX_CALL); + mockedChronik.setUtxosByTokenId(createdTokenId, [ + MOCK_UTXO_FOR_BALANCE, + ]); // Add tx mock to mockedChronik const hex = '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064417055f05736401020a4eec59c8c9cb2e76bdbcfca5e2a9b1468e1dcf5ef5534febab436728463762b015f9564fa33cc870de0cfcafa7a906b663bc8ba58816c644121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000646a504c60534c5032000747454e4553495303544b450a7465737420746f6b656e1768747470733a2f2f7777772e636173687461622e636f6d0021031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02d02010087930300000122020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac22020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188acf47c0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid: createdTokenId }, - }); + mockedChronik.setBroadcastTx(hex, createdTokenId); render( <CashtabTestWrapper chronik={mockedChronik} diff --git a/cashtab/src/components/Etokens/__tests__/Token.test.js b/cashtab/src/components/Etokens/__tests__/Token.test.js --- a/cashtab/src/components/Etokens/__tests__/Token.test.js +++ b/cashtab/src/components/Etokens/__tests__/Token.test.js @@ -64,19 +64,12 @@ localforage, ); // Set chronik mocks required for cache preparation and supply calc - mockedChronik.setMock('token', { - input: slp1FixedBear.tokenId, - output: slp1FixedBear.token, - }); - mockedChronik.setMock('tx', { - input: slp1FixedBear.tokenId, - output: slp1FixedBear.tx, - }); - mockedChronik.setTokenId(slp1FixedBear.tokenId); - mockedChronik.setUtxosByTokenId(slp1FixedBear.tokenId, { - tokenId: slp1FixedBear.tokenId, - utxos: slp1FixedBear.utxos, - }); + mockedChronik.setToken(slp1FixedBear.tokenId, slp1FixedBear.token); + mockedChronik.setTx(slp1FixedBear.tokenId, slp1FixedBear.tx); + mockedChronik.setUtxosByTokenId( + slp1FixedBear.tokenId, + slp1FixedBear.utxos, + ); // Set up userEvent user = userEvent.setup(); @@ -588,10 +581,7 @@ const txid = '6de2d27d40bced679a8b8e55c85230ed8da0977c30ad31247fefc0b1eba0976e'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -640,10 +630,7 @@ const txid = 'f3023fd2265ed98438f5d4d01d31a1d94633b496e03d4aad5acd8da240e38736'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -794,29 +781,22 @@ localforage, ); // Set mock tokeninfo call - mintMockedChronik.setMock('token', { - input: slp1FixedCachet.tokenId, - output: slp1FixedCachet.token, - }); - mintMockedChronik.setMock('tx', { - input: slp1FixedCachet.tokenId, - output: slp1FixedCachet.tx, - }); - mockedChronik.setTokenId(slp1FixedCachet.tokenId); - mockedChronik.setUtxosByTokenId(slp1FixedCachet.tokenId, { - tokenId: slp1FixedCachet.tokenId, - utxos: slp1FixedCachet.utxos, - }); + mintMockedChronik.setToken( + slp1FixedCachet.tokenId, + slp1FixedCachet.token, + ); + mintMockedChronik.setTx(slp1FixedCachet.tokenId, slp1FixedCachet.tx); + mintMockedChronik.setUtxosByTokenId( + slp1FixedCachet.tokenId, + slp1FixedCachet.utxos, + ); const hex = '02000000028ec326590f3e42afae0e458995599c4c892af8e749efc7cc6bcfca8b0f2a5b4b020000006441672ba8ac8941cc69b6f49f80da73046e65a125376dc0311b5467d678350924d598d5750cd2c19dd8b42016cef9629969373336ce2eb50c1d741985a652449db44121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dfffffffffe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441dfb3546c5e588030696f1e4a1ef00d039743514be0304505415ad9de4cf4ea0b4e9d0fda1ba3869241825e269867f6a45251477057a68ba39883eb4d25008cd64121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000396a04534c50000101044d494e5420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1010208000000000000273122020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac22020000000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac517e0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '567114b4adbb5e8969a587ac58866c0ccf0c91ded1fd0d96d75f8cb7aeb6f33a'; - mintMockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mintMockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mintMockedChronik} @@ -860,19 +840,9 @@ it('For an uncached token with no balance, we show a spinner while loading the token info, then show an info screen and open agora offers', async () => { // Set mock tokeninfo call const CACHET_TOKENID = slp1FixedCachet.tokenId; - mockedChronik.setMock('token', { - input: CACHET_TOKENID, - output: slp1FixedCachet.token, - }); - mockedChronik.setMock('tx', { - input: CACHET_TOKENID, - output: slp1FixedCachet.tx, - }); - mockedChronik.setTokenId(CACHET_TOKENID); - mockedChronik.setUtxosByTokenId(CACHET_TOKENID, { - tokenId: slp1FixedCachet.tokenId, - utxos: slp1FixedCachet.utxos, - }); + mockedChronik.setToken(CACHET_TOKENID, slp1FixedCachet.token); + mockedChronik.setTx(CACHET_TOKENID, slp1FixedCachet.tx); + mockedChronik.setUtxosByTokenId(CACHET_TOKENID, slp1FixedCachet.utxos); render( <CashtabTestWrapper @@ -912,19 +882,12 @@ it('For an uncached token with no balance, we show a chronik query error if we are unable to fetch the token info', async () => { // Set mock tokeninfo call const CACHET_TOKENID = slp1FixedCachet.tokenId; - mockedChronik.setMock('token', { - input: CACHET_TOKENID, - output: new Error('some error'), - }); - mockedChronik.setMock('tx', { - input: CACHET_TOKENID, - output: new Error('some error'), - }); - mockedChronik.setTokenId(CACHET_TOKENID); - mockedChronik.setUtxosByTokenId(CACHET_TOKENID, { - tokenId: slp1FixedCachet.tokenId, - utxos: new Error('some error'), - }); + mockedChronik.setToken(CACHET_TOKENID, new Error('some error')); + mockedChronik.setTx(CACHET_TOKENID, new Error('some error')); + mockedChronik.setUtxosByTokenId( + CACHET_TOKENID, + new Error('some error'), + ); render( <CashtabTestWrapper diff --git a/cashtab/src/components/Etokens/__tests__/TokenActions.test.js b/cashtab/src/components/Etokens/__tests__/TokenActions.test.js --- a/cashtab/src/components/Etokens/__tests__/TokenActions.test.js +++ b/cashtab/src/components/Etokens/__tests__/TokenActions.test.js @@ -57,19 +57,9 @@ // Build chronik mocks that Cashtab would use to add token info to cache for (const tokenMock of supportedTokens) { - mockedChronik.setMock('token', { - input: tokenMock.tokenId, - output: tokenMock.token, - }); - mockedChronik.setMock('tx', { - input: tokenMock.tokenId, - output: tokenMock.tx, - }); - mockedChronik.setTokenId(tokenMock.tokenId); - mockedChronik.setUtxosByTokenId(tokenMock.tokenId, { - tokenId: tokenMock.tokenId, - utxos: tokenMock.utxos, - }); + mockedChronik.setToken(tokenMock.tokenId, tokenMock.token); + mockedChronik.setTx(tokenMock.tokenId, tokenMock.tx); + mockedChronik.setUtxosByTokenId(tokenMock.tokenId, tokenMock.utxos); // Set empty tx history to mock no existing NFTs mockedChronik.setTxHistoryByTokenId(tokenMock.tokenId, []); } @@ -225,22 +215,14 @@ '0200000002666de5d5852807a13612b6ea0373643266d435822daeb39c29e5d4b67e893cda0100000064414feb64ffdf50b0eb40a6fe0c34da65e94e0cbbbc2e58f2b290f3b2bf31480b34a57c4862ee177129dc8a1ce645573cd240e5e83d336d19ff22c3a7675bc903564121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf7926180300000064410f0461f0e843cc5b78196e3fdb3b89d64948629645f3b44ea960c2a5ac8f5835189697165a01cc259a0f4eff931c83e110019ee5c7721a43e0dde11ba04e068d4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000406a04534c500001010453454e442020a0b9337a78603c6681ed2bc541593375535dcd9979196620ce71f233f2f6f80800000019d80000000800000000001d9600060500000000000017a914e49e695e2f466e34447cb253567b8b277b60e3908722020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac2c2e0f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const adPrepTxid = '280b6fda5a11a94145f3b4203fb4f199d875d3621c8e4cc9d63501e73b9649bc'; - - mockedChronik.setMock('broadcastTx', { - input: adPrepHex, - output: { txid: adPrepTxid }, - }); + mockedChronik.setBroadcastTx(adPrepHex, adPrepTxid); // SLP1 ad list const adListHex = '0200000001bc49963be70135d6c94c8e1c62d375d899f1b43f20b4f34541a9115ada6f0b2801000000dd0441475230075041525449414c41b11b013fb8140dcce13f93ee99584b1c6b547ee076ed63f9ec0a6c0068ad84c5420ecd608af68134366576bae4196a83f6a8f521c50dea4acc75dda6215c7fec414c8c4c766a04534c500001010453454e442020a0b9337a78603c6681ed2bc541593375535dcd9979196620ce71f233f2f6f80800000000000000000300dbf30400000000003dc7010000000000d226af0c000000002099c53f031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02d01557f77ad075041525449414c88044147523087ffffffff020000000000000000376a04534c500001010453454e442020a0b9337a78603c6681ed2bc541593375535dcd9979196620ce71f233f2f6f80800000019d8000000220200000000000017a91472df09389a835adb0e13e32bf1c91144ed107eef8700000000'; const adListTxid = '823f652e22d154fc7bdd77ee9d9fa37c77e9649235f1430958bef68b7428b9ae'; - - mockedChronik.setMock('broadcastTx', { - input: adListHex, - output: { txid: adListTxid }, - }); + mockedChronik.setBroadcastTx(adListHex, adListTxid); // Mock response for agora select params check // Note @@ -250,9 +232,8 @@ // Note that Date() and Math.random() must be mocked to keep this deterministic const EXPECTED_OFFER_P2SH = '72df09389a835adb0e13e32bf1c91144ed107eef'; - mockedChronik.setScript('p2sh', EXPECTED_OFFER_P2SH); // We mock no existing utxos - mockedChronik.setUtxos('p2sh', EXPECTED_OFFER_P2SH, { utxos: [] }); + mockedChronik.setUtxosByScript('p2sh', EXPECTED_OFFER_P2SH, []); const agora = new Agora(mockedChronik); render( @@ -406,11 +387,7 @@ '0200000002cc04a35686950a66845ebf8e37677fffcc5ee0e2b63e3f05822838273149660c010000006441878aa7e698097a4961646a2da44f701d8895cb065113fcf1d2e9f073afbc37025a5587e121bd0311a24a7af60445abfc4de7e3675a3a9f51cffddc875d88fca24121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf7926180300000064412f509f90f23f4b85b27452e0f25d33cef07ad8fef898e2d308c43fb0dfd6f7e00f7201336be4089171ddc094a24688882b518ec0c6958c904df12d0239a7342f4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff150000000000000000d96a04534c500001810453454e44200c66493127382882053f3eb6e2e05eccff7f67378ebf5e84660a958656a304cc08000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000000108000000000000005222020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac0d070f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'cdc6afbf1ddd796388692ec9106816be1f9229ece11e545c1cbe6854ccf087ec'; - - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mockedChronik} @@ -534,19 +511,12 @@ // Build chronik mocks that Cashtab would use to add token info to cache for (const tokenMock of supportedTokens) { - mintNftMockedChronik.setMock('token', { - input: tokenMock.tokenId, - output: tokenMock.token, - }); - mintNftMockedChronik.setMock('tx', { - input: tokenMock.tokenId, - output: tokenMock.tx, - }); - mintNftMockedChronik.setTokenId(tokenMock.tokenId); - mintNftMockedChronik.setUtxosByTokenId(tokenMock.tokenId, { - tokenId: tokenMock.tokenId, - utxos: tokenMock.utxos, - }); + mintNftMockedChronik.setToken(tokenMock.tokenId, tokenMock.token); + mintNftMockedChronik.setTx(tokenMock.tokenId, tokenMock.tx); + mintNftMockedChronik.setUtxosByTokenId( + tokenMock.tokenId, + tokenMock.utxos, + ); // Set empty tx history to mock no existing NFTs mintNftMockedChronik.setTxHistoryByTokenId(tokenMock.tokenId, []); } @@ -556,10 +526,7 @@ const txid = 'd215995b67194576b66ef9c593a66d9255a3ec21e424ecfbb6046643b8e0dbe6'; - mintNftMockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mintNftMockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mintNftMockedChronik} @@ -701,19 +668,15 @@ // Build chronik mocks that Cashtab would use to add token info to cache for (const tokenMock of supportedTokens) { - renderChildNftsMockedChronik.setMock('token', { - input: tokenMock.tokenId, - output: tokenMock.token, - }); - renderChildNftsMockedChronik.setMock('tx', { - input: tokenMock.tokenId, - output: tokenMock.tx, - }); - renderChildNftsMockedChronik.setTokenId(tokenMock.tokenId); - renderChildNftsMockedChronik.setUtxosByTokenId(tokenMock.tokenId, { - tokenId: tokenMock.tokenId, - utxos: tokenMock.utxos, - }); + renderChildNftsMockedChronik.setToken( + tokenMock.tokenId, + tokenMock.token, + ); + renderChildNftsMockedChronik.setTx(tokenMock.tokenId, tokenMock.tx); + renderChildNftsMockedChronik.setUtxosByTokenId( + tokenMock.tokenId, + tokenMock.utxos, + ); // Set tx history of parent tokenId to empty renderChildNftsMockedChronik.setTxHistoryByTokenId( tokenMock.tokenId, @@ -838,32 +801,21 @@ '0200000002268322a2a8e67fe9efdaf15c9eb7397fb640ae32d8a245c2933f9eb967ff9b5d010000006441e4365d350b1dfee55e60cc2600ba094ed0e05c1d6a297bd3fe3f0721b88d9ec09b7d114cf0aab08a3b264153858f1a48f839f3639a8a8f9b11214038080cb9e34121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf7926180300000064411e9913b28017832fa38944675eb8815411fd210f9dfc8f0aa806bed055f52b6592488fdd1f9be942c19dcb98d7ddd7c55bc8b1233a64ad3dfa1c65eebbd48f254121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a22283260800000000000000019a0400000000000017a91407d2b0e6ec7b96cbfbe4a7d54e28d28fbcf65e408710310f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const adPrepTxid = '7b4f2b1cf9716ead03f91910bd0c08956c381987e1cb3cd9f9b4d555a7b9ba25'; - - mockedChronik.setMock('broadcastTx', { - input: adPrepHex, - output: { txid: adPrepTxid }, - }); + mockedChronik.setBroadcastTx(adPrepHex, adPrepTxid); // NFT ad list const adListHex = '020000000125bab9a755d5b4f9d93ccbe18719386c95080cbd1019f903ad6e71f91c2b4f7b01000000a70441475230074f4e4553484f544106bd7c3cc4f6aca45a7f97644b8cb5e745dee224246f38605171e8f9e0d6e036af3ea4853b08e1baa92e091bd0ceabf83d4a246e07e6b0b008a3e091b111f22a414c56222b50fe00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac7521031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dad074f4e4553484f5488044147523087ffffffff020000000000000000376a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a2228326080000000000000001220200000000000017a914729833ae294590bbcf28bfbb9ad54c01b6cdb6288700000000'; const adListTxid = '97cf0fed5062419ad456f22457cfeb3b15909f1de2350be48c53b24944e0de89'; - - mockedChronik.setMock('broadcastTx', { - input: adListHex, - output: { txid: adListTxid }, - }); + mockedChronik.setBroadcastTx(adListHex, adListTxid); // NFT send const hex = '0200000002268322a2a8e67fe9efdaf15c9eb7397fb640ae32d8a245c2933f9eb967ff9b5d010000006441fff60607ba0fb6eda064075b321abc3980c249efcc0e91d4d95e464500a654476e59b76dd19bdd66f5d207a0d731550c93ce724a09e00a3bff3fcfbc08c970844121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441fe754300443dfb293619693087016c9d9a8437489d48cb7c0c3fcb6b5af6277833ff7156355aeb557145c4075b7917d90d79239ba7bf776a38fef935d8da2f7c4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a222832608000000000000000122020000000000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac84330f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'daa5872d1ef95a05bd3ee59fc532aa7921a54b783a5af68c5aa9146f61d2e134'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mockedChronik} @@ -1011,10 +963,7 @@ '0200000002268322a2a8e67fe9efdaf15c9eb7397fb640ae32d8a245c2933f9eb967ff9b5d010000006441fff60607ba0fb6eda064075b321abc3980c249efcc0e91d4d95e464500a654476e59b76dd19bdd66f5d207a0d731550c93ce724a09e00a3bff3fcfbc08c970844121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441fe754300443dfb293619693087016c9d9a8437489d48cb7c0c3fcb6b5af6277833ff7156355aeb557145c4075b7917d90d79239ba7bf776a38fef935d8da2f7c4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a222832608000000000000000122020000000000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac84330f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'daa5872d1ef95a05bd3ee59fc532aa7921a54b783a5af68c5aa9146f61d2e134'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper chronik={mockedChronik} @@ -1119,19 +1068,15 @@ // Build chronik mocks that Cashtab would use to add token info to cache for (const tokenMock of supportedTokens) { - renderChildNftsMockedChronik.setMock('token', { - input: tokenMock.tokenId, - output: tokenMock.token, - }); - renderChildNftsMockedChronik.setMock('tx', { - input: tokenMock.tokenId, - output: tokenMock.tx, - }); - renderChildNftsMockedChronik.setTokenId(tokenMock.tokenId); - renderChildNftsMockedChronik.setUtxosByTokenId(tokenMock.tokenId, { - tokenId: tokenMock.tokenId, - utxos: tokenMock.utxos, - }); + renderChildNftsMockedChronik.setToken( + tokenMock.tokenId, + tokenMock.token, + ); + renderChildNftsMockedChronik.setTx(tokenMock.tokenId, tokenMock.tx); + renderChildNftsMockedChronik.setUtxosByTokenId( + tokenMock.tokenId, + tokenMock.utxos, + ); // Set tx history of parent tokenId to empty renderChildNftsMockedChronik.setTxHistoryByTokenId( tokenMock.tokenId, @@ -1203,23 +1148,17 @@ const heismanNftTokenId = heismanNftOneOffer.token.tokenId; // Mock the API calls for getting and caching this token's info - mockedChronik.setMock('token', { - input: heismanNftTokenId, - output: heismanNftOneCache.token, - }); - mockedChronik.setMock('tx', { - input: heismanNftTokenId, - output: heismanNftOneCache.tx, - }); + mockedChronik.setToken(heismanNftTokenId, heismanNftOneCache.token); + mockedChronik.setTx(heismanNftTokenId, heismanNftOneCache.tx); // Also mock for the collection - mockedChronik.setMock('token', { - input: heismanCollectionCacheMocks.tokenId, - output: heismanCollectionCacheMocks.token, - }); - mockedChronik.setMock('tx', { - input: heismanCollectionCacheMocks.tokenId, - output: heismanCollectionCacheMocks.tx, - }); + mockedChronik.setToken( + heismanCollectionCacheMocks.tokenId, + heismanCollectionCacheMocks.token, + ); + mockedChronik.setTx( + heismanCollectionCacheMocks.tokenId, + heismanCollectionCacheMocks.tx, + ); // Mock an error querying this NFT listing const mockedAgora = new MockAgora(); @@ -1255,23 +1194,17 @@ const heismanNftTokenId = heismanNftOneOffer.token.tokenId; // Mock the API calls for getting and caching this token's info - mockedChronik.setMock('token', { - input: heismanNftTokenId, - output: heismanNftOneCache.token, - }); - mockedChronik.setMock('tx', { - input: heismanNftTokenId, - output: heismanNftOneCache.tx, - }); + mockedChronik.setToken(heismanNftTokenId, heismanNftOneCache.token); + mockedChronik.setTx(heismanNftTokenId, heismanNftOneCache.tx); // Also mock for the collection - mockedChronik.setMock('token', { - input: heismanCollectionCacheMocks.tokenId, - output: heismanCollectionCacheMocks.token, - }); - mockedChronik.setMock('tx', { - input: heismanCollectionCacheMocks.tokenId, - output: heismanCollectionCacheMocks.tx, - }); + mockedChronik.setToken( + heismanCollectionCacheMocks.tokenId, + heismanCollectionCacheMocks.token, + ); + mockedChronik.setTx( + heismanCollectionCacheMocks.tokenId, + heismanCollectionCacheMocks.tx, + ); // Mock an error querying this NFT listing const mockedAgora = new MockAgora(); @@ -1362,10 +1295,7 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c25010000006441999a894cafbab21d590da6ce07e572935144c480bce48c4df3efb74e9ee2fd3a4de61a40f93c28775c7b135a6a9ccba7d880bd5776d289b6c8ae5752afee24b34121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441f6e2b2a66d8676854e281f5af375bc56d4f359cb4be1e178d330720384da79a5216bd7a132bfd44654835c95a8d81b099b03e953d4a720187255ef1c9a1b646e4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff0400000000000000003a6a5037534c5032000453454e4449884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c02102700000000301b0f00000022020000000000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac18310f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = '33313eaf3365d9bf440645c5fffa8ed91681d1e1464afe598a564cdc76855c04'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Mock NOT blacklisted when(fetch) @@ -1461,10 +1391,7 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c250100000064416f667f359f04e273d524eac5fdaede0bfaf483daaf74f2ab5ba849c3a126b36b059003ef22b647d5265b74938e50c40505c1ad56474d0af2930192994011b9c84121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441ed0c24a83ec9137bc2cc367f674b1932de280f3bc2fbfd9cd70b840e61ccf5fa272e714ba06d3060574df97bc135acae2367d00fdd67ce2bbf347193a871348c4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000656a5030534c503200044255524e49884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c10270000000031534c5032000453454e4449884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c01301b0f00000022020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac28330f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'f71293a94bd444c0b82ce6a6a8a1d2ae182f6a848cd2382bb6ca496955184fdf'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Mock NOT blacklisted when(fetch) @@ -1545,10 +1472,7 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c250100000064413919d2894e681586f285af178ef2c8d86b2f008e31519b1592c76cae7bee17eb4bb1558db35b225a15a2ba1c1f3d86564e12adfa0d5c012427f096398cdff20e4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf79261803000000644126a0f23966db5ba3212e4d5c545a186d407af4d110335e521c867e63549ade8d25da8a911343d9bf9275bbb58255cd445a1b3fc14ae35a89b8964cfbe47299aa4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000336a5030534c503200044255524e49884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c40420f00000022020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac8c330f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'f413a14acc391c2541f0dea477cf7ee07cf6256bc3b201d6b276272f2fdda407'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Mock NOT blacklisted when(fetch) @@ -1669,19 +1593,12 @@ ); // Mock cache info - mintAlpMockedChronik.setMock('token', { - input: alpMocks.tokenId, - output: alpMocks.token, - }); - mintAlpMockedChronik.setMock('tx', { - input: alpMocks.tokenId, - output: alpMocks.tx, - }); - mintAlpMockedChronik.setTokenId(alpMocks.tokenId); - mintAlpMockedChronik.setUtxosByTokenId(alpMocks.tokenId, { - tokenId: alpMocks.tokenId, - utxos: alpMocks.utxos, - }); + mintAlpMockedChronik.setToken(alpMocks.tokenId, alpMocks.token); + mintAlpMockedChronik.setTx(alpMocks.tokenId, alpMocks.tx); + mintAlpMockedChronik.setUtxosByTokenId( + alpMocks.tokenId, + alpMocks.utxos, + ); // Set empty tx history mintAlpMockedChronik.setTxHistoryByTokenId(alpMocks.tokenId, []); @@ -1690,10 +1607,7 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c25020000006441acdadb019c561b7bfa761695503eb1250d3ae1f34e66eeb3c4c8fb561b4ec95291bde678871451316a8f0472922d25936dd341eb90eb6bb3ccde98b00a2138da4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441fc7a554a708c3e6a2fc72e7c96871521678d0a36e336a599b39eac6a36f4ecedcfd2a728c8e639b5946fde677f1afa9e31468531476dd66fce1adfc760e7e2ff4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000356a5032534c503200044d494e5449884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c01ffffffffffff0122020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac22310f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = '28c733455a50be334948600bcdf0817610b0321ceba3da52c7c7ffec995320f0'; - mintAlpMockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mintAlpMockedChronik.setBroadcastTx(hex, txid); // Mock NOT blacklisted when(fetch) @@ -1768,11 +1682,7 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c25010000006441d32ae72fa880a40975a475147443a3a7fe10308178ad38d80e6a2428921732b0699849443d8e24124a8ee5b75f1e9f74628fdb8cd0c9704d8cd0c70df65828e94121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf7926180300000064415fc18bb026bc3122776e708b8cdba9225494c704c1feca7aefb36b592abed96568cd57cb3504769bc4019ec0f36990c28c57012cefe805e4d3b046cc308bc86b4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000866a504b41475230075041525449414c01009b630800000000005532000000000000d6b24701000000002099c53f031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02d37534c5032000453454e4449884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c0200420f000000400000000000220200000000000017a91450eb4978c85ec89b63e37e6b87409c9f5815c7058722020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac83300f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const offerTxid = 'e00be7011ee5d585cbd54049570ea0754ab0d5c05acf6cb01c25afa3aa61663d'; - - mockedChronik.setMock('broadcastTx', { - input: offerHex, - output: { txid: offerTxid }, - }); + mockedChronik.setBroadcastTx(offerHex, offerTxid); // Mock response for agora select params check // Note @@ -1782,9 +1692,8 @@ // Note that Date() and Math.random() must be mocked to keep this deterministic const EXPECTED_OFFER_P2SH = '50eb4978c85ec89b63e37e6b87409c9f5815c705'; - mockedChronik.setScript('p2sh', EXPECTED_OFFER_P2SH); // We mock no existing utxos - mockedChronik.setUtxos('p2sh', EXPECTED_OFFER_P2SH, { utxos: [] }); + mockedChronik.setUtxosByScript('p2sh', EXPECTED_OFFER_P2SH, []); // Note that we cannot use mockedAgora to avoid agoraQueryErrors, as we need a proper // agora object to build the partial diff --git a/cashtab/src/components/Send/__tests__/SendXec.test.js b/cashtab/src/components/Send/__tests__/SendXec.test.js --- a/cashtab/src/components/Send/__tests__/SendXec.test.js +++ b/cashtab/src/components/Send/__tests__/SendXec.test.js @@ -1144,10 +1144,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064410fed2b69cf2c9f0ca92318461d707292347ef567d6866d3889b510d1d1ab8615451dd1d56608457d4f40e8eb97f61dad4f3dc9fbef57099105a6a3e32e0efe8e4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000296a04007461622263617368746162206d6573736167652077697468206f705f72657475726e5f726177a4060000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac4f7b0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '63e4bba044135367eb71c71bc78aee91ecce0551fbdfbdb975e668fb808547ed'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1283,10 +1280,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064418305d1f7771a13e90b0cb15adf1c0a39b4381d1ec1bc3bebfa67cbbb5c9461b1a9d0c5a66ca5935aad771cbe869c9002add8b9d9822724ce73db8d15554f26cb4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff0200000000000000003c6a040074616235486f772061626f75742061206c6f6e672d6973682043617368746162206d7367207769746820656d6f6a697320f09f8eaff09f988e11820e00000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac00000000'; const txid = 'b1d49881be9c810e4408881438efb9e910d9e03bcc12a7bfcd652a0952d06f42'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1386,10 +1380,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064410fed2b69cf2c9f0ca92318461d707292347ef567d6866d3889b510d1d1ab8615451dd1d56608457d4f40e8eb97f61dad4f3dc9fbef57099105a6a3e32e0efe8e4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000296a04007461622263617368746162206d6573736167652077697468206f705f72657475726e5f726177a4060000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac4f7b0e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '63e4bba044135367eb71c71bc78aee91ecce0551fbdfbdb975e668fb808547ed'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1526,10 +1517,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064413b207f573a7abb9ec0d149fa71cbde63272a0e6b58298a81bc39ac2001729205bd1e9284c9d5a268f7abe63c5c953bf932ac06c13e408341bde4e4807d7f2fe94121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff0260ae0a00000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388acf7d30300000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = 'a6e905185097cc1ffb289ca366ff7322f8aaf95713d1e5d1a4e89663e609530f'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1592,10 +1580,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a210200000064411aa35b343dea193092b46c01b877677d595d854686655ae24a3387a10955656a7604dca1cae999239d8ae76dc16ec9db72560832e8a9b0fb09f4ba6e1fb384b14121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff03d0070000000000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88ac98080000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388acab710e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = 'a306834359b3591c68dc3ee8227e5e10225e6ab3c5a7496ead6e119aaaf31635'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1655,10 +1640,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441e11f1d96347ab50d56b111e9fd5ef68f9f1c69c76e1f8a65ec1fa58bd2e0eaee7a33b2c961ed5e58231c793b5d8a2950e2def6e7613df1055e681bc8f25d0a5b4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff019c820e00000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac00000000'; const txid = '521eda8ad78014c60374931dcc4e35f312847f9332e16cb846cd387a984e95d2'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1763,10 +1745,7 @@ '0200000001fe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441d95dfbf01e233d19684fd525d1cc39eb82a53ebfc97b8f2f9160f418ce863f4360f9fd1d6c182abde1d582ed39c6998ec5e4cdbde1b09736f6abe390a6ab8d8f4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff040000000000000000296a04007461622263617368746162206d6573736167652077697468206f705f72657475726e5f726177a4060000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac40e20100000000001976a91495e79f51d4260bc0dc3ba7fb77c7be92d0fbdd1d88acca980c00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = 'f153119862f52dbe765ed5d66a5ff848d0386c5d987af9bef5e49a7e62a2c889'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); render( <CashtabTestWrapper @@ -1912,14 +1891,8 @@ // Mock API calls for fetching this token info from cache const token_id = mockTokenId; // Set chronik mocks required for cache preparation and supply calc - mockedChronik.setMock('token', { - input: token_id, - output: new Error('some chronik error'), - }); - mockedChronik.setMock('tx', { - input: token_id, - output: slp1FixedBear.tx, - }); + mockedChronik.setToken(token_id, new Error('some chronik error')); + mockedChronik.setTx(token_id, slp1FixedBear.tx); render( <CashtabTestWrapper @@ -2009,22 +1982,13 @@ '02000000023023c2a02d7932e2f716016ab866249dd292387967dbd050ff200b8b8560073b010000006441bac61dbfa47bc7b92952caaa867c2c5fd11bde4cfa36c21b818dbb80c15b19a0c94845e916bc57bc5f35f32ca379bd48a6ee1dc4ded52794bcee231655b105f14121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dfffffffffe667fba52a1aa603a892126e492717eed3dad43bfea7365a7fdd08e051e8a21020000006441a59dcc96f885dcbf56d473ba74b3202adb00dbc1142e379efa3784b559d7be97aa3d777eb4001613f205191d177c9896f652132d397a65cdfa93c69657d59f1b4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001010453454e44203fee3384150b030490b7bee095a63900f66a45f2d8e3002ae2cf17ce3ef4d10908000000000000000122020000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388acbb800e00000000001976a9143a5fb236934ec078b4507c303d3afd82067f8fc188ac00000000'; const txid = '6de2d27d40bced679a8b8e55c85230ed8da0977c30ad31247fefc0b1eba0976e'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Mock API calls for fetching this token info from cache const token_id = slp1FixedBear.tokenId; // Set chronik mocks required for cache preparation and supply calc - mockedChronik.setMock('token', { - input: slp1FixedBear.tokenId, - output: slp1FixedBear.token, - }); - mockedChronik.setMock('tx', { - input: slp1FixedBear.tokenId, - output: slp1FixedBear.tx, - }); + mockedChronik.setToken(slp1FixedBear.tokenId, slp1FixedBear.token); + mockedChronik.setTx(slp1FixedBear.tokenId, slp1FixedBear.tx); const { tokenName, tokenTicker } = slp1FixedBear.token.genesisInfo; @@ -2129,22 +2093,12 @@ '020000000288bb5c0d60e11b4038b00af152f9792fa954571ffdd2413a85f1c26bfd930c25010000006441fff980a72dab5fed2ef4b94c54c5b91dd2e4d22fab32bd8daa8ba8118fc45b121cceb8c43a869966219d1e6b1ebf6c34436287a349fbd132a11b8928cdf642784121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf792618030000006441c8203434106d39d750461d8a6939412f432220cba2e957f19a699e5ed57a4357bb257dfcde9aa5618d6b87721f939b69312c429eba28c056f06efad33b4875314121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff0400000000000000003a6a5037534c5032000453454e4449884c726ebb974b9b8345ee12b44cc48445562b970f776e307d16547ccdd77c02102700000000301b0f00000022020000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac22020000000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac18310f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = 'cf78a0c9f88027ab90dec0fe2180ef4d4d45ab431e179ce262ea19502202da52'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); - + mockedChronik.setBroadcastTx(hex, txid); // Mock API calls for fetching this token info from cache const token_id = alpMocks.tokenId; // Set chronik mocks required for cache preparation and supply calc - mockedChronik.setMock('token', { - input: alpMocks.tokenId, - output: alpMocks.token, - }); - mockedChronik.setMock('tx', { - input: alpMocks.tokenId, - output: alpMocks.tx, - }); + mockedChronik.setToken(alpMocks.tokenId, alpMocks.token); + mockedChronik.setTx(alpMocks.tokenId, alpMocks.tx); const { tokenName, tokenTicker } = alpMocks.token.genesisInfo; @@ -2249,22 +2203,16 @@ '0200000002268322a2a8e67fe9efdaf15c9eb7397fb640ae32d8a245c2933f9eb967ff9b5d0100000064415b08020f453b87695e24d8ea104fab2c98c1e944502582599e945b407a8900dc75bcd599cbbb2cd3216402e9d6b0b1329aec686033cd838c9555777eaad8c0704121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffef76d01776229a95c45696cf68f2f98c8332d0c53e3f24e73fd9c6deaf79261803000000644164f0fe5c018e1b2ef2ed49e0ff1d87e5fe116e32ca30db8422ae09cc825976abc705ae59faee5d3372638bc297cd70f77582f5d0c513bfabfd9146dfb916d3ad4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff030000000000000000376a04534c500001410453454e44205d9bff67b99e3f93c245a2d832ae40b67f39b79e5cf1daefe97fe6a8a222832608000000000000000122020000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac84330f00000000001976a91400549451e5c22b18686cacdf34dce649e5ec3be288ac00000000'; const txid = '57f665440f7ab0686fece1d744484140d3013e301b45842f5e9371597871ea8c'; - mockedChronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + mockedChronik.setBroadcastTx(hex, txid); // Mock API calls for fetching this token info from cache const token_id = slp1NftChildMocks.tokenId; // Set chronik mocks required for cache preparation and supply calc - mockedChronik.setMock('token', { - input: slp1NftChildMocks.tokenId, - output: slp1NftChildMocks.token, - }); - mockedChronik.setMock('tx', { - input: slp1NftChildMocks.tokenId, - output: slp1NftChildMocks.tx, - }); + mockedChronik.setToken( + slp1NftChildMocks.tokenId, + slp1NftChildMocks.token, + ); + mockedChronik.setTx(slp1NftChildMocks.tokenId, slp1NftChildMocks.tx); const { tokenName, tokenTicker } = slp1NftChildMocks.token.genesisInfo; diff --git a/cashtab/src/transactions/__tests__/index.test.js b/cashtab/src/transactions/__tests__/index.test.js --- a/cashtab/src/transactions/__tests__/index.test.js +++ b/cashtab/src/transactions/__tests__/index.test.js @@ -51,10 +51,7 @@ } = tx; it(`sendXec: ${description}`, async () => { const chronik = new MockChronikClient(); - chronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + chronik.setBroadcastTx(hex, txid); expect( await sendXec( chronik, @@ -79,10 +76,7 @@ if (typeof hex !== 'undefined') { // For error cases that are not thrown until after the tx is successfully built, // set a tx broadcast error that can be thrown by the broadcasting eCash node - chronik.setMock('broadcastTx', { - input: hex, - output: new Error(msg), - }); + chronik.setBroadcastTx(hex, new Error(msg)); } await expect( @@ -105,12 +99,7 @@ '0200000003c31d0b990c5a707dca806648fe5036dbb3f9590b3e22e026392912edeef154680000000064417353fc52d6f47efffddf90656dcbd4313f476c292625e24c71660b7b075f36f2c163ff2c713ad8e593490cbbaa32b424c93671908731912de255327e394c65eb4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffc31d0b990c5a707dca806648fe5036dbb3f9590b3e22e026392912edeef15468010000006441ef045f01ba4b6dd75b470787de704c366ad8869369ae445f9fb744ee3ec220533324423ae6028e6fb72fbd3d7f6359eb9c1b35322ced7e2d263170a4092bebaa4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffffc31d0b990c5a707dca806648fe5036dbb3f9590b3e22e026392912edeef15468020000006441faa831725c8e38a909cbf3ba594360b2d51fd884397347f4c0ce0d1379096636db4126d7f9caf34f7480d3700ffbed062352ea7e0b2fac15f5a35df880b9154c4121031d4603bdc23aca9432f903e3cf5975a3f655cc3fa5057c61d00dfc1ca5dfd02dffffffff01d0070000000000001976a9144e532257c01b310b3b5c1fd947c79a72addf852388ac00000000'; const txid = '73af2c7dcf70811ef6fa68c671673529289b1304e1cb3979f9792780f2b885ab'; - chronik.setMock('broadcastTx', { - input: hex, - output: { - txid, - }, - }); + chronik.setBroadcastTx(hex, txid); const walletWithEdgeCaseUtxos = { ...wallet, state: { @@ -303,14 +292,8 @@ } = tx; it(`Build and broadcast an SLP V1 SEND and BURN tx from in-node chronik-client utxos: ${description}`, async () => { const chronik = new MockChronikClient(); - chronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); - chronik.setMock('broadcastTx', { - input: burn.hex, - output: { txid: burn.txid }, - }); + chronik.setBroadcastTx(hex, txid); + chronik.setBroadcastTx(burn.hex, burn.txid); // Get tokenInputs and sendAmounts const tokenInputInfo = getSendTokenInputs( @@ -377,10 +360,7 @@ const { hex, txid } = rawTx; it(`sendXec: ${description}`, async () => { const chronik = new MockChronikClient(); - chronik.setMock('broadcastTx', { - input: hex, - output: { txid }, - }); + chronik.setBroadcastTx(hex, txid); expect( await sendXec( chronik, diff --git a/cashtab/src/wallet/__tests__/useWallet.test.js b/cashtab/src/wallet/__tests__/useWallet.test.js --- a/cashtab/src/wallet/__tests__/useWallet.test.js +++ b/cashtab/src/wallet/__tests__/useWallet.test.js @@ -713,10 +713,8 @@ // Mock chronik.tx response for this tx to be a new token tx const MOCK_TXID = '1111111111111111111111111111111111111111111111111111111111111111'; - mockedChronik.setMock('tx', { - input: MOCK_TXID, - output: mockIncomingTokenTxDetails, - }); + mockedChronik.setTx(MOCK_TXID, mockIncomingTokenTxDetails); + const { result } = renderHook(() => useWallet(mockedChronik)); // Wait for the wallet to load diff --git a/contrib/teamcity/build-configurations.yml b/contrib/teamcity/build-configurations.yml --- a/contrib/teamcity/build-configurations.yml +++ b/contrib/teamcity/build-configurations.yml @@ -88,15 +88,6 @@ npm run build fi - # Install mock-chronik-client dependencies if this test uses them - if [ -z "${DEPENDS_MOCK_CHRONIK_CLIENT+x}" ] ; then - echo "Test does not depend on mock-chronik-client, skipping mock-chronik-client dependencies..." - else - echo "Test depends on mock-chronik-client. Installing mock-chronik-client dependencies..." - pushd "${TOPLEVEL}/modules/mock-chronik-client" - npm ci - fi - # Build ecash-lib-wasm for ecash-lib's WebAssembly part if [ -z "${DEPENDS_ECASH_LIB_WASM+x}" ] ; then echo "Test does not depend on ecash-lib-wasm, skipping" @@ -114,6 +105,16 @@ npm ci fi + # Install mock-chronik-client dependencies if this test uses them + if [ -z "${DEPENDS_MOCK_CHRONIK_CLIENT+x}" ] ; then + echo "Test does not depend on mock-chronik-client, skipping mock-chronik-client dependencies..." + else + echo "Test depends on mock-chronik-client. Installing mock-chronik-client dependencies..." + pushd "${TOPLEVEL}/modules/mock-chronik-client" + npm ci + npm run build + fi + if [ -z "${DEPENDS_ECASH_LIB+x}" ] ; then echo "Test does not depend on ecash-lib" else diff --git a/mock-chronik-client.Dockerfile b/mock-chronik-client.Dockerfile --- a/mock-chronik-client.Dockerfile +++ b/mock-chronik-client.Dockerfile @@ -13,6 +13,10 @@ COPY modules/mock-chronik-client . # Install ecashaddrjs from npm, so that module users install it automatically RUN npm install ecashaddrjs@latest +# Install chronik-client from npm, so that module users install it automatically +# Note that in practice any user of chronik-client probably already has chronik-client installed +# So it won't really be bloating their node_modules +RUN npm install chronik-client@latest RUN npm ci # Publish the module diff --git a/modules/mock-chronik-client/.eslintrc.js b/modules/mock-chronik-client/.eslintrc.js new file mode 100644 --- /dev/null +++ b/modules/mock-chronik-client/.eslintrc.js @@ -0,0 +1,33 @@ +// Copyright (c) 2024 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +const headerArray = [ + { + pattern: + '^ Copyright \\(c\\) [2][0-9]{3}([-][2][0-9]{3})? The Bitcoin developers$', + template: ` Copyright (c) ${new Date().getFullYear()} The Bitcoin developers`, + }, + ' Distributed under the MIT software license, see the accompanying', + ' file COPYING or http://www.opensource.org/licenses/mit-license.php.', +]; + +module.exports = { + env: { + node: true, + commonjs: true, + es2021: true, + mocha: true, + }, + overrides: [], + extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended'], + parserOptions: { + ecmaVersion: 'latest', + sourceType: 'module', + parser: '@typescript-eslint/parser', + }, + plugins: ['header', '@typescript-eslint'], + rules: { + 'header/header': [2, 'line', headerArray, 2], + }, +}; diff --git a/modules/mock-chronik-client/.gitignore b/modules/mock-chronik-client/.gitignore --- a/modules/mock-chronik-client/.gitignore +++ b/modules/mock-chronik-client/.gitignore @@ -9,3 +9,5 @@ # generated by testing CI locally test_results/ + +dist/ diff --git a/modules/mock-chronik-client/README.md b/modules/mock-chronik-client/README.md --- a/modules/mock-chronik-client/README.md +++ b/modules/mock-chronik-client/README.md @@ -168,3 +168,15 @@ 1.12.3 - Add dummy `plugin` method to allow construction of `new Agora()` from `ecash-agora` with a `MockChronikClient` [D17279](https://reviews.bitcoinabc.org/D17279) + +2.0.0 + +[D17332](https://reviews.bitcoinabc.org/D17332) + +- Full implementation of typescript +- Set history and utxos by script, address, or tokenId in one step (prev 2) +- Set history by lokadId in one step (prev 2) +- Better type checking +- Improved mock websocket (now it more closely follows the API of chronik-client) +- Add `broadcastTxs` method +- Add `chronikInfo` method diff --git a/modules/mock-chronik-client/index.d.ts b/modules/mock-chronik-client/index.d.ts deleted file mode 100644 --- a/modules/mock-chronik-client/index.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare var MockChronikClient: any; -declare var MockAgora: any; -export { MockAgora, MockChronikClient }; diff --git a/modules/mock-chronik-client/index.js b/modules/mock-chronik-client/index.js deleted file mode 100644 --- a/modules/mock-chronik-client/index.js +++ /dev/null @@ -1,496 +0,0 @@ -// Copyright (c) 2023 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. -'use strict'; -const cashaddr = require('ecashaddrjs'); - -const CHRONIK_DEFAULT_PAGESIZE = 25; - -module.exports = { - MockAgora: class { - // Agora can make specialized chronik-client calls to a chronik-client instance - // running the agora plugin - // For the purposes of unit testing, we only need to re-create how this object - // is initialized and support getting and setting of expected responses - constructor() { - // Use self since it is not a reserved term in js - // Can access self from inside a method and still get the class - const self = this; - // API call mock return objects - // Can be set with self.setMock - self.mockedResponses = { - offeredGroupTokenIds: {}, - offeredFungibleTokenIds: {}, - activeOffersByPubKey: {}, - activeOffersByGroupTokenId: {}, - activeOffersByTokenId: {}, - }; - - // Allow user to set supported agora query responses - self.setOfferedGroupTokenIds = function (response) { - self.mockedResponses.offeredGroupTokenIds = response; - }; - self.setOfferedFungibleTokenIds = function (response) { - self.mockedResponses.offeredFungibleTokenIds = response; - }; - self.setActiveOffersByPubKey = function (pubKey, response) { - self.mockedResponses.activeOffersByPubKey[pubKey] = response; - }; - self.setActiveOffersByGroupTokenId = function ( - groupTokenId, - response, - ) { - self.mockedResponses.activeOffersByGroupTokenId[groupTokenId] = - response; - }; - self.setActiveOffersByTokenId = function (tokenId, response) { - self.mockedResponses.activeOffersByTokenId[tokenId] = response; - }; - - // Checks whether the user set this mock response to be an error. - // If so, throw it to simulate an API error response. - function throwOrReturnValue(mockResponse) { - if (mockResponse instanceof Error) { - throw mockResponse; - } - return mockResponse; - } - - self.offeredGroupTokenIds = async function () { - return throwOrReturnValue( - self.mockedResponses.offeredGroupTokenIds, - ); - }; - self.offeredFungibleTokenIds = async function () { - return throwOrReturnValue( - self.mockedResponses.offeredFungibleTokenIds, - ); - }; - self.activeOffersByPubKey = async function (pubKey) { - return throwOrReturnValue( - self.mockedResponses.activeOffersByPubKey[pubKey], - ); - }; - self.activeOffersByGroupTokenId = async function (groupTokenId) { - return throwOrReturnValue( - self.mockedResponses.activeOffersByGroupTokenId[ - groupTokenId - ], - ); - }; - self.activeOffersByTokenId = async function (tokenId) { - return throwOrReturnValue( - self.mockedResponses.activeOffersByTokenId[tokenId], - ); - }; - } - }, - MockChronikClient: class { - constructor() { - // Use self since it is not a reserved term in js - // Can access self from inside a method and still get the class - const self = this; - - // We need to give mockedChronik a plugin function - // This is required for creating a new Agora(mockedChronik) - self.plugin = () => 'dummy plugin'; - - // API call mock return objects - // Can be set with self.setMock - self.mockedResponses = { - block: {}, - blockTxs: {}, - blockchainInfo: {}, - txHistory: [], - tx: {}, - token: {}, - p2sh: {}, - p2pkh: {}, - broadcastTx: {}, - }; - self.mockedMethods = { p2pkh: {}, p2sh: {} }; - self.manuallyClosed = false; - - // API call mock functions - self.block = async function (blockHashOrHeight) { - return throwOrReturnValue( - self.mockedResponses.block[blockHashOrHeight], - ); - }; - self.blockTxs = async function ( - hashOrHeight, - pageNumber = 0, - pageSize = CHRONIK_DEFAULT_PAGESIZE, - ) { - if ( - self.mockedResponses[hashOrHeight].txHistory instanceof - Error - ) { - throw self.mockedResponses[hashOrHeight].txHistory; - } - return self.getTxHistory( - pageNumber, - pageSize, - self.mockedResponses[hashOrHeight].txHistory, - ); - }; - self.tx = async function (txid) { - return throwOrReturnValue(self.mockedResponses.tx[txid]); - }; - self.token = async function (tokenId) { - return throwOrReturnValue(self.mockedResponses.token[tokenId]); - }; - self.broadcastTx = async function (txHex) { - return throwOrReturnValue( - self.mockedResponses.broadcastTx[txHex], - ); - }; - self.blockchainInfo = async function () { - return throwOrReturnValue(self.mockedResponses.blockchainInfo); - }; - - // Return assigned script mocks - self.script = function (type, hash) { - return self.mockedMethods[type][hash]; - }; - - // Return assigned address mocks - self.address = function (address) { - return self.mockedMethods[address]; - }; - - // Return assigned tokenId mocks - self.tokenId = function (tokenId) { - return self.mockedMethods[tokenId]; - }; - - // Return assigned lokadId mocks - self.lokadId = function (lokadId) { - return self.mockedMethods[lokadId]; - }; - - // Checks whether the user set this mock response to be an error. - // If so, throw it to simulate an API error response. - function throwOrReturnValue(mockResponse) { - if (mockResponse instanceof Error) { - throw mockResponse; - } - return mockResponse; - } - - // Flags to check if ws methods have been called - self.wsSubscribeCalled = false; - self.wsWaitForOpenCalled = false; - - // Websocket mocks - self.ws = function (wsObj) { - if (wsObj !== null) { - const returnedWs = { - onMessage: wsObj.onMessage, // may be undefined - onConnect: wsObj.onConnect, // may be undefined - onReconnect: wsObj.onReconnect, // may be undefined - onEnd: wsObj.onEnd, // may be undefined - autoReconnect: wsObj.autoReconnect || true, // default to true if unset - manuallyClosed: false, - subs: { - blocks: false, - tokens: [], - lokadIds: [], - scripts: [], - }, - isSubscribedBlocks: false, - waitForOpen: async function () { - self.wsWaitForOpenCalled = true; - }, - // Note: subscribe is a legacy NNG method - subscribe: function (type, hash) { - this.subs.scripts.push({ - scriptType: type, - scriptPayload: hash, - }); - self.wsSubscribeCalled = true; - }, - // Note: unsubscribe is a legacy NNG method - unsubscribe: function (type, hash) { - const thisSubInSubsIndex = - this.subs.scripts.findIndex( - sub => - sub.scriptType === type && - sub.scriptPayload === hash, - ); - - if (typeof thisSubInSubsIndex !== 'undefined') { - // Remove from subs - this.subs.scripts.splice(thisSubInSubsIndex, 1); - } - // Otherwise do nothing - }, - subscribeToScript: function (type, hash) { - // in-node only - if (Array.isArray(this.subs)) { - this.subs = { scripts: [] }; - } - this.subs.scripts.push({ - scriptType: type, - payload: hash, - }); - self.wsSubscribeCalled = true; - }, - unsubscribeFromScript: function (type, hash) { - const thisSubInSubsIndex = - this.subs.scripts.findIndex( - sub => - sub.scriptType === type && - sub.payload === hash, - ); - - if (typeof thisSubInSubsIndex !== 'undefined') { - // Remove from subs - this.subs.scripts.splice(thisSubInSubsIndex, 1); - } - // Otherwise do nothing - }, - subscribeToAddress: function (address) { - // in-node only - if (Array.isArray(this.subs)) { - this.subs = { scripts: [] }; - } - const { type, hash } = cashaddr.decode( - address, - true, - ); - this.subs.scripts.push({ - scriptType: type, - payload: hash, - }); - }, - unsubscribeFromAddress: function (address) { - const { type, hash } = cashaddr.decode( - address, - true, - ); - // Find the requested unsub script and remove it - const unsubIndex = this.subs.scripts.findIndex( - sub => - sub.scriptType === type && - sub.payload === hash, - ); - if (unsubIndex === -1) { - // If we cannot find this subscription in this.subs, throw an error - // We do not want an app developer thinking they have unsubscribed from something - throw new Error( - `No existing sub at ${type}, ${hash}`, - ); - } - - // Remove the requested subscription from this.subs - this.subs.scripts.splice(unsubIndex, 1); - }, - subscribeToBlocks: function () { - this.subs.blocks = true; - }, - unsubscribeFromBlocks: function () { - this.subs.blocks = false; - }, - }; - return returnedWs; - } - }; - self.wsClose = function () { - self.manuallyClosed = true; - }; - - // Allow user to set expected chronik call response - self.setMock = function (call, options) { - // e.g. ('block', {input: '', output: ''}) - const { input, output } = options; - if (input) { - self.mockedResponses[call][input] = output; - } else { - self.mockedResponses[call] = output; - } - }; - - // script calls need to be set differently - self.setTxHistory = function (type, hash, txHistory) { - self.mockedResponses[type][hash].txHistory = txHistory; - }; - - self.setTxHistoryByAddress = function (address, txHistory) { - self.mockedResponses[address].txHistory = txHistory; - }; - - self.setTxHistoryByTokenId = function (tokenId, txHistory) { - self.mockedResponses[tokenId].txHistory = txHistory; - }; - - self.setTxHistoryByLokadId = function (lokadId, txHistory) { - self.mockedResponses[lokadId].txHistory = txHistory; - }; - - self.setTxHistoryByBlock = function (hashOrHeight, txHistory) { - // Set all expected tx history as array where it can be accessed by mock method - self.mockedResponses[hashOrHeight] = { txHistory }; - }; - - /** - * Set utxos to custom response; must be called after setScript - * @param {string} type 'p2sh' or 'p2pkh' - * @param {string} hash hash of an eCash address - * @param {array} utxos mocked response of chronik.script(type,hash).utxos() - */ - self.setUtxos = function (type, hash, utxos) { - self.mockedResponses[type][hash].utxos = utxos; - }; - - /** - * Set utxos to custom response; must be called after setAddress - * @param {string} address 'p2sh' or 'p2pkh' address - * @param {array} utxos mocked response of chronik.address(address).utxos() - */ - self.setUtxosByAddress = function (address, utxos) { - self.mockedResponses[address].utxos = utxos; - }; - - /** - * Set utxos to custom response; must be called after setTokenId - * @param {string} tokenId a tokenId - * @param {array} utxos mocked response of chronik.tokenId(tokenId).utxos() - */ - self.setUtxosByTokenId = function (tokenId, utxos) { - self.mockedResponses[tokenId].utxos = utxos; - }; - - // Allow users to set expected chronik script call responses - self.setScript = function (type, hash) { - // Initialize object that will hold utxos if set - self.mockedResponses[type][hash] = {}; - - self.mockedMethods[type][hash] = { - history: async function ( - pageNumber = 0, - pageSize = CHRONIK_DEFAULT_PAGESIZE, - ) { - if ( - self.mockedResponses[type][hash] - .txHistory instanceof Error - ) { - throw self.mockedResponses[type][hash].txHistory; - } - return self.getTxHistory( - pageNumber, - pageSize, - self.mockedResponses[type][hash].txHistory, - ); - }, - utxos: async function () { - return throwOrReturnValue( - self.mockedResponses[type][hash].utxos, - ); - }, - }; - }; - - // Allow users to set expected chronik address call responses - self.setAddress = function (address) { - // Initialize object that will hold utxos if set - self.mockedResponses[address] = {}; - - self.mockedMethods[address] = { - history: async function ( - pageNumber = 0, - pageSize = CHRONIK_DEFAULT_PAGESIZE, - ) { - if ( - self.mockedResponses[address].txHistory instanceof - Error - ) { - throw self.mockedResponses[address].txHistory; - } - return self.getTxHistory( - pageNumber, - pageSize, - self.mockedResponses[address].txHistory, - ); - }, - utxos: async function () { - return throwOrReturnValue( - self.mockedResponses[address].utxos, - ); - }, - }; - }; - - // Allow users to set expected chronik tokenId call responses - self.setTokenId = function (tokenId) { - // Initialize object that will hold utxos if set - self.mockedResponses[tokenId] = {}; - - self.mockedMethods[tokenId] = { - history: async function ( - pageNumber = 0, - pageSize = CHRONIK_DEFAULT_PAGESIZE, - ) { - if ( - self.mockedResponses[tokenId].txHistory instanceof - Error - ) { - throw self.mockedResponses[tokenId].txHistory; - } - return self.getTxHistory( - pageNumber, - pageSize, - self.mockedResponses[tokenId].txHistory, - ); - }, - utxos: async function () { - return throwOrReturnValue( - self.mockedResponses[tokenId].utxos, - ); - }, - }; - }; - - // Allow users to set expected chronik lokadId call responses - self.setLokadId = function (lokadId) { - // Initialize object that will hold utxos if set - self.mockedResponses[lokadId] = {}; - - self.mockedMethods[lokadId] = { - history: async function ( - pageNumber = 0, - pageSize = CHRONIK_DEFAULT_PAGESIZE, - ) { - if ( - self.mockedResponses[lokadId].txHistory instanceof - Error - ) { - throw self.mockedResponses[lokadId].txHistory; - } - return self.getTxHistory( - pageNumber, - pageSize, - self.mockedResponses[lokadId].txHistory, - ); - }, - }; - }; - } - // Method to get paginated tx history with same variables as chronik - getTxHistory(pageNumber = 0, pageSize, txHistory) { - // Return chronik shaped responses - const startSliceOnePage = pageNumber * pageSize; - const endSliceOnePage = startSliceOnePage + pageSize; - const thisPage = txHistory.slice( - startSliceOnePage, - endSliceOnePage, - ); - const response = {}; - - response.txs = thisPage; - response.numPages = Math.ceil(txHistory.length / pageSize); - response.numTxs = txHistory.length; - return response; - } - }, -}; diff --git a/modules/mock-chronik-client/index.test.ts b/modules/mock-chronik-client/index.test.ts new file mode 100644 --- /dev/null +++ b/modules/mock-chronik-client/index.test.ts @@ -0,0 +1,375 @@ +// Copyright (c) 2023 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +import * as chai from 'chai'; +import chaiAsPromised from 'chai-as-promised'; +import { MockChronikClient, MockAgora } from './index'; +import mocks from './mocks'; +import * as cashaddr from 'ecashaddrjs'; + +const expect = chai.expect; +chai.use(chaiAsPromised); + +describe('MockAgora', () => { + let mockAgora: MockAgora; + const agoraError = new Error('some agora error'); + beforeEach(() => { + mockAgora = new MockAgora(); + }); + it('We can set and get offeredGroupTokenIds', async () => { + const tokenIds = ['a', 'b', 'c']; + mockAgora.setOfferedGroupTokenIds(tokenIds); + expect(await mockAgora.offeredGroupTokenIds()).to.deep.equal(tokenIds); + // And force a thrown error + mockAgora.setOfferedGroupTokenIds(agoraError); + await expect(mockAgora.offeredGroupTokenIds()).to.be.rejectedWith( + agoraError, + ); + }); + it('We can set and get offeredFungibleTokenIds', async () => { + const tokenIds = ['a', 'b', 'c']; + mockAgora.setOfferedFungibleTokenIds(tokenIds); + expect(await mockAgora.offeredFungibleTokenIds()).to.deep.equal( + tokenIds, + ); + // And force a thrown error + mockAgora.setOfferedFungibleTokenIds(agoraError); + await expect(mockAgora.offeredFungibleTokenIds()).to.be.rejectedWith( + agoraError, + ); + }); + it('We can set and get activeOffersByPubKey', async () => { + const pk = 'pk'; + const mockOffers = [{ test: 'a' }]; + mockAgora.setActiveOffersByPubKey(pk, mockOffers); + expect(await mockAgora.activeOffersByPubKey(pk)).to.deep.equal( + mockOffers, + ); + // And force a thrown error + mockAgora.setActiveOffersByPubKey(pk, agoraError); + await expect(mockAgora.activeOffersByPubKey(pk)).to.be.rejectedWith( + agoraError, + ); + }); + it('We can set and get activeOffersByGroupTokenId', async () => { + const groupTokenId = '00'.repeat(32); + const mockOffers = [{ test: 'a' }]; + mockAgora.setActiveOffersByGroupTokenId(groupTokenId, mockOffers); + expect( + await mockAgora.activeOffersByGroupTokenId(groupTokenId), + ).to.deep.equal(mockOffers); + // And force a thrown error + mockAgora.setActiveOffersByGroupTokenId(groupTokenId, agoraError); + await expect( + mockAgora.activeOffersByGroupTokenId(groupTokenId), + ).to.be.rejectedWith(agoraError); + }); + it('We can set and get activeOffersByTokenId', async () => { + const tokenId = '00'.repeat(32); + const mockOffers = [{ test: 'a' }]; + mockAgora.setActiveOffersByTokenId(tokenId, mockOffers); + expect(await mockAgora.activeOffersByTokenId(tokenId)).to.deep.equal( + mockOffers, + ); + // And force a thrown error + mockAgora.setActiveOffersByTokenId(tokenId, agoraError); + await expect( + mockAgora.activeOffersByTokenId(tokenId), + ).to.be.rejectedWith(agoraError); + }); +}); +describe('MockChronikClient', () => { + let mockChronik: MockChronikClient; + const chronikError = new Error('some chronik error'); + beforeEach(() => { + mockChronik = new MockChronikClient(); + }); + it('We can set and get a Block by height', async () => { + const { tipHeight, block } = mocks; + mockChronik.setBlock(tipHeight, block); + expect(await mockChronik.block(tipHeight)).to.deep.equal(block); + // And force a thrown error + mockChronik.setBlock(tipHeight, chronikError); + await expect(mockChronik.block(tipHeight)).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get a Block by hash', async () => { + const { tipHash, block } = mocks; + mockChronik.setBlock(tipHash, block); + expect(await mockChronik.block(tipHash)).to.deep.equal(block); + // And force a thrown error + mockChronik.setBlock(tipHash, chronikError); + await expect(mockChronik.block(tipHash)).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get BlockchainInfo', async () => { + mockChronik.setBlockchainInfo(mocks.blockchainInfo); + expect(await mockChronik.blockchainInfo()).to.deep.equal( + mocks.blockchainInfo, + ); + // And force a thrown error + mockChronik.setBlockchainInfo(chronikError); + await expect(mockChronik.blockchainInfo()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get chronikInfo', async () => { + const versionInfo = { version: '1.0.0' }; + mockChronik.setChronikInfo(versionInfo); + expect(await mockChronik.chronikInfo()).to.deep.equal(versionInfo); + // And force a thrown error + mockChronik.setChronikInfo(chronikError); + await expect(mockChronik.chronikInfo()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get a Tx by txid', async () => { + const { txid, tx } = mocks; + mockChronik.setTx(txid, tx); + expect(await mockChronik.tx(txid)).to.deep.equal(tx); + // And force a thrown error + mockChronik.setTx(txid, chronikError); + await expect(mockChronik.tx(txid)).to.be.rejectedWith(chronikError); + }); + it('We can set and get a Token by tokenId', async () => { + const { tokenId, token } = mocks; + mockChronik.setToken(tokenId, token); + expect(await mockChronik.token(tokenId)).to.deep.equal(token); + // And force a thrown error + mockChronik.setToken(tokenId, chronikError); + await expect(mockChronik.token(tokenId)).to.be.rejectedWith( + chronikError, + ); + }); + it('We can mock broadcasting a rawTx and getting its txid', async () => { + const { txid, rawTx } = mocks; + mockChronik.setBroadcastTx(rawTx, txid); + expect(await mockChronik.broadcastTx(rawTx)).to.deep.equal({ txid }); + + // And force a thrown error + mockChronik.setBroadcastTx(rawTx, chronikError); + await expect(mockChronik.broadcastTx(rawTx)).to.be.rejectedWith( + chronikError, + ); + }); + it('We can mock broadcasting an array of rawTxs and getting txids', async () => { + const { txid, rawTx } = mocks; + // We still set them one at a time + mockChronik.setBroadcastTx(rawTx, txid); + expect( + await mockChronik.broadcastTxs([rawTx, rawTx, rawTx]), + ).to.deep.equal([{ txid }, { txid }, { txid }]); + + // And force a thrown error + mockChronik.setBroadcastTx(rawTx, chronikError); + await expect(mockChronik.broadcastTxs([rawTx])).to.be.rejectedWith( + chronikError, + ); + }); + it('We can test websocket methods', async () => { + // Create websocket subscription to listen to confirmations on txid + const ws = mockChronik.ws({ + onMessage: msg => { + console.log(`msg`, msg); + }, + }); + + // Wait for WS to be connected: + await ws.waitForOpen(); + expect(ws.waitForOpenCalled).to.equal(true); + + // We can test if a websocket was closed by calling wsClose() (aka "manually closed") + ws.close(); + expect(ws.manuallyClosed).to.equal(true); + + // We can subscribe to blocks + ws.subscribeToBlocks(); + expect(ws.subs.blocks).to.equal(true); + + // We can unsubscribe from blocks + ws.unsubscribeFromBlocks(); + expect(ws.subs.blocks).to.equal(false); + + // We can subscribe to a script + const scriptType = 'p2pkh'; + const payload = '00'.repeat(20); + ws.subscribeToScript(scriptType, payload); + expect(ws.subs.scripts).to.deep.equal([{ scriptType, payload }]); + + // We can unsubscribe from a script + ws.unsubscribeFromScript(scriptType, payload); + expect(ws.subs.scripts).to.deep.equal([]); + + // We can subscribe to an address + const addr = cashaddr.encode('ecash', scriptType, payload); + ws.subscribeToAddress(addr); + expect(ws.subs.scripts).to.deep.equal([{ scriptType, payload }]); + + // We can unsubscribe from an address + ws.unsubscribeFromAddress(addr); + expect(ws.subs.scripts).to.deep.equal([]); + + const tokenId = '00'.repeat(32); + + // We can subscribe to a token by tokenId + ws.subscribeToTokenId(tokenId); + expect(ws.subs.tokens).to.deep.equal([tokenId]); + + // We can unsubscribe from a tokenid + ws.unsubscribeFromTokenId(tokenId); + expect(ws.subs.tokens).to.deep.equal([]); + + const lokadId = '00'.repeat(2); + + // We can subscribe to a token by lokadId + ws.subscribeToLokadId(lokadId); + expect(ws.subs.lokadIds).to.deep.equal([lokadId]); + + // We can unsubscribe from a lokadId + ws.unsubscribeFromLokadId(lokadId); + expect(ws.subs.lokadIds).to.deep.equal([]); + + // We can subscribe to a plugin + ws.subscribeToPlugin('name', 'group'); + expect(ws.subs.plugins).to.deep.equal([ + { group: 'group', pluginName: 'name' }, + ]); + + // We can unsubscribe from a plugin + ws.unsubscribeFromPlugin('name', 'group'); + expect(ws.subs.plugins).to.deep.equal([]); + }); + it('We can set and get tx history by script', async () => { + const { tx } = mocks; + const type = 'p2pkh'; + const hash = '00'.repeat(20); + mockChronik.setTxHistoryByScript(type, hash, [tx]); + expect(await mockChronik.script(type, hash).history()).to.deep.equal({ + txs: [tx], + numPages: 1, + numTxs: 1, + }); + mockChronik.setTxHistoryByScript(type, hash, chronikError); + await expect( + mockChronik.script(type, hash).history(), + ).to.be.rejectedWith(chronikError); + }); + it('We can set and get utxos by script', async () => { + const { utxo } = mocks; + const type = 'p2pkh'; + const hash = '00'.repeat(20); + mockChronik.setUtxosByScript(type, hash, [utxo]); + expect(await mockChronik.script(type, hash).utxos()).to.deep.equal({ + outputScript: `76a914${hash}88ac`, + utxos: [utxo], + }); + mockChronik.setUtxosByScript(type, hash, chronikError); + await expect(mockChronik.script(type, hash).utxos()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get tx history by address', async () => { + const { tx } = mocks; + const type = 'p2pkh'; + const hash = '00'.repeat(20); + const address = cashaddr.encode('ecash', type, hash); + mockChronik.setTxHistoryByAddress(address, [tx]); + expect(await mockChronik.address(address).history()).to.deep.equal({ + txs: [tx], + numPages: 1, + numTxs: 1, + }); + mockChronik.setTxHistoryByAddress(address, chronikError); + await expect(mockChronik.address(address).history()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get utxos by address', async () => { + const { utxo, scriptUtxo } = mocks; + const type = 'p2pkh'; + const hash = '00'.repeat(20); + const address = cashaddr.encode('ecash', type, hash); + mockChronik.setUtxosByAddress(address, [utxo]); + expect(await mockChronik.address(address).utxos()).to.deep.equal({ + outputScript: `76a914${hash}88ac`, + utxos: [utxo], + }); + mockChronik.setUtxosByAddress(address, chronikError); + await expect(mockChronik.address(address).utxos()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get tx history by tokenId', async () => { + const { tx } = mocks; + const tokenId = '00'.repeat(32); + mockChronik.setTxHistoryByTokenId(tokenId, [tx]); + expect(await mockChronik.tokenId(tokenId).history()).to.deep.equal({ + txs: [tx], + numPages: 1, + numTxs: 1, + }); + mockChronik.setTxHistoryByTokenId(tokenId, chronikError); + await expect(mockChronik.tokenId(tokenId).history()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get utxos by tokenId', async () => { + const { utxo } = mocks; + const tokenId = '00'.repeat(32); + mockChronik.setUtxosByTokenId(tokenId, [utxo]); + expect(await mockChronik.tokenId(tokenId).utxos()).to.deep.equal({ + tokenId, + utxos: [utxo], + }); + mockChronik.setUtxosByTokenId(tokenId, chronikError); + await expect(mockChronik.tokenId(tokenId).utxos()).to.be.rejectedWith( + chronikError, + ); + }); + it('We can set and get tx history by lokadId', async () => { + // NB we cannot set and get utxos by lokadId, this is not available in chronik-client + const { tx } = mocks; + const lokadId = '00'.repeat(2); + mockChronik.setTxHistoryByLokadId(lokadId, [tx]); + expect(await mockChronik.lokadId(lokadId).history()).to.deep.equal({ + txs: [tx], + numPages: 1, + numTxs: 1, + }); + mockChronik.setTxHistoryByLokadId(lokadId, chronikError); + await expect(mockChronik.lokadId(lokadId).history()).to.be.rejectedWith( + chronikError, + ); + }); + context('Integration tests', () => { + it('We can set utxos and then tx history at the same address without overwriting the utxos', async () => { + const { utxo, scriptUtxo } = mocks; + const type = 'p2pkh'; + const hash = '00'.repeat(20); + const address = cashaddr.encode('ecash', type, hash); + mockChronik.setUtxosByAddress(address, [utxo]); + expect(await mockChronik.address(address).utxos()).to.deep.equal({ + outputScript: `76a914${hash}88ac`, + utxos: [utxo], + }); + + const { tx } = mocks; + const tokenId = '00'.repeat(32); + mockChronik.setTxHistoryByTokenId(tokenId, [tx]); + expect(await mockChronik.tokenId(tokenId).history()).to.deep.equal({ + txs: [tx], + numPages: 1, + numTxs: 1, + }); + + // Setting the tx history did not overwrite the utxos + expect(await mockChronik.address(address).utxos()).to.deep.equal({ + outputScript: `76a914${hash}88ac`, + utxos: [utxo], + }); + }); + }); +}); diff --git a/modules/mock-chronik-client/index.ts b/modules/mock-chronik-client/index.ts new file mode 100644 --- /dev/null +++ b/modules/mock-chronik-client/index.ts @@ -0,0 +1,926 @@ +// Copyright (c) 2023 The Bitcoin developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. +import * as cashaddr from 'ecashaddrjs'; +import { + Block, + TxHistoryPage, + Tx, + TokenInfo, + BlockchainInfo, + Utxo, + TokenIdUtxos, + ScriptUtxo, + ScriptUtxos, + WsConfig, + WsMsgClient, + WsSubScriptClient, + WsSubPluginClient, +} from 'chronik-client'; +import * as ws from 'ws'; + +const CHRONIK_DEFAULT_PAGESIZE = 25; + +// Properly this should be AgoraOffer, but the mock will work with anything +// I do not think we should add ecash-agora as a dep just for this type +type MockAgoraOffer = Record<string, any>; + +/** + * MockAgora stores set responses in this object + */ +interface MockAgoraMockResponses { + /** Supported Agora methods in MockAgora */ + offeredGroupTokenIds: string[] | Error; + offeredFungibleTokenIds: string[] | Error; + activeOffersByPubKey: { [key: string]: MockAgoraOffer[] | Error }; + activeOffersByGroupTokenId: { + [key: string]: MockAgoraOffer[] | Error; + }; + activeOffersByTokenId: { + [key: string]: MockAgoraOffer[] | Error; + }; +} + +interface MockAgoraInterface { + mockedResponses: MockAgoraMockResponses; + /** Methods used to set expected responses */ + setOfferedGroupTokenIds: (expectedResponse: string[] | Error) => void; + setOfferedFungibleTokenIds: (expectedResponse: string[] | Error) => void; + setActiveOffersByPubKey: ( + pubKey: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => void; + setActiveOffersByGroupTokenId: ( + groupTokenId: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => void; + setActiveOffersByTokenId: ( + tokenId: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => void; + /** Supported Agora methods */ + offeredGroupTokenIds: () => void; + offeredFungibleTokenIds: () => void; + activeOffersByPubKey: (pubKey: string) => void; + activeOffersByGroupTokenId: (groupTokenId: string) => void; + activeOffersByTokenId: (tokenId: string) => void; +} + +/** + * MockAgora + * Useful test mock for writing unit tests for functions that use the Agora + * class from the ecash-agora library. Drop-in replacement for Agora object + * to unit test functions that accept an intialized Agora object as a param. + * In this way, can write unit tests without hitting an actual chronik API. + * + * Mock calls to chronik nodes indexed with the ecash-agora plugin + * + * See Cashtab and ecash-herald for implementation examples. + * + * Note: not all Agora methods are mocked, can be extended as needed + */ +export class MockAgora implements MockAgoraInterface { + mockedResponses: MockAgoraMockResponses; + + // Agora can make specialized chronik-client calls to a chronik-client instance + // running the agora plugin + // For the purposes of unit testing, we only need to re-create how this object + // is initialized and support getting and setting of expected responses + constructor() { + // API call mock return objects + // Can be set with self.setMock + this.mockedResponses = { + offeredGroupTokenIds: [], + offeredFungibleTokenIds: [], + activeOffersByPubKey: {}, + activeOffersByGroupTokenId: {}, + activeOffersByTokenId: {}, + }; + } + + // Allow user to set supported agora query responses + setOfferedGroupTokenIds = (expectedResponse: string[] | Error) => { + this.mockedResponses.offeredGroupTokenIds = expectedResponse; + }; + setOfferedFungibleTokenIds = (expectedResponse: string[] | Error) => { + this.mockedResponses.offeredFungibleTokenIds = expectedResponse; + }; + setActiveOffersByPubKey = ( + pubKey: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => { + this.mockedResponses.activeOffersByPubKey[pubKey] = expectedResponse; + }; + setActiveOffersByGroupTokenId = ( + groupTokenId: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => { + this.mockedResponses.activeOffersByGroupTokenId[groupTokenId] = + expectedResponse; + }; + setActiveOffersByTokenId = ( + tokenId: string, + expectedResponse: MockAgoraOffer[] | Error, + ) => { + this.mockedResponses.activeOffersByTokenId[tokenId] = expectedResponse; + }; + + offeredGroupTokenIds = async () => { + return this._throwOrReturnValue( + this.mockedResponses.offeredGroupTokenIds, + ); + }; + offeredFungibleTokenIds = async () => { + return this._throwOrReturnValue( + this.mockedResponses.offeredFungibleTokenIds, + ); + }; + activeOffersByPubKey = async (pubKey: string) => { + return this._throwOrReturnValue( + this.mockedResponses.activeOffersByPubKey[pubKey], + ); + }; + activeOffersByGroupTokenId = async (groupTokenId: string) => { + return this._throwOrReturnValue( + this.mockedResponses.activeOffersByGroupTokenId[groupTokenId], + ); + }; + activeOffersByTokenId = async (tokenId: string) => { + return this._throwOrReturnValue( + this.mockedResponses.activeOffersByTokenId[tokenId], + ); + }; + + // Checks whether the user set this mock response to be an error. + // If so, throw it to simulate an API error response. + private _throwOrReturnValue<T>(mockResponse: T): T { + if (mockResponse instanceof Error) { + throw mockResponse; + } + return mockResponse as T; + } +} + +type AddressType = 'p2sh' | 'p2pkh'; + +/** + * Object where we store expected the values we want to get when + * we make ChronikClient calls + */ +interface MockChronikClientMockedResponses { + block: { [key: string | number]: Block | Error }; + blockTxs: { [key: string | number]: { history: Tx[] | Error } }; + tx: { [key: string | number]: Tx | Error }; + token: { [key: string | number]: TokenInfo | Error }; + broadcastTx: { [key: string | number]: { txid: string } | Error }; + blockchainInfo: BlockchainInfo | Error | {}; + chronikInfo: { version: string } | Error; + script: { + p2pkh: { + [key: string | number]: { + history: Tx[] | Error; + utxos: ScriptUtxo[] | Error; + }; + }; + p2sh: { + [key: string | number]: { + history: Tx[] | Error; + utxos: ScriptUtxo[] | Error; + }; + }; + }; + address: { + [key: string | number]: { + history: Tx[] | Error; + utxos: ScriptUtxo[] | Error; + }; + }; + tokenId: { + [key: string | number]: { + history: Tx[] | Error; + // Note that getting utxo by tokenId returns a utxo with script as a key + utxos: Utxo[] | Error; + }; + }; + lokadId: { + [key: string | number]: { + history: Tx[] | Error; + utxos: ScriptUtxo[] | Error; + }; + }; +} + +/** + * Object where we store "deeper" methods + * ChronikClient API supports methods that take params + * So, when we call chronik.address(address).utxos, we + * want the utxos for that address + * And we want to also be able to set and get utxos for + * another address in the mock + */ +interface MockChronikClientMockedMethods { + script: { + p2pkh: { + [key: string]: { + history: ( + pageNumer?: number, + pageSize?: number, + ) => Promise<TxHistoryPage | Error>; + utxos: () => Promise<ScriptUtxos | Error>; + }; + }; + p2sh: { + [key: string]: { + history: ( + pageNumer?: number, + pageSize?: number, + ) => Promise<TxHistoryPage | Error>; + utxos: () => Promise<ScriptUtxos | Error>; + }; + }; + }; + address: { + [key: string]: { + history: ( + pageNumer?: number, + pageSize?: number, + ) => Promise<TxHistoryPage | Error>; + utxos: () => Promise<ScriptUtxos | Error>; + }; + }; + tokenId: { + [key: string]: { + history: ( + pageNumer?: number, + pageSize?: number, + ) => Promise<TxHistoryPage | Error>; + utxos: () => Promise<TokenIdUtxos | Error>; + }; + }; + lokadId: { + [key: string]: { + history: ( + pageNumer?: number, + pageSize?: number, + ) => Promise<TxHistoryPage | Error>; + }; + }; +} + +/** + * MockChronikClient + * Drop-in replacement for ChronikClient in unit tests + * + * See Cashtab, token-server, ecash-herald for implementation + * + * Can set expected return values to test ChronikClient functions + * without hitting an API + */ +export class MockChronikClient { + mockedResponses: MockChronikClientMockedResponses; + mockedMethods: MockChronikClientMockedMethods; + + constructor() { + // API call mock return objects + // Can be set with self.setMock + this.mockedResponses = { + block: {}, + blockTxs: {}, + tx: {}, + token: {}, + blockchainInfo: {}, + chronikInfo: { version: 'unset' }, + address: {}, + tokenId: {}, + lokadId: {}, + script: { p2sh: {}, p2pkh: {} }, + broadcastTx: {}, + }; + this.mockedMethods = { + script: { p2pkh: {}, p2sh: {} }, + address: {}, + tokenId: {}, + lokadId: {}, + }; + } + + // Public methods from ChronikClient that are mocked by MockChronikClient + // Note that there are often peculiar / specific ways to set these mocks + // See tests for examples + block = async (blockHashOrHeight: string | number) => { + return this._throwOrReturnValue( + this.mockedResponses.block[blockHashOrHeight], + ); + }; + + tx = async (txid: string) => { + return this._throwOrReturnValue(this.mockedResponses.tx[txid]); + }; + + token = async (tokenId: string) => { + return this._throwOrReturnValue(this.mockedResponses.token[tokenId]); + }; + + blockTxs = async ( + hashOrHeight: number | string, + pageNumber = 0, + pageSize = CHRONIK_DEFAULT_PAGESIZE, + ) => { + if ( + this.mockedResponses.blockTxs[hashOrHeight].history instanceof Error + ) { + throw this.mockedResponses.blockTxs[hashOrHeight].history; + } + return this._getTxHistory( + pageNumber, + pageSize, + this.mockedResponses.blockTxs[hashOrHeight].history as Tx[], + ); + }; + + broadcastTx = async (txHex: string) => { + return this._throwOrReturnValue( + this.mockedResponses.broadcastTx[txHex], + ); + }; + broadcastTxs = async (txsHex: string[]) => { + const returns = []; + for (const txHex of txsHex) { + if (this.mockedResponses.broadcastTx[txHex] instanceof Error) { + throw this.mockedResponses.broadcastTx[txHex]; + } else { + returns.push(this.mockedResponses.broadcastTx[txHex]); + } + } + return returns; + }; + blockchainInfo = async () => { + return this._throwOrReturnValue(this.mockedResponses.blockchainInfo); + }; + + // Return assigned script mocks + script = (type: AddressType, hash: string) => { + return this.mockedMethods.script[type][hash]; + }; + + // Return assigned address mocked methods + address = (address: string) => { + return this.mockedMethods.address[address]; + }; + + // Return assigned tokenId mocked methods + tokenId = (tokenId: string) => { + return this.mockedMethods.tokenId[tokenId]; + }; + + // Return assigned lokadId mocked methods + lokadId = (lokadId: string) => { + return this.mockedMethods.lokadId[lokadId]; + }; + + // Websocket mocks + ws = (wsConfig: WsConfig) => { + const returnedWs = new MockWsEndpoint(wsConfig); + return returnedWs; + }; + + setBlock = (hashOrHeight: string | number, block: Block | Error) => { + this.mockedResponses.block[hashOrHeight] = block; + }; + + setTx = (txid: string, tx: Tx | Error) => { + this.mockedResponses.tx[txid] = tx; + }; + + setToken = (tokenId: string, token: TokenInfo | Error) => { + this.mockedResponses.token[tokenId] = token; + }; + + setBlockchainInfo = (blockchainInfo: BlockchainInfo | Error) => { + this.mockedResponses.blockchainInfo = blockchainInfo; + }; + + setChronikInfo = (versionInfo: { version: string } | Error) => { + this.mockedResponses.chronikInfo = versionInfo; + }; + chronikInfo = async () => { + return this._throwOrReturnValue(this.mockedResponses.chronikInfo); + }; + + setBroadcastTx = (rawTx: string, txidOrError: string | Error) => { + this.mockedResponses.broadcastTx[rawTx] = + typeof txidOrError === 'string' + ? { txid: txidOrError } + : txidOrError; + }; + + setTxHistoryByScript = ( + type: AddressType, + hash: string, + history: Tx[] | Error, + ) => { + this._setScript(type, hash); + this.mockedResponses.script[type][hash].history = history; + }; + + setTxHistoryByAddress = (address: string, history: Tx[] | Error) => { + this._setAddress(address); + this.mockedResponses.address[address].history = history; + }; + + setTxHistoryByTokenId = (tokenId: string, history: Tx[] | Error) => { + this._setTokenId(tokenId); + this.mockedResponses.tokenId[tokenId].history = history; + }; + + setTxHistoryByLokadId = (lokadId: string, history: Tx[] | Error) => { + this._setLokadId(lokadId); + this.mockedResponses.lokadId[lokadId].history = history; + }; + + setTxHistoryByBlock = ( + hashOrHeight: string | number, + history: Tx[] | Error, + ) => { + // Set all expected tx history as array where it can be accessed by mock method + this.mockedResponses.blockTxs[hashOrHeight] = { history }; + }; + + // Set utxos to custom response; must be called after setScript + setUtxosByScript = ( + type: AddressType, + hash: string, + utxos: ScriptUtxo[] | Error, + ) => { + this._setScript(type, hash); + this.mockedResponses.script[type][hash].utxos = utxos; + }; + + // Set utxos to custom response; must be called after setAddress + setUtxosByAddress = (address: string, utxos: ScriptUtxo[] | Error) => { + this._setAddress(address); + this.mockedResponses.address[address].utxos = utxos; + }; + + // Set utxos to custom response; must be called after setTokenId + setUtxosByTokenId = (tokenId: string, utxos: Utxo[] | Error) => { + this._setTokenId(tokenId); + this.mockedResponses.tokenId[tokenId].utxos = utxos; + }; + + // We need to give mockedChronik a plugin function + // This is required for creating a new Agora(mockedChronik) + plugin = () => 'dummy plugin'; + // Dummy values not supported by MockChronikClient + private _proxyInterface: unknown = {}; + proxyInterface = {}; + // Methods not supported by MockChronikClient + blocks = () => { + console.info('MockChronikClient does not support blocks'); + }; + rawTx = () => { + console.info('MockChronikClient does not support rawTx'); + }; + + // Allow users to set expected chronik address call responses + private _setAddress(address: string) { + // Do not overwrite existing history, but initialize if nothing is there + if (typeof this.mockedResponses.address[address] === 'undefined') { + this.mockedResponses.address[address] = { + history: [], + utxos: [], + }; + } + + this.mockedMethods.address[address] = { + history: async ( + pageNumber = 0, + pageSize = CHRONIK_DEFAULT_PAGESIZE, + ): Promise<TxHistoryPage> => { + if ( + this.mockedResponses.address[address].history instanceof + Error + ) { + throw this.mockedResponses.address[address].history; + } + return this._getTxHistory( + pageNumber, + pageSize, + this.mockedResponses.address[address].history as Tx[], + ); + }, + utxos: async (): Promise<ScriptUtxos> => { + if ( + this.mockedResponses.address[address].utxos instanceof Error + ) { + throw this.mockedResponses.address[address].utxos; + } + return this._getAddressUtxos( + address, + this.mockedResponses.address[address].utxos as ScriptUtxo[], + ); + }, + }; + } + + // Allow users to set expected chronik tokenId call responses + private _setTokenId(tokenId: string) { + if (typeof this.mockedResponses.tokenId[tokenId] === 'undefined') { + this.mockedResponses.tokenId[tokenId] = { + history: [], + utxos: [], + }; + } + + this.mockedMethods.tokenId[tokenId] = { + history: async ( + pageNumber = 0, + pageSize = CHRONIK_DEFAULT_PAGESIZE, + ): Promise<TxHistoryPage> => { + if ( + this.mockedResponses.tokenId[tokenId].history instanceof + Error + ) { + throw this.mockedResponses.tokenId[tokenId].history; + } + return this._getTxHistory( + pageNumber, + pageSize, + this.mockedResponses.tokenId[tokenId].history as Tx[], + ); + }, + utxos: async (): Promise<TokenIdUtxos> => { + if ( + this.mockedResponses.tokenId[tokenId].utxos instanceof Error + ) { + throw this.mockedResponses.tokenId[tokenId].utxos; + } + return this._getTokenIdUtxos( + tokenId, + this.mockedResponses.tokenId[tokenId].utxos as Utxo[], + ); + }, + }; + } + + // Allow users to set expected chronik lokadId call responses + private _setLokadId(lokadId: string) { + if (typeof this.mockedResponses.lokadId[lokadId] === 'undefined') { + this.mockedResponses.lokadId[lokadId] = { + history: [], + utxos: [], + }; + } + + this.mockedMethods.lokadId[lokadId] = { + history: async ( + pageNumber = 0, + pageSize = CHRONIK_DEFAULT_PAGESIZE, + ): Promise<TxHistoryPage> => { + if ( + this.mockedResponses.lokadId[lokadId].history instanceof + Error + ) { + throw this.mockedResponses.lokadId[lokadId].history; + } + return this._getTxHistory( + pageNumber, + pageSize, + this.mockedResponses.lokadId[lokadId].history as Tx[], + ); + }, + }; + } + + private _setScript(type: AddressType, hash: string) { + if (typeof this.mockedResponses.script[type][hash] === 'undefined') { + this.mockedResponses.script[type][hash] = { + history: [], + utxos: [], + }; + } + + this.mockedMethods.script[type][hash] = { + history: async ( + pageNumber = 0, + pageSize = CHRONIK_DEFAULT_PAGESIZE, + ): Promise<TxHistoryPage> => { + if ( + this.mockedResponses.script[type][hash].history instanceof + Error + ) { + throw this.mockedResponses.script[type][hash].history; + } + return this._getTxHistory( + pageNumber, + pageSize, + this.mockedResponses.script[type][hash].history as Tx[], + ); + }, + utxos: async (): Promise<ScriptUtxos> => { + if ( + this.mockedResponses.script[type][hash].utxos instanceof + Error + ) { + throw this.mockedResponses.script[type][hash].utxos; + } + return this._getScriptUtxos( + type, + hash, + this.mockedResponses.script[type][hash] + .utxos as ScriptUtxo[], + ); + }, + }; + } + + private _getScriptUtxos( + type: AddressType, + hash: string, + utxos: ScriptUtxo[], + ): ScriptUtxos { + const outputScript = cashaddr.getOutputScriptFromAddress( + cashaddr.encode('ecash', type, hash), + ); + return { outputScript, utxos }; + } + + private _getAddressUtxos( + address: string, + utxos: ScriptUtxo[], + ): ScriptUtxos { + const outputScript = cashaddr.getOutputScriptFromAddress(address); + return { outputScript, utxos }; + } + private _getTokenIdUtxos(tokenId: string, utxos: Utxo[]): TokenIdUtxos { + return { tokenId, utxos }; + } + + // Method to get paginated tx history with same variables as chronik + private _getTxHistory(pageNumber = 0, pageSize: number, history: Tx[]) { + // Return chronik shaped responses + const startSliceOnePage = pageNumber * pageSize; + const endSliceOnePage = startSliceOnePage + pageSize; + const thisPage = history.slice(startSliceOnePage, endSliceOnePage); + const response: TxHistoryPage = { + txs: [], + numPages: 0, + numTxs: 0, + }; + + response.txs = thisPage; + response.numPages = Math.ceil(history.length / pageSize); + response.numTxs = history.length; + return response; + } + + // Checks whether the user set this mock response to be an error. + // If so, throw it to simulate an API error response. + private _throwOrReturnValue<T>(mockResponse: T): T { + if (mockResponse instanceof Error) { + throw mockResponse; + } + return mockResponse as T; + } +} + +interface WsSubscriptions { + /** Subscriptions to scripts */ + scripts: WsSubScriptClient[]; + /** Subscriptions to tokens by tokenId */ + tokens: string[]; + /** Subscriptions to lokadIds */ + lokadIds: string[]; + /** Subscriptions to plugins */ + plugins: WsSubPluginClient[]; + /** Subscription to blocks */ + blocks: boolean; +} +/** + * Mock WsEndpoint for MockChronikClient. + * Based on WsEndpoint in chronik-client. + * We do not test network functionality + * Useful for testing that methods are called as expected, + * ws is opened and closed as expected, subscriptions are added + * and removed as expected + * + * See Cashtab and token-server tests for implemented examples + */ +export class MockWsEndpoint { + /** Fired when a message is sent from the WebSocket. */ + public onMessage?: (msg: WsMsgClient) => void; + + /** Fired when a connection has been (re)established. */ + public onConnect?: (e: ws.Event) => void; + + /** + * Fired after a connection has been unexpectedly closed, and before a + * reconnection attempt is made. Only fired if `autoReconnect` is true. + */ + public onReconnect?: (e: ws.Event) => void; + + /** Fired when an error with the WebSocket occurs. */ + public onError?: (e: ws.ErrorEvent) => void; + + /** + * Fired after a connection has been manually closed, or if `autoReconnect` + * is false, if the WebSocket disconnects for any reason. + */ + public onEnd?: (e: ws.Event) => void; + + /** Whether to automatically reconnect on disconnect, default true. */ + public autoReconnect: boolean; + + public ws: ws.WebSocket | undefined; + public connected: Promise<ws.Event> | undefined; + public manuallyClosed: boolean; + public waitForOpenCalled: boolean; + public subs: WsSubscriptions; + + constructor(config: WsConfig) { + this.onMessage = config.onMessage; + this.onConnect = config.onConnect; + this.onReconnect = config.onReconnect; + this.onEnd = config.onEnd; + this.autoReconnect = + config.autoReconnect !== undefined ? config.autoReconnect : true; + this.manuallyClosed = false; + + this.subs = { + scripts: [], + tokens: [], + lokadIds: [], + plugins: [], + blocks: false, + }; + this.waitForOpenCalled = false; + } + + /** Wait for the WebSocket to be connected. */ + public async waitForOpen() { + // We just set a flag that tests can use + this.waitForOpenCalled = true; + await this.connected; + } + + /** + * Subscribe to block messages + */ + public subscribeToBlocks() { + this.subs.blocks = true; + this._subUnsubBlocks(false); + } + + /** + * Unsubscribe from block messages + */ + public unsubscribeFromBlocks() { + this.subs.blocks = false; + this._subUnsubBlocks(true); + } + + /** + * Subscribe to the given script type and payload. + * For "p2pkh", `scriptPayload` is the 20 byte public key hash. + */ + public subscribeToScript(type: AddressType, payload: string) { + // Build sub according to chronik expected type + const subscription: WsSubScriptClient = { + scriptType: type, + payload, + }; + + this.subs.scripts.push(subscription as WsSubScriptClient); + } + + /** Unsubscribe from the given script type and payload. */ + public unsubscribeFromScript(type: AddressType, payload: string) { + // Build sub according to chronik expected type + const subscription: WsSubScriptClient = { + scriptType: type, + payload, + }; + + // Find the requested unsub script and remove it + const unsubIndex = this.subs.scripts.findIndex( + sub => sub.scriptType === type && sub.payload === payload, + ); + if (unsubIndex === -1) { + // If we cannot find this subscription in this.subs, throw an error + // We do not want an app developer thinking they have unsubscribed from something + throw new Error(`No existing sub at ${type}, ${payload}`); + } + + // Remove the requested subscription from this.subs + this.subs.scripts.splice(unsubIndex, 1); + } + + /** + * Subscribe to an address + * Method can be used for p2pkh or p2sh addresses + */ + public subscribeToAddress(address: string) { + // Get type and hash + const { type, hash } = cashaddr.decode(address, true); + + // Subscribe to script + this.subscribeToScript(type as 'p2pkh' | 'p2sh', hash as string); + } + + /** Unsubscribe from the given address */ + public unsubscribeFromAddress(address: string) { + // Get type and hash + const { type, hash } = cashaddr.decode(address, true); + + // Unsubscribe from script + this.unsubscribeFromScript(type as 'p2pkh' | 'p2sh', hash as string); + } + + /** Subscribe to a lokadId */ + public subscribeToLokadId(lokadId: string) { + // Update ws.subs to include this lokadId + this.subs.lokadIds.push(lokadId); + } + + /** Unsubscribe from the given lokadId */ + public unsubscribeFromLokadId(lokadId: string) { + // Find the requested unsub lokadId and remove it + const unsubIndex = this.subs.lokadIds.findIndex( + thisLokadId => thisLokadId === lokadId, + ); + if (unsubIndex === -1) { + // If we cannot find this subscription in this.subs.lokadIds, throw an error + // We do not want an app developer thinking they have unsubscribed from something if no action happened + throw new Error(`No existing sub at lokadId "${lokadId}"`); + } + + // Remove the requested lokadId subscription from this.subs.lokadIds + this.subs.lokadIds.splice(unsubIndex, 1); + } + + /** Subscribe to a tokenId */ + public subscribeToTokenId(tokenId: string) { + // Update ws.subs to include this tokenId + this.subs.tokens.push(tokenId); + } + + /** Unsubscribe from the given tokenId */ + public unsubscribeFromTokenId(tokenId: string) { + // Find the requested unsub tokenId and remove it + const unsubIndex = this.subs.tokens.findIndex( + thisTokenId => thisTokenId === tokenId, + ); + if (unsubIndex === -1) { + // If we cannot find this subscription in this.subs.tokens, throw an error + // We do not want an app developer thinking they have unsubscribed from something if no action happened + throw new Error(`No existing sub at tokenId "${tokenId}"`); + } + + // Remove the requested tokenId subscription from this.subs.tokens + this.subs.tokens.splice(unsubIndex, 1); + } + + /** Subscribe to a plugin */ + public subscribeToPlugin(pluginName: string, group: string) { + // Build sub according to chronik expected type + const subscription: WsSubPluginClient = { + pluginName, + group, + }; + + // Update ws.subs to include this plugin + this.subs.plugins.push(subscription); + } + + /** Unsubscribe from the given plugin */ + public unsubscribeFromPlugin(pluginName: string, group: string) { + // Find the requested unsub script and remove it + const unsubIndex = this.subs.plugins.findIndex( + sub => sub.pluginName === pluginName && sub.group === group, + ); + if (unsubIndex === -1) { + // If we cannot find this subscription in this.subs.plugins, throw an error + // We do not want an app developer thinking they have unsubscribed from something + throw new Error( + `No existing sub at pluginName="${pluginName}", group="${group}"`, + ); + } + + // Remove the requested subscription from this.subs.plugins + this.subs.plugins.splice(unsubIndex, 1); + } + + /** + * Close the WebSocket connection and prevent any future reconnection + * attempts. + */ + public close() { + this.manuallyClosed = true; + this.ws?.close(); + } + + private _subUnsubBlocks(isUnsub: boolean) { + // Blocks subscription is empty object + this.subs.blocks = !isUnsub; + } +} diff --git a/modules/mock-chronik-client/mocks/mockChronikResponses.js b/modules/mock-chronik-client/mocks/index.ts rename from modules/mock-chronik-client/mocks/mockChronikResponses.js rename to modules/mock-chronik-client/mocks/index.ts --- a/modules/mock-chronik-client/mocks/mockChronikResponses.js +++ b/modules/mock-chronik-client/mocks/index.ts @@ -2,8 +2,226 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. // @generated -'use strict'; +import { + Block, + BlockchainInfo, + Tx, + TokenInfo, + ScriptUtxo, + Utxo, +} from 'chronik-client'; +interface ChronikMocks { + tipHeight: number; + tipHash: string; + block: Block; + blockchainInfo: BlockchainInfo; + txid: string; + tx: Tx; + tokenId: string; + token: TokenInfo; + rawTx: string; + scriptUtxo: ScriptUtxo; + utxo: Utxo; +} +const DUMMY_SCRIPT_UTXO: ScriptUtxo = { + outpoint: { txid: '00'.repeat(32), outIdx: 0 }, + blockHeight: 800000, + isCoinbase: false, + value: 546, + isFinal: true, +}; +const DUMMY_UTXO: Utxo = { + outpoint: { txid: '00'.repeat(32), outIdx: 0 }, + script: `76a914${'00'.repeat(20)}88ac`, + blockHeight: 800000, + isCoinbase: false, + value: 546, + isFinal: true, +}; +const chronikMocks: ChronikMocks = { + tipHeight: 800000, + tipHash: '0000000000000000115e051672e3d4a6c523598594825a1194862937941296fe', + block: { + blockInfo: { + hash: '0000000000000000115e051672e3d4a6c523598594825a1194862937941296fe', + prevHash: + '0000000000000000023ab587190a05e44cdb76fe1dd7949f6187f1e632d2e123', + height: 800000, + nBits: 403943060, + timestamp: 1688808780, + isFinal: true, + blockSize: 3094, + numTxs: 9, + numInputs: 13, + numOutputs: 26, + sumInputSats: 859760862, + sumCoinbaseOutputSats: 625005728, + sumNormalOutputSats: 859755134, + sumBurnedSats: 0, + }, + }, + blockchainInfo: { + tipHash: + '0000000000000000115e051672e3d4a6c523598594825a1194862937941296fe', + tipHeight: 800000, + }, + txid: '2c1540131fb7611b72ec3ca9a215ac5c408248327d3c5b5ff987cd2a959ee1d2', + tx: { + txid: '2c1540131fb7611b72ec3ca9a215ac5c408248327d3c5b5ff987cd2a959ee1d2', + version: 2, + inputs: [ + { + prevOut: { + txid: '1cb37ece9d9dbc19ef2c6d57766ca3b91bdc3e56d203aa0fc1b41a7268c0c9d2', + outIdx: 2, + }, + inputScript: + '41ebe634094888c4215b8690546b74695a048a9c49c8a5c6efedd940591ec9039e91cf2a6f7836107afbc41bb6e13fb22d99739aeadf1a740f75efea177cfcd86641210353f81d61d41d6e22c73ab449476113dea124afe3972991cd237e654f15950b7c', + value: 546, + sequenceNo: 4294967295, + token: { + tokenId: + 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + tokenType: { + protocol: 'SLP', + type: 'SLP_TOKEN_TYPE_FUNGIBLE', + number: 1, + }, + amount: '455320000', + isMintBaton: false, + entryIdx: 0, + }, + outputScript: + '76a914821407ac2993f8684227004f4086082f3f801da788ac', + }, + { + prevOut: { + txid: '1cb37ece9d9dbc19ef2c6d57766ca3b91bdc3e56d203aa0fc1b41a7268c0c9d2', + outIdx: 3, + }, + inputScript: + '412e7de41834aaf15d16347a59c954cb886d8ec00584bb566252e16f8e1779ce2e4d6ddd91782bd6ba2f695a28ce4115cd0561d27c1ae16b3d8bf77f8186235b1441210353f81d61d41d6e22c73ab449476113dea124afe3972991cd237e654f15950b7c', + value: 94518653, + sequenceNo: 4294967295, + outputScript: + '76a914821407ac2993f8684227004f4086082f3f801da788ac', + }, + ], + outputs: [ + { + value: 0, + outputScript: + '6a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000271008000000001b237ab0', + }, + { + value: 546, + outputScript: + '76a914a805a320360fa685f83605d8e56de6f9d8a7a99988ac', + token: { + tokenId: + 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + tokenType: { + protocol: 'SLP', + type: 'SLP_TOKEN_TYPE_FUNGIBLE', + number: 1, + }, + amount: '10000', + isMintBaton: false, + entryIdx: 0, + }, + }, + { + value: 546, + outputScript: + '76a914821407ac2993f8684227004f4086082f3f801da788ac', + token: { + tokenId: + 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + tokenType: { + protocol: 'SLP', + type: 'SLP_TOKEN_TYPE_FUNGIBLE', + number: 1, + }, + amount: '455310000', + isMintBaton: false, + entryIdx: 0, + }, + spentBy: { + txid: 'b334ad4ee98718707142a7a951163f1cb94817269b55ac840a7b416ce256eecd', + outIdx: 0, + }, + }, + { + value: 94517640, + outputScript: + '76a914821407ac2993f8684227004f4086082f3f801da788ac', + spentBy: { + txid: 'b334ad4ee98718707142a7a951163f1cb94817269b55ac840a7b416ce256eecd', + outIdx: 1, + }, + }, + ], + lockTime: 0, + timeFirstSeen: 0, + size: 467, + isCoinbase: false, + tokenEntries: [ + { + tokenId: + 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + tokenType: { + protocol: 'SLP', + type: 'SLP_TOKEN_TYPE_FUNGIBLE', + number: 1, + }, + txType: 'SEND', + isInvalid: false, + burnSummary: '', + failedColorings: [], + actualBurnAmount: '0', + intentionalBurn: '0', + burnsMintBatons: false, + }, + ], + tokenFailedParsings: [], + tokenStatus: 'TOKEN_STATUS_NORMAL', + isFinal: false, + block: { + height: 866581, + hash: '000000000000000000860f542fac8cbb10614e40ab0f37f90ec4d41b126eb5d9', + timestamp: 1728930658, + }, + }, + tokenId: 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + token: { + tokenId: + 'aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb1', + tokenType: { + protocol: 'SLP', + type: 'SLP_TOKEN_TYPE_FUNGIBLE', + number: 1, + }, + timeFirstSeen: 1711776546, + genesisInfo: { + tokenTicker: 'CACHET', + tokenName: 'Cachet', + url: 'https://cashtab.com/', + decimals: 2, + hash: '', + }, + block: { + height: 838192, + hash: '0000000000000000132232769161d6211f7e6e20cf63b26e5148890aacd26962', + timestamp: 1711779364, + }, + }, + rawTx: '0200000002d2c9c068721ab4c10faa03d2563edc1bb9a36c76576d2cef19bc9d9dce7eb31c020000006441ebe634094888c4215b8690546b74695a048a9c49c8a5c6efedd940591ec9039e91cf2a6f7836107afbc41bb6e13fb22d99739aeadf1a740f75efea177cfcd86641210353f81d61d41d6e22c73ab449476113dea124afe3972991cd237e654f15950b7cffffffffd2c9c068721ab4c10faa03d2563edc1bb9a36c76576d2cef19bc9d9dce7eb31c0300000064412e7de41834aaf15d16347a59c954cb886d8ec00584bb566252e16f8e1779ce2e4d6ddd91782bd6ba2f695a28ce4115cd0561d27c1ae16b3d8bf77f8186235b1441210353f81d61d41d6e22c73ab449476113dea124afe3972991cd237e654f15950b7cffffffff040000000000000000406a04534c500001010453454e4420aed861a31b96934b88c0252ede135cb9700d7649f69191235087a3030e553cb108000000000000271008000000001b237ab022020000000000001976a914a805a320360fa685f83605d8e56de6f9d8a7a99988ac22020000000000001976a914821407ac2993f8684227004f4086082f3f801da788ac8839a205000000001976a914821407ac2993f8684227004f4086082f3f801da788ac00000000', + scriptUtxo: DUMMY_SCRIPT_UTXO, + utxo: DUMMY_UTXO, +}; +export default chronikMocks; +/* module.exports = { mockBlockInfo: { blockInfo: { @@ -627,3 +845,4 @@ mockSendXecNoChangeRawTxHex: '02000000010c8dabdfc27f4e43e4c99e5f5534f7c3465a9036445674fc05bcd8510437a81f000000006b4830450221008c86fe8d3fee5082c4429eef064a2063fcc1ea9216afd88cba1ff8cfe7b7083602204c1655728b1bbfc5ded78d46db00968a67e2f4c7c8072fe808feff4ccfd29d74412102560c43edaa6a058c9096c90ce5d4a3bbbf70fd18b2030d26614bc32379151de9ffffffff0194110000000000001976a9140b7d35fda03544a08e65464d54cfae4257eb6db788ac00000000', }; +*/ diff --git a/modules/mock-chronik-client/package-lock.json b/modules/mock-chronik-client/package-lock.json --- a/modules/mock-chronik-client/package-lock.json +++ b/modules/mock-chronik-client/package-lock.json @@ -1,24 +1,71 @@ { "name": "mock-chronik-client", - "version": "1.12.3", + "version": "2.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mock-chronik-client", - "version": "1.12.3", + "version": "2.0.0", "license": "MIT", "dependencies": { - "ecashaddrjs": "file:../ecashaddrjs" + "chronik-client": "file:../chronik-client", + "ecashaddrjs": "file:../ecashaddrjs", + "ws": "^8.18.0" }, "devDependencies": { - "mocha": "^10.2.0", + "@types/chai": "^5.0.1", + "@types/chai-as-promised": "^8.0.1", + "@types/mocha": "^10.0.10", + "@types/ws": "^8.5.13", + "chai": "^5.1.2", + "chai-as-promised": "^8.0.1", + "eslint": "8.57", + "eslint-plugin-header": "^3.1.1", + "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", - "nyc": "^15.1.0" + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.0" + } + }, + "../chronik-client": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "@types/ws": "^8.2.1", + "axios": "^1.6.3", + "ecashaddrjs": "file:../ecashaddrjs", + "isomorphic-ws": "^4.0.1", + "protobufjs": "^6.8.8", + "ws": "^8.3.0" + }, + "devDependencies": { + "@types/chai": "^4.2.22", + "@types/chai-as-promised": "^7.1.4", + "@types/mocha": "^9.0.0", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "eslint": "^8.37.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-header": "^3.1.1", + "mocha": "^9.1.3", + "mocha-junit-reporter": "^2.2.0", + "mocha-suppress-logs": "^0.3.1", + "prettier": "^2.5.1", + "prettier-plugin-organize-imports": "^2.3.4", + "ts-node": "^10.4.0", + "ts-proto": "^1.92.1", + "typedoc": "^0.22.10", + "typescript": "^4.5.2" } }, "../ecashaddrjs": { - "version": "1.5.8", + "version": "1.6.2", "license": "MIT", "dependencies": { "big-integer": "1.6.36", @@ -28,7 +75,9 @@ "@babel/cli": "^7.21.0", "@babel/core": "^7.21.3", "@babel/preset-env": "^7.20.2", - "babel-loader": "^9.1.2", + "@types/chai": "^5.0.1", + "@types/mocha": "^10.0.7", + "@typescript-eslint/parser": "^8.15.0", "buffer": "^6.0.3", "chai": "^4.3.7", "debug": "^4.3.4", @@ -39,6 +88,8 @@ "mocha-suppress-logs": "^0.3.1", "nyc": "^15.1.0", "random-js": "^2.1.0", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", "webpack": "^5.76.2", "webpack-cli": "^5.0.1" } @@ -486,229 +537,1249 @@ "node": ">=6.9.0" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, + "license": "MIT", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "@jridgewell/trace-mapping": "0.3.9" }, "engines": { - "node": ">=8" + "node": ">=12" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, + "license": "MIT", "dependencies": { - "sprintf-js": "~1.0.2" + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "cpu": [ + "ppc64" + ], "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "node_modules/@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "cpu": [ + "arm" + ], "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "node_modules/@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "node_modules/@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=18" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", - "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "cpu": [ + "arm64" + ], "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", - "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", - "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "node_modules/@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6.0.0" + "node": ">=18" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.19", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", - "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "cpu": [ + "ia32" + ], "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/aggregate-error": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", - "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "cpu": [ + "loong64" + ], "dev": true, - "dependencies": { - "clean-stack": "^2.0.0", - "indent-string": "^4.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "cpu": [ + "mips64el" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "cpu": [ + "ppc64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "cpu": [ + "riscv64" + ], "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=18" } }, - "node_modules/anymatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", - "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "cpu": [ + "s390x" + ], "dev": true, - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/append-transform": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", - "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "node_modules/@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "default-require-extensions": "^3.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/archy": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", - "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", - "dev": true + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "deprecated": "Use @eslint/config-array instead", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "deprecated": "Use @eslint/object-schema instead", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz", + "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.19", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.19.tgz", + "integrity": "sha512-kf37QtfW+Hwx/buWGMPcR60iF9ziHa6r/CZJIHbmcm4+0qrXiVdxegAH0F6yddEVQ7zdkjcGCgCzUu+BcbhQxw==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.1.tgz", + "integrity": "sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*" + } + }, + "node_modules/@types/chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/chai": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.20.0" + } + }, + "node_modules/@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", + "dev": true, + "license": "MITClause", + "dependencies": { + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/visitor-keys/node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true, + "license": "ISC" + }, + "node_modules/acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/append-transform": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", + "integrity": "sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==", + "dev": true, + "dependencies": { + "default-require-extensions": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", + "dev": true + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" }, "node_modules/argparse": { "version": "2.0.1", @@ -716,6 +1787,16 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -806,6 +1887,16 @@ "node": ">=8" } }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -835,6 +1926,36 @@ } ] }, + "node_modules/chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-OIEJtOL8xxJSH8JJWbIoRjybbzR52iFuDHuF8eb+nTPD6tgXLjRqsgnUGqQfFODxYvq5QdirT0pN9dZ0+Gz6rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "check-error": "^2.0.0" + }, + "peerDependencies": { + "chai": ">= 2.1.2 < 6" + } + }, "node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -872,6 +1993,16 @@ "node": "*" } }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, "node_modules/chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -899,6 +2030,10 @@ "fsevents": "~2.3.2" } }, + "node_modules/chronik-client": { + "resolved": "../chronik-client", + "link": true + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -955,6 +2090,13 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -979,12 +2121,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -995,12 +2138,6 @@ } } }, - "node_modules/debug/node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, "node_modules/decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", @@ -1010,6 +2147,23 @@ "node": ">=0.10.0" } }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -1026,14 +2180,28 @@ } }, "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true, + "license": "BSD-3-Clause", "engines": { "node": ">=0.3.1" } }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/ecashaddrjs": { "resolved": "../ecashaddrjs", "link": true @@ -1056,6 +2224,46 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "node_modules/esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "node_modules/escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1077,6 +2285,187 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-plugin-header": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", + "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "eslint": ">=7.7.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", @@ -1090,6 +2479,113 @@ "node": ">=4" } }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -1145,6 +2641,28 @@ "flat": "cli.js" } }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true, + "license": "ISC" + }, "node_modules/foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -1225,6 +2743,19 @@ "node": ">=8.0.0" } }, + "node_modules/get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, "node_modules/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -1294,6 +2825,13 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -1334,6 +2872,43 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -1426,6 +3001,16 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -1664,6 +3249,27 @@ "node": ">=4" } }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -1676,6 +3282,30 @@ "node": ">=6" } }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -1697,6 +3327,13 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, "node_modules/log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -1713,6 +3350,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true, + "license": "MIT" + }, "node_modules/lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -1737,6 +3381,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -1748,11 +3399,36 @@ "is-buffer": "~1.1.6" } }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, + "license": "ISC", "dependencies": { "brace-expansion": "^2.0.1" }, @@ -1776,32 +3452,32 @@ } }, "node_modules/mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "dependencies": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" }, "bin": { "_mocha": "bin/_mocha", @@ -1809,10 +3485,6 @@ }, "engines": { "node": ">= 14.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mochajs" } }, "node_modules/mocha-junit-reporter": { @@ -1831,23 +3503,39 @@ "mocha": ">=2.2.5" } }, + "node_modules/mocha/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "node_modules/nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true, - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } + "license": "MIT" }, "node_modules/node-preload": { "version": "0.2.1", @@ -2044,6 +3732,24 @@ "wrappy": "1" } }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -2110,6 +3816,19 @@ "node": ">=8" } }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -2137,6 +3856,16 @@ "node": ">=8" } }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -2219,6 +3948,16 @@ "node": ">=8" } }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -2231,11 +3970,43 @@ "node": ">=8" } }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", "dev": true, + "license": "MIT", "dependencies": { "safe-buffer": "^5.1.0" } @@ -2288,6 +4059,27 @@ "node": ">=8" } }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -2303,6 +4095,30 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2321,7 +4137,8 @@ "type": "consulting", "url": "https://feross.org/support" } - ] + ], + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -2333,10 +4150,11 @@ } }, "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { "randombytes": "^2.1.0" } @@ -2504,6 +4322,13 @@ "node": "*" } }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, "node_modules/to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2526,6 +4351,106 @@ "node": ">=8.0" } }, + "node_modules/ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "~0.23.0", + "get-tsconfig": "^4.7.5" + }, + "bin": { + "tsx": "dist/cli.mjs" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -2541,9 +4466,53 @@ "integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==", "dev": true, "dependencies": { - "is-typedarray": "^1.0.0" + "is-typedarray": "^1.0.0" + } + }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.0.tgz", + "integrity": "sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.18.0", + "@typescript-eslint/parser": "8.18.0", + "@typescript-eslint/utils": "8.18.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.8.0" } }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true, + "license": "MIT" + }, "node_modules/update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -2574,6 +4543,16 @@ "browserslist": ">= 4.21.0" } }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, "node_modules/uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", @@ -2583,6 +4562,13 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -2604,11 +4590,22 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", - "dev": true + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", + "dev": true, + "license": "Apache-2.0" }, "node_modules/wrap-ansi": { "version": "7.0.0", @@ -2645,6 +4642,27 @@ "typedarray-to-buffer": "^3.1.5" } }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -2685,10 +4703,11 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, + "license": "ISC", "engines": { "node": ">=10" } @@ -2732,6 +4751,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", @@ -2955,137 +4984,444 @@ "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "dev": true }, - "@babel/helper-validator-option": { - "version": "7.22.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", - "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", - "dev": true + "@babel/helper-validator-option": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.22.5.tgz", + "integrity": "sha512-R3oB6xlIVKUnxNUxbmgq7pKjxpru24zlimpE8WK47fACIlM0II/Hm1RS8IaOI7NgCr6LNS+jl5l75m20npAziw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.22.11", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", + "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", + "dev": true, + "requires": { + "@babel/template": "^7.22.5", + "@babel/traverse": "^7.22.11", + "@babel/types": "^7.22.11" + } + }, + "@babel/highlight": { + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", + "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.5", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@babel/parser": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "dev": true + }, + "@babel/template": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" + } + }, + "@babel/traverse": { + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@esbuild/aix-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.1.tgz", + "integrity": "sha512-6VhYk1diRqrhBAqpJEdjASR/+WVRtfjpqKuNw11cLiaWpAT/Uu+nokB+UJnevzy/P9C/ty6AOe0dwueMrGh/iQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.1.tgz", + "integrity": "sha512-uz6/tEy2IFm9RYOyvKl88zdzZfwEfKZmnX9Cj1BHjeSGNuGLuMD1kR8y5bteYmwqKm1tj8m4cb/aKEorr6fHWQ==", + "dev": true, + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.1.tgz", + "integrity": "sha512-xw50ipykXcLstLeWH7WRdQuysJqejuAGPd30vd1i5zSyKK3WE+ijzHmLKxdiCMtH1pHz78rOg0BKSYOSB/2Khw==", + "dev": true, + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.1.tgz", + "integrity": "sha512-nlN9B69St9BwUoB+jkyU090bru8L0NA3yFvAd7k8dNsVH8bi9a8cUAUSEcEEgTp2z3dbEDGJGfP6VUnkQnlReg==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.1.tgz", + "integrity": "sha512-YsS2e3Wtgnw7Wq53XXBLcV6JhRsEq8hkfg91ESVadIrzr9wO6jJDMZnCQbHm1Guc5t/CdDiFSSfWP58FNuvT3Q==", + "dev": true, + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.1.tgz", + "integrity": "sha512-aClqdgTDVPSEGgoCS8QDG37Gu8yc9lTHNAQlsztQ6ENetKEO//b8y31MMu2ZaPbn4kVsIABzVLXYLhCGekGDqw==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.1.tgz", + "integrity": "sha512-h1k6yS8/pN/NHlMl5+v4XPfikhJulk4G+tKGFIOwURBSFzE8bixw1ebjluLOjfwtLqY0kewfjLSrO6tN2MgIhA==", + "dev": true, + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.1.tgz", + "integrity": "sha512-lK1eJeyk1ZX8UklqFd/3A60UuZ/6UVfGT2LuGo3Wp4/z7eRTRYY+0xOu2kpClP+vMTi9wKOfXi2vjUpO1Ro76g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.1.tgz", + "integrity": "sha512-CXXkzgn+dXAPs3WBwE+Kvnrf4WECwBdfjfeYHpMeVxWE0EceB6vhWGShs6wi0IYEqMSIzdOF1XjQ/Mkm5d7ZdQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.1.tgz", + "integrity": "sha512-/93bf2yxencYDnItMYV/v116zff6UyTjo4EtEQjUBeGiVpMmffDNUyD9UN2zV+V3LRV3/on4xdZ26NKzn6754g==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.1.tgz", + "integrity": "sha512-VTN4EuOHwXEkXzX5nTvVY4s7E/Krz7COC8xkftbbKRYAl96vPiUssGkeMELQMOnLOJ8k3BY1+ZY52tttZnHcXQ==", + "dev": true, + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.1.tgz", + "integrity": "sha512-Vx09LzEoBa5zDnieH8LSMRToj7ir/Jeq0Gu6qJ/1GcBq9GkfoEAoXvLiW1U9J1qE/Y/Oyaq33w5p2ZWrNNHNEw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.1.tgz", + "integrity": "sha512-nrFzzMQ7W4WRLNUOU5dlWAqa6yVeI0P78WKGUo7lg2HShq/yx+UYkeNSE0SSfSure0SqgnsxPvmAUu/vu0E+3Q==", + "dev": true, + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.1.tgz", + "integrity": "sha512-dKN8fgVqd0vUIjxuJI6P/9SSSe/mB9rvA98CSH2sJnlZ/OCZWO1DJvxj8jvKTfYUdGfcq2dDxoKaC6bHuTlgcw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.1.tgz", + "integrity": "sha512-5AV4Pzp80fhHL83JM6LoA6pTQVWgB1HovMBsLQ9OZWLDqVY8MVobBXNSmAJi//Csh6tcY7e7Lny2Hg1tElMjIA==", + "dev": true, + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.1.tgz", + "integrity": "sha512-9ygs73tuFCe6f6m/Tb+9LtYxWR4c9yg7zjt2cYkjDbDpV/xVn+68cQxMXCjUpYwEkze2RcU/rMnfIXNRFmSoDw==", + "dev": true, + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.1.tgz", + "integrity": "sha512-EV6+ovTsEXCPAp58g2dD68LxoP/wK5pRvgy0J/HxPGB009omFPv3Yet0HiaqvrIrgPTBuC6wCH1LTOY91EO5hQ==", + "dev": true, + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.1.tgz", + "integrity": "sha512-aevEkCNu7KlPRpYLjwmdcuNz6bDFiE7Z8XC4CPqExjTvrHugh28QzUXVOZtiYghciKUacNktqxdpymplil1beA==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.1.tgz", + "integrity": "sha512-3x37szhLexNA4bXhLrCC/LImN/YtWis6WXr1VESlfVtVeoFJBRINPJ3f0a/6LV8zpikqoUg4hyXw0sFBt5Cr+Q==", + "dev": true, + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.1.tgz", + "integrity": "sha512-aY2gMmKmPhxfU+0EdnN+XNtGbjfQgwZj43k8G3fyrDM/UdZww6xrWxmDkuz2eCZchqVeABjV5BpildOrUbBTqA==", + "dev": true, + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.1.tgz", + "integrity": "sha512-RBRT2gqEl0IKQABT4XTj78tpk9v7ehp+mazn2HbUeZl1YMdaGAQqhapjGTCe7uw7y0frDi4gS0uHzhvpFuI1sA==", + "dev": true, + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.1.tgz", + "integrity": "sha512-4O+gPR5rEBe2FpKOVyiJ7wNDPA8nGzDuJ6gN4okSA1gEOYZ67N8JPk58tkWtdtPeLz7lBnY6I5L3jdsr3S+A6A==", + "dev": true, + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.1.tgz", + "integrity": "sha512-BcaL0Vn6QwCwre3Y717nVHZbAa4UBEigzFm6VdsVdT/MbZ38xoj1X9HPkZhbmaBGUD1W8vxAfffbDe8bA6AKnQ==", + "dev": true, + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz", + "integrity": "sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg==", + "dev": true, + "optional": true }, - "@babel/helpers": { - "version": "7.22.11", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.22.11.tgz", - "integrity": "sha512-vyOXC8PBWaGc5h7GMsNx68OH33cypkEDJCHvYVVgVbbxJDROYVtexSk0gK5iCF1xNjRIN2s8ai7hwkWDq5szWg==", + "@eslint-community/eslint-utils": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz", + "integrity": "sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA==", "dev": true, "requires": { - "@babel/template": "^7.22.5", - "@babel/traverse": "^7.22.11", - "@babel/types": "^7.22.11" + "eslint-visitor-keys": "^3.4.3" } }, - "@babel/highlight": { - "version": "7.22.13", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.13.tgz", - "integrity": "sha512-C/BaXcnnvBCmHTpz/VGZ8jgtE2aYlW4hxDhseJAWZb7gqGM/qtCK6iZUb0TyKFf7BOUsBH7Q7fkRsDRhg1XklQ==", + "@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "requires": { - "@babel/helper-validator-identifier": "^7.22.5", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" }, "dependencies": { - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "type-fest": "^0.20.2" } }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "requires": { - "color-name": "1.1.3" + "brace-expansion": "^1.1.7" } }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } } } }, - "@babel/parser": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", - "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", + "@eslint/js": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", + "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", "dev": true }, - "@babel/template": { - "version": "7.22.15", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", - "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", + "@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", "dev": true, "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/parser": "^7.22.15", - "@babel/types": "^7.22.15" + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } } }, - "@babel/traverse": { - "version": "7.23.2", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", - "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.22.13", - "@babel/generator": "^7.23.0", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.22.6", - "@babel/parser": "^7.23.0", - "@babel/types": "^7.23.0", - "debug": "^4.1.0", - "globals": "^11.1.0" - } + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true }, - "@babel/types": { - "version": "7.23.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", - "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", - "dev": true, - "requires": { - "@babel/helper-string-parser": "^7.22.5", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" - } + "@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -3203,6 +5539,253 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "@types/chai": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.0.1.tgz", + "integrity": "sha512-5T8ajsg3M/FOncpLYW7sdOcD6yf4+722sze/tc4KQV0P8Z2rAr3SAuHCIkYmYpt8VbcQlnz8SxlOlPQYefe4cA==", + "dev": true, + "requires": { + "@types/deep-eql": "*" + } + }, + "@types/chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/@types/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-dAlDhLjJlABwAVYObo9TPWYTRg9NaQM5CXeaeJYcYAkvzUf0JRLIiog88ao2Wqy/20WUnhbbUZcgvngEbJ3YXQ==", + "dev": true, + "requires": { + "@types/chai": "*" + } + }, + "@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true + }, + "@types/mocha": { + "version": "10.0.10", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-10.0.10.tgz", + "integrity": "sha512-xPyYSz1cMPnJQhl0CLMH68j3gprKZaTjG3s5Vi+fDgx+uhG9NOXwbVt52eFS8ECyXhyKcjDLCBEqBExKuiZb7Q==", + "dev": true + }, + "@types/node": { + "version": "22.10.1", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.10.1.tgz", + "integrity": "sha512-qKgsUwfHZV2WCWLAnVP1JqnpE6Im6h3Y0+fYgMTasNQ7V++CBX5OT1as0g0f+OyubbFqhf6XVNIsmN4IIhEgGQ==", + "dev": true, + "requires": { + "undici-types": "~6.20.0" + } + }, + "@types/ws": { + "version": "8.5.13", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.13.tgz", + "integrity": "sha512-osM/gWBTPKgHV8XkTunnegTRIsvF6owmf5w+JtAfOw472dptdm0dlGv4xCt6GwQRcC2XVOvvRE/0bAoQcL2QkA==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.0.tgz", + "integrity": "sha512-NR2yS7qUqCL7AIxdJUQf2MKKNDVNaig/dEB0GBLU7D+ZdHgK1NoH/3wsgO3OnPVipn51tG3MAwaODEGil70WEw==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/type-utils": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + } + }, + "@typescript-eslint/parser": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.18.0.tgz", + "integrity": "sha512-hgUZ3kTEpVzKaK3uNibExUYm6SKKOmTU2BOxBSvOYwtJEPdVQ70kZJpPjstlnhCHcuc2WGfSbpKlb/69ttyN5Q==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.18.0.tgz", + "integrity": "sha512-PNGcHop0jkK2WVYGotk/hxj+UFLhXtGPiGtiaWgVBVP1jhMoMCHlTyJA+hEj4rszoSdLTK3fN4oOatrL0Cp+Xw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.18.0.tgz", + "integrity": "sha512-er224jRepVAVLnMF2Q7MZJCq5CsdH2oqjP4dT7K6ij09Kyd+R21r7UVJrF0buMVdZS5QRhDzpvzAxHxabQadow==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "8.18.0", + "@typescript-eslint/utils": "8.18.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + } + }, + "@typescript-eslint/types": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.18.0.tgz", + "integrity": "sha512-FNYxgyTCAnFwTrzpBGq+zrnoTO4x0c1CKYY5MuUTzpScqmY5fmsh2o3+57lqdI3NZucBDCzDgdEbIaNfAjAHQA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.18.0.tgz", + "integrity": "sha512-rqQgFRu6yPkauz+ms3nQpohwejS8bvgbPyIDq13cgEDbkXt4LH4OkDMT0/fN1RUtzG8e8AKJyDBoocuQh8qNeg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/visitor-keys": "8.18.0", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "dependencies": { + "minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "semver": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.18.0.tgz", + "integrity": "sha512-p6GLdY383i7h5b0Qrfbix3Vc3+J2k6QWw6UMUeY5JGfm3C5LbZ4QIZzJNoNOfgyRe0uuYKjvVOsO/jD4SJO+xg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.18.0", + "@typescript-eslint/types": "8.18.0", + "@typescript-eslint/typescript-estree": "8.18.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.18.0.tgz", + "integrity": "sha512-pCh/qEA8Lb1wVIqNvBke8UaRjJ6wrAWkJO5yyIbs8Yx6TNGYyfNjOo61tLv+WwLvoLPp4BQ8B7AHKijl8NGUfw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "8.18.0", + "eslint-visitor-keys": "^4.2.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true + } + } + }, + "@ungap/structured-clone": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.1.tgz", + "integrity": "sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA==", + "dev": true + }, + "acorn": { + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "requires": { + "acorn": "^8.11.0" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3213,10 +5796,22 @@ "indent-string": "^4.0.0" } }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, "ansi-colors": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", - "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", "dev": true }, "ansi-regex": { @@ -3259,12 +5854,24 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, "argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true + }, "balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3325,6 +5932,12 @@ "write-file-atomic": "^3.0.0" } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "camelcase": { "version": "5.3.1", "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", @@ -3337,6 +5950,28 @@ "integrity": "sha512-Jj917pJtYg9HSJBF95HVX3Cdr89JUyLT4IZ8SvM5aDRni95swKgYi3TgYLH5hnGfPE/U1dg6IfZ50UsIlLkwSA==", "dev": true }, + "chai": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.2.tgz", + "integrity": "sha512-aGtmf24DW6MLHHG5gCx4zaI3uBq3KRtxeVs0DjFH6Z0rDNbsvTxFASFvdj79pxjxZ8/5u3PIiN3IwEIQkiiuPw==", + "dev": true, + "requires": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + } + }, + "chai-as-promised": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/chai-as-promised/-/chai-as-promised-8.0.1.tgz", + "integrity": "sha512-OIEJtOL8xxJSH8JJWbIoRjybbzR52iFuDHuF8eb+nTPD6tgXLjRqsgnUGqQfFODxYvq5QdirT0pN9dZ0+Gz6rA==", + "dev": true, + "requires": { + "check-error": "^2.0.0" + } + }, "chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", @@ -3364,6 +5999,12 @@ "integrity": "sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==", "dev": true }, + "check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true + }, "chokidar": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", @@ -3380,6 +6021,36 @@ "readdirp": "~3.6.0" } }, + "chronik-client": { + "version": "file:../chronik-client", + "requires": { + "@types/chai": "^4.2.22", + "@types/chai-as-promised": "^7.1.4", + "@types/mocha": "^9.0.0", + "@types/ws": "^8.2.1", + "@typescript-eslint/eslint-plugin": "^5.5.0", + "@typescript-eslint/parser": "^5.5.0", + "axios": "^1.6.3", + "chai": "^4.3.4", + "chai-as-promised": "^7.1.1", + "ecashaddrjs": "file:../ecashaddrjs", + "eslint": "^8.37.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-header": "^3.1.1", + "isomorphic-ws": "^4.0.1", + "mocha": "^9.1.3", + "mocha-junit-reporter": "^2.2.0", + "mocha-suppress-logs": "^0.3.1", + "prettier": "^2.5.1", + "prettier-plugin-organize-imports": "^2.3.4", + "protobufjs": "^6.8.8", + "ts-node": "^10.4.0", + "ts-proto": "^1.92.1", + "typedoc": "^0.22.10", + "typescript": "^4.5.2", + "ws": "^8.3.0" + } + }, "clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -3430,6 +6101,12 @@ "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", "dev": true }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, "cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -3448,20 +6125,12 @@ "dev": true }, "debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, "requires": { - "ms": "2.1.2" - }, - "dependencies": { - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } + "ms": "^2.1.3" } }, "decamelize": { @@ -3470,6 +6139,18 @@ "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, + "deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -3480,18 +6161,29 @@ } }, "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.2.0.tgz", + "integrity": "sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==", "dev": true }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "ecashaddrjs": { "version": "file:../ecashaddrjs", "requires": { "@babel/cli": "^7.21.0", "@babel/core": "^7.21.3", "@babel/preset-env": "^7.20.2", - "babel-loader": "^9.1.2", + "@types/chai": "^5.0.1", + "@types/mocha": "^10.0.7", + "@typescript-eslint/parser": "^8.15.0", "big-integer": "1.6.36", "bs58check": "^3.0.1", "buffer": "^6.0.3", @@ -3504,6 +6196,8 @@ "mocha-suppress-logs": "^0.3.1", "nyc": "^15.1.0", "random-js": "^2.1.0", + "ts-loader": "^9.5.1", + "ts-node": "^10.9.2", "webpack": "^5.76.2", "webpack-cli": "^5.0.1" } @@ -3526,6 +6220,38 @@ "integrity": "sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==", "dev": true }, + "esbuild": { + "version": "0.23.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz", + "integrity": "sha512-VVNz/9Sa0bs5SELtn3f7qhJCDPCF5oMEl5cO9/SSinpE9hbPVvxbd572HH5AKiP7WD8INO53GgfDDhRjkylHEg==", + "dev": true, + "requires": { + "@esbuild/aix-ppc64": "0.23.1", + "@esbuild/android-arm": "0.23.1", + "@esbuild/android-arm64": "0.23.1", + "@esbuild/android-x64": "0.23.1", + "@esbuild/darwin-arm64": "0.23.1", + "@esbuild/darwin-x64": "0.23.1", + "@esbuild/freebsd-arm64": "0.23.1", + "@esbuild/freebsd-x64": "0.23.1", + "@esbuild/linux-arm": "0.23.1", + "@esbuild/linux-arm64": "0.23.1", + "@esbuild/linux-ia32": "0.23.1", + "@esbuild/linux-loong64": "0.23.1", + "@esbuild/linux-mips64el": "0.23.1", + "@esbuild/linux-ppc64": "0.23.1", + "@esbuild/linux-riscv64": "0.23.1", + "@esbuild/linux-s390x": "0.23.1", + "@esbuild/linux-x64": "0.23.1", + "@esbuild/netbsd-x64": "0.23.1", + "@esbuild/openbsd-arm64": "0.23.1", + "@esbuild/openbsd-x64": "0.23.1", + "@esbuild/sunos-x64": "0.23.1", + "@esbuild/win32-arm64": "0.23.1", + "@esbuild/win32-ia32": "0.23.1", + "@esbuild/win32-x64": "0.23.1" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -3538,12 +6264,216 @@ "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", "dev": true }, + "eslint": { + "version": "8.57.1", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", + "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.1", + "@humanwhocodes/config-array": "^0.13.0", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-plugin-header": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-header/-/eslint-plugin-header-3.1.1.tgz", + "integrity": "sha512-9vlKxuJ4qf793CmeeSrZUvVClw6amtpghq3CuWcB5cUNnWHQhgcqy5eF8oVKFk1G3Y/CbchGfEaw3wiIJaNmVg==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + } + }, "esprima": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", "dev": true }, + "esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -3580,6 +6510,23 @@ "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", "dev": true }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.2.tgz", + "integrity": "sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA==", + "dev": true + }, "foreground-child": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-2.0.0.tgz", @@ -3627,6 +6574,15 @@ "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", "dev": true }, + "get-tsconfig": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz", + "integrity": "sha512-k9PN+cFBmaLWtVz29SkUoqU5O0slLuHJXt/2P+tMVFT+phsSGXGkp9t3rQIqdz0e+06EHNGs3oM6ZX1s2zHxRg==", + "dev": true, + "requires": { + "resolve-pkg-maps": "^1.0.0" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -3683,6 +6639,12 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -3711,6 +6673,30 @@ "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true }, + "ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "imurmurhash": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", @@ -3781,6 +6767,12 @@ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, "is-plain-obj": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", @@ -3955,12 +6947,49 @@ "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", "dev": true }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -3976,6 +7005,12 @@ "integrity": "sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==", "dev": true }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, "log-symbols": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", @@ -3986,6 +7021,12 @@ "is-unicode-supported": "^0.1.0" } }, + "loupe": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.2.tgz", + "integrity": "sha512-23I4pFZHmAemUnz8WZXbYRSKYj801VDaNv9ETuMh7IrMc7VuVVSo+Z9iLE3ni30+U48iDWfi30d3twAXBYmnCg==", + "dev": true + }, "lru-cache": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", @@ -4004,6 +7045,12 @@ "semver": "^6.0.0" } }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, "md5": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/md5/-/md5-2.3.0.tgz", @@ -4015,10 +7062,26 @@ "is-buffer": "~1.1.6" } }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "requires": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + } + }, "minimatch": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.0.1.tgz", - "integrity": "sha512-nLDxIFRyhDblz3qMuq+SoRZED4+miJ/G+tdDrjkkkRnjAsBexeGpgjLEQ0blJy7rHhR2b93rhQY4SvyWu9v03g==", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", "dev": true, "requires": { "brace-expansion": "^2.0.1" @@ -4031,32 +7094,46 @@ "dev": true }, "mocha": { - "version": "10.2.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.2.0.tgz", - "integrity": "sha512-IDY7fl/BecMwFHzoqF2sg/SHHANeBoMMXFlS9r0OXKDssYE1M5O43wUY/9BVPeIvfH2zmEbBfseqN9gBQZzXkg==", - "dev": true, - "requires": { - "ansi-colors": "4.1.1", - "browser-stdout": "1.3.1", - "chokidar": "3.5.3", - "debug": "4.3.4", - "diff": "5.0.0", - "escape-string-regexp": "4.0.0", - "find-up": "5.0.0", - "glob": "7.2.0", - "he": "1.2.0", - "js-yaml": "4.1.0", - "log-symbols": "4.1.0", - "minimatch": "5.0.1", - "ms": "2.1.3", - "nanoid": "3.3.3", - "serialize-javascript": "6.0.0", - "strip-json-comments": "3.1.1", - "supports-color": "8.1.1", - "workerpool": "6.2.1", - "yargs": "16.2.0", - "yargs-parser": "20.2.4", - "yargs-unparser": "2.0.0" + "version": "10.8.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.8.2.tgz", + "integrity": "sha512-VZlYo/WE8t1tstuRmqgeyBgCbJc/lEdopaa+axcKzTBJ+UIdlAB9XnmvTCAH4pwR4ElNInaedhEBmZD8iCSVEg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.3", + "browser-stdout": "^1.3.1", + "chokidar": "^3.5.3", + "debug": "^4.3.5", + "diff": "^5.2.0", + "escape-string-regexp": "^4.0.0", + "find-up": "^5.0.0", + "glob": "^8.1.0", + "he": "^1.2.0", + "js-yaml": "^4.1.0", + "log-symbols": "^4.1.0", + "minimatch": "^5.1.6", + "ms": "^2.1.3", + "serialize-javascript": "^6.0.2", + "strip-json-comments": "^3.1.1", + "supports-color": "^8.1.1", + "workerpool": "^6.5.1", + "yargs": "^16.2.0", + "yargs-parser": "^20.2.9", + "yargs-unparser": "^2.0.0" + }, + "dependencies": { + "glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + } + } } }, "mocha-junit-reporter": { @@ -4078,10 +7155,10 @@ "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "dev": true }, - "nanoid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.3.tgz", - "integrity": "sha512-p1sjXuopFs0xg+fPASzQ28agW1oHD7xDsd9Xkf3T15H3c/cifrFHVwrh74PdoklAPi+i7MdRsE47vm2r6JoB+w==", + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "dev": true }, "node-preload": { @@ -4245,6 +7322,20 @@ "wrappy": "1" } }, + "optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + } + }, "p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -4290,6 +7381,15 @@ "release-zalgo": "^1.0.0" } }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -4308,6 +7408,12 @@ "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, + "pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -4368,6 +7474,12 @@ } } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, "process-on-spawn": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/process-on-spawn/-/process-on-spawn-1.0.0.tgz", @@ -4377,6 +7489,18 @@ "fromentries": "^1.2.0" } }, + "punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, "randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -4422,6 +7546,18 @@ "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true }, + "resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, "rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -4431,6 +7567,15 @@ "glob": "^7.1.3" } }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4444,9 +7589,9 @@ "dev": true }, "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz", + "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==", "dev": true, "requires": { "randombytes": "^2.1.0" @@ -4578,6 +7723,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -4593,6 +7744,62 @@ "is-number": "^7.0.0" } }, + "ts-api-utils": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", + "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", + "dev": true, + "requires": {} + }, + "ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + } + } + }, + "tsx": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/tsx/-/tsx-4.19.2.tgz", + "integrity": "sha512-pOUl6Vo2LUq/bSa8S5q7b91cgNSjctn9ugq/+Mvow99qW6x/UZYwzxy/3NmqoT66eHYfCVvFvACC58UBPFf28g==", + "dev": true, + "requires": { + "esbuild": "~0.23.0", + "fsevents": "~2.3.3", + "get-tsconfig": "^4.7.5" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, "type-fest": { "version": "0.8.1", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", @@ -4608,6 +7815,29 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true + }, + "typescript-eslint": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.18.0.tgz", + "integrity": "sha512-Xq2rRjn6tzVpAyHr3+nmSg1/9k9aIHnJ2iZeOH7cfGOWqTkXTm3kwpQglEuLGdNrYvPF+2gtAs+/KF5rjVo+WQ==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "8.18.0", + "@typescript-eslint/parser": "8.18.0", + "@typescript-eslint/utils": "8.18.0" + } + }, + "undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==", + "dev": true + }, "update-browserslist-db": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz", @@ -4618,12 +7848,27 @@ "picocolors": "^1.0.0" } }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, "uuid": { "version": "8.3.2", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "dev": true }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, "which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -4639,10 +7884,16 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "dev": true }, + "word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true + }, "workerpool": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.1.tgz", - "integrity": "sha512-ILEIE97kDZvF9Wb9f6h5aXK4swSlKGUcOEGiIYb2OOu/IrDU9iwj0fD//SsA6E5ibwJxpEvhullJY4Sl4GcpAw==", + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.5.1.tgz", + "integrity": "sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA==", "dev": true }, "wrap-ansi": { @@ -4674,6 +7925,12 @@ "typedarray-to-buffer": "^3.1.5" } }, + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "requires": {} + }, "xml": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz", @@ -4708,9 +7965,9 @@ } }, "yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true }, "yargs-unparser": { @@ -4739,6 +7996,12 @@ } } }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, "yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/modules/mock-chronik-client/package.json b/modules/mock-chronik-client/package.json --- a/modules/mock-chronik-client/package.json +++ b/modules/mock-chronik-client/package.json @@ -1,18 +1,33 @@ { "dependencies": { - "ecashaddrjs": "file:../ecashaddrjs" + "chronik-client": "file:../chronik-client", + "ecashaddrjs": "file:../ecashaddrjs", + "ws": "^8.18.0" }, "name": "mock-chronik-client", "description": "Testing utility to mock the Chronik indexer client and support unit tests that need to mock chronik related API calls.", - "version": "1.12.3", - "main": "index.js", + "version": "2.0.0", + "main": "./dist/index.js", "devDependencies": { - "mocha": "^10.2.0", + "@types/chai": "^5.0.1", + "@types/chai-as-promised": "^8.0.1", + "@types/mocha": "^10.0.10", + "@types/ws": "^8.5.13", + "chai": "^5.1.2", + "chai-as-promised": "^8.0.1", + "eslint": "8.57", + "eslint-plugin-header": "^3.1.1", + "mocha": "^10.8.2", "mocha-junit-reporter": "^2.2.1", - "nyc": "^15.1.0" + "nyc": "^15.1.0", + "ts-node": "^10.9.2", + "tsx": "^4.19.2", + "typescript": "^5.7.2", + "typescript-eslint": "^8.18.0" }, "scripts": { - "test": "mocha", + "test": "mocha --import=tsx index.test.ts", + "build": "tsc", "coverage": "nyc mocha", "junit": "mocha test --reporter mocha-junit-reporter" }, diff --git a/modules/mock-chronik-client/test/index.test.js b/modules/mock-chronik-client/test/index.test.js deleted file mode 100644 --- a/modules/mock-chronik-client/test/index.test.js +++ /dev/null @@ -1,564 +0,0 @@ -// Copyright (c) 2023 The Bitcoin developers -// Distributed under the MIT software license, see the accompanying -// file COPYING or http://www.opensource.org/licenses/mit-license.php. - -'use strict'; -const assert = require('assert'); -const { MockChronikClient, MockAgora } = require('../index'); -const { - mockBlockInfo, - mockTxInfo, - mockTokenInfo, - mockTxHistory, - mockP2pkhUtxos, - mockBlockchainInfo, - mockRawTxHex, -} = require('../mocks/mockChronikResponses'); -const cashaddr = require('ecashaddrjs'); -const P2PKH_ADDRESS = 'ecash:qzth8qvakhr6y8zcefdrvx30zrdmt2z2gvp7zc5vj8'; - -it('Mock the block() API response', async function () { - // Initialize chronik mock with block info - const blockHash = mockBlockInfo.blockInfo.hash; - const mockedChronik = new MockChronikClient(); - mockedChronik.setMock('block', { - input: blockHash, - output: mockBlockInfo, - }); - - // Execute the API call - const result = await mockedChronik.block(blockHash); - assert.deepEqual(result, mockBlockInfo); -}); - -it('Mock the tx() API response', async function () { - // Initialize chronik mock with tx info - const txid = mockTxInfo.txid; - const mockedChronik = new MockChronikClient(); - mockedChronik.setMock('tx', { - input: txid, - output: mockTxInfo, - }); - - // Execute the API call - const result = await mockedChronik.tx(txid); - assert.deepEqual(result, mockTxInfo); -}); - -it('Mock the token() API response', async function () { - // Initialize chronik mock with token info - const tokenId = mockTokenInfo.slpTxData.slpMeta.tokenId; - const mockedChronik = new MockChronikClient(); - mockedChronik.setMock('token', { - input: tokenId, - output: mockTokenInfo, - }); - - // Execute the API call - const result = await mockedChronik.token(tokenId); - assert.deepEqual(result, mockTokenInfo); -}); - -it('Mock the blockchainInfo() API response', async function () { - // Initialize chronik mock with blockchain info - const mockedChronik = new MockChronikClient(); - mockedChronik.setMock('blockchainInfo', { - output: mockBlockchainInfo, - }); - - // Execute the API call - const result = await mockedChronik.blockchainInfo(); - assert.deepEqual(result, mockBlockchainInfo); -}); - -it('Mock the broadcastTx() API response', async function () { - // Initialize chronik mock with tx broadcast info - const mockedChronik = new MockChronikClient(); - const txid = - '0075130c9ecb342b5162bb1a8a870e69c935ea0c9b2353a967cda404401acf19'; - mockedChronik.setMock('broadcastTx', { - input: mockRawTxHex, - output: { txid: txid }, - }); - - // Execute the API call - const result = await mockedChronik.broadcastTx(mockRawTxHex); - assert.deepEqual(result, { txid: txid }); -}); - -it('Mock the script().utxos() API response', async function () { - // Initialize chronik mock with a utxo set - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - mockedChronik.setScript(type, hash); - mockedChronik.setUtxos(type, hash, mockP2pkhUtxos); - - // Execute the API call - const result = await mockedChronik.script(type, hash).utxos(); - assert.deepEqual(result, mockP2pkhUtxos); -}); - -it('We get the same script().utxos() API response using address().utxos()', async function () { - // Initialize chronik mock with a utxo set - const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(P2PKH_ADDRESS); - mockedChronik.setUtxosByAddress(P2PKH_ADDRESS, mockP2pkhUtxos); - - // Execute the API call - const result = await mockedChronik.address(P2PKH_ADDRESS).utxos(); - assert.deepEqual(result, mockP2pkhUtxos); -}); - -it('We can get a tokenId().utxos() API response using tokenId().utxos()', async function () { - // Initialize chronik mock with a utxo set - const mockedChronik = new MockChronikClient(); - - const tokenId = - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e'; - mockedChronik.setTokenId(tokenId); - mockedChronik.setUtxosByTokenId(tokenId, mockP2pkhUtxos); - - // Execute the API call - const result = await mockedChronik.tokenId(tokenId).utxos(); - assert.deepEqual(result, mockP2pkhUtxos); -}); - -it('Mock the script().history() API response', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - mockedChronik.setScript(type, hash); - mockedChronik.setTxHistory(type, hash, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.script(type, hash).history(0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual( - await mockedChronik.script(type, hash).history(), - mockTxHistory, - ); -}); - -it('We get the same script().history() API response using address().history()', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - mockedChronik.setAddress(P2PKH_ADDRESS); - mockedChronik.setTxHistoryByAddress(P2PKH_ADDRESS, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.address(P2PKH_ADDRESS).history(0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual( - await mockedChronik.address(P2PKH_ADDRESS).history(), - mockTxHistory, - ); -}); - -it('We can also set and get tx history by tokenId', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - const tokenId = - '50d8292c6255cda7afc6c8566fed3cf42a2794e9619740fe8f4c95431271410e'; - mockedChronik.setTokenId(tokenId); - mockedChronik.setTxHistoryByTokenId(tokenId, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.tokenId(tokenId).history(0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual( - await mockedChronik.tokenId(tokenId).history(), - mockTxHistory, - ); -}); - -it('We can also set and get tx history by lokadId', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - const lokadId = '63686174'; - mockedChronik.setLokadId(lokadId); - mockedChronik.setTxHistoryByLokadId(lokadId, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.lokadId(lokadId).history(0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual( - await mockedChronik.lokadId(lokadId).history(), - mockTxHistory, - ); -}); - -it('We can get blockTxs by height', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - const height = 800000; - mockedChronik.setTxHistoryByBlock(height, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.blockTxs(height, 0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual(await mockedChronik.blockTxs(height), mockTxHistory); -}); - -it('We can get blockTxs by hash', async function () { - // Initialize chronik mock with history info - const mockedChronik = new MockChronikClient(); - const hash = - '0000000000000000115e051672e3d4a6c523598594825a1194862937941296fe'; - mockedChronik.setTxHistoryByBlock(hash, mockTxHistory.txs); - - // Execute the API call - const result = await mockedChronik.blockTxs(hash, 0, 2); - assert.deepEqual(result, mockTxHistory); - - // We can also call this without page size - assert.deepEqual(await mockedChronik.blockTxs(hash), mockTxHistory); -}); - -it('We can sub and unsub to scripts with the websocket', async function () { - // Initialize chronik mock with script info - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - - // Create websocket subscription to listen to confirmations on txid - const ws = mockedChronik.ws({ - onMessage: msg => { - console.log(`msg`, msg); - }, - }); - - // Wait for WS to be connected: - await ws.waitForOpen(); - - // Subscribe to scripts - ws.subscribe(type, hash); - - // The sub is in ws.subs - assert.deepEqual(ws.subs.scripts, [ - { scriptType: type, scriptPayload: hash }, - ]); - - // We can unsubscribe from the script - ws.unsubscribe(type, hash); - - // The sub is no longer there - assert.deepEqual(ws.subs.scripts, []); -}); - -it('We can mock a chronik websocket connection', async function () { - // Initialize chronik mock with script info - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - - // Create websocket subscription to listen to confirmations on txid - const ws = mockedChronik.ws({ - onMessage: msg => { - console.log(`msg`, msg); - }, - }); - - // Wait for WS to be connected: - await ws.waitForOpen(); - - // Subscribe to scripts - ws.subscribe(type, hash); - // We can test that ws.subscribe was called - assert.strictEqual(mockedChronik.wsSubscribeCalled, true); - - // The sub is in ws.subs - assert.deepEqual(ws.subs.scripts, [ - { scriptType: type, scriptPayload: hash }, - ]); - - // We can unsubscribe from the script - ws.unsubscribe(type, hash); - - // The sub is no longer there - assert.deepEqual(ws.subs.scripts, []); - - // We can test that waitForOpen() has been called - await ws.waitForOpen(); - assert.equal(mockedChronik.wsWaitForOpenCalled, true); - - // We can test if a websocket was closed by calling wsClose() (aka "manually closed") - mockedChronik.wsClose(); - assert.equal(mockedChronik.manuallyClosed, true); - - // We can subscribe to blocks (in-node chronik-client) - ws.subscribeToBlocks(); - assert.equal(ws.subs.blocks, true); - - // We can unsubscribe from blocks (in-node chronik-client) - ws.unsubscribeFromBlocks(); - assert.equal(ws.subs.blocks, false); -}); - -it('We can subscribe to and unsubscribe from addresses with the ws object', async function () { - // Initialize chronik mock with script info - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - - // Create websocket subscription to listen to confirmations on txid - const ws = mockedChronik.ws({ - onMessage: msg => { - console.log(msg); - }, - }); - - // Wait for WS to be connected: - await ws.waitForOpen(); - - // Subscribe to address - ws.subscribeToAddress(P2PKH_ADDRESS); - - // Verify websocket subscription is as expected - assert.deepEqual(ws.subs.scripts, [{ scriptType: type, payload: hash }]); - - // Unsubscribe from address - ws.unsubscribeFromAddress(P2PKH_ADDRESS); - - // Verify websocket subscription is as expected - assert.deepEqual(ws.subs.scripts, []); - - // We expect an error if we unsubscribe from an address and there is no existing subscription - assert.throws( - () => ws.unsubscribeFromAddress(P2PKH_ADDRESS), - new Error(`No existing sub at ${type}, ${hash}`), - ); -}); - -it('We can subscribe to and unsubscribe from scripts with the ws object', async function () { - // Initialize chronik mock with script info - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - - // Create websocket subscription to listen to confirmations on txid - const ws = mockedChronik.ws({ - onMessage: msg => { - console.log(msg); - }, - }); - - // Wait for WS to be connected: - await ws.waitForOpen(); - - // Subscribe to address - ws.subscribeToScript(type, hash); - - // Verify websocket subscription is as expected - assert.deepEqual(ws.subs.scripts, [{ scriptType: type, payload: hash }]); - - // Unsubscribe from address - ws.unsubscribeFromScript(type, hash); - - // Verify websocket subscription is as expected - assert.deepEqual(ws.subs.scripts, []); - - // We expect an error if we unsubscribe from an address and there is no existing subscription - assert.throws( - () => ws.unsubscribeFromAddress(P2PKH_ADDRESS), - new Error(`No existing sub at ${type}, ${hash}`), - ); -}); - -it('Mock an error returned from the block() API', async function () { - const mockedChronik = new MockChronikClient(); - const blockHash = 'some block hash'; - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setMock('block', { - input: blockHash, - output: expectedError, - }); - - // Execute the API call - await assert.rejects( - async () => mockedChronik.block(blockHash), - expectedError, - ); -}); - -it('Mock an error returned from the tx() API', async function () { - const mockedChronik = new MockChronikClient(); - const txid = 'some txid'; - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setMock('tx', { - input: txid, - output: expectedError, - }); - - // Execute the API call - await assert.rejects(mockedChronik.tx(txid), expectedError); -}); - -it('Mock an error returned from the token() API', async function () { - const mockedChronik = new MockChronikClient(); - const tokenId = 'some token id'; - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setMock('token', { - input: tokenId, - output: expectedError, - }); - - // Execute the API call - await assert.rejects(mockedChronik.token(tokenId), expectedError); -}); - -it('Mock an error returned from the blockchainInfo() API', async function () { - const mockedChronik = new MockChronikClient(); - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setMock('blockchainInfo', { - output: expectedError, - }); - - // Execute the API call - await assert.rejects(mockedChronik.blockchainInfo(), expectedError); -}); - -it('Mock an error returned from the broadcastTx() API', async function () { - const mockedChronik = new MockChronikClient(); - const rawTxHex = 'some raw tx hex'; - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setMock('broadcastTx', { - input: rawTxHex, - output: expectedError, - }); - - // Execute the API call - await assert.rejects(mockedChronik.broadcastTx(rawTxHex), expectedError); -}); - -it('Mock an error returned from the script().utxos() API', async function () { - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setScript(type, hash); - mockedChronik.setUtxos(type, hash, expectedError); - - // Execute the API call - await assert.rejects( - mockedChronik.script(type, hash).utxos(), - expectedError, - ); -}); - -it('Mock an error returned from the address().utxos() API', async function () { - const mockedChronik = new MockChronikClient(); - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setAddress(P2PKH_ADDRESS); - mockedChronik.setUtxosByAddress(P2PKH_ADDRESS, expectedError); - - await assert.rejects( - mockedChronik.address(P2PKH_ADDRESS).utxos(), - expectedError, - ); -}); - -it('Mock an error returned from the script().history() API', async function () { - const mockedChronik = new MockChronikClient(); - const { type, hash } = cashaddr.decode(P2PKH_ADDRESS, true); - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setScript(type, hash); - mockedChronik.setTxHistory(type, hash, expectedError); - - // Execute the API call - await assert.rejects( - mockedChronik.script(type, hash).history(0, 2), - expectedError, - ); -}); - -it('Mock an error returned from the address().history() API', async function () { - const mockedChronik = new MockChronikClient(); - const expectedError = new Error('Bad response from Chronik'); - mockedChronik.setAddress(P2PKH_ADDRESS); - mockedChronik.setTxHistoryByAddress(P2PKH_ADDRESS, expectedError); - - // Execute the API call - await assert.rejects( - async () => mockedChronik.address(P2PKH_ADDRESS).history(0, 2), - expectedError, - ); -}); - -it('We can set and return expected values for supported Agora query methods', async function () { - // Initialize agora mock - const mockedAgora = new MockAgora(); - - // offeredGroupTokenIds - const mockOfferedTokenIds = [ - '0000000000000000000000000000000000000000000000000000000000000000', - '1111111111111111111111111111111111111111111111111111111111111111', - ]; - mockedAgora.setOfferedGroupTokenIds(mockOfferedTokenIds); - assert.deepEqual( - await mockedAgora.offeredGroupTokenIds(), - mockOfferedTokenIds, - ); - - // offeredFungibleTokenIds - const mockOfferedFungibleTokenIds = [ - '0000000000000000000000000000000000000000000000000000000000000000', - '1111111111111111111111111111111111111111111111111111111111111111', - ]; - mockedAgora.setOfferedFungibleTokenIds(mockOfferedFungibleTokenIds); - assert.deepEqual( - await mockedAgora.offeredFungibleTokenIds(), - mockOfferedTokenIds, - ); - - // activeOffersByPubKey - const mockPubKey = '01020304'; - const mockActiveOffersByPubKey = [{ test: 'test' }, { test: 'test' }]; - mockedAgora.setActiveOffersByPubKey(mockPubKey, mockActiveOffersByPubKey); - assert.deepEqual( - await mockedAgora.activeOffersByPubKey(mockPubKey), - mockActiveOffersByPubKey, - ); - - // activeOffersByGroupTokenId - const mockGroupTokenId = - '3333333333333333333333333333333333333333333333333333333333333333'; - const mockActiveOffersByGroupTokenId = [ - { test: 'test2' }, - { test: 'test2' }, - ]; - mockedAgora.setActiveOffersByGroupTokenId( - mockGroupTokenId, - mockActiveOffersByGroupTokenId, - ); - assert.deepEqual( - await mockedAgora.activeOffersByGroupTokenId(mockGroupTokenId), - mockActiveOffersByGroupTokenId, - ); - - // activeOffersByTokenId - const mockTokenId = - '3333333333333333333333333333333333333333333333333333333333333333'; - const mockActiveOffersByTokenId = [{ test: 'test2' }, { test: 'test2' }]; - mockedAgora.setActiveOffersByTokenId( - mockTokenId, - mockActiveOffersByTokenId, - ); - assert.deepEqual( - await mockedAgora.activeOffersByTokenId(mockTokenId), - mockActiveOffersByTokenId, - ); - - // We can also set and throw errors - const expectedError = new Error('some agora error'); - mockedAgora.setOfferedGroupTokenIds(expectedError); - - await assert.rejects( - async () => mockedAgora.offeredGroupTokenIds(), - expectedError, - ); -}); diff --git a/apps/token-server/tsconfig.json b/modules/mock-chronik-client/tsconfig.json copy from apps/token-server/tsconfig.json copy to modules/mock-chronik-client/tsconfig.json --- a/apps/token-server/tsconfig.json +++ b/modules/mock-chronik-client/tsconfig.json @@ -1,12 +1,14 @@ { "compilerOptions": { - "target": "es2020", + "target": "es2016", "module": "commonjs", + "declaration": true, + "declarationMap": true, + "sourceMap": true, "outDir": "./dist", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, - "alwaysStrict": true, "skipLibCheck": true - }, + } }