nftstorage.link
Version:
Utilities for working with the NFT.Storage IPFS Edge Gateway
3 lines (2 loc) • 10.1 kB
JavaScript
class t{constructor(t){t=t||{},this._apiURL=t.apiURL||"https://api.nftstoragestatus.com",this._gatewayURL=new URL(t.gatewayURL||"https://nftstorage.link"),this._maxAge=t.maxAge||6e4,this._fetch=t.fetch,!this._fetch&&globalThis.fetch&&(this._fetch=globalThis.fetch.bind(globalThis)),this._lastCheck=0,this._request=null}get gatewayURL(){return this._gatewayURL}ok(){const t=Date.now();return(!this._request||t-this._lastCheck>this._maxAge)&&(this._request=(async()=>{this._lastCheck=t;try{const t=this._fetch;if(!t)throw new Error("missing fetch implementation");const e=await t(this._apiURL.toString());return"ok"===(await e.json()).status}catch(t){return console.warn("Failed to fetch gateway status:",t),!1}})()),this._request}}const e=new t;async function r(t,r){const o=(r=r||{}).statusChecker||e,i=r.fallbackGatewayURL||"https://dweb.link",n=await o.ok();let{protocol:s,hostname:a,pathname:u,search:c,hash:h}=new URL(t,o.gatewayURL);if("ipfs:"===s||"ipns:"===s)u=a?`/${a}${u}`:u.slice(1),u=`/${s.slice(0,-1)}${u}`;else if(!u.startsWith("/ipfs")&&!u.startsWith("/ipns")){const t=a.split(".");u="ipfs"===t[1]||"ipns"===t[1]?`/${t[1]}/${t[0]}${"/"===u?"":u}`:`/ipfs${u}`}const p=n?o.gatewayURL:i;return new URL(`${u}${c}${h}`,p)}function o(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var i={exports:{}};!function(t,e){function r(t,e,r){void 0===r&&(r=!1),r&&(e/=t,t=1);var o,i=[],n=0,s=0,a=function(){var r=n+e,u=Date.now();if(u<r)return void 0!==o&&clearTimeout(o),void(o=setTimeout(a,r-u));n=u,s=0;for(var c=0,h=i.splice(0,t);c<h.length;c++){var p=h[c];s++,p()}o=i.length?setTimeout(a,e):void 0};return function(r){return new Promise((function(u,c){var h=function(){return Promise.resolve().then(r).then(u).catch(c)},p=Date.now();void 0===o&&p-n>e&&(n=p,s=0),s++<t?h():(i.push(h),void 0===o&&(o=setTimeout(a,n+e-p)))}))}}Object.defineProperty(e,"__esModule",{value:!0}),t.exports=r,e.default=r}(i,i.exports);var n=o(i.exports),s={exports:{}};const a=async t=>{try{return{isFulfilled:!0,isRejected:!1,value:await t}}catch(t){return{isFulfilled:!1,isRejected:!0,reason:t}}};s.exports=a,s.exports.default=a;var u={exports:{}},c={exports:{}};const h=(t,...e)=>new Promise((r=>{r(t(...e))}));c.exports=h,c.exports.default=h;const p=c.exports,m=t=>{if(!Number.isInteger(t)&&t!==1/0||!(t>0))return Promise.reject(new TypeError("Expected `concurrency` to be a number from 1 and up"));const e=[];let r=0;const o=()=>{r--,e.length>0&&e.shift()()},i=(t,e,...i)=>{r++;const n=p(t,...i);e(n),n.then(o,o)},n=(o,...n)=>new Promise((s=>((o,n,...s)=>{r<t?i(o,n,...s):e.push(i.bind(null,o,n,...s))})(o,s,...n)));return Object.defineProperties(n,{activeCount:{get:()=>r},pendingCount:{get:()=>e.length},clearQueue:{value:()=>{e.length=0}}}),n};u.exports=m,u.exports.default=m;const l=s.exports,f=u.exports;var w=async(t,e={})=>{const{concurrency:r=1/0}=e,o=f(r);return Promise.all(t.map((t=>t&&"function"==typeof t.then?l(t):l("function"==typeof t?o((()=>t())):Promise.resolve(t)))))},_={exports:{}},d={};function y(t,e){"boolean"==typeof e&&(e={forever:e}),this._originalTimeouts=JSON.parse(JSON.stringify(t)),this._timeouts=t,this._options=e||{},this._maxRetryTime=e&&e.maxRetryTime||1/0,this._fn=null,this._errors=[],this._attempts=1,this._operationTimeout=null,this._operationTimeoutCb=null,this._timeout=null,this._operationStart=null,this._timer=null,this._options.forever&&(this._cachedTimeouts=this._timeouts.slice(0))}var g=y;y.prototype.reset=function(){this._attempts=1,this._timeouts=this._originalTimeouts.slice(0)},y.prototype.stop=function(){this._timeout&&clearTimeout(this._timeout),this._timer&&clearTimeout(this._timer),this._timeouts=[],this._cachedTimeouts=null},y.prototype.retry=function(t){if(this._timeout&&clearTimeout(this._timeout),!t)return!1;var e=(new Date).getTime();if(t&&e-this._operationStart>=this._maxRetryTime)return this._errors.push(t),this._errors.unshift(new Error("RetryOperation timeout occurred")),!1;this._errors.push(t);var r=this._timeouts.shift();if(void 0===r){if(!this._cachedTimeouts)return!1;this._errors.splice(0,this._errors.length-1),r=this._cachedTimeouts.slice(-1)}var o=this;return this._timer=setTimeout((function(){o._attempts++,o._operationTimeoutCb&&(o._timeout=setTimeout((function(){o._operationTimeoutCb(o._attempts)}),o._operationTimeout),o._options.unref&&o._timeout.unref()),o._fn(o._attempts)}),r),this._options.unref&&this._timer.unref(),!0},y.prototype.attempt=function(t,e){this._fn=t,e&&(e.timeout&&(this._operationTimeout=e.timeout),e.cb&&(this._operationTimeoutCb=e.cb));var r=this;this._operationTimeoutCb&&(this._timeout=setTimeout((function(){r._operationTimeoutCb()}),r._operationTimeout)),this._operationStart=(new Date).getTime(),this._fn(this._attempts)},y.prototype.try=function(t){console.log("Using RetryOperation.try() is deprecated"),this.attempt(t)},y.prototype.start=function(t){console.log("Using RetryOperation.start() is deprecated"),this.attempt(t)},y.prototype.start=y.prototype.try,y.prototype.errors=function(){return this._errors},y.prototype.attempts=function(){return this._attempts},y.prototype.mainError=function(){if(0===this._errors.length)return null;for(var t={},e=null,r=0,o=0;o<this._errors.length;o++){var i=this._errors[o],n=i.message,s=(t[n]||0)+1;t[n]=s,s>=r&&(e=i,r=s)}return e},function(t){var e=g;t.operation=function(r){var o=t.timeouts(r);return new e(o,{forever:r&&(r.forever||r.retries===1/0),unref:r&&r.unref,maxRetryTime:r&&r.maxRetryTime})},t.timeouts=function(t){if(t instanceof Array)return[].concat(t);var e={retries:10,factor:2,minTimeout:1e3,maxTimeout:1/0,randomize:!1};for(var r in t)e[r]=t[r];if(e.minTimeout>e.maxTimeout)throw new Error("minTimeout is greater than maxTimeout");for(var o=[],i=0;i<e.retries;i++)o.push(this.createTimeout(i,e));return t&&t.forever&&!o.length&&o.push(this.createTimeout(i,e)),o.sort((function(t,e){return t-e})),o},t.createTimeout=function(t,e){var r=e.randomize?Math.random()+1:1,o=Math.round(r*Math.max(e.minTimeout,1)*Math.pow(e.factor,t));return o=Math.min(o,e.maxTimeout)},t.wrap=function(e,r,o){if(r instanceof Array&&(o=r,r=null),!o)for(var i in o=[],e)"function"==typeof e[i]&&o.push(i);for(var n=0;n<o.length;n++){var s=o[n],a=e[s];e[s]=function(o){var i=t.operation(r),n=Array.prototype.slice.call(arguments,1),s=n.pop();n.push((function(t){i.retry(t)||(t&&(arguments[0]=i.mainError()),s.apply(this,arguments))})),i.attempt((function(){o.apply(e,n)}))}.bind(e,a),e[s].options=r}}}(d);const T=d,v=["Failed to fetch","NetworkError when attempting to fetch resource.","The Internet connection appears to be offline.","Network request failed"];class x extends Error{constructor(t){super(),t instanceof Error?(this.originalError=t,({message:t}=t)):(this.originalError=new Error(t),this.originalError.stack=this.stack),this.name="AbortError",this.message=t}}const R=(t,e)=>new Promise(((r,o)=>{e={onFailedAttempt:()=>{},retries:10,...e};const i=T.operation(e);i.attempt((async n=>{try{r(await t(n))}catch(t){if(!(t instanceof Error))return void o(new TypeError(`Non-error was thrown: "${t}". You should only throw errors.`));if(t instanceof x)i.stop(),o(t.originalError);else if(t instanceof TypeError&&(s=t.message,!v.includes(s)))i.stop(),o(t);else{((t,e,r)=>{const o=r.retries-(e-1);t.attemptNumber=e,t.retriesLeft=o})(t,n,e);try{await e.onFailedAttempt(t)}catch(t){return void o(t)}i.retry(t)||o(i.mainError())}}var s}))}));_.exports=R,_.exports.default=R;var E=_.exports.AbortError=x,k=_.exports,L=globalThis.fetch;class b{constructor({token:t,endpoint:e=new URL("https://api.nftstorage.link"),rateLimiter:r}){this.token=t,this.endpoint=e,this.rateLimiter=r||U()}static headers(t){if(!t)throw new Error("missing token");return{Authorization:`Bearer ${t}`,"X-Client":"nftstorage.link/js"}}static async put({endpoint:t,token:e,rateLimiter:r=$},o,{onPut:i,maxRetries:n}={}){o.forEach(C);const s=b.headers(e);return(await w(o.map((async e=>{const o=new URL(`perma-cache/${encodeURIComponent(e)}`,t);return await k((async()=>{await r();const t=await L(o.toString(),{method:"POST",headers:s}),n=await t.json();if(!t.ok){const e=new Error(n.message);if(t.status>=400&&t.status<500)throw new E(e);throw e}return i&&i(e),n}),{retries:null==n?5:n})})))).map(((t,e)=>t.reason?{url:o[e],error:t.reason.message}:t.value))}static async*list({endpoint:t,token:e,rateLimiter:r=$},{sort:o="date",order:i="asc"}={}){const n=b.headers(e);let s=new URLSearchParams({sort:o,order:i}),a=new URL(`perma-cache?${s}`,t);for(;;){await r();const e=await L(a.toString(),{method:"GET",headers:n}),o=await e.json();if(!e.ok)throw new Error(o.message);for(const t of o)yield t;const i=e.headers.get("link");if(!i)break;a=new URL(i.replace("<","").replace('>; rel="next"',""),t)}}static async delete({endpoint:t,token:e,rateLimiter:r=$},o,{onDelete:i,maxRetries:n}={}){o.forEach(C);const s=b.headers(e);return(await w(o.map((async e=>{const o=new URL(`perma-cache/${encodeURIComponent(e)}`,t);return await k((async()=>{await r();const t=await L(o.toString(),{method:"DELETE",headers:s}),n=await t.json();if(!t.ok){const e=new Error(n.message);if(t.status>=400&&t.status<500)throw new E(e);throw e}return i&&i(e),{url:e}}),{retries:null==n?5:n})})))).map(((t,e)=>t.reason?{url:o[e],error:t.reason.message}:t.value))}static async accountInfo({endpoint:t,token:e,rateLimiter:r=$}){const o=new URL("perma-cache/account",t),i=b.headers(e);await r();const n=await L(o.toString(),{method:"GET",headers:i}),s=await n.json();if(!n.ok)throw new Error(s.message);return s}put(t,e){return b.put(this,t,e)}list(t){return b.list(this,t)}delete(t,e){return b.delete(this,t,e)}accountInfo(){return b.accountInfo(this)}}function U(){const t=n(100,6e4);return()=>t((()=>{}))}const $=U();function C(t){const e=new URL(t);if(!(e.hostname.includes(".ipfs.nftstorage.link")||e.hostname.includes("nftstorage.link")&&e.pathname.startsWith("/ipfs")))throw new Error(`Invalid URL (not an nftstorage.link IPFS URL): ${t}`)}export{t as GatewayStatusChecker,b as PermaCache,U as createRateLimiter,r as getGatewayURL};
//# sourceMappingURL=bundle.esm.min.js.map