Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@nftx/api

Package Overview
Dependencies
Maintainers
2
Versions
81
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@nftx/api - npm Package Compare versions

Comparing version 1.14.0 to 1.15.0

11

CHANGELOG.md

@@ -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 @@

270

dist/cjs/api.js

@@ -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> = {

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc