Description
Here in IPFSX adding content always returns an iterator, which is a nice consistent API, but when adding a single file calling .first()
or .last()
on the iterator feels a little clunky and it seems to me that the more usual case is actually adding a single file, so I'd like to keep that API as simple and clean as possible.
I've ruled out:
- Automatically changing the return type to be a
Promise
if we detect a single item is being added and anIterable
otherwise. This is too weird, and I think people would get confused. - Always return a
Promise
that is monkey patched to also beIterable
😱. This makes me feel weird, and it's not obvious what the promise would resolve to when adding multiple and I think people will accidentially await when they should be iterating i.e. its also confusing - Always return a
Promise
that resolves to anIterable
if adding multiple - similar confusion ranking 😂. There's also no need to force execution onto the next tick if we're going to resolve immediately to an async iterable.
So, what if this instead:
ipfs.add
(single, returns a Promise) & ipfs.addEach
(multiple, returns an async iterator)
ipfs.add
accepts aBuffer
orIterable
that yields buffers and returns aPromise
that resolves to a CID
e.g.const cid = await ipfs.add(Buffer.from('hello world')) // or const cid = await ipfs.add(fs.createReadStream('/path/to/file'))
ipfs.addEach
accepts an iterable (optionally async) where each yieldeditem
is a file to be added. Eachitem
can be aBuffer
orIterable
that yields buffers or a{ path, content }
object. It returns an async iterable of{ cid, path }
e.g.const adder = ipfs.addEach([ { path: 'root/file1', content: fs.createReadStream(/*...*/) }, { path: 'root/file2', content: fs.createReadStream(/*...*/) } ]) for await (const { cid, path } of adder) // ...
...and pushing this out to other API methods that write DAG nodes:
ipfs.block.put
&ipfs.block.putEach
ipfs.dag.put
&ipfs.dag.putEach
- etc.
I want to keep the API surface area as small as possible so this is a step away from that. In general I believe that functions should be permissive in what they accept and consistent in what they return. However, we're not really talking about that here, what we're talking about is splitting on difference in operation - ipfs.add
behaves very differently when you're adding multiple files than it does when adding a single file and combining the two together makes it very difficult to return a consistent value with a "nice" API for both cases.
Interested to hear opinions and alternatives and settle on the most convenient and best API. Adding stuff programmatically to IPFS needs to be way easier. I think what we have here in IPFSX is a good start but I'd like to make it even better!
cc @olizilla @lidel @hacdias @achingbrain @hugomrdias @daviddias @jacobheun @vasco-santos @mikeal @vmx @Gozala (plz mention others if I've missed anyone that might be interested...)