nftstorage.link
Version:
Utilities for working with the NFT.Storage IPFS Edge Gateway
1 lines • 17.3 kB
Source Map (JSON)
{"version":3,"file":"perma-cache.cjs","sources":["../../src/perma-cache.js"],"sourcesContent":["/**\n * A client library for the https://api.nftstorage.link/ perma-cache service. It provides a convenient\n * interface for working with the [Raw HTTP API](https://nftstorage.link/#api-docs)\n * from a web browser or [Node.js](https://nodejs.org/) and comes bundled with\n * TS for out-of-the box type inference and better IntelliSense.\n *\n * @example\n * ```js\n * import { PermaCache } from 'nftstorage.link'\n *\n * const urls = [\n * 'https://bafkreidyeivj7adnnac6ljvzj2e3rd5xdw3revw4da7mx2ckrstapoupoq.ipfs.nftstorage.link'\n * ]\n *\n * const cache = new PermaCache({ token: 'YOUR_NFT_STORAGE_TOKEN' })\n * const permaCacheEntries = await cache.put(urls)\n * await cache.delete(urls)\n * ```\n * @module\n */\n\nimport throttledQueue from 'throttled-queue'\nimport pSettle from 'p-settle'\nimport pRetry, { AbortError } from 'p-retry'\n\nimport { fetch } from './platform.js'\n\nconst MAX_RETRIES = 5\n// These match what is enforced server-side\nconst RATE_LIMIT_REQUESTS = 100\nconst RATE_LIMIT_PERIOD = 60 * 1000\n\n/**\n * @typedef { import('./lib/interface.js').RateLimiter } RateLimiter\n * @typedef { import('./lib/interface.js').Service } Service\n * @typedef { import('./lib/interface.js').PutOptions} PutOptions\n * @typedef { import('./lib/interface.js').DeleteOptions} DeleteOptions\n * @typedef { import('./lib/interface.js').ListOptions} ListOptions\n * @typedef { import('./lib/interface.js').CacheResult} CacheResult\n * @typedef { import('./lib/interface.js').CacheDeleteResult} CacheDeleteResult\n * @typedef { import('./lib/interface.js').CacheEntry} CacheEntry\n * @typedef { import('./lib/interface.js').AccountInfo} AccountInfo\n */\n\n/**\n * @implements Service\n */\nexport class PermaCache {\n /**\n * Constructs a client bound to the given `options.token` and\n * `options.endpoint`.\n *\n * @example\n * ```js\n * import { PermaCache } from 'nftstorage.link'\n * const cache = new PermaCache({ token: API_TOKEN })\n * ```\n *\n * @param {{token: string, endpoint?:URL, rateLimiter?: RateLimiter}} options\n */\n constructor({\n token,\n endpoint = new URL('https://api.nftstorage.link'),\n rateLimiter,\n }) {\n /**\n * Authorization token.\n *\n * @readonly\n */\n this.token = token\n /**\n * Service API endpoint `URL`.\n * @readonly\n */\n this.endpoint = endpoint\n /**\n * @readonly\n */\n this.rateLimiter = rateLimiter || createRateLimiter()\n }\n\n /**\n * @hidden\n * @param {string} token\n * @returns {Record<string, string>}\n */\n static headers(token) {\n /* c8 ignore next 1 */\n if (!token) throw new Error('missing token')\n return {\n Authorization: `Bearer ${token}`,\n 'X-Client': 'nftstorage.link/js',\n }\n }\n\n /**\n * @param {Service} service\n * @param {string[]} urls\n * @param {PutOptions} [options]\n * @returns {Promise<CacheResult[]>}\n */\n static async put(\n { endpoint, token, rateLimiter = globalRateLimiter },\n urls,\n { onPut, maxRetries } = {}\n ) {\n urls.forEach(validateUrl)\n\n const headers = PermaCache.headers(token)\n\n /** @type {import('p-settle').PromiseResult<CacheResult>[]} */\n const cacheResults = await pSettle(\n urls.map(async (url) => {\n const apiUrl = new URL(\n `perma-cache/${encodeURIComponent(url)}`,\n endpoint\n )\n\n return await pRetry(\n async () => {\n await rateLimiter()\n const response = await fetch(apiUrl.toString(), {\n method: 'POST',\n headers,\n })\n\n /** @type {CacheResult} */\n const result = await response.json()\n if (!response.ok) {\n // @ts-ignore Only exists on Error\n const e = new Error(result.message)\n // do not retry if fatal errors - will not succeed\n if (response.status >= 400 && response.status < 500) {\n throw new AbortError(e)\n }\n /* c8 ignore next 2 */\n throw e\n }\n onPut && onPut(url)\n\n return result\n },\n /* c8 ignore next 3 */\n {\n retries: maxRetries == null ? MAX_RETRIES : maxRetries,\n }\n )\n })\n )\n\n return cacheResults.map((r, i) => {\n // @ts-ignore reason and value might not exist, but one of them always exists\n return r.reason ? { url: urls[i], error: r.reason.message } : r.value\n })\n }\n\n /**\n * @param {Service} service\n * @param {ListOptions} [options]\n * @returns {AsyncIterable<CacheEntry>}\n */\n static async *list(\n { endpoint, token, rateLimiter = globalRateLimiter },\n { sort = 'date', order = 'asc' } = {}\n ) {\n const headers = PermaCache.headers(token)\n let search = new URLSearchParams({ sort, order })\n let nextPageUrl = new URL(`perma-cache?${search}`, endpoint)\n\n while (true) {\n await rateLimiter()\n\n const response = await fetch(nextPageUrl.toString(), {\n method: 'GET',\n headers,\n })\n const result = await response.json()\n if (!response.ok) {\n throw new Error(result.message)\n }\n\n for (const entry of result) {\n yield entry\n }\n\n // Go over next links until not provided by API anymore\n const link = response.headers.get('link')\n if (!link) {\n break\n }\n nextPageUrl = new URL(\n link.replace('<', '').replace('>; rel=\"next\"', ''),\n endpoint\n )\n }\n }\n\n /**\n * @param {Service} service\n * @param {string[]} urls\n * @param {DeleteOptions} [options]\n * @returns {Promise<CacheDeleteResult[]>}\n */\n static async delete(\n { endpoint, token, rateLimiter = globalRateLimiter },\n urls,\n { onDelete, maxRetries } = {}\n ) {\n urls.forEach(validateUrl)\n\n const headers = PermaCache.headers(token)\n\n /** @type {import('p-settle').PromiseResult<CacheDeleteResult>[]} */\n const cacheDeleteResults = await pSettle(\n urls.map(async (url) => {\n const apiUrl = new URL(\n `perma-cache/${encodeURIComponent(url)}`,\n endpoint\n )\n\n return await pRetry(\n async () => {\n await rateLimiter()\n const response = await fetch(apiUrl.toString(), {\n method: 'DELETE',\n headers,\n })\n\n const result = await response.json()\n if (!response.ok) {\n const e = new Error(result.message)\n // do not retry if fatal errors - will not succeed\n if (response.status >= 400 && response.status < 500) {\n throw new AbortError(e)\n }\n /* c8 ignore next 2 */\n throw e\n }\n\n onDelete && onDelete(url)\n\n return {\n url,\n }\n },\n /* c8 ignore next 3 */\n {\n retries: maxRetries == null ? MAX_RETRIES : maxRetries,\n }\n )\n })\n )\n\n return cacheDeleteResults.map((r, i) => {\n // @ts-ignore reason and value might not exist, but one of them always exists\n return r.reason ? { url: urls[i], error: r.reason.message } : r.value\n })\n }\n\n /**\n * @param {Service} service\n * @return {Promise<AccountInfo>}\n */\n static async accountInfo({\n endpoint,\n token,\n rateLimiter = globalRateLimiter,\n }) {\n const url = new URL('perma-cache/account', endpoint)\n const headers = PermaCache.headers(token)\n\n await rateLimiter()\n const response = await fetch(url.toString(), {\n method: 'GET',\n headers,\n })\n const result = await response.json()\n if (!response.ok) {\n throw new Error(result.message)\n }\n\n return result\n }\n\n // Just a sugar so you don't have to pass around endpoint and token around.\n\n /**\n * Perma cache URLS into nftstorage.link.\n *\n * Returns the corresponding Perma cache entries created.\n *\n * @param {string[]} urls\n * @param {PutOptions} [options]\n * @returns {Promise<CacheResult[]>}\n */\n put(urls, options) {\n return PermaCache.put(this, urls, options)\n }\n\n /**\n * List all Perma cached URLs for this account. Use a `for await...of` loop to fetch them all.\n * @example\n * Fetch all the urls\n * ```js\n * const urls = []\n * for await (const item of client.list()) {\n * urls.push(item)\n * }\n * ```\n * @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of\n * @param {ListOptions} [options]\n * @returns {AsyncIterable<CacheEntry>}\n */\n list(options) {\n return PermaCache.list(this, options)\n }\n\n /**\n * @param {string[]} urls\n * @param {DeleteOptions} [options]\n * @returns {Promise<CacheDeleteResult[]>}\n */\n delete(urls, options) {\n return PermaCache.delete(this, urls, options)\n }\n\n /**\n * Fetch info on PermaCache for the user.\n */\n accountInfo() {\n return PermaCache.accountInfo(this)\n }\n}\n\n/**\n * Creates a rate limiter which limits at the same rate as is enforced\n * server-side, to allow the client to avoid exceeding the requests limit and\n * being blocked for 30 seconds.\n * @returns {RateLimiter}\n */\nexport function createRateLimiter() {\n const throttle = throttledQueue(RATE_LIMIT_REQUESTS, RATE_LIMIT_PERIOD)\n return () => throttle(() => {})\n}\n\n/**\n * Rate limiter used by static API if no rate limiter is passed. Note that each\n * instance of the PermaCache class gets it's own limiter if none is passed.\n * This is because rate limits are enforced per API token.\n */\nconst globalRateLimiter = createRateLimiter()\n\n/**\n * @param {string} urlString\n */\nfunction validateUrl(urlString) {\n const url = new URL(urlString)\n if (\n !url.hostname.includes('.ipfs.nftstorage.link') &&\n !(\n url.hostname.includes('nftstorage.link') &&\n url.pathname.startsWith('/ipfs')\n )\n ) {\n throw new Error(\n `Invalid URL (not an nftstorage.link IPFS URL): ${urlString}`\n )\n }\n}\n"],"names":["pSettle","pRetry","fetch","AbortError","throttledQueue"],"mappings":"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"}