Skip to content

Latest commit

 

History

History
1208 lines (902 loc) · 70.2 KB

README.md

File metadata and controls

1208 lines (902 loc) · 70.2 KB

The JavaScript implementation of the IPFS protocol.


Project status - Alpha

We've come a long way, but this project is still in Alpha, lots of development is happening, API might change, beware of the Dragons 🐉..

Want to get started? Check our examples folder to learn how to spawn an IPFS node in Node.js and in the Browser.

Please read this: The DHT, a fundamental piece for automatic content and peer discovery is not yet complete. There are multiple applications that can be built without this service but nevertheless it is fundamental to getting that magic IPFS experience. The current status is that implementation is done and merged and we're working on performance issues. Expect the DHT to be available in a release very soon.

Weekly Core Dev Calls

Tech Lead

David Dias

Lead Maintainer

Alan Shaw

Table of Contents

Install

npm

This project is available through npm. To install, run:

> npm install ipfs

JS IPFS depends on native modules that are installed by node-gyp. If you have problems running the command above, it is likely that the build tools required by node-gyp are missing from your system. Please install them and then try again.

We support both the Current and Active LTS versions of Node.js. Please see nodejs.org for what these currently are.

This project is tested on macOS, Linux and Windows.

Use in Node.js

To create an IPFS node programmatically:

const IPFS = require('ipfs')
const node = await IPFS.create()

// Ready to use!
// See https://github.com/ipfs/js-ipfs#core-api

Through command line tool

In order to use js-ipfs as a CLI, you must install it with the global flag. Run the following (even if you have ipfs installed locally):

npm install ipfs --global

The CLI is available by using the command jsipfs in your terminal. This is aliased, instead of using ipfs, to make sure it does not conflict with the Go implementation.

Use in the browser

Learn how to bundle with browserify and webpack in the examples folder.

You can also load it using a <script> using the unpkg CDN or the jsDelivr CDN. Inserting one of the following lines will make an Ipfs object available in the global namespace.

<!-- loading the minified version using unpkg -->
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>

<!-- loading the human-readable (not minified) version using unpkg -->
<script src="https://unpkg.com/ipfs/dist/index.js"></script>

OR THIS:

<!-- loading the minified version using jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/ipfs/dist/index.min.js"></script>

<!-- loading the human-readable (not minified) version jsDelivr -->
<script src="https://cdn.jsdelivr.net/npm/ipfs/dist/index.js"></script>

Inserting one of the above lines will make an Ipfs object available in the global namespace:

<script>
async function main () {
  const node = await window.Ipfs.create()
  // Ready to use!
  // See https://github.com/ipfs/js-ipfs#core-api
}
main()
</script>

Usage

IPFS CLI

The jsipfs CLI, available when js-ipfs is installed globally, follows (should, it is a WIP) the same interface defined by go-ipfs, you can always use the help command for help menus.

# Install js-ipfs globally
> npm install ipfs --global
> jsipfs --help
Commands:
  bitswap               A set of commands to manipulate the bitswap agent.
  block                 Manipulate raw IPFS blocks.
  bootstrap             Show or edit the list of bootstrap peers.
  commands              List all available commands
  config <key> [value]  Get and set IPFS config values
  daemon                Start a long-running daemon process
# ...

js-ipfs uses some different default config values, so that they don't clash directly with a go-ipfs node running in the same machine. These are:

  • default repo location: ~/.jsipfs (can be changed with env variable IPFS_PATH)
  • default swarm port: 4002
  • default API port: 5002

IPFS Daemon

The IPFS Daemon exposes the API defined in the HTTP API spec`. You can use any of the IPFS HTTP-API client libraries with it, such as: js-ipfs-http-client.

If you want a programmatic way to spawn a IPFS Daemon using JavaScript, check out ipfsd-ctl module

IPFS Module

Use the IPFS Module as a dependency of a project to spawn in process instances of IPFS. Create an instance by calling await IPFS.create():

// Create the IPFS node instance
const node = await IPFS.create()
// Your node is now ready to use \o/
await node.stop()
// node is now 'offline'

You can find some examples and tutorials in the examples folder, these exist to help you get started using js-ipfs.

API

IPFS Constructor

const node = await IPFS.create([options])

Creates and returns a ready to use instance of an IPFS node.

Alternative method to construct an IPFS node

The recommended method of creating a new IPFS node is to use the IPFS.create method. However, IPFS is a class, and can also be constructed using the new keyword:

const node = new IPFS([options])

At this point, your node has been created but is not ready to use. You must either attach a listener for the "ready" event or wait for the node.ready promise to resolve:

node.on('ready', () => { /* Node is now ready to use */ })
// OR
await node.ready

Use the options argument to specify advanced configuration. It is an object with any of these properties:

options.repo
Type Default
string or ipfs.Repo instance '~/.jsipfs' in Node.js, 'ipfs' in browsers

The file path at which to store the IPFS node’s data. Alternatively, you can set up a customized storage system by providing an ipfs.Repo instance.

Example:

// Store data outside your user directory
const node = await IPFS.create({ repo: '/var/ipfs/data' })
options.init
Type Default
boolean or object true

Initialize the repo when creating the IPFS node.

If you have already initialized a repo before creating your IPFS node (e.g. you are loading a repo that was saved to disk from a previous run of your program), you must make sure to set this to false. Note that initializing a repo is different from creating an instance of ipfs.Repo. The IPFS constructor sets many special properties when initializing a repo, so you should usually not try and call repoInstance.init() yourself.

Instead of a boolean, you may provide an object with custom initialization options. All properties are optional:

  • emptyRepo (boolean) Whether to remove built-in assets, like the instructional tour and empty mutable file system, from the repo. (Default: false)
  • bits (number) Number of bits to use in the generated key pair. (Default: 2048)
  • privateKey (string/PeerId) A pre-generated private key to use. Can be either a base64 string or a PeerId instance. NOTE: This overrides bits.
    // Generating a Peer ID:
    const PeerId = require('peer-id')
    PeerId.create({ bits: 2048 }, (err, peerId) => {
      // Generates a new Peer ID, complete with public/private keypair
      // See https://github.com/libp2p/js-peer-id
    })
  • pass (string) A passphrase to encrypt keys. You should generally use the top-level pass option instead of the init.pass option (this one will take its value from the top-level option if not set).
options.start
Type Default
boolean true

If false, do not automatically start the IPFS node. Instead, you’ll need to manually call node.start() yourself.

options.pass
Type Default
string null

A passphrase to encrypt/decrypt your keys.

options.silent
Type Default
Boolean false

Prevents all logging output from the IPFS node.

options.relay
Type Default
object { enabled: true, hop: { enabled: false, active: false } }

Configure circuit relay (see the circuit relay tutorial to learn more).

  • enabled (boolean): Enable circuit relay dialer and listener. (Default: true)
  • hop (object)
    • enabled (boolean): Make this node a relay (other nodes can connect through it). (Default: false)
    • active (boolean): Make this an active relay node. Active relay nodes will attempt to dial a destination peer even if that peer is not yet connected to the relay. (Default: false)
options.preload
Type Default
object { enabled: true, addresses: [...] }

Configure remote preload nodes. The remote will preload content added on this node, and also attempt to preload objects requested by this node.

  • enabled (boolean): Enable content preloading (Default: true)
  • addresses (array): Multiaddr API addresses of nodes that should preload content. NOTE: nodes specified here should also be added to your node's bootstrap address list at config.Boostrap.
options.EXPERIMENTAL
Type Default
object { pubsub: false, sharding: false, dht: false }

Enable and configure experimental features.

  • pubsub (boolean): Enable libp2p pub-sub. (Default: false)
  • ipnsPubsub (boolean): Enable pub-sub on IPNS. (Default: false)
  • sharding (boolean): Enable directory sharding. Directories that have many child objects will be represented by multiple DAG nodes instead of just one. It can improve lookup performance when a directory has several thousand files or more. (Default: false)
options.config
Type Default
object config-nodejs.js in Node.js, config-browser.js in browsers

Modify the default IPFS node config. This object will be merged with the default config; it will not replace it. The default config is documented in the js-ipfs config file doc.

Configuring Delegate Routers

If you need to support Delegated Content and/or Peer Routing, you can enable it by specifying the multiaddrs of your delegate nodes in the config via options.config.Addresses.Delegates. If you need to run a delegate router we encourage you to run your own, with go-ipfs. You can see instructions for doing so in the delegated routing example.

If you are not able to run your own delegate router nodes, we currently have two nodes that support delegated routing. Important: As many people may be leveraging these nodes, performance may be affected, which is why we recommend running your own nodes in production.

Available delegate multiaddrs are:

  • /dns4/node0.preload.ipfs.io/tcp/443/https
  • /dns4/node1.preload.ipfs.io/tcp/443/https

Note: If more than 1 delegate multiaddr is specified, the actual delegate will be randomly selected on startup.

options.ipld
Type Default
object ipld-nodejs.js in Node.js, ipld-browser.js in browsers

Modify the default IPLD config. This object will be merged with the default config; it will not replace it. Check IPLD docs for more information on the available options.

Browser config does NOT include by default all the IPLD formats. Only ipld-dag-pb, ipld-dag-cbor and ipld-raw are included.

To add support for other formats we provide two options, one sync and another async.

Examples for the sync option:

ESM Environments
import ipldGit from 'ipld-git'
import ipldBitcoin from 'ipld-bitcoin'

const node = await IPFS.create({
  ipld: {
    formats: [ipldGit, ipldBitcoin]
  }
})
Commonjs Environments
const node = await IPFS.create({
  ipld: {
    formats: [require('ipld-git'), require('ipld-bitcoin')]
  }
})
Using script tags
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>
<script src="https://unpkg.com/ipld-git/dist/index.min.js"></script>
<script src="https://unpkg.com/ipld-bitcoin/dist/index.min.js"></script>
<script>
async function main () {
  const node = await self.IPFS.create({
    ipld: {
      formats: [self.IpldGit, self.IpldBitcoin]
    }
  })
}
main()
</script>

Examples for the async option:

ESM Environments
const node = await IPFS.create({
  ipld: {
    async loadFormat (codec) {
      if (codec === multicodec.GIT_RAW) {
        return import('ipld-git') // This is a dynamic import
      } else {
        throw new Error('unable to load format ' + multicodec.print[codec])
      }
    }
  }
})

For more information about dynamic imports please check webpack docs or search your bundler documention.

Using dynamic imports will tell your bundler to create a separate file (normally called chunk) that will only be requested by the browser if it's really needed. This strategy will reduce your bundle size and load times without removing any functionality.

With Webpack IPLD formats can even be grouped together using magic comments import(/* webpackChunkName: "ipld-formats" */ 'ipld-git') to produce a single file with all of them.

Commonjs Environments
const node = await IPFS.create({
  ipld: {
    async loadFormat (codec) {
      if (codec === multicodec.GIT_RAW) {
        return require('ipld-git')
      } else {
        throw new Error('unable to load format ' + multicodec.print[codec])
      }
    }
  }
})
Using Script tags
<script src="https://unpkg.com/ipfs/dist/index.min.js"></script>
<script>
const load = (name, url) => new Promise((resolve, reject) => {
  const script = document.createElement('script')
  script.src = url
  script.onload = () => resolve(self[name])
  script.onerror = () => reject(new Error('Failed to load ' + url))
  document.body.appendChild(script)
})

const node = await self.IPFS.create({
  ipld: {
    async loadFormat (codec) {
      switch (codec) {
        case multicodec.GIT_RAW:
          return load('IpldGit', 'https://unpkg.com/ipld-git/dist/index.min.js')
        case multicodec.BITCOIN_BLOCK:
          return load('IpldBitcoin', 'https://unpkg.com/ipld-bitcoin/dist/index.min.js')
        default:
          throw new Error('Unable to load format ' + multicodec.print[codec])
      }
    }
  }
})
</script>
options.libp2p
Type Default
object libp2p-nodejs.js in Node.js, libp2p-browser.js in browsers
function libp2p bundle

The libp2p option allows you to build your libp2p node by configuration, or via a bundle function. If you are looking to just modify the below options, using the object format is the quickest way to get the default features of libp2p. If you need to create a more customized libp2p node, such as with custom transports or peer/content routers that need some of the ipfs data on startup, a custom bundle is a great way to achieve this.

You can see the bundle in action in the custom libp2p example.

  • modules (object):
    • transport (Array<libp2p.Transport>): An array of Libp2p transport classes/instances to use instead of the defaults. See libp2p/interface-transport for details.
    • peerDiscovery (Array<libp2p.PeerDiscovery>): An array of Libp2p peer discovery classes/instances to use instead of the defaults. See libp2p/peer-discovery for details. If passing a class, configuration can be passed using the config section below under the key corresponding to you module's unique tag (a static property on the class)
  • config (object):
    • peerDiscovery (object):
      • autoDial (boolean): Dial to discovered peers when under the Connection Manager min peer count watermark. (default true)
      • [PeerDiscovery.tag] (object): configuration for a peer discovery module
        • enabled (boolean): whether this module is enabled or disabled
        • [custom config] (any): other keys are specific to the module
    • dht (object): Configuration options for the DHT (WARNING: the current DHT implementation has performance issues, your mileage may vary)
      • enabled (boolean): whether the DHT is enabled or not (default false)
      • kBucketSize (number): bucket size (default 20)
      • randomWalk (object): configuration for random walk
        • enabled (boolean): whether random DHT walking is enabled (default false)
options.connectionManager
Type Default
object defaults

Configure the libp2p connection manager.

Events

IPFS instances are Node.js EventEmitters. You can listen for events by calling node.on('event', handler):

const node = await IPFS.create({ repo: '/var/ipfs/data' })
node.on('error', errorObject => console.error(errorObject))
  • error is always accompanied by an Error object with information about the error that occurred.

    node.on('error', error => {
      console.error(error.message)
    })
  • init is emitted after a new repo has been initialized. It will not be emitted if you set the init: false option on the constructor.

  • ready is emitted when a node is ready to use. This is the final event you will receive when creating a node (after init and start).

    When creating a new IPFS node, you should almost always wait for the ready event before calling methods or interacting with the node.

  • start is emitted when a node has started listening for connections. It will not be emitted if you set the start: false option on the constructor.

  • stop is emitted when a node has closed all connections and released access to its repo. This is usually the result of calling node.stop().

node.ready

A promise that resolves when the node is ready to use. Should be used when constructing an IPFS node using new. You don't need to use this if you're using await IPFS.create. e.g.

const node = new IPFS()
await node.ready
// Ready to use!

node.start()

Start listening for connections with other IPFS nodes on the network. In most cases, you do not need to call this method — IPFS.create() will automatically do it for you.

This method is asynchronous and returns a promise.

const node = await IPFS.create({ start: false })
console.log('Node is ready to use but not started!')

try {
  await node.start()
  console.log('Node started!')
} catch (error) {
  console.error('Node failed to start!', error)
}
Starting using callbacks and events

If you pass a function to this method, it will be called when the node is started (Note: this method will not return a promise if you use a callback function).

// Note: you can use the class constructor style for more
// idiomatic callback/events style code
const node = new IPFS({ start: false })

node.on('ready', () => {
  console.log('Node is ready to use but not started!')

  node.start(error => {
    if (error) {
      return console.error('Node failed to start!', error)
    }
    console.log('Node started!')
  })
})

Alternatively you can listen for the start event:

// Note: you can use the class constructor style for more
// idiomatic callback/events style code
const node = new IPFS({ start: false })

node.on('ready', () => {
  console.log('Node is ready to use but not started!')
  node.start()
})

node.on('error', error => {
  console.error('Something went terribly wrong!', error)
})

node.on('start', () => console.log('Node started!'))

node.stop()

Close and stop listening for connections with other IPFS nodes, then release access to the node’s repo.

This method is asynchronous and returns a promise.

const node = await IPFS.create()
console.log('Node is ready to use!')

try {
  await node.stop()
  console.log('Node stopped!')
} catch (error) {
  console.error('Node failed to stop!', error)
}
Stopping using callbacks and events

If you pass a function to this method, it will be called when the node is stopped (Note: this method will not return a promise if you use a callback function).

// Note: you can use the class constructor style for more
// idiomatic callback/events style code
const node = new IPFS()

node.on('ready', () => {
  console.log('Node is ready to use!')

  node.stop(error => {
    if (error) {
      return console.error('Node failed to stop cleanly!', error)
    }
    console.log('Node stopped!')
  })
})

Alternatively you can listen for the stop event.

const node = new IPFS()

node.on('ready', () => {
  console.log('Node is ready to use!')
  node.stop()
})

node.on('error', error => {
  console.error('Something went terribly wrong!', error)
})

node.on('stop', () => console.log('Node stopped!'))

Core API

The IPFS core API provides all functionality that is not specific to setting up and starting or stopping a node. This API is available directly on an IPFS instance, on the command line (when using the CLI interface), and as an HTTP REST API. For a complete reference, see .

All the API methods aside from streaming methods (ones that end in ReadableStream or PullStream) are asynchronous and return Promises, but also accept callbacks.

The core API is grouped into several areas:

Files

Graph

Block

Name

Crypto and Key Management

Network

Node Management

Static types and utils

Aside from the default export, ipfs exports various types and utilities that are included in the bundle:

These can be accessed like this, for example:

const { CID } = require('ipfs')
// ...or from an es-module:
import { CID } from 'ipfs'

FAQ

How to enable WebRTC support for js-ipfs in the Browser

To add a WebRTC transport to your js-ipfs node, you must add a WebRTC multiaddr. To do that, simple override the config.Addresses.Swarm array which contains all the multiaddrs which the IPFS node will use. See below:

const node = await IPFS.create({
  config: {
    Addresses: {
      Swarm: [
        '/dns4/wrtc-star.discovery.libp2p.io/tcp/443/wss/p2p-webrtc-star'
      ]
    }
  }
})

// your instance with WebRTC is ready

Important: This transport usage is kind of unstable and several users have experienced crashes. Track development of a solution at ipfs#1088.

Is there WebRTC support for js-ipfs with Node.js?

Yes, however, bear in mind that there isn't a 100% stable solution to use WebRTC in Node.js, use it at your own risk. The most tested options are:

To add WebRTC support in a IPFS node instance, do:

const wrtc = require('wrtc') // or require('electron-webrtc')()
const WStar = require('libp2p-webrtc-star')
const wstar = new WStar({ wrtc })

const node = await IPFS.create({
  repo: 'your-repo-path',
  // start: false,
  config: {
    Addresses: {
      Swarm: [
        "/ip4/0.0.0.0/tcp/4002",
        "/ip4/127.0.0.1/tcp/4003/ws",
        "/dns4/wrtc-star.discovery.libp2p.io/tcp/443/wss/p2p-webrtc-star"
      ]
    }
  },
  libp2p: {
    modules: {
      transport: [wstar],
      peerDiscovery: [wstar.discovery]
    }
  }
})

// your instance with WebRTC is ready

To add WebRTC support to the IPFS daemon, you only need to install one of the WebRTC modules globally:

npm install wrtc --global
# or
npm install electron-webrtc --global

Then, update your IPFS Daemon config to include the multiaddr for this new transport on the Addresses.Swarm array. Add: "/dns4/wrtc-star.discovery.libp2p.io/wss/p2p-webrtc-star"

How can I configure an IPFS node to use a custom signaling endpoint for my WebRTC transport?

You'll need to execute a compatible signaling server (libp2p-webrtc-star works) and include the correct configuration param for your IPFS node:

  • provide the multiaddr for the signaling server
const node = await IPFS.create({
  repo: 'your-repo-path',
  config: {
    Addresses: {
      Swarm: [
        '/ip4/127.0.0.1/tcp/9090/ws/p2p-webrtc-star'
      ]
    }
  }
})

The code above assumes you are running a local signaling server on port 9090. Provide the correct values accordingly.

Is there a more stable alternative to webrtc-star that offers a similar functionality?

Yes, websocket-star! A WebSockets based transport that uses a Relay to route the messages. To enable it, just do:

const node = await IPFS.create({
  config: {
    Addresses: {
      Swarm: [
        '/dns4/ws-star.discovery.libp2p.io/tcp/443/wss/p2p-websocket-star'
      ]
    }
  }
})

// your instance with websocket-star is ready

I see some slowness when hopping between tabs Chrome with IPFS nodes, is there a reason why?

Yes, unfortunately, due to Chrome aggressive resource throttling policy, it cuts freezes the execution of any background tab, turning an IPFS node that was running on that webpage into a vegetable state.

A way to mitigate this in Chrome, is to run your IPFS node inside a Service Worker, so that the IPFS instance runs in a background process. You can learn how to install an IPFS node as a service worker in here the repo ipfs-service-worker

Can I use IPFS in my Electron App?

Yes you can and in many ways. Read ipfs/notes#256 for the multiple options.

We now support Electron v5.0.0 without the need to rebuilt native modules. Still if you run into problems with native modules follow these instructions here.

Have more questions?

Ask for help in our forum at https://discuss.ipfs.io or in IRC (#ipfs on Freenode).

Running js-ipfs with Docker

We have automatic Docker builds setup with Docker Hub: https://hub.docker.com/r/ipfs/js-ipfs/

All branches in the Github repository maps to a tag in Docker Hub, except master Git branch which is mapped to latest Docker tag.

You can run js-ipfs like this:

$ docker run -it -p 4002:4002 -p 4003:4003 -p 5002:5002 -p 9090:9090 ipfs/js-ipfs:latest

initializing ipfs node at /root/.jsipfs
generating 2048-bit RSA keypair...done
peer identity: Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS
to get started, enter:

         jsipfs files cat /ipfs/QmfGBRT6BbWJd7yUc2uYdaUZJBbnEFvTqehPFoSMQ6wgdr/readme

Initializing daemon...
Using wrtc for webrtc support
Swarm listening on /ip4/127.0.0.1/tcp/4003/ws/ipfs/Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS
Swarm listening on /ip4/172.17.0.2/tcp/4003/ws/ipfs/Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS
Swarm listening on /ip4/127.0.0.1/tcp/4002/ipfs/Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS
Swarm listening on /ip4/172.17.0.2/tcp/4002/ipfs/Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS
API is listening on: /ip4/0.0.0.0/tcp/5002
Gateway (readonly) is listening on: /ip4/0.0.0.0/tcp/9090
Daemon is ready

$ curl --silent localhost:5002/api/v0/id | jq .ID
"Qmbd5jx8YF1QLhvwfLbCTWXGyZLyEJHrPbtbpRESvYs4FS"

Packages

Listing of the main packages used in the IPFS ecosystem. There are also three specifications worth linking here:

This table is generated using the module package-table with package-table --data=package-list.json.

Package Version Deps CI/Travis Coverage Lead Maintainer
Files
ipfs-unixfs-engine npm Deps Travis CI codecov Alex Potsides
DAG
ipld npm Deps Travis CI codecov Volker Mische
ipld-dag-pb npm Deps Travis CI codecov Volker Mische
ipld-dag-cbor npm Deps Travis CI codecov Volker Mische
Repo
ipfs-repo npm Deps Travis CI codecov Jacob Heun
Exchange
ipfs-block-service npm Deps Travis CI codecov Volker Mische
ipfs-bitswap npm Deps Travis CI codecov Dirk McCormick
libp2p
libp2p npm Deps Travis CI codecov Jacob Heun
libp2p-circuit npm Deps Travis CI codecov Jacob Heun
libp2p-floodsub npm Deps Travis CI codecov Vasco Santos
libp2p-kad-dht npm Deps Travis CI codecov Vasco Santos
libp2p-mdns npm Deps Travis CI codecov Jacob Heun
libp2p-bootstrap npm Deps Travis CI codecov Vasco Santos
libp2p-secio npm Deps Travis CI codecov Friedel Ziegelmayer
libp2p-tcp npm Deps Travis CI codecov Jacob Heun
libp2p-webrtc-star npm Deps Travis CI codecov Vasco Santos
libp2p-websocket-star npm Deps Travis CI codecov Jacob Heun
libp2p-websockets npm Deps Travis CI codecov Jacob Heun
pull-mplex npm Deps Travis CI codecov Jacob Heun
Data Types
ipfs-block npm Deps Travis CI codecov Volker Mische
ipfs-unixfs npm Deps Travis CI codecov Alex Potsides
peer-id npm Deps Travis CI codecov Pedro Teixeira
peer-info npm Deps Travis CI codecov Pedro Teixeira
multiaddr npm Deps Travis CI codecov Jacob Heun
multihashes npm Deps Travis CI codecov David Dias
Crypto
libp2p-crypto npm Deps Travis CI codecov Friedel Ziegelmayer
libp2p-keychain npm Deps Travis CI codecov Vasco Santos
Generics/Utils
ipfs-http-client npm Deps Travis CI codecov Alan Shaw
ipfs-multipart npm Deps Travis CI codecov N/A
is-ipfs npm Deps Travis CI codecov Marcin Rataj
multihashing npm Deps Travis CI codecov Hugo Dias
mafmt npm Deps Travis CI codecov Vasco Santos

Development

Clone and install dependencies

> git clone https://github.com/ipfs/js-ipfs.git
> cd js-ipfs
> npm install

Run tests

# run all the unit tests
> npm test

# run individual tests (findprovs)
> npm run test -- --grep findprovs

# run just IPFS tests in Node.js
> npm run test:node

# run just IPFS core tests
> npm run test:node:core

# run just IPFS HTTP-API tests
> npm run test:node:http

# run just IPFS CLI tests
> npm run test:node:cli

# run just IPFS core tests in the Browser (Chrome)
> npm run test:browser

# run some interface tests (block API) on Node.js
> npm run test:node:interface -- --grep '.block'

Run interop tests

Run the interop tests with https://github.com/ipfs/interop

Run benchmark tests

# run all the benchmark tests
> npm run benchmark

# run just IPFS benchmarks in Node.js
> npm run benchmark:node

# run just IPFS benchmarks in Node.js for an IPFS instance
> npm run benchmark:node:core

# run just IPFS benchmarks in Node.js for an IPFS daemon
> npm run benchmark:node:http

# run just IPFS benchmarks in the browser (Chrome)
> npm run benchmark:browser

Lint

Conforming to linting rules is a prerequisite to commit to js-ipfs.

> npm run lint

Build a dist version

> npm run build

Code Architecture and folder Structure

Source code
> tree src -L 2
src                 # Main source code folder
├── cli             # Implementation of the IPFS CLI
│   └── ...
├── http            # The HTTP-API implementation of IPFS as defined by HTTP API spec
├── core            # IPFS implementation, the core (what gets loaded in browser)
│   ├── components  # Each of IPFS subcomponent
│   └── ...
└── ...

Monitoring

The HTTP API exposed with js-ipfs can also be used for exposing metrics about the running js-ipfs node and other Node.js metrics.

To enable it, you need to set the environment variable IPFS_MONITORING (any value)

Once the environment variable is set and the js-ipfs daemon is running, you can get the metrics (in prometheus format) by making a GET request to the following endpoint:

http://localhost:5002/debug/metrics/prometheus

IPFS Architecture

Annotated versionj

What does this image explain?

  • IPFS uses ipfs-repo which picks fs or indexeddb as its storage drivers, depending if it is running in Node.js or in the Browser.
  • The exchange protocol, bitswap, uses the Block Service which in turn uses the Repo, offering a get and put of blocks to the IPFS implementation.
  • The DAG API (previously Object) comes from the IPLD Resolver, it can support several IPLD Formats (i.e: dag-pb, dag-cbor, etc).
  • The Files API uses ipfs-unixfs-engine to import and export files to and from IPFS.
  • libp2p, the network stack of IPFS, uses libp2p to dial and listen for connections, to use the DHT, for discovery mechanisms, and more.

Contribute

IPFS implementation in JavaScript is a work in progress. As such, there's a few things you can do right now to help out:

  • Go through the modules below and check out existing issues. This would be especially useful for modules in active development. Some knowledge of IPFS may be required, as well as the infrastructure behind it - for instance, you may need to read up on p2p and more complex operations like muxing to be able to help technically.
  • Perform code reviews. More eyes will help (a) speed the project along, (b) ensure quality, and (c) reduce possible future bugs.
  • Take a look at go-ipfs and some of the planning repositories or issues: for instance, the libp2p spec. Contributions here that would be most helpful are top-level comments about how it should look based on our understanding. Again, the more eyes the better.
  • Add tests. There can never be enough tests.

Want to hack on IPFS?

License

FOSSA Status