@@ -5,13 +5,17 @@ const { default: parseDuration } = require('parse-duration')
5
5
const LegacyCID = require ( 'cids' )
6
6
const { CID } = require ( 'multiformats/cid' )
7
7
const Block = require ( 'multiformats/block' )
8
- const { base58 } = require ( 'multiformats/bases/base58' )
8
+ const { base58btc } = require ( 'multiformats/bases/base58' )
9
9
const { CarWriter } = require ( '@ipld/car/writer' )
10
+ /**
11
+ * @typedef {import('multiformats/codecs/interface').BlockCodec<number, any> } BlockCodec
12
+ */
13
+ /** @type {BlockCodec[] } */
10
14
const codecs = [
11
15
require ( '@ipld/dag-pb' ) ,
12
16
require ( '@ipld/dag-cbor' ) ,
13
17
require ( '@ipld/dag-json' )
14
- ] . reduce ( ( codecs , codec ) => {
18
+ ] . reduce ( ( /** @type { BlockCodec[] } */ codecs , /** @type { BlockCodec } */ codec ) => {
15
19
codecs [ codec . code ] = codec
16
20
return codecs
17
21
} , [ ] )
@@ -53,34 +57,37 @@ module.exports = {
53
57
const { writer, out } = await CarWriter . create ( [ cid ] )
54
58
Readable . from ( out ) . pipe ( process . stdout )
55
59
56
- const complete = await traverseWrite ( ipfs , options , cid , writer )
60
+ await traverseWrite ( ipfs , options , cid , writer )
57
61
writer . close ( )
58
-
59
- if ( ! complete ) {
60
- print ( 'cannot decode links in all blocks, DAG may be incomplete' )
61
- }
62
62
}
63
63
}
64
64
65
65
/**
66
66
* @param {IPFS } ipfs
67
67
* @param {{ timeout?: number} } options
68
68
* @param {CID } cid
69
- * @returns {Promise<{cid:CID, bytes:Uint8Array, links:CID[]|null }> }
69
+ * @returns {Promise<{cid:CID, bytes:Uint8Array, links:CID[]}> }
70
70
*/
71
71
const getBlock = async ( ipfs , options , cid ) => {
72
- cid = CID . asCID ( cid )
73
72
const result = await ipfs . block . get ( new LegacyCID ( cid . bytes ) , options )
73
+ if ( ! result ) {
74
+ throw new Error ( `Failed to fetch block ${ cid } ` )
75
+ }
76
+ const resultCid = CID . asCID ( result . cid )
77
+ if ( ! resultCid || ! resultCid . equals ( cid ) ) {
78
+ // shouldn't happen, but let's sanity check
79
+ throw new Error ( `Fetched CID ${ result . cid } does not match requested ${ cid } ` )
80
+ }
74
81
const bytes = result . data
75
- let links = null
82
+ /** @type {CID[] } */
83
+ let links = [ ]
76
84
const codec = codecs [ result . cid . code ]
77
85
if ( codec ) {
78
- const block = Block . createUnsafe ( { bytes : result . data , cid : CID . asCID ( result . cid ) , codec } )
86
+ const block = Block . createUnsafe ( { bytes : result . data , cid, codec } )
79
87
links = [ ...block . links ( ) ] . map ( ( l ) => l [ 1 ] )
80
- } else if ( NO_LINKS_CODECS . includes ( result . cid . code ) ) {
81
- // these blocks are known not to contain any IPLD links
82
- links = [ ]
83
- } // else we may have a block with links that we can't decode
88
+ } else if ( ! NO_LINKS_CODECS . includes ( result . cid . code ) ) {
89
+ throw new Error ( `Can't decode links in block with codec 0x${ result . cid . code . toString ( 16 ) } to form complete DAG` )
90
+ }
84
91
return { cid, bytes, links }
85
92
}
86
93
@@ -90,26 +97,19 @@ const getBlock = async (ipfs, options, cid) => {
90
97
* @param {CID } cid
91
98
* @param {BlockWriter } writer
92
99
* @param {Set<string> } seen
93
- * @returns {boolean } complete DAG
100
+ * @returns {Promise<void> }
94
101
*/
95
102
async function traverseWrite ( ipfs , options , cid , writer , seen = new Set ( ) ) {
96
- const b58Cid = cid . toString ( base58 )
103
+ const b58Cid = cid . toString ( base58btc )
97
104
if ( seen . has ( b58Cid ) ) {
98
- return true
105
+ return
99
106
}
100
107
const block = await getBlock ( ipfs , options , cid )
101
108
await writer . put ( block )
102
109
seen . add ( b58Cid )
103
- if ( block . links === null ) {
104
- return false // potentially incomplete DAG
105
- }
106
110
107
111
// recursive traversal of all links
108
- let complete = true
109
112
for ( const link of block . links ) {
110
- if ( ! await traverseWrite ( ipfs , options , link , writer , seen ) ) {
111
- complete = false
112
- }
113
+ await traverseWrite ( ipfs , options , link , writer , seen )
113
114
}
114
- return complete
115
115
}
0 commit comments