Problem
Current CAR building buffers entire content before upload:
- Node.js: Writes CAR to temp file, then streams file to Synapse
- Browser: Accumulates CAR bytes in memory (up to 1GiB), then uploads
Two reasons for this:
-
CAR header patching: We write a placeholder root CID in the CAR header, build the DAG, then patch/rewrite the header with the actual root. This requires the CAR to be fully built before streaming. We can eliminate this by using ZERO_CID in the header instead (valid CAR, signals "no meaningful root"; technically an empty roots array is fine but there are some historical compatibility issues that make having one the safe option).
-
Synapse metadata timing: The upload() API requires IPFS root CID metadata at call time, but root CID is only known after DAG building completes. This requires API changes in Synapse.
Blocker
Synapse SDK's upload() API requires metadata at call time. The IPFS root CID (ipfsRootCID metadata key) must be provided when calling upload(), but we don't know it until DAG building completes.
Blocked by: FilOzone/synapse-sdk#494 - Split upload() into store() + commit()
Solution
Once Synapse provides separate store() and commit() operations:
-
CAR builder changes:
- Use
CarWriter.create([ZERO_CID]) (where ZERO_CID = bafkqaaa)
- Return
{ carStream: ReadableStream, rootCidPromise: Promise<CID> } instead of buffered bytes/file
- Remove
updateRootCidInCar() post-processing
-
Upload flow changes:
- Call
store(carStream) - streams bytes directly as DAG builds
- Await
rootCidPromise - resolves when UnixFS completes
- Call
commit(pieceCid, { ics: rootCid }) - registers with metadata
-
Files to modify:
src/core/car/car-*-backend.ts - expose out stream, use ZERO_CID
src/core/unixfs/car-builder.ts - return streaming result
src/core/unixfs/browser-car-builder.ts - return streaming result
src/core/upload/synapse.ts - use new store/commit API
src/add/add.ts, src/import/import.ts, src/filecoin-pin-store.ts - consume streaming API
Problem
Current CAR building buffers entire content before upload:
Two reasons for this:
CAR header patching: We write a placeholder root CID in the CAR header, build the DAG, then patch/rewrite the header with the actual root. This requires the CAR to be fully built before streaming. We can eliminate this by using
ZERO_CIDin the header instead (valid CAR, signals "no meaningful root"; technically an empty roots array is fine but there are some historical compatibility issues that make having one the safe option).Synapse metadata timing: The
upload()API requires IPFS root CID metadata at call time, but root CID is only known after DAG building completes. This requires API changes in Synapse.Blocker
Synapse SDK's
upload()API requires metadata at call time. The IPFS root CID (ipfsRootCIDmetadata key) must be provided when callingupload(), but we don't know it until DAG building completes.Blocked by: FilOzone/synapse-sdk#494 - Split
upload()intostore()+commit()Solution
Once Synapse provides separate
store()andcommit()operations:CAR builder changes:
CarWriter.create([ZERO_CID])(whereZERO_CID = bafkqaaa){ carStream: ReadableStream, rootCidPromise: Promise<CID> }instead of buffered bytes/fileupdateRootCidInCar()post-processingUpload flow changes:
store(carStream)- streams bytes directly as DAG buildsrootCidPromise- resolves when UnixFS completescommit(pieceCid, { ics: rootCid })- registers with metadataFiles to modify:
src/core/car/car-*-backend.ts- exposeoutstream, use ZERO_CIDsrc/core/unixfs/car-builder.ts- return streaming resultsrc/core/unixfs/browser-car-builder.ts- return streaming resultsrc/core/upload/synapse.ts- use new store/commit APIsrc/add/add.ts,src/import/import.ts,src/filecoin-pin-store.ts- consume streaming API