{"id":19032590,"url":"https://github.com/storacha/ipfs-car","last_synced_at":"2025-08-23T22:32:08.707Z","repository":{"id":39491082,"uuid":"366423831","full_name":"storacha/ipfs-car","owner":"storacha","description":"🚘 Convert files to content-addressable archives and back","archived":false,"fork":false,"pushed_at":"2024-01-22T11:53:40.000Z","size":2011,"stargazers_count":148,"open_issues_count":24,"forks_count":43,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-09-10T13:09:13.092Z","etag":null,"topics":["car","ipfs"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/storacha.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-05-11T15:06:44.000Z","updated_at":"2024-08-01T01:20:21.000Z","dependencies_parsed_at":"2023-02-08T19:50:20.330Z","dependency_job_id":"3d71510b-899e-4878-b9bd-cbbc6ab284c0","html_url":"https://github.com/storacha/ipfs-car","commit_stats":{"total_commits":101,"total_committers":13,"mean_commits":7.769230769230769,"dds":0.7029702970297029,"last_synced_commit":"31817e00f703705bf7e9e25f61f03aa87b9afc66"},"previous_names":["storacha-network/ipfs-car","web3-storage/ipfs-car","storacha/ipfs-car"],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storacha%2Fipfs-car","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storacha%2Fipfs-car/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storacha%2Fipfs-car/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/storacha%2Fipfs-car/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/storacha","download_url":"https://codeload.github.com/storacha/ipfs-car/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230744786,"owners_count":18274000,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["car","ipfs"],"created_at":"2024-11-08T21:29:27.256Z","updated_at":"2024-12-21T17:18:07.831Z","avatar_url":"https://github.com/storacha.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ipfs-car 🚘✨⬢\n\n\u003e Convert files to content-addressable archives (.car) and back\n\n[![Build](https://github.com/web3-storage/ipfs-car/actions/workflows/main.yml/badge.svg)](https://github.com/web3-storage/ipfs-car/actions/workflows/main.yml)\n[![dependencies Status](https://status.david-dm.org/gh/web3-storage/ipfs-car.svg)](https://david-dm.org/web3-storage/ipfs-car)\n[![JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)\n[![Downloads](https://img.shields.io/npm/dm/ipfs-car.svg)](https://www.npmjs.com/package/ipfs-car)\n[![Minzipped size](https://badgen.net/bundlephobia/minzip/ipfs-car)](https://bundlephobia.com/result?p=ipfs-car)\n\n## Description\n\n`ipfs-car` is a library and CLI tool to pack \u0026 unpack files from [Content Addressable aRchives (CAR)](https://ipld.io/specs/transport/car/) file. A thin wrapper over [@ipld/car](https://github.com/ipld/js-car) and [unix-fs](https://github.com/ipfs/js-ipfs-unixfs).\n\nContent-addressable archives store data as blocks (a sequence of bytes) each prefixed with the [Content ID (CID)](https://docs.ipfs.tech/concepts/content-addressing/) derived from the hash of the data; typically in a file with a `.car` extension.\n\nUse `ipfs-car` to pack your files into a .car; a portable, verifiable, IPFS compatible archive.\n\n```sh\n$ ipfs-car pack path/to/files --output my-files.car\n```\n\nor unpack files from a .car, and verify that every block matches it's CID\n\n```sh\n$ ipfs-car unpack my-files.car --output path/to/write/to\n```\n\nFetch and locally verify files from a IPFS gateway over http\n\n```sh\ncurl \"https://ipfs.io/ipfs/bafybeidd2gyhagleh47qeg77xqndy2qy3yzn4vkxmk775bg2t5lpuy7pcu?format=car\" | ipfs-car unpack -o images\n```\n\n## Install\n\n```sh\n# install it as a dependency\n$ npm i ipfs-car\n\n# OR use the cli without installing via `npx`\n$ npx ipfs-car --help\n```\n\n## Usage\n\nPack files into a .car\n\n```sh\n# write a content addressed archive to stdout.\n$ ipfs-car pack path/to/file/or/dir\n# note: CAR data streamed to stdout will not have roots set in CAR header!\n\n# specify the car file name.\n$ ipfs-car pack path/to/files --output path/to/write/a.car\n\n# by default, ipfs-car will wrap files in an IPFS directory.\n# use --no-wrap to avoid this.\n$ ipfs-car pack path/to/file --no-wrap --output path/to/write/a.car\n```\n\nUnpack files from a .car\n\n```sh\n# unpack files to a specific path.\n$ ipfs-car unpack path/to/my.car --output /path/to/unpack/files/to\n\n# unpack a specific root.\n$ ipfs-car unpack path/to/my.car --root \u003ccid1\u003e\n\n# unpack files from a .car on stdin.\n$ cat path/to/my.car | ipfs-car unpack\n```\n\nShow the files and directories in a .car\n\n```sh\n# show the files and directories.\n$ ipfs-car ls path/to/my.car\n\n# show the files and directories, their CIDs and byte sizes.\n$ ipfs-car ls path/to/my.car --verbose\n```\n\nShow the root CIDs in a .car\n\n```sh\n# show the CID roots found in the CAR header.\n$ ipfs-car roots path/to/my.car\n\n# show the CID roots found implicitly from the blocks in the file.\n$ ipfs-car roots --implicit path/to/my.car\n```\n\nShow the block CIDs in a .car\n\n```sh\n# show the CIDs for all the blocks.\n$ ipfs-car blocks path/to/my.car\n```\n\nGet other information about a CAR\n\n```sh\n# generate CID for a CAR.\n$ ipfs-car hash path/to/my.car\n```\n\n## API\n\nTo pack files into content-addressable archives, you can use the following:\n\n- `createFileEncoderStream` a factory function for creating a `ReadableStream` that encodes a single file into DAG `Block`s.\n- `createDirectoryEncoderStream` a factory function for creating a `ReadableStream` for encoding a directory of files into DAG `Block`s.\n- `CAREncoderStream` a `TransformStream` sub-class that you can write `Block`s to and read `Uint8Array` CAR file data from.\n\nTo unpack content-addressable archives to files, you should use `@ipld/car` and `ipfs-unixfs-exporter` modules.\n\n### Examples\n\n#### Basic single file pack\n\n```js\nimport { createFileEncoderStream, CAREncoderStream } from 'ipfs-car'\n\nconst file = new Blob(['Hello ipfs-car!'])\nconst carStream = createFileEncoderStream(file).pipeThrough(new CAREncoderStream())\n\n// carStream.pipeTo(somewhereWritable)\n```\n\n#### Directory pack to file system in Node.js\n\n```js\nimport { Writable } from 'stream'\nimport { createDirectoryEncoderStream, CAREncoderStream } from 'ipfs-car'\nimport { filesFromPaths } from 'files-from-path'\n\nconst files = await filesFromPaths(process.argv.slice(2))\n\nawait createDirectoryEncoderStream(files)\n  .pipeThrough(new CAREncoderStream())\n  .pipeTo(Writable.toWeb(process.stdout))\n```\n\nUsage: `node script.js file0 file1 dir0 \u003e my.car`.\n\n#### Obtaining the root CID\n\nThe root CID is the final block generated by the file/directory encoder stream. Use a transform stream to record the CID of the last block generated:\n\n```js\nimport { createFileEncoderStream, CAREncoderStream } from 'ipfs-car'\n\nconst file = new Blob(['Hello ipfs-car!'])\nlet rootCID\n\nawait createFileEncoderStream(file)\n  .pipeThrough(new TransformStream({\n    transform (block, controller) {\n      rootCID = block.cid\n      controller.enqueue(block)\n    }\n  }))\n  .pipeThrough(new CAREncoderStream())\n  .pipeTo(new WritableStream())\n\nconsole.log(rootCID.toString())\n```\n\n#### Adding root CIDs to the CAR header\n\nIf you need root CIDs in the CAR header, there are two approaches you can use:\n\n1. Buffer all the DAG blocks, then encode with known root:\n\n```js\nimport { createFileEncoderStream, CAREncoderStream } from 'ipfs-car'\n\nconst file = new Blob(['Hello ipfs-car!'])\nconst blocks = []\n\n// buffer the output\nawait createFileEncoderStream(file)\n  .pipeTo(new WritableStream({ write: b =\u003e blocks.push(b) }))\n\nconst rootCID = blocks.at(-1).cid\nconst blockStream = new ReadableStream({\n  pull (controller) {\n    if (blocks.length) {\n      controller.enqueue(blocks.shift())\n    } else {\n      controller.close()\n    }\n  }\n})\n\nawait blockStream\n  .pipeThrough(new CAREncoderStream([rootCID])) // pass root to CAR encoder\n  .pipeTo(new WritableStream())\n```\n\n2. Write to disk with placeholder CID, then update after DAG is completely generated (Note: Node.js only):\n\n```js\nimport fs from 'fs'\nimport { Writable } from 'stream'\nimport { CarWriter } from '@ipld/car/writer'\nimport { CID } from 'multiformats/cid'\nimport { createFileEncoderStream, CAREncoderStream } from 'ipfs-car'\n\n// Root CID written in CAR file header before it is updated with the real root CID.\nconst placeholderCID = CID.parse('bafybeigdyrzt5sfp7udm7hu76uh7y26nf3efuylqabf3oclgtqy55fbzdi')\n\nconst file = new Blob(['Hello ipfs-car!'])\nlet rootCID\n\nawait createFileEncoderStream(file)\n  .pipeThrough(new TransformStream({\n    transform (block, controller) {\n      rootCID = block.cid\n      controller.enqueue(block)\n    }\n  }))\n  .pipeThrough(new CAREncoderStream(placeholderCID))\n  .pipeTo(Writable.toWeb(fs.createWriteStream('path/to/my.car')))\n\n// update roots in CAR header\nconst fd = await fs.promises.open(opts.output, 'r+')\nawait CarWriter.updateRootsInFile(fd, [rootCID])\nawait fd.close()\n```\n\n#### Unpacking files from a CAR\n\nThis functionality is not provided by this library, but is easy to do with `@ipld/car` and `ipfs-unixfs-exporter` modules:\n\n```js\nimport { CarIndexedReader } from '@ipld/car/indexed-reader'\nimport { recursive as exporter } from 'ipfs-unixfs-exporter'\n\nconst reader = await CarIndexedReader.fromFile('path/to/my.car')\nconst roots = await reader.getRoots()\n\nconst entries = exporter(roots[0], {\n  async get (cid) {\n    const block = await reader.get(cid)\n    return block.bytes\n  }\n})\n\nfor await (const entry of entries) {\n  if (entry.type === 'file' || entry.type === 'raw') {\n    console.log('file', entry.path, entry.content)\n  } else if (entry.type === 'directory') {\n    console.log('directory', entry.path)\n  }\n}\n```\n\n## Contributing\n\nFeel free to join in. All welcome. [Open an issue](https://github.com/web3-storage/ipfs-car/issues)!\n\n## License\n\nDual-licensed under [MIT + Apache 2.0](https://github.com/web3-storage/ipfs-car/blob/main/LICENSE.md)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstoracha%2Fipfs-car","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstoracha%2Fipfs-car","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstoracha%2Fipfs-car/lists"}