Dumb, permissionless, but secure, real-time, multi-writer, distributed file system
npm i autodrive
import Autodrive from "autodrive"
import b4a from "b4a"
import Corestore from "corestore"
import { once } from "bare-events"
import fs from "fs"
const driveA = new Autodrive(new Corestore("./storageA"))
await driveA.ready()
const driveB = new Autodrive(new Corestore("./storageB"), driveA.key)
await driveB.ready()
await driveA.put("/example.txt", b4a.from("Hello, World!"))
const data = await driveB.get("/example.txt")
const ws = driveB.createWriteStream("/example.txt")
const rs = fs.createReadStream("./file.txt")
rs.pipe(ws)
await once(ws, "finish")
for await (const chunk of driveA.createReadStream("/example.txt")) {
console.log(b4a.toString(chunk))
}
await driveA.del("/example.txt")
Create new Autodrive. store
must be an instance of Corestore.
If you provide a key you get read access to the drive at key.
Options are passed-through to underlying autobase.
Wait until internal state is loaded. Use it once before accessing synchronous properties like key
.
Fully close this drive and all internal hypercores used by it.
The ID of the drive, this consists of base-z-32 encoded key of the drive.
The binary hash of the drive's signers. Giving this someone grants full read access to the drive.
Hash of the drive.key
. Use this to e.g. replicate drive over Hyperswarm without leaking read access.
For writable drives this is the key pair used to authenticate local writer. null
otherwise.
Boolean indicating whether this drive uses encryption.
Buffer containing the key used to encrypt this drive. null
otherwise.
Local writer hypercore. If the drive is not writable this is null.
The underlying file database, an instance of Hyperbee.
The Corestore used to instantiate this drive.
The Corestore used to instantiate this drive. Hyperdrive compat.
The current version of the drive's file database.
Boolean indicating whether this drive has write access.
Should always be true.
Whether this drive supports file metadata. Should always be true.
Get the Hyperblobs instance for the given writer. If forWriter
is omitted, returns Hyperblobs for the local writer.
Add writer to this drive. key
can be obtained by accessing drive.local.key
on the writer to be added. Can only be called by existing writer.
Remove a writer from this drive. key
should be drive.local.key
of the writer to be removed. Can only be called by existing writer.
Try to download the latest version of the files database.
Indicating that you're finding peers in the background, operations will be on hold until done()
is called.
Call done()
when current iteration finishes, e.g. after swarm.flush()
.
Checkout an earlier database version. This allows to go back in time to an earlier filesystem state.
Mirror this drive into an instance of either another Autodrive, Hyperdrive, or Localdrive. Returns an instance of MirrorDrive.
const item = await drive.entry(path: string | Node, options?: { follow?: boolean, wait?: boolean, timeout?: number })
Get an entry in the files database.
- If
follow
is true and the entry is a symlink, this will resolve the destination. wait: false
returns immediately, if the entry is not locally available, it will returnnull
.timeout
specifies how long to wait for the entry data to download. The default timeout of 0 means wait indefinitely.
const buffer = await drive.get(path: string | Node, options?: { follow?: boolean, wait?: boolean, timeout?: number })
Get the file contents. Takes either a path, or a Node object returned by e.g. drive.entry()
.
Options are the same as drive.entry()
.
await drive.put(path: string, data: Uint8Array, options?: { executable?: boolean, metadata?: JSON })
Write data to the filesystem, either creating or updating a file. For large data consider drive.createWriteStream()
.
Delete a file from filesystem.
for await (const chunk of drive.createReadStream(path: string, options?: { start?: number, end?: number, length?: number, follow?: boolean, wait?: boolean, timeout?: number }))
Get a readable stream of file data at path. Options are same as drive.entry()
with the addition of range options:
start
: byte offset at which to start readingend
: byte offset at which to stoplength
: how many bytes to read
const ws = drive.createWriteStream(path: string, options?: { executable?: boolean, metadata?: JSON })
Efficiently write data at given path, returns a writable stream. Options are the same as drive.put()
.
Create a symlink to another location in the filesystem. Options are the same as drive.put()
.
Check if the file at given path exists. Options are the same as drive.entry()
without the follow
.
List file entries at a given folder. If recursive: true
also descends into the subdirectories.
List filenames of entries at given folder.
Returns 0
if entries are the same, 1
if a
is older, and -1
if b
is older.
for await (const { left: Node, right: Node } of drive.diff(version: number, folder?: string, options?: { limit?: number }))
Efficiently create a stream of the shallow changes to folder between version
and drive.version
.
Each entry is sorted by key.
If 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.
Returns an iterator that listens on folder
to yield changes, by default on /
.
Usage example:
for await (const [current, previous] of watcher) {
console.log(current.version)
console.log(previous.version)
}
Those current and previous are Autodrive snapshots that are auto-closed before next value. Don't close those snapshots yourself because they're used internally, let them be auto-closed.
Waits until the watcher is loaded and detecting changes.
Stops the watcher. You could also stop it by using break in the loop.
Downloads the blobs corresponding to all entries in the drive at paths prefixed with folder
.
Downloads all the blobs in folder
corresponding to entries in drive.checkout(version)
that are not in drive.version
.
In other words, downloads all the blobs added to folder
up to version
of the drive.
Deletes the blob from storage to free up space, but the file structure reference is kept.
Pass { diff: true }
to get stats about cleared blocks. Otherwise returns void.
Clear all blobs from storage, freeing up space. Options are the same as drive.clear()
Delete all data used by this drive from the local filesystem, effectively erasing the drive.
The ID object identifying data store in blobs hypercores, paired with a source this allows to retrieve the actual binary data.
interface Blob {
blockOffset: number
blockLength: number
byteOffset: number
/** The size of this file in bytes */
byteLength: number
}
The main file object Autodrive deals with.
interface Entry {
/** The writer core key that produced this version of a file */
source: Uint8Array
/** Blob object pointing to the actual file data */
blob?: Blob | null
executable: boolean
/** If this is a symlink, linkname will point to the destination */
linkname?: string | null
/** Any additional data you want to associate with the file, stored as JSON */
metadata?: JsonValue
}
Carry over from hyperbee, Node wraps entry with additional metadata.
interface Item {
/** The database version when this entry was written */
seq: number
/** The path at which this entry is stored */
key: string
/** The Entry object */
value: Entry
}