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

nftstorage.link

Package Overview
Dependencies
Maintainers
5
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

nftstorage.link - npm Package Compare versions

Comparing version 1.1.0 to 2.0.0

dist/src/lib/interface.d.ts

2

dist/bundle.esm.min.js

@@ -1,2 +0,2 @@

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 s=await t(this._apiURL.toString());return"ok"===(await s.json()).status}catch(t){return console.warn("Failed to fetch gateway status:",t),!1}})()),this._request}}const s=new t;async function e(t,e){const a=(e=e||{}).statusChecker||s,i=e.fallbackGatewayURL||"https://dweb.link",h=await a.ok();let{protocol:n,hostname:c,pathname:o,search:r,hash:l}=new URL(t,a.gatewayURL);if("ipfs:"===n||"ipns:"===n)o=c?`/${c}${o}`:o.slice(1),o=`/${n.slice(0,-1)}${o}`;else if(!o.startsWith("/ipfs")&&!o.startsWith("/ipns")){const t=c.split(".");o="ipfs"===t[1]||"ipns"===t[1]?`/${t[1]}/${t[0]}${"/"===o?"":o}`:`/ipfs${o}`}const f=h?a.gatewayURL:i;return new URL(`${o}${r}${l}`,f)}export{t as GatewayStatusChecker,e as getGatewayURL};
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
export * from "./gateway.js";
export * from "./perma-cache.js";
//# sourceMappingURL=lib.d.ts.map
{
"name": "nftstorage.link",
"version": "1.1.0",
"version": "2.0.0",
"description": "Utilities for working with the NFT.Storage IPFS Edge Gateway",

@@ -25,2 +25,7 @@ "type": "module",

},
"./src/perma-cache.js": {
"browser": "./src/perma-cache.js",
"require": "./dist/src/perma-cache.cjs",
"node": "./src/perma-cache.js"
},
"./dist/bundle.esm.min.js": {

@@ -33,7 +38,10 @@ "browser": "./dist/bundle.esm.min.js",

"scripts": {
"test": "run-s test:*",
"test:web": "playwright-test test/*.spec.js --cov && nyc report",
"test:es": "hundreds mocha test/*.spec.js --exit",
"test:cjs": "npm run build:cjs && mocha dist/**/*.spec.cjs --exit",
"build": "run-s build:*",
"test": "npm-run-all -p -r mock:api test:all",
"test:all": "run-s test:web test:cjs test:es test:size",
"test:size": "bundlesize",
"test:web": "API_PORT=1337 playwright-test test/*.spec.js --cov && nyc report",
"test:es": "API_PORT=1337 hundreds mocha test/*.spec.js --exit",
"test:cjs": "npm run build:cjs && API_PORT=1337 mocha dist/**/*.spec.cjs --exit",
"mock:api": "smoke -p 1337 test/mocks/api",
"build": "run-s clean build:*",
"build:ts": "tsc --build",

@@ -43,3 +51,4 @@ "build:cjs": "rollup --config rollup.config.js",

"coverage": "nyc report --reporter=text-lcov > coverage.lcov && npx codecov",
"prepare": "npm run build"
"prepare": "npm run build",
"clean": "rm -rf dist"
},

@@ -58,2 +67,8 @@ "keywords": [

"license": "Apache-2.0 OR MIT",
"dependencies": {
"@web-std/fetch": "^4.1.0",
"p-settle": "^4.1.1",
"p-retry": "^4.5.0",
"throttled-queue": "^2.1.4"
},
"devDependencies": {

@@ -65,3 +80,5 @@ "@rollup/plugin-commonjs": "^21.1.0",

"@types/mocha": "^9.0.0",
"@types/node": "^17.0.36",
"assert": "^2.0.0",
"bundlesize": "^0.18.1",
"c8": "^7.11.2",

@@ -72,8 +89,16 @@ "hundreds": "^0.0.9",

"nyc": "15.1.0",
"playwright-test": "^7.2.1",
"playwright-test": "^7.4.1",
"rollup": "^2.70.2",
"rollup-plugin-multi-input": "^1.3.1",
"rollup-plugin-terser": "^7.0.2",
"smoke": "^3.1.1",
"throttled-queue": "^2.1.2",
"typescript": "^4.6.3"
},
"bundlesize": [
{
"path": "./dist/bundle.esm.min.js",
"maxSize": "30 kB"
}
],
"homepage": "https://github.com/nftstorage/nftstorage.link/tree/main/packages/client",

@@ -80,0 +105,0 @@ "bugs": "https://github.com/nftstorage/nftstorage.link/issues",

@@ -11,147 +11,7 @@ # nftstorage.link client utilities

## Usage
## Libraries and utilities
Import the library in your client application like:
- [perma-cache](./docs/perma-cache.md)
- [gateway](./docs/gateway.md)
```js
import { getGatewayURL } from 'nftstorage.link'
```
### `getGatewayURL`
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). Status result is cached for **60 seconds** by default.
Note: the fallback gateway is not guaranteed to be operational and this library makes no attempt to verify this.
```ts
getGatewayURL (cid: string|URL): Promise<string>
// (typical usage - also takes options object as second param)
```
#### Examples
```js
const url = await getGatewayURL(
'bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui'
)
console.log(url)
// https://nftstorage.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
// or
// https://dweb.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
```
Also works with CID + path:
```js
const url = await getGatewayURL(
'bafyreihwsoxxcxfsisghlc22xzc6datssd7n52wonpdgrhu3lwyqqagzye/metadata.json'
)
console.log(url)
// https://nftstorage.link/ipfs/bafyreihwsoxxcxfsisghlc22xzc6datssd7n52wonpdgrhu3lwyqqagzye/metadata.json
// or
// https://dweb.link/ipfs/bafyreihwsoxxcxfsisghlc22xzc6datssd7n52wonpdgrhu3lwyqqagzye/metadata.json
```
Also works with `ipfs://` URL:
```js
const url = await getGatewayURL(
'ipfs://bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui'
)
console.log(url)
// https://nftstorage.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
// or
// https://dweb.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
```
Also works with _any_ IPFS gateway URL:
```js
const url = await getGatewayURL(
'https://ipfs.io/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui'
)
console.log(url)
// https://nftstorage.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
// or
// https://dweb.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
```
...including _subdomain_ gateway URL:
```js
const url = await getGatewayURL(
'https://bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui.ipfs.dweb.link'
)
console.log(url)
// https://nftstorage.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
// or
// https://dweb.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
```
You can also specify a different fallback gateway URL:
```js
const fallbackGatewayURL = 'https://ipfs.io' // default is 'https://dweb.link'
const url = await getGatewayURL(
'bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui',
{ fallbackGatewayURL }
)
console.log(url)
// https://nftstorage.link/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
// or
// https://ipfs.io/ipfs/bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui
```
##### React Components
Example of how this function could be used in a React project:
```js
import { useState, useEffect } from 'react'
import { getGatewayURL } from 'nftstorage.link'
function GatewayLink({ cid, title }) {
const [url, setUrl] = useState('')
useEffect(() => {
getGatewayURL(cid).then(setUrl)
}, [cid])
return url ? <a href={url}>{title}</a> : null
}
function GatewayImage({ cid, alt }) {
const [url, setUrl] = useState('')
useEffect(() => {
getGatewayURL(cid).then(setUrl)
}, [cid])
return url ? <img src={url} alt={alt} /> : null
}
```
See the full example here: https://github.com/nftstorage/react-nftstorage.link-fallback-example
##### Node.js usage
This library uses the `fetch` API. In Node.js there are two options to enable usage:
Assign to global:
```js
import fetch from '@web-std/fetch' // npm install @web-std/fetch
globalThis.fetch = fetch
// use getGatewayURL etc. as usual
```
Pass to `GatewayStatusChecker`:
```js
import { getGatewayURL, GatewayStatusChecker } from 'nftstorage.link'
import fetch from '@web-std/fetch' // npm install @web-std/fetch
const statusChecker = new GatewayStatusChecker({ fetch })
const url = await getGatewayURL(
'bafkreiem4twkqzsq2aj4shbycd4yvoj2cx72vezicletlhi7dijjciqpui',
{ statusChecker }
)
```
## Contributing

@@ -158,0 +18,0 @@

export * from './gateway.js'
export * from './perma-cache.js'

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

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