Awesome
ipfs-provider
<!-- TODO: improve this API - [create our own!](#creating-a-provider) -->Returns IPFS API object by trying multiple providers in a custom fallback order.
This is a general-purpose replacement for ipfs-redux-bundle.
Install
via NPM
$ npm install ipfs-provider
via prebuilt browser bundles
<!-- remember to include js-ipfs (core) and/or js-ipfs-http-client, if they are used -->
<script src="https://cdn.jsdelivr.net/npm/ipfs-core/dist/index.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/ipfs-http-client/dist/index.min.js"></script>
<!-- prebuilt and minified bundle -->
<script src="https://cdn.jsdelivr.net/npm/ipfs-provider/dist/index.min.js"></script>
<script>
const { getIpfs, providers } = window.IpfsProvider
const { ipfs, provider, apiAddress } = await getIpfs({
loadHttpClientModule: () => window.IpfsHttpClient,
loadJsIpfsModule: () => window.IpfsCore,
providers: [ /* see Usage below */ ]
})
</script>
Note: when using prebuilt bundles in production use explicit versions and SRI hashes. Details here.
<!-- TODO: add prebuild+versions+sri example to ./examples -->Usage
const { getIpfs, providers } = require('ipfs-provider')
const { httpClient, jsIpfs } = providers
const { ipfs, provider, apiAddress } = await getIpfs({
// when httpClient provider is used multiple times
// define its constructor once, at the top level
loadHttpClientModule: () => require('ipfs-http-client'),
// note this is an array, providers are tried in order:
providers: [
// try various HTTP endpoints (best-effort),
httpClient({
// (1) try multiaddr of a local node
apiAddress: '/ip4/127.0.0.1/tcp/5001'
}),
httpClient(), // (2) try "/api/v0/" on the same Origin as the page
httpClient({
// (3) try arbitrary API from URL string
apiAddress: 'https://some.example.com:8080'
}),
httpClient({
// (4) try API defined by a custom http client config
apiAddress: {
host: 'apis.example.com',
port: '443',
protocol: 'https',
apiPath: 'custom/path/to/api/v0',
headers: {
authorization: 'Basic dXNlcjpwYXNz'
}
}
}),
// (5) final fallback to spawning embedded js-ipfs running in-page
jsIpfs({
// js-ipfs package is used only once, as a last resort
loadJsIpfsModule: () => require('ipfs-core'),
options: { } // pass config: https://github.com/ipfs/js-ipfs/blob/master/packages/ipfs/docs/MODULE.md#ipfscreateoptions
})
]
})
for await (const file of ipfs.add("text")) {
if (file && file.cid) {
console.log(`successfully stored at ${file.cid}`)
} else {
console.error('unable to ipfs.add', file)
}
}
ipfs
– returned instance of IPFS API (see SPEC)provider
– a string with a name of the first successful provider.- built-in names match constants from
providers
:httpClient
,jsIpfs
,windowIpfs
andwebExt
.
- built-in names match constants from
apiAddress
– returned only whenhttpClient
provider is used, provides information which HTTP endpoint succeded
Examples
See examples/
for sample code and demonstration of advanced fallback strategies.
Providers
You can customize the order of the providers by passing a different array order to the providers
array.
For example, if you want to try httpClient
and then jsIpfs
, you should run it like this:
const { getIpfs, providers } = require('ipfs-provider')
const { httpClient, jsIpfs } = providers
const { ipfs, provider } = await getIpfs({
providers: [
httpClient(),
jsIpfs()
]
})
Customizing connection test
const { ipfs, provider } = await getIpfs({
providers: [ /* array of providers to try in order */ ],
connectionTest: () => { /* boolean function to test the connection to IPFS, default one tries to ipfs.get the CID of an empty directory */ },
})
httpClient
Tries to connect to HTTP API via js-ipfs-http-client
:
const { ipfs, provider } = await getIpfs({
providers: [
httpClient({
loadHttpClientModule: () => require('ipfs-http-client'),
apiAddress: 'https://api.example.com:8080/'
})
]
})
This provider will attempt to establish connection with (in order):
apiAddress
(if provided)/api/
at the current Origin- the default local API (
/ip4/127.0.0.1/tcp/5001
)
It supports lazy-loading and small bundle sizes. The client library is initialized using constructor (in order):
- one returned by
loadHttpClientModule
async function (if provided) - one exposed at
window.IpfsHttpClient
(if present)
Value passed in apiAddress
can be:
- a multiaddr (string like
/ip4/127.0.0.1/tcp/5001
or an object) - a String with an URL (
https://api.example.com:8080/
) - a configuration object supported by the constructor
(
{ host: '1.1.1.1', port: '80', apiPath: '/ipfs/api/v0' }
)
To try multiple endpoints, simply use this provider multiple times.
See examples/browser-browserify/src/index.js
for real world example.
jsIpfs
Spawns embedded js-ipfs
(a full IPFS node in JavaScript)
in the context of the current page using customizable constructor:
const { ipfs, provider } = await getIpfs({
providers: [
jsIpfs({
loadJsIpfsModule: () => require('ipfs-core'),
options: { /* advanced config */ }
})
]
})
loadJsIpfsModule
should be a function that returns a promise that resolves to a js-ipfs constructor <!-- TODO confirm below is true, if it is, add example to examples/ and link to it This works well with [dynamic `import()`](https://developers.google.com/web/updates/2017/11/dynamic-import), so you can lazily load js-ipfs when it is needed. -->options
should be an object which specifies advanced configurations to the node.- TIP: when used in a browser context, use
ipfs-core
for a smaller browser bundle
windowIpfs
window.ipfs
was an experiment created by ipfs-companion browser extension.
It supported passing an optional list of permissions to display a single ACL prompt the first time it is used:
const { ipfs, provider } = await getIpfs({
providers: [
windowIpfs({
// example
permissions: { commands: ['add','cat','id', 'version'] }
})
]
})
webExt
webExt
looks for an instance in the background page of a WebExtension
(useful only in browser extensions, not regular pages, disabled by default)
const { ipfs, provider } = await getIpfs({
providers: [
webExt()
]
})
<!-- TODO: improve this API
#### Creating a provider
If built-in providers do not solve your use case, create your own!
A provider is just a function that returns an async function that returns
`{ ipfs, provider }`, but we provide `makeProvider` which enables `connectionTest`:
```js
const { getIpfs, makeProvider } = require('ipfs-provider')
const customProvider = makeProvider(async ({ connectionTest }) => {
try {
const ipfs = // create IPFS API instance somehow
await connectionTest(ipfs)
return { ipfs, provider: 'customProvider' }
} catch (_) {
return null
}
})
const { ipfs, provider } = await getIpfs({
providers: [
customProvider()
]
})
```
-->
Test
$ npm test
Lint
Perform standard
linting on the code:
$ npm run lint
Contribute
Feel free to dive in! Open an issue or submit PRs.
To contribute to IPFS in general, see the contributing guide.
License
MIT © Protocol Labs