https://github.com/ozymandiasthegreat/autodrive
Dumb, permissionless, but secure, real-time, multi-writer, distributed file system
https://github.com/ozymandiasthegreat/autodrive
autobase distributed-file-system hyperdrive multi-writer p2p
Last synced: 7 months ago
JSON representation
Dumb, permissionless, but secure, real-time, multi-writer, distributed file system
- Host: GitHub
- URL: https://github.com/ozymandiasthegreat/autodrive
- Owner: OzymandiasTheGreat
- License: apache-2.0
- Created: 2024-08-17T23:22:22.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-04-09T11:17:44.000Z (about 1 year ago)
- Last Synced: 2025-10-01T20:48:24.790Z (7 months ago)
- Topics: autobase, distributed-file-system, hyperdrive, multi-writer, p2p
- Language: JavaScript
- Homepage:
- Size: 57.6 KB
- Stars: 0
- Watchers: 1
- Forks: 1
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# autodrive
Dumb, permissionless, but secure, real-time, multi-writer, distributed file system
## Install
`npm i autodrive`
## Usage
```javascript
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")
```
## API
#### `const drive = new Autodrive(store, key, options)`
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.
#### `await drive.ready()`
Wait until internal state is loaded. Use it once before accessing synchronous properties like `key`.
#### `await drive.close()`
Fully close this drive and all internal hypercores used by it.
#### `drive.id`
The ID of the drive, this consists of base-z-32 encoded key of the drive.
#### `drive.key`
The binary hash of the drive's signers. Giving this someone grants full read access to the drive.
#### `drive.discoveryKey`
Hash of the `drive.key`. Use this to e.g. replicate drive over Hyperswarm without leaking read access.
#### `drive.keyPair`
For writable drives this is the key pair used to authenticate local writer. `null` otherwise.
#### `drive.encrypted`
Boolean indicating whether this drive uses encryption.
#### `drive.encryptionKey`
Buffer containing the key used to encrypt this drive. `null` otherwise.
#### `drive.local`
Local writer hypercore. If the drive is not writable this is null.
#### `drive.db`
The underlying file database, an instance of Hyperbee.
#### `drive.store`
The Corestore used to instantiate this drive.
#### `drive.corestore`
The Corestore used to instantiate this drive. Hyperdrive compat.
#### `drive.version`
The current version of the drive's file database.
#### `drive.writable`
Boolean indicating whether this drive has write access.
#### `drive.readable`
Should always be true.
#### `drive.supportsMetadata`
Whether this drive supports file metadata. Should always be true.
#### `const blobs = await drive.getBlobs(forWriter?: Uint8Array)`
Get the Hyperblobs instance for the given writer. If `forWriter` is omitted, returns Hyperblobs for the local writer.
#### `await drive.addWriter(key: Uint8Array, { indexer?: boolean })`
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.
#### `await drive.removeWriter(key: Uint8Array)`
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.
#### `await drive.update()`
Try to download the latest version of the files database.
#### `const stream = drive.replicate(isInitiator: boolean)`
See [`Corestore.replicate()`](https://github.com/holepunchto/corestore#const-stream--storereplicateoptsorstream)
#### `const done = drive.findingPeers()`
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()`.
#### `const checkout = drive.checkout(version: number)`
Checkout an earlier database version. This allows to go back in time to an earlier filesystem state.
#### `const mirror = drive.mirror(dest: Drive, options?: MirrorDrive Options)`
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 return `null`.
- `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()`.
#### `await drive.del(path: string)`
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 reading
- `end`: byte offset at which to stop
- `length`: 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()`.
#### `await symlink(path: string, dest: string, options?: { executable?: boolean, metadata?: JSON })`
Create a symlink to another location in the filesystem. Options are the same as `drive.put()`.
#### `await drive.exists(path: string, options?: { wait?: boolean, timeout?: number })`
Check if the file at given path exists. Options are the same as `drive.entry()` without the `follow`.
#### `for await (const item of drive.list(folder?: string, options?: { recursive?: boolean }))`
List file entries at a given folder. If `recursive: true` also descends into the subdirectories.
#### `for await (const filename of drive.readdir(folder?: string))`
List filenames of entries at given folder.
#### `const int = drive.compare(a: Node, b: Node)`
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.
#### `const watcher = drive.watch(folder?: string)`
Returns an iterator that listens on `folder` to yield changes, by default on `/`.
Usage example:
```javascript
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.
##### `await watcher.ready()`
Waits until the watcher is loaded and detecting changes.
##### `await watcher.destroy()`
Stops the watcher. You could also stop it by using break in the loop.
##### `await drive.download(folder?: string, options?: { recursive?: boolean })`
Downloads the blobs corresponding to all entries in the drive at paths prefixed with `folder`.
#### `await drive.downloadDiff(version: number, folder?: string, options?: { limit?: number })`
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.
#### `const { blocks: number } = await drive.clear(path: string | Node, options?: { diff?: boolean })`
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.
#### `const { blocks: number } = await drive.clearAll(options?: { diff?: boolean })`
Clear all blobs from storage, freeing up space. Options are the same as `drive.clear()`
#### `await drive.purge()`
Delete all data used by this drive from the local filesystem, effectively erasing the drive.
## Types
### Blob
The ID object identifying data store in blobs hypercores,
paired with a source this allows to retrieve the actual binary data.
```typescript
interface Blob {
blockOffset: number
blockLength: number
byteOffset: number
/** The size of this file in bytes */
byteLength: number
}
```
### Entry
The main file object Autodrive deals with.
```typescript
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
}
```
### Node
Carry over from hyperbee, Node wraps entry with additional metadata.
```typescript
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
}
```