Comparing version 1.14.0 to 1.15.0
@@ -6,2 +6,13 @@ # Change Log | ||
# [1.15.0](https://github.com/NFTX-project/nftxjs/compare/v1.14.2...v1.15.0) (2024-02-12) | ||
### Features | ||
* improve live/api mode logic ([c6f5253](https://github.com/NFTX-project/nftxjs/commit/c6f5253229daad59ab63f0517a6483a9342fef1a)) | ||
# [1.14.0](https://github.com/NFTX-project/nftxjs/compare/v1.13.2...v1.14.0) (2024-02-01) | ||
@@ -8,0 +19,0 @@ |
@@ -5,5 +5,5 @@ 'use strict'; | ||
var errors = require('@nftx/errors'); | ||
var config = require('@nftx/config'); | ||
var utils = require('@nftx/utils'); | ||
var errors = require('@nftx/errors'); | ||
@@ -14,47 +14,5 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } | ||
const queryApi$1 = async ({ | ||
url, | ||
query: givenQuery = {}, | ||
method = 'GET' | ||
}) => { | ||
const uri = new URL(url, config__default["default"].urls.NFTX_API_URL); | ||
const query = { | ||
...givenQuery, | ||
ebn: 'true', | ||
source: config__default["default"].internal.source | ||
}; | ||
// Add the api key header | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
}; | ||
if (config__default["default"].keys.NFTX_API) { | ||
headers['Authorization'] = config__default["default"].keys.NFTX_API; | ||
} else { | ||
console.warn('No NFTX API key found'); | ||
} | ||
// Send the request | ||
const data = await utils.query({ | ||
url: uri.toString(), | ||
method, | ||
headers, | ||
query | ||
}); | ||
return data; | ||
}; | ||
var queryApiBase = queryApi$1; | ||
const isApiBehind = () => { | ||
const { | ||
network, | ||
internal | ||
} = config__default["default"]; | ||
const apiBlockNumber = internal.apiBlockNumber[network]; | ||
const requiredBlockNumber = internal.requiredBlockNumber[network]; | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
// Wraps an async function. | ||
// While the promise is unresolved, all subsequent calls will receive the same promise | ||
const throttleFn = fn => { | ||
const throttleAsyncFn = fn => { | ||
let p; | ||
@@ -75,67 +33,134 @@ return (...args) => { | ||
}; | ||
const fetchLastIndexedBlock = throttleFn(async () => { | ||
const url = `/${config__default["default"].network}/block`; | ||
const response = await queryApiBase({ | ||
url, | ||
/** Gets the required block number */ | ||
const getRequiredBlockNumber = (network = config__default["default"].network) => { | ||
return config__default["default"].internal.requiredBlockNumber[network] ?? 0; | ||
}; | ||
/** Sets the required block number */ | ||
const setRequiredBlockNumber = (value, network = config__default["default"].network) => { | ||
config__default["default"].internal.requiredBlockNumber[network] = value; | ||
}; | ||
/** Gets the current block number from the api */ | ||
const getApiBlockNumber = (network = config__default["default"].network) => { | ||
return config__default["default"].internal.apiBlockNumber[network] ?? 0; | ||
}; | ||
const getBlockBuffer = () => { | ||
return config__default["default"].internal.blockBuffer; | ||
}; | ||
// Checks whether the required block number is ahead of the api block number | ||
const isApiBehind = ({ | ||
network, | ||
requiredBlockNumber | ||
}) => { | ||
if (!requiredBlockNumber) { | ||
// No required block number so we don't need to worry about the api | ||
return false; | ||
} | ||
const apiBlockNumber = getApiBlockNumber(network); | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
const updateLastIndexedBlock = async ({ | ||
network | ||
}) => { | ||
// Get the last indexed block on the api | ||
const response = await utils.query({ | ||
url: `/${network}/block`, | ||
query: { | ||
source: 'live' | ||
source: 'live', | ||
ebn: 'true' | ||
}, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Authorization: config__default["default"].keys.NFTX_API | ||
} | ||
}); | ||
return response?.block; | ||
}); | ||
const updateApiBlock = ({ | ||
source | ||
const block = response?.block ?? 0; | ||
// Save it (writes to local storage) | ||
config__default["default"].internal.apiBlockNumber[network] = block; | ||
}; | ||
const resetRequiredBlock = ({ | ||
network | ||
}) => { | ||
// Switch to live mode | ||
if (source !== 'live') { | ||
config__default["default"].internal.source = 'live'; | ||
} | ||
// Wait a few seconds before polling the api again | ||
setTimeout(async () => { | ||
// Get the last indexed block on the api | ||
config__default["default"].internal.apiBlockNumber[config__default["default"].network] = await fetchLastIndexedBlock(); | ||
// Run this fn again until we're up to date... | ||
checkApiBlock(); | ||
}, 5000); | ||
}; | ||
const resetRequiredBlock = () => { | ||
// Reset the required block number | ||
config__default["default"].internal.requiredBlockNumber[config__default["default"].network] = 0; | ||
// reset the required block number | ||
setRequiredBlockNumber(0, network); | ||
// Switch back to using the api as the SoT | ||
config__default["default"].internal.source = 'api'; | ||
}; | ||
const checkApiBlock = () => { | ||
const requiredBlockNumber = config__default["default"].internal.requiredBlockNumber[config__default["default"].network]; | ||
// We don't need to worry about syncing if there's no required block number | ||
if (!requiredBlockNumber) { | ||
return; | ||
} | ||
const { | ||
source | ||
} = config__default["default"].internal; | ||
/** Checks if the api is behind the latest block. | ||
* If it is behind, it will switch to live mode and continue checking the api until it has caught up | ||
**/ | ||
const syncApiBlock = throttleAsyncFn(async (network = config__default["default"].network) => { | ||
// We throttle this method so even if 1k requests are made in quick succession, | ||
// we'll only attempt to sync the api one time | ||
// The API is behind the required block | ||
if (isApiBehind()) { | ||
// Switch to live mode and start polling the api to see what the last-indexed block is | ||
updateApiBlock({ | ||
source | ||
// Keep looping while the api is behind the current block | ||
while (isApiBehind({ | ||
network, | ||
requiredBlockNumber: getRequiredBlockNumber(network) | ||
})) { | ||
if (config__default["default"].internal.source !== 'live') { | ||
// Switch to live mode | ||
config__default["default"].internal.source = 'live'; | ||
} | ||
// Wait 5s before polling again | ||
await new Promise(res => setTimeout(res, 5000)); | ||
// Fetch the latest block from the api | ||
await updateLastIndexedBlock({ | ||
network | ||
}); | ||
} else if (source === 'live') { | ||
// Api has caught up so we no longer need to be in live mode | ||
resetRequiredBlock(); | ||
} | ||
}; | ||
/** Wrap another function so that when it gets called, we first check the last-indexed block from the api */ | ||
const nsync = f => { | ||
return (...args) => { | ||
checkApiBlock(); | ||
return f(...args); | ||
// The api has caught up and we no longer need to be in live mode | ||
resetRequiredBlock({ | ||
network | ||
}); | ||
}); | ||
var nsync = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
getRequiredBlockNumber: getRequiredBlockNumber, | ||
setRequiredBlockNumber: setRequiredBlockNumber, | ||
getApiBlockNumber: getApiBlockNumber, | ||
getBlockBuffer: getBlockBuffer, | ||
syncApiBlock: syncApiBlock | ||
}); | ||
const queryApi = async ({ | ||
url, | ||
query: givenQuery = {}, | ||
method = 'GET' | ||
}) => { | ||
// Make sure the api is up to date (or switch to live mode if necessary) | ||
syncApiBlock(); | ||
const uri = new URL(url, config__default["default"].urls.NFTX_API_URL); | ||
const query = { | ||
...givenQuery, | ||
ebn: 'true', | ||
source: config__default["default"].internal.source | ||
}; | ||
// Add the api key header | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
}; | ||
if (config__default["default"].keys.NFTX_API) { | ||
headers['Authorization'] = config__default["default"].keys.NFTX_API; | ||
} else { | ||
console.warn('No NFTX API key found'); | ||
} | ||
// Send the request | ||
const data = await utils.query({ | ||
url: uri.toString(), | ||
method, | ||
headers, | ||
query | ||
}); | ||
return data; | ||
}; | ||
var nsync$1 = nsync; | ||
var queryApi$1 = queryApi; | ||
const queryApi = nsync$1(queryApiBase); | ||
const fetchAsset = ({ | ||
@@ -146,3 +171,3 @@ assetAddress, | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/assets/${assetAddress}/${tokenId}` | ||
@@ -246,3 +271,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -355,3 +380,3 @@ query | ||
const url = `/${network}/auctions`; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url | ||
@@ -366,3 +391,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/inventory/${vaultId}` | ||
@@ -378,3 +403,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/inventory`, | ||
@@ -394,3 +419,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/liquidity/${poolId}` | ||
@@ -411,3 +436,3 @@ }); | ||
} = {}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/liquidity`, | ||
@@ -428,3 +453,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/positions/inventory/${positionId}` | ||
@@ -445,3 +470,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -458,3 +483,3 @@ query | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/positions/liquidity/${positionId}` | ||
@@ -479,3 +504,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -501,3 +526,3 @@ query | ||
if (quoteType === 'price') { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/price`, | ||
@@ -518,3 +543,3 @@ query: { | ||
} = args; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote`, | ||
@@ -694,3 +719,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/balances`, | ||
@@ -719,3 +744,3 @@ query: { | ||
} | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/activity`, | ||
@@ -735,3 +760,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/vaults/${vaultId}` | ||
@@ -753,3 +778,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/vaults`, | ||
@@ -775,3 +800,3 @@ query: { | ||
}) => { | ||
await queryApi({ | ||
await queryApi$1({ | ||
url: `/${network}/vaults/${vaultId}`, | ||
@@ -790,3 +815,3 @@ method: 'POST' | ||
}) => { | ||
await queryApi({ | ||
await queryApi$1({ | ||
url: `/${network}/users/${userAddress}`, | ||
@@ -802,3 +827,3 @@ method: 'POST' | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/collections/${collectionAddress}` | ||
@@ -814,3 +839,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/collections`, | ||
@@ -829,3 +854,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-inventory-position`, | ||
@@ -842,3 +867,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-liquidity-position`, | ||
@@ -855,3 +880,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-vault`, | ||
@@ -868,3 +893,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/increase-liquidity`, | ||
@@ -881,3 +906,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/withdraw-inventory`, | ||
@@ -894,3 +919,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/withdraw-liquidity`, | ||
@@ -933,3 +958,4 @@ method: 'POST', | ||
exports.invalidateVault = invalidateVault$1; | ||
exports.queryApi = queryApi; | ||
exports.nsync = nsync; | ||
exports.queryApi = queryApi$1; | ||
exports.quoteCreateInventoryPosition = quoteCreateInventoryPosition$1; | ||
@@ -936,0 +962,0 @@ exports.quoteCreateLiquidityPosition = quoteCreateLiquidityPosition$1; |
@@ -0,50 +1,8 @@ | ||
import { BadRequestError } from '@nftx/errors'; | ||
import config from '@nftx/config'; | ||
import { query, getUniqueTokenIds, getTokenIdAmounts } from '@nftx/utils'; | ||
import { BadRequestError } from '@nftx/errors'; | ||
const queryApi$1 = async ({ | ||
url, | ||
query: givenQuery = {}, | ||
method = 'GET' | ||
}) => { | ||
const uri = new URL(url, config.urls.NFTX_API_URL); | ||
const query$1 = { | ||
...givenQuery, | ||
ebn: 'true', | ||
source: config.internal.source | ||
}; | ||
// Add the api key header | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
}; | ||
if (config.keys.NFTX_API) { | ||
headers['Authorization'] = config.keys.NFTX_API; | ||
} else { | ||
console.warn('No NFTX API key found'); | ||
} | ||
// Send the request | ||
const data = await query({ | ||
url: uri.toString(), | ||
method, | ||
headers, | ||
query: query$1 | ||
}); | ||
return data; | ||
}; | ||
var queryApiBase = queryApi$1; | ||
const isApiBehind = () => { | ||
const { | ||
network, | ||
internal | ||
} = config; | ||
const apiBlockNumber = internal.apiBlockNumber[network]; | ||
const requiredBlockNumber = internal.requiredBlockNumber[network]; | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
// Wraps an async function. | ||
// While the promise is unresolved, all subsequent calls will receive the same promise | ||
const throttleFn = fn => { | ||
const throttleAsyncFn = fn => { | ||
let p; | ||
@@ -65,67 +23,134 @@ return (...args) => { | ||
}; | ||
const fetchLastIndexedBlock = throttleFn(async () => { | ||
const url = `/${config.network}/block`; | ||
const response = await queryApiBase({ | ||
url, | ||
/** Gets the required block number */ | ||
const getRequiredBlockNumber = (network = config.network) => { | ||
return config.internal.requiredBlockNumber[network] ?? 0; | ||
}; | ||
/** Sets the required block number */ | ||
const setRequiredBlockNumber = (value, network = config.network) => { | ||
config.internal.requiredBlockNumber[network] = value; | ||
}; | ||
/** Gets the current block number from the api */ | ||
const getApiBlockNumber = (network = config.network) => { | ||
return config.internal.apiBlockNumber[network] ?? 0; | ||
}; | ||
const getBlockBuffer = () => { | ||
return config.internal.blockBuffer; | ||
}; | ||
// Checks whether the required block number is ahead of the api block number | ||
const isApiBehind = ({ | ||
network, | ||
requiredBlockNumber | ||
}) => { | ||
if (!requiredBlockNumber) { | ||
// No required block number so we don't need to worry about the api | ||
return false; | ||
} | ||
const apiBlockNumber = getApiBlockNumber(network); | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
const updateLastIndexedBlock = async ({ | ||
network | ||
}) => { | ||
// Get the last indexed block on the api | ||
const response = await query({ | ||
url: `/${network}/block`, | ||
query: { | ||
source: 'live' | ||
source: 'live', | ||
ebn: 'true' | ||
}, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Authorization: config.keys.NFTX_API | ||
} | ||
}); | ||
return response?.block; | ||
}); | ||
const updateApiBlock = ({ | ||
source | ||
const block = response?.block ?? 0; | ||
// Save it (writes to local storage) | ||
config.internal.apiBlockNumber[network] = block; | ||
}; | ||
const resetRequiredBlock = ({ | ||
network | ||
}) => { | ||
// Switch to live mode | ||
if (source !== 'live') { | ||
config.internal.source = 'live'; | ||
} | ||
// Wait a few seconds before polling the api again | ||
setTimeout(async () => { | ||
// Get the last indexed block on the api | ||
config.internal.apiBlockNumber[config.network] = await fetchLastIndexedBlock(); | ||
// Run this fn again until we're up to date... | ||
checkApiBlock(); | ||
}, 5000); | ||
}; | ||
const resetRequiredBlock = () => { | ||
// Reset the required block number | ||
config.internal.requiredBlockNumber[config.network] = 0; | ||
// reset the required block number | ||
setRequiredBlockNumber(0, network); | ||
// Switch back to using the api as the SoT | ||
config.internal.source = 'api'; | ||
}; | ||
const checkApiBlock = () => { | ||
const requiredBlockNumber = config.internal.requiredBlockNumber[config.network]; | ||
// We don't need to worry about syncing if there's no required block number | ||
if (!requiredBlockNumber) { | ||
return; | ||
} | ||
const { | ||
source | ||
} = config.internal; | ||
/** Checks if the api is behind the latest block. | ||
* If it is behind, it will switch to live mode and continue checking the api until it has caught up | ||
**/ | ||
const syncApiBlock = throttleAsyncFn(async (network = config.network) => { | ||
// We throttle this method so even if 1k requests are made in quick succession, | ||
// we'll only attempt to sync the api one time | ||
// The API is behind the required block | ||
if (isApiBehind()) { | ||
// Switch to live mode and start polling the api to see what the last-indexed block is | ||
updateApiBlock({ | ||
source | ||
// Keep looping while the api is behind the current block | ||
while (isApiBehind({ | ||
network, | ||
requiredBlockNumber: getRequiredBlockNumber(network) | ||
})) { | ||
if (config.internal.source !== 'live') { | ||
// Switch to live mode | ||
config.internal.source = 'live'; | ||
} | ||
// Wait 5s before polling again | ||
await new Promise(res => setTimeout(res, 5000)); | ||
// Fetch the latest block from the api | ||
await updateLastIndexedBlock({ | ||
network | ||
}); | ||
} else if (source === 'live') { | ||
// Api has caught up so we no longer need to be in live mode | ||
resetRequiredBlock(); | ||
} | ||
}; | ||
/** Wrap another function so that when it gets called, we first check the last-indexed block from the api */ | ||
const nsync = f => { | ||
return (...args) => { | ||
checkApiBlock(); | ||
return f(...args); | ||
// The api has caught up and we no longer need to be in live mode | ||
resetRequiredBlock({ | ||
network | ||
}); | ||
}); | ||
var nsync = /*#__PURE__*/Object.freeze({ | ||
__proto__: null, | ||
getRequiredBlockNumber: getRequiredBlockNumber, | ||
setRequiredBlockNumber: setRequiredBlockNumber, | ||
getApiBlockNumber: getApiBlockNumber, | ||
getBlockBuffer: getBlockBuffer, | ||
syncApiBlock: syncApiBlock | ||
}); | ||
const queryApi = async ({ | ||
url, | ||
query: givenQuery = {}, | ||
method = 'GET' | ||
}) => { | ||
// Make sure the api is up to date (or switch to live mode if necessary) | ||
syncApiBlock(); | ||
const uri = new URL(url, config.urls.NFTX_API_URL); | ||
const query$1 = { | ||
...givenQuery, | ||
ebn: 'true', | ||
source: config.internal.source | ||
}; | ||
// Add the api key header | ||
const headers = { | ||
'Content-Type': 'application/json' | ||
}; | ||
if (config.keys.NFTX_API) { | ||
headers['Authorization'] = config.keys.NFTX_API; | ||
} else { | ||
console.warn('No NFTX API key found'); | ||
} | ||
// Send the request | ||
const data = await query({ | ||
url: uri.toString(), | ||
method, | ||
headers, | ||
query: query$1 | ||
}); | ||
return data; | ||
}; | ||
var nsync$1 = nsync; | ||
var queryApi$1 = queryApi; | ||
const queryApi = nsync$1(queryApiBase); | ||
const fetchAsset = ({ | ||
@@ -136,3 +161,3 @@ assetAddress, | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/assets/${assetAddress}/${tokenId}` | ||
@@ -236,3 +261,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -345,3 +370,3 @@ query | ||
const url = `/${network}/auctions`; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url | ||
@@ -356,3 +381,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/inventory/${vaultId}` | ||
@@ -368,3 +393,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/inventory`, | ||
@@ -384,3 +409,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/liquidity/${poolId}` | ||
@@ -401,3 +426,3 @@ }); | ||
} = {}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/pools/liquidity`, | ||
@@ -418,3 +443,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/positions/inventory/${positionId}` | ||
@@ -435,3 +460,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -448,3 +473,3 @@ query | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/positions/liquidity/${positionId}` | ||
@@ -469,3 +494,3 @@ }); | ||
}; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url, | ||
@@ -491,3 +516,3 @@ query | ||
if (quoteType === 'price') { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/price`, | ||
@@ -508,3 +533,3 @@ query: { | ||
} = args; | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote`, | ||
@@ -684,3 +709,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/balances`, | ||
@@ -709,3 +734,3 @@ query: { | ||
} | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/activity`, | ||
@@ -725,3 +750,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/vaults/${vaultId}` | ||
@@ -743,3 +768,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/vaults`, | ||
@@ -765,3 +790,3 @@ query: { | ||
}) => { | ||
await queryApi({ | ||
await queryApi$1({ | ||
url: `/${network}/vaults/${vaultId}`, | ||
@@ -780,3 +805,3 @@ method: 'POST' | ||
}) => { | ||
await queryApi({ | ||
await queryApi$1({ | ||
url: `/${network}/users/${userAddress}`, | ||
@@ -792,3 +817,3 @@ method: 'POST' | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/collections/${collectionAddress}` | ||
@@ -804,3 +829,3 @@ }); | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/collections`, | ||
@@ -819,3 +844,3 @@ query: { | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-inventory-position`, | ||
@@ -832,3 +857,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-liquidity-position`, | ||
@@ -845,3 +870,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/create-vault`, | ||
@@ -858,3 +883,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/increase-liquidity`, | ||
@@ -871,3 +896,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/withdraw-inventory`, | ||
@@ -884,3 +909,3 @@ method: 'POST', | ||
}) => { | ||
return queryApi({ | ||
return queryApi$1({ | ||
url: `/${network}/quote/withdraw-liquidity`, | ||
@@ -893,2 +918,2 @@ method: 'POST', | ||
export { fetchActivity$1 as fetchActivity, fetchAllAssets, fetchAsset$1 as fetchAsset, fetchAssets, fetchAuctions$1 as fetchAuctions, fetchCollection$1 as fetchCollection, fetchCollections$1 as fetchCollections, fetchInventoryPool$1 as fetchInventoryPool, fetchInventoryPools$1 as fetchInventoryPools, fetchInventoryPosition$1 as fetchInventoryPosition, fetchInventoryPositions$1 as fetchInventoryPositions, fetchLiquidityPool$1 as fetchLiquidityPool, fetchLiquidityPools$1 as fetchLiquidityPools, fetchLiquidityPosition$1 as fetchLiquidityPosition, fetchLiquidityPositions$1 as fetchLiquidityPositions, fetchVTokenBalances$1 as fetchVTokenBalances, fetchVault$1 as fetchVault, fetchVaultBuyPrice$1 as fetchVaultBuyPrice, fetchVaultBuyQuote$1 as fetchVaultBuyQuote, fetchVaultMintPrice$1 as fetchVaultMintPrice, fetchVaultMintQuote$1 as fetchVaultMintQuote, fetchVaultRedeemPrice$1 as fetchVaultRedeemPrice, fetchVaultRedeemQuote$1 as fetchVaultRedeemQuote, fetchVaultSellPrice$1 as fetchVaultSellPrice, fetchVaultSellQuote$1 as fetchVaultSellQuote, fetchVaultSwapPrice$1 as fetchVaultSwapPrice, fetchVaultSwapQuote$1 as fetchVaultSwapQuote, fetchVaults$1 as fetchVaults, invalidateUser$1 as invalidateUser, invalidateVault$1 as invalidateVault, queryApi, quoteCreateInventoryPosition$1 as quoteCreateInventoryPosition, quoteCreateLiquidityPosition$1 as quoteCreateLiquidityPosition, quoteCreateVault$1 as quoteCreateVault, quoteIncreaseLiquidity$1 as quoteIncreaseLiquidity, quoteWithdrawInventory$1 as quoteWithdrawInventory, quoteWithdrawLiquidity$1 as quoteWithdrawLiquidity, streamAssets }; | ||
export { fetchActivity$1 as fetchActivity, fetchAllAssets, fetchAsset$1 as fetchAsset, fetchAssets, fetchAuctions$1 as fetchAuctions, fetchCollection$1 as fetchCollection, fetchCollections$1 as fetchCollections, fetchInventoryPool$1 as fetchInventoryPool, fetchInventoryPools$1 as fetchInventoryPools, fetchInventoryPosition$1 as fetchInventoryPosition, fetchInventoryPositions$1 as fetchInventoryPositions, fetchLiquidityPool$1 as fetchLiquidityPool, fetchLiquidityPools$1 as fetchLiquidityPools, fetchLiquidityPosition$1 as fetchLiquidityPosition, fetchLiquidityPositions$1 as fetchLiquidityPositions, fetchVTokenBalances$1 as fetchVTokenBalances, fetchVault$1 as fetchVault, fetchVaultBuyPrice$1 as fetchVaultBuyPrice, fetchVaultBuyQuote$1 as fetchVaultBuyQuote, fetchVaultMintPrice$1 as fetchVaultMintPrice, fetchVaultMintQuote$1 as fetchVaultMintQuote, fetchVaultRedeemPrice$1 as fetchVaultRedeemPrice, fetchVaultRedeemQuote$1 as fetchVaultRedeemQuote, fetchVaultSellPrice$1 as fetchVaultSellPrice, fetchVaultSellQuote$1 as fetchVaultSellQuote, fetchVaultSwapPrice$1 as fetchVaultSwapPrice, fetchVaultSwapQuote$1 as fetchVaultSwapQuote, fetchVaults$1 as fetchVaults, invalidateUser$1 as invalidateUser, invalidateVault$1 as invalidateVault, nsync, queryApi$1 as queryApi, quoteCreateInventoryPosition$1 as quoteCreateInventoryPosition, quoteCreateLiquidityPosition$1 as quoteCreateLiquidityPosition, quoteCreateVault$1 as quoteCreateVault, quoteIncreaseLiquidity$1 as quoteIncreaseLiquidity, quoteWithdrawInventory$1 as quoteWithdrawInventory, quoteWithdrawLiquidity$1 as quoteWithdrawLiquidity, streamAssets }; |
@@ -1,5 +0,2 @@ | ||
export declare const queryApi: <T>({ url, query: givenQuery, method, }: { | ||
url: string; | ||
query?: Record<string, any> | undefined; | ||
method?: string | undefined; | ||
}) => Promise<T>; | ||
export { default as queryApi } from './queryApi'; | ||
export * as nsync from './nsync'; |
@@ -1,3 +0,11 @@ | ||
/** Wrap another function so that when it gets called, we first check the last-indexed block from the api */ | ||
declare const nsync: <F extends (...args: any[]) => any>(f: F) => F; | ||
export default nsync; | ||
/** Gets the required block number */ | ||
export declare const getRequiredBlockNumber: (network?: number) => number; | ||
/** Sets the required block number */ | ||
export declare const setRequiredBlockNumber: (value: number, network?: number) => void; | ||
/** Gets the current block number from the api */ | ||
export declare const getApiBlockNumber: (network?: number) => number; | ||
export declare const getBlockBuffer: () => number; | ||
/** Checks if the api is behind the latest block. | ||
* If it is behind, it will switch to live mode and continue checking the api until it has caught up | ||
**/ | ||
export declare const syncApiBlock: (network?: number) => Promise<void>; |
{ | ||
"name": "@nftx/api", | ||
"version": "1.14.0", | ||
"version": "1.15.0", | ||
"description": "", | ||
@@ -27,6 +27,6 @@ "homepage": "https://github.com/NFTX-project/nftxjs", | ||
"dependencies": { | ||
"@nftx/config": "^1.14.0", | ||
"@nftx/config": "^1.15.0", | ||
"@nftx/errors": "^1.6.0", | ||
"@nftx/types": "^1.14.0", | ||
"@nftx/utils": "^1.14.0", | ||
"@nftx/utils": "^1.15.0", | ||
"viem": "^1.16.6" | ||
@@ -33,0 +33,0 @@ }, |
@@ -1,4 +0,2 @@ | ||
import queryApiBase from './queryApi'; | ||
import nsync from './nsync'; | ||
export const queryApi = nsync(queryApiBase); | ||
export { default as queryApi } from './queryApi'; | ||
export * as nsync from './nsync'; |
import config from '@nftx/config'; | ||
import queryApi from './queryApi'; | ||
import { query } from '@nftx/utils'; | ||
const isApiBehind = () => { | ||
const { network, internal } = config; | ||
const apiBlockNumber = internal.apiBlockNumber[network]; | ||
const requiredBlockNumber = internal.requiredBlockNumber[network]; | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
// Wraps an async function. | ||
// While the promise is unresolved, all subsequent calls will receive the same promise | ||
const throttleFn = <F extends (...args: any[]) => Promise<any>>(fn: F): F => { | ||
const throttleAsyncFn = <F extends (...args: any[]) => Promise<any>>( | ||
fn: F | ||
): F => { | ||
let p: Promise<any> | undefined; | ||
@@ -34,63 +28,91 @@ return ((...args: Parameters<F>) => { | ||
const fetchLastIndexedBlock = throttleFn(async () => { | ||
const url = `/${config.network}/block`; | ||
type Response = { block: number }; | ||
const response = await queryApi<Response>({ | ||
url, | ||
query: { source: 'live' }, | ||
}); | ||
return response?.block; | ||
}); | ||
/** Gets the required block number */ | ||
export const getRequiredBlockNumber = (network = config.network) => { | ||
return config.internal.requiredBlockNumber[network] ?? 0; | ||
}; | ||
const updateApiBlock = ({ source }: { source: 'live' | 'api' }) => { | ||
// Switch to live mode | ||
if (source !== 'live') { | ||
config.internal.source = 'live'; | ||
} | ||
// Wait a few seconds before polling the api again | ||
setTimeout(async () => { | ||
// Get the last indexed block on the api | ||
config.internal.apiBlockNumber[config.network] = | ||
await fetchLastIndexedBlock(); | ||
// Run this fn again until we're up to date... | ||
checkApiBlock(); | ||
}, 5000); | ||
/** Sets the required block number */ | ||
export const setRequiredBlockNumber = ( | ||
value: number, | ||
network: number = config.network | ||
) => { | ||
config.internal.requiredBlockNumber[network] = value; | ||
}; | ||
const resetRequiredBlock = () => { | ||
// Reset the required block number | ||
config.internal.requiredBlockNumber[config.network] = 0; | ||
// Switch back to using the api as the SoT | ||
config.internal.source = 'api'; | ||
/** Gets the current block number from the api */ | ||
export const getApiBlockNumber = (network = config.network) => { | ||
return config.internal.apiBlockNumber[network] ?? 0; | ||
}; | ||
const checkApiBlock = (): void => { | ||
const requiredBlockNumber = | ||
config.internal.requiredBlockNumber[config.network]; | ||
export const getBlockBuffer = () => { | ||
return config.internal.blockBuffer; | ||
}; | ||
// We don't need to worry about syncing if there's no required block number | ||
// Checks whether the required block number is ahead of the api block number | ||
const isApiBehind = ({ | ||
network, | ||
requiredBlockNumber, | ||
}: { | ||
network: number; | ||
requiredBlockNumber: number; | ||
}) => { | ||
if (!requiredBlockNumber) { | ||
return; | ||
// No required block number so we don't need to worry about the api | ||
return false; | ||
} | ||
const apiBlockNumber = getApiBlockNumber(network); | ||
const { source } = config.internal; | ||
return apiBlockNumber < requiredBlockNumber; | ||
}; | ||
// The API is behind the required block | ||
if (isApiBehind()) { | ||
// Switch to live mode and start polling the api to see what the last-indexed block is | ||
updateApiBlock({ source }); | ||
} else if (source === 'live') { | ||
// Api has caught up so we no longer need to be in live mode | ||
resetRequiredBlock(); | ||
} | ||
const updateLastIndexedBlock = async ({ network }: { network: number }) => { | ||
// Get the last indexed block on the api | ||
const response = await query<{ block: number }>({ | ||
url: `/${network}/block`, | ||
query: { source: 'live', ebn: 'true' }, | ||
headers: { | ||
'Content-Type': 'application/json', | ||
Authorization: config.keys.NFTX_API, | ||
}, | ||
}); | ||
const block = response?.block ?? 0; | ||
// Save it (writes to local storage) | ||
config.internal.apiBlockNumber[network] = block; | ||
}; | ||
/** Wrap another function so that when it gets called, we first check the last-indexed block from the api */ | ||
const nsync = <F extends (...args: any[]) => any>(f: F): F => { | ||
return ((...args: any[]) => { | ||
checkApiBlock(); | ||
return f(...args); | ||
}) as F; | ||
const resetRequiredBlock = ({ network }: { network: number }) => { | ||
// reset the required block number | ||
setRequiredBlockNumber(0, network); | ||
// Switch back to using the api as the SoT | ||
config.internal.source = 'api'; | ||
}; | ||
export default nsync; | ||
/** Checks if the api is behind the latest block. | ||
* If it is behind, it will switch to live mode and continue checking the api until it has caught up | ||
**/ | ||
export const syncApiBlock = throttleAsyncFn( | ||
async (network: number = config.network) => { | ||
// We throttle this method so even if 1k requests are made in quick succession, | ||
// we'll only attempt to sync the api one time | ||
// Keep looping while the api is behind the current block | ||
while ( | ||
isApiBehind({ | ||
network, | ||
requiredBlockNumber: getRequiredBlockNumber(network), | ||
}) | ||
) { | ||
if (config.internal.source !== 'live') { | ||
// Switch to live mode | ||
config.internal.source = 'live'; | ||
} | ||
// Wait 5s before polling again | ||
await new Promise<void>((res) => setTimeout(res, 5000)); | ||
// Fetch the latest block from the api | ||
await updateLastIndexedBlock({ network }); | ||
} | ||
// The api has caught up and we no longer need to be in live mode | ||
resetRequiredBlock({ network }); | ||
} | ||
); |
import config from '@nftx/config'; | ||
import { query as sendQuery } from '@nftx/utils'; | ||
import { syncApiBlock } from './nsync'; | ||
@@ -13,2 +14,5 @@ const queryApi = async <T>({ | ||
}) => { | ||
// Make sure the api is up to date (or switch to live mode if necessary) | ||
syncApiBlock(); | ||
const uri = new URL(url, config.urls.NFTX_API_URL); | ||
@@ -15,0 +19,0 @@ const query: Record<string, any> = { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
105514
3393
Updated@nftx/config@^1.15.0
Updated@nftx/utils@^1.15.0