@@ -24,6 +24,7 @@ import * as Token from './token.js'
2424import { fetch , File , Blob , FormData , Blockstore } from './platform.js'
2525import { toGatewayURL } from './gateway.js'
2626import { BlockstoreCarReader } from './bs-car-reader.js'
27+ import pipe from 'it-pipe'
2728
2829const MAX_STORE_RETRIES = 5
2930const MAX_CONCURRENT_UPLOADS = 3
@@ -215,7 +216,7 @@ class NFTStorage {
215216 * `foo/bla/baz.json` is ok but `foo/bar.png`, `bla/baz.json` is not.
216217 *
217218 * @param {Service } service
218- * @param {Iterable<File> } files
219+ * @param {Iterable<File>|AsyncIterable<File> } files
219220 * @returns {Promise<CIDString> }
220221 */
221222 static async storeDirectory ( service , files ) {
@@ -455,29 +456,32 @@ class NFTStorage {
455456 * await client.storeCar(car)
456457 * ```
457458 *
458- * @param {Iterable<File> } files
459+ * @param {Iterable<File>|AsyncIterable<File> } files
459460 * @param {object } [options]
460461 * @param {BlockstoreI } [options.blockstore]
461462 * @returns {Promise<{ cid: CID, car: CarReader }> }
462463 */
463464 static async encodeDirectory ( files , { blockstore } = { } ) {
464- const input = [ ]
465465 let size = 0
466- for ( const file of files ) {
467- input . push ( toImportCandidate ( file . name , file ) )
468- size += file . size
469- }
470-
466+ const input = pipe (
467+ isIterable ( files ) ? toAsyncIterable ( files ) : files ,
468+ async function * ( files ) {
469+ for await ( const file of files ) {
470+ yield toImportCandidate ( file . name , file )
471+ size += file . size
472+ }
473+ }
474+ )
475+ const packed = await packCar ( input , {
476+ blockstore,
477+ wrapWithDirectory : true ,
478+ } )
471479 if ( size === 0 ) {
472480 throw new Error (
473481 'Total size of files should exceed 0, make sure to provide some content'
474482 )
475483 }
476-
477- return packCar ( input , {
478- blockstore,
479- wrapWithDirectory : true ,
480- } )
484+ return packed
481485 }
482486
483487 // Just a sugar so you don't have to pass around endpoint and token around.
@@ -557,7 +561,7 @@ class NFTStorage {
557561 * Argument can be a [FileList](https://developer.mozilla.org/en-US/docs/Web/API/FileList)
558562 * instance as well, in which case directory structure will be retained.
559563 *
560- * @param {Iterable<File> } files
564+ * @param {AsyncIterable<File>| Iterable<File> } files
561565 */
562566 storeDirectory ( files ) {
563567 return NFTStorage . storeDirectory ( this , files )
@@ -654,6 +658,29 @@ class NFTStorage {
654658 }
655659}
656660
661+ /**
662+ * type guard checking for Iterable
663+ * @param {any } x;
664+ * @returns {x is Iterable<unknown> }
665+ */
666+ function isIterable ( x ) {
667+ return Symbol . iterator in x
668+ }
669+
670+ /**
671+ * Cast an iterable to an asyncIterable
672+ * @template T
673+ * @param {Iterable<T> } iterable
674+ * @returns {AsyncIterable<T> }
675+ */
676+ export function toAsyncIterable ( iterable ) {
677+ return ( async function * ( ) {
678+ for ( const item of iterable ) {
679+ yield item
680+ }
681+ } ) ( )
682+ }
683+
657684/**
658685 * @template {import('./lib/interface.js').TokenInput} T
659686 * @param {T } metadata
@@ -686,7 +713,7 @@ For more context please see ERC-721 specification https://eips.ethereum.org/EIPS
686713}
687714
688715/**
689- * @param {Array<{ path: string, content: import('./platform.js').ReadableStream }> } input
716+ * @param {import('ipfs-car/pack').ImportCandidateStream| Array<{ path: string, content: import('./platform.js').ReadableStream }> } input
690717 * @param {object } [options]
691718 * @param {BlockstoreI } [options.blockstore]
692719 * @param {boolean } [options.wrapWithDirectory]
0 commit comments