{"id":13482768,"url":"https://github.com/holepunchto/hyperdrive","last_synced_at":"2025-12-15T18:48:55.020Z","repository":{"id":42575649,"uuid":"46445764","full_name":"holepunchto/hyperdrive","owner":"holepunchto","description":"Hyperdrive is a secure, real time distributed file system","archived":false,"fork":false,"pushed_at":"2025-04-16T14:18:23.000Z","size":1057,"stargazers_count":1908,"open_issues_count":9,"forks_count":133,"subscribers_count":57,"default_branch":"main","last_synced_at":"2025-04-24T02:09:25.681Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/holepunchto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","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":"2015-11-18T20:33:23.000Z","updated_at":"2025-04-21T10:33:52.000Z","dependencies_parsed_at":"2022-08-20T16:50:46.901Z","dependency_job_id":"7a18b5e7-4289-4f0f-9b95-4a350628359f","html_url":"https://github.com/holepunchto/hyperdrive","commit_stats":{"total_commits":934,"total_committers":47,"mean_commits":"19.872340425531913","dds":0.5149892933618844,"last_synced_commit":"5ee0164fb39eadc0a073f7926800f81117a4c52e"},"previous_names":["holepunchto/hyperdrive","hypercore-protocol/hyperdrive","mafintosh/hyperdrive"],"tags_count":249,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holepunchto%2Fhyperdrive","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holepunchto%2Fhyperdrive/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holepunchto%2Fhyperdrive/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/holepunchto%2Fhyperdrive/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/holepunchto","download_url":"https://codeload.github.com/holepunchto/hyperdrive/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250546082,"owners_count":21448260,"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":[],"created_at":"2024-07-31T17:01:05.331Z","updated_at":"2025-12-15T18:48:55.011Z","avatar_url":"https://github.com/holepunchto.png","language":"JavaScript","funding_links":[],"categories":["Modules","JavaScript","others"],"sub_categories":[],"readme":"# Hyperdrive\n\n[See API docs at docs.pears.com](https://docs.pears.com/building-blocks/hyperdrive)\n\nHyperdrive is a secure, real-time distributed file system\n\n## Install\n\n```sh\nnpm install hyperdrive\n```\n\n## Usage\n\n```js\nconst Hyperdrive = require('hyperdrive')\nconst Corestore = require('corestore')\n\nconst store = new Corestore('./storage')\nconst drive = new Hyperdrive(store)\n\nawait drive.put('/blob.txt', Buffer.from('example'))\nawait drive.put('/images/logo.png', Buffer.from('..'))\nawait drive.put('/images/old-logo.png', Buffer.from('..'))\n\nconst buffer = await drive.get('/blob.txt')\nconsole.log(buffer) // =\u003e \u003cBuffer ..\u003e \"example\"\n\nconst entry = await drive.entry('/blob.txt')\nconsole.log(entry) // =\u003e { seq, key, value: { executable, linkname, blob, metadata } }\n\nawait drive.del('/images/old-logo.png')\n\nawait drive.symlink('/images/logo.shortcut', '/images/logo.png')\n\nfor await (const file of drive.list('/images')) {\n  console.log('list', file) // =\u003e { key, value }\n}\n\nconst rs = drive.createReadStream('/blob.txt')\nfor await (const chunk of rs) {\n  console.log('rs', chunk) // =\u003e \u003cBuffer ..\u003e\n}\n\nconst ws = drive.createWriteStream('/blob.txt')\nws.write('new example')\nws.end()\nws.once('close', () =\u003e console.log('file saved'))\n```\n\n## API\n\n#### `const drive = new Hyperdrive(store, [key])`\n\nCreates a new Hyperdrive instance. `store` must be an instance of `Corestore`.\n\nBy default it uses the core at `{ name: 'db' }` from `store`, unless you set the public `key`.\n\n#### `await drive.ready()`\n\nWaits until internal state is loaded.\n\nUse it once before reading synchronous properties like `drive.discoveryKey`, unless you called any of the other APIs.\n\n#### `await drive.close()`\n\nFully close this drive, including its underlying Hypercore backed datastructures.\n\n#### `drive.corestore`\n\nThe Corestore instance used as storage.\n\n#### `drive.db`\n\nThe underlying Hyperbee backing the drive file structure.\n\n#### `drive.core`\n\nThe Hypercore used for `drive.db`.\n\n#### `drive.id`\n\nString containing the id (z-base-32 of the public key) identifying this drive.\n\n#### `drive.key`\n\nThe public key of the Hypercore backing the drive.\n\n#### `drive.discoveryKey`\n\nThe hash of the public key of the Hypercore backing the drive.\n\nCan be used as a `topic` to seed the drive using Hyperswarm.\n\n#### `drive.contentKey`\n\nThe public key of the [Hyperblobs](https://github.com/holepunchto/hyperblobs) instance holding blobs associated with entries in the drive.\n\n#### `drive.writable`\n\nBoolean indicating if we can write or delete data in this drive.\n\n#### `drive.readable`\n\nBoolean indicating if we can read from this drive. After closing the drive this will be `false`.\n\n#### `drive.version`\n\nNumber that indicates how many modifications were made, useful as a version identifier.\n\n#### `drive.supportsMetadata`\n\nBoolean indicating if the drive handles or not metadata. Always `true`.\n\n#### `await drive.put(path, buffer, [options])`\n\nCreates a file at `path` in the drive. `options` are the same as in `createWriteStream`.\n\n#### `const buffer = await drive.get(path, [options])`\n\nReturns the blob at `path` in the drive. If no blob exists, returns `null`.\n\nIt also returns `null` for symbolic links.\n\n`options` include:\n\n```js\n{\n  wait: true, // Wait for block to be downloaded\n  timeout: 0 // Wait at max some milliseconds (0 means no timeout)\n}\n```\n\n#### `const entry = await drive.entry(path, [options])`\n\nReturns the entry at `path` in the drive. It looks like this:\n\n```js\n{\n  seq: Number,\n  key: String,\n  value: {\n    executable: Boolean, // Whether the blob at path is an executable\n    linkname: null, // If entry not symlink, otherwise a string to the entry this links to\n    blob: { // Hyperblobs id that can be used to fetch the blob associated with this entry\n      blockOffset: Number,\n      blockLength: Number,\n      byteOffset: Number,\n      byteLength: Number\n    },\n    metadata: null\n  }\n}\n```\n\n`options` include:\n\n```js\n{\n  follow: false, // Follow symlinks, 16 max or throws an error\n  wait: true, // Wait for block to be downloaded\n  timeout: 0 // Wait at max some milliseconds (0 means no timeout)\n}\n```\n\n#### `const exists = await drive.exists(path)`\n\nReturns `true` if the entry at `path` does exists, otherwise `false`.\n\n#### `await drive.del(path)`\n\nDeletes the file at `path` from the drive.\n\n#### `const comparison = drive.compare(entryA, entryB)`\n\nReturns `0` if entries are the same, `1` if `entryA` is older, and `-1` if `entryB` is older.\n\n#### `const cleared = await drive.clear(path, [options])`\n\nDeletes the blob from storage to free up space, but the file structure reference is kept.\n\n`options` include:\n\n```js\n{\n  diff: false // Returned `cleared` bytes object is null unless you enable this\n}\n```\n\n#### `const cleared = await drive.clearAll([options])`\n\nDeletes all the blobs from storage to free up space, similar to how `drive.clear()` works.\n\n`options` include:\n\n```js\n{\n  diff: false // Returned `cleared` bytes object is null unless you enable this\n}\n```\n\n#### `await drive.truncate(version, [options] })`\n\nTruncates the Hyperdrive to a previous version (both the file-structure reference and the blobs).\n\nA `blobs: \u003clength\u003e` option can be passed in if you know the corresponding blobs length, but it is recommended to let the method figure it out for you.\n\n#### `await drive.purge()`\n\nPurge both cores (db and blobs) from your storage, completely removing all the drive's data.\n\n#### `await drive.symlink(path, linkname)`\n\nCreates an entry in drive at `path` that points to the entry at `linkname`.\n\nIf a blob entry currently exists at `path` then it will get overwritten and `drive.get(key)` will return `null`, while `drive.entry(key)` will return the entry with symlink information.\n\n#### `const batch = drive.batch()`\n\nUseful for atomically mutate the drive, has the same interface as Hyperdrive.\n\n#### `await batch.flush()`\n\nCommit a batch of mutations to the underlying drive.\n\n#### `const stream = drive.list(folder, [options])`\n\nReturns a stream of all entries in the drive at paths prefixed with `folder`.\n\n`options` include:\n\n```js\n{\n  recursive: true | false // Whether to descend into all subfolders or not,\n  ignore: String || Array // Ignore files and folders by name,\n  wait: true, // Wait for block to be downloaded.\n}\n```\n\n#### `const stream = drive.readdir(folder, [options])`\n\nReturns a stream of all subpaths of entries in drive stored at paths prefixed by `folder`.\n\n`options` include:\n\n```js\n{\n  wait: true, // Wait for block to be downloaded\n}\n```\n\n#### `const stream = await drive.entries([range], [options])`\n\nReturns a read stream of entries in the drive.\n\n`options` are the same as `Hyperbee().createReadStream([range], [options])`.\n\n#### `const mirror = drive.mirror(out, [options])`\n\nEfficiently mirror this drive into another. Returns a [`MirrorDrive`](https://github.com/holepunchto/mirror-drive#api) instance constructed with `options`.\n\nCall `await mirror.done()` to wait for the mirroring to finish.\n\n#### `const watcher = drive.watch([folder])`\n\nReturns an iterator that listens on `folder` to yield changes, by default on `/`.\n\nUsage example:\n\n```js\nfor await (const [current, previous] of watcher) {\n  console.log(current.version)\n  console.log(previous.version)\n}\n```\n\nThose `current` and `previous` are snapshots that are auto-closed before next value.\n\nDon't close those snapshots yourself because they're used internally, let them be auto-closed.\n\n`await watcher.ready()`\n\nWaits until the watcher is loaded and detecting changes.\n\n`await watcher.destroy()`\n\nStops the watcher. You could also stop it by using `break` in the loop.\n\n#### `const rs = drive.createReadStream(path, [options])`\n\nReturns a stream to read out the blob stored in the drive at `path`.\n\n`options` include:\n\n```js\n{\n  start: Number, // `start` and `end` are inclusive\n  end: Number,\n  length: Number, // `length` overrides `end`, they're not meant to be used together\n  wait: true, // Wait for blocks to be downloaded\n  timeout: 0 // Wait at max some milliseconds (0 means no timeout)\n}\n```\n\n#### `const ws = drive.createWriteStream(path, [options])`\n\nStream a blob into the drive at `path`.\n\n`options` include:\n\n```js\n{\n  executable: Boolean,\n  metadata: null // Extended file information i.e. arbitrary JSON value\n}\n```\n\n#### `const download = drive.download(folder, [options])`\n\nDownloads the blobs corresponding to all entries in the drive at paths prefixed with `folder`. Returns a `Download` object that resolves once all data has been downloaded:\n\n```js\nconst download = await drive.download(key)\nawait download.done()\n```\n\nYou can also cancel an ongoing download using `destroy()`.\n\n```js\ndownload.destroy()\n```\n\n`options` are the same as those for `drive.list(folder, [options])`.\n\n#### `const snapshot = drive.checkout(version)`\n\nGet a read-only snapshot of a previous version.\n\n#### `const stream = drive.diff(version, folder, [options])`\n\nEfficiently create a stream of the shallow changes to `folder` between `version` and `drive.version`.\n\nEach entry is sorted by key and looks like this:\n\n```js\n{\n  left: Object, // Entry in folder at drive.version for some path\n  right: Object, // Entry in folder at drive.checkout(version) for some path\n}\n```\n\nIf an entry exists in `drive.version` of the `folder` but not in `version`, then `left` is set and `right` will be `null`, and vice versa.\n\n#### `await drive.downloadDiff(version, folder, [options])`\n\nDownloads all the blobs in `folder` corresponding to entries in `drive.checkout(version)` that are not in `drive.version`. Returns a `Download` object that resolves once all data has been downloaded:\n\n```js\nconst download = await drive.downloadDiff(version, folder)\nawait download.done()\n```\n\nYou can also cancel an ongoing download using `destroy()`.\n\n```js\ndownload.destroy()\n```\n\nIn other words, downloads all the blobs added to `folder` up to `version` of the drive.\n\n#### `await drive.downloadRange(dbRanges, blobRanges)`\n\nDownloads the entries and blobs stored in the [ranges][core-range-docs] `dbRanges` and `blobRanges`. Returns a `Download` object that resolves once all data has been downloaded:\n\n```js\nconst download = await drive.downloadRange(dbRanges, blobRanges)\nawait download.done()\n```\n\nYou can also cancel an ongoing download using `destroy()`.\n\n```js\ndownload.destroy()\n```\n\n#### `await drive.has(path)`\n\nChecks if path is saved to local store already.\n\n#### `const done = drive.findingPeers()`\n\nIndicate to Hyperdrive that you're finding peers in the background, requests will be on hold until this is done.\n\nCall `done()` when your current discovery iteration is done, i.e. after `swarm.flush()` finishes.\n\n#### `const stream = drive.replicate(isInitiatorOrStream)`\n\nUsage example:\n\n```js\nconst swarm = new Hyperswarm()\nconst done = drive.findingPeers()\nswarm.on('connection', (socket) =\u003e drive.replicate(socket))\nswarm.join(drive.discoveryKey)\nswarm.flush().then(done, done)\n```\n\nSee more about how replicate works at [corestore.replicate][store-replicate-docs].\n\n#### `const updated = await drive.update([options])`\n\nWaits for initial proof of the new drive version until all `findingPeers` are done.\n\n`options` include:\n\n```js\n{\n  wait: false\n}\n```\n\nUse `drive.findingPeers()` or `{ wait: true }` to make await `drive.update()` blocking.\n\n#### `const blobs = await drive.getBlobs()`\n\nReturns the [Hyperblobs](https://github.com/holepunchto/hyperblobs) instance storing the blobs indexed by drive entries.\n\n```js\nawait drive.put('/file.txt', Buffer.from('hi'))\n\nconst buffer1 = await drive.get('/file.txt')\n\nconst blobs = await drive.getBlobs()\nconst entry = await drive.entry('/file.txt')\nconst buffer2 = await blobs.get(entry.value.blob)\n\n// =\u003e buffer1 and buffer2 are equals\n```\n\n[core-range-docs]: https://github.com/holepunchto/hypercore#const-range--coredownloadrange\n[store-replicate-docs]: https://github.com/holepunchto/corestore#const-stream--storereplicateoptsorstream\n\n#### `const blobsLength = await drive.getBlobsLength(checkout)`\n\nReturns the length of the Hyperblobs instance at the time of the specified Hyperdrive version (defaults to the current version).\n\n## License\n\nApache-2.0\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholepunchto%2Fhyperdrive","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fholepunchto%2Fhyperdrive","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fholepunchto%2Fhyperdrive/lists"}