dPay

dPack API

This section provides reference materials for the following topics:

Background

A library of functions that make working with @dpack/cli / @ddrive/core easier.

These functions were factored out of @dbrowser/core's internal APIs.

All async methods work with callbacks and promises. If no callback is provided, a promise will be returned.

Any time a dDrive vault is expected, a @dbrowser/vfs-wrapper instance can be provided, unless otherwise stated.

Environment Requirements

  • Node 7 or newer

Usage

var ddrive = require('@ddrive/core')
var vfsWrapper = require('@dbrowser/vfs-wrapper')

var vault = ddrive('./ddrive')
var vfsWrap = new vfsWrapper('./vfs')

await dpackapi.readFile(vault, '/greetings.txt') // read the published greetings.txt
await dpackapi.readFile(vfsWrap, '/greetings.txt') // read the local greetings.txt

To use with node versions lesser than 7 use:

var dpackapi = require('dpack-api-v2/es5');
const dpackapi = require('@dpack/api')

Lookup

stat(vault, name[, cb])

  • vault dDrive vault (object).
  • name Entry name (string).
  • Returns a dDrive Stat entry (object).
  • Throws NotFoundError
// by name:
var st = await dpackapi.stat(vault, '/dpack.json')
st.isDirectory()
st.isFile()
console.log(st) /* =>
Stat {
  dev: 0,
  nlink: 1,
  rdev: 0,
  blksize: 0,
  ino: 0,
  mode: 16877,
  uid: 0,
  gid: 0,
  size: 0,
  offset: 0,
  blocks: 0,
  atime: 2017-04-10T18:59:00.147Z,
  mtime: 2017-04-10T18:59:00.147Z,
  ctime: 2017-04-10T18:59:00.147Z,
  linkname: undefined } */

Read

readFile(vault, name[, opts, cb])

  • vault dDrive vault (object).
  • name Entry path (string).
  • opts. Options (object|string). If a string, will act as opts.encoding.
  • opts.encoding Desired output encoding (string). May be 'binary', 'utf8', 'hex', or 'base64'. Default 'utf8'.
  • Returns the content of the file in the requested encoding.
  • Throws NotFoundError, NotAFileError.
var manifestStr = await dpackapi.readFile(vault, '/dpack.json')
var imageBase64 = await dpackapi.readFile(vault, '/favicon.png', 'base64')

readdir(vault, path[, opts, cb])

  • vault dDrive vault (object).
  • path Target directory path (string).
  • opts.recursive Read all subfolders and their files as well?
  • Returns an array of file and folder names.
var listing = await dpackapi.readdir(vault, '/assets')
console.log(listing) // => ['profile.png', 'styles.css']

var listing = await dpackapi.readdir(vault, '/', { recursive: true })
console.log(listing) /* => [
  'index.html',
  'assets',
  'assets/profile.png',
  'assets/styles.css'
]*/

readSize(vault, path[, cb])

  • vault dDrive vault (object).
  • path Target directory path (string).
  • Returns a number (size in bytes).

This method will recurse on folders.

var size = await dpackapi.readSize(vault, '/assets')
console.log(size) // => 123

Write

writeFile(vault, name, data[, opts, cb])

  • vault dDrive vault (object).
  • name Entry path (string).
  • data Data to write (string|Buffer).
  • opts. Options (object|string). If a string, will act as opts.encoding.
  • opts.encoding Desired file encoding (string). May be 'binary', 'utf8', 'hex', or 'base64'. Default 'utf8' if data is a string, 'binary' if data is a Buffer.
  • Throws VaultNotWritableError, InvalidPathError, EntryAlreadyExistsError, ParentFolderDoesntExistError, InvalidEncodingError.
await dpackapi.writeFile(vault, '/greetings.txt', 'world', 'utf8')
await dpackapi.writeFile(vault, '/profile.png', fs.readFileSync('/tmp/dog.png'))

mkdir(vault, name[, cb])

  • vault dDrive vault (object).
  • name Directory path (string).
  • Throws VaultNotWritableError, InvalidPathError, EntryAlreadyExistsError, ParentFolderDoesntExistError, InvalidEncodingError.
await dpackapi.mkdir(vault, '/stuff')

copy(vault, sourceName, targetName[, cb])

  • vault dDrive vault (object).
  • sourceName Path to file or directory to copy (string).
  • targetName Where to copy the file or folder to (string).
  • Throws VaultNotWritableError, InvalidPathError, EntryAlreadyExistsError, ParentFolderDoesntExistError, InvalidEncodingError.
// copy file:
await dpackapi.copy(vault, '/foo.txt', '/foo.txt.back')
// copy folder:
await dpackapi.copy(vault, '/stuff', '/stuff-copy')

rename(vault, sourceName, targetName[, cb])

  • vault dDrive vault (object).
  • sourceName Path to file or directory to rename (string).
  • targetName What the file or folder should be named (string).
  • Throws VaultNotWritableError, InvalidPathError, EntryAlreadyExistsError, ParentFolderDoesntExistError, InvalidEncodingError.

This is equivalent to moving a file/folder.

// move file:
await dpackapi.rename(vault, '/foo.txt', '/foo.md')
// move folder:
await dpackapi.rename(vault, '/stuff', '/things')

Delete

unlink(vault, name[, cb])

  • vault dDrive vault (object).
  • name Entry path (string).
  • Throws VaultNotWritableError, NotFoundError, NotAFileError
await dpackapi.unlink(vault, '/greetings.txt')

rmdir(vault, name[, opts, cb])

  • vault dDrive vault (object).
  • name Entry path (string).
  • opts.recursive Delete all subfolders and files if the directory is not empty.
  • Throws VaultNotWritableError, NotFoundError, NotAFolderError, DestDirectoryNotEmpty
await dpackapi.rmdir(vault, '/stuff', {recursive: true})

Network

download(vault, name[, cb])

  • vault dDrive vault (object). Can not be a scoped-fs object.
  • name Entry path (string). Can point to a file or folder.

Download an vault file or folder-tree.

// download a specific file:
await dpackapi.download(vault, '/foo.txt')
// download a specific folder and all children:
await dpackapi.download(vault, '/bar/')
// download the entire vault:
await dpackapi.download(vault, '/')

Activity Streams

watch(vault[, path])

  • vault dDrive vault (object).
  • path Entry path (string) or anymatch pattern (array of strings). If falsy, will watch all files.
  • Returns a Readable stream.

Watches the given path or path-pattern for file events, which it emits as an emit-stream. Supported events:

  • ['changed',{path}] - The contents of the file has changed, either by a local write or a remote write. The new content will be ready when this event is emitted. path is the path-string of the file.
  • ['invalidated',{path}] - The contents of the file has changed remotely, but hasn't been downloaded yet. path is the path-string of the file.

An vault will emit "invalidated" first, when it receives the new metadata for the file. It will then emit "changed" when the content arrives. (A local vault will not emit "invalidated.")

var es = dpackapi.watch(vault)
var es = dpackapi.watch(vault, 'foo.txt')
var es = dpackapi.watch(vault, ['**/*.txt', '**/*.md'])

es.on('data', ([event, args]) => {
  if (event === 'invalidated') {
    console.log(args.path, 'has been invalidated')
    dpackapi.download(vault, args.path)
  } else if (event === 'changed') {
    console.log(args.path, 'has changed')
  }
})

// alternatively, via emit-stream:

var emitStream = require('emit-stream')
var events = emitStream(dpackapi.watch(vault))
events.on('invalidated', args => {
  console.log(args.path, 'has been invalidated')
  dpackapi.download(vault, args.path)
})
events.on('changed', args => {
  console.log(args.path, 'has changed')
})

createNetworkActivityStream(vault)

  • vault dDrive vault (object). Can not be a scoped-fs object.
  • Returns a Readable stream.

Watches the vault for network events, which it emits as an emit-stream. Supported events:

  • ['network-changed',{connections}] - The number of connections has changed. connections is a number.
  • ['download',{feed,block,bytes}] - A block has been downloaded. feed will either be "metadata" or "content". block is the index of data downloaded. bytes is the number of bytes in the block.
  • ['upload',{feed,block,bytes}] - A block has been uploaded. feed will either be "metadata" or "content". block is the index of data downloaded. bytes is the number of bytes in the block.
  • ['sync',{feed}] - All known blocks have been downloaded. feed will either be "metadata" or "content".
var es = dpackapi.createNetworkActivityStream(vault)

es.on('data', ([event, args]) => {
  if (event === 'network-changed') {
    console.log('Connected to %d peers', args.connections)
  } else if (event === 'download') {
    console.log('Just downloaded %d bytes (block %d) of the %s feed', args.bytes, args.block, args.feed)
  } else if (event === 'upload') {
    console.log('Just uploaded %d bytes (block %d) of the %s feed', args.bytes, args.block, args.feed)
  } else if (event === 'sync') {
    console.log('Finished downloading', args.feed)
  }
})

// alternatively, via emit-stream:

var emitStream = require('emit-stream')
var events = emitStream(es)
events.on('network-changed', args => {
  console.log('Connected to %d peers', args.connections)
})
events.on('download', args => {
  console.log('Just downloaded %d bytes (block %d) of the %s feed', args.bytes, args.block, args.feed)
})
events.on('upload', args => {
  console.log('Just uploaded %d bytes (block %d) of the %s feed', args.bytes, args.block, args.feed)
})
events.on('sync', args => {
  console.log('Finished downloading', args.feed)
})

Exporters

exportFilesystemToVault(opts[, cb])

  • opts.srcPath Source path in the filesystem (string). Required.
  • opts.dstVault Destination vault (object). Required.
  • opts.dstPath Destination path within the vault. Optional, defaults to '/'.
  • opts.ignore Files not to copy (array of strings). Optional. Uses anymatch.
  • opts.inplaceImport Should import source directory in-place? (boolean). If true and importing a directory, this will cause the directory's content to be copied directy into the dstPath. If false, will cause the source-directory to become a child of the dstPath.
  • Returns stats on the export.

Copies a file-tree into an vault.

var stats = await dpackapi.exportFilesystemToVault({
  srcPath: '/tmp/mystuff',
  dstVault: vault,
  inplaceImport: true
})
console.log(stats) /* => {
  addedFiles: ['fuzz.txt', 'foo/bar.txt'],
  updatedFiles: ['something.txt'],
  skipCount: 3, // files skipped due to the target already existing
  fileCount: 3,
  totalSize: 400 // bytes
}*/

exportVaultToFilesystem(opts[, cb])

  • opts.srcVault Source vault (object). Required.
  • opts.dstPath Destination path in the filesystem (string). Required.
  • opts.srcPath Source path within the vault. Optional, defaults to '/'.
  • opts.ignore Files not to copy (array of strings). Optional. Uses anymatch.
  • opts.overwriteExisting Proceed if the destination isn't empty (boolean). Default false.
  • opts.skipUndownloadedFiles Ignore files that haven't been downloaded yet (boolean). Default false. If false, will wait for source files to download.
  • Returns stats on the export.

Copies an vault into the filesystem.

NOTE

  • Unlike exportFilesystemToVault, this will not compare the target for equality before copying. If overwriteExisting is true, it will simply copy all files again.
var stats = await dpackapi.exportVaultToFilesystem({
  srcVault: vault,
  dstPath: '/tmp/mystuff',
  skipUndownloadedFiles: true
})
console.log(stats) /* => {
  addedFiles: ['fuzz.txt', 'foo/bar.txt'],
  updatedFiles: ['something.txt'],
  fileCount: 3,
  totalSize: 400 // bytes
}*/

exportVaultToVault(opts[, cb])

  • opts.srcVault Source vault (object). Required.
  • opts.dstVault Destination vault (object). Required.
  • opts.srcPath Source path within the source vault (string). Optional, defaults to '/'.
  • opts.dstPath Destination path within the destination vault (string). Optional, defaults to '/'.
  • opts.ignore Files not to copy (array of strings). Optional. Uses anymatch.
  • opts.skipUndownloadedFiles Ignore files that haven't been downloaded yet (boolean). Default false. If false, will wait for source files to download.

Copies an vault into another vault.

NOTE

  • Unlike exportFilesystemToVault, this will not compare the target for equality before copying. It copies files indescriminately.
var stats = await dpackapi.exportVaultToVault({
  srcVault: vaultA,
  dstVault: vaultB,
  skipUndownloadedFiles: true
})
console.log(stats) /* => {
  addedFiles: ['fuzz.txt', 'foo/bar.txt'],
  updatedFiles: ['something.txt'],
  fileCount: 3,
  totalSize: 400 // bytes
}*/

Manifest

readManifest(vault[, cb])

  • vault dDrive vault (object).

A sugar to get the manifest object.

var manifestObj = await dpackapi.readManifest(vault)

writeManifest(vault, manifest[, cb])

  • vault dDrive vault (object).
  • manifest Manifest values (object).

A sugar to write the manifest object.

await dpackapi.writeManifest(vault, { title: 'My dPack!' })

updateManifest(vault, manifest[, cb])

  • vault dDrive vault (object).
  • manifest Manifest values (object).

A sugar to modify the manifest object.

await dpackapi.writeManifest(vault, { title: 'My dPack!', description: 'the desc' })
await dpackapi.writeManifest(vault, { title: 'My new title!' }) // preserves description

generateManifest(opts)

  • opts Manifest options (object).

Helper to generate a manifest object. Opts in detail:

{
  url: String, the dPack's url
  title: String
  description: String
  type: Array<String>
  author: String | Object{name: String, url: String}
  links: Object
  web_root: String
  fallback_page: String
}

See: https://docs.dpack.io/metadata

Diff/Merge

diff(srcVault, srcPath, dstVault, dstPath[, opts, cb])

  • srcVault Source vault (object). Required.
  • srcPath Source path within the source vault (string). Required.
  • dstVault Destination vault (object). Required.
  • dstPath Destination path within the destination vault (string). Required.
  • opts.shallow Don't descend into changed folders (bool). Optional, default false.
  • opts.compareContent. Compare the content of the files, rather than the mtime and size. Optional, default false.
  • opts.paths Whitelist of files to diff (array<string>). Optional.
  • opts.ops Whitelist of operations to include in the diff (array<string>). Optional. Valid values are 'add', 'mod', and 'del'.
  • Returns diff data.

Get a list of differences between the two vaults at the given paths.

await dpackapi.diff(vaultA, '/', vaultB, '/')
await dpackapi.diff(vaultA, '/', vaultB, '/', {shallow: false, compareContent: true})
await dpackapi.diff(vaultA, '/', vaultB, '/', {paths: ['/foo', '/bar']})
await dpackapi.diff(vaultA, '/', vaultB, '/', {ops: ['add']}) // additions only

Output looks like:

[
  {change: 'mod', type: 'file', path: '/greetings.txt'},
  {change: 'add', type: 'dir',  path: '/pics'},
  {change: 'add', type: 'file', path: '/pics/kitty.png'},
  {change: 'del', type: 'file', path: '/backup/greetings.txt'},
  {change: 'del', type: 'dir',  path: '/backup'},
  {change: 'del', type: 'file', path: '/greetings.txt'},
]

merge(srcVault, srcPath, dstVault, dstPath[, opts, cb])

  • srcVault Source vault (object). Required.
  • srcPath Source path within the source vault (string). Required.
  • dstVault Destination vault (object). Required.
  • dstPath Destination path within the destination vault (string). Required.
  • opts.shallow Don't descend into changed folders (bool). Optional, default false.
  • opts.compareContent. Compare the content of the files, rather than the mtime and size. Optional, default false.
  • opts.paths Whitelist of files to diff (array<string>). Optional.
  • opts.ops Whitelist of operations to include in the diff (array<string>). Optional. Valid values are 'add', 'mod', and 'del'.
  • Returns the changes applied.

Merges the source vault into the destinatio vault at the given paths, causing dstVault content to match srcVault.

await dpackapi.merge(vaultA, '/', vaultB, '/')
await dpackapi.merge(vaultA, '/', vaultB, '/', {shallow: false, compareContent: true})
await dpackapi.merge(vaultA, '/', vaultB, '/', {paths: ['/foo', '/bar']})
await dpackapi.merge(vaultA, '/', vaultB, '/', {ops: ['add']}) // additions only

Output looks like:

[
  {change: 'mod', type: 'file', path: '/greetings.txt'},
  {change: 'add', type: 'dir',  path: '/pics'},
  {change: 'add', type: 'file', path: '/pics/kitty.png'},
  {change: 'del', type: 'file', path: '/backup/greetings.txt'},
  {change: 'del', type: 'dir',  path: '/backup'},
  {change: 'del', type: 'file', path: '/greetings.txt'},
]

Helpers

findEntryByContentBlock(vault, block)

  • vault dDrive vault (object).
  • block Content-block index
  • Returns a Promise for {name:, start:, end:}

Runs a binary search to find the file-entry that the given content-block index belongs to.

await dpackapi.findEntryByContentBlock(vault, 5)
/* => {
  name: '/foo.txt',
  start: 4,
  end: 6
}*/