nftstorage.link
Version:
Utilities for working with the NFT.Storage IPFS Edge Gateway
125 lines (115 loc) • 4.39 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
const API_URL = 'https://api.nftstoragestatus.com';
const MAX_AGE = 60000;
const GATEWAY_URL = 'https://nftstorage.link';
const FALLBACK_GATEWAY_URL = 'https://dweb.link';
/**
* @typedef {Object} IGatewayStatusChecker Checks the status of an IPFS gateway.
* @property {URL} gatewayURL Base URL of the IPFS gateway status is being checked for.
* @property {() => Promise<boolean>} ok Determines if the status of the gateway is OK or not.
*/
/**
* Check the status of a gateway and cache the result for a period of time.
* @implements {IGatewayStatusChecker}
*/
class GatewayStatusChecker {
/**
* @param {Object} [config]
* @param {string|URL} [config.apiURL] Gateway status API URL.
* @param {string|URL} [config.gatewayURL] Base URL of the IPFS gateway status is being checked for.
* @param {number} [config.maxAge] Time in ms after which a status value is stale.
* @param {globalThis.fetch} [config.fetch] Custom fetch API implementation.
*/
constructor(config) {
config = config || {};
/** @private */
this._apiURL = config.apiURL || API_URL;
/** @private */
this._gatewayURL = new URL(config.gatewayURL || GATEWAY_URL);
/** @private */
this._maxAge = config.maxAge || MAX_AGE;
/** @private */
this._fetch = config.fetch;
/* c8 ignore next 3 */
if (!this._fetch && globalThis.fetch) {
this._fetch = globalThis.fetch.bind(globalThis);
}
/** @private */
this._lastCheck = 0;
/**
* @type {Promise<boolean>|null}
* @private
*/
this._request = null;
}
get gatewayURL() {
return this._gatewayURL
}
/**
* Determine if the status of the gateway is OK or not.
*/
ok() {
const now = Date.now();
if (!this._request || now - this._lastCheck > this._maxAge) {
this._request = (async () => {
this._lastCheck = now;
try {
const fetch = this._fetch;
/* c8 ignore next 1 */
if (!fetch) throw new Error('missing fetch implementation')
const res = await fetch(this._apiURL.toString());
const data = await res.json();
return data.status === 'ok'
} catch (err) {
console.warn('Failed to fetch gateway status:', err);
return false
}
})();
}
return this._request
}
}
const defaultStatusChecker = new GatewayStatusChecker();
/**
* Get a gateway URL, given a CID, CID+path, IPFS path or an IPFS gateway URL.
* If the status of the nftstorage.link gateway is known to be good (according
* to the status checker) then return a URL that uses nftstorage.link, otherwise
* return an URL that uses dweb.link (or the optional passed fallback gateway
* URL).
*
* @param {string|URL} cidPath
* @param {Object} [options]
* @param {IGatewayStatusChecker} [options.statusChecker]
* @param {string|URL} [options.fallbackGatewayURL]
*/
async function getGatewayURL(cidPath, options) {
/* c8 ignore next 2 */
options = options || {};
const statusChecker = options.statusChecker || defaultStatusChecker;
const fallbackGatewayURL = options.fallbackGatewayURL || FALLBACK_GATEWAY_URL;
const isOk = await statusChecker.ok();
let { protocol, hostname, pathname, search, hash } = new URL(
cidPath,
statusChecker.gatewayURL
);
if (protocol === 'ipfs:' || protocol === 'ipns:') {
// differences in parsing behaviour between Node.js and Chrome URL:
// in one impl, hostname is 'bafyrei...', pathname is '/path' and in the
// other, hostname is '', pathname is '//bafyrei.../path'.
/* c8 ignore next 1 */
pathname = hostname ? `/${hostname}${pathname}` : pathname.slice(1);
pathname = `/${protocol.slice(0, -1)}${pathname}`;
} else if (!pathname.startsWith('/ipfs') && !pathname.startsWith('/ipns')) {
const hostParts = hostname.split('.'); // subdomain gateway URL?
pathname =
hostParts[1] === 'ipfs' || hostParts[1] === 'ipns'
? `/${hostParts[1]}/${hostParts[0]}${pathname === '/' ? '' : pathname}`
: `/ipfs${pathname}`;
}
const base = isOk ? statusChecker.gatewayURL : fallbackGatewayURL;
return new URL(`${pathname}${search}${hash}`, base)
}
exports.GatewayStatusChecker = GatewayStatusChecker;
exports.getGatewayURL = getGatewayURL;
//# sourceMappingURL=gateway.cjs.map