@ipld/stack

This repository is an exporatory space to work on the next stack of modules for authoring IPLD data structures.

Usage no npm install needed!

<script type="module">
  import ipldStack from 'https://cdn.skypack.dev/@ipld/stack';
</script>

README

EXPERIMENTAL: New stack for authoring IPLD data structures

This repository is an exporatory space to work on the next stack of modules for authoring IPLD data structures.

Eventually this repository will be deleted as it contains code for many modules. This code will eventually migrate to the right repositories but it's much easier to develop and test the stack as a whole in one repository during this early stage of development.

Goals

After having spent time authoring IPLD data structures we have several improvements and changes we'd like to see implemented.

  • Single end point for authoring a block (rather than finding each format)
  • Lazy encoding, decoding, and cid (hash) creation.
  • Caching everywhere possible: encoding, hashing, etc.
  • Simplified authoring of new formats.
  • Less verbose API names.

Block API

The Block API is the single endpoint for authoring IPLD data structures. Unless you're implementing a new codec you can get everything you need from the Block API: encoding, decoding, cid creation w/ hashing.

Block.encoder(object, codec, algorithm = 'sha2-256')

Create a Block instance from either a native object.

The cid as well as encoding will not happen until requested and then will be cached when appropriate.

let block = Block.encoder({hello: 'world'}, 'dag-cbor')

Returns a Block instance.

Block.decoder(binary, codec, algorithm = 'sha2-256')

Create a Block instance from an existing binary encoded block

The cid as well as decoding will not happen until requested and then will be cached when appropriate.

let block = Block.decoder(someBuffer, 'dag-cbor')

Returns a Block instance.

Block.create(binary, cid)

Create a new block from the raw binary data and cid.

cid can be an instance of CID or a base encoded string of a cid.

Returns a Block instance.

Block(opts)

Once a block instance is created the information represented in the block is considered immutable.

block.decode()

Promise that resolves to a native JavaScript object decoded from the block data.

A new object is returned on every call. The decoding is not cached because it is likely to be mutated by the consumer.

block.cid()

Promise that resolves to a cid instance. Cached after creation.

block.encode()

Promise that resolves to a Buffer instance encoded from the source input.

block.reader()

Returns an instance of Reader() from the codec implementation.

block.validate()

Returns true/false if the CID's multihash matches the given block.

If a CID hasn't been created yet it will return true since we know the hash will match in our eventually created CID.

Hot path methods

We expose a few extra APIs you can use if you find IPLD in the hot paths of your own code.

Since some codecs require async work and some do not, it's a good idea to try and factor our unnecesary async operations when you can if you can in hot paths.

block.encodeMaybeSync

Just like block.encode but returns either a promise or the encoded value synchronously.

block.decodeMaybeSync

Just like block.decode but returns either a proimse or the decoded value synchronously.

Codec Interface

This is the primary interface for implementing new codecs.

The interface is quite simple:

{
  encode: Function,
  decode: Function,
  codec: String,
  reader: Function
}

encode & decode

These are the primary methods you need to implement in order to implement a new codec.

While you can implement the entire Reader interface yourself, you can actually leverage our codec-interface.create utility to get a full implementation with these methods alone.

  • encode takes a native JavaScript object and returns a binary encoding.
  • decode takes a binary encoding and returns a nativfe JavaScript object.

Methods can be either synchronous or asynchronous (returns a promise).

reader(block)

The reader function accepts a Block instance and returns a full Reader interface.

This method can be either synchronous or asynchronous (returns a promise).

codec-interface.create(encode, decode, codecName)

Returns a full Codec Interface based on your encode and decode implementations.

Reader()

Reader.get(path)

Reader.links()

Reader.tree()