(#4652) - Migrate to ES6/Rollup, build one index.js
diff --git a/.gitignore b/.gitignore
index a0e7b00..b7e0c48 100644
--- a/.gitignore
+++ b/.gitignore
@@ -13,4 +13,6 @@
 tests/pouchdb_server
 tests/performance-bundle.js
 dist/*
-pouchdb-webpack.js
\ No newline at end of file
+pouchdb-webpack.js
+lib
+lib_unit
diff --git a/.jshintrc b/.jshintrc
index 2a33813..3cd6fd4 100755
--- a/.jshintrc
+++ b/.jshintrc
@@ -10,13 +10,12 @@
   "eqnull": true,
   "browser": true,
   "node": true,
-  "strict": true,
   "trailing": true,
-  "globalstrict": true,
   "white": true,
   "indent": 2,
   "forin": true,
   "futurehostile": true,
+  "esnext": true,
   "globals": {
     "PouchDB": true,
     "should": true,
diff --git a/.npmignore b/.npmignore
index 742dcfa..88b21e7 100644
--- a/.npmignore
+++ b/.npmignore
@@ -11,3 +11,4 @@
 bower_components
 ./docs/
 pouchdb-webpack.js
+lib_unit
diff --git a/.travis.yml b/.travis.yml
index 6f91944..4477e89 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -33,6 +33,8 @@
     # Fail early so we dont run hours of saucelabs if we know there
     # is a lint failure
   - npm run jshint
+    # build before each test
+  - npm run build
 
 script: npm run $COMMAND
 
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index ae81029..561c2b0 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -59,7 +59,9 @@
 
 You will now have various distributions of PouchDB in your `dist` folder, congratulations.
 
- * If you are on windows, you will need `node-gyp` to install levelup, visit https://github.com/TooTallNate/node-gyp#installation for installation instructions.
+Note that the source code is in `src/`, which is built by [Rollup](http://rollupjs.org/) as a
+Node module to `lib/`, which is then built by [Browserify](http://browserify.com/) as a browser-ready
+UMD module to `dist/`. All of this logic is in `bin/build.sh`.
 
 Testing PouchDB
 --------------------------------------
diff --git a/TESTING.md b/TESTING.md
index 708073c..9eb6323 100644
--- a/TESTING.md
+++ b/TESTING.md
@@ -25,6 +25,14 @@
 
 and open [http://127.0.0.1:8000/tests/integration/index.html](http://127.0.0.1:8000/tests/integration/index.html) in your browser of choice. The performance tests are located @ [http://localhost:8000/tests/performance/index.html](http://localhost:8000/tests/performance/index.html).
 
+### Unit tests
+
+    $ npm run build-as-modular-es5
+    $ npm run test-unit
+
+These are tests that confirm small parts of PouchDB functionality. In order to
+work correctly with ES6, they are first transpiled to `lib` as modular ES5 (`run run build-as-modular-es5`) using Babel, and then tested as CommonJS modules. See `build-as-modular-es5.sh` for details.
+
 ### Test Options
 
 #### Subset of tests:
@@ -35,8 +43,12 @@
 
 #### Test Coverage
 
+    $ npm run build-as-modular-es5
     $ COVERAGE=1 npm test
 
+Again, this uses `npm run build-as-modular-es5` in order to fully test the codebase
+as a non-bundle. See `build-as-modular-es5.sh` for details.
+
 #### Test alternative server
 
     $ COUCH_HOST=http://user:pass@myname.host.com npm run dev
diff --git a/bin/add-license.js b/bin/add-license.js
index 5e6d78a..2392af1 100755
--- a/bin/add-license.js
+++ b/bin/add-license.js
@@ -54,6 +54,7 @@
     var contents = fs.readFileSync(filename);
     contents = comment + '\n' + contents;
 
-    fs.writeFileSync(filename, contents);
+    fs.writeFileSync(filename + '.tmp', contents);
+    fs.renameSync(filename + '.tmp', filename);
   });
 });
diff --git a/bin/build-all-plugins.sh b/bin/build-all-plugins.sh
deleted file mode 100755
index c94cb56..0000000
--- a/bin/build-all-plugins.sh
+++ /dev/null
@@ -1,14 +0,0 @@
-#!/bin/sh
-
-DEREQUIRE=./node_modules/.bin/derequire
-BROWSERIFY=./node_modules/.bin/browserify
-UGLIFY=./node_modules/.bin/uglifyjs
-
-for plugin in memory localstorage fruitdown; do
-  $BROWSERIFY ./extras/${plugin} \
-      -x pouchdb \
-      -p bundle-collapser/plugin \
-      | ./bin/es3ify.js \
-      | $DEREQUIRE > ./dist/pouchdb.${plugin}.js
-  $UGLIFY dist/pouchdb.${plugin}.js -mc > dist/pouchdb.${plugin}.min.js
-done
diff --git a/bin/build-as-modular-es5.sh b/bin/build-as-modular-es5.sh
new file mode 100755
index 0000000..389aa72
--- /dev/null
+++ b/bin/build-as-modular-es5.sh
@@ -0,0 +1,38 @@
+#!/usr/bin/env bash
+
+#
+# This script builds `src` to `lib` in a modular style that preserves the
+# original file structure. This is useful for things like 1) unit tests, which
+# need to "reach inside" the bundle, and 2) coverage reports, which need to be
+# able to run all tests against the codebase, including the unit tests.
+#
+
+npm run build
+
+# In this case, Babel is roughly equivalent to what Rollup would do.
+# "add-module-exports" gives us a backwards-compatible CJS module structure
+# that doesn't oblige use to do require('foo').default for every module.
+
+./node_modules/.bin/babel \
+  --presets es2015 \
+  --plugins add-module-exports \
+  --out-dir lib src
+
+# Add a version number to both files (equivalent to build.sh)
+
+VERSION=$(node -e "console.log(require('./package.json').version)")
+./node_modules/.bin/replace --silent __VERSION__ $VERSION lib/*
+
+# Make the extras point back to the modular code (instead of being bundles).
+
+echo "module.exports = require('../deps/promise');" \
+    > lib/extras/promise.js
+
+echo "module.exports = require('../replicate/checkpointer');" \
+    > lib/extras/checkpointer.js
+
+echo "module.exports = require('../deps/ajax/prequest');" \
+    > lib/extras/ajax.js
+
+echo "module.exports = require('../replicate/generateReplicationId');" \
+    > lib/extras/generateReplicationId.js
\ No newline at end of file
diff --git a/bin/build.sh b/bin/build.sh
new file mode 100644
index 0000000..8e5b5bc
--- /dev/null
+++ b/bin/build.sh
@@ -0,0 +1,117 @@
+#!/usr/bin/env bash
+
+RIMRAF=./node_modules/.bin/rimraf
+MKDIRP=./node_modules/.bin/mkdirp
+BROWSERIFY=./node_modules/.bin/browserify
+ROLLUP=./node_modules/.bin/rollup
+REPLACE=./node_modules/.bin/replace
+DEREQUIRE=./node_modules/.bin/derequire
+UGLIFY=./node_modules/.bin/uglifyjs
+
+VERSION=$(node -e "console.log(require('./package.json').version)")
+
+$RIMRAF lib_staging
+$MKDIRP lib_staging
+
+EXTERNAL='argsarray,crypto,debug,double-ended-queue,es3ify,events,fruitdown,fs,inherits,inherits,js-extend,level-sublevel,level-sublevel/legacy,level-write-stream,levelup,lie,localstorage-down,memdown,path,pouchdb,pouchdb-collate,pouchdb-collections,request,scope-eval,spark-md5,through2,vuvuzela'
+
+# build for Node
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+  src/index.js \
+  --output=lib_staging/index.js
+
+# build for Browserify/Webpack
+
+$RIMRAF src_browser
+cp -r src src_browser
+
+for file in `find src_browser | grep '\-browser.js'`; do
+  cp $file `echo $file | sed 's/-browser//g'`;
+done
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+  src_browser/index.js \
+  --output=lib_staging/index-browser.js
+
+# add a version number to both files
+$REPLACE --silent __VERSION__ $VERSION lib_staging/*
+
+# rename to avoid concurrency issues in dev server
+$MKDIRP lib
+mv lib_staging/* lib/
+$RIMRAF lib_staging
+
+echo Built lib/index*
+
+# build for the browser (dist)
+
+$RIMRAF dist
+$MKDIRP dist
+
+$BROWSERIFY . -s PouchDB -p bundle-collapser/plugin \
+  | node ./bin/es3ify.js \
+  | $DEREQUIRE \
+  > dist/pouchdb.js
+
+$UGLIFY dist/pouchdb.js -m -c warnings=false > dist/pouchdb.min.js
+
+echo Built dist/*
+
+# build browser plugins
+
+$MKDIRP lib_staging/plugins
+
+for plugin in fruitdown localstorage memory; do
+  $ROLLUP --format=cjs --external $EXTERNAL \
+    src_browser/plugins/${plugin}/index.js \
+    > lib_staging/plugins/${plugin}.js
+done
+
+$MKDIRP lib/plugins
+mv lib_staging/plugins/* lib/plugins/
+$RIMRAF lib_staging
+
+echo Built lib/plugins/*
+
+# build extras API
+
+$MKDIRP lib_staging/extras
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+    src_browser/deps/promise.js \
+    > lib_staging/extras/promise.js
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+    src_browser/replicate/checkpointer.js \
+    > lib_staging/extras/checkpointer.js
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+    src_browser/deps/ajax/prequest.js \
+    > lib_staging/extras/ajax.js
+
+$ROLLUP --format=cjs --external $EXTERNAL \
+    src_browser/replicate/generateReplicationId.js \
+    > lib_staging/extras/generateReplicationId.js
+
+$MKDIRP lib/extras
+mv lib_staging/extras/* lib/extras/
+$RIMRAF lib_staging
+
+echo Built lib/extras/*
+
+# build browser plugins to dist/
+
+for plugin in memory localstorage fruitdown; do
+  $BROWSERIFY ./extras/${plugin} \
+      -x pouchdb \
+      -p bundle-collapser/plugin \
+      | ./bin/es3ify.js \
+      | $DEREQUIRE > ./dist/pouchdb.${plugin}.js
+  $UGLIFY dist/pouchdb.${plugin}.js -m -c warnings=false \
+    > dist/pouchdb.${plugin}.min.js
+  echo Built dist/pouchdb.${plugin}.*
+done
+
+# cleanup
+$RIMRAF src_browser
\ No newline at end of file
diff --git a/bin/dev-server.js b/bin/dev-server.js
index 8c2f643..6922a99 100755
--- a/bin/dev-server.js
+++ b/bin/dev-server.js
@@ -4,25 +4,14 @@
 
 var fs = require('fs');
 var Promise = require('lie');
-var through = require('through2');
-var _derequire = require('derequire');
 var watchify = require('watchify');
+var watch = require('node-watch');
 var browserify = require('browserify');
 var cors_proxy = require('corsproxy');
 var http_proxy = require('pouchdb-http-proxy');
 var http_server = require('http-server');
-var mkdirp = require('mkdirp');
+var spawn = require('child_process').spawn;
 
-function derequire() {
-  var out = new Buffer('');
-  return through(function (data, _, next) {
-    out = Buffer.concat([out, data]);
-    next();
-  }, function (next) {
-    this.push(_derequire(out.toString()));
-    next();
-  });
-}
 var queryParams = {};
 
 if (process.env.ES5_SHIM || process.env.ES5_SHIMS) {
@@ -38,58 +27,61 @@
   queryParams.src = process.env.POUCHDB_SRC;
 }
 
-var indexfile = "./lib/index.js";
-var outfile = "./dist/pouchdb.js";
 var perfRoot = './tests/performance/';
 var performanceBundle = './tests/performance-bundle.js';
 
-var w = watchify(browserify(indexfile, {
-  standalone: "PouchDB",
+var b = watchify(browserify({
+  entries: perfRoot,
   cache: {},
   packageCache: {},
   fullPaths: true,
   debug: true
-})).on('update', bundle);
-var b = watchify(browserify({
-    entries: perfRoot,
-    cache: {},
-    packageCache: {},
-    fullPaths: true,
-    debug: true
-  })).on('update', bundlePerfTests);
+})).on('update', rebuildPerfTests);
 
-function bundle(callback) {
-  mkdirp.sync('./dist');
-  w.bundle().pipe(derequire()).pipe(fs.createWriteStream(outfile))
-  .on('finish', function () {
-    console.log('Updated: ', outfile);
-    if (typeof callback === 'function') {
-      callback();
-    }
-  });
-}
-
-function bundlePerfTests(callback) {
-   
+function rebuildPerfTests(callback) {
   b.bundle().pipe(fs.createWriteStream(performanceBundle))
-  .on('finish', function () {
-    console.log('Updated: ', performanceBundle);
-    if (typeof callback === 'function') {
-      callback();
-    }
-  });
-
+    .on('finish', function () {
+      console.log('Updated: ', performanceBundle);
+      if (typeof callback === 'function') {
+        callback();
+      }
+    });
 }
 
+var rebuildPromise = Promise.resolve();
+
+function rebuild(callback) {
+  // only run one build at a time
+  rebuildPromise = rebuildPromise.then(function () {
+    var child = spawn('npm', ['run', 'build']);
+    child.stdout.on('data', function (buf) {
+      console.log(String(buf).replace(/\s*$/, ''));
+    });
+    child.stderr.on('data', function (buf) {
+      console.log(String(buf).replace(/\s*$/, ''));
+    });
+    child.on('close', function () {
+      if (typeof callback === 'function') {
+        callback();
+      }
+    });
+  });
+}
+
+watch('./src', rebuild);
+
 var filesWritten = false;
-Promise.all([
-  new Promise(function (resolve) {
-    bundle(resolve);
-  }),
-  new Promise(function (resolve) {
-    bundlePerfTests(resolve);
-  })
-]).then(function () {
+
+new Promise(function (resolve) {
+  if (require.main === module) {
+    return rebuild(resolve);
+  }
+  resolve(); // don't bother rebuilding if we're in `npm run dev`
+}).then(function () {
+  return new Promise(function (resolve) {
+    rebuildPerfTests(resolve);
+  });
+}).then(function () {
   filesWritten = true;
   checkReady();
 });
@@ -135,7 +127,6 @@
   }
 }
 
-
 if (require.main === module) {
   startServers();
 } else {
diff --git a/bin/test-webpack.sh b/bin/test-webpack.sh
index 0512f38..0bf4173 100644
--- a/bin/test-webpack.sh
+++ b/bin/test-webpack.sh
@@ -6,8 +6,9 @@
 # Webpack and Browserify to justify it.
 #
 
+npm run build
 ./node_modules/.bin/webpack \
   --module-bind json \
   --output-library PouchDB --output-library-target umd \
-  ./lib/index.js pouchdb-webpack.js
+  . pouchdb-webpack.js
 POUCHDB_SRC='../../pouchdb-webpack.js' npm test
\ No newline at end of file
diff --git a/extras/ajax.js b/extras/ajax.js
index aebed66..ef82744 100644
--- a/extras/ajax.js
+++ b/extras/ajax.js
@@ -1,4 +1,4 @@
 'use strict';
 
 // allow external plugins to require('pouchdb/extras/ajax')
-module.exports = require('../lib/deps/ajax/ajaxCore');
\ No newline at end of file
+module.exports = require('../lib/extras/ajax');
\ No newline at end of file
diff --git a/extras/checkpointer.js b/extras/checkpointer.js
index 11757d6..4283f50 100644
--- a/extras/checkpointer.js
+++ b/extras/checkpointer.js
@@ -1,4 +1,4 @@
 'use strict';
 
 // allow external plugins to require('pouchdb/extras/checkpointer')
-module.exports = require('../lib/replicate/checkpointer');
\ No newline at end of file
+module.exports = require('../lib/extras/checkpointer');
\ No newline at end of file
diff --git a/extras/generateReplicationId.js b/extras/generateReplicationId.js
index 84d5252..f05ecfb 100644
--- a/extras/generateReplicationId.js
+++ b/extras/generateReplicationId.js
@@ -1,4 +1,4 @@
 'use strict';
 
 // allow external plugins to require('pouchdb/extras/genReplicationId')
-module.exports = require('../lib/replicate/generateReplicationId');
\ No newline at end of file
+module.exports = require('../lib/extras/generateReplicationId');
\ No newline at end of file
diff --git a/extras/promise.js b/extras/promise.js
index 48cd066..10135a4 100644
--- a/extras/promise.js
+++ b/extras/promise.js
@@ -1,4 +1,4 @@
 'use strict';
 
 // allow external plugins to require('pouchdb/extras/promise')
-module.exports = require('../lib/deps/promise');
\ No newline at end of file
+module.exports = require('../lib/extras/promise');
\ No newline at end of file
diff --git a/lib/adapters-browser.js b/lib/adapters-browser.js
deleted file mode 100644
index a653a2c..0000000
--- a/lib/adapters-browser.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-module.exports = {
-  idb: require('./adapters/idb'),
-  websql: require('./adapters/websql')
-};
\ No newline at end of file
diff --git a/lib/adapters.js b/lib/adapters.js
deleted file mode 100644
index 1ff3ec1..0000000
--- a/lib/adapters.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict';
-
-module.exports = {
-  leveldb: require('./adapters/leveldb')
-};
\ No newline at end of file
diff --git a/lib/adapters/idb/constants.js b/lib/adapters/idb/constants.js
deleted file mode 100644
index 2a6ccc7..0000000
--- a/lib/adapters/idb/constants.js
+++ /dev/null
@@ -1,26 +0,0 @@
-'use strict';
-
-// IndexedDB requires a versioned database structure, so we use the
-// version here to manage migrations.
-exports.ADAPTER_VERSION = 5;
-
-// The object stores created for each database
-// DOC_STORE stores the document meta data, its revision history and state
-// Keyed by document id
-exports. DOC_STORE = 'document-store';
-// BY_SEQ_STORE stores a particular version of a document, keyed by its
-// sequence id
-exports.BY_SEQ_STORE = 'by-sequence';
-// Where we store attachments
-exports.ATTACH_STORE = 'attach-store';
-// Where we store many-to-many relations
-// between attachment digests and seqs
-exports.ATTACH_AND_SEQ_STORE = 'attach-seq-store';
-
-// Where we store database-wide meta data in a single record
-// keyed by id: META_STORE
-exports.META_STORE = 'meta-store';
-// Where we store local documents
-exports.LOCAL_STORE = 'local-store';
-// Where we detect blob support
-exports.DETECT_BLOB_SUPPORT_STORE = 'detect-blob-support';
\ No newline at end of file
diff --git a/lib/adapters/leveldb/createEmptyBlobOrBuffer-browser.js b/lib/adapters/leveldb/createEmptyBlobOrBuffer-browser.js
deleted file mode 100644
index 342134a..0000000
--- a/lib/adapters/leveldb/createEmptyBlobOrBuffer-browser.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var createBlob = require('../../deps/binary/blob');
-
-module.exports = function createEmptyBlobOrBuffer(type) {
-  return createBlob([''], {type: type});
-};
\ No newline at end of file
diff --git a/lib/adapters/leveldb/createEmptyBlobOrBuffer.js b/lib/adapters/leveldb/createEmptyBlobOrBuffer.js
deleted file mode 100644
index d8b8663..0000000
--- a/lib/adapters/leveldb/createEmptyBlobOrBuffer.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var typedBuffer = require('../../deps/binary/typedBuffer');
-
-module.exports = function createEmptyBlobOrBuffer(type) {
-  return typedBuffer('', 'binary', type);
-};
\ No newline at end of file
diff --git a/lib/adapters/leveldb/prepareAttachmentForStorage-browser.js b/lib/adapters/leveldb/prepareAttachmentForStorage-browser.js
deleted file mode 100644
index 8894da3..0000000
--- a/lib/adapters/leveldb/prepareAttachmentForStorage-browser.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-var readAsBinaryString = require('../../deps/binary/readAsBinaryString');
-
-// In the browser, we store a binary string
-module.exports = function prepareAttachmentForStorage(attData, cb) {
-  readAsBinaryString(attData, cb);
-};
\ No newline at end of file
diff --git a/lib/adapters/leveldb/prepareAttachmentForStorage.js b/lib/adapters/leveldb/prepareAttachmentForStorage.js
deleted file mode 100644
index 1476c5f..0000000
--- a/lib/adapters/leveldb/prepareAttachmentForStorage.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-// in Node, we store the buffer directly
-module.exports = function prepareAttachmentForStorage(attData, cb) {
-  process.nextTick(function () {
-    cb(attData);
-  });
-};
\ No newline at end of file
diff --git a/lib/adapters/websql/constants.js b/lib/adapters/websql/constants.js
deleted file mode 100644
index 58051c6..0000000
--- a/lib/adapters/websql/constants.js
+++ /dev/null
@@ -1,22 +0,0 @@
-'use strict';
-
-function quote(str) {
-  return "'" + str + "'";
-}
-
-exports.ADAPTER_VERSION = 7; // used to manage migrations
-
-// The object stores created for each database
-// DOC_STORE stores the document meta data, its revision history and state
-exports.DOC_STORE = quote('document-store');
-// BY_SEQ_STORE stores a particular version of a document, keyed by its
-// sequence id
-exports.BY_SEQ_STORE = quote('by-sequence');
-// Where we store attachments
-exports.ATTACH_STORE = quote('attach-store');
-exports.LOCAL_STORE = quote('local-store');
-exports.META_STORE = quote('metadata-store');
-// where we store many-to-many relations between attachment
-// digests and seqs
-exports.ATTACH_AND_SEQ_STORE = quote('attach-seq-store');
-
diff --git a/lib/deps/ajax/applyTypeToBuffer-browser.js b/lib/deps/ajax/applyTypeToBuffer-browser.js
deleted file mode 100644
index 2f79bba..0000000
--- a/lib/deps/ajax/applyTypeToBuffer-browser.js
+++ /dev/null
@@ -1,4 +0,0 @@
-'use strict';
-
-// the blob already has a type; do nothing
-module.exports = function () {};
\ No newline at end of file
diff --git a/lib/deps/ajax/applyTypeToBuffer.js b/lib/deps/ajax/applyTypeToBuffer.js
deleted file mode 100644
index a75ade5..0000000
--- a/lib/deps/ajax/applyTypeToBuffer.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-// non-standard, but we do this to mimic blobs in the browser
-module.exports = function (buffer, resp) {
-  buffer.type = resp.headers['content-type'];
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/createBlobOrBufferFromParts-browser.js b/lib/deps/ajax/createBlobOrBufferFromParts-browser.js
deleted file mode 100644
index 4feb61d..0000000
--- a/lib/deps/ajax/createBlobOrBufferFromParts-browser.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var createBlob = require('../binary/blob');
-
-module.exports = function createBlobOrBufferFromParts(parts, type) {
-  return createBlob(parts, {type: type});
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/createBlobOrBufferFromParts.js b/lib/deps/ajax/createBlobOrBufferFromParts.js
deleted file mode 100644
index 14355e0..0000000
--- a/lib/deps/ajax/createBlobOrBufferFromParts.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-var buffer = require('../binary/buffer');
-
-module.exports = function createBlobOrBufferFromParts(parts, type) {
-  return buffer.concat(parts.map(function (part) {
-    return new buffer(part, 'binary');
-  }));
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/createMultipartPart-browser.js b/lib/deps/ajax/createMultipartPart-browser.js
deleted file mode 100644
index 0840bb4..0000000
--- a/lib/deps/ajax/createMultipartPart-browser.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-var binaryStringToArrayBuffer = require('../binary/binaryStringToArrayBuffer');
-
-// create a "part" suitable for multipart. in the browser
-// this is an ArrayBuffer; in Node it's a binary string
-module.exports = function createMultipartPart(data) {
-  return binaryStringToArrayBuffer(data);
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/defaultBody-browser.js b/lib/deps/ajax/defaultBody-browser.js
deleted file mode 100644
index 4039d9a..0000000
--- a/lib/deps/ajax/defaultBody-browser.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict';
-
-module.exports = function defaultBody() {
-  return '';
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/defaultBody.js b/lib/deps/ajax/defaultBody.js
deleted file mode 100644
index d801479..0000000
--- a/lib/deps/ajax/defaultBody.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var buffer = require('../binary/buffer');
-
-module.exports = function defaultBody() {
-  return new buffer('', 'binary');
-};
\ No newline at end of file
diff --git a/lib/deps/ajax/explainError.js b/lib/deps/ajax/explainError.js
deleted file mode 100644
index 29e7895..0000000
--- a/lib/deps/ajax/explainError.js
+++ /dev/null
@@ -1,4 +0,0 @@
-'use strict';
-
-// We assume Node users don't need to see this warning
-module.exports = function () {};
diff --git a/lib/deps/ajax/prequest.js b/lib/deps/ajax/prequest.js
deleted file mode 100644
index 3a723e7..0000000
--- a/lib/deps/ajax/prequest.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-var ajax = require('./ajaxCore');
-
-module.exports = function(opts, callback) {
-  // do nothing; all the action is in prerequest-browser.js
-  return ajax(opts, callback);
-};
diff --git a/lib/deps/binary/base64-browser.js b/lib/deps/binary/base64-browser.js
deleted file mode 100644
index 243613b..0000000
--- a/lib/deps/binary/base64-browser.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-exports.atob = function (str) {
-  return atob(str);
-};
-exports.btoa = function (str) {
-  return btoa(str);
-};
\ No newline at end of file
diff --git a/lib/deps/binary/base64StringToBlobOrBuffer-browser.js b/lib/deps/binary/base64StringToBlobOrBuffer-browser.js
deleted file mode 100644
index 405e371..0000000
--- a/lib/deps/binary/base64StringToBlobOrBuffer-browser.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-var atob = require('./base64').atob;
-var binaryStringToBlobOrBuffer = require('./binaryStringToBlobOrBuffer');
-
-module.exports = function (b64, type) {
-  return binaryStringToBlobOrBuffer(atob(b64), type);
-};
\ No newline at end of file
diff --git a/lib/deps/binary/base64StringToBlobOrBuffer.js b/lib/deps/binary/base64StringToBlobOrBuffer.js
deleted file mode 100644
index 3ebf981..0000000
--- a/lib/deps/binary/base64StringToBlobOrBuffer.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var typedBuffer = require('./typedBuffer');
-
-module.exports = function (b64, type) {
-  return typedBuffer(b64, 'base64', type);
-};
\ No newline at end of file
diff --git a/lib/deps/binary/binaryStringToBlobOrBuffer-browser.js b/lib/deps/binary/binaryStringToBlobOrBuffer-browser.js
deleted file mode 100644
index a4b4252..0000000
--- a/lib/deps/binary/binaryStringToBlobOrBuffer-browser.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-var createBlob = require('./blob');
-var binaryStringToArrayBuffer = require('./binaryStringToArrayBuffer');
-
-module.exports = function (binString, type) {
-  return createBlob([binaryStringToArrayBuffer(binString)], {type: type});
-};
\ No newline at end of file
diff --git a/lib/deps/binary/binaryStringToBlobOrBuffer.js b/lib/deps/binary/binaryStringToBlobOrBuffer.js
deleted file mode 100644
index 9148ef1..0000000
--- a/lib/deps/binary/binaryStringToBlobOrBuffer.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var typedBuffer = require('./typedBuffer');
-
-module.exports = function (binString, type) {
-  return typedBuffer(binString, 'binary', type);
-};
\ No newline at end of file
diff --git a/lib/deps/binary/blobOrBufferToBase64-browser.js b/lib/deps/binary/blobOrBufferToBase64-browser.js
deleted file mode 100644
index 693db16..0000000
--- a/lib/deps/binary/blobOrBufferToBase64-browser.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict';
-
-var Promise = require('../promise');
-var readAsBinaryString = require('./readAsBinaryString');
-var btoa = require('./base64').btoa;
-
-module.exports = function blobToBase64(blobOrBuffer) {
-  return new Promise(function (resolve) {
-    readAsBinaryString(blobOrBuffer, function (bin) {
-      resolve(btoa(bin));
-    });
-  });
-};
\ No newline at end of file
diff --git a/lib/deps/binary/blobOrBufferToBase64.js b/lib/deps/binary/blobOrBufferToBase64.js
deleted file mode 100644
index cef7978..0000000
--- a/lib/deps/binary/blobOrBufferToBase64.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var Promise = require('../promise');
-
-module.exports = function blobToBase64(blobOrBuffer) {
-  return Promise.resolve(blobOrBuffer.toString('base64'));
-};
\ No newline at end of file
diff --git a/lib/deps/binary/cloneBinaryObject.js b/lib/deps/binary/cloneBinaryObject.js
deleted file mode 100644
index f975646..0000000
--- a/lib/deps/binary/cloneBinaryObject.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-module.exports = function cloneBinaryObject(object) {
-  var copy = new Buffer(object.length);
-  object.copy(copy);
-  return copy;
-};
\ No newline at end of file
diff --git a/lib/deps/binary/isBinaryObject.js b/lib/deps/binary/isBinaryObject.js
deleted file mode 100644
index 068b1d5..0000000
--- a/lib/deps/binary/isBinaryObject.js
+++ /dev/null
@@ -1,5 +0,0 @@
-'use strict';
-
-module.exports = function isBinaryObject(object) {
-  return object instanceof Buffer;
-};
\ No newline at end of file
diff --git a/lib/deps/docs/isLocalId.js b/lib/deps/docs/isLocalId.js
deleted file mode 100644
index cc0d605..0000000
--- a/lib/deps/docs/isLocalId.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-function isLocalId(id) {
-  return (/^_local/).test(id);
-}
-
-module.exports = isLocalId;
\ No newline at end of file
diff --git a/lib/deps/docs/normalizeDdocFunctionName.js b/lib/deps/docs/normalizeDdocFunctionName.js
deleted file mode 100644
index e3e5e44..0000000
--- a/lib/deps/docs/normalizeDdocFunctionName.js
+++ /dev/null
@@ -1,8 +0,0 @@
-'use strict';
-
-var parseDdocFunctionName = require('./parseDdocFunctionName');
-
-module.exports = function normalizeDesignDocFunctionName(s) {
-  var normalized = parseDdocFunctionName(s);
-  return normalized ? normalized.join('/') : null;
-};
\ No newline at end of file
diff --git a/lib/deps/env/hasLocalStorage.js b/lib/deps/env/hasLocalStorage.js
deleted file mode 100644
index 5f8115c..0000000
--- a/lib/deps/env/hasLocalStorage.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-// in Node of course this is false
-module.exports = function hasLocalStorage() {
-  return false;
-};
\ No newline at end of file
diff --git a/lib/deps/env/isChromeApp.js b/lib/deps/env/isChromeApp.js
deleted file mode 100644
index bc81370..0000000
--- a/lib/deps/env/isChromeApp.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-// in Node of course this is false
-module.exports = function isChromeApp() {
-  return false;
-};
\ No newline at end of file
diff --git a/lib/deps/md5.js b/lib/deps/md5.js
deleted file mode 100644
index 52f88d4..0000000
--- a/lib/deps/md5.js
+++ /dev/null
@@ -1,9 +0,0 @@
-'use strict';
-
-var toPromise = require('./toPromise');
-var crypto = require('crypto');
-
-module.exports = toPromise(function (data, callback) {
-  var base64 = crypto.createHash('md5').update(data).digest('base64');
-  callback(null, base64);
-});
\ No newline at end of file
diff --git a/lib/deps/migrate-browser.js b/lib/deps/migrate-browser.js
deleted file mode 100644
index bff6ea8..0000000
--- a/lib/deps/migrate-browser.js
+++ /dev/null
@@ -1,14 +0,0 @@
-'use strict';
-// in the browser, LevelAlt doesn't need the
-// pre-2.2.0 LevelDB-specific migrations
-exports.toSublevel = function (name, db, callback) {
-  process.nextTick(function () {
-    callback();
-  });
-};
-
-exports.localAndMetaStores = function (db, stores, callback) {
-  process.nextTick(function () {
-    callback();
-  });
-};
\ No newline at end of file
diff --git a/lib/deps/promise.js b/lib/deps/promise.js
deleted file mode 100644
index 66a4abc..0000000
--- a/lib/deps/promise.js
+++ /dev/null
@@ -1,3 +0,0 @@
-'use strict';
-/* istanbul ignore next */
-module.exports = typeof Promise === 'function' ? Promise : require('lie');
diff --git a/lib/deps/safeJsonParse.js b/lib/deps/safeJsonParse.js
deleted file mode 100644
index 65ae484..0000000
--- a/lib/deps/safeJsonParse.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-
-var vuvuzela = require('vuvuzela');
-
-module.exports = function safeJsonParse(str) {
-  try {
-    return JSON.parse(str);
-  } catch (e) {
-    /* istanbul ignore next */
-    return vuvuzela.parse(str);
-  }
-};
\ No newline at end of file
diff --git a/lib/deps/safeJsonStringify.js b/lib/deps/safeJsonStringify.js
deleted file mode 100644
index b755071..0000000
--- a/lib/deps/safeJsonStringify.js
+++ /dev/null
@@ -1,12 +0,0 @@
-'use strict';
-
-var vuvuzela = require('vuvuzela');
-
-module.exports = function safeJsonStringify(json) {
-  try {
-    return JSON.stringify(json);
-  } catch (e) {
-    /* istanbul ignore next */
-    return vuvuzela.stringify(json);
-  }
-};
\ No newline at end of file
diff --git a/lib/evalFilter.js b/lib/evalFilter.js
deleted file mode 100644
index cfc1671..0000000
--- a/lib/evalFilter.js
+++ /dev/null
@@ -1,11 +0,0 @@
-'use strict';
-
-module.exports = evalFilter;
-function evalFilter(input) {
-  /*jshint evil: true */
-  return eval([
-    '(function () { return ',
-    input,
-    ' })()'
-  ].join(''));
-}
\ No newline at end of file
diff --git a/lib/evalView.js b/lib/evalView.js
deleted file mode 100644
index 0cff5ac..0000000
--- a/lib/evalView.js
+++ /dev/null
@@ -1,21 +0,0 @@
-'use strict';
-
-module.exports = evalView;
-function evalView(input) {
-  /*jshint evil: true */
-  return eval([
-    '(function () {',
-    '  return function (doc) {',
-    '    var emitted = false;',
-    '    var emit = function (a, b) {',
-    '      emitted = true;',
-    '    };',
-    '    var view = ' + input + ';',
-    '    view(doc);',
-    '    if (emitted) {',
-    '      return true;',
-    '    }',
-    '  }',
-    '})()'
-  ].join('\n'));
-}
\ No newline at end of file
diff --git a/lib/index.js b/lib/index.js
deleted file mode 100644
index c9b8dd5..0000000
--- a/lib/index.js
+++ /dev/null
@@ -1,23 +0,0 @@
-"use strict";
-
-var PouchDB = require('./setup');
-
-module.exports = PouchDB;
-
-PouchDB.ajax = require('./deps/ajax/prequest');
-PouchDB.utils = require('./utils');
-PouchDB.Errors = require('./deps/errors');
-PouchDB.replicate = require('./replicate').replicate;
-PouchDB.sync = require('./sync');
-PouchDB.version = require('../package.json').version;
-var httpAdapter = require('./adapters/http');
-PouchDB.adapter('http', httpAdapter);
-PouchDB.adapter('https', httpAdapter);
-
-PouchDB.plugin(require('./mapreduce'));
-
-var adapters = require('./adapters');
-
-Object.keys(adapters).forEach(function (adapterName) {
-  PouchDB.adapter(adapterName, adapters[adapterName], true);
-});
diff --git a/lib/mapreduce/evalfunc.js b/lib/mapreduce/evalfunc.js
deleted file mode 100644
index 3776020..0000000
--- a/lib/mapreduce/evalfunc.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-module.exports = function (func, emit, sum, log, isArray, toJSON) {
-  /*jshint evil:true,unused:false */
-  return eval("(" + func.replace(/;\s*$/, "") + ");");
-};
diff --git a/lib/mapreduce/md5-browser.js b/lib/mapreduce/md5-browser.js
deleted file mode 100644
index d4572fa..0000000
--- a/lib/mapreduce/md5-browser.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var Md5 = require('spark-md5');
-
-module.exports = function (string) {
-  return Md5.hash(string);
-};
\ No newline at end of file
diff --git a/lib/mapreduce/md5.js b/lib/mapreduce/md5.js
deleted file mode 100644
index db83f6c..0000000
--- a/lib/mapreduce/md5.js
+++ /dev/null
@@ -1,7 +0,0 @@
-'use strict';
-
-var crypto = require('crypto');
-
-module.exports = function (string) {
-  return crypto.createHash('md5').update(string).digest('hex');
-};
\ No newline at end of file
diff --git a/lib/plugins/fruitdown/index.js b/lib/plugins/fruitdown/index.js
deleted file mode 100644
index 222ef50..0000000
--- a/lib/plugins/fruitdown/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-var pluginBase = require('../base');
-var adapterConfig = require('./config');
-var downAdapter = require('fruitdown');
-pluginBase(adapterConfig, downAdapter);
diff --git a/lib/plugins/localstorage/index.js b/lib/plugins/localstorage/index.js
deleted file mode 100644
index d023561..0000000
--- a/lib/plugins/localstorage/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-var pluginBase = require('../base');
-var adapterConfig = require('./config');
-var downAdapter = require('localstorage-down');
-pluginBase(adapterConfig, downAdapter);
\ No newline at end of file
diff --git a/lib/plugins/memory/index.js b/lib/plugins/memory/index.js
deleted file mode 100644
index 132ff4e..0000000
--- a/lib/plugins/memory/index.js
+++ /dev/null
@@ -1,6 +0,0 @@
-'use strict';
-
-var pluginBase = require('../base');
-var adapterConfig = require('./config');
-var downAdapter = require('memdown');
-pluginBase(adapterConfig, downAdapter);
\ No newline at end of file
diff --git a/lib/utils.js b/lib/utils.js
deleted file mode 100644
index 37b924b..0000000
--- a/lib/utils.js
+++ /dev/null
@@ -1,37 +0,0 @@
-'use strict';
-
-//
-// PouchDB.utils is basically a throwback to the pre-Browserify days,
-// when this was the easiest way to access global utilities from anywhere
-// in the project. For code cleanliness, we're trying to remove this file,
-// but for practical reasons (legacy code, test code, etc.) this is still here.
-//
-
-// TODO: only used by the integration tests, which have
-// some tests that explicitly override PouchDB.utils.ajax
-exports.ajax = require('./deps/ajax/prequest');
-
-// TODO: only used by the integration tests
-exports.parseUri = require('./deps/parseUri');
-
-// TODO: only used by the integration tests
-exports.uuid = require('./deps/uuid');
-
-// TODO: used by the integration tests and elsewhere, possibly
-// even in the PouchDB guide and example code
-var Promise = require('./deps/promise');
-exports.Promise = Promise;
-
-// TODO: only used by the integration tests
-var base64 = require('./deps/binary/base64');
-exports.atob = base64.atob;
-exports.btoa = base64.btoa;
-
-// TODO: only used by the integration tests
-var binToBluffer = require('./deps/binary/binaryStringToBlobOrBuffer');
-exports.binaryStringToBlobOrBuffer = binToBluffer;
-
-// TODO: pretty sure these are in widespread use by Hoodie and others,
-// also in the integration tests
-exports.clone = require('./deps/clone');
-exports.extend = require('js-extend').extend;
diff --git a/package.json b/package.json
index 1178240..3de6984 100644
--- a/package.json
+++ b/package.json
@@ -30,10 +30,10 @@
     "lie": "3.0.1",
     "localstorage-down": "0.6.3",
     "memdown": "1.1.0",
-    "package-json-versionify": "^1.0.0",
     "pouchdb-collate": "1.2.0",
     "pouchdb-collections": "1.0.1",
     "request": "2.67.0",
+    "scope-eval": "0.0.3",
     "spark-md5": "2.0.0",
     "through2": "2.0.0",
     "vuvuzela": "1.0.1"
@@ -45,6 +45,9 @@
     "leveldown": "1.4.3"
   },
   "devDependencies": {
+    "babel-cli": "^6.3.17",
+    "babel-plugin-add-module-exports": "^0.1.2",
+    "babel-preset-es2015": "^6.3.13",
     "browserify": "12.0.1",
     "bundle-collapser": "1.2.1",
     "chai": "3.4.1",
@@ -66,12 +69,14 @@
     "mocha": "2.3.4",
     "mockery": "1.4.0",
     "ncp": "2.0.0",
+    "node-watch": "^0.3.5",
     "phantomjs": "1.9.19",
     "pouchdb-express-router": "0.0.8",
     "pouchdb-http-proxy": "0.10.4",
     "pouchdb-server": "1.0.0",
     "replace": "0.3.0",
     "rimraf": "2.5.0",
+    "rollup": "^0.22.0",
     "sauce-connect-launcher": "0.13.0",
     "seedrandom": "2.4.2",
     "selenium-standalone": "4.8.0",
@@ -86,19 +91,16 @@
     "webpack": "^1.12.9"
   },
   "scripts": {
-    "build-js": "npm run build-main-js && npm run min && npm run build-plugins",
-    "build-main-js": "browserify . -s PouchDB -p bundle-collapser/plugin | node ./bin/es3ify.js | derequire > dist/pouchdb.js",
-    "min": "uglifyjs dist/pouchdb.js -mc > dist/pouchdb.min.js",
-    "build-plugins": "sh bin/build-all-plugins.sh",
-    "build": "rimraf dist && mkdirp dist && npm run build-js && npm run license",
+    "build": "sh bin/build.sh && npm run license",
     "license": "node ./bin/add-license.js",
-    "test-unit": "mocha tests/unit",
+    "build-as-modular-es5": "sh bin/build-as-modular-es5.sh",
+    "test-unit": "npm run build-as-modular-es5 && mocha tests/unit",
     "test-node": "sh bin/test-node.sh",
     "test-component": "mocha tests/component",
     "test-fuzzy": "TYPE=fuzzy npm run test",
-    "test-browser": "mkdirp dist && npm run build-js && node ./bin/test-browser.js",
+    "test-browser": "node ./bin/test-browser.js",
     "cordova": "npm run build && sh bin/run-cordova.sh",
-    "jshint": "jshint -c .jshintrc bin/ lib/ tests/",
+    "jshint": "jshint -c .jshintrc bin/ src/ tests/",
     "dev": "CLIENT=dev bash bin/run-test.sh",
     "launch-dev-server": "node ./bin/dev-server.js",
     "test": "bash bin/run-test.sh",
@@ -106,46 +108,15 @@
     "release": "sh bin/release.sh",
     "publish-site": "sh bin/publish-site.sh",
     "build-site": "node ./bin/build-site.js",
-    "report-coverage": "COVERAGE=1 npm test && istanbul-coveralls --no-rm",
+    "report-coverage": "npm run build-as-modular-es5 && COVERAGE=1 npm test && istanbul-coveralls --no-rm",
     "build-perf": "browserify tests/performance/*.js > tests/performance-bundle.js",
     "verify-bundle-size": "sh bin/verify-bundle-size.sh",
     "test-webpack": "sh bin/test-webpack.sh"
   },
   "browser": {
-    "./adapters/levelalt": false,
-    "./adapters/leveldb": false,
-    "./lib/adapters.js": "./lib/adapters-browser.js",
-    "./lib/adapters/leveldb/createEmptyBlobOrBuffer.js": "./lib/adapters/leveldb/createEmptyBlobOrBuffer-browser.js",
-    "./lib/adapters/leveldb/prepareAttachmentForStorage.js": "./lib/adapters/leveldb/prepareAttachmentForStorage-browser.js",
-    "./lib/adapters/leveldb/readAsBlobOrBuffer.js": "./lib/adapters/leveldb/readAsBlobOrBuffer-browser.js",
-    "./lib/adapters/preferredAdapters.js": "./lib/adapters/preferredAdapters-browser.js",
-    "./lib/deps/ajax/applyTypeToBuffer.js": "./lib/deps/ajax/applyTypeToBuffer-browser.js",
-    "./lib/deps/ajax/createBlobOrBufferFromParts.js": "./lib/deps/ajax/createBlobOrBufferFromParts-browser.js",
-    "./lib/deps/ajax/createMultipartPart.js": "./lib/deps/ajax/createMultipartPart-browser.js",
-    "./lib/deps/ajax/defaultBody.js": "./lib/deps/ajax/defaultBody-browser.js",
-    "./lib/deps/ajax/explainCors.js": "./lib/deps/ajax/explainCors-browser.js",
-    "./lib/deps/ajax/explainError.js": "./lib/deps/ajax/explainError-browser.js",
-    "./lib/deps/ajax/prequest.js": "./lib/deps/ajax/prequest-browser.js",
-    "./lib/deps/ajax/request.js": "./lib/deps/ajax/request-browser.js",
-    "./lib/deps/binary/base64.js": "./lib/deps/binary/base64-browser.js",
-    "./lib/deps/binary/base64StringToBlobOrBuffer.js": "./lib/deps/binary/base64StringToBlobOrBuffer-browser.js",
-    "./lib/deps/binary/binaryStringToBlobOrBuffer.js": "./lib/deps/binary/binaryStringToBlobOrBuffer-browser.js",
-    "./lib/deps/binary/blobOrBufferToBase64.js": "./lib/deps/binary/blobOrBufferToBase64-browser.js",
-    "./lib/deps/binary/buffer.js": "./lib/deps/binary/buffer-browser.js",
-    "./lib/deps/binary/cloneBinaryObject.js": "./lib/deps/binary/cloneBinaryObject-browser.js",
-    "./lib/deps/binary/isBinaryObject.js": "./lib/deps/binary/isBinaryObject-browser.js",
-    "./lib/deps/env/hasLocalStorage.js": "./lib/deps/env/hasLocalStorage-browser.js",
-    "./lib/deps/env/isChromeApp.js": "./lib/deps/env/isChromeApp-browser.js",
-    "./lib/deps/md5.js": "./lib/deps/md5-browser.js",
-    "./lib/deps/migrate.js": "./lib/deps/migrate-browser.js",
-    "./lib/mapreduce/md5.js": "./lib/mapreduce/md5-browser.js",
+    "./lib/index.js": "./lib/index-browser.js",
     "crypto": false,
     "fs": false,
     "leveldown": false
-  },
-  "browserify": {
-    "transform": [
-      "package-json-versionify"
-    ]
   }
 }
diff --git a/lib/adapter.js b/src/adapter.js
similarity index 92%
rename from lib/adapter.js
rename to src/adapter.js
index 988944d..d475bfa 100644
--- a/lib/adapter.js
+++ b/src/adapter.js
@@ -1,24 +1,33 @@
-"use strict";
-
-var extend = require('js-extend').extend;
-var Promise = require('./deps/promise');
-var pick = require('./deps/pick');
-var collections = require('pouchdb-collections');
-var inherits = require('inherits');
-var getArguments = require('argsarray');
-var adapterFun = require('./deps/adapterFun');
-var errors = require('./deps/errors');
-var EventEmitter = require('events').EventEmitter;
-var upsert = require('./deps/upsert');
-var Changes = require('./changes');
-var bulkGetShim = require('./deps/bulkGetShim');
-var isDeleted = require('./deps/docs/isDeleted');
-var isLocalId = require('./deps/docs/isLocalId');
-var traverseRevTree = require('./deps/merge/traverseRevTree');
-var collectLeaves = require('./deps/merge/collectLeaves');
-var rootToLeaf = require('./deps/merge/rootToLeaf');
-var collectConflicts = require('./deps/merge/collectConflicts');
-var parseDoc = require('./deps/docs/parseDoc');
+import { extend as extend } from 'js-extend';
+import Promise from './deps/promise';
+import pick from './deps/pick';
+import collections from 'pouchdb-collections';
+import inherits from 'inherits';
+import getArguments from 'argsarray';
+import adapterFun from './deps/adapterFun';
+import { EventEmitter as EventEmitter } from 'events';
+import upsert from './deps/upsert';
+import Changes from './changes';
+import bulkGetShim from './deps/bulkGetShim';
+import isDeleted from './deps/docs/isDeleted';
+import isLocalId from './deps/docs/isLocalId';
+import traverseRevTree from './deps/merge/traverseRevTree';
+import collectLeaves from './deps/merge/collectLeaves';
+import rootToLeaf from './deps/merge/rootToLeaf';
+import collectConflicts from './deps/merge/collectConflicts';
+import { invalidIdError } from './deps/docs/parseDoc';
+import {
+  MISSING_BULK_DOCS,
+  MISSING_DOC,
+  REV_CONFLICT,
+  INVALID_ID,
+  UNKNOWN_ERROR,
+  QUERY_PARSE_ERROR,
+  BAD_REQUEST,
+  NOT_AN_OBJECT,
+  INVALID_REV,
+  createError,
+} from './deps/errors';
 
 /*
  * A generic pouch adapter
@@ -177,7 +186,6 @@
 }
 
 inherits(AbstractPouchDB, EventEmitter);
-module.exports = AbstractPouchDB;
 
 function AbstractPouchDB() {
   EventEmitter.call(this);
@@ -190,7 +198,7 @@
     opts = {};
   }
   if (typeof doc !== 'object' || Array.isArray(doc)) {
-    return callback(errors.error(errors.NOT_AN_OBJECT));
+    return callback(createError(NOT_AN_OBJECT));
   }
   this.bulkDocs({docs: [doc]}, opts, yankError(callback));
 });
@@ -202,7 +210,7 @@
   var id = '_id' in doc;
   if (typeof doc !== 'object' || Array.isArray(doc)) {
     callback = args.pop();
-    return callback(errors.error(errors.NOT_AN_OBJECT));
+    return callback(createError(NOT_AN_OBJECT));
   }
   while (true) {
     temp = args.shift();
@@ -222,7 +230,7 @@
     }
   }
   opts = opts || {};
-  parseDoc.invalidIdError(doc._id);
+  invalidIdError(doc._id);
   if (isLocalId(doc._id) && typeof this._putLocal === 'function') {
     if (doc._deleted) {
       return this._removeLocal(doc, callback);
@@ -262,14 +270,14 @@
 
   return api.get(docId).then(function (doc) {
     if (doc._rev !== rev) {
-      throw errors.error(errors.REV_CONFLICT);
+      throw createError(REV_CONFLICT);
     }
 
     return createAttachment(doc);
   }, function (err) {
      // create new doc
     /* istanbul ignore else */
-    if (err.reason === errors.MISSING_DOC.message) {
+    if (err.reason === MISSING_DOC.message) {
       return createAttachment({_id: docId});
     } else {
       throw err;
@@ -288,7 +296,7 @@
       return;
     }
     if (obj._rev !== rev) {
-      callback(errors.error(errors.REV_CONFLICT));
+      callback(createError(REV_CONFLICT));
       return;
     }
     /* istanbul ignore if */
@@ -506,7 +514,7 @@
     opts = {};
   }
   if (typeof id !== 'string') {
-    return callback(errors.error(errors.INVALID_ID));
+    return callback(createError(INVALID_ID));
   }
   if (isLocalId(id) && typeof this._getLocal === 'function') {
     return this._getLocal(id, callback);
@@ -558,12 +566,12 @@
           var l = leaves[i];
           // looks like it's the only thing couchdb checks
           if (!(typeof(l) === "string" && /^\d+-/.test(l))) {
-            return callback(errors.error(errors.INVALID_REV));
+            return callback(createError(INVALID_REV));
           }
         }
         finishOpenRevs();
       } else {
-        return callback(errors.error(errors.UNKNOWN_ERROR,
+        return callback(createError(UNKNOWN_ERROR,
           'function_clause'));
       }
     }
@@ -674,7 +682,7 @@
       opts.binary = true;
       self._getAttachment(res.doc._attachments[attachmentId], opts, callback);
     } else {
-      return callback(errors.error(errors.MISSING_DOC));
+      return callback(createError(MISSING_DOC));
     }
   });
 });
@@ -701,7 +709,7 @@
       return incompatibleOpt in opts;
     })[0];
     if (incompatibleOpt) {
-      callback(errors.error(errors.QUERY_PARSE_ERROR,
+      callback(createError(QUERY_PARSE_ERROR,
         'Query parameter `' + incompatibleOpt +
         '` is not compatible with multi-get'
       ));
@@ -768,12 +776,12 @@
   }
 
   if (!req || !req.docs || !Array.isArray(req.docs)) {
-    return callback(errors.error(errors.MISSING_BULK_DOCS));
+    return callback(createError(MISSING_BULK_DOCS));
   }
 
   for (var i = 0; i < req.docs.length; ++i) {
     if (typeof req.docs[i] !== 'object' || Array.isArray(req.docs[i])) {
-      return callback(errors.error(errors.NOT_AN_OBJECT));
+      return callback(createError(NOT_AN_OBJECT));
     }
   }
 
@@ -787,7 +795,7 @@
   });
 
   if (attachmentError) {
-    return callback(errors.error(errors.BAD_REQUEST, attachmentError));
+    return callback(createError(BAD_REQUEST, attachmentError));
   }
 
   if (!('new_edits' in opts)) {
@@ -888,3 +896,5 @@
     });
   });
 });
+
+export default AbstractPouchDB;
\ No newline at end of file
diff --git a/src/adapters-browser.js b/src/adapters-browser.js
new file mode 100644
index 0000000..98f3379
--- /dev/null
+++ b/src/adapters-browser.js
@@ -0,0 +1,7 @@
+import idb from './adapters/idb/index';
+import websql from './adapters/websql/index';
+
+export default {
+  idb: idb,
+  websql: websql
+};
\ No newline at end of file
diff --git a/src/adapters.js b/src/adapters.js
new file mode 100644
index 0000000..c4117be
--- /dev/null
+++ b/src/adapters.js
@@ -0,0 +1,5 @@
+import leveldb from './adapters/leveldb/index';
+
+export default {
+  leveldb: leveldb
+};
\ No newline at end of file
diff --git a/lib/adapters/http/index.js b/src/adapters/http/index.js
similarity index 95%
rename from lib/adapters/http/index.js
rename to src/adapters/http/index.js
index f8e96a8..b0dc7fb 100644
--- a/lib/adapters/http/index.js
+++ b/src/adapters/http/index.js
@@ -1,5 +1,3 @@
-"use strict";
-
 var CHANGES_BATCH_SIZE = 25;
 var MAX_SIMULTANEOUS_REVS = 50;
 
@@ -12,29 +10,26 @@
 // TODO: we could measure the full URL to enforce exactly 2000 chars
 var MAX_URL_LENGTH = 1800;
 
-var extend = require('js-extend').extend;
+import { extend as extend } from 'js-extend';
 
-var pick = require('../../deps/pick');
-var filterChange = require('../../deps/filterChange');
-var coreAdapterFun = require('../../deps/adapterFun');
-var explainError = require('../../deps/ajax/explainError');
-var binStringToBluffer =
-  require('../../deps/binary/binaryStringToBlobOrBuffer');
-var b64StringToBluffer =
-  require('../../deps/binary/base64StringToBlobOrBuffer');
-var utils = require('../../utils');
-var Promise = require('../../deps/promise');
-var clone = require('../../deps/clone');
-var parseUri = require('../../deps/parseUri');
-var getArguments = require('argsarray');
-var base64 = require('../../deps/binary/base64');
-var btoa = base64.btoa;
-var atob = base64.atob;
-var errors = require('../../deps/errors');
-var log = require('debug')('pouchdb:http');
-var blufferToBase64 = require('../../deps/binary/blobOrBufferToBase64');
-var bulkGetShim = require('../../deps/bulkGetShim');
-var flatten = require('../../deps/flatten');
+import pick from '../../deps/pick';
+import filterChange from '../../deps/filterChange';
+import coreAdapterFun from '../../deps/adapterFun';
+import explainError from '../../deps/ajax/explainError';
+import binStringToBluffer from '../../deps/binary/binaryStringToBlobOrBuffer';
+import b64StringToBluffer from '../../deps/binary/base64StringToBlobOrBuffer';
+import utils from '../../utils';
+import Promise from '../../deps/promise';
+import clone from '../../deps/clone';
+import parseUri from '../../deps/parseUri';
+import getArguments from 'argsarray';
+import { atob as atob, btoa as btoa } from '../../deps/binary/base64';
+import { createError, BAD_ARG } from '../../deps/errors';
+import debug from 'debug';
+var log = debug('pouchdb:http');
+import blufferToBase64 from '../../deps/binary/blobOrBufferToBase64';
+import bulkGetShim from '../../deps/bulkGetShim';
+import flatten from '../../deps/flatten';
 
 function readAttachmentsAsBlobOrBuffer(row) {
   var atts = row.doc && row.doc._attachments;
@@ -562,7 +557,7 @@
       try {
         binary = atob(blob);
       } catch (err) {
-        return callback(errors.error(errors.BAD_ARG,
+        return callback(createError(BAD_ARG,
                         'Attachment is not a valid base64 string'));
       }
       blob = binary ? binStringToBluffer(binary, type) : '';
@@ -966,4 +961,4 @@
   return true;
 };
 
-module.exports = HttpPouch;
+export default HttpPouch;
diff --git a/lib/adapters/idb/allDocs.js b/src/adapters/idb/allDocs.js
similarity index 86%
rename from lib/adapters/idb/allDocs.js
rename to src/adapters/idb/allDocs.js
index e858e7a..3207ce6 100644
--- a/lib/adapters/idb/allDocs.js
+++ b/src/adapters/idb/allDocs.js
@@ -1,19 +1,19 @@
-'use strict';
+import { createError, IDB_ERROR } from '../../deps/errors';
+import collectConflicts from '../../deps/merge/collectConflicts';
 
-var errors = require('../../deps/errors');
-var idbUtils = require('./utils');
-var idbConstants = require('./constants');
-var collectConflicts = require('../../deps/merge/collectConflicts');
+import {
+  ATTACH_STORE,
+  BY_SEQ_STORE,
+  DOC_STORE
+} from './constants';
 
-var ATTACH_STORE = idbConstants.ATTACH_STORE;
-var BY_SEQ_STORE = idbConstants.BY_SEQ_STORE;
-var DOC_STORE = idbConstants.DOC_STORE;
-
-var decodeDoc = idbUtils.decodeDoc;
-var decodeMetadata = idbUtils.decodeMetadata;
-var fetchAttachmentsIfNecessary = idbUtils.fetchAttachmentsIfNecessary;
-var postProcessAttachments = idbUtils.postProcessAttachments;
-var openTransactionSafely = idbUtils.openTransactionSafely;
+import {
+  decodeDoc,
+  decodeMetadata,
+  fetchAttachmentsIfNecessary,
+  postProcessAttachments,
+  openTransactionSafely
+} from './utils';
 
 function createKeyRange(start, end, inclusiveEnd, key, descending) {
   try {
@@ -53,7 +53,7 @@
       rows: []
     });
   }
-  callback(errors.error(errors.IDB_ERROR, err.name, err.message));
+  callback(createError(IDB_ERROR, err.name, err.message));
 }
 
 function idbAllDocs(opts, api, idb, callback) {
@@ -181,4 +181,4 @@
   allDocs(opts, callback);
 }
 
-module.exports = idbAllDocs;
\ No newline at end of file
+export default idbAllDocs;
\ No newline at end of file
diff --git a/lib/adapters/idb/blobSupport.js b/src/adapters/idb/blobSupport.js
similarity index 84%
rename from lib/adapters/idb/blobSupport.js
rename to src/adapters/idb/blobSupport.js
index 23a14b7..045c232 100644
--- a/lib/adapters/idb/blobSupport.js
+++ b/src/adapters/idb/blobSupport.js
@@ -1,9 +1,6 @@
-'use strict';
-
-var createBlob = require('../../deps/binary/blob');
-var Promise = require('../../deps/promise');
-var idbConstants = require('./constants');
-var DETECT_BLOB_SUPPORT_STORE = idbConstants.DETECT_BLOB_SUPPORT_STORE;
+import createBlob from '../../deps/binary/blob';
+import Promise from '../../deps/promise';
+import { DETECT_BLOB_SUPPORT_STORE } from './constants';
 
 //
 // Blobs are not supported in all versions of IndexedDB, notably
@@ -43,4 +40,4 @@
   });
 }
 
-module.exports = checkBlobSupport;
+export default checkBlobSupport;
diff --git a/lib/adapters/idb/bulkDocs.js b/src/adapters/idb/bulkDocs.js
similarity index 88%
rename from lib/adapters/idb/bulkDocs.js
rename to src/adapters/idb/bulkDocs.js
index 1ef57f4..e8aacae 100644
--- a/lib/adapters/idb/bulkDocs.js
+++ b/src/adapters/idb/bulkDocs.js
@@ -1,28 +1,27 @@
-'use strict';
+import collections from 'pouchdb-collections';
+import { createError, MISSING_STUB } from '../../deps/errors';
+import preprocessAttachments from '../../deps/docs/preprocessAttachments';
+import processDocs from '../../deps/docs/processDocs';
+import isLocalId from '../../deps/docs/isLocalId';
+import compactTree from '../../deps/merge/compactTree';
+import { parseDoc } from '../../deps/docs/parseDoc';
 
-var collections = require('pouchdb-collections');
-var errors = require('../../deps/errors');
-var preprocessAttachments =
-  require('../../deps/docs/preprocessAttachments');
-var processDocs = require('../../deps/docs/processDocs');
-var isLocalId = require('../../deps/docs/isLocalId');
-var compactTree = require('../../deps/merge/compactTree');
-var parseDoc = require('../../deps/docs/parseDoc');
-var idbUtils = require('./utils');
-var idbConstants = require('./constants');
+import {
+  ATTACH_AND_SEQ_STORE,
+  ATTACH_STORE,
+  BY_SEQ_STORE,
+  DOC_STORE,
+  LOCAL_STORE,
+  META_STORE
+} from './constants';
 
-var ATTACH_AND_SEQ_STORE = idbConstants.ATTACH_AND_SEQ_STORE;
-var ATTACH_STORE = idbConstants.ATTACH_STORE;
-var BY_SEQ_STORE = idbConstants.BY_SEQ_STORE;
-var DOC_STORE = idbConstants.DOC_STORE;
-var LOCAL_STORE = idbConstants.LOCAL_STORE;
-var META_STORE = idbConstants.META_STORE;
-
-var compactRevs = idbUtils.compactRevs;
-var decodeMetadata = idbUtils.decodeMetadata;
-var encodeMetadata = idbUtils.encodeMetadata;
-var idbError = idbUtils.idbError;
-var openTransactionSafely = idbUtils.openTransactionSafely;
+import {
+  compactRevs,
+  decodeMetadata,
+  encodeMetadata,
+  idbError,
+  openTransactionSafely
+} from './utils';
 
 function idbBulkDocs(dbOpts, req, opts, api, idb, Changes, callback) {
   var docInfos = req.docs;
@@ -39,7 +38,7 @@
     if (doc._id && isLocalId(doc._id)) {
       continue;
     }
-    doc = docInfos[i] = parseDoc.parseDoc(doc, opts.new_edits);
+    doc = docInfos[i] = parseDoc(doc, opts.new_edits);
     if (doc.error && !docInfoError) {
       docInfoError = doc;
     }
@@ -144,7 +143,7 @@
     var req = attachStore.get(digest);
     req.onsuccess = function (e) {
       if (!e.target.result) {
-        var err = errors.error(errors.MISSING_STUB,
+        var err = createError(MISSING_STUB,
           'unknown stub attachment with digest ' +
           digest);
         err.status = 412;
@@ -367,4 +366,4 @@
   }
 }
 
-module.exports = idbBulkDocs;
+export default idbBulkDocs;
diff --git a/src/adapters/idb/constants.js b/src/adapters/idb/constants.js
new file mode 100644
index 0000000..7c53e88
--- /dev/null
+++ b/src/adapters/idb/constants.js
@@ -0,0 +1,35 @@
+// IndexedDB requires a versioned database structure, so we use the
+// version here to manage migrations.
+var ADAPTER_VERSION = 5;
+
+// The object stores created for each database
+// DOC_STORE stores the document meta data, its revision history and state
+// Keyed by document id
+var DOC_STORE = 'document-store';
+// BY_SEQ_STORE stores a particular version of a document, keyed by its
+// sequence id
+var BY_SEQ_STORE = 'by-sequence';
+// Where we store attachments
+var ATTACH_STORE = 'attach-store';
+// Where we store many-to-many relations
+// between attachment digests and seqs
+var ATTACH_AND_SEQ_STORE = 'attach-seq-store';
+
+// Where we store database-wide meta data in a single record
+// keyed by id: META_STORE
+var META_STORE = 'meta-store';
+// Where we store local documents
+var LOCAL_STORE = 'local-store';
+// Where we detect blob support
+var DETECT_BLOB_SUPPORT_STORE = 'detect-blob-support';
+
+export {
+  ADAPTER_VERSION as ADAPTER_VERSION,
+  DOC_STORE as DOC_STORE,
+  BY_SEQ_STORE as BY_SEQ_STORE,
+  ATTACH_STORE as ATTACH_STORE,
+  ATTACH_AND_SEQ_STORE as ATTACH_AND_SEQ_STORE,
+  META_STORE as META_STORE,
+  LOCAL_STORE as LOCAL_STORE,
+  DETECT_BLOB_SUPPORT_STORE as DETECT_BLOB_SUPPORT_STORE
+};
\ No newline at end of file
diff --git a/lib/adapters/idb/index.js b/src/adapters/idb/index.js
similarity index 91%
rename from lib/adapters/idb/index.js
rename to src/adapters/idb/index.js
index fefd667..7da64ad 100644
--- a/lib/adapters/idb/index.js
+++ b/src/adapters/idb/index.js
@@ -1,43 +1,49 @@
-'use strict';
+import clone from '../../deps/clone';
+import uuid from '../../deps/uuid';
+import collections from 'pouchdb-collections';
+import filterChange from '../../deps/filterChange';
+import toPromise from '../../deps/toPromise';
+import isDeleted from '../../deps/docs/isDeleted';
+import isLocalId from '../../deps/docs/isLocalId';
+import idbBulkDocs from './bulkDocs';
+import idbAllDocs from './allDocs';
+import checkBlobSupport from './blobSupport';
+import hasLocalStorage from '../../deps/env/hasLocalStorage';
+import calculateWinningRev from '../../deps/merge/winningRev';
+import traverseRevTree from '../../deps/merge/traverseRevTree';
+import Changes from '../../changesHandler';
+import {
+  MISSING_DOC,
+  REV_CONFLICT,
+  NOT_OPEN,
+  IDB_ERROR,
+  createError
+} from '../../deps/errors';
 
-var clone = require('../../deps/clone');
-var uuid = require('../../deps/uuid');
-var collections = require('pouchdb-collections');
-var filterChange = require('../../deps/filterChange');
-var toPromise = require('../../deps/toPromise');
-var isDeleted = require('../../deps/docs/isDeleted');
-var isLocalId = require('../../deps/docs/isLocalId');
-var errors = require('../../deps/errors');
-var idbUtils = require('./utils');
-var idbConstants = require('./constants');
-var idbBulkDocs = require('./bulkDocs');
-var idbAllDocs = require('./allDocs');
-var checkBlobSupport = require('./blobSupport');
-var hasLocalStorage = require('../../deps/env/hasLocalStorage');
-var calculateWinningRev = require('../../deps/merge/winningRev');
-var traverseRevTree = require('../../deps/merge/traverseRevTree');
-var Changes = require('../../changesHandler');
+import {
+  ADAPTER_VERSION,
+  ATTACH_AND_SEQ_STORE,
+  ATTACH_STORE,
+  BY_SEQ_STORE,
+  DETECT_BLOB_SUPPORT_STORE,
+  DOC_STORE,
+  LOCAL_STORE,
+  META_STORE
+} from './constants';
 
-var ADAPTER_VERSION = idbConstants.ADAPTER_VERSION;
-var ATTACH_AND_SEQ_STORE = idbConstants.ATTACH_AND_SEQ_STORE;
-var ATTACH_STORE = idbConstants.ATTACH_STORE;
-var BY_SEQ_STORE = idbConstants.BY_SEQ_STORE;
-var DETECT_BLOB_SUPPORT_STORE = idbConstants.DETECT_BLOB_SUPPORT_STORE;
-var DOC_STORE = idbConstants.DOC_STORE;
-var LOCAL_STORE = idbConstants.LOCAL_STORE;
-var META_STORE = idbConstants.META_STORE;
-
-var applyNext = idbUtils.applyNext;
-var compactRevs = idbUtils.compactRevs;
-var decodeDoc = idbUtils.decodeDoc;
-var decodeMetadata = idbUtils.decodeMetadata;
-var encodeMetadata = idbUtils.encodeMetadata;
-var fetchAttachmentsIfNecessary = idbUtils.fetchAttachmentsIfNecessary;
-var idbError = idbUtils.idbError;
-var postProcessAttachments = idbUtils.postProcessAttachments;
-var readBlobData = idbUtils.readBlobData;
-var taskQueue = idbUtils.taskQueue;
-var openTransactionSafely = idbUtils.openTransactionSafely;
+import {
+  applyNext,
+  compactRevs,
+  decodeDoc,
+  decodeMetadata,
+  encodeMetadata,
+  fetchAttachmentsIfNecessary,
+  idbError,
+  postProcessAttachments,
+  readBlobData,
+  openTransactionSafely,
+  taskQueue
+} from './utils';
 
 var cachedDBs = {};
 var blobSupportPromise;
@@ -321,11 +327,11 @@
       // When we ask with opts.rev we expect the answer to be either
       // doc (possibly with _deleted=true) or missing error
       if (!metadata) {
-        err = errors.error(errors.MISSING_DOC, 'missing');
+        err = createError(MISSING_DOC, 'missing');
         return finish();
       }
       if (isDeleted(metadata) && !opts.rev) {
-        err = errors.error(errors.MISSING_DOC, "deleted");
+        err = createError(MISSING_DOC, "deleted");
         return finish();
       }
       var objectStore = txn.objectStore(BY_SEQ_STORE);
@@ -339,7 +345,7 @@
           doc = decodeDoc(doc);
         }
         if (!doc) {
-          err = errors.error(errors.MISSING_DOC, 'missing');
+          err = createError(MISSING_DOC, 'missing');
           return finish();
         }
         finish();
@@ -588,7 +594,7 @@
 
   api._close = function (callback) {
     if (idb === null) {
-      return callback(errors.error(errors.NOT_OPEN));
+      return callback(createError(NOT_OPEN));
     }
 
     // https://developer.mozilla.org/en-US/docs/IndexedDB/IDBDatabase#close
@@ -609,7 +615,7 @@
     req.onsuccess = function (event) {
       var doc = decodeMetadata(event.target.result);
       if (!doc) {
-        callback(errors.error(errors.MISSING_DOC));
+        callback(createError(MISSING_DOC));
       } else {
         callback(null, doc.rev_tree);
       }
@@ -668,7 +674,7 @@
     req.onsuccess = function (e) {
       var doc = e.target.result;
       if (!doc) {
-        callback(errors.error(errors.MISSING_DOC));
+        callback(createError(MISSING_DOC));
       } else {
         delete doc['_doc_id_rev']; // for backwards compat
         callback(null, doc);
@@ -713,7 +719,7 @@
       req.onsuccess = function (e) {
         var oldDoc = e.target.result;
         if (!oldDoc || oldDoc._rev !== oldRev) {
-          callback(errors.error(errors.REV_CONFLICT));
+          callback(createError(REV_CONFLICT));
         } else { // update
           var req = oStore.put(doc);
           req.onsuccess = function () {
@@ -728,7 +734,7 @@
       req = oStore.add(doc);
       req.onerror = function (e) {
         // constraint error, already exists
-        callback(errors.error(errors.REV_CONFLICT));
+        callback(createError(REV_CONFLICT));
         e.preventDefault(); // avoid transaction abort
         e.stopPropagation(); // avoid transaction onerror
       };
@@ -768,7 +774,7 @@
     req.onsuccess = function (e) {
       var oldDoc = e.target.result;
       if (!oldDoc || oldDoc._rev !== doc._rev) {
-        callback(errors.error(errors.MISSING_DOC));
+        callback(createError(MISSING_DOC));
       } else {
         oStore.delete(id);
         ret = {ok: true, id: id, rev: '0-0'};
@@ -959,7 +965,7 @@
   req.onerror = function(e) {
     var msg = 'Failed to open indexedDB, are you in private browsing mode?';
     console.error(msg);
-    callback(errors.error(errors.IDB_ERROR, msg));
+    callback(createError(IDB_ERROR, msg));
   };
 }
 
@@ -991,4 +997,4 @@
   }
 }
 
-module.exports = IdbPouch;
+export default IdbPouch;
diff --git a/lib/adapters/idb/utils.js b/src/adapters/idb/utils.js
similarity index 74%
rename from lib/adapters/idb/utils.js
rename to src/adapters/idb/utils.js
index da8c82a..e86c7cf 100644
--- a/lib/adapters/idb/utils.js
+++ b/src/adapters/idb/utils.js
@@ -1,17 +1,14 @@
-'use strict';
-
-var extend = require('js-extend').extend;
-var Promise = require('../../deps/promise');
-var errors = require('../../deps/errors');
-var pick = require('../../deps/pick');
-var safeJsonParse = require('../../deps/safeJsonParse');
-var safeJsonStringify = require('../../deps/safeJsonStringify');
-var base64 = require('../../deps/binary/base64');
-var btoa = base64.btoa;
-var constants = require('./constants');
-var readAsBinaryString = require('../../deps/binary/readAsBinaryString');
-var b64StringToBlob = require('../../deps/binary/base64StringToBlobOrBuffer');
-var createBlob = require('../../deps/binary/blob');
+import { extend as extend } from 'js-extend';
+import Promise from '../../deps/promise';
+import { createError, IDB_ERROR } from '../../deps/errors';
+import pick from '../../deps/pick';
+import safeJsonParse from '../../deps/safeJsonParse';
+import safeJsonStringify from '../../deps/safeJsonStringify';
+import { btoa } from '../../deps/binary/base64';
+import { ATTACH_AND_SEQ_STORE, ATTACH_STORE, BY_SEQ_STORE } from './constants';
+import readAsBinaryString from '../../deps/binary/readAsBinaryString';
+import b64StringToBlob from '../../deps/binary/base64StringToBlobOrBuffer';
+import createBlob from '../../deps/binary/blob';
 
 function tryCode(fun, that, args) {
   try {
@@ -23,33 +20,33 @@
   }
 }
 
-exports.taskQueue = {
+var taskQueue = {
   running: false,
   queue: []
 };
 
-exports.applyNext = function () {
-  if (exports.taskQueue.running || !exports.taskQueue.queue.length) {
+function applyNext() {
+  if (taskQueue.running || !taskQueue.queue.length) {
     return;
   }
-  exports.taskQueue.running = true;
-  var item = exports.taskQueue.queue.shift();
+  taskQueue.running = true;
+  var item = taskQueue.queue.shift();
   item.action(function (err, res) {
     tryCode(item.callback, this, [err, res]);
-    exports.taskQueue.running = false;
-    process.nextTick(exports.applyNext);
+    taskQueue.running = false;
+    process.nextTick(applyNext);
   });
-};
+}
 
-exports.idbError = function (callback) {
+function idbError(callback) {
   return function (evt) {
     var message = 'unknown_error';
     if (evt.target && evt.target.error) {
       message = evt.target.error.name || evt.target.error.message;
     }
-    callback(errors.error(errors.IDB_ERROR, message, evt.type));
+    callback(createError(IDB_ERROR, message, evt.type));
   };
-};
+}
 
 // Unfortunately, the metadata has to be stringified
 // when it is put into the database, because otherwise
@@ -58,7 +55,7 @@
 // we use this custom vuvuzela library that avoids recursion.
 // If we could do it all over again, we'd probably use a
 // format for the revision trees other than JSON.
-exports.encodeMetadata = function (metadata, winningRev, deleted) {
+function encodeMetadata(metadata, winningRev, deleted) {
   return {
     data: safeJsonStringify(metadata),
     winningRev: winningRev,
@@ -66,9 +63,9 @@
     seq: metadata.seq, // highest seq for this doc
     id: metadata.id
   };
-};
+}
 
-exports.decodeMetadata = function (storedObject) {
+function decodeMetadata(storedObject) {
   if (!storedObject) {
     return null;
   }
@@ -77,11 +74,11 @@
   metadata.deleted = storedObject.deletedOrLocal === '1';
   metadata.seq = storedObject.seq;
   return metadata;
-};
+}
 
 // read the doc back out from the database. we don't store the
 // _id or _rev because we already have _doc_id_rev.
-exports.decodeDoc = function (doc) {
+function decodeDoc(doc) {
   if (!doc) {
     return doc;
   }
@@ -90,12 +87,12 @@
   doc._rev = doc._doc_id_rev.substring(idx + 1);
   delete doc._doc_id_rev;
   return doc;
-};
+}
 
 // Read a blob from the database, encoding as necessary
 // and translating from base64 if the IDB doesn't support
 // native Blobs
-exports.readBlobData = function (body, type, asBlob, callback) {
+function readBlobData(body, type, asBlob, callback) {
   if (asBlob) {
     if (!body) {
       callback(createBlob([''], {type: type}));
@@ -115,9 +112,9 @@
       callback(body);
     }
   }
-};
+}
 
-exports.fetchAttachmentsIfNecessary = function (doc, opts, txn, cb) {
+function fetchAttachmentsIfNecessary(doc, opts, txn, cb) {
   var attachments = Object.keys(doc._attachments || {});
   if (!attachments.length) {
     return cb && cb();
@@ -133,7 +130,7 @@
   function fetchAttachment(doc, att) {
     var attObj = doc._attachments[att];
     var digest = attObj.digest;
-    var req = txn.objectStore(constants.ATTACH_STORE).get(digest);
+    var req = txn.objectStore(ATTACH_STORE).get(digest);
     req.onsuccess = function (e) {
       attObj.body = e.target.result.body;
       checkDone();
@@ -148,13 +145,13 @@
       checkDone();
     }
   });
-};
+}
 
 // IDB-specific postprocessing necessary because
 // we don't know whether we stored a true Blob or
 // a base64-encoded string, and if it's a Blob it
 // needs to be read outside of the transaction context
-exports.postProcessAttachments = function (results, asBlob) {
+function postProcessAttachments(results, asBlob) {
   return Promise.all(results.map(function (row) {
     if (row.doc && row.doc._attachments) {
       var attNames = Object.keys(row.doc._attachments);
@@ -166,7 +163,7 @@
         var body = attObj.body;
         var type = attObj.content_type;
         return new Promise(function (resolve) {
-          exports.readBlobData(body, type, asBlob, function (data) {
+          readBlobData(body, type, asBlob, function (data) {
             row.doc._attachments[att] = extend(
               pick(attObj, ['digest', 'content_type']),
               {data: data}
@@ -177,14 +174,14 @@
       }));
     }
   }));
-};
+}
 
-exports.compactRevs = function (revs, docId, txn) {
+function compactRevs(revs, docId, txn) {
 
   var possiblyOrphanedDigests = [];
-  var seqStore = txn.objectStore(constants.BY_SEQ_STORE);
-  var attStore = txn.objectStore(constants.ATTACH_STORE);
-  var attAndSeqStore = txn.objectStore(constants.ATTACH_AND_SEQ_STORE);
+  var seqStore = txn.objectStore(BY_SEQ_STORE);
+  var attStore = txn.objectStore(ATTACH_STORE);
+  var attAndSeqStore = txn.objectStore(ATTACH_AND_SEQ_STORE);
   var count = revs.length;
 
   function checkDone() {
@@ -238,9 +235,9 @@
       };
     };
   });
-};
+}
 
-exports.openTransactionSafely = function (idb, stores, mode) {
+function openTransactionSafely(idb, stores, mode) {
   try {
     return {
       txn: idb.transaction(stores, mode)
@@ -250,4 +247,18 @@
       error: err
     };
   }
-};
+}
+
+export {
+  fetchAttachmentsIfNecessary,
+  openTransactionSafely,
+  compactRevs,
+  postProcessAttachments,
+  applyNext,
+  idbError,
+  encodeMetadata,
+  decodeMetadata,
+  decodeDoc,
+  taskQueue,
+  readBlobData
+};
\ No newline at end of file
diff --git a/src/adapters/leveldb/createEmptyBlobOrBuffer-browser.js b/src/adapters/leveldb/createEmptyBlobOrBuffer-browser.js
new file mode 100644
index 0000000..41914fc
--- /dev/null
+++ b/src/adapters/leveldb/createEmptyBlobOrBuffer-browser.js
@@ -0,0 +1,7 @@
+import createBlob from '../../deps/binary/blob';
+
+function createEmptyBlobOrBuffer(type) {
+  return createBlob([''], {type: type});
+}
+
+export default createEmptyBlobOrBuffer;
\ No newline at end of file
diff --git a/src/adapters/leveldb/createEmptyBlobOrBuffer.js b/src/adapters/leveldb/createEmptyBlobOrBuffer.js
new file mode 100644
index 0000000..dbaf3bf
--- /dev/null
+++ b/src/adapters/leveldb/createEmptyBlobOrBuffer.js
@@ -0,0 +1,7 @@
+import typedBuffer from '../../deps/binary/typedBuffer';
+
+function createEmptyBlobOrBuffer(type) {
+  return typedBuffer('', 'binary', type);
+}
+
+export default createEmptyBlobOrBuffer;
\ No newline at end of file
diff --git a/lib/adapters/leveldb/index.js b/src/adapters/leveldb/index.js
similarity index 93%
rename from lib/adapters/leveldb/index.js
rename to src/adapters/leveldb/index.js
index 37ceb0d..cc36c87 100644
--- a/lib/adapters/leveldb/index.js
+++ b/src/adapters/leveldb/index.js
@@ -1,40 +1,43 @@
-'use strict';
+import levelup from 'levelup';
+import sublevel from 'level-sublevel/legacy';
+import { obj as through } from 'through2';
 
-var levelup = require('levelup');
-var sublevel = require('level-sublevel/legacy');
-var through = require('through2').obj;
+import clone from '../../deps/clone';
+import Changes from '../../changesHandler';
+import uuid from '../../deps/uuid';
+import collections from 'pouchdb-collections';
+import filterChange from '../../deps/filterChange';
+import getArguments from 'argsarray';
+import safeJsonParse from '../../deps/safeJsonParse';
+import safeJsonStringify from '../../deps/safeJsonStringify';
+import calculateWinningRev from '../../deps/merge/winningRev';
+import traverseRevTree from '../../deps/merge/traverseRevTree';
+import compactTree from '../../deps/merge/compactTree';
+import collectConflicts from '../../deps/merge/collectConflicts';
+import isDeleted from '../../deps/docs/isDeleted';
+import isLocalId from '../../deps/docs/isLocalId';
+import { parseDoc as parseDoc } from '../../deps/docs/parseDoc';
+import processDocs from '../../deps/docs/processDocs';
+import md5 from '../../deps/md5';
+import migrate from '../../deps/migrate';
+import Deque from "double-ended-queue";
+import { atob as atob } from '../../deps/binary/base64';
+import functionName from '../../deps/functionName';
+import readAsBluffer from './readAsBlobOrBuffer';
+import prepareAttachmentForStorage from './prepareAttachmentForStorage';
+import createEmptyBluffer from './createEmptyBlobOrBuffer';
+import Promise from '../../deps/promise';
+import binStringToBluffer from '../../deps/binary/binaryStringToBlobOrBuffer';
+import LevelTransaction from './transaction';
 
-var errors = require('../../deps/errors');
-var clone = require('../../deps/clone');
-var Changes = require('../../changesHandler');
-var uuid = require('../../deps/uuid');
-var collections = require('pouchdb-collections');
-var filterChange = require('../../deps/filterChange');
-var getArguments = require('argsarray');
-var safeJsonParse = require('../../deps/safeJsonParse');
-var safeJsonStringify = require('../../deps/safeJsonStringify');
-var calculateWinningRev = require('../../deps/merge/winningRev');
-var traverseRevTree = require('../../deps/merge/traverseRevTree');
-var compactTree = require('../../deps/merge/compactTree');
-var collectConflicts = require('../../deps/merge/collectConflicts');
-var isDeleted = require('../../deps/docs/isDeleted');
-var isLocalId = require('../../deps/docs/isLocalId');
-var parseDoc = require('../../deps/docs/parseDoc');
-var processDocs = require('../../deps/docs/processDocs');
-var md5 = require('../../deps/md5');
-var migrate = require('../../deps/migrate');
-var Deque = require("double-ended-queue");
-var atob = require('../../deps/binary/base64').atob;
-var functionName = require('../../deps/functionName');
-var readAsBluffer = require('./readAsBlobOrBuffer');
-var prepareAttachmentForStorage = require('./prepareAttachmentForStorage');
-var createEmptyBluffer = require('./createEmptyBlobOrBuffer');
-var Promise = require('../../deps/promise');
-
-var binStringToBluffer =
-  require('../../deps/binary/binaryStringToBlobOrBuffer');
-
-var LevelTransaction = require('./transaction');
+import {
+  MISSING_DOC,
+  REV_CONFLICT,
+  NOT_OPEN,
+  BAD_ARG,
+  MISSING_STUB,
+  createError
+} from '../../deps/errors';
 
 var DOC_STORE = 'document-store';
 var BY_SEQ_STORE = 'by-sequence';
@@ -376,13 +379,13 @@
     stores.docStore.get(id, function (err, metadata) {
 
       if (err || !metadata) {
-        return callback(errors.error(errors.MISSING_DOC, 'missing'));
+        return callback(createError(MISSING_DOC, 'missing'));
       }
 
       var rev = getWinningRev(metadata);
       var deleted = getIsDeleted(metadata, rev);
       if (deleted && !opts.rev) {
-        return callback(errors.error(errors.MISSING_DOC, "deleted"));
+        return callback(createError(MISSING_DOC, "deleted"));
       }
 
       rev = opts.rev ? opts.rev : rev;
@@ -391,7 +394,7 @@
 
       stores.bySeqStore.get(formatSeq(seq), function (err, doc) {
         if (!doc) {
-          return callback(errors.error(errors.MISSING_DOC));
+          return callback(createError(MISSING_DOC));
         }
         /* istanbul ignore if */
         if ('_id' in doc && doc._id !== metadata.id) {
@@ -452,7 +455,7 @@
       if (doc._id && isLocalId(doc._id)) {
         return doc;
       }
-      var newDoc = parseDoc.parseDoc(doc, newEdits);
+      var newDoc = parseDoc(doc, newEdits);
 
       if (newDoc.metadata && !newDoc.metadata.rev_map) {
         newDoc.metadata.rev_map = {};
@@ -473,7 +476,7 @@
     function verifyAttachment(digest, callback) {
       txn.get(stores.attachmentStore, digest, function (levelErr) {
         if (levelErr) {
-          var err = errors.error(errors.MISSING_STUB,
+          var err = createError(MISSING_STUB,
                                 'unknown stub attachment with digest ' +
                                 digest);
           callback(err);
@@ -640,7 +643,7 @@
           try {
             data = atob(att.data);
           } catch (e) {
-            callback(errors.error(errors.BAD_ARG,
+            callback(createError(BAD_ARG,
                      'Attachment is not a valid base64 string'));
             return;
           }
@@ -1141,7 +1144,7 @@
   api._close = function (callback) {
     /* istanbul ignore if */
     if (db.isClosed()) {
-      return callback(errors.error(errors.NOT_OPEN));
+      return callback(createError(NOT_OPEN));
     }
     db.close(function (err) {
       /* istanbul ignore if */
@@ -1157,7 +1160,7 @@
   api._getRevisionTree = function (docId, callback) {
     stores.docStore.get(docId, function (err, metadata) {
       if (err) {
-        callback(errors.error(errors.MISSING_DOC));
+        callback(createError(MISSING_DOC));
       } else {
         callback(null, metadata.rev_tree);
       }
@@ -1321,7 +1324,7 @@
   api._getLocal = function (id, callback) {
     stores.localStore.get(id, function (err, doc) {
       if (err) {
-        callback(errors.error(errors.MISSING_DOC));
+        callback(createError(MISSING_DOC));
       } else {
         callback(null, doc);
       }
@@ -1354,10 +1357,10 @@
 
     txn.get(stores.localStore, id, function (err, resp) {
       if (err && oldRev) {
-        return callback(errors.error(errors.REV_CONFLICT));
+        return callback(createError(REV_CONFLICT));
       }
       if (resp && resp._rev !== oldRev) {
-        return callback(errors.error(errors.REV_CONFLICT));
+        return callback(createError(REV_CONFLICT));
       }
       doc._rev =
           oldRev ? '0-' + (parseInt(oldRev.split('-')[1], 10) + 1) : '0-1';
@@ -1412,11 +1415,11 @@
         if (err.name !== 'NotFoundError') {
           return callback(err);
         } else {
-          return callback(errors.error(errors.MISSING_DOC));
+          return callback(createError(MISSING_DOC));
         }
       }
       if (resp._rev !== doc._rev) {
-        return callback(errors.error(errors.REV_CONFLICT));
+        return callback(createError(REV_CONFLICT));
       }
       txn.batch([{
         prefix: stores.localStore,
@@ -1480,4 +1483,4 @@
 
 LevelPouch.Changes = new Changes();
 
-module.exports = LevelPouch;
+export default LevelPouch;
diff --git a/src/adapters/leveldb/prepareAttachmentForStorage-browser.js b/src/adapters/leveldb/prepareAttachmentForStorage-browser.js
new file mode 100644
index 0000000..30453db
--- /dev/null
+++ b/src/adapters/leveldb/prepareAttachmentForStorage-browser.js
@@ -0,0 +1,8 @@
+import readAsBinaryString from '../../deps/binary/readAsBinaryString';
+
+// In the browser, we store a binary string
+function prepareAttachmentForStorage(attData, cb) {
+  readAsBinaryString(attData, cb);
+}
+
+export default prepareAttachmentForStorage;
\ No newline at end of file
diff --git a/src/adapters/leveldb/prepareAttachmentForStorage.js b/src/adapters/leveldb/prepareAttachmentForStorage.js
new file mode 100644
index 0000000..c551cca
--- /dev/null
+++ b/src/adapters/leveldb/prepareAttachmentForStorage.js
@@ -0,0 +1,8 @@
+// in Node, we store the buffer directly
+function prepareAttachmentForStorage(attData, cb) {
+  process.nextTick(function () {
+    cb(attData);
+  });
+}
+
+export default prepareAttachmentForStorage;
\ No newline at end of file
diff --git a/lib/adapters/leveldb/readAsBlobOrBuffer-browser.js b/src/adapters/leveldb/readAsBlobOrBuffer-browser.js
similarity index 60%
rename from lib/adapters/leveldb/readAsBlobOrBuffer-browser.js
rename to src/adapters/leveldb/readAsBlobOrBuffer-browser.js
index c2d69af..9906a01 100644
--- a/lib/adapters/leveldb/readAsBlobOrBuffer-browser.js
+++ b/src/adapters/leveldb/readAsBlobOrBuffer-browser.js
@@ -1,9 +1,9 @@
-'use strict';
+import createBlob from '../../deps/binary/blob';
 
-var createBlob = require('../../deps/binary/blob');
-
-module.exports = function readAsBlobOrBuffer(storedObject, type) {
+function readAsBlobOrBuffer(storedObject, type) {
   // In the browser, we've stored a binary string. This now comes back as a
   // browserified Node-style Buffer, but we want a Blob instead.
   return createBlob([storedObject.toArrayBuffer()], {type: type});
-};
\ No newline at end of file
+}
+
+export default readAsBlobOrBuffer;
\ No newline at end of file
diff --git a/lib/adapters/leveldb/readAsBlobOrBuffer.js b/src/adapters/leveldb/readAsBlobOrBuffer.js
similarity index 60%
rename from lib/adapters/leveldb/readAsBlobOrBuffer.js
rename to src/adapters/leveldb/readAsBlobOrBuffer.js
index 86e6884..d478528 100644
--- a/lib/adapters/leveldb/readAsBlobOrBuffer.js
+++ b/src/adapters/leveldb/readAsBlobOrBuffer.js
@@ -1,7 +1,7 @@
-'use strict';
-
-module.exports = function readAsBlobOrBuffer(storedObject, type) {
+function readAsBlobOrBuffer(storedObject, type) {
   // In Node, we've stored a buffer
   storedObject.type = type; // non-standard, but used for consistency
   return storedObject;
-};
\ No newline at end of file
+}
+
+export default readAsBlobOrBuffer;
\ No newline at end of file
diff --git a/lib/adapters/leveldb/transaction.js b/src/adapters/leveldb/transaction.js
similarity index 95%
rename from lib/adapters/leveldb/transaction.js
rename to src/adapters/leveldb/transaction.js
index b46d58b..2543002 100644
--- a/lib/adapters/leveldb/transaction.js
+++ b/src/adapters/leveldb/transaction.js
@@ -1,11 +1,9 @@
-'use strict';
-
 // similar to an idb or websql transaction object
 // designed to be passed around. basically just caches
 // things in-memory and then does a big batch() operation
 // when you're done
 
-var collections = require('pouchdb-collections');
+import collections from 'pouchdb-collections';
 
 function getCacheFor(transaction, store) {
   var prefix = store.prefix()[0];
@@ -83,4 +81,4 @@
   db.batch(uniqBatches, callback);
 };
 
-module.exports = LevelTransaction;
+export default LevelTransaction;
diff --git a/lib/adapters/websql/bulkDocs.js b/src/adapters/websql/bulkDocs.js
similarity index 87%
rename from lib/adapters/websql/bulkDocs.js
rename to src/adapters/websql/bulkDocs.js
index b73fa51..75fd1c6 100644
--- a/lib/adapters/websql/bulkDocs.js
+++ b/src/adapters/websql/bulkDocs.js
@@ -1,28 +1,30 @@
-'use strict';
+import collections from 'pouchdb-collections';
+import preprocessAttachments from '../../deps/docs/preprocessAttachments';
+import isLocalId from '../../deps/docs/isLocalId';
+import processDocs from '../../deps/docs/processDocs';
+import safeJsonParse from '../../deps/safeJsonParse';
+import safeJsonStringify from '../../deps/safeJsonStringify';
+import compactTree from '../../deps/merge/compactTree';
+import { parseDoc } from '../../deps/docs/parseDoc';
+import {
+  MISSING_STUB,
+  createError
+} from '../../deps/errors';
 
-var collections = require('pouchdb-collections');
-var errors = require('../../deps/errors');
-var preprocessAttachments =
-  require('../../deps/docs/preprocessAttachments');
-var isLocalId = require('../../deps/docs/isLocalId');
-var processDocs = require('../../deps/docs/processDocs');
-var safeJsonParse = require('../../deps/safeJsonParse');
-var safeJsonStringify = require('../../deps/safeJsonStringify');
-var compactTree = require('../../deps/merge/compactTree');
-var parseDoc = require('../../deps/docs/parseDoc');
+import {
+  DOC_STORE,
+  BY_SEQ_STORE,
+  ATTACH_STORE,
+  ATTACH_AND_SEQ_STORE
+} from './constants';
 
-var websqlUtils = require('./utils');
-var websqlConstants = require('./constants');
-
-var DOC_STORE = websqlConstants.DOC_STORE;
-var BY_SEQ_STORE = websqlConstants.BY_SEQ_STORE;
-var ATTACH_STORE = websqlConstants.ATTACH_STORE;
-var ATTACH_AND_SEQ_STORE = websqlConstants.ATTACH_AND_SEQ_STORE;
-
-var select = websqlUtils.select;
-var stringifyDoc = websqlUtils.stringifyDoc;
-var compactRevs = websqlUtils.compactRevs;
-var unknownError = websqlUtils.websqlError;
+import {
+  select,
+  stringifyDoc,
+  compactRevs,
+  websqlError,
+  escapeBlob
+} from './utils';
 
 function websqlBulkDocs(dbOpts, req, opts, api, db, Changes, callback) {
   var newEdits = opts.new_edits;
@@ -33,7 +35,7 @@
     if (doc._id && isLocalId(doc._id)) {
       return doc;
     }
-    var newDoc = parseDoc.parseDoc(doc, newEdits);
+    var newDoc = parseDoc(doc, newEdits);
     return newDoc;
   });
 
@@ -63,7 +65,7 @@
       ' WHERE digest=?';
     tx.executeSql(sql, [digest], function (tx, result) {
       if (result.rows.item(0).cnt === 0) {
-        var err = errors.error(errors.MISSING_STUB,
+        var err = createError(MISSING_STUB,
           'unknown stub attachment with digest ' +
           digest);
         callback(err);
@@ -301,7 +303,7 @@
       // from JS to C if we don't have to (TODO: confirm this)
       sql = 'INSERT INTO ' + ATTACH_STORE +
       ' (digest, body, escaped) VALUES (?,?,1)';
-      tx.executeSql(sql, [digest, websqlUtils.escapeBlob(data)], function () {
+      tx.executeSql(sql, [digest, escapeBlob(data)], function () {
         callback();
       }, function () {
         // ignore constaint errors, means it already exists
@@ -324,8 +326,8 @@
           fetchExistingDocs(websqlProcessDocs);
         }
       });
-    }, unknownError(callback), complete);
+    }, websqlError(callback), complete);
   });
 }
 
-module.exports = websqlBulkDocs;
+export default websqlBulkDocs;
diff --git a/src/adapters/websql/constants.js b/src/adapters/websql/constants.js
new file mode 100644
index 0000000..445ee06
--- /dev/null
+++ b/src/adapters/websql/constants.js
@@ -0,0 +1,29 @@
+function quote(str) {
+  return "'" + str + "'";
+}
+
+var ADAPTER_VERSION = 7; // used to manage migrations
+
+// The object stores created for each database
+// DOC_STORE stores the document meta data, its revision history and state
+var DOC_STORE = quote('document-store');
+// BY_SEQ_STORE stores a particular version of a document, keyed by its
+// sequence id
+var BY_SEQ_STORE = quote('by-sequence');
+// Where we store attachments
+var ATTACH_STORE = quote('attach-store');
+var LOCAL_STORE = quote('local-store');
+var META_STORE = quote('metadata-store');
+// where we store many-to-many relations between attachment
+// digests and seqs
+var ATTACH_AND_SEQ_STORE = quote('attach-seq-store');
+
+export {
+  ADAPTER_VERSION as ADAPTER_VERSION,
+  DOC_STORE as DOC_STORE,
+  BY_SEQ_STORE as BY_SEQ_STORE,
+  ATTACH_STORE as ATTACH_STORE,
+  LOCAL_STORE as LOCAL_STORE,
+  META_STORE as META_STORE,
+  ATTACH_AND_SEQ_STORE as ATTACH_AND_SEQ_STORE
+};
\ No newline at end of file
diff --git a/lib/adapters/websql/index.js b/src/adapters/websql/index.js
similarity index 92%
rename from lib/adapters/websql/index.js
rename to src/adapters/websql/index.js
index e351b0a..4b934e2 100644
--- a/lib/adapters/websql/index.js
+++ b/src/adapters/websql/index.js
@@ -1,46 +1,51 @@
-'use strict';
+import { extend as extend } from 'js-extend';
+import clone from '../../deps/clone';
+import uuid from '../../deps/uuid';
+import pick from '../../deps/pick';
+import filterChange from '../../deps/filterChange';
+import isDeleted from '../../deps/docs/isDeleted';
+import isLocalId from '../../deps/docs/isLocalId';
+import parseHexString from '../../deps/parseHex';
+import binStringToBlob from '../../deps/binary/binaryStringToBlobOrBuffer';
+import hasLocalStorage from '../../deps/env/hasLocalStorage';
+import collectConflicts from '../../deps/merge/collectConflicts';
+import traverseRevTree from '../../deps/merge/traverseRevTree';
+import safeJsonParse from '../../deps/safeJsonParse';
+import safeJsonStringify from '../../deps/safeJsonStringify';
+import Changes from '../../changesHandler';
+import isCordova from '../../deps/isCordova';
+import toPromise from '../../deps/toPromise';
+import { btoa } from '../../deps/binary/base64';
+import websqlBulkDocs from './bulkDocs';
 
-var extend = require('js-extend').extend;
-var clone = require('../../deps/clone');
-var uuid = require('../../deps/uuid');
-var pick = require('../../deps/pick');
-var filterChange = require('../../deps/filterChange');
-var isDeleted = require('../../deps/docs/isDeleted');
-var isLocalId = require('../../deps/docs/isLocalId');
-var errors = require('../../deps/errors');
-var parseHexString = require('../../deps/parseHex');
-var binStringToBlob = require('../../deps/binary/binaryStringToBlobOrBuffer');
-var hasLocalStorage = require('../../deps/env/hasLocalStorage');
-var collectConflicts = require('../../deps/merge/collectConflicts');
-var traverseRevTree = require('../../deps/merge/traverseRevTree');
-var safeJsonParse = require('../../deps/safeJsonParse');
-var safeJsonStringify = require('../../deps/safeJsonStringify');
-var Changes = require('../../changesHandler');
-var isCordova = require('../../deps/isCordova');
-var toPromise = require('../../deps/toPromise');
-var base64 = require('../../deps/binary/base64');
-var btoa = base64.btoa;
+import {
+  MISSING_DOC,
+  REV_CONFLICT,
+  createError
+} from '../../deps/errors';
 
-var websqlConstants = require('./constants');
-var websqlUtils = require('./utils');
-var websqlBulkDocs = require('./bulkDocs');
+import {
+  ADAPTER_VERSION,
+  DOC_STORE,
+  BY_SEQ_STORE,
+  ATTACH_STORE,
+  LOCAL_STORE,
+  META_STORE,
+  ATTACH_AND_SEQ_STORE
+} from './constants';
 
-var ADAPTER_VERSION = websqlConstants.ADAPTER_VERSION;
-var DOC_STORE = websqlConstants.DOC_STORE;
-var BY_SEQ_STORE = websqlConstants.BY_SEQ_STORE;
-var ATTACH_STORE = websqlConstants.ATTACH_STORE;
-var LOCAL_STORE = websqlConstants.LOCAL_STORE;
-var META_STORE = websqlConstants.META_STORE;
-var ATTACH_AND_SEQ_STORE = websqlConstants.ATTACH_AND_SEQ_STORE;
-
-var qMarks = websqlUtils.qMarks;
-var stringifyDoc = websqlUtils.stringifyDoc;
-var unstringifyDoc = websqlUtils.unstringifyDoc;
-var select = websqlUtils.select;
-var compactRevs = websqlUtils.compactRevs;
-var websqlError = websqlUtils.websqlError;
-var getSize = websqlUtils.getSize;
-var openDB = websqlUtils.openDB;
+import {
+  qMarks,
+  stringifyDoc,
+  unstringifyDoc,
+  select,
+  compactRevs,
+  websqlError,
+  getSize,
+  openDB,
+  valid,
+  unescapeBlob
+} from './utils';
 
 function fetchAttachmentsIfNecessary(doc, opts, api, txn, cb) {
   var attachments = Object.keys(doc._attachments || {});
@@ -587,13 +592,13 @@
     }
     tx.executeSql(sql, sqlArgs, function (a, results) {
       if (!results.rows.length) {
-        err = errors.error(errors.MISSING_DOC, 'missing');
+        err = createError(MISSING_DOC, 'missing');
         return finish();
       }
       var item = results.rows.item(0);
       metadata = safeJsonParse(item.metadata);
       if (item.deleted && !opts.rev) {
-        err = errors.error(errors.MISSING_DOC, 'deleted');
+        err = createError(MISSING_DOC, 'deleted');
         return finish();
       }
       doc = unstringifyDoc(item.data, metadata.id, item.rev);
@@ -864,7 +869,7 @@
       // but that's not performant. after migration 6, we remove \u0000
       // and add it back in afterwards
       var item = result.rows.item(0);
-      var data = item.escaped ? websqlUtils.unescapeBlob(item.body) :
+      var data = item.escaped ? unescapeBlob(item.body) :
         parseHexString(item.body, encoding);
       if (opts.binary) {
         res = binStringToBlob(data, type);
@@ -880,7 +885,7 @@
       var sql = 'SELECT json AS metadata FROM ' + DOC_STORE + ' WHERE id = ?';
       tx.executeSql(sql, [docId], function (tx, result) {
         if (!result.rows.length) {
-          callback(errors.error(errors.MISSING_DOC));
+          callback(createError(MISSING_DOC));
         } else {
           var data = safeJsonParse(result.rows.item(0).metadata);
           callback(null, data.rev_tree);
@@ -926,7 +931,7 @@
           var doc = unstringifyDoc(item.json, id, item.rev);
           callback(null, doc);
         } else {
-          callback(errors.error(errors.MISSING_DOC));
+          callback(createError(MISSING_DOC));
         }
       });
     });
@@ -967,10 +972,10 @@
             callback(null, ret);
           }
         } else {
-          callback(errors.error(errors.REV_CONFLICT));
+          callback(createError(REV_CONFLICT));
         }
       }, function () {
-        callback(errors.error(errors.REV_CONFLICT));
+        callback(createError(REV_CONFLICT));
         return false; // ack that we handled the error
       });
     }
@@ -998,7 +1003,7 @@
       var params = [doc._id, doc._rev];
       tx.executeSql(sql, params, function (tx, res) {
         if (!res.rowsAffected) {
-          return callback(errors.error(errors.MISSING_DOC));
+          return callback(createError(MISSING_DOC));
         }
         ret = {ok: true, id: doc._id, rev: '0-0'};
         if (opts.ctx) { // return immediately
@@ -1036,8 +1041,8 @@
   };
 }
 
-WebSqlPouch.valid = websqlUtils.valid;
+WebSqlPouch.valid = valid;
 
 WebSqlPouch.Changes = new Changes();
 
-module.exports = WebSqlPouch;
+export default WebSqlPouch;
diff --git a/lib/adapters/websql/utils.js b/src/adapters/websql/utils.js
similarity index 90%
rename from lib/adapters/websql/utils.js
rename to src/adapters/websql/utils.js
index cdcaec7..0eec164 100644
--- a/lib/adapters/websql/utils.js
+++ b/src/adapters/websql/utils.js
@@ -1,12 +1,11 @@
-'use strict';
+import collections from 'pouchdb-collections';
+import { createError, WSQ_ERROR } from '../../deps/errors';
 
-var errors = require('../../deps/errors');
-var collections = require('pouchdb-collections');
-var websqlConstants = require('./constants');
-
-var BY_SEQ_STORE = websqlConstants.BY_SEQ_STORE;
-var ATTACH_STORE = websqlConstants.ATTACH_STORE;
-var ATTACH_AND_SEQ_STORE = websqlConstants.ATTACH_AND_SEQ_STORE;
+import {
+  BY_SEQ_STORE,
+  ATTACH_STORE,
+  ATTACH_AND_SEQ_STORE
+} from './constants';
 
 // escapeBlob and unescapeBlob are workarounds for a websql bug:
 // https://code.google.com/p/chromium/issues/detail?id=422690
@@ -154,7 +153,7 @@
         .match(/function ([^\(]+)/);
     var errorName = (errorNameMatch && errorNameMatch[1]) || event.type;
     var errorReason = event.target || event.message;
-    callback(errors.error(errors.WSQ_ERROR, errorReason, errorName));
+    callback(createError(WSQ_ERROR, errorReason, errorName));
   };
 }
 
@@ -225,16 +224,16 @@
     typeof SQLitePlugin !== 'undefined';
 }
 
-module.exports = {
-  escapeBlob: escapeBlob,
-  unescapeBlob: unescapeBlob,
-  stringifyDoc: stringifyDoc,
-  unstringifyDoc: unstringifyDoc,
-  qMarks: qMarks,
-  select: select,
-  compactRevs: compactRevs,
-  websqlError: websqlError,
-  getSize: getSize,
-  openDB: openDB,
-  valid: valid
+export {
+  escapeBlob,
+  unescapeBlob,
+  stringifyDoc,
+  unstringifyDoc,
+  qMarks,
+  select,
+  compactRevs,
+  getSize,
+  openDB,
+  valid,
+  websqlError
 };
\ No newline at end of file
diff --git a/lib/changes.js b/src/changes.js
similarity index 84%
rename from lib/changes.js
rename to src/changes.js
index b895e87..3bdb4a1 100644
--- a/lib/changes.js
+++ b/src/changes.js
@@ -1,20 +1,24 @@
-'use strict';
-var clone = require('./deps/clone');
-var Promise = require('./deps/promise');
-var isDeleted = require('./deps/docs/isDeleted');
-var inherits = require('inherits');
-var getArguments = require('argsarray');
-var once = require('./deps/once');
-var errors = require('./deps/errors');
-var EE = require('events').EventEmitter;
-var evalFilter = require('./evalFilter');
-var evalView = require('./evalView');
-var parseDdocFunctionName = require('./deps/docs/parseDdocFunctionName');
-var normalizeDdocFunctionName =
-  require('./deps/docs/normalizeDdocFunctionName');
-var collectLeaves = require('./deps/merge/collectLeaves');
-var collectConflicts = require('./deps/merge/collectConflicts');
-module.exports = Changes;
+import clone from './deps/clone';
+import Promise from './deps/promise';
+import isDeleted from './deps/docs/isDeleted';
+import inherits from 'inherits';
+import getArguments from 'argsarray';
+import once from './deps/once';
+import { EventEmitter as EE } from 'events';
+import evalFilter from './evalFilter';
+import evalView from './evalView';
+import parseDdocFunctionName from './deps/docs/parseDdocFunctionName';
+import normalizeDdocFunctionName from './deps/docs/normalizeDdocFunctionName';
+import collectLeaves from './deps/merge/collectLeaves';
+import collectConflicts from './deps/merge/collectConflicts';
+
+import {
+  MISSING_DOC,
+  BAD_REQUEST,
+  createError,
+  generateErrorFromResponse
+} from './deps/errors';
+
 inherits(Changes, EE);
 
 function Changes(db, opts, callback) {
@@ -195,7 +199,7 @@
   var callback = opts.complete;
   if (opts.filter === '_view') {
     if (!opts.view || typeof opts.view !== 'string') {
-      var err = errors.error(errors.BAD_REQUEST,
+      var err = createError(BAD_REQUEST,
         '`view` filter parameter not found or invalid.');
       return callback(err);
     }
@@ -208,12 +212,12 @@
       }
       /* istanbul ignore next */
       if (err) {
-        return callback(errors.generateErrorFromResponse(err));
+        return callback(generateErrorFromResponse(err));
       }
       var mapFun = ddoc && ddoc.views && ddoc.views[viewName[1]] &&
         ddoc.views[viewName[1]].map;
       if (!mapFun) {
-        return callback(errors.error(errors.MISSING_DOC,
+        return callback(createError(MISSING_DOC,
           (ddoc.views ? 'missing json key: ' + viewName[1] :
             'missing json key: views')));
       }
@@ -233,11 +237,11 @@
       }
       /* istanbul ignore next */
       if (err) {
-        return callback(errors.generateErrorFromResponse(err));
+        return callback(generateErrorFromResponse(err));
       }
       var filterFun = ddoc && ddoc.filters && ddoc.filters[filterName[1]];
       if (!filterFun) {
-        return callback(errors.error(errors.MISSING_DOC,
+        return callback(createError(MISSING_DOC,
           ((ddoc && ddoc.filters) ? 'missing json key: ' + filterName[1]
             : 'missing json key: filters')));
       }
@@ -246,3 +250,5 @@
     });
   }
 };
+
+export default Changes;
diff --git a/lib/changesHandler.js b/src/changesHandler.js
similarity index 89%
rename from lib/changesHandler.js
rename to src/changesHandler.js
index da1a96d..db210b2 100644
--- a/lib/changesHandler.js
+++ b/src/changesHandler.js
@@ -1,10 +1,8 @@
-'use strict';
-
-var EventEmitter = require('events').EventEmitter;
-var inherits = require('inherits');
-var isChromeApp = require('./deps/env/isChromeApp');
-var hasLocalStorage = require('./deps/env/hasLocalStorage');
-var pick = require('./deps/pick');
+import { EventEmitter as EventEmitter } from 'events';
+import inherits from 'inherits';
+import isChromeApp from './deps/env/isChromeApp';
+import hasLocalStorage from './deps/env/hasLocalStorage';
+import pick from './deps/pick';
 
 inherits(Changes, EventEmitter);
 
@@ -106,4 +104,4 @@
   this.notifyLocalWindows(dbName);
 };
 
-module.exports = Changes;
+export default Changes;
diff --git a/lib/constructor.js b/src/constructor.js
similarity index 93%
rename from lib/constructor.js
rename to src/constructor.js
index 5ac0132..c841deb 100644
--- a/lib/constructor.js
+++ b/src/constructor.js
@@ -1,13 +1,11 @@
 /*globals cordova */
-"use strict";
-
-var debug = require('debug');
-var inherits = require('inherits');
-var Adapter = require('./adapter');
-var TaskQueue = require('./taskqueue');
-var isCordova = require('./deps/isCordova');
-var Promise = require('./deps/promise');
-var clone = require('./deps/clone');
+import debug from 'debug';
+import inherits from 'inherits';
+import Adapter from './adapter';
+import TaskQueue from './taskqueue';
+import isCordova from './deps/isCordova';
+import Promise from './deps/promise';
+import clone from './deps/clone';
 
 function defaultCallback(err) {
   /* istanbul ignore next */
@@ -183,4 +181,4 @@
 
 PouchDB.debug = debug;
 
-module.exports = PouchDB;
+export default PouchDB;
diff --git a/lib/deps/adapterFun.js b/src/deps/adapterFun.js
similarity index 83%
rename from lib/deps/adapterFun.js
rename to src/deps/adapterFun.js
index 63473da..54b0ee7 100644
--- a/lib/deps/adapterFun.js
+++ b/src/deps/adapterFun.js
@@ -1,12 +1,10 @@
-'use strict';
+import Promise from './promise';
+import toPromise from './toPromise';
+import getArguments from 'argsarray';
+import debug from 'debug';
+var log = debug('pouchdb:api');
 
-var Promise = require('./promise');
-var toPromise = require('./toPromise');
-var getArguments = require('argsarray');
-
-module.exports = function adapterFun(name, callback) {
-  var log = require('debug')('pouchdb:api');
-
+function adapterFun(name, callback) {
   function logApiCall(self, name, args) {
     /* istanbul ignore if */
     if (log.enabled) {
@@ -48,4 +46,6 @@
     }
     return callback.apply(this, args);
   }));
-};
\ No newline at end of file
+}
+
+export default adapterFun;
\ No newline at end of file
diff --git a/lib/deps/ajax/ajaxCore.js b/src/deps/ajax/ajaxCore.js
similarity index 81%
rename from lib/deps/ajax/ajaxCore.js
rename to src/deps/ajax/ajaxCore.js
index bfbed98..56cd02d 100644
--- a/lib/deps/ajax/ajaxCore.js
+++ b/src/deps/ajax/ajaxCore.js
@@ -1,13 +1,11 @@
-"use strict";
+import request from './request';
+import { extend as extend } from 'js-extend';
+import { generateErrorFromResponse } from './../errors';
+import clone from '../../deps/clone';
+import applyTypeToBuffer from './applyTypeToBuffer';
+import defaultBody from './defaultBody';
 
-var request = require('./request');
-var extend = require('js-extend').extend;
-var errors = require('./../errors');
-var clone = require('../../deps/clone');
-var applyTypeToBuffer = require('./applyTypeToBuffer');
-var defaultBody = require('./defaultBody');
-
-function ajax(options, callback) {
+function ajaxCore(options, callback) {
 
   options = clone(options);
 
@@ -34,7 +32,7 @@
     if (Array.isArray(obj)) {
       obj = obj.map(function (v) {
         if (v.error || v.missing) {
-          return errors.generateErrorFromResponse(v);
+          return generateErrorFromResponse(v);
         } else {
           return v;
         }
@@ -58,9 +56,9 @@
     try {
       errParsed = JSON.parse(err.responseText);
       //would prefer not to have a try/catch clause
-      errObj = errors.generateErrorFromResponse(errParsed);
+      errObj = generateErrorFromResponse(errParsed);
     } catch (e) {
-      errObj = errors.generateErrorFromResponse(err);
+      errObj = generateErrorFromResponse(err);
     }
     /* istanbul ignore next */
     cb(errObj);
@@ -108,11 +106,11 @@
     if (response.statusCode >= 200 && response.statusCode < 300) {
       onSuccess(data, response, callback);
     } else {
-      error = errors.generateErrorFromResponse(data);
+      error = generateErrorFromResponse(data);
       error.status = response.statusCode;
       callback(error);
     }
   });
 }
 
-module.exports = ajax;
+export default ajaxCore;
diff --git a/src/deps/ajax/applyTypeToBuffer-browser.js b/src/deps/ajax/applyTypeToBuffer-browser.js
new file mode 100644
index 0000000..b24b807
--- /dev/null
+++ b/src/deps/ajax/applyTypeToBuffer-browser.js
@@ -0,0 +1,4 @@
+// the blob already has a type; do nothing
+var res = function () {};
+
+export default res;
\ No newline at end of file
diff --git a/src/deps/ajax/applyTypeToBuffer.js b/src/deps/ajax/applyTypeToBuffer.js
new file mode 100644
index 0000000..bc7151f
--- /dev/null
+++ b/src/deps/ajax/applyTypeToBuffer.js
@@ -0,0 +1,6 @@
+// non-standard, but we do this to mimic blobs in the browser
+function applyTypeToBuffer(buffer, resp) {
+  buffer.type = resp.headers['content-type'];
+}
+
+export default applyTypeToBuffer;
\ No newline at end of file
diff --git a/src/deps/ajax/createBlobOrBufferFromParts-browser.js b/src/deps/ajax/createBlobOrBufferFromParts-browser.js
new file mode 100644
index 0000000..a3fdc2c
--- /dev/null
+++ b/src/deps/ajax/createBlobOrBufferFromParts-browser.js
@@ -0,0 +1,7 @@
+import createBlob from '../binary/blob';
+
+function createBlobOrBufferFromParts(parts, type) {
+  return createBlob(parts, {type: type});
+}
+
+export default createBlobOrBufferFromParts;
\ No newline at end of file
diff --git a/src/deps/ajax/createBlobOrBufferFromParts.js b/src/deps/ajax/createBlobOrBufferFromParts.js
new file mode 100644
index 0000000..c49b2a4
--- /dev/null
+++ b/src/deps/ajax/createBlobOrBufferFromParts.js
@@ -0,0 +1,9 @@
+import buffer from '../binary/buffer';
+
+function createBlobOrBufferFromParts(parts, type) {
+  return buffer.concat(parts.map(function (part) {
+    return new buffer(part, 'binary');
+  }));
+}
+
+export default createBlobOrBufferFromParts;
\ No newline at end of file
diff --git a/src/deps/ajax/createMultipartPart-browser.js b/src/deps/ajax/createMultipartPart-browser.js
new file mode 100644
index 0000000..a733fbf
--- /dev/null
+++ b/src/deps/ajax/createMultipartPart-browser.js
@@ -0,0 +1,9 @@
+import binaryStringToArrayBuffer from '../binary/binaryStringToArrayBuffer';
+
+// create a "part" suitable for multipart. in the browser
+// this is an ArrayBuffer; in Node it's a binary string
+function createMultipartPart(data) {
+  return binaryStringToArrayBuffer(data);
+}
+
+export default createMultipartPart;
\ No newline at end of file
diff --git a/lib/deps/ajax/createMultipartPart.js b/src/deps/ajax/createMultipartPart.js
similarity index 63%
rename from lib/deps/ajax/createMultipartPart.js
rename to src/deps/ajax/createMultipartPart.js
index 91769cb..3280305 100644
--- a/lib/deps/ajax/createMultipartPart.js
+++ b/src/deps/ajax/createMultipartPart.js
@@ -1,7 +1,7 @@
-'use strict';
-
 // create a "part" suitable for multipart. in the browser
 // this is an ArrayBuffer; in Node it's a binary string
-module.exports = function createMultipartPart(data) {
+function createMultipartPart(data) {
   return data;
-};
\ No newline at end of file
+}
+
+export default createMultipartPart;
\ No newline at end of file
diff --git a/src/deps/ajax/defaultBody-browser.js b/src/deps/ajax/defaultBody-browser.js
new file mode 100644
index 0000000..d176c37
--- /dev/null
+++ b/src/deps/ajax/defaultBody-browser.js
@@ -0,0 +1,5 @@
+function defaultBody() {
+  return '';
+}
+
+export default defaultBody;
\ No newline at end of file
diff --git a/src/deps/ajax/defaultBody.js b/src/deps/ajax/defaultBody.js
new file mode 100644
index 0000000..650c0ac
--- /dev/null
+++ b/src/deps/ajax/defaultBody.js
@@ -0,0 +1,7 @@
+import buffer from '../binary/buffer';
+
+function defaultBody() {
+  return new buffer('', 'binary');
+}
+
+export default defaultBody;
\ No newline at end of file
diff --git a/lib/deps/ajax/explainError-browser.js b/src/deps/ajax/explainError-browser.js
similarity index 76%
rename from lib/deps/ajax/explainError-browser.js
rename to src/deps/ajax/explainError-browser.js
index 093be8f..83594f1 100644
--- a/lib/deps/ajax/explainError-browser.js
+++ b/src/deps/ajax/explainError-browser.js
@@ -1,9 +1,9 @@
-'use strict';
-
 // designed to give info to browser users, who are disturbed
 // when they see http errors in the console
-module.exports = function explainError(status, str) {
+function explainError(status, str) {
   if ('console' in global && 'info' in console) {
     console.info('The above ' + status + ' is totally normal. ' + str);
   }
-};
+}
+
+export default explainError;
\ No newline at end of file
diff --git a/src/deps/ajax/explainError.js b/src/deps/ajax/explainError.js
new file mode 100644
index 0000000..5f602ee
--- /dev/null
+++ b/src/deps/ajax/explainError.js
@@ -0,0 +1,4 @@
+// We assume Node users don't need to see this warning
+var res = function () {};
+
+export default res;
diff --git a/lib/deps/ajax/prequest-browser.js b/src/deps/ajax/prequest-browser.js
similarity index 85%
rename from lib/deps/ajax/prequest-browser.js
rename to src/deps/ajax/prequest-browser.js
index a95bd65..2087ba0 100644
--- a/lib/deps/ajax/prequest-browser.js
+++ b/src/deps/ajax/prequest-browser.js
@@ -1,8 +1,6 @@
-'use strict';
+import ajaxCore from './ajaxCore';
 
-var ajax = require('./ajaxCore');
-
-module.exports = function(opts, callback) {
+function ajax(opts, callback) {
 
   // cache-buster, specifically designed to work around IE's aggressive caching
   // see http://www.dashbay.com/2011/05/internet-explorer-caches-ajax/
@@ -23,5 +21,7 @@
     opts.url += (hasArgs ? '&' : '?') + '_nonce=' + Date.now();
   }
 
-  return ajax(opts, callback);
-};
+  return ajaxCore(opts, callback);
+}
+
+export default ajax;
\ No newline at end of file
diff --git a/src/deps/ajax/prequest.js b/src/deps/ajax/prequest.js
new file mode 100644
index 0000000..0ee7a2f
--- /dev/null
+++ b/src/deps/ajax/prequest.js
@@ -0,0 +1,8 @@
+import ajaxCore from './ajaxCore';
+
+function ajax(opts, callback) {
+  // do nothing; all the action is in prerequest-browser.js
+  return ajaxCore(opts, callback);
+}
+
+export default ajax;
\ No newline at end of file
diff --git a/lib/deps/ajax/request-browser.js b/src/deps/ajax/request-browser.js
similarity index 95%
rename from lib/deps/ajax/request-browser.js
rename to src/deps/ajax/request-browser.js
index 6d94acd..bcba635 100644
--- a/lib/deps/ajax/request-browser.js
+++ b/src/deps/ajax/request-browser.js
@@ -1,10 +1,8 @@
 /* global fetch */
 /* global Headers */
-'use strict';
-
-var createBlob = require('./../binary/blob.js');
-var readAsArrayBuffer = require('./../binary/readAsArrayBuffer');
-var Promise = require('../../deps/promise');
+import createBlob from './../binary/blob.js';
+import readAsArrayBuffer from './../binary/readAsArrayBuffer';
+import Promise from '../../deps/promise';
 
 function wrappedFetch() {
   var wrappedPromise = {};
@@ -218,10 +216,12 @@
 
 var hasXhr = testXhr();
 
-module.exports = function(options, callback) {
+function ajax(options, callback) {
   if (hasXhr || options.xhr) {
     return xhRequest(options, callback);
   } else {
     return fetchRequest(options, callback);
   }
-};
+}
+
+export default ajax;
\ No newline at end of file
diff --git a/lib/deps/ajax/request.js b/src/deps/ajax/request.js
similarity index 61%
rename from lib/deps/ajax/request.js
rename to src/deps/ajax/request.js
index b2865de..92c1697 100644
--- a/lib/deps/ajax/request.js
+++ b/src/deps/ajax/request.js
@@ -1,5 +1,3 @@
-'use strict';
-
 // May seem redundant, but this is to allow switching with
 // request-browser.js.
-module.exports = require('request');
\ No newline at end of file
+export default require('request');
\ No newline at end of file
diff --git a/lib/deps/binary/arrayBufferToBinaryString.js b/src/deps/binary/arrayBufferToBinaryString.js
similarity index 80%
rename from lib/deps/binary/arrayBufferToBinaryString.js
rename to src/deps/binary/arrayBufferToBinaryString.js
index 65ec454..a7892bb 100644
--- a/lib/deps/binary/arrayBufferToBinaryString.js
+++ b/src/deps/binary/arrayBufferToBinaryString.js
@@ -1,9 +1,7 @@
-'use strict';
-
 //Can't find original post, but this is close
 //http://stackoverflow.com/questions/6965107/ (continues on next line)
 //converting-between-strings-and-arraybuffers
-module.exports = function (buffer) {
+function arrayBufferToBinaryString(buffer) {
   var binary = '';
   var bytes = new Uint8Array(buffer);
   var length = bytes.byteLength;
@@ -11,4 +9,6 @@
     binary += String.fromCharCode(bytes[i]);
   }
   return binary;
-};
\ No newline at end of file
+}
+
+export default arrayBufferToBinaryString;
\ No newline at end of file
diff --git a/src/deps/binary/base64-browser.js b/src/deps/binary/base64-browser.js
new file mode 100644
index 0000000..95f595a
--- /dev/null
+++ b/src/deps/binary/base64-browser.js
@@ -0,0 +1,12 @@
+var thisAtob = function (str) {
+  return atob(str);
+};
+
+var thisBtoa = function (str) {
+  return btoa(str);
+};
+
+export {
+  thisAtob as atob,
+  thisBtoa as btoa
+};
\ No newline at end of file
diff --git a/lib/deps/binary/base64.js b/src/deps/binary/base64.js
similarity index 72%
rename from lib/deps/binary/base64.js
rename to src/deps/binary/base64.js
index 84baca0..9dc95f5 100644
--- a/lib/deps/binary/base64.js
+++ b/src/deps/binary/base64.js
@@ -1,8 +1,6 @@
-'use strict';
+import buffer from './buffer';
 
-var buffer = require('./buffer');
-
-exports.atob = function (str) {
+function thisAtob(str) {
   var base64 = new buffer(str, 'base64');
   // Node.js will just skip the characters it can't decode instead of
   // throwing an exception
@@ -10,8 +8,13 @@
     throw new Error("attachment is not a valid base64 string");
   }
   return base64.toString('binary');
-};
+}
 
-exports.btoa = function (str) {
+function thisBtoa(str) {
   return new buffer(str, 'binary').toString('base64');
+}
+
+export {
+  thisAtob as atob,
+  thisBtoa as btoa
 };
\ No newline at end of file
diff --git a/src/deps/binary/base64StringToBlobOrBuffer-browser.js b/src/deps/binary/base64StringToBlobOrBuffer-browser.js
new file mode 100644
index 0000000..f182866
--- /dev/null
+++ b/src/deps/binary/base64StringToBlobOrBuffer-browser.js
@@ -0,0 +1,8 @@
+import { atob as atob } from './base64';
+import binaryStringToBlobOrBuffer from './binaryStringToBlobOrBuffer';
+
+function b64ToBluffer(b64, type) {
+  return binaryStringToBlobOrBuffer(atob(b64), type);
+}
+
+export default b64ToBluffer;
\ No newline at end of file
diff --git a/src/deps/binary/base64StringToBlobOrBuffer.js b/src/deps/binary/base64StringToBlobOrBuffer.js
new file mode 100644
index 0000000..b2082ab
--- /dev/null
+++ b/src/deps/binary/base64StringToBlobOrBuffer.js
@@ -0,0 +1,7 @@
+import typedBuffer from './typedBuffer';
+
+function b64ToBluffer(b64, type) {
+  return typedBuffer(b64, 'base64', type);
+}
+
+export default b64ToBluffer;
\ No newline at end of file
diff --git a/lib/deps/binary/binaryStringToArrayBuffer.js b/src/deps/binary/binaryStringToArrayBuffer.js
similarity index 79%
rename from lib/deps/binary/binaryStringToArrayBuffer.js
rename to src/deps/binary/binaryStringToArrayBuffer.js
index c11b166..180f1b4 100644
--- a/lib/deps/binary/binaryStringToArrayBuffer.js
+++ b/src/deps/binary/binaryStringToArrayBuffer.js
@@ -1,8 +1,6 @@
-'use strict';
-
 // From http://stackoverflow.com/questions/14967647/ (continues on next line)
 // encode-decode-image-with-base64-breaks-image (2013-04-21)
-module.exports = function (bin) {
+function binaryStringToArrayBuffer(bin) {
   var length = bin.length;
   var buf = new ArrayBuffer(length);
   var arr = new Uint8Array(buf);
@@ -10,4 +8,6 @@
     arr[i] = bin.charCodeAt(i);
   }
   return buf;
-};
\ No newline at end of file
+}
+
+export default binaryStringToArrayBuffer;
\ No newline at end of file
diff --git a/src/deps/binary/binaryStringToBlobOrBuffer-browser.js b/src/deps/binary/binaryStringToBlobOrBuffer-browser.js
new file mode 100644
index 0000000..e7a9f08
--- /dev/null
+++ b/src/deps/binary/binaryStringToBlobOrBuffer-browser.js
@@ -0,0 +1,8 @@
+import createBlob from './blob';
+import binaryStringToArrayBuffer from './binaryStringToArrayBuffer';
+
+function binStringToBluffer(binString, type) {
+  return createBlob([binaryStringToArrayBuffer(binString)], {type: type});
+}
+
+export default binStringToBluffer;
\ No newline at end of file
diff --git a/src/deps/binary/binaryStringToBlobOrBuffer.js b/src/deps/binary/binaryStringToBlobOrBuffer.js
new file mode 100644
index 0000000..eb18534
--- /dev/null
+++ b/src/deps/binary/binaryStringToBlobOrBuffer.js
@@ -0,0 +1,7 @@
+import typedBuffer from './typedBuffer';
+
+function binStringToBluffer(binString, type) {
+  return typedBuffer(binString, 'binary', type);
+}
+
+export default binStringToBluffer;
\ No newline at end of file
diff --git a/lib/deps/binary/blob.js b/src/deps/binary/blob.js
similarity index 95%
rename from lib/deps/binary/blob.js
rename to src/deps/binary/blob.js
index 6821fd7..5c04eb1 100644
--- a/lib/deps/binary/blob.js
+++ b/src/deps/binary/blob.js
@@ -1,5 +1,3 @@
-"use strict";
-
 // Abstracts constructing a Blob object, so it also works in older
 // browsers that don't support the native Blob constructor (e.g.
 // old QtWebKit versions, Android < 4.4).
@@ -25,5 +23,5 @@
   }
 }
 
-module.exports = createBlob;
+export default createBlob;
 
diff --git a/src/deps/binary/blobOrBufferToBase64-browser.js b/src/deps/binary/blobOrBufferToBase64-browser.js
new file mode 100644
index 0000000..b5ba5d1
--- /dev/null
+++ b/src/deps/binary/blobOrBufferToBase64-browser.js
@@ -0,0 +1,13 @@
+import Promise from '../promise';
+import readAsBinaryString from './readAsBinaryString';
+import { btoa as btoa } from './base64';
+
+function blobToBase64(blobOrBuffer) {
+  return new Promise(function (resolve) {
+    readAsBinaryString(blobOrBuffer, function (bin) {
+      resolve(btoa(bin));
+    });
+  });
+}
+
+export default blobToBase64;
\ No newline at end of file
diff --git a/src/deps/binary/blobOrBufferToBase64.js b/src/deps/binary/blobOrBufferToBase64.js
new file mode 100644
index 0000000..16dc63f
--- /dev/null
+++ b/src/deps/binary/blobOrBufferToBase64.js
@@ -0,0 +1,7 @@
+import Promise from '../promise';
+
+function blobToBase64(blobOrBuffer) {
+  return Promise.resolve(blobOrBuffer.toString('base64'));
+}
+
+export default blobToBase64;
\ No newline at end of file
diff --git a/lib/deps/binary/buffer-browser.js b/src/deps/binary/buffer-browser.js
similarity index 72%
rename from lib/deps/binary/buffer-browser.js
rename to src/deps/binary/buffer-browser.js
index 67af5e6..1fe449a 100644
--- a/lib/deps/binary/buffer-browser.js
+++ b/src/deps/binary/buffer-browser.js
@@ -1,2 +1,2 @@
 // hey guess what, we don't need this in the browser
-module.exports = {};
\ No newline at end of file
+export default {};
\ No newline at end of file
diff --git a/lib/deps/binary/buffer.js b/src/deps/binary/buffer.js
similarity index 70%
rename from lib/deps/binary/buffer.js
rename to src/deps/binary/buffer.js
index 08e67bf..7f5908e 100644
--- a/lib/deps/binary/buffer.js
+++ b/src/deps/binary/buffer.js
@@ -1,2 +1,2 @@
 //this solely exists so we can exclude it in browserify
-module.exports = Buffer;
\ No newline at end of file
+export default Buffer;
\ No newline at end of file
diff --git a/lib/deps/binary/cloneBinaryObject-browser.js b/src/deps/binary/cloneBinaryObject-browser.js
similarity index 89%
rename from lib/deps/binary/cloneBinaryObject-browser.js
rename to src/deps/binary/cloneBinaryObject-browser.js
index eafcc4a..fab74c9 100644
--- a/lib/deps/binary/cloneBinaryObject-browser.js
+++ b/src/deps/binary/cloneBinaryObject-browser.js
@@ -1,5 +1,3 @@
-'use strict';
-
 function cloneArrayBuffer(buff) {
   if (typeof buff.slice === 'function') {
     return buff.slice(0);
@@ -12,7 +10,7 @@
   return target;
 }
 
-module.exports = function cloneBinaryObject(object) {
+function cloneBinaryObject(object) {
   if (object instanceof ArrayBuffer) {
     return cloneArrayBuffer(object);
   }
@@ -24,4 +22,6 @@
   }
   // PhantomJS slice() replacement
   return object.webkitSlice(0, size, type);
-};
+}
+
+export default cloneBinaryObject;
\ No newline at end of file
diff --git a/src/deps/binary/cloneBinaryObject.js b/src/deps/binary/cloneBinaryObject.js
new file mode 100644
index 0000000..2ed765c
--- /dev/null
+++ b/src/deps/binary/cloneBinaryObject.js
@@ -0,0 +1,7 @@
+function cloneBinaryObject(object) {
+  var copy = new Buffer(object.length);
+  object.copy(copy);
+  return copy;
+}
+
+export default cloneBinaryObject;
\ No newline at end of file
diff --git a/lib/deps/binary/isBinaryObject-browser.js b/src/deps/binary/isBinaryObject-browser.js
similarity index 60%
rename from lib/deps/binary/isBinaryObject-browser.js
rename to src/deps/binary/isBinaryObject-browser.js
index 26a4401..5982f28 100644
--- a/lib/deps/binary/isBinaryObject-browser.js
+++ b/src/deps/binary/isBinaryObject-browser.js
@@ -1,6 +1,6 @@
-'use strict';
-
-module.exports = function isBinaryObject(object) {
+function isBinaryObject(object) {
   return object instanceof ArrayBuffer ||
     (typeof Blob !== 'undefined' && object instanceof Blob);
-};
\ No newline at end of file
+}
+
+export default isBinaryObject;
\ No newline at end of file
diff --git a/src/deps/binary/isBinaryObject.js b/src/deps/binary/isBinaryObject.js
new file mode 100644
index 0000000..9ee1942
--- /dev/null
+++ b/src/deps/binary/isBinaryObject.js
@@ -0,0 +1,5 @@
+function isBinaryObject(object) {
+  return object instanceof Buffer;
+}
+
+export default isBinaryObject;
\ No newline at end of file
diff --git a/lib/deps/binary/readAsArrayBuffer.js b/src/deps/binary/readAsArrayBuffer.js
similarity index 84%
rename from lib/deps/binary/readAsArrayBuffer.js
rename to src/deps/binary/readAsArrayBuffer.js
index 224bec1..60fead7 100644
--- a/lib/deps/binary/readAsArrayBuffer.js
+++ b/src/deps/binary/readAsArrayBuffer.js
@@ -1,7 +1,5 @@
-'use strict';
-
 // simplified API. universal browser support is assumed
-module.exports = function (blob, callback) {
+function readAsArrayBuffer(blob, callback) {
   if (typeof FileReader === 'undefined') {
     // fix for Firefox in a web worker:
     // https://bugzilla.mozilla.org/show_bug.cgi?id=901097
@@ -14,4 +12,6 @@
     callback(result);
   };
   reader.readAsArrayBuffer(blob);
-};
\ No newline at end of file
+}
+
+export default readAsArrayBuffer;
\ No newline at end of file
diff --git a/lib/deps/binary/readAsBinaryString.js b/src/deps/binary/readAsBinaryString.js
similarity index 82%
rename from lib/deps/binary/readAsBinaryString.js
rename to src/deps/binary/readAsBinaryString.js
index defe286..9c27781 100644
--- a/lib/deps/binary/readAsBinaryString.js
+++ b/src/deps/binary/readAsBinaryString.js
@@ -1,9 +1,7 @@
-'use strict';
-
-var arrayBufferToBinaryString = require('./arrayBufferToBinaryString');
+import arrayBufferToBinaryString from './arrayBufferToBinaryString';
 
 // shim for browsers that don't support it
-module.exports = function (blob, callback) {
+function readAsBinaryString(blob, callback) {
   if (typeof FileReader === 'undefined') {
     // fix for Firefox in a web worker
     // https://bugzilla.mozilla.org/show_bug.cgi?id=901097
@@ -25,4 +23,6 @@
   } else {
     reader.readAsArrayBuffer(blob);
   }
-};
\ No newline at end of file
+}
+
+export default readAsBinaryString;
\ No newline at end of file
diff --git a/lib/deps/binary/typedBuffer.js b/src/deps/binary/typedBuffer.js
similarity index 75%
rename from lib/deps/binary/typedBuffer.js
rename to src/deps/binary/typedBuffer.js
index 9939bd5..ad8c453 100644
--- a/lib/deps/binary/typedBuffer.js
+++ b/src/deps/binary/typedBuffer.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var buffer = require('./buffer');
+import buffer from './buffer';
 
 function typedBuffer(binString, buffType, type) {
   // buffType is either 'binary' or 'base64'
@@ -9,4 +7,4 @@
   return buff;
 }
 
-module.exports = typedBuffer;
\ No newline at end of file
+export default typedBuffer;
\ No newline at end of file
diff --git a/lib/deps/bulkGetShim.js b/src/deps/bulkGetShim.js
similarity index 96%
rename from lib/deps/bulkGetShim.js
rename to src/deps/bulkGetShim.js
index 70afa86..0fbfb5a 100644
--- a/lib/deps/bulkGetShim.js
+++ b/src/deps/bulkGetShim.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var pick = require('../deps/pick');
+import pick from '../deps/pick';
 
 // shim for P/CouchDB adapters that don't directly implement _bulk_get
 function bulkGet(db, opts, callback) {
@@ -90,4 +88,4 @@
   });
 }
 
-module.exports = bulkGet;
+export default bulkGet;
diff --git a/lib/deps/clone.js b/src/deps/clone.js
similarity index 81%
rename from lib/deps/clone.js
rename to src/deps/clone.js
index bb70628..73667e6 100644
--- a/lib/deps/clone.js
+++ b/src/deps/clone.js
@@ -1,9 +1,7 @@
-'use strict';
+import isBinaryObject from './binary/isBinaryObject';
+import cloneBinaryObject from './binary/cloneBinaryObject';
 
-var isBinaryObject = require('./binary/isBinaryObject');
-var cloneBinaryObject = require('./binary/cloneBinaryObject');
-
-module.exports = function clone(object) {
+function clone(object) {
   var newObject;
   var i;
   var len;
@@ -40,4 +38,6 @@
     }
   }
   return newObject;
-};
+}
+
+export default clone;
\ No newline at end of file
diff --git a/lib/deps/docs/isDeleted.js b/src/deps/docs/isDeleted.js
similarity index 85%
rename from lib/deps/docs/isDeleted.js
rename to src/deps/docs/isDeleted.js
index 179f9f2..7c100b9 100644
--- a/lib/deps/docs/isDeleted.js
+++ b/src/deps/docs/isDeleted.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var winningRev = require('../../deps/merge/winningRev');
+import winningRev from '../../deps/merge/winningRev';
 
 function getTrees(node) {
   return node.ids;
@@ -25,4 +23,4 @@
   }
 }
 
-module.exports = isDeleted;
\ No newline at end of file
+export default isDeleted;
\ No newline at end of file
diff --git a/src/deps/docs/isLocalId.js b/src/deps/docs/isLocalId.js
new file mode 100644
index 0000000..d55afd8
--- /dev/null
+++ b/src/deps/docs/isLocalId.js
@@ -0,0 +1,5 @@
+function isLocalId(id) {
+  return (/^_local/).test(id);
+}
+
+export default isLocalId;
\ No newline at end of file
diff --git a/src/deps/docs/normalizeDdocFunctionName.js b/src/deps/docs/normalizeDdocFunctionName.js
new file mode 100644
index 0000000..b0a6ce5
--- /dev/null
+++ b/src/deps/docs/normalizeDdocFunctionName.js
@@ -0,0 +1,8 @@
+import parseDdocFunctionName from './parseDdocFunctionName';
+
+function normalizeDesignDocFunctionName(s) {
+  var normalized = parseDdocFunctionName(s);
+  return normalized ? normalized.join('/') : null;
+}
+
+export default normalizeDesignDocFunctionName;
\ No newline at end of file
diff --git a/lib/deps/docs/parseDdocFunctionName.js b/src/deps/docs/parseDdocFunctionName.js
similarity index 67%
rename from lib/deps/docs/parseDdocFunctionName.js
rename to src/deps/docs/parseDdocFunctionName.js
index 2b4f850..e9ccac2 100644
--- a/lib/deps/docs/parseDdocFunctionName.js
+++ b/src/deps/docs/parseDdocFunctionName.js
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = function parseDesignDocFunctionName(s) {
+function parseDesignDocFunctionName(s) {
   if (!s) {
     return null;
   }
@@ -12,4 +10,6 @@
     return [s, s];
   }
   return null;
-};
\ No newline at end of file
+}
+
+export default parseDesignDocFunctionName;
\ No newline at end of file
diff --git a/lib/deps/docs/parseDoc.js b/src/deps/docs/parseDoc.js
similarity index 86%
rename from lib/deps/docs/parseDoc.js
rename to src/deps/docs/parseDoc.js
index 351cefa..6c89f72 100644
--- a/lib/deps/docs/parseDoc.js
+++ b/src/deps/docs/parseDoc.js
@@ -1,7 +1,13 @@
-'use strict';
+import uuid from './../uuid';
 
-var errors = require('./../errors');
-var uuid = require('./../uuid');
+import {
+  INVALID_ID,
+  MISSING_ID,
+  RESERVED_ID,
+  DOC_VALIDATION,
+  INVALID_REV,
+  createError
+} from '../../deps/errors';
 
 function toObject(array) {
   return array.reduce(function (obj, item) {
@@ -47,23 +53,23 @@
 //     '_local'
 //   - any other string value is a valid id
 // Returns the specific error object for each case
-exports.invalidIdError = function (id) {
+function invalidIdError(id) {
   var err;
   if (!id) {
-    err = errors.error(errors.MISSING_ID);
+    err = createError(MISSING_ID);
   } else if (typeof id !== 'string') {
-    err = errors.error(errors.INVALID_ID);
+    err = createError(INVALID_ID);
   } else if (/^_/.test(id) && !(/^_(design|local)/).test(id)) {
-    err = errors.error(errors.RESERVED_ID);
+    err = createError(RESERVED_ID);
   }
   if (err) {
     throw err;
   }
-};
+}
 
 function parseRevisionInfo(rev) {
   if (!/^\d+\-./.test(rev)) {
-    return errors.error(errors.INVALID_REV);
+    return createError(INVALID_REV);
   }
   var idx = rev.indexOf('-');
   var left = rev.substring(0, idx);
@@ -92,7 +98,7 @@
 
 // Preprocess documents, parse their revisions, assign an id and a
 // revision for new writes that are missing them, etc
-exports.parseDoc = function (doc, newEdits) {
+function parseDoc(doc, newEdits) {
 
   var nRevNum;
   var newRevId;
@@ -144,7 +150,7 @@
     }
   }
 
-  exports.invalidIdError(doc._id);
+  invalidIdError(doc._id);
 
   doc._rev = nRevNum + '-' + newRevId;
 
@@ -154,8 +160,8 @@
     if (Object.prototype.hasOwnProperty.call(doc, key)) {
       var specialKey = key[0] === '_';
       if (specialKey && !reservedWords[key]) {
-        var error = errors.error(errors.DOC_VALIDATION, key);
-        error.message = errors.DOC_VALIDATION.message + ': ' + key;
+        var error = createError(DOC_VALIDATION, key);
+        error.message = DOC_VALIDATION.message + ': ' + key;
         throw error;
       } else if (specialKey && !dataWords[key]) {
         result.metadata[key.slice(1)] = doc[key];
@@ -165,4 +171,9 @@
     }
   }
   return result;
-};
+}
+
+export {
+  invalidIdError,
+  parseDoc
+};
\ No newline at end of file
diff --git a/lib/deps/docs/preprocessAttachments.js b/src/deps/docs/preprocessAttachments.js
similarity index 79%
rename from lib/deps/docs/preprocessAttachments.js
rename to src/deps/docs/preprocessAttachments.js
index ebabc6d..6ac9a78 100644
--- a/lib/deps/docs/preprocessAttachments.js
+++ b/src/deps/docs/preprocessAttachments.js
@@ -1,11 +1,9 @@
-'use strict';
-
-var base64 = require('../binary/base64');
-var arrayBuffToBinString = require('../binary/arrayBufferToBinaryString');
-var readAsArrayBuffer = require('../binary/readAsArrayBuffer');
-var binStringToBlobOrBuffer = require('../binary/binaryStringToBlobOrBuffer');
-var errors = require('../errors');
-var md5 = require('../md5');
+import { atob, btoa } from '../binary/base64';
+import arrayBuffToBinString from '../binary/arrayBufferToBinaryString';
+import readAsArrayBuffer from '../binary/readAsArrayBuffer';
+import binStringToBlobOrBuffer from '../binary/binaryStringToBlobOrBuffer';
+import { createError, BAD_ARG } from '../errors';
+import md5 from '../md5';
 
 function preprocessAttachments(docInfos, blobType, callback) {
 
@@ -17,9 +15,9 @@
 
   function parseBase64(data) {
     try {
-      return base64.atob(data);
+      return atob(data);
     } catch (e) {
-      var err = errors.error(errors.BAD_ARG,
+      var err = createError(BAD_ARG,
         'Attachment is not a valid base64 string');
       return {error: err};
     }
@@ -41,7 +39,7 @@
       if (blobType === 'blob') {
         att.data = binStringToBlobOrBuffer(asBinary, att.content_type);
       } else if (blobType === 'base64') {
-        att.data = base64.btoa(asBinary);
+        att.data = btoa(asBinary);
       } else { // binary
         att.data = asBinary;
       }
@@ -54,7 +52,7 @@
         if (blobType === 'binary') {
           att.data = arrayBuffToBinString(buff);
         } else if (blobType === 'base64') {
-          att.data = base64.btoa(arrayBuffToBinString(buff));
+          att.data = btoa(arrayBuffToBinString(buff));
         }
         md5(buff).then(function (result) {
           att.digest = 'md5-' + result;
@@ -104,4 +102,4 @@
   }
 }
 
-module.exports = preprocessAttachments;
\ No newline at end of file
+export default preprocessAttachments;
\ No newline at end of file
diff --git a/lib/deps/docs/processDocs.js b/src/deps/docs/processDocs.js
similarity index 82%
rename from lib/deps/docs/processDocs.js
rename to src/deps/docs/processDocs.js
index cb667b4..1a143e9 100644
--- a/lib/deps/docs/processDocs.js
+++ b/src/deps/docs/processDocs.js
@@ -1,13 +1,10 @@
-'use strict';
-
-var errors = require('../errors');
-var updateDoc = require('./updateDoc');
-var isDeleted = require('./isDeleted');
-var isLocalId = require('./isLocalId');
-var calculateWinningRev = require('../../deps/merge/winningRev');
-var merge = require('../../deps/merge');
-var collections = require('pouchdb-collections');
-var Map = collections.Map;
+import { createError, MISSING_DOC } from '../errors';
+import updateDoc from './updateDoc';
+import isDeleted from './isDeleted';
+import isLocalId from './isLocalId';
+import calculateWinningRev from '../../deps/merge/winningRev';
+import merge from '../../deps/merge/index';
+import collections from 'pouchdb-collections';
 
 function processDocs(revLimit, docInfos, api, fetchedDocs, tx, results,
                      writeDoc, opts, overallCallback) {
@@ -20,7 +17,7 @@
     var winningRev = calculateWinningRev(docInfo.metadata);
     var deleted = isDeleted(docInfo.metadata, winningRev);
     if ('was_delete' in opts && deleted) {
-      results[resultsIdx] = errors.error(errors.MISSING_DOC, 'deleted');
+      results[resultsIdx] = createError(MISSING_DOC, 'deleted');
       return callback();
     }
 
@@ -31,7 +28,7 @@
   }
 
   var newEdits = opts.new_edits;
-  var idsToDocs = new Map();
+  var idsToDocs = new collections.Map();
 
   var docsDone = 0;
   var docsToDo = docInfos.length;
@@ -93,4 +90,4 @@
   });
 }
 
-module.exports = processDocs;
+export default processDocs;
diff --git a/lib/deps/docs/updateDoc.js b/src/deps/docs/updateDoc.js
similarity index 85%
rename from lib/deps/docs/updateDoc.js
rename to src/deps/docs/updateDoc.js
index d0a4315..030e5db 100644
--- a/lib/deps/docs/updateDoc.js
+++ b/src/deps/docs/updateDoc.js
@@ -1,11 +1,9 @@
-'use strict';
-
-var errors = require('../errors');
-var isDeleted = require('./isDeleted');
-var parseDoc = require('./parseDoc').parseDoc;
-var calculateWinningRev = require('../../deps/merge/winningRev');
-var merge = require('../../deps/merge');
-var revExists = require('../../deps/merge/revExists');
+import { createError, REV_CONFLICT } from '../errors';
+import isDeleted from './isDeleted';
+import { parseDoc as parseDoc } from './parseDoc';
+import calculateWinningRev from '../../deps/merge/winningRev';
+import merge from '../../deps/merge/index';
+import revExists from '../../deps/merge/revExists';
 
 function updateDoc(revLimit, prev, docInfo, results,
                    i, cb, writeDoc, newEdits) {
@@ -37,7 +35,7 @@
     (previouslyDeleted && !deleted && merged.conflicts === 'new_branch')));
 
   if (inConflict) {
-    var err = errors.error(errors.REV_CONFLICT);
+    var err = createError(REV_CONFLICT);
     results[i] = err;
     return cb();
   }
@@ -71,4 +69,4 @@
     true, delta, i, cb);
 }
 
-module.exports = updateDoc;
+export default updateDoc;
diff --git a/lib/deps/env/hasLocalStorage-browser.js b/src/deps/env/hasLocalStorage-browser.js
similarity index 71%
rename from lib/deps/env/hasLocalStorage-browser.js
rename to src/deps/env/hasLocalStorage-browser.js
index 96d4228..e83bbbd 100644
--- a/lib/deps/env/hasLocalStorage-browser.js
+++ b/src/deps/env/hasLocalStorage-browser.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var isChromeApp = require('./isChromeApp');
+import isChromeApp from './isChromeApp';
 
 var hasLocal;
 
@@ -15,6 +13,8 @@
   }
 }
 
-module.exports = function hasLocalStorage() {
+function hasLocalStorage() {
   return hasLocal;
-};
\ No newline at end of file
+}
+
+export default hasLocalStorage;
\ No newline at end of file
diff --git a/src/deps/env/hasLocalStorage.js b/src/deps/env/hasLocalStorage.js
new file mode 100644
index 0000000..4460fb9
--- /dev/null
+++ b/src/deps/env/hasLocalStorage.js
@@ -0,0 +1,6 @@
+// in Node of course this is false
+function hasLocalStorage() {
+  return false;
+}
+
+export default hasLocalStorage;
\ No newline at end of file
diff --git a/lib/deps/env/isChromeApp-browser.js b/src/deps/env/isChromeApp-browser.js
similarity index 70%
rename from lib/deps/env/isChromeApp-browser.js
rename to src/deps/env/isChromeApp-browser.js
index dff2cd9..60cf319 100644
--- a/lib/deps/env/isChromeApp-browser.js
+++ b/src/deps/env/isChromeApp-browser.js
@@ -1,7 +1,7 @@
-'use strict';
-
-module.exports = function isChromeApp() {
+function isChromeApp() {
   return (typeof chrome !== "undefined" &&
     typeof chrome.storage !== "undefined" &&
     typeof chrome.storage.local !== "undefined");
-};
\ No newline at end of file
+}
+
+export default isChromeApp;
\ No newline at end of file
diff --git a/src/deps/env/isChromeApp.js b/src/deps/env/isChromeApp.js
new file mode 100644
index 0000000..acc41b2
--- /dev/null
+++ b/src/deps/env/isChromeApp.js
@@ -0,0 +1,6 @@
+// in Node of course this is false
+function isChromeApp() {
+  return false;
+}
+
+export default isChromeApp;
\ No newline at end of file
diff --git a/lib/deps/errors.js b/src/deps/errors.js
similarity index 62%
rename from lib/deps/errors.js
rename to src/deps/errors.js
index c40ed79..fc8a52b 100644
--- a/lib/deps/errors.js
+++ b/src/deps/errors.js
@@ -1,6 +1,4 @@
-"use strict";
-
-var inherits = require('inherits');
+import inherits from 'inherits';
 inherits(PouchError, Error);
 
 function PouchError(opts) {
@@ -20,150 +18,177 @@
   });
 };
 
-exports.UNAUTHORIZED = new PouchError({
+var UNAUTHORIZED = new PouchError({
   status: 401,
   error: 'unauthorized',
   reason: "Name or password is incorrect."
 });
 
-exports.MISSING_BULK_DOCS = new PouchError({
+var MISSING_BULK_DOCS = new PouchError({
   status: 400,
   error: 'bad_request',
   reason: "Missing JSON list of 'docs'"
 });
 
-exports.MISSING_DOC = new PouchError({
+var MISSING_DOC = new PouchError({
   status: 404,
   error: 'not_found',
   reason: 'missing'
 });
 
-exports.REV_CONFLICT = new PouchError({
+var REV_CONFLICT = new PouchError({
   status: 409,
   error: 'conflict',
   reason: 'Document update conflict'
 });
 
-exports.INVALID_ID = new PouchError({
+var INVALID_ID = new PouchError({
   status: 400,
   error: 'invalid_id',
   reason: '_id field must contain a string'
 });
 
-exports.MISSING_ID = new PouchError({
+var MISSING_ID = new PouchError({
   status: 412,
   error: 'missing_id',
   reason: '_id is required for puts'
 });
 
-exports.RESERVED_ID = new PouchError({
+var RESERVED_ID = new PouchError({
   status: 400,
   error: 'bad_request',
   reason: 'Only reserved document ids may start with underscore.'
 });
 
-exports.NOT_OPEN = new PouchError({
+var NOT_OPEN = new PouchError({
   status: 412,
   error: 'precondition_failed',
   reason: 'Database not open'
 });
 
-exports.UNKNOWN_ERROR = new PouchError({
+var UNKNOWN_ERROR = new PouchError({
   status: 500,
   error: 'unknown_error',
   reason: 'Database encountered an unknown error'
 });
 
-exports.BAD_ARG = new PouchError({
+var BAD_ARG = new PouchError({
   status: 500,
   error: 'badarg',
   reason: 'Some query argument is invalid'
 });
 
-exports.INVALID_REQUEST = new PouchError({
+var INVALID_REQUEST = new PouchError({
   status: 400,
   error: 'invalid_request',
   reason: 'Request was invalid'
 });
 
-exports.QUERY_PARSE_ERROR = new PouchError({
+var QUERY_PARSE_ERROR = new PouchError({
   status: 400,
   error: 'query_parse_error',
   reason: 'Some query parameter is invalid'
 });
 
-exports.DOC_VALIDATION = new PouchError({
+var DOC_VALIDATION = new PouchError({
   status: 500,
   error: 'doc_validation',
   reason: 'Bad special document member'
 });
 
-exports.BAD_REQUEST = new PouchError({
+var BAD_REQUEST = new PouchError({
   status: 400,
   error: 'bad_request',
   reason: 'Something wrong with the request'
 });
 
-exports.NOT_AN_OBJECT = new PouchError({
+var NOT_AN_OBJECT = new PouchError({
   status: 400,
   error: 'bad_request',
   reason: 'Document must be a JSON object'
 });
 
-exports.DB_MISSING = new PouchError({
+var DB_MISSING = new PouchError({
   status: 404,
   error: 'not_found',
   reason: 'Database not found'
 });
 
-exports.IDB_ERROR = new PouchError({
+var IDB_ERROR = new PouchError({
   status: 500,
   error: 'indexed_db_went_bad',
   reason: 'unknown'
 });
 
-exports.WSQ_ERROR = new PouchError({
+var WSQ_ERROR = new PouchError({
   status: 500,
   error: 'web_sql_went_bad',
   reason: 'unknown'
 });
 
-exports.LDB_ERROR = new PouchError({
+var LDB_ERROR = new PouchError({
   status: 500,
   error: 'levelDB_went_went_bad',
   reason: 'unknown'
 });
 
-exports.FORBIDDEN = new PouchError({
+var FORBIDDEN = new PouchError({
   status: 403,
   error: 'forbidden',
   reason: 'Forbidden by design doc validate_doc_update function'
 });
 
-exports.INVALID_REV = new PouchError({
+var INVALID_REV = new PouchError({
   status: 400,
   error: 'bad_request',
   reason: 'Invalid rev format'
 });
 
-exports.FILE_EXISTS = new PouchError({
+var FILE_EXISTS = new PouchError({
   status: 412,
   error: 'file_exists',
   reason: 'The database could not be created, the file already exists.'
 });
 
-exports.MISSING_STUB = new PouchError({
+var MISSING_STUB = new PouchError({
   status: 412,
   error: 'missing_stub'
 });
 
-exports.INVALID_URL = new PouchError({
+var INVALID_URL = new PouchError({
   status: 413,
   error: 'invalid_url',
   reason: 'Provided URL is invalid'
 });
 
-exports.error = function (error, reason, name) {
+var allErrors = {
+  UNAUTHORIZED: UNAUTHORIZED,
+  MISSING_BULK_DOCS: MISSING_BULK_DOCS,
+  MISSING_DOC: MISSING_DOC,
+  REV_CONFLICT: REV_CONFLICT,
+  INVALID_ID: INVALID_ID,
+  MISSING_ID: MISSING_ID,
+  RESERVED_ID: RESERVED_ID,
+  NOT_OPEN: NOT_OPEN,
+  UNKNOWN_ERROR: UNKNOWN_ERROR,
+  BAD_ARG: BAD_ARG,
+  INVALID_REQUEST: INVALID_REQUEST,
+  QUERY_PARSE_ERROR: QUERY_PARSE_ERROR,
+  DOC_VALIDATION: DOC_VALIDATION,
+  BAD_REQUEST: BAD_REQUEST,
+  NOT_AN_OBJECT: NOT_AN_OBJECT,
+  DB_MISSING: DB_MISSING,
+  WSQ_ERROR: WSQ_ERROR,
+  LDB_ERROR: LDB_ERROR,
+  FORBIDDEN: FORBIDDEN,
+  INVALID_REV: INVALID_REV,
+  FILE_EXISTS: FILE_EXISTS,
+  MISSING_STUB: MISSING_STUB,
+  IDB_ERROR: IDB_ERROR,
+  INVALID_URL: INVALID_URL
+};
+
+function createError(error, reason, name) {
   function CustomPouchError(reason) {
     // inherit error properties from our parent error manually
     // so as to allow proper JSON parsing.
@@ -183,59 +208,57 @@
   }
   CustomPouchError.prototype = PouchError.prototype;
   return new CustomPouchError(reason);
-};
+}
 
 // Find one of the errors defined above based on the value
 // of the specified property.
 // If reason is provided prefer the error matching that reason.
 // This is for differentiating between errors with the same name and status,
 // eg, bad_request.
-exports.getErrorTypeByProp = function (prop, value, reason) {
-  var errors = exports;
-  var keys = Object.keys(errors).filter(function (key) {
-    var error = errors[key];
+var getErrorTypeByProp = function (prop, value, reason) {
+  var keys = Object.keys(allErrors).filter(function (key) {
+    var error = allErrors[key];
     return typeof error !== 'function' && error[prop] === value;
   });
   var key = reason && keys.filter(function (key) {
-        var error = errors[key];
+        var error = allErrors[key];
         return error.message === reason;
       })[0] || keys[0];
-  return (key) ? errors[key] : null;
+  return (key) ? allErrors[key] : null;
 };
 
-exports.generateErrorFromResponse = function (res) {
+function generateErrorFromResponse(res) {
   var error, errName, errType, errMsg, errReason;
-  var errors = exports;
 
   errName = (res.error === true && typeof res.name === 'string') ?
               res.name :
               res.error;
   errReason = res.reason;
-  errType = errors.getErrorTypeByProp('name', errName, errReason);
+  errType = getErrorTypeByProp('name', errName, errReason);
 
   if (res.missing ||
       errReason === 'missing' ||
       errReason === 'deleted' ||
       errName === 'not_found') {
-    errType = errors.MISSING_DOC;
+    errType = MISSING_DOC;
   } else if (errName === 'doc_validation') {
     // doc validation needs special treatment since
     // res.reason depends on the validation error.
     // see utils.js
-    errType = errors.DOC_VALIDATION;
+    errType = DOC_VALIDATION;
     errMsg = errReason;
   } else if (errName === 'bad_request' && errType.message !== errReason) {
     // if bad_request error already found based on reason don't override.
-    errType = errors.BAD_REQUEST;
+    errType = BAD_REQUEST;
   }
 
   // fallback to error by status or unknown error.
   if (!errType) {
-    errType = errors.getErrorTypeByProp('status', res.status, errReason) ||
-                errors.UNKNOWN_ERROR;
+    errType = getErrorTypeByProp('status', res.status, errReason) ||
+                UNKNOWN_ERROR;
   }
 
-  error = errors.error(errType, errReason, errName);
+  error = createError(errType, errReason, errName);
 
   // Keep custom message.
   if (errMsg) {
@@ -254,4 +277,35 @@
   }
 
   return error;
-};
+}
+
+export {
+  UNAUTHORIZED,
+  MISSING_BULK_DOCS,
+  MISSING_DOC,
+  REV_CONFLICT,
+  INVALID_ID,
+  MISSING_ID,
+  RESERVED_ID,
+  NOT_OPEN,
+  UNKNOWN_ERROR,
+  BAD_ARG,
+  INVALID_REQUEST,
+  QUERY_PARSE_ERROR,
+  DOC_VALIDATION,
+  BAD_REQUEST,
+  NOT_AN_OBJECT,
+  DB_MISSING,
+  WSQ_ERROR,
+  LDB_ERROR,
+  FORBIDDEN,
+  INVALID_REV,
+  FILE_EXISTS,
+  MISSING_STUB,
+  IDB_ERROR,
+  INVALID_URL,
+  getErrorTypeByProp,
+  createError,
+  generateErrorFromResponse,
+  allErrors as errors
+};
\ No newline at end of file
diff --git a/lib/deps/extend.js b/src/deps/extend.js
similarity index 76%
rename from lib/deps/extend.js
rename to src/deps/extend.js
index a192a47..220c818 100644
--- a/lib/deps/extend.js
+++ b/src/deps/extend.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var clone = require('./clone');
+import clone from './clone';
 
 function extendInner(obj, otherObj) {
   for (var key in otherObj) {
@@ -13,10 +11,12 @@
   }
 }
 
-module.exports = function extend(obj, obj2, obj3) {
+function extend(obj, obj2, obj3) {
   extendInner(obj, obj2);
   if (obj3) {
     extendInner(obj, obj3);
   }
   return obj;
-};
\ No newline at end of file
+}
+
+export default extend;
\ No newline at end of file
diff --git a/lib/deps/filterChange.js b/src/deps/filterChange.js
similarity index 86%
rename from lib/deps/filterChange.js
rename to src/deps/filterChange.js
index b652275..07fd7c8 100644
--- a/lib/deps/filterChange.js
+++ b/src/deps/filterChange.js
@@ -1,17 +1,15 @@
-'use strict';
-
-var errors = require('./errors');
+import { createError, BAD_REQUEST } from './errors';
 
 function tryFilter(filter, doc, req) {
   try {
     return !filter(doc, req);
   } catch (err) {
     var msg = 'Filter function threw: ' + err.toString();
-    return errors.error(errors.BAD_REQUEST, msg);
+    return createError(BAD_REQUEST, msg);
   }
 }
 
-module.exports = function filterChange(opts) {
+function filterChange(opts) {
   var req = {};
   var hasFilter = opts.filter && typeof opts.filter === 'function';
   req.query = opts.query_params;
@@ -45,4 +43,6 @@
     }
     return true;
   };
-};
\ No newline at end of file
+}
+
+export default filterChange;
\ No newline at end of file
diff --git a/lib/deps/flatten.js b/src/deps/flatten.js
similarity index 66%
rename from lib/deps/flatten.js
rename to src/deps/flatten.js
index dd5b3f7..16ff98c 100644
--- a/lib/deps/flatten.js
+++ b/src/deps/flatten.js
@@ -1,9 +1,9 @@
-'use strict';
-
-module.exports = function flatten(arrs) {
+function flatten(arrs) {
   var res = [];
   for (var i = 0, len = arrs.length; i < len; i++) {
     res = res.concat(arrs[i]);
   }
   return res;
-};
+}
+
+export default flatten;
\ No newline at end of file
diff --git a/lib/deps/functionName.js b/src/deps/functionName.js
similarity index 65%
rename from lib/deps/functionName.js
rename to src/deps/functionName.js
index cdf7863..376cde5 100644
--- a/lib/deps/functionName.js
+++ b/src/deps/functionName.js
@@ -1,16 +1,19 @@
-'use strict';
-
 // shim for Function.prototype.name,
 // for browsers that don't support it like IE
 
+var hasName = (function f() {}).name;
+var res;
+
 // We dont run coverage in IE
 /* istanbul ignore else */
-if ((function f() {}).name) {
-  module.exports = function (fun) {
+if (hasName) {
+  res = function (fun) {
     return fun.name;
   };
 } else {
-  module.exports = function (fun) {
+  res = function (fun) {
     return fun.toString().match(/^\s*function\s*(\S*)\s*\(/)[1];
   };
 }
+
+export default res;
diff --git a/lib/deps/isCordova.js b/src/deps/isCordova.js
similarity index 67%
rename from lib/deps/isCordova.js
rename to src/deps/isCordova.js
index 0cfa3fb..48dada2 100644
--- a/lib/deps/isCordova.js
+++ b/src/deps/isCordova.js
@@ -1,7 +1,7 @@
-'use strict';
-
-module.exports = function isCordova() {
+function isCordova() {
   return (typeof cordova !== "undefined" ||
   typeof PhoneGap !== "undefined" ||
   typeof phonegap !== "undefined");
-};
\ No newline at end of file
+}
+
+export default isCordova;
\ No newline at end of file
diff --git a/lib/deps/md5-browser.js b/src/deps/md5-browser.js
similarity index 86%
rename from lib/deps/md5-browser.js
rename to src/deps/md5-browser.js
index 888190b..2a3352b 100644
--- a/lib/deps/md5-browser.js
+++ b/src/deps/md5-browser.js
@@ -1,13 +1,11 @@
-'use strict';
-
-var toPromise = require('./toPromise');
-var base64 = require('./binary/base64');
-var Md5 = require('spark-md5');
+import toPromise from './toPromise';
+import { btoa } from './binary/base64';
+import Md5 from 'spark-md5';
 var setImmediateShim = global.setImmediate || global.setTimeout;
 var MD5_CHUNK_SIZE = 32768;
 
 function rawToBase64(raw) {
-  return base64.btoa(raw);
+  return btoa(raw);
 }
 
 function appendBuffer(buffer, data, start, end) {
@@ -27,7 +25,7 @@
   buffer.appendBinary(data);
 }
 
-module.exports = toPromise(function (data, callback) {
+var md5 = toPromise(function (data, callback) {
   var inputIsString = typeof data === 'string';
   var len = inputIsString ? data.length : data.byteLength;
   var chunkSize = Math.min(MD5_CHUNK_SIZE, len);
@@ -54,3 +52,5 @@
   }
   loadNextChunk();
 });
+
+export default md5;
\ No newline at end of file
diff --git a/src/deps/md5.js b/src/deps/md5.js
new file mode 100644
index 0000000..6646004
--- /dev/null
+++ b/src/deps/md5.js
@@ -0,0 +1,9 @@
+import toPromise from './toPromise';
+import crypto from 'crypto';
+
+var res = toPromise(function (data, callback) {
+  var base64 = crypto.createHash('md5').update(data).digest('base64');
+  callback(null, base64);
+});
+
+export default res;
\ No newline at end of file
diff --git a/lib/deps/merge/collectConflicts.js b/src/deps/merge/collectConflicts.js
similarity index 72%
rename from lib/deps/merge/collectConflicts.js
rename to src/deps/merge/collectConflicts.js
index 6f58c0d..6daf9f3 100644
--- a/lib/deps/merge/collectConflicts.js
+++ b/src/deps/merge/collectConflicts.js
@@ -1,12 +1,10 @@
-'use strict';
-
-var winningRev = require('./winningRev');
-var collectLeaves = require('./collectLeaves');
+import winningRev from './winningRev';
+import collectLeaves from './collectLeaves';
 
 // returns revs of all conflicts that is leaves such that
 // 1. are not deleted and
 // 2. are different than winning revision
-module.exports = function collectConflicts(metadata) {
+function collectConflicts(metadata) {
   var win = winningRev(metadata);
   var leaves = collectLeaves(metadata.rev_tree);
   var conflicts = [];
@@ -17,4 +15,6 @@
     }
   }
   return conflicts;
-};
\ No newline at end of file
+}
+
+export default collectConflicts;
\ No newline at end of file
diff --git a/lib/deps/merge/collectLeaves.js b/src/deps/merge/collectLeaves.js
similarity index 76%
rename from lib/deps/merge/collectLeaves.js
rename to src/deps/merge/collectLeaves.js
index ada0cb0..520ed30 100644
--- a/lib/deps/merge/collectLeaves.js
+++ b/src/deps/merge/collectLeaves.js
@@ -1,12 +1,10 @@
-'use strict';
-
-var traverseRevTree = require('./traverseRevTree');
+import traverseRevTree from './traverseRevTree';
 
 function sortByPos(a, b) {
   return a.pos - b.pos;
 }
 
-module.exports = function collectLeaves(revs) {
+function collectLeaves(revs) {
   var leaves = [];
   traverseRevTree(revs, function (isLeaf, pos, id, acc, opts) {
     if (isLeaf) {
@@ -18,4 +16,6 @@
     delete leaves[i].pos;
   }
   return leaves;
-};
\ No newline at end of file
+}
+
+export default collectLeaves;
\ No newline at end of file
diff --git a/lib/deps/merge/compactTree.js b/src/deps/merge/compactTree.js
similarity index 76%
rename from lib/deps/merge/compactTree.js
rename to src/deps/merge/compactTree.js
index 529c2b1..885877a 100644
--- a/lib/deps/merge/compactTree.js
+++ b/src/deps/merge/compactTree.js
@@ -1,9 +1,7 @@
-'use strict';
-
-var traverseRevTree = require('./traverseRevTree');
+import traverseRevTree from './traverseRevTree';
 // compact a tree by marking its non-leafs as missing,
 // and return a list of revs to delete
-module.exports = function compactTree(metadata) {
+function compactTree(metadata) {
   var revs = [];
   traverseRevTree(metadata.rev_tree, function (isLeaf, pos,
                                                revHash, ctx, opts) {
@@ -13,4 +11,6 @@
     }
   });
   return revs;
-};
\ No newline at end of file
+}
+
+export default compactTree;
\ No newline at end of file
diff --git a/lib/deps/merge/index.js b/src/deps/merge/index.js
similarity index 97%
rename from lib/deps/merge/index.js
rename to src/deps/merge/index.js
index b9adafd..3a069c5 100644
--- a/lib/deps/merge/index.js
+++ b/src/deps/merge/index.js
@@ -1,5 +1,3 @@
-'use strict';
-
 // for a better overview of what this is doing, read:
 // https://github.com/apache/couchdb/blob/master/src/couchdb/couch_key_tree.erl
 //
@@ -11,7 +9,7 @@
 // Path = {pos: position_from_root, ids: Tree}
 // Tree = [Key, Opts, [Tree, ...]], in particular single node: [Key, []]
 
-var rootToLeaf = require('./rootToLeaf');
+import rootToLeaf from './rootToLeaf';
 
 function sortByPos(a, b) {
   return a.pos - b.pos;
@@ -209,10 +207,12 @@
   return result;
 }
 
-module.exports = function merge(tree, path, depth) {
+function merge(tree, path, depth) {
   var newTree = doMerge(tree, path);
   return {
     tree: stem(newTree.tree, depth),
     conflicts: newTree.conflicts
   };
-};
\ No newline at end of file
+}
+
+export default merge;
\ No newline at end of file
diff --git a/lib/deps/merge/revExists.js b/src/deps/merge/revExists.js
similarity index 88%
rename from lib/deps/merge/revExists.js
rename to src/deps/merge/revExists.js
index 0affe08..b25c1da 100644
--- a/lib/deps/merge/revExists.js
+++ b/src/deps/merge/revExists.js
@@ -1,7 +1,5 @@
-'use strict';
-
 // return true if a rev exists in the rev tree, false otherwise
-module.exports = function revExists(revs, rev) {
+function revExists(revs, rev) {
   var toVisit = revs.slice();
   var splitRev = rev.split('-');
   var targetPos = parseInt(splitRev[0], 10);
@@ -18,4 +16,6 @@
     }
   }
   return false;
-};
\ No newline at end of file
+}
+
+export default revExists;
\ No newline at end of file
diff --git a/lib/deps/merge/rootToLeaf.js b/src/deps/merge/rootToLeaf.js
similarity index 91%
rename from lib/deps/merge/rootToLeaf.js
rename to src/deps/merge/rootToLeaf.js
index e5f5f4e..d16f509 100644
--- a/lib/deps/merge/rootToLeaf.js
+++ b/src/deps/merge/rootToLeaf.js
@@ -1,6 +1,5 @@
-'use strict';
 // build up a list of all the paths to the leafs in this revision tree
-module.exports = function rootToLeaf(revs) {
+function rootToLeaf(revs) {
   var paths = [];
   var toVisit = revs.slice();
   var node;
@@ -22,4 +21,6 @@
     }
   }
   return paths.reverse();
-};
\ No newline at end of file
+}
+
+export default rootToLeaf;
\ No newline at end of file
diff --git a/lib/deps/merge/traverseRevTree.js b/src/deps/merge/traverseRevTree.js
similarity index 88%
rename from lib/deps/merge/traverseRevTree.js
rename to src/deps/merge/traverseRevTree.js
index 03f8937..ca42949 100644
--- a/lib/deps/merge/traverseRevTree.js
+++ b/src/deps/merge/traverseRevTree.js
@@ -1,10 +1,8 @@
-'use strict';
-
 // Pretty much all below can be combined into a higher order function to
 // traverse revisions
 // The return value from the callback will be passed as context to all
 // children of that node
-module.exports = function traverseRevTree(revs, callback) {
+function traverseRevTree(revs, callback) {
   var toVisit = revs.slice();
 
   var node;
@@ -18,4 +16,6 @@
       toVisit.push({pos: pos + 1, ids: branches[i], ctx: newCtx});
     }
   }
-};
\ No newline at end of file
+}
+
+export default traverseRevTree;
\ No newline at end of file
diff --git a/lib/deps/merge/winningRev.js b/src/deps/merge/winningRev.js
similarity index 94%
rename from lib/deps/merge/winningRev.js
rename to src/deps/merge/winningRev.js
index 2f5959d..6b5744a 100644
--- a/lib/deps/merge/winningRev.js
+++ b/src/deps/merge/winningRev.js
@@ -1,11 +1,9 @@
-'use strict';
-
 // We fetch all leafs of the revision tree, and sort them based on tree length
 // and whether they were deleted, undeleted documents with the longest revision
 // tree (most edits) win
 // The final sort algorithm is slightly documented in a sidebar here:
 // http://guide.couchdb.org/draft/conflicts.html
-module.exports = function winningRev(metadata) {
+function winningRev(metadata) {
   var winningId;
   var winningPos;
   var winningDeleted;
@@ -33,4 +31,6 @@
   }
 
   return winningPos + '-' + winningId;
-};
\ No newline at end of file
+}
+
+export default winningRev;
\ No newline at end of file
diff --git a/src/deps/migrate-browser.js b/src/deps/migrate-browser.js
new file mode 100644
index 0000000..bd5f071
--- /dev/null
+++ b/src/deps/migrate-browser.js
@@ -0,0 +1,18 @@
+// in the browser, LevelAlt doesn't need the
+// pre-2.2.0 LevelDB-specific migrations
+var toSublevel = function (name, db, callback) {
+  process.nextTick(function () {
+    callback();
+  });
+};
+
+var localAndMetaStores = function (db, stores, callback) {
+  process.nextTick(function () {
+    callback();
+  });
+};
+
+export default {
+  toSublevel: toSublevel,
+  localAndMetaStores: localAndMetaStores
+};
diff --git a/lib/deps/migrate.js b/src/deps/migrate.js
similarity index 90%
rename from lib/deps/migrate.js
rename to src/deps/migrate.js
index 1b0e78a..6dee1db 100644
--- a/lib/deps/migrate.js
+++ b/src/deps/migrate.js
@@ -1,12 +1,10 @@
-'use strict';
-
-var fs = require('fs');
-var path = require('path');
-var isLocalId = require('./docs/isLocalId');
-var winningRev = require('../deps/merge/winningRev');
-var levelup = require('levelup');
-var through = require('through2').obj;
-var LevelWriteStream = require("level-write-stream");
+import fs from 'fs';
+import path from 'path';
+import isLocalId from './docs/isLocalId';
+import winningRev from '../deps/merge/winningRev';
+import levelup from 'levelup';
+import { obj as through } from 'through2';
+import LevelWriteStream from "level-write-stream";
 
 var stores = [
   'document-store',
@@ -21,7 +19,7 @@
 var DOC_COUNT_KEY = '_local_doc_count';
 var UUID_KEY = '_local_uuid';
 
-exports.toSublevel = function (name, db, callback) {
+var toSublevel = function (name, db, callback) {
   // local require to prevent crashing if leveldown isn't installed.
   var leveldown = require("leveldown");
 
@@ -76,7 +74,7 @@
     });
   });
 };
-exports.localAndMetaStores = function (db, stores, callback) {
+var localAndMetaStores = function (db, stores, callback) {
   var batches = [];
   stores.bySeqStore.get(UUID_KEY, function (err, value) {
     if (err) {
@@ -190,3 +188,8 @@
   });
 
 };
+
+export default {
+  toSublevel: toSublevel,
+  localAndMetaStores: localAndMetaStores
+};
diff --git a/lib/deps/once.js b/src/deps/once.js
similarity index 80%
rename from lib/deps/once.js
rename to src/deps/once.js
index f64ed70..b2d9c5b 100644
--- a/lib/deps/once.js
+++ b/src/deps/once.js
@@ -1,6 +1,4 @@
-'use strict';
-
-var getArguments = require('argsarray');
+import getArguments from 'argsarray';
 
 function once(fun) {
   var called = false;
@@ -16,4 +14,4 @@
   });
 }
 
-module.exports = once;
\ No newline at end of file
+export default once;
\ No newline at end of file
diff --git a/lib/deps/parseHex.js b/src/deps/parseHex.js
similarity index 96%
rename from lib/deps/parseHex.js
rename to src/deps/parseHex.js
index 4812a39..0e74425 100644
--- a/lib/deps/parseHex.js
+++ b/src/deps/parseHex.js
@@ -1,5 +1,3 @@
-'use strict';
-
 //
 // Parsing hex strings. Yeah.
 //
@@ -64,4 +62,4 @@
   }
 }
 
-module.exports = parseHexString;
\ No newline at end of file
+export default parseHexString;
\ No newline at end of file
diff --git a/lib/deps/parseUri.js b/src/deps/parseUri.js
similarity index 95%
rename from lib/deps/parseUri.js
rename to src/deps/parseUri.js
index cbe0437..d8d4711 100644
--- a/lib/deps/parseUri.js
+++ b/src/deps/parseUri.js
@@ -1,5 +1,3 @@
-'use strict';
-
 // originally parseUri 1.2.2, now patched by us
 // (c) Steven Levithan <stevenlevithan.com>
 // MIT License
@@ -34,4 +32,4 @@
   return uri;
 }
 
-module.exports = parseUri;
\ No newline at end of file
+export default parseUri;
\ No newline at end of file
diff --git a/lib/deps/pick.js b/src/deps/pick.js
similarity index 77%
rename from lib/deps/pick.js
rename to src/deps/pick.js
index 17a5ecd..192e593 100644
--- a/lib/deps/pick.js
+++ b/src/deps/pick.js
@@ -1,7 +1,5 @@
-'use strict';
-
 // like underscore/lodash _.pick()
-module.exports = function pick(obj, arr) {
+function pick(obj, arr) {
   var res = {};
   for (var i = 0, len = arr.length; i < len; i++) {
     var prop = arr[i];
@@ -10,4 +8,6 @@
     }
   }
   return res;
-};
\ No newline at end of file
+}
+
+export default pick;
\ No newline at end of file
diff --git a/src/deps/promise.js b/src/deps/promise.js
new file mode 100644
index 0000000..75e1f3d
--- /dev/null
+++ b/src/deps/promise.js
@@ -0,0 +1,5 @@
+import lie from 'lie';
+/* istanbul ignore next */
+var PouchPromise = typeof Promise === 'function' ? Promise : lie;
+
+export default PouchPromise;
diff --git a/src/deps/safeJsonParse.js b/src/deps/safeJsonParse.js
new file mode 100644
index 0000000..ee0de96
--- /dev/null
+++ b/src/deps/safeJsonParse.js
@@ -0,0 +1,12 @@
+import vuvuzela from 'vuvuzela';
+
+function safeJsonParse(str) {
+  try {
+    return JSON.parse(str);
+  } catch (e) {
+    /* istanbul ignore next */
+    return vuvuzela.parse(str);
+  }
+}
+
+export default safeJsonParse;
\ No newline at end of file
diff --git a/src/deps/safeJsonStringify.js b/src/deps/safeJsonStringify.js
new file mode 100644
index 0000000..44a81f3
--- /dev/null
+++ b/src/deps/safeJsonStringify.js
@@ -0,0 +1,12 @@
+import vuvuzela from 'vuvuzela';
+
+function safeJsonStringify(json) {
+  try {
+    return JSON.stringify(json);
+  } catch (e) {
+    /* istanbul ignore next */
+    return vuvuzela.stringify(json);
+  }
+}
+
+export default safeJsonStringify;
\ No newline at end of file
diff --git a/lib/deps/toPromise.js b/src/deps/toPromise.js
similarity index 88%
rename from lib/deps/toPromise.js
rename to src/deps/toPromise.js
index 3657d5e..bfb8aaa 100644
--- a/lib/deps/toPromise.js
+++ b/src/deps/toPromise.js
@@ -1,9 +1,7 @@
-'use strict';
-
-var Promise = require('./promise');
-var getArguments = require('argsarray');
-var clone = require('./clone');
-var once = require('./once');
+import Promise from './promise';
+import getArguments from 'argsarray';
+import clone from './clone';
+import once from './once';
 
 function toPromise(func) {
   //create the function we will be returning
@@ -55,4 +53,4 @@
   });
 }
 
-module.exports = toPromise;
+export default toPromise;
diff --git a/lib/deps/upsert.js b/src/deps/upsert.js
similarity index 90%
rename from lib/deps/upsert.js
rename to src/deps/upsert.js
index ccfde7c..4eb96bf 100644
--- a/lib/deps/upsert.js
+++ b/src/deps/upsert.js
@@ -1,11 +1,9 @@
-'use strict';
-
-var Promise = require('./promise');
+import Promise from './promise';
 
 // this is essentially the "update sugar" function from daleharvey/pouchdb#1388
 // the diffFun tells us what delta to apply to the doc.  it either returns
 // the doc, or false if it doesn't need to do an update after all
-var upsert = module.exports = function upsert(db, docId, diffFun) {
+function upsert(db, docId, diffFun) {
   return new Promise(function (fulfill, reject) {
     db.get(docId, function (err, doc) {
       if (err) {
@@ -33,7 +31,7 @@
       fulfill(tryAndPut(db, newDoc, diffFun));
     });
   });
-};
+}
 
 function tryAndPut(db, doc, diffFun) {
   return db.put(doc).then(function (res) {
@@ -49,3 +47,5 @@
     return upsert(db, doc._id, diffFun);
   });
 }
+
+export default upsert;
\ No newline at end of file
diff --git a/lib/deps/uuid.js b/src/deps/uuid.js
similarity index 97%
rename from lib/deps/uuid.js
rename to src/deps/uuid.js
index fc3ba70..0b6b3d6 100644
--- a/lib/deps/uuid.js
+++ b/src/deps/uuid.js
@@ -1,5 +1,3 @@
-"use strict";
-
 // BEGIN Math.uuid.js
 
 /*!
@@ -79,5 +77,5 @@
 
 
 
-module.exports = uuid;
+export default uuid;
 
diff --git a/src/evalFilter.js b/src/evalFilter.js
new file mode 100644
index 0000000..5003956
--- /dev/null
+++ b/src/evalFilter.js
@@ -0,0 +1,7 @@
+import scopedEval from 'scope-eval';
+
+function evalFilter(input) {
+  return scopedEval('return ' + input + ';', {});
+}
+
+export default evalFilter;
\ No newline at end of file
diff --git a/src/evalView.js b/src/evalView.js
new file mode 100644
index 0000000..3e4a036
--- /dev/null
+++ b/src/evalView.js
@@ -0,0 +1,16 @@
+function evalView(input) {
+  /* jshint evil:true */
+  return new Function('doc', [
+    'var emitted = false;',
+    'var emit = function (a, b) {',
+    '  emitted = true;',
+    '};',
+    'var view = ' + input + ';',
+    'view(doc);',
+    'if (emitted) {',
+    '  return true;',
+    '}'
+  ].join('\n'));
+}
+
+export default evalView;
\ No newline at end of file
diff --git a/src/index.js b/src/index.js
new file mode 100644
index 0000000..1262271
--- /dev/null
+++ b/src/index.js
@@ -0,0 +1,26 @@
+import PouchDB from './setup';
+import ajax from './deps/ajax/prequest';
+import utils from './utils';
+import { errors } from './deps/errors';
+import replicate from './replicate/index';
+import sync from './sync';
+import httpAdapter from './adapters/http/index';
+import mapreduce from './mapreduce/index';
+import adapters from './adapters';
+
+PouchDB.ajax = ajax;
+PouchDB.utils = utils;
+PouchDB.Errors = errors;
+PouchDB.replicate = replicate.replicate;
+PouchDB.sync = sync;
+PouchDB.version = '__VERSION__'; // will be automatically supplied by build.sh
+PouchDB.adapter('http', httpAdapter);
+PouchDB.adapter('https', httpAdapter);
+
+PouchDB.plugin(mapreduce);
+
+Object.keys(adapters).forEach(function (adapterName) {
+  PouchDB.adapter(adapterName, adapters[adapterName], true);
+});
+
+export default PouchDB;
\ No newline at end of file
diff --git a/lib/mapreduce/createView.js b/src/mapreduce/createView.js
similarity index 93%
rename from lib/mapreduce/createView.js
rename to src/mapreduce/createView.js
index eed858a..8c1f027 100644
--- a/lib/mapreduce/createView.js
+++ b/src/mapreduce/createView.js
@@ -1,10 +1,8 @@
-'use strict';
+import upsert from '../deps/upsert';
+import Promise from '../deps/promise';
+import md5 from './md5';
 
-var upsert = require('../deps/upsert');
-var Promise = require('../deps/promise');
-var md5 = require('./md5');
-
-module.exports = function (opts) {
+function createView(opts) {
   var sourceDB = opts.db;
   var viewName = opts.viewName;
   var mapFun = opts.map;
@@ -74,4 +72,6 @@
       });
     });
   });
-};
+}
+
+export default createView;
diff --git a/src/mapreduce/evalfunc.js b/src/mapreduce/evalfunc.js
new file mode 100644
index 0000000..af6cce1
--- /dev/null
+++ b/src/mapreduce/evalfunc.js
@@ -0,0 +1,16 @@
+import scopedEval from 'scope-eval';
+
+function evalfunc(func, emit, sum, log, isArray, toJSON) {
+  return scopedEval(
+    "return (" + func.replace(/;\s*$/, "") + ");",
+    {
+      emit: emit,
+      sum: sum,
+      log: log,
+      isArray: isArray,
+      toJSON: toJSON
+    }
+  );
+}
+
+export default evalfunc;
diff --git a/lib/mapreduce/index.js b/src/mapreduce/index.js
similarity index 97%
rename from lib/mapreduce/index.js
rename to src/mapreduce/index.js
index 7cb4ea5..bec146e 100644
--- a/lib/mapreduce/index.js
+++ b/src/mapreduce/index.js
@@ -1,14 +1,12 @@
-'use strict';
-
-var b64ToBluffer = require('../deps/binary/base64StringToBlobOrBuffer');
-var pouchCollate = require('pouchdb-collate');
-var TaskQueue = require('./taskqueue');
+import b64ToBluffer from '../deps/binary/base64StringToBlobOrBuffer';
+import pouchCollate from 'pouchdb-collate';
+import TaskQueue from './taskqueue';
 var collate = pouchCollate.collate;
 var toIndexableString = pouchCollate.toIndexableString;
 var normalizeKey = pouchCollate.normalizeKey;
 var parseIndexableString = pouchCollate.parseIndexableString;
-var createView = require('./createView');
-var evalFunc = require('./evalfunc');
+import createView from './createView';
+import evalFunc from './evalfunc';
 var log;
 /* istanbul ignore else */
 if ((typeof console !== 'undefined') && (typeof console.log === 'function')) {
@@ -16,15 +14,15 @@
 } else {
   log = function () {};
 }
-var utils = require('./utils');
+import utils from './utils';
 var callbackify = utils.callbackify;
 var sequentialize = utils.sequentialize;
 var uniq = utils.uniq;
 var fin = utils.fin;
 var promisedCallback = utils.promisedCallback;
-var Promise = require('../deps/promise');
-var flatten = require('../deps/flatten');
-var inherits = require('inherits');
+import Promise from '../deps/promise';
+import flatten from '../deps/flatten';
+import inherits from 'inherits';
 var persistentQueues = {};
 var tempViewQueue = new TaskQueue();
 var CHANGES_BATCH_SIZE = 50;
@@ -836,7 +834,7 @@
   }, defaultsTo({ok: true}));
 }
 
-exports.viewCleanup = callbackify(function () {
+var viewCleanup = callbackify(function () {
   var db = this;
   if (db.type() === 'http') {
     return httpViewCleanup(db);
@@ -919,7 +917,7 @@
   }
 }
 
-exports.query = function (fun, opts, callback) {
+var query = function (fun, opts, callback) {
   if (typeof opts === 'function') {
     callback = opts;
     opts = {};
@@ -973,3 +971,8 @@
 }
 
 inherits(BuiltInError, Error);
+
+export default {
+  query: query,
+  viewCleanup: viewCleanup
+};
\ No newline at end of file
diff --git a/src/mapreduce/md5-browser.js b/src/mapreduce/md5-browser.js
new file mode 100644
index 0000000..142d109
--- /dev/null
+++ b/src/mapreduce/md5-browser.js
@@ -0,0 +1,7 @@
+import Md5 from 'spark-md5';
+
+function md5(string) {
+  return Md5.hash(string);
+}
+
+export default md5;
\ No newline at end of file
diff --git a/src/mapreduce/md5.js b/src/mapreduce/md5.js
new file mode 100644
index 0000000..182fdc8
--- /dev/null
+++ b/src/mapreduce/md5.js
@@ -0,0 +1,7 @@
+import crypto from 'crypto';
+
+function MD5(string) {
+  return crypto.createHash('md5').update(string).digest('hex');
+}
+
+export default MD5;
\ No newline at end of file
diff --git a/lib/mapreduce/taskqueue.js b/src/mapreduce/taskqueue.js
similarity index 84%
rename from lib/mapreduce/taskqueue.js
rename to src/mapreduce/taskqueue.js
index e233c18..9064939 100644
--- a/lib/mapreduce/taskqueue.js
+++ b/src/mapreduce/taskqueue.js
@@ -1,10 +1,9 @@
-'use strict';
 /*
  * Simple task queue to sequentialize actions. Assumes
  * callbacks will eventually fire (once).
  */
 
-var Promise = require('../deps/promise');
+import Promise from '../deps/promise';
 
 function TaskQueue() {
   this.promise = new Promise(function (fulfill) {fulfill(); });
@@ -21,4 +20,4 @@
   return this.promise;
 };
 
-module.exports = TaskQueue;
+export default TaskQueue;
diff --git a/lib/mapreduce/utils.js b/src/mapreduce/utils.js
similarity index 74%
rename from lib/mapreduce/utils.js
rename to src/mapreduce/utils.js
index 5883caa..3fe6bf9 100644
--- a/lib/mapreduce/utils.js
+++ b/src/mapreduce/utils.js
@@ -1,8 +1,6 @@
-'use strict';
+import argsarray from 'argsarray';
 
-var argsarray = require('argsarray');
-
-exports.promisedCallback = function (promise, callback) {
+var promisedCallback = function (promise, callback) {
   if (callback) {
     promise.then(function (res) {
       process.nextTick(function () {
@@ -17,19 +15,19 @@
   return promise;
 };
 
-exports.callbackify = function (fun) {
+var callbackify = function (fun) {
   return argsarray(function (args) {
     var cb = args.pop();
     var promise = fun.apply(this, args);
     if (typeof cb === 'function') {
-      exports.promisedCallback(promise, cb);
+      promisedCallback(promise, cb);
     }
     return promise;
   });
 };
 
 // Promise finally util similar to Q.finally
-exports.fin = function (promise, finalPromiseFactory) {
+var fin = function (promise, finalPromiseFactory) {
   return promise.then(function (res) {
     return finalPromiseFactory().then(function () {
       return res;
@@ -41,7 +39,7 @@
   });
 };
 
-exports.sequentialize = function (queue, promiseFactory) {
+var sequentialize = function (queue, promiseFactory) {
   return function () {
     var args = arguments;
     var that = this;
@@ -53,7 +51,7 @@
 
 // uniq an array of strings, order not guaranteed
 // similar to underscore/lodash _.uniq
-exports.uniq = function (arr) {
+var uniq = function (arr) {
   var map = {};
 
   for (var i = 0, len = arr.length; i < len; i++) {
@@ -68,3 +66,11 @@
   }
   return output;
 };
+
+export default {
+  uniq: uniq,
+  sequentialize: sequentialize,
+  fin: fin,
+  callbackify: callbackify,
+  promisedCallback: promisedCallback
+};
\ No newline at end of file
diff --git a/lib/plugins/base.js b/src/plugins/base.js
similarity index 80%
rename from lib/plugins/base.js
rename to src/plugins/base.js
index 9765815..a695e56 100644
--- a/lib/plugins/base.js
+++ b/src/plugins/base.js
@@ -1,9 +1,10 @@
-'use strict';
 /* global PouchDB */
 
+import altFactory from './levelalt';
+
 function pluginBase(adapterConfig, downAdapter) {
   var adapterName = adapterConfig.name;
-  var adapter = require('./levelalt')(adapterConfig, downAdapter);
+  var adapter = altFactory(adapterConfig, downAdapter);
   // use global PouchDB if it's there (e.g. window.PouchDB)
   var PDB = (typeof PouchDB !== 'undefined') ? PouchDB : require('pouchdb');
   if (!PDB) {
@@ -15,4 +16,4 @@
   }
 }
 
-module.exports = pluginBase;
\ No newline at end of file
+export default pluginBase;
\ No newline at end of file
diff --git a/lib/plugins/fruitdown/config.js b/src/plugins/fruitdown/config.js
similarity index 74%
rename from lib/plugins/fruitdown/config.js
rename to src/plugins/fruitdown/config.js
index 26c6c77..cddee27 100644
--- a/lib/plugins/fruitdown/config.js
+++ b/src/plugins/fruitdown/config.js
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = {
+export default {
   name: 'fruitdown',
   valid: function () {
     return !!global.indexedDB;
diff --git a/src/plugins/fruitdown/index.js b/src/plugins/fruitdown/index.js
new file mode 100644
index 0000000..2ec4313
--- /dev/null
+++ b/src/plugins/fruitdown/index.js
@@ -0,0 +1,5 @@
+import pluginBase from '../base';
+import adapterConfig from './config';
+import downAdapter from 'fruitdown';
+
+pluginBase(adapterConfig, downAdapter);
\ No newline at end of file
diff --git a/lib/plugins/levelalt.js b/src/plugins/levelalt.js
similarity index 78%
rename from lib/plugins/levelalt.js
rename to src/plugins/levelalt.js
index 590462c..a947360 100644
--- a/lib/plugins/levelalt.js
+++ b/src/plugins/levelalt.js
@@ -1,10 +1,7 @@
-'use strict';
+import LevelPouch from '../adapters/leveldb/index';
+import toPromise from '../deps/toPromise';
+import { extend as extend } from 'js-extend';
 
-var LevelPouch = require('../adapters/leveldb/index');
-var toPromise = require('../deps/toPromise');
-var extend = require('js-extend').extend;
-
-module.exports = altFactory;
 function altFactory(adapterConfig, downAdapter) {
 
   function LevelPouchAlt(opts, callback) {
@@ -33,5 +30,6 @@
     return LevelPouch.destroy(name, _opts, callback);
   });
   return LevelPouchAlt;
-
 }
+
+export default altFactory;
\ No newline at end of file
diff --git a/lib/plugins/localstorage/config.js b/src/plugins/localstorage/config.js
similarity index 78%
rename from lib/plugins/localstorage/config.js
rename to src/plugins/localstorage/config.js
index 86ac083..6260f1d 100644
--- a/lib/plugins/localstorage/config.js
+++ b/src/plugins/localstorage/config.js
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = {
+export default {
   name: 'localstorage',
   valid: function () {
     return typeof localStorage !== 'undefined';
diff --git a/src/plugins/localstorage/index.js b/src/plugins/localstorage/index.js
new file mode 100644
index 0000000..afd3485
--- /dev/null
+++ b/src/plugins/localstorage/index.js
@@ -0,0 +1,5 @@
+import pluginBase from '../base';
+import adapterConfig from './config';
+import downAdapter from 'localstorage-down';
+
+pluginBase(adapterConfig, downAdapter);
\ No newline at end of file
diff --git a/lib/plugins/memory/config.js b/src/plugins/memory/config.js
similarity index 70%
rename from lib/plugins/memory/config.js
rename to src/plugins/memory/config.js
index ee517ca..f4d893c 100644
--- a/lib/plugins/memory/config.js
+++ b/src/plugins/memory/config.js
@@ -1,9 +1,7 @@
-'use strict';
-
-module.exports = {
+export default {
   name: 'memory',
   valid: function () {
     return true;
   },
   use_prefix: false
-};
+};
\ No newline at end of file
diff --git a/src/plugins/memory/index.js b/src/plugins/memory/index.js
new file mode 100644
index 0000000..a19e540
--- /dev/null
+++ b/src/plugins/memory/index.js
@@ -0,0 +1,5 @@
+import pluginBase from '../base';
+import adapterConfig from './config';
+import downAdapter from 'memdown';
+
+pluginBase(adapterConfig, downAdapter);
\ No newline at end of file
diff --git a/lib/replicate/backoff.js b/src/replicate/backoff.js
similarity index 96%
rename from lib/replicate/backoff.js
rename to src/replicate/backoff.js
index f5a81a9..c812a77 100644
--- a/lib/replicate/backoff.js
+++ b/src/replicate/backoff.js
@@ -1,5 +1,3 @@
-'use strict';
-
 var STARTING_BACK_OFF = 0;
 
 function randomNumber(min, max) {
@@ -47,4 +45,4 @@
   setTimeout(callback, opts.current_back_off);
 }
 
-module.exports = backOff;
+export default backOff;
diff --git a/lib/replicate/checkpointer.js b/src/replicate/checkpointer.js
similarity index 96%
rename from lib/replicate/checkpointer.js
rename to src/replicate/checkpointer.js
index ce10c8e..0c8e95a 100644
--- a/lib/replicate/checkpointer.js
+++ b/src/replicate/checkpointer.js
@@ -1,8 +1,6 @@
-'use strict';
-
-var Promise = require('./../deps/promise');
-var explainError = require('./../deps/ajax/explainError');
-var pouchCollate = require('pouchdb-collate');
+import Promise from './../deps/promise';
+import explainError from './../deps/ajax/explainError';
+import pouchCollate from 'pouchdb-collate';
 var collate = pouchCollate.collate;
 
 var CHECKPOINT_VERSION = 1;
@@ -238,4 +236,4 @@
 }
 
 
-module.exports = Checkpointer;
+export default Checkpointer;
diff --git a/lib/replicate/generateReplicationId.js b/src/replicate/generateReplicationId.js
similarity index 86%
rename from lib/replicate/generateReplicationId.js
rename to src/replicate/generateReplicationId.js
index 12391f1..fc2f46e 100644
--- a/lib/replicate/generateReplicationId.js
+++ b/src/replicate/generateReplicationId.js
@@ -1,8 +1,6 @@
-'use strict';
-
-var Promise = require('./../deps/promise');
-var md5 = require('../deps/md5');
-var collate = require('pouchdb-collate').collate;
+import Promise from './../deps/promise';
+import md5 from '../deps/md5';
+import { collate as collate } from 'pouchdb-collate';
 
 function sortObjectPropertiesByKey(queryParams) {
   return Object.keys(queryParams).sort(collate).reduce(function (result, key) {
@@ -40,4 +38,4 @@
   });
 }
 
-module.exports = generateReplicationId;
+export default generateReplicationId;
diff --git a/lib/replicate/getDocs.js b/src/replicate/getDocs.js
similarity index 95%
rename from lib/replicate/getDocs.js
rename to src/replicate/getDocs.js
index d52594a..f2f3c06 100644
--- a/lib/replicate/getDocs.js
+++ b/src/replicate/getDocs.js
@@ -1,7 +1,5 @@
-'use strict';
-
-var clone = require('../deps/clone');
-var Promise = require('../deps/promise');
+import clone from '../deps/clone';
+import Promise from '../deps/promise';
 
 function isGenOne(rev) {
   return /^1-/.test(rev);
@@ -111,4 +109,4 @@
     .then(returnDocs);
 }
 
-module.exports = getDocs;
+export default getDocs;
diff --git a/lib/replicate/index.js b/src/replicate/index.js
similarity index 80%
rename from lib/replicate/index.js
rename to src/replicate/index.js
index f87e62e..9208298 100644
--- a/lib/replicate/index.js
+++ b/src/replicate/index.js
@@ -1,9 +1,7 @@
-'use strict';
-
-var replicate = require('./replicate');
-var Replication = require('./replication');
-var clone = require('../deps/clone');
-var errors = require('../deps/errors');
+import replicate from './replicate';
+import Replication from './replication';
+import clone from '../deps/clone';
+import { createError, BAD_REQUEST } from '../deps/errors';
 
 function toPouch(db, opts) {
   var PouchConstructor = opts.PouchConstructor;
@@ -25,7 +23,7 @@
   }
 
   if (opts.doc_ids && !Array.isArray(opts.doc_ids)) {
-    throw errors.error(errors.BAD_REQUEST,
+    throw createError(BAD_REQUEST,
                        "`doc_ids` filter parameter is not a list.");
   }
 
@@ -42,7 +40,7 @@
   return replicateRet;
 }
 
-module.exports = {
+export default {
   replicate: replicateWrapper,
   toPouch: toPouch
-};
+};
\ No newline at end of file
diff --git a/lib/replicate/replicate.js b/src/replicate/replicate.js
similarity index 94%
rename from lib/replicate/replicate.js
rename to src/replicate/replicate.js
index cbafaf4..58159af 100644
--- a/lib/replicate/replicate.js
+++ b/src/replicate/replicate.js
@@ -1,13 +1,11 @@
-'use strict';
-
-var clone = require('../deps/clone');
-var Promise = require('../deps/promise');
-var uuid = require('../deps/uuid');
-var filterChange = require('../deps/filterChange');
-var Checkpointer = require('./checkpointer');
-var backOff = require('./backoff');
-var generateReplicationId = require('./generateReplicationId');
-var getDocs = require('./getDocs');
+import clone from '../deps/clone';
+import Promise from '../deps/promise';
+import uuid from '../deps/uuid';
+import filterChange from '../deps/filterChange';
+import Checkpointer from './checkpointer';
+import backOff from './backoff';
+import generateReplicationId from './generateReplicationId';
+import getDocs from './getDocs';
 
 function replicate(src, target, opts, returnValue, result) {
   var batches = [];               // list of batches to be processed
@@ -392,6 +390,13 @@
     });
   }
 
+  /* istanbul ignore next */
+  function onCheckpointError(err) {
+    writingCheckpoint = false;
+    abortReplication('writeCheckpoint completed with error', err);
+    throw err;
+  }
+
   /* istanbul ignore if */
   if (returnValue.cancelled) { // cancelled immediately
     completeReplication();
@@ -425,12 +430,8 @@
       }
       last_seq = opts.since;
       startChanges();
-    }).catch(/* istanbul ignore next */ function (err) {
-      writingCheckpoint = false;
-      abortReplication('writeCheckpoint completed with error', err);
-      throw err;
-    });
+    }).catch(onCheckpointError);
   }
 }
 
-module.exports = replicate;
+export default replicate;
diff --git a/lib/replicate/replication.js b/src/replicate/replication.js
similarity index 88%
rename from lib/replicate/replication.js
rename to src/replicate/replication.js
index 0db7bd1..7d0603a 100644
--- a/lib/replicate/replication.js
+++ b/src/replicate/replication.js
@@ -1,8 +1,6 @@
-'use strict';
-
-var EE = require('events').EventEmitter;
-var Promise = require('../deps/promise');
-var inherits = require('inherits');
+import { EventEmitter as EE } from 'events';
+import Promise from '../deps/promise';
+import inherits from 'inherits';
 
 // We create a basic promise so the caller can cancel the replication possibly
 // before we have actually started listening to changes etc
@@ -52,4 +50,4 @@
   self.once('complete', cleanup);
 };
 
-module.exports = Replication;
\ No newline at end of file
+export default Replication;
\ No newline at end of file
diff --git a/lib/setup.js b/src/setup.js
similarity index 91%
rename from lib/setup.js
rename to src/setup.js
index bd31117..4854930 100644
--- a/lib/setup.js
+++ b/src/setup.js
@@ -1,12 +1,10 @@
-"use strict";
+import { extend as extend } from 'js-extend';
 
-var extend = require('js-extend').extend;
-
-var PouchDB = require("./constructor");
-var inherits = require('inherits');
-var collections = require('pouchdb-collections');
-var EE = require('events').EventEmitter;
-var hasLocalStorage = require('./deps/env/hasLocalStorage');
+import PouchDB from "./constructor";
+import inherits from 'inherits';
+import collections from 'pouchdb-collections';
+import { EventEmitter as EE } from 'events';
+import hasLocalStorage from './deps/env/hasLocalStorage';
 
 PouchDB.adapters = {};
 PouchDB.preferredAdapters = [];
@@ -140,4 +138,4 @@
   return PouchAlt;
 };
 
-module.exports = PouchDB;
+export default PouchDB;
diff --git a/lib/sync.js b/src/sync.js
similarity index 94%
rename from lib/sync.js
rename to src/sync.js
index 627e3b1..ab9e13b 100644
--- a/lib/sync.js
+++ b/src/sync.js
@@ -1,15 +1,13 @@
-'use strict';
-
-var extend = require('js-extend').extend;
-var Promise = require('./deps/promise');
-var replication = require('./replicate');
-var inherits = require('inherits');
+import { extend as extend } from 'js-extend';
+import Promise from './deps/promise';
+import replication from './replicate/index';
+import inherits from 'inherits';
 var replicate = replication.replicate;
-var EE = require('events').EventEmitter;
-var clone = require('./deps/clone');
+import { EventEmitter as EE } from 'events';
+import clone from './deps/clone';
 
 inherits(Sync, EE);
-module.exports = sync;
+export default sync;
 function sync(src, target, opts, callback) {
   if (typeof opts === 'function') {
     callback = opts;
diff --git a/lib/taskqueue.js b/src/taskqueue.js
similarity index 93%
rename from lib/taskqueue.js
rename to src/taskqueue.js
index a67556a..5f3d731 100644
--- a/lib/taskqueue.js
+++ b/src/taskqueue.js
@@ -1,6 +1,4 @@
-'use strict';
-
-module.exports = TaskQueue;
+export default TaskQueue;
 
 function TaskQueue() {
   this.isReady = false;
diff --git a/src/utils.js b/src/utils.js
new file mode 100644
index 0000000..c199276
--- /dev/null
+++ b/src/utils.js
@@ -0,0 +1,48 @@
+//
+// PouchDB.utils is basically a throwback to the pre-Browserify days,
+// when this was the easiest way to access global utilities from anywhere
+// in the project. For code cleanliness, we're trying to remove this file,
+// but for practical reasons (legacy code, test code, etc.) this is still here.
+//
+
+// TODO: only used by the integration tests, which have
+// some tests that explicitly override PouchDB.utils.ajax
+import ajax from './deps/ajax/prequest';
+
+// TODO: only used by the integration tests
+import parseUri from './deps/parseUri';
+
+// TODO: only used by the integration tests
+import uuid from './deps/uuid';
+
+// TODO: used by the integration tests and elsewhere, possibly
+// even in the PouchDB guide and example code
+import Promise from './deps/promise';
+
+// TODO: only used by the integration tests
+import { atob as atob, btoa as btoa } from './deps/binary/base64';
+
+// TODO: required by tests
+import {createError } from './deps/errors';
+
+// TODO: only used by the integration tests
+import binToBluffer from './deps/binary/binaryStringToBlobOrBuffer';
+
+// TODO: pretty sure these are in widespread use by Hoodie and others,
+// also in the integration tests
+import clone from './deps/clone';
+import jsExtend from 'js-extend';
+var extend = jsExtend.extend;
+
+export default {
+  ajax: ajax,
+  parseUri: parseUri,
+  uuid: uuid,
+  Promise: Promise,
+  atob: atob,
+  btoa: btoa,
+  binaryStringToBlobOrBuffer: binToBluffer,
+  clone: clone,
+  extend: extend,
+  createError: createError
+};
\ No newline at end of file
diff --git a/tests/integration/test.basics.js b/tests/integration/test.basics.js
index fcad29e..62893db 100644
--- a/tests/integration/test.basics.js
+++ b/tests/integration/test.basics.js
@@ -731,8 +731,8 @@
     });
 
     it('Error works', function () {
-      var newError = PouchDB.Errors
-        .error(PouchDB.Errors.BAD_REQUEST, 'love needs no message');
+      var newError = PouchDB.utils
+        .createError(PouchDB.Errors.BAD_REQUEST, 'love needs no message');
       newError.status.should.equal(PouchDB.Errors.BAD_REQUEST.status);
       newError.name.should.equal(PouchDB.Errors.BAD_REQUEST.name);
       newError.message.should.equal(PouchDB.Errors.BAD_REQUEST.message,
diff --git a/tests/integration/utils.js b/tests/integration/utils.js
index 8bf58f6..64b7cca 100644
--- a/tests/integration/utils.js
+++ b/tests/integration/utils.js
@@ -301,8 +301,6 @@
 var testDir;
 if (typeof module !== 'undefined' && module.exports) {
   global.PouchDB = require('../../lib');
-  global.binaryStringToBlobOrBuffer =
-    require('../../lib/deps/binary/binaryStringToBlobOrBuffer');
   if (process.env.LEVEL_ADAPTER || process.env.LEVEL_PREFIX) {
     var defaults = {};
 
@@ -323,7 +321,7 @@
     testDir = process.env.TESTS_DIR ? process.env.TESTS_DIR : './tmp';
     testDir = testDir.slice(-1) === '/' ? testDir : testDir + '/';
     global.PouchDB.prefix = testDir + global.PouchDB.prefix;
-    require('../../lib/adapters/leveldb').use_prefix = true;
+    global.PouchDB.adapters.leveldb.use_prefix = true;
   }
   module.exports = testUtils;
 }
diff --git a/tests/unit/test.gen-replication-id.js b/tests/unit/test.gen-replication-id.js
index 48270b0..fc25e36 100644
--- a/tests/unit/test.gen-replication-id.js
+++ b/tests/unit/test.gen-replication-id.js
@@ -4,7 +4,8 @@
 var PouchDB = require('../../lib/index');
 var sourceDb = new PouchDB({name: 'local_db', db: memdown});
 var targetDb = new PouchDB({name: 'target_db', db: memdown});
-var genReplicationId = require('../../lib/replicate/generateReplicationId');
+var genReplicationId =
+  require('../../lib/replicate/generateReplicationId');
 
 require('chai').should();