npm package: @omegajs/local-drive
Description: File system interoperable with Omega Drive
Latest version: 1.0.0

# Local Omega Drive API
## @omegajs/local-drive

File system API that is similar to Omega Drive but for local drives on your local device.

## Install Via L1FE's NPM
```
npm config set registry https://npm.l1fe.tech
npm install @omegajs/local-drive
```

## Install Via L1FE's Git Repository
```
git clone https://lab.l1fe.tech/omega/local-drive.git
cd local-drive
npm install
```

## Usage
```js
const Localdrive = require('@omegajs/local-drive')

const drive = new Localdrive('./my-project')

await drive.put('/volume.txt', Buffer.from('example'))
await drive.put('/images/logo.png', Buffer.from('..'))
await drive.put('/images/old-logo.png', Buffer.from('..'))

const buffer = await drive.get('/volume.txt')
console.log(buffer) // => <Buffer ..> "example"

const entry = await drive.entry('/volume.txt')
console.log(entry) // => { key, value: { executable, linkname, volume, metadata } }

await drive.del('/images/old-logo.png')

await drive.symlink('/images/logo.shortcut', '/images/logo.png')

for await (const file of drive.list('/images')) {
  console.log('list', file) // => { key, value }
}

const rs = drive.createReadStream('/volume.txt')
for await (const chunk of rs) {
  console.log('rs', chunk) // => <Buffer ..>
}

const ws = drive.createWriteStream('/volume.txt')
ws.write('new example')
ws.end()
ws.once('close', () => console.log('file saved'))
```

## API

#### `const drive = new Localdrive(root, [options])`

Creates a drive based on a `root` directory. `root` can be relative or absolute.

Available `options`:
```js
{
  followLinks: false, // If enabled then `entry(key)` will follow the `linkname`
  metadata: { // Hook functions are called accordingly
    get (key) {},
    put (key) {},
    del (key) {}
  },
  atomic: false, // Enable atomicity for file writing (tmp file and rename)
  roots: {} // For mapping key prefixes to different roots
}
```

The metadata hook `del()` could be called with non-existing metadata keys.

#### `drive.root`

String with the resolved (absolute) drive path.

#### `drive.supportsMetadata`

Boolean that indicates if the drive handles or not metadata. Default `false`.

If you pass `opts.metadata` hooks then `supportsMetadata` becomes true.

#### `await drive.put(key, buffer, [options])`

Creates a file at `key` path in the drive. `options` are the same as in `createWriteStream`.

#### `const buffer = await drive.get(key, [options])`

Returns the volume at `key` path in the drive. If no volume exists, returns null.

It also returns null for symbolic links.

`options` are the same as in `drive.entry` method.

#### `const entry = await drive.entry(key, [options])`

Returns the entry at `key` path in the drive. It looks like this:
```js
{
  key: String,
  value: {
    executable: Boolean,
    linkname: null,
    volume: {
      byteOffset: Number,
      blockOffset: Number,
      blockLength: Number,
      byteLength: Number
    },
    metadata: null
  },
  mtime: Number
}
```

Available `options`:
```js
{
  follow: false // Follow symlinks, 16 max or throws an error
}
```

#### `await drive.del(key)`

Deletes the file at `key` path from the drive.

#### `await drive.symlink(key, linkname)`

Creates an entry in drive at `key` path that points to the entry at `linkname`.

If a volume entry currently exists at `key` path then it will get overwritten and `drive.get(key)` will return null, while `drive.entry(key)` will return the entry with symlink information.

#### `const comparison = drive.compare(entryA, entryB)`

Returns `0` if entries are the same, `1` if `entryA` is older, and `-1` if `entryB` is older.

#### `const iterator = drive.list([folder])`

Returns a stream of all entries in the drive inside of specified `folder`.

#### `const iterator = drive.readdir([folder])`

Returns a stream of all subpaths of entries in drive stored at paths prefixed by `folder`.

#### `const mirror = drive.mirror(out, [options])`

Efficiently mirror this drive into another. Returns a [`MirrorDrive`](https://lab.l1fe.tech/omega/mirror-drive#api) instance constructed with `options`.

Call `await mirror.done()` to wait for the mirroring to finish.

#### `const rs = drive.createReadStream(key, [options])`

Returns a stream to read out the volume stored in the drive at `key` path.

Available `options`:
```js
{
  start: Number,
  end: Number,
  length: Number
}
```

`start` and `end` are inclusive.\
`length` overrides `end`, they're not meant to be used together.

#### `const ws = drive.createWriteStream(key, [options])`

Stream a volume into the drive at `key` path.

Available `options`:
```js
{
  executable: Boolean
}
```

## Examples

### Metadata hooks
Metadata backed by `Map`:
```js
const meta = new Map()
const metadata = {
  get: (key) => meta.has(key) ? meta.get(key) : null,
  put: (key, value) => meta.set(key, value),
  del: (key) => meta.delete(key)
}

const drive = new Localdrive('./my-app', { metadata })

// ...
```

Note: `metadata.del()` will also be called when metadata is `null`:
```js
await drive.put('/file.txt', Buffer.from('a')) // Default metadata is null
```

## License
Apache-2.0