Bug 1317841 - Update version of kinto.js to v6.0.0, r?MattN draft
authorEthan Glasser-Camp <eglassercamp@mozilla.com>
Tue, 15 Nov 2016 17:15:14 -0800
changeset 439385 9476c0ade65074d9856ed4874ce0013fcae73467
parent 438748 be95aa5249cf8d1cf33434273f7c789e332b886d
child 537161 5931a806091f3215a75725363017b1024f3066b2
push id35998
push usermozilla@noorenberghe.ca
push dateWed, 16 Nov 2016 01:15:38 +0000
reviewersMattN
bugs1317841
milestone52.0a1
Bug 1317841 - Update version of kinto.js to v6.0.0, r?MattN This major version of kinto.js released without a FirefoxStorage adapter. Since Gecko is the only project with a need for this adapter as well as the only one who can use it, that file moves to this repo as a new kinto-storage-adapter.js. This file is mostly a copy of the most recent FirefoxStorage.js, plus some other non-exported utility functions copied from kinto.js to make it work. This changes the export of the kinto-offline-client.js from a `loadKinto` function which returns the Kinto class, to the actual Kinto class itself, with the user expected to "hook up" the adapter. It turns out that this doesn't change much in how we actually use Kinto, since we were always previously explicitly selecting the Kinto adapter. This release of kinto.js also changes some of the build options around, which changes the minified output of kinto-offline-client.js. There are still some outstanding stylistic complaints about FirefoxAdapter having to do with its _init static method which is public and the fact that sometimes FirefoxAdapter manages its own Sqlite connection and sometimes it doesn't. These will be addressed in a future patch. MozReview-Commit-ID: HF0oNCEDcFs
services/common/blocklist-clients.js
services/common/kinto-offline-client.js
services/common/kinto-storage-adapter.js
services/common/moz.build
services/common/tests/unit/test_blocklist_certificates.js
services/common/tests/unit/test_blocklist_clients.js
services/common/tests/unit/test_blocklist_signatures.js
services/common/tests/unit/test_kinto.js
toolkit/components/extensions/ExtensionStorageSync.jsm
--- a/services/common/blocklist-clients.js
+++ b/services/common/blocklist-clients.js
@@ -14,18 +14,19 @@ this.EXPORTED_SYMBOLS = ["AddonBlocklist
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
 Cu.import("resource://gre/modules/Services.jsm");
 const { Task } = Cu.import("resource://gre/modules/Task.jsm");
 const { OS } = Cu.import("resource://gre/modules/osfile.jsm");
 Cu.importGlobalProperties(["fetch"]);
 
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js");
 const { KintoHttpClient } = Cu.import("resource://services-common/kinto-http-client.js");
+const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js");
 const { CanonicalJSON } = Components.utils.import("resource://gre/modules/CanonicalJSON.jsm");
 
 const PREF_SETTINGS_SERVER                   = "services.settings.server";
 const PREF_BLOCKLIST_BUCKET                  = "services.blocklist.bucket";
 const PREF_BLOCKLIST_ONECRL_COLLECTION       = "services.blocklist.onecrl.collection";
 const PREF_BLOCKLIST_ONECRL_CHECKED_SECONDS  = "services.blocklist.onecrl.checked";
 const PREF_BLOCKLIST_ADDONS_COLLECTION       = "services.blocklist.addons.collection";
 const PREF_BLOCKLIST_ADDONS_CHECKED_SECONDS  = "services.blocklist.addons.checked";
@@ -86,20 +87,16 @@ function fetchRemoteCollection(collectio
  * Helper to instantiate a Kinto client based on preferences for remote server
  * URL and bucket name. It uses the `FirefoxAdapter` which relies on SQLite to
  * persist the local DB.
  */
 function kintoClient() {
   let base = Services.prefs.getCharPref(PREF_SETTINGS_SERVER);
   let bucket = Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET);
 
-  let Kinto = loadKinto();
-
-  let FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
-
   let config = {
     remote: base,
     bucket: bucket,
     adapter: FirefoxAdapter,
   };
 
   return new Kinto(config);
 }
--- a/services/common/kinto-offline-client.js
+++ b/services/common/kinto-offline-client.js
@@ -12,438 +12,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
 
 /*
  * This file is generated from kinto.js - do not modify directly.
  */
 
-this.EXPORTED_SYMBOLS = ["loadKinto"];
-
-/*
- * Version 5.1.0 - 8beb61d
- */
-
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.loadKinto = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-var _stringify = require("babel-runtime/core-js/json/stringify");
-
-var _stringify2 = _interopRequireDefault(_stringify);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-exports.reduceRecords = reduceRecords;
-
-var _base = require("../src/adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
-
-var _utils = require("../src/utils");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
+this.EXPORTED_SYMBOLS = ["Kinto"];
 
 /*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
+ * Version 6.0.0 - de9dd38
  */
-Components.utils.import("resource://gre/modules/Sqlite.jsm");
-Components.utils.import("resource://gre/modules/Task.jsm");
-
-const SQLITE_PATH = "kinto.sqlite";
-
-const statements = {
-  "createCollectionData": `
-    CREATE TABLE collection_data (
-      collection_name TEXT,
-      record_id TEXT,
-      record TEXT
-    );`,
-
-  "createCollectionMetadata": `
-    CREATE TABLE collection_metadata (
-      collection_name TEXT PRIMARY KEY,
-      last_modified INTEGER
-    ) WITHOUT ROWID;`,
-
-  "createCollectionDataRecordIdIndex": `
-    CREATE UNIQUE INDEX unique_collection_record
-      ON collection_data(collection_name, record_id);`,
-
-  "clearData": `
-    DELETE FROM collection_data
-      WHERE collection_name = :collection_name;`,
-
-  "createData": `
-    INSERT INTO collection_data (collection_name, record_id, record)
-      VALUES (:collection_name, :record_id, :record);`,
-
-  "updateData": `
-    INSERT OR REPLACE INTO collection_data (collection_name, record_id, record)
-      VALUES (:collection_name, :record_id, :record);`,
-
-  "deleteData": `
-    DELETE FROM collection_data
-      WHERE collection_name = :collection_name
-      AND record_id = :record_id;`,
-
-  "saveLastModified": `
-    REPLACE INTO collection_metadata (collection_name, last_modified)
-      VALUES (:collection_name, :last_modified);`,
-
-  "getLastModified": `
-    SELECT last_modified
-      FROM collection_metadata
-        WHERE collection_name = :collection_name;`,
-
-  "getRecord": `
-    SELECT record
-      FROM collection_data
-        WHERE collection_name = :collection_name
-        AND record_id = :record_id;`,
-
-  "listRecords": `
-    SELECT record
-      FROM collection_data
-        WHERE collection_name = :collection_name;`,
-
-  // N.B. we have to have a dynamic number of placeholders, which you
-  // can't do without building your own statement. See `execute` for details
-  "listRecordsById": `
-    SELECT record_id, record
-      FROM collection_data
-        WHERE collection_name = ?
-          AND record_id IN `,
-
-  "importData": `
-    REPLACE INTO collection_data (collection_name, record_id, record)
-      VALUES (:collection_name, :record_id, :record);`,
-
-  "scanAllRecords": `SELECT * FROM collection_data;`,
-
-  "clearCollectionMetadata": `DELETE FROM collection_metadata;`
-};
-
-const createStatements = ["createCollectionData", "createCollectionMetadata", "createCollectionDataRecordIdIndex"];
-
-const currentSchemaVersion = 1;
-
-/**
- * Firefox adapter.
- *
- * Uses Sqlite as a backing store.
- *
- * Options:
- *  - path: the filename/path for the Sqlite database. If absent, use SQLITE_PATH.
- */
-class FirefoxAdapter extends _base2.default {
-  constructor(collection, options = {}) {
-    super();
-    const { sqliteHandle = null } = options;
-    this.collection = collection;
-    this._connection = sqliteHandle;
-    this._options = options;
-  }
-
-  // We need to be capable of calling this from "outside" the adapter
-  // so that someone can initialize a connection and pass it to us in
-  // adapterOptions.
-  static _init(connection) {
-    return Task.spawn(function* () {
-      yield connection.executeTransaction(function* doSetup() {
-        const schema = yield connection.getSchemaVersion();
-
-        if (schema == 0) {
-
-          for (let statementName of createStatements) {
-            yield connection.execute(statements[statementName]);
-          }
-
-          yield connection.setSchemaVersion(currentSchemaVersion);
-        } else if (schema != 1) {
-          throw new Error("Unknown database schema: " + schema);
-        }
-      });
-      return connection;
-    });
-  }
-
-  _executeStatement(statement, params) {
-    if (!this._connection) {
-      throw new Error("The storage adapter is not open");
-    }
-    return this._connection.executeCached(statement, params);
-  }
-
-  open() {
-    const self = this;
-    return Task.spawn(function* () {
-      if (!self._connection) {
-        const path = self._options.path || SQLITE_PATH;
-        const opts = { path, sharedMemoryCache: false };
-        self._connection = yield Sqlite.openConnection(opts).then(FirefoxAdapter._init);
-      }
-    });
-  }
-
-  close() {
-    if (this._connection) {
-      const promise = this._connection.close();
-      this._connection = null;
-      return promise;
-    }
-    return _promise2.default.resolve();
-  }
-
-  clear() {
-    const params = { collection_name: this.collection };
-    return this._executeStatement(statements.clearData, params);
-  }
-
-  execute(callback, options = { preload: [] }) {
-    if (!this._connection) {
-      throw new Error("The storage adapter is not open");
-    }
-
-    let result;
-    const conn = this._connection;
-    const collection = this.collection;
-
-    return conn.executeTransaction(function* doExecuteTransaction() {
-      // Preload specified records from DB, within transaction.
-      const parameters = [collection, ...options.preload];
-      const placeholders = options.preload.map(_ => "?");
-      const stmt = statements.listRecordsById + "(" + placeholders.join(",") + ");";
-      const rows = yield conn.execute(stmt, parameters);
-
-      const preloaded = rows.reduce((acc, row) => {
-        const record = JSON.parse(row.getResultByName("record"));
-        acc[row.getResultByName("record_id")] = record;
-        return acc;
-      }, {});
-
-      const proxy = transactionProxy(collection, preloaded);
-      result = callback(proxy);
 
-      for (let { statement, params } of proxy.operations) {
-        yield conn.executeCached(statement, params);
-      }
-    }, conn.TRANSACTION_EXCLUSIVE).then(_ => result);
-  }
-
-  get(id) {
-    const params = {
-      collection_name: this.collection,
-      record_id: id
-    };
-    return this._executeStatement(statements.getRecord, params).then(result => {
-      if (result.length == 0) {
-        return;
-      }
-      return JSON.parse(result[0].getResultByName("record"));
-    });
-  }
-
-  list(params = { filters: {}, order: "" }) {
-    const parameters = {
-      collection_name: this.collection
-    };
-    return this._executeStatement(statements.listRecords, parameters).then(result => {
-      const records = [];
-      for (let k = 0; k < result.length; k++) {
-        const row = result[k];
-        records.push(JSON.parse(row.getResultByName("record")));
-      }
-      return records;
-    }).then(results => {
-      // The resulting list of records is filtered and sorted.
-      // XXX: with some efforts, this could be implemented using SQL.
-      return reduceRecords(params.filters, params.order, results);
-    });
-  }
-
-  /**
-   * Load a list of records into the local database.
-   *
-   * Note: The adapter is not in charge of filtering the already imported
-   * records. This is done in `Collection#loadDump()`, as a common behaviour
-   * between every adapters.
-   *
-   * @param  {Array} records.
-   * @return {Array} imported records.
-   */
-  loadDump(records) {
-    const connection = this._connection;
-    const collection_name = this.collection;
-    return Task.spawn(function* () {
-      yield connection.executeTransaction(function* doImport() {
-        for (let record of records) {
-          const params = {
-            collection_name: collection_name,
-            record_id: record.id,
-            record: (0, _stringify2.default)(record)
-          };
-          yield connection.execute(statements.importData, params);
-        }
-        const lastModified = Math.max(...records.map(record => record.last_modified));
-        const params = {
-          collection_name: collection_name
-        };
-        const previousLastModified = yield connection.execute(statements.getLastModified, params).then(result => {
-          return result.length > 0 ? result[0].getResultByName("last_modified") : -1;
-        });
-        if (lastModified > previousLastModified) {
-          const params = {
-            collection_name: collection_name,
-            last_modified: lastModified
-          };
-          yield connection.execute(statements.saveLastModified, params);
-        }
-      });
-      return records;
-    });
-  }
-
-  saveLastModified(lastModified) {
-    const parsedLastModified = parseInt(lastModified, 10) || null;
-    const params = {
-      collection_name: this.collection,
-      last_modified: parsedLastModified
-    };
-    return this._executeStatement(statements.saveLastModified, params).then(() => parsedLastModified);
-  }
-
-  getLastModified() {
-    const params = {
-      collection_name: this.collection
-    };
-    return this._executeStatement(statements.getLastModified, params).then(result => {
-      if (result.length == 0) {
-        return 0;
-      }
-      return result[0].getResultByName("last_modified");
-    });
-  }
-
-  /**
-   * Reset the sync status of every record and collection we have
-   * access to.
-   */
-  resetSyncStatus() {
-    // We're going to use execute instead of executeCached, so build
-    // in our own sanity check
-    if (!this._connection) {
-      throw new Error("The storage adapter is not open");
-    }
-
-    return this._connection.executeTransaction(function* (conn) {
-      const promises = [];
-      yield conn.execute(statements.scanAllRecords, null, function (row) {
-        const record = JSON.parse(row.getResultByName("record"));
-        const record_id = row.getResultByName("record_id");
-        const collection_name = row.getResultByName("collection_name");
-        if (record._status === "deleted") {
-          // Garbage collect deleted records.
-          promises.push(conn.execute(statements.deleteData, { collection_name, record_id }));
-        } else {
-          const newRecord = (0, _extends3.default)({}, record, {
-            _status: "created",
-            last_modified: undefined
-          });
-          promises.push(conn.execute(statements.updateData, { record: (0, _stringify2.default)(newRecord), record_id, collection_name }));
-        }
-      });
-      yield _promise2.default.all(promises);
-      yield conn.execute(statements.clearCollectionMetadata);
-    });
-  }
-}
-
-exports.default = FirefoxAdapter;
-function transactionProxy(collection, preloaded) {
-  const _operations = [];
-
-  return {
-    get operations() {
-      return _operations;
-    },
-
-    create(record) {
-      _operations.push({
-        statement: statements.createData,
-        params: {
-          collection_name: collection,
-          record_id: record.id,
-          record: (0, _stringify2.default)(record)
-        }
-      });
-    },
-
-    update(record) {
-      _operations.push({
-        statement: statements.updateData,
-        params: {
-          collection_name: collection,
-          record_id: record.id,
-          record: (0, _stringify2.default)(record)
-        }
-      });
-    },
-
-    delete(id) {
-      _operations.push({
-        statement: statements.deleteData,
-        params: {
-          collection_name: collection,
-          record_id: id
-        }
-      });
-    },
-
-    get(id) {
-      // Gecko JS engine outputs undesired warnings if id is not in preloaded.
-      return id in preloaded ? preloaded[id] : undefined;
-    }
-  };
-}
-
-/**
- * Filter and sort list against provided filters and order.
- *
- * @param  {Object} filters  The filters to apply.
- * @param  {String} order    The order to apply.
- * @param  {Array}  list     The list to reduce.
- * @return {Array}
- */
-function reduceRecords(filters, order, list) {
-  const filtered = filters ? (0, _utils.filterObjects)(filters, list) : list;
-  return order ? (0, _utils.sortObjects)(order, filtered) : filtered;
-}
-
-},{"../src/adapters/base":85,"../src/utils":87,"babel-runtime/core-js/json/stringify":3,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/extends":8}],2:[function(require,module,exports){
+(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.Kinto = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
 /*
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
@@ -455,1452 +40,76 @@ function reduceRecords(filters, order, l
  */
 
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-exports.default = loadKinto;
-
-var _base = require("../src/adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
 var _KintoBase = require("../src/KintoBase");
 
 var _KintoBase2 = _interopRequireDefault(_KintoBase);
 
-var _FirefoxStorage = require("./FirefoxStorage");
-
-var _FirefoxStorage2 = _interopRequireDefault(_FirefoxStorage);
-
 var _utils = require("../src/utils");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
 const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
 
-function loadKinto() {
-  const { EventEmitter } = Cu.import("resource://devtools/shared/event-emitter.js", {});
-  const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
+Cu.import("resource://gre/modules/Timer.jsm");
+Cu.importGlobalProperties(["fetch"]);
+const { EventEmitter } = Cu.import("resource://devtools/shared/event-emitter.js", {});
+const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
 
-  // Use standalone kinto-http module landed in FFx.
-  const { KintoHttpClient } = Cu.import("resource://services-common/kinto-http-client.js");
+// Use standalone kinto-http module landed in FFx.
+const { KintoHttpClient } = Cu.import("resource://services-common/kinto-http-client.js");
 
-  Cu.import("resource://gre/modules/Timer.jsm");
-  Cu.importGlobalProperties(['fetch']);
+class Kinto extends _KintoBase2.default {
+  constructor(options = {}) {
+    const events = {};
+    EventEmitter.decorate(events);
 
-  // Leverage Gecko service to generate UUIDs.
-  function makeIDSchema() {
-    return {
+    const defaults = {
+      events,
+      ApiClass: KintoHttpClient
+    };
+    super(_extends({}, defaults, options));
+  }
+
+  collection(collName, options = {}) {
+    const idSchema = {
       validate: _utils.RE_UUID.test.bind(_utils.RE_UUID),
       generate: function () {
         return generateUUID().toString().replace(/[{}]/g, "");
       }
     };
+    return super.collection(collName, _extends({ idSchema }, options));
   }
-
-  class KintoFX extends _KintoBase2.default {
-    static get adapters() {
-      return {
-        BaseAdapter: _base2.default,
-        FirefoxAdapter: _FirefoxStorage2.default
-      };
-    }
-
-    constructor(options = {}) {
-      const emitter = {};
-      EventEmitter.decorate(emitter);
-
-      const defaults = {
-        events: emitter,
-        ApiClass: KintoHttpClient,
-        adapter: _FirefoxStorage2.default
-      };
-
-      const expandedOptions = (0, _extends3.default)({}, defaults, options);
-      super(expandedOptions);
-    }
-
-    collection(collName, options = {}) {
-      const idSchema = makeIDSchema();
-      const expandedOptions = (0, _extends3.default)({ idSchema }, options);
-      return super.collection(collName, expandedOptions);
-    }
-  }
-
-  return KintoFX;
-}
-
-// This fixes compatibility with CommonJS required by browserify.
-// See http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default/33683495#33683495
-if (typeof module === "object") {
-  module.exports = loadKinto;
 }
 
-},{"../src/KintoBase":83,"../src/adapters/base":85,"../src/utils":87,"./FirefoxStorage":1,"babel-runtime/helpers/extends":8}],3:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/json/stringify"), __esModule: true };
-},{"core-js/library/fn/json/stringify":10}],4:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/object/assign"), __esModule: true };
-},{"core-js/library/fn/object/assign":11}],5:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/object/keys"), __esModule: true };
-},{"core-js/library/fn/object/keys":12}],6:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/promise"), __esModule: true };
-},{"core-js/library/fn/promise":13}],7:[function(require,module,exports){
-"use strict";
-
-exports.__esModule = true;
-
-var _promise = require("../core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = function (fn) {
-  return function () {
-    var gen = fn.apply(this, arguments);
-    return new _promise2.default(function (resolve, reject) {
-      function step(key, arg) {
-        try {
-          var info = gen[key](arg);
-          var value = info.value;
-        } catch (error) {
-          reject(error);
-          return;
-        }
-
-        if (info.done) {
-          resolve(value);
-        } else {
-          return _promise2.default.resolve(value).then(function (value) {
-            return step("next", value);
-          }, function (err) {
-            return step("throw", err);
-          });
-        }
-      }
-
-      return step("next");
-    });
-  };
-};
-},{"../core-js/promise":6}],8:[function(require,module,exports){
-"use strict";
-
-exports.__esModule = true;
-
-var _assign = require("../core-js/object/assign");
-
-var _assign2 = _interopRequireDefault(_assign);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _assign2.default || function (target) {
-  for (var i = 1; i < arguments.length; i++) {
-    var source = arguments[i];
-
-    for (var key in source) {
-      if (Object.prototype.hasOwnProperty.call(source, key)) {
-        target[key] = source[key];
-      }
-    }
-  }
-
-  return target;
-};
-},{"../core-js/object/assign":4}],9:[function(require,module,exports){
-
-},{}],10:[function(require,module,exports){
-var core  = require('../../modules/_core')
-  , $JSON = core.JSON || (core.JSON = {stringify: JSON.stringify});
-module.exports = function stringify(it){ // eslint-disable-line no-unused-vars
-  return $JSON.stringify.apply($JSON, arguments);
-};
-},{"../../modules/_core":21}],11:[function(require,module,exports){
-require('../../modules/es6.object.assign');
-module.exports = require('../../modules/_core').Object.assign;
-},{"../../modules/_core":21,"../../modules/es6.object.assign":77}],12:[function(require,module,exports){
-require('../../modules/es6.object.keys');
-module.exports = require('../../modules/_core').Object.keys;
-},{"../../modules/_core":21,"../../modules/es6.object.keys":78}],13:[function(require,module,exports){
-require('../modules/es6.object.to-string');
-require('../modules/es6.string.iterator');
-require('../modules/web.dom.iterable');
-require('../modules/es6.promise');
-module.exports = require('../modules/_core').Promise;
-},{"../modules/_core":21,"../modules/es6.object.to-string":79,"../modules/es6.promise":80,"../modules/es6.string.iterator":81,"../modules/web.dom.iterable":82}],14:[function(require,module,exports){
-module.exports = function(it){
-  if(typeof it != 'function')throw TypeError(it + ' is not a function!');
-  return it;
-};
-},{}],15:[function(require,module,exports){
-module.exports = function(){ /* empty */ };
-},{}],16:[function(require,module,exports){
-module.exports = function(it, Constructor, name, forbiddenField){
-  if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){
-    throw TypeError(name + ': incorrect invocation!');
-  } return it;
-};
-},{}],17:[function(require,module,exports){
-var isObject = require('./_is-object');
-module.exports = function(it){
-  if(!isObject(it))throw TypeError(it + ' is not an object!');
-  return it;
-};
-},{"./_is-object":38}],18:[function(require,module,exports){
-// false -> Array#indexOf
-// true  -> Array#includes
-var toIObject = require('./_to-iobject')
-  , toLength  = require('./_to-length')
-  , toIndex   = require('./_to-index');
-module.exports = function(IS_INCLUDES){
-  return function($this, el, fromIndex){
-    var O      = toIObject($this)
-      , length = toLength(O.length)
-      , index  = toIndex(fromIndex, length)
-      , value;
-    // Array#includes uses SameValueZero equality algorithm
-    if(IS_INCLUDES && el != el)while(length > index){
-      value = O[index++];
-      if(value != value)return true;
-    // Array#toIndex ignores holes, Array#includes - not
-    } else for(;length > index; index++)if(IS_INCLUDES || index in O){
-      if(O[index] === el)return IS_INCLUDES || index || 0;
-    } return !IS_INCLUDES && -1;
-  };
-};
-},{"./_to-index":67,"./_to-iobject":69,"./_to-length":70}],19:[function(require,module,exports){
-// getting tag from 19.1.3.6 Object.prototype.toString()
-var cof = require('./_cof')
-  , TAG = require('./_wks')('toStringTag')
-  // ES3 wrong here
-  , ARG = cof(function(){ return arguments; }()) == 'Arguments';
-
-// fallback for IE11 Script Access Denied error
-var tryGet = function(it, key){
-  try {
-    return it[key];
-  } catch(e){ /* empty */ }
-};
-
-module.exports = function(it){
-  var O, T, B;
-  return it === undefined ? 'Undefined' : it === null ? 'Null'
-    // @@toStringTag case
-    : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T
-    // builtinTag case
-    : ARG ? cof(O)
-    // ES3 arguments fallback
-    : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
-};
-},{"./_cof":20,"./_wks":74}],20:[function(require,module,exports){
-var toString = {}.toString;
-
-module.exports = function(it){
-  return toString.call(it).slice(8, -1);
-};
-},{}],21:[function(require,module,exports){
-var core = module.exports = {version: '2.4.0'};
-if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
-},{}],22:[function(require,module,exports){
-// optional / simple context binding
-var aFunction = require('./_a-function');
-module.exports = function(fn, that, length){
-  aFunction(fn);
-  if(that === undefined)return fn;
-  switch(length){
-    case 1: return function(a){
-      return fn.call(that, a);
-    };
-    case 2: return function(a, b){
-      return fn.call(that, a, b);
-    };
-    case 3: return function(a, b, c){
-      return fn.call(that, a, b, c);
-    };
-  }
-  return function(/* ...args */){
-    return fn.apply(that, arguments);
-  };
-};
-},{"./_a-function":14}],23:[function(require,module,exports){
-// 7.2.1 RequireObjectCoercible(argument)
-module.exports = function(it){
-  if(it == undefined)throw TypeError("Can't call method on  " + it);
-  return it;
-};
-},{}],24:[function(require,module,exports){
-// Thank's IE8 for his funny defineProperty
-module.exports = !require('./_fails')(function(){
-  return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
-});
-},{"./_fails":28}],25:[function(require,module,exports){
-var isObject = require('./_is-object')
-  , document = require('./_global').document
-  // in old IE typeof document.createElement is 'object'
-  , is = isObject(document) && isObject(document.createElement);
-module.exports = function(it){
-  return is ? document.createElement(it) : {};
-};
-},{"./_global":30,"./_is-object":38}],26:[function(require,module,exports){
-// IE 8- don't enum bug keys
-module.exports = (
-  'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
-).split(',');
-},{}],27:[function(require,module,exports){
-var global    = require('./_global')
-  , core      = require('./_core')
-  , ctx       = require('./_ctx')
-  , hide      = require('./_hide')
-  , PROTOTYPE = 'prototype';
-
-var $export = function(type, name, source){
-  var IS_FORCED = type & $export.F
-    , IS_GLOBAL = type & $export.G
-    , IS_STATIC = type & $export.S
-    , IS_PROTO  = type & $export.P
-    , IS_BIND   = type & $export.B
-    , IS_WRAP   = type & $export.W
-    , exports   = IS_GLOBAL ? core : core[name] || (core[name] = {})
-    , expProto  = exports[PROTOTYPE]
-    , target    = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
-    , key, own, out;
-  if(IS_GLOBAL)source = name;
-  for(key in source){
-    // contains in native
-    own = !IS_FORCED && target && target[key] !== undefined;
-    if(own && key in exports)continue;
-    // export native or passed
-    out = own ? target[key] : source[key];
-    // prevent global pollution for namespaces
-    exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
-    // bind timers to global for call from export context
-    : IS_BIND && own ? ctx(out, global)
-    // wrap global constructors for prevent change them in library
-    : IS_WRAP && target[key] == out ? (function(C){
-      var F = function(a, b, c){
-        if(this instanceof C){
-          switch(arguments.length){
-            case 0: return new C;
-            case 1: return new C(a);
-            case 2: return new C(a, b);
-          } return new C(a, b, c);
-        } return C.apply(this, arguments);
-      };
-      F[PROTOTYPE] = C[PROTOTYPE];
-      return F;
-    // make static versions for prototype methods
-    })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
-    // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%
-    if(IS_PROTO){
-      (exports.virtual || (exports.virtual = {}))[key] = out;
-      // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%
-      if(type & $export.R && expProto && !expProto[key])hide(expProto, key, out);
-    }
-  }
-};
-// type bitmap
-$export.F = 1;   // forced
-$export.G = 2;   // global
-$export.S = 4;   // static
-$export.P = 8;   // proto
-$export.B = 16;  // bind
-$export.W = 32;  // wrap
-$export.U = 64;  // safe
-$export.R = 128; // real proto method for `library` 
-module.exports = $export;
-},{"./_core":21,"./_ctx":22,"./_global":30,"./_hide":32}],28:[function(require,module,exports){
-module.exports = function(exec){
-  try {
-    return !!exec();
-  } catch(e){
-    return true;
-  }
-};
-},{}],29:[function(require,module,exports){
-var ctx         = require('./_ctx')
-  , call        = require('./_iter-call')
-  , isArrayIter = require('./_is-array-iter')
-  , anObject    = require('./_an-object')
-  , toLength    = require('./_to-length')
-  , getIterFn   = require('./core.get-iterator-method')
-  , BREAK       = {}
-  , RETURN      = {};
-var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){
-  var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable)
-    , f      = ctx(fn, that, entries ? 2 : 1)
-    , index  = 0
-    , length, step, iterator, result;
-  if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!');
-  // fast case for arrays with default iterator
-  if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){
-    result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);
-    if(result === BREAK || result === RETURN)return result;
-  } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){
-    result = call(iterator, f, step.value, entries);
-    if(result === BREAK || result === RETURN)return result;
-  }
-};
-exports.BREAK  = BREAK;
-exports.RETURN = RETURN;
-},{"./_an-object":17,"./_ctx":22,"./_is-array-iter":37,"./_iter-call":39,"./_to-length":70,"./core.get-iterator-method":75}],30:[function(require,module,exports){
-// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
-var global = module.exports = typeof window != 'undefined' && window.Math == Math
-  ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
-if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
-},{}],31:[function(require,module,exports){
-var hasOwnProperty = {}.hasOwnProperty;
-module.exports = function(it, key){
-  return hasOwnProperty.call(it, key);
-};
-},{}],32:[function(require,module,exports){
-var dP         = require('./_object-dp')
-  , createDesc = require('./_property-desc');
-module.exports = require('./_descriptors') ? function(object, key, value){
-  return dP.f(object, key, createDesc(1, value));
-} : function(object, key, value){
-  object[key] = value;
-  return object;
-};
-},{"./_descriptors":24,"./_object-dp":49,"./_property-desc":57}],33:[function(require,module,exports){
-module.exports = require('./_global').document && document.documentElement;
-},{"./_global":30}],34:[function(require,module,exports){
-module.exports = !require('./_descriptors') && !require('./_fails')(function(){
-  return Object.defineProperty(require('./_dom-create')('div'), 'a', {get: function(){ return 7; }}).a != 7;
-});
-},{"./_descriptors":24,"./_dom-create":25,"./_fails":28}],35:[function(require,module,exports){
-// fast apply, http://jsperf.lnkit.com/fast-apply/5
-module.exports = function(fn, args, that){
-  var un = that === undefined;
-  switch(args.length){
-    case 0: return un ? fn()
-                      : fn.call(that);
-    case 1: return un ? fn(args[0])
-                      : fn.call(that, args[0]);
-    case 2: return un ? fn(args[0], args[1])
-                      : fn.call(that, args[0], args[1]);
-    case 3: return un ? fn(args[0], args[1], args[2])
-                      : fn.call(that, args[0], args[1], args[2]);
-    case 4: return un ? fn(args[0], args[1], args[2], args[3])
-                      : fn.call(that, args[0], args[1], args[2], args[3]);
-  } return              fn.apply(that, args);
-};
-},{}],36:[function(require,module,exports){
-// fallback for non-array-like ES3 and non-enumerable old V8 strings
-var cof = require('./_cof');
-module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
-  return cof(it) == 'String' ? it.split('') : Object(it);
-};
-},{"./_cof":20}],37:[function(require,module,exports){
-// check on default Array iterator
-var Iterators  = require('./_iterators')
-  , ITERATOR   = require('./_wks')('iterator')
-  , ArrayProto = Array.prototype;
-
-module.exports = function(it){
-  return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);
-};
-},{"./_iterators":44,"./_wks":74}],38:[function(require,module,exports){
-module.exports = function(it){
-  return typeof it === 'object' ? it !== null : typeof it === 'function';
-};
-},{}],39:[function(require,module,exports){
-// call something on iterator step with safe closing on error
-var anObject = require('./_an-object');
-module.exports = function(iterator, fn, value, entries){
-  try {
-    return entries ? fn(anObject(value)[0], value[1]) : fn(value);
-  // 7.4.6 IteratorClose(iterator, completion)
-  } catch(e){
-    var ret = iterator['return'];
-    if(ret !== undefined)anObject(ret.call(iterator));
-    throw e;
-  }
-};
-},{"./_an-object":17}],40:[function(require,module,exports){
-'use strict';
-var create         = require('./_object-create')
-  , descriptor     = require('./_property-desc')
-  , setToStringTag = require('./_set-to-string-tag')
-  , IteratorPrototype = {};
-
-// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
-require('./_hide')(IteratorPrototype, require('./_wks')('iterator'), function(){ return this; });
-
-module.exports = function(Constructor, NAME, next){
-  Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)});
-  setToStringTag(Constructor, NAME + ' Iterator');
-};
-},{"./_hide":32,"./_object-create":48,"./_property-desc":57,"./_set-to-string-tag":61,"./_wks":74}],41:[function(require,module,exports){
-'use strict';
-var LIBRARY        = require('./_library')
-  , $export        = require('./_export')
-  , redefine       = require('./_redefine')
-  , hide           = require('./_hide')
-  , has            = require('./_has')
-  , Iterators      = require('./_iterators')
-  , $iterCreate    = require('./_iter-create')
-  , setToStringTag = require('./_set-to-string-tag')
-  , getPrototypeOf = require('./_object-gpo')
-  , ITERATOR       = require('./_wks')('iterator')
-  , BUGGY          = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next`
-  , FF_ITERATOR    = '@@iterator'
-  , KEYS           = 'keys'
-  , VALUES         = 'values';
-
-var returnThis = function(){ return this; };
-
-module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){
-  $iterCreate(Constructor, NAME, next);
-  var getMethod = function(kind){
-    if(!BUGGY && kind in proto)return proto[kind];
-    switch(kind){
-      case KEYS: return function keys(){ return new Constructor(this, kind); };
-      case VALUES: return function values(){ return new Constructor(this, kind); };
-    } return function entries(){ return new Constructor(this, kind); };
-  };
-  var TAG        = NAME + ' Iterator'
-    , DEF_VALUES = DEFAULT == VALUES
-    , VALUES_BUG = false
-    , proto      = Base.prototype
-    , $native    = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]
-    , $default   = $native || getMethod(DEFAULT)
-    , $entries   = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined
-    , $anyNative = NAME == 'Array' ? proto.entries || $native : $native
-    , methods, key, IteratorPrototype;
-  // Fix native
-  if($anyNative){
-    IteratorPrototype = getPrototypeOf($anyNative.call(new Base));
-    if(IteratorPrototype !== Object.prototype){
-      // Set @@toStringTag to native iterators
-      setToStringTag(IteratorPrototype, TAG, true);
-      // fix for some old engines
-      if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis);
-    }
-  }
-  // fix Array#{values, @@iterator}.name in V8 / FF
-  if(DEF_VALUES && $native && $native.name !== VALUES){
-    VALUES_BUG = true;
-    $default = function values(){ return $native.call(this); };
-  }
-  // Define iterator
-  if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){
-    hide(proto, ITERATOR, $default);
-  }
-  // Plug for library
-  Iterators[NAME] = $default;
-  Iterators[TAG]  = returnThis;
-  if(DEFAULT){
-    methods = {
-      values:  DEF_VALUES ? $default : getMethod(VALUES),
-      keys:    IS_SET     ? $default : getMethod(KEYS),
-      entries: $entries
-    };
-    if(FORCED)for(key in methods){
-      if(!(key in proto))redefine(proto, key, methods[key]);
-    } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
-  }
-  return methods;
-};
-},{"./_export":27,"./_has":31,"./_hide":32,"./_iter-create":40,"./_iterators":44,"./_library":45,"./_object-gpo":52,"./_redefine":59,"./_set-to-string-tag":61,"./_wks":74}],42:[function(require,module,exports){
-var ITERATOR     = require('./_wks')('iterator')
-  , SAFE_CLOSING = false;
-
-try {
-  var riter = [7][ITERATOR]();
-  riter['return'] = function(){ SAFE_CLOSING = true; };
-  Array.from(riter, function(){ throw 2; });
-} catch(e){ /* empty */ }
-
-module.exports = function(exec, skipClosing){
-  if(!skipClosing && !SAFE_CLOSING)return false;
-  var safe = false;
-  try {
-    var arr  = [7]
-      , iter = arr[ITERATOR]();
-    iter.next = function(){ return {done: safe = true}; };
-    arr[ITERATOR] = function(){ return iter; };
-    exec(arr);
-  } catch(e){ /* empty */ }
-  return safe;
-};
-},{"./_wks":74}],43:[function(require,module,exports){
-module.exports = function(done, value){
-  return {value: value, done: !!done};
-};
-},{}],44:[function(require,module,exports){
-module.exports = {};
-},{}],45:[function(require,module,exports){
-module.exports = true;
-},{}],46:[function(require,module,exports){
-var global    = require('./_global')
-  , macrotask = require('./_task').set
-  , Observer  = global.MutationObserver || global.WebKitMutationObserver
-  , process   = global.process
-  , Promise   = global.Promise
-  , isNode    = require('./_cof')(process) == 'process';
-
-module.exports = function(){
-  var head, last, notify;
-
-  var flush = function(){
-    var parent, fn;
-    if(isNode && (parent = process.domain))parent.exit();
-    while(head){
-      fn   = head.fn;
-      head = head.next;
-      try {
-        fn();
-      } catch(e){
-        if(head)notify();
-        else last = undefined;
-        throw e;
-      }
-    } last = undefined;
-    if(parent)parent.enter();
-  };
-
-  // Node.js
-  if(isNode){
-    notify = function(){
-      process.nextTick(flush);
-    };
-  // browsers with MutationObserver
-  } else if(Observer){
-    var toggle = true
-      , node   = document.createTextNode('');
-    new Observer(flush).observe(node, {characterData: true}); // eslint-disable-line no-new
-    notify = function(){
-      node.data = toggle = !toggle;
-    };
-  // environments with maybe non-completely correct, but existent Promise
-  } else if(Promise && Promise.resolve){
-    var promise = Promise.resolve();
-    notify = function(){
-      promise.then(flush);
-    };
-  // for other environments - macrotask based on:
-  // - setImmediate
-  // - MessageChannel
-  // - window.postMessag
-  // - onreadystatechange
-  // - setTimeout
-  } else {
-    notify = function(){
-      // strange IE + webpack dev server bug - use .call(global)
-      macrotask.call(global, flush);
-    };
-  }
-
-  return function(fn){
-    var task = {fn: fn, next: undefined};
-    if(last)last.next = task;
-    if(!head){
-      head = task;
-      notify();
-    } last = task;
-  };
-};
-},{"./_cof":20,"./_global":30,"./_task":66}],47:[function(require,module,exports){
-'use strict';
-// 19.1.2.1 Object.assign(target, source, ...)
-var getKeys  = require('./_object-keys')
-  , gOPS     = require('./_object-gops')
-  , pIE      = require('./_object-pie')
-  , toObject = require('./_to-object')
-  , IObject  = require('./_iobject')
-  , $assign  = Object.assign;
-
-// should work with symbols and should have deterministic property order (V8 bug)
-module.exports = !$assign || require('./_fails')(function(){
-  var A = {}
-    , B = {}
-    , S = Symbol()
-    , K = 'abcdefghijklmnopqrst';
-  A[S] = 7;
-  K.split('').forEach(function(k){ B[k] = k; });
-  return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
-}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
-  var T     = toObject(target)
-    , aLen  = arguments.length
-    , index = 1
-    , getSymbols = gOPS.f
-    , isEnum     = pIE.f;
-  while(aLen > index){
-    var S      = IObject(arguments[index++])
-      , keys   = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
-      , length = keys.length
-      , j      = 0
-      , key;
-    while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
-  } return T;
-} : $assign;
-},{"./_fails":28,"./_iobject":36,"./_object-gops":51,"./_object-keys":54,"./_object-pie":55,"./_to-object":71}],48:[function(require,module,exports){
-// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
-var anObject    = require('./_an-object')
-  , dPs         = require('./_object-dps')
-  , enumBugKeys = require('./_enum-bug-keys')
-  , IE_PROTO    = require('./_shared-key')('IE_PROTO')
-  , Empty       = function(){ /* empty */ }
-  , PROTOTYPE   = 'prototype';
+exports.default = Kinto; // This fixes compatibility with CommonJS required by browserify.
+// See http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default/33683495#33683495
 
-// Create object with fake `null` prototype: use iframe Object with cleared prototype
-var createDict = function(){
-  // Thrash, waste and sodomy: IE GC bug
-  var iframe = require('./_dom-create')('iframe')
-    , i      = enumBugKeys.length
-    , lt     = '<'
-    , gt     = '>'
-    , iframeDocument;
-  iframe.style.display = 'none';
-  require('./_html').appendChild(iframe);
-  iframe.src = 'javascript:'; // eslint-disable-line no-script-url
-  // createDict = iframe.contentWindow.Object;
-  // html.removeChild(iframe);
-  iframeDocument = iframe.contentWindow.document;
-  iframeDocument.open();
-  iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);
-  iframeDocument.close();
-  createDict = iframeDocument.F;
-  while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]];
-  return createDict();
-};
-
-module.exports = Object.create || function create(O, Properties){
-  var result;
-  if(O !== null){
-    Empty[PROTOTYPE] = anObject(O);
-    result = new Empty;
-    Empty[PROTOTYPE] = null;
-    // add "__proto__" for Object.getPrototypeOf polyfill
-    result[IE_PROTO] = O;
-  } else result = createDict();
-  return Properties === undefined ? result : dPs(result, Properties);
-};
-
-},{"./_an-object":17,"./_dom-create":25,"./_enum-bug-keys":26,"./_html":33,"./_object-dps":50,"./_shared-key":62}],49:[function(require,module,exports){
-var anObject       = require('./_an-object')
-  , IE8_DOM_DEFINE = require('./_ie8-dom-define')
-  , toPrimitive    = require('./_to-primitive')
-  , dP             = Object.defineProperty;
-
-exports.f = require('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes){
-  anObject(O);
-  P = toPrimitive(P, true);
-  anObject(Attributes);
-  if(IE8_DOM_DEFINE)try {
-    return dP(O, P, Attributes);
-  } catch(e){ /* empty */ }
-  if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!');
-  if('value' in Attributes)O[P] = Attributes.value;
-  return O;
-};
-},{"./_an-object":17,"./_descriptors":24,"./_ie8-dom-define":34,"./_to-primitive":72}],50:[function(require,module,exports){
-var dP       = require('./_object-dp')
-  , anObject = require('./_an-object')
-  , getKeys  = require('./_object-keys');
-
-module.exports = require('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties){
-  anObject(O);
-  var keys   = getKeys(Properties)
-    , length = keys.length
-    , i = 0
-    , P;
-  while(length > i)dP.f(O, P = keys[i++], Properties[P]);
-  return O;
-};
-},{"./_an-object":17,"./_descriptors":24,"./_object-dp":49,"./_object-keys":54}],51:[function(require,module,exports){
-exports.f = Object.getOwnPropertySymbols;
-},{}],52:[function(require,module,exports){
-// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
-var has         = require('./_has')
-  , toObject    = require('./_to-object')
-  , IE_PROTO    = require('./_shared-key')('IE_PROTO')
-  , ObjectProto = Object.prototype;
-
-module.exports = Object.getPrototypeOf || function(O){
-  O = toObject(O);
-  if(has(O, IE_PROTO))return O[IE_PROTO];
-  if(typeof O.constructor == 'function' && O instanceof O.constructor){
-    return O.constructor.prototype;
-  } return O instanceof Object ? ObjectProto : null;
-};
-},{"./_has":31,"./_shared-key":62,"./_to-object":71}],53:[function(require,module,exports){
-var has          = require('./_has')
-  , toIObject    = require('./_to-iobject')
-  , arrayIndexOf = require('./_array-includes')(false)
-  , IE_PROTO     = require('./_shared-key')('IE_PROTO');
-
-module.exports = function(object, names){
-  var O      = toIObject(object)
-    , i      = 0
-    , result = []
-    , key;
-  for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key);
-  // Don't enum bug & hidden keys
-  while(names.length > i)if(has(O, key = names[i++])){
-    ~arrayIndexOf(result, key) || result.push(key);
-  }
-  return result;
-};
-},{"./_array-includes":18,"./_has":31,"./_shared-key":62,"./_to-iobject":69}],54:[function(require,module,exports){
-// 19.1.2.14 / 15.2.3.14 Object.keys(O)
-var $keys       = require('./_object-keys-internal')
-  , enumBugKeys = require('./_enum-bug-keys');
-
-module.exports = Object.keys || function keys(O){
-  return $keys(O, enumBugKeys);
-};
-},{"./_enum-bug-keys":26,"./_object-keys-internal":53}],55:[function(require,module,exports){
-exports.f = {}.propertyIsEnumerable;
-},{}],56:[function(require,module,exports){
-// most Object methods by ES6 should accept primitives
-var $export = require('./_export')
-  , core    = require('./_core')
-  , fails   = require('./_fails');
-module.exports = function(KEY, exec){
-  var fn  = (core.Object || {})[KEY] || Object[KEY]
-    , exp = {};
-  exp[KEY] = exec(fn);
-  $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp);
-};
-},{"./_core":21,"./_export":27,"./_fails":28}],57:[function(require,module,exports){
-module.exports = function(bitmap, value){
-  return {
-    enumerable  : !(bitmap & 1),
-    configurable: !(bitmap & 2),
-    writable    : !(bitmap & 4),
-    value       : value
-  };
-};
-},{}],58:[function(require,module,exports){
-var hide = require('./_hide');
-module.exports = function(target, src, safe){
-  for(var key in src){
-    if(safe && target[key])target[key] = src[key];
-    else hide(target, key, src[key]);
-  } return target;
-};
-},{"./_hide":32}],59:[function(require,module,exports){
-module.exports = require('./_hide');
-},{"./_hide":32}],60:[function(require,module,exports){
-'use strict';
-var global      = require('./_global')
-  , core        = require('./_core')
-  , dP          = require('./_object-dp')
-  , DESCRIPTORS = require('./_descriptors')
-  , SPECIES     = require('./_wks')('species');
-
-module.exports = function(KEY){
-  var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY];
-  if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, {
-    configurable: true,
-    get: function(){ return this; }
-  });
-};
-},{"./_core":21,"./_descriptors":24,"./_global":30,"./_object-dp":49,"./_wks":74}],61:[function(require,module,exports){
-var def = require('./_object-dp').f
-  , has = require('./_has')
-  , TAG = require('./_wks')('toStringTag');
-
-module.exports = function(it, tag, stat){
-  if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag});
-};
-},{"./_has":31,"./_object-dp":49,"./_wks":74}],62:[function(require,module,exports){
-var shared = require('./_shared')('keys')
-  , uid    = require('./_uid');
-module.exports = function(key){
-  return shared[key] || (shared[key] = uid(key));
-};
-},{"./_shared":63,"./_uid":73}],63:[function(require,module,exports){
-var global = require('./_global')
-  , SHARED = '__core-js_shared__'
-  , store  = global[SHARED] || (global[SHARED] = {});
-module.exports = function(key){
-  return store[key] || (store[key] = {});
-};
-},{"./_global":30}],64:[function(require,module,exports){
-// 7.3.20 SpeciesConstructor(O, defaultConstructor)
-var anObject  = require('./_an-object')
-  , aFunction = require('./_a-function')
-  , SPECIES   = require('./_wks')('species');
-module.exports = function(O, D){
-  var C = anObject(O).constructor, S;
-  return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S);
-};
-},{"./_a-function":14,"./_an-object":17,"./_wks":74}],65:[function(require,module,exports){
-var toInteger = require('./_to-integer')
-  , defined   = require('./_defined');
-// true  -> String#at
-// false -> String#codePointAt
-module.exports = function(TO_STRING){
-  return function(that, pos){
-    var s = String(defined(that))
-      , i = toInteger(pos)
-      , l = s.length
-      , a, b;
-    if(i < 0 || i >= l)return TO_STRING ? '' : undefined;
-    a = s.charCodeAt(i);
-    return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff
-      ? TO_STRING ? s.charAt(i) : a
-      : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
-  };
-};
-},{"./_defined":23,"./_to-integer":68}],66:[function(require,module,exports){
-var ctx                = require('./_ctx')
-  , invoke             = require('./_invoke')
-  , html               = require('./_html')
-  , cel                = require('./_dom-create')
-  , global             = require('./_global')
-  , process            = global.process
-  , setTask            = global.setImmediate
-  , clearTask          = global.clearImmediate
-  , MessageChannel     = global.MessageChannel
-  , counter            = 0
-  , queue              = {}
-  , ONREADYSTATECHANGE = 'onreadystatechange'
-  , defer, channel, port;
-var run = function(){
-  var id = +this;
-  if(queue.hasOwnProperty(id)){
-    var fn = queue[id];
-    delete queue[id];
-    fn();
-  }
-};
-var listener = function(event){
-  run.call(event.data);
-};
-// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
-if(!setTask || !clearTask){
-  setTask = function setImmediate(fn){
-    var args = [], i = 1;
-    while(arguments.length > i)args.push(arguments[i++]);
-    queue[++counter] = function(){
-      invoke(typeof fn == 'function' ? fn : Function(fn), args);
-    };
-    defer(counter);
-    return counter;
-  };
-  clearTask = function clearImmediate(id){
-    delete queue[id];
-  };
-  // Node.js 0.8-
-  if(require('./_cof')(process) == 'process'){
-    defer = function(id){
-      process.nextTick(ctx(run, id, 1));
-    };
-  // Browsers with MessageChannel, includes WebWorkers
-  } else if(MessageChannel){
-    channel = new MessageChannel;
-    port    = channel.port2;
-    channel.port1.onmessage = listener;
-    defer = ctx(port.postMessage, port, 1);
-  // Browsers with postMessage, skip WebWorkers
-  // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
-  } else if(global.addEventListener && typeof postMessage == 'function' && !global.importScripts){
-    defer = function(id){
-      global.postMessage(id + '', '*');
-    };
-    global.addEventListener('message', listener, false);
-  // IE8-
-  } else if(ONREADYSTATECHANGE in cel('script')){
-    defer = function(id){
-      html.appendChild(cel('script'))[ONREADYSTATECHANGE] = function(){
-        html.removeChild(this);
-        run.call(id);
-      };
-    };
-  // Rest old browsers
-  } else {
-    defer = function(id){
-      setTimeout(ctx(run, id, 1), 0);
-    };
-  }
-}
-module.exports = {
-  set:   setTask,
-  clear: clearTask
-};
-},{"./_cof":20,"./_ctx":22,"./_dom-create":25,"./_global":30,"./_html":33,"./_invoke":35}],67:[function(require,module,exports){
-var toInteger = require('./_to-integer')
-  , max       = Math.max
-  , min       = Math.min;
-module.exports = function(index, length){
-  index = toInteger(index);
-  return index < 0 ? max(index + length, 0) : min(index, length);
-};
-},{"./_to-integer":68}],68:[function(require,module,exports){
-// 7.1.4 ToInteger
-var ceil  = Math.ceil
-  , floor = Math.floor;
-module.exports = function(it){
-  return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
-};
-},{}],69:[function(require,module,exports){
-// to indexed object, toObject with fallback for non-array-like ES3 strings
-var IObject = require('./_iobject')
-  , defined = require('./_defined');
-module.exports = function(it){
-  return IObject(defined(it));
-};
-},{"./_defined":23,"./_iobject":36}],70:[function(require,module,exports){
-// 7.1.15 ToLength
-var toInteger = require('./_to-integer')
-  , min       = Math.min;
-module.exports = function(it){
-  return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
-};
-},{"./_to-integer":68}],71:[function(require,module,exports){
-// 7.1.13 ToObject(argument)
-var defined = require('./_defined');
-module.exports = function(it){
-  return Object(defined(it));
-};
-},{"./_defined":23}],72:[function(require,module,exports){
-// 7.1.1 ToPrimitive(input [, PreferredType])
-var isObject = require('./_is-object');
-// instead of the ES6 spec version, we didn't implement @@toPrimitive case
-// and the second argument - flag - preferred type is a string
-module.exports = function(it, S){
-  if(!isObject(it))return it;
-  var fn, val;
-  if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
-  if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val;
-  if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
-  throw TypeError("Can't convert object to primitive value");
-};
-},{"./_is-object":38}],73:[function(require,module,exports){
-var id = 0
-  , px = Math.random();
-module.exports = function(key){
-  return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
-};
-},{}],74:[function(require,module,exports){
-var store      = require('./_shared')('wks')
-  , uid        = require('./_uid')
-  , Symbol     = require('./_global').Symbol
-  , USE_SYMBOL = typeof Symbol == 'function';
-
-var $exports = module.exports = function(name){
-  return store[name] || (store[name] =
-    USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));
-};
-
-$exports.store = store;
-},{"./_global":30,"./_shared":63,"./_uid":73}],75:[function(require,module,exports){
-var classof   = require('./_classof')
-  , ITERATOR  = require('./_wks')('iterator')
-  , Iterators = require('./_iterators');
-module.exports = require('./_core').getIteratorMethod = function(it){
-  if(it != undefined)return it[ITERATOR]
-    || it['@@iterator']
-    || Iterators[classof(it)];
-};
-},{"./_classof":19,"./_core":21,"./_iterators":44,"./_wks":74}],76:[function(require,module,exports){
-'use strict';
-var addToUnscopables = require('./_add-to-unscopables')
-  , step             = require('./_iter-step')
-  , Iterators        = require('./_iterators')
-  , toIObject        = require('./_to-iobject');
-
-// 22.1.3.4 Array.prototype.entries()
-// 22.1.3.13 Array.prototype.keys()
-// 22.1.3.29 Array.prototype.values()
-// 22.1.3.30 Array.prototype[@@iterator]()
-module.exports = require('./_iter-define')(Array, 'Array', function(iterated, kind){
-  this._t = toIObject(iterated); // target
-  this._i = 0;                   // next index
-  this._k = kind;                // kind
-// 22.1.5.2.1 %ArrayIteratorPrototype%.next()
-}, function(){
-  var O     = this._t
-    , kind  = this._k
-    , index = this._i++;
-  if(!O || index >= O.length){
-    this._t = undefined;
-    return step(1);
-  }
-  if(kind == 'keys'  )return step(0, index);
-  if(kind == 'values')return step(0, O[index]);
-  return step(0, [index, O[index]]);
-}, 'values');
-
-// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
-Iterators.Arguments = Iterators.Array;
-
-addToUnscopables('keys');
-addToUnscopables('values');
-addToUnscopables('entries');
-},{"./_add-to-unscopables":15,"./_iter-define":41,"./_iter-step":43,"./_iterators":44,"./_to-iobject":69}],77:[function(require,module,exports){
-// 19.1.3.1 Object.assign(target, source)
-var $export = require('./_export');
-
-$export($export.S + $export.F, 'Object', {assign: require('./_object-assign')});
-},{"./_export":27,"./_object-assign":47}],78:[function(require,module,exports){
-// 19.1.2.14 Object.keys(O)
-var toObject = require('./_to-object')
-  , $keys    = require('./_object-keys');
-
-require('./_object-sap')('keys', function(){
-  return function keys(it){
-    return $keys(toObject(it));
-  };
-});
-},{"./_object-keys":54,"./_object-sap":56,"./_to-object":71}],79:[function(require,module,exports){
-arguments[4][9][0].apply(exports,arguments)
-},{"dup":9}],80:[function(require,module,exports){
-'use strict';
-var LIBRARY            = require('./_library')
-  , global             = require('./_global')
-  , ctx                = require('./_ctx')
-  , classof            = require('./_classof')
-  , $export            = require('./_export')
-  , isObject           = require('./_is-object')
-  , aFunction          = require('./_a-function')
-  , anInstance         = require('./_an-instance')
-  , forOf              = require('./_for-of')
-  , speciesConstructor = require('./_species-constructor')
-  , task               = require('./_task').set
-  , microtask          = require('./_microtask')()
-  , PROMISE            = 'Promise'
-  , TypeError          = global.TypeError
-  , process            = global.process
-  , $Promise           = global[PROMISE]
-  , process            = global.process
-  , isNode             = classof(process) == 'process'
-  , empty              = function(){ /* empty */ }
-  , Internal, GenericPromiseCapability, Wrapper;
-
-var USE_NATIVE = !!function(){
-  try {
-    // correct subclassing with @@species support
-    var promise     = $Promise.resolve(1)
-      , FakePromise = (promise.constructor = {})[require('./_wks')('species')] = function(exec){ exec(empty, empty); };
-    // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
-    return (isNode || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
-  } catch(e){ /* empty */ }
-}();
-
-// helpers
-var sameConstructor = function(a, b){
-  // with library wrapper special case
-  return a === b || a === $Promise && b === Wrapper;
-};
-var isThenable = function(it){
-  var then;
-  return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
-};
-var newPromiseCapability = function(C){
-  return sameConstructor($Promise, C)
-    ? new PromiseCapability(C)
-    : new GenericPromiseCapability(C);
-};
-var PromiseCapability = GenericPromiseCapability = function(C){
-  var resolve, reject;
-  this.promise = new C(function($$resolve, $$reject){
-    if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor');
-    resolve = $$resolve;
-    reject  = $$reject;
-  });
-  this.resolve = aFunction(resolve);
-  this.reject  = aFunction(reject);
-};
-var perform = function(exec){
-  try {
-    exec();
-  } catch(e){
-    return {error: e};
-  }
-};
-var notify = function(promise, isReject){
-  if(promise._n)return;
-  promise._n = true;
-  var chain = promise._c;
-  microtask(function(){
-    var value = promise._v
-      , ok    = promise._s == 1
-      , i     = 0;
-    var run = function(reaction){
-      var handler = ok ? reaction.ok : reaction.fail
-        , resolve = reaction.resolve
-        , reject  = reaction.reject
-        , domain  = reaction.domain
-        , result, then;
-      try {
-        if(handler){
-          if(!ok){
-            if(promise._h == 2)onHandleUnhandled(promise);
-            promise._h = 1;
-          }
-          if(handler === true)result = value;
-          else {
-            if(domain)domain.enter();
-            result = handler(value);
-            if(domain)domain.exit();
-          }
-          if(result === reaction.promise){
-            reject(TypeError('Promise-chain cycle'));
-          } else if(then = isThenable(result)){
-            then.call(result, resolve, reject);
-          } else resolve(result);
-        } else reject(value);
-      } catch(e){
-        reject(e);
-      }
-    };
-    while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
-    promise._c = [];
-    promise._n = false;
-    if(isReject && !promise._h)onUnhandled(promise);
-  });
-};
-var onUnhandled = function(promise){
-  task.call(global, function(){
-    var value = promise._v
-      , abrupt, handler, console;
-    if(isUnhandled(promise)){
-      abrupt = perform(function(){
-        if(isNode){
-          process.emit('unhandledRejection', value, promise);
-        } else if(handler = global.onunhandledrejection){
-          handler({promise: promise, reason: value});
-        } else if((console = global.console) && console.error){
-          console.error('Unhandled promise rejection', value);
-        }
-      });
-      // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
-      promise._h = isNode || isUnhandled(promise) ? 2 : 1;
-    } promise._a = undefined;
-    if(abrupt)throw abrupt.error;
-  });
-};
-var isUnhandled = function(promise){
-  if(promise._h == 1)return false;
-  var chain = promise._a || promise._c
-    , i     = 0
-    , reaction;
-  while(chain.length > i){
-    reaction = chain[i++];
-    if(reaction.fail || !isUnhandled(reaction.promise))return false;
-  } return true;
-};
-var onHandleUnhandled = function(promise){
-  task.call(global, function(){
-    var handler;
-    if(isNode){
-      process.emit('rejectionHandled', promise);
-    } else if(handler = global.onrejectionhandled){
-      handler({promise: promise, reason: promise._v});
-    }
-  });
-};
-var $reject = function(value){
-  var promise = this;
-  if(promise._d)return;
-  promise._d = true;
-  promise = promise._w || promise; // unwrap
-  promise._v = value;
-  promise._s = 2;
-  if(!promise._a)promise._a = promise._c.slice();
-  notify(promise, true);
-};
-var $resolve = function(value){
-  var promise = this
-    , then;
-  if(promise._d)return;
-  promise._d = true;
-  promise = promise._w || promise; // unwrap
-  try {
-    if(promise === value)throw TypeError("Promise can't be resolved itself");
-    if(then = isThenable(value)){
-      microtask(function(){
-        var wrapper = {_w: promise, _d: false}; // wrap
-        try {
-          then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
-        } catch(e){
-          $reject.call(wrapper, e);
-        }
-      });
-    } else {
-      promise._v = value;
-      promise._s = 1;
-      notify(promise, false);
-    }
-  } catch(e){
-    $reject.call({_w: promise, _d: false}, e); // wrap
-  }
-};
-
-// constructor polyfill
-if(!USE_NATIVE){
-  // 25.4.3.1 Promise(executor)
-  $Promise = function Promise(executor){
-    anInstance(this, $Promise, PROMISE, '_h');
-    aFunction(executor);
-    Internal.call(this);
-    try {
-      executor(ctx($resolve, this, 1), ctx($reject, this, 1));
-    } catch(err){
-      $reject.call(this, err);
-    }
-  };
-  Internal = function Promise(executor){
-    this._c = [];             // <- awaiting reactions
-    this._a = undefined;      // <- checked in isUnhandled reactions
-    this._s = 0;              // <- state
-    this._d = false;          // <- done
-    this._v = undefined;      // <- value
-    this._h = 0;              // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
-    this._n = false;          // <- notify
-  };
-  Internal.prototype = require('./_redefine-all')($Promise.prototype, {
-    // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
-    then: function then(onFulfilled, onRejected){
-      var reaction    = newPromiseCapability(speciesConstructor(this, $Promise));
-      reaction.ok     = typeof onFulfilled == 'function' ? onFulfilled : true;
-      reaction.fail   = typeof onRejected == 'function' && onRejected;
-      reaction.domain = isNode ? process.domain : undefined;
-      this._c.push(reaction);
-      if(this._a)this._a.push(reaction);
-      if(this._s)notify(this, false);
-      return reaction.promise;
-    },
-    // 25.4.5.1 Promise.prototype.catch(onRejected)
-    'catch': function(onRejected){
-      return this.then(undefined, onRejected);
-    }
-  });
-  PromiseCapability = function(){
-    var promise  = new Internal;
-    this.promise = promise;
-    this.resolve = ctx($resolve, promise, 1);
-    this.reject  = ctx($reject, promise, 1);
-  };
+if (typeof module === "object") {
+  module.exports = Kinto;
 }
 
-$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: $Promise});
-require('./_set-to-string-tag')($Promise, PROMISE);
-require('./_set-species')(PROMISE);
-Wrapper = require('./_core')[PROMISE];
+},{"../src/KintoBase":3,"../src/utils":7}],2:[function(require,module,exports){
 
-// statics
-$export($export.S + $export.F * !USE_NATIVE, PROMISE, {
-  // 25.4.4.5 Promise.reject(r)
-  reject: function reject(r){
-    var capability = newPromiseCapability(this)
-      , $$reject   = capability.reject;
-    $$reject(r);
-    return capability.promise;
-  }
-});
-$export($export.S + $export.F * (LIBRARY || !USE_NATIVE), PROMISE, {
-  // 25.4.4.6 Promise.resolve(x)
-  resolve: function resolve(x){
-    // instanceof instead of internal slot check because we should fix it without replacement native Promise core
-    if(x instanceof $Promise && sameConstructor(x.constructor, this))return x;
-    var capability = newPromiseCapability(this)
-      , $$resolve  = capability.resolve;
-    $$resolve(x);
-    return capability.promise;
-  }
-});
-$export($export.S + $export.F * !(USE_NATIVE && require('./_iter-detect')(function(iter){
-  $Promise.all(iter)['catch'](empty);
-})), PROMISE, {
-  // 25.4.4.1 Promise.all(iterable)
-  all: function all(iterable){
-    var C          = this
-      , capability = newPromiseCapability(C)
-      , resolve    = capability.resolve
-      , reject     = capability.reject;
-    var abrupt = perform(function(){
-      var values    = []
-        , index     = 0
-        , remaining = 1;
-      forOf(iterable, false, function(promise){
-        var $index        = index++
-          , alreadyCalled = false;
-        values.push(undefined);
-        remaining++;
-        C.resolve(promise).then(function(value){
-          if(alreadyCalled)return;
-          alreadyCalled  = true;
-          values[$index] = value;
-          --remaining || resolve(values);
-        }, reject);
-      });
-      --remaining || resolve(values);
-    });
-    if(abrupt)reject(abrupt.error);
-    return capability.promise;
-  },
-  // 25.4.4.4 Promise.race(iterable)
-  race: function race(iterable){
-    var C          = this
-      , capability = newPromiseCapability(C)
-      , reject     = capability.reject;
-    var abrupt = perform(function(){
-      forOf(iterable, false, function(promise){
-        C.resolve(promise).then(capability.resolve, reject);
-      });
-    });
-    if(abrupt)reject(abrupt.error);
-    return capability.promise;
-  }
-});
-},{"./_a-function":14,"./_an-instance":16,"./_classof":19,"./_core":21,"./_ctx":22,"./_export":27,"./_for-of":29,"./_global":30,"./_is-object":38,"./_iter-detect":42,"./_library":45,"./_microtask":46,"./_redefine-all":58,"./_set-species":60,"./_set-to-string-tag":61,"./_species-constructor":64,"./_task":66,"./_wks":74}],81:[function(require,module,exports){
-'use strict';
-var $at  = require('./_string-at')(true);
-
-// 21.1.3.27 String.prototype[@@iterator]()
-require('./_iter-define')(String, 'String', function(iterated){
-  this._t = String(iterated); // target
-  this._i = 0;                // next index
-// 21.1.5.2.1 %StringIteratorPrototype%.next()
-}, function(){
-  var O     = this._t
-    , index = this._i
-    , point;
-  if(index >= O.length)return {value: undefined, done: true};
-  point = $at(O, index);
-  this._i += point.length;
-  return {value: point, done: false};
-});
-},{"./_iter-define":41,"./_string-at":65}],82:[function(require,module,exports){
-require('./es6.array.iterator');
-var global        = require('./_global')
-  , hide          = require('./_hide')
-  , Iterators     = require('./_iterators')
-  , TO_STRING_TAG = require('./_wks')('toStringTag');
-
-for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){
-  var NAME       = collections[i]
-    , Collection = global[NAME]
-    , proto      = Collection && Collection.prototype;
-  if(proto && !proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME);
-  Iterators[NAME] = Iterators.Array;
-}
-},{"./_global":30,"./_hide":32,"./_iterators":44,"./_wks":74,"./es6.array.iterator":76}],83:[function(require,module,exports){
+},{}],3:[function(require,module,exports){
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
 var _collection = require("./collection");
 
 var _collection2 = _interopRequireDefault(_collection);
 
 var _base = require("./adapters/base");
 
 var _base2 = _interopRequireDefault(_base);
@@ -1955,17 +164,17 @@ class KintoBase {
    *
    * @param  {Object} options The options object.
    */
   constructor(options = {}) {
     const defaults = {
       bucket: DEFAULT_BUCKET_NAME,
       remote: DEFAULT_REMOTE
     };
-    this._options = (0, _extends3.default)({}, defaults, options);
+    this._options = _extends({}, defaults, options);
     if (!this._options.adapter) {
       throw new Error("No adapter provided");
     }
 
     const { remote, events, headers, requestMode, timeout, ApiClass } = this._options;
 
     // public properties
 
@@ -2004,43 +213,33 @@ class KintoBase {
       idSchema: options.idSchema,
       remoteTransformers: options.remoteTransformers,
       hooks: options.hooks
     });
   }
 }
 exports.default = KintoBase;
 
-},{"./adapters/base":85,"./collection":86,"babel-runtime/helpers/extends":8}],84:[function(require,module,exports){
+},{"./adapters/base":5,"./collection":6}],4:[function(require,module,exports){
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 
-var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
-
-var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _keys = require("babel-runtime/core-js/object/keys");
-
-var _keys2 = _interopRequireDefault(_keys);
-
 var _base = require("./base.js");
 
 var _base2 = _interopRequireDefault(_base);
 
 var _utils = require("../utils");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
 const INDEXED_FIELDS = ["id", "_status", "last_modified"];
 
 /**
  * IDB cursor handlers.
  * @type {Object}
  */
 const cursorHandlers = {
   all(filters, done) {
@@ -2093,17 +292,17 @@ const cursorHandlers = {
 /**
  * Extract from filters definition the first indexed field. Since indexes were
  * created on single-columns, extracting a single one makes sense.
  *
  * @param  {Object} filters The filters object.
  * @return {String|undefined}
  */
 function findIndexedField(filters) {
-  const filteredFields = (0, _keys2.default)(filters);
+  const filteredFields = Object.keys(filters);
   const indexedFields = filteredFields.filter(field => {
     return INDEXED_FIELDS.indexOf(field) !== -1;
   });
   return indexedFields[0];
 }
 
 /**
  * Creates an IDB request and attach it the appropriate cursor event handler to
@@ -2170,19 +369,19 @@ class IDB extends _base2.default {
   /**
    * Ensures a connection to the IndexedDB database has been opened.
    *
    * @override
    * @return {Promise}
    */
   open() {
     if (this._db) {
-      return _promise2.default.resolve(this);
+      return Promise.resolve(this);
     }
-    return new _promise2.default((resolve, reject) => {
+    return new Promise((resolve, reject) => {
       const request = indexedDB.open(this.dbname, 1);
       request.onupgradeneeded = event => {
         // DB object
         const db = event.target.result;
         // Main collection store
         const collStore = db.createObjectStore(this.dbname, {
           keyPath: "id"
         });
@@ -2246,20 +445,20 @@ class IDB extends _base2.default {
    * Deletes every records in the current collection.
    *
    * @override
    * @return {Promise}
    */
   clear() {
     var _this = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       try {
         yield _this.open();
-        return new _promise2.default(function (resolve, reject) {
+        return new Promise(function (resolve, reject) {
           const { transaction, store } = _this.prepare("readwrite");
           store.clear();
           transaction.onerror = function (event) {
             return reject(new Error(event.target.error));
           };
           transaction.oncomplete = function () {
             return resolve();
           };
@@ -2298,29 +497,29 @@ class IDB extends _base2.default {
    *
    * @param  {Function} callback The operation description callback.
    * @param  {Object}   options  The options object.
    * @return {Promise}
    */
   execute(callback, options = { preload: [] }) {
     var _this2 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       // Transactions in IndexedDB are autocommited when a callback does not
       // perform any additional operation.
       // The way Promises are implemented in Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=1193394)
       // prevents using within an opened transaction.
       // To avoid managing asynchronocity in the specified `callback`, we preload
       // a list of record in order to execute the `callback` synchronously.
       // See also:
       // - http://stackoverflow.com/a/28388805/330911
       // - http://stackoverflow.com/a/10405196
       // - https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
       yield _this2.open();
-      return new _promise2.default(function (resolve, reject) {
+      return new Promise(function (resolve, reject) {
         // Start transaction.
         const { transaction, store } = _this2.prepare("readwrite");
         // Preload specified records using index.
         const ids = options.preload;
         store.index("id").openCursor().onsuccess = cursorHandlers.in(ids, function (records) {
           // Store obtained records by id.
           const preloaded = records.reduce(function (acc, record) {
             acc[record.id] = record;
@@ -2331,17 +530,17 @@ class IDB extends _base2.default {
           // The callback is executed synchronously within the same transaction.
           let result;
           try {
             result = callback(proxy);
           } catch (e) {
             transaction.abort();
             reject(e);
           }
-          if (result instanceof _promise2.default) {
+          if (result instanceof Promise) {
             // XXX: investigate how to provide documentation details in error.
             reject(new Error("execute() callback should not return a Promise."));
           }
           // XXX unsure if we should manually abort the transaction on error
           transaction.onerror = function (event) {
             return reject(new Error(event.target.error));
           };
           transaction.oncomplete = function (event) {
@@ -2357,20 +556,20 @@ class IDB extends _base2.default {
    *
    * @override
    * @param  {String} id The record id.
    * @return {Promise}
    */
   get(id) {
     var _this3 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       try {
         yield _this3.open();
-        return new _promise2.default(function (resolve, reject) {
+        return new Promise(function (resolve, reject) {
           const { transaction, store } = _this3.prepare();
           const request = store.get(id);
           transaction.onerror = function (event) {
             return reject(new Error(event.target.error));
           };
           transaction.oncomplete = function () {
             return resolve(request.result);
           };
@@ -2385,23 +584,23 @@ class IDB extends _base2.default {
    * Lists all records from the IndexedDB database.
    *
    * @override
    * @return {Promise}
    */
   list(params = { filters: {} }) {
     var _this4 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const { filters } = params;
       const indexField = findIndexedField(filters);
       const value = filters[indexField];
       try {
         yield _this4.open();
-        const results = yield new _promise2.default(function (resolve, reject) {
+        const results = yield new Promise(function (resolve, reject) {
           let results = [];
           // If `indexField` was used already, don't filter again.
           const remainingFilters = (0, _utils.omitKeys)(filters, indexField);
 
           const { transaction, store } = _this4.prepare();
           createListRequest(store, indexField, value, remainingFilters, function (_results) {
             // we have received all requested records, parking them within
             // current scope
@@ -2429,20 +628,20 @@ class IDB extends _base2.default {
    *
    * @override
    * @param  {Number}  lastModified
    * @return {Promise}
    */
   saveLastModified(lastModified) {
     var _this5 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const value = parseInt(lastModified, 10) || null;
       yield _this5.open();
-      return new _promise2.default(function (resolve, reject) {
+      return new Promise(function (resolve, reject) {
         const { transaction, store } = _this5.prepare("readwrite", "__meta__");
         store.put({ name: "lastModified", value: value });
         transaction.onerror = function (event) {
           return reject(event.target.error);
         };
         transaction.oncomplete = function (event) {
           return resolve(value);
         };
@@ -2454,19 +653,19 @@ class IDB extends _base2.default {
    * Retrieve saved lastModified value.
    *
    * @override
    * @return {Promise}
    */
   getLastModified() {
     var _this6 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       yield _this6.open();
-      return new _promise2.default(function (resolve, reject) {
+      return new Promise(function (resolve, reject) {
         const { transaction, store } = _this6.prepare(undefined, "__meta__");
         const request = store.get("lastModified");
         transaction.onerror = function (event) {
           return reject(event.target.error);
         };
         transaction.oncomplete = function (event) {
           resolve(request.result && request.result.value || null);
         };
@@ -2478,17 +677,17 @@ class IDB extends _base2.default {
    * Load a dump of records exported from a server.
    *
    * @abstract
    * @return {Promise}
    */
   loadDump(records) {
     var _this7 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       try {
         yield _this7.execute(function (transaction) {
           records.forEach(function (record) {
             return transaction.update(record);
           });
         });
         const previousLastModified = yield _this7.getLastModified();
         const lastModified = Math.max(...records.map(function (record) {
@@ -2529,54 +728,47 @@ function transactionProxy(store, preload
     },
 
     get(id) {
       return preloaded[id];
     }
   };
 }
 
-},{"../utils":87,"./base.js":85,"babel-runtime/core-js/object/keys":5,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/asyncToGenerator":7}],85:[function(require,module,exports){
+},{"../utils":7,"./base.js":5}],5:[function(require,module,exports){
 "use strict";
 
 /**
  * Base db adapter.
  *
  * @abstract
  */
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
 class BaseAdapter {
   /**
    * Opens a connection to the database.
    *
    * @abstract
    * @return {Promise}
    */
   open() {
-    return _promise2.default.resolve();
+    return Promise.resolve();
   }
 
   /**
    * Closes current connection to the database.
    *
    * @abstract
    * @return {Promise}
    */
   close() {
-    return _promise2.default.resolve();
+    return Promise.resolve();
   }
 
   /**
    * Deletes every records present in the database.
    *
    * @abstract
    * @return {Promise}
    */
@@ -2646,43 +838,25 @@ class BaseAdapter {
    * @return {Promise}
    */
   loadDump(records) {
     throw new Error("Not Implemented.");
   }
 }
 exports.default = BaseAdapter;
 
-},{"babel-runtime/core-js/promise":6}],86:[function(require,module,exports){
+},{}],6:[function(require,module,exports){
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
 exports.CollectionTransaction = exports.SyncResultObject = undefined;
 
-var _stringify = require("babel-runtime/core-js/json/stringify");
-
-var _stringify2 = _interopRequireDefault(_stringify);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
-
-var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-var _assign = require("babel-runtime/core-js/object/assign");
-
-var _assign2 = _interopRequireDefault(_assign);
+var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
 
 exports.recordsEqual = recordsEqual;
 
 var _base = require("./adapters/base");
 
 var _base2 = _interopRequireDefault(_base);
 
 var _IDB = require("./adapters/IDB");
@@ -2690,16 +864,18 @@ var _IDB = require("./adapters/IDB");
 var _IDB2 = _interopRequireDefault(_IDB);
 
 var _utils = require("./utils");
 
 var _uuid = require("uuid");
 
 function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
 
+function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
+
 const RECORD_FIELDS_TO_CLEAN = ["_status"];
 const AVAILABLE_HOOKS = ["incoming-changes"];
 
 /**
  * Compare two records omitting local fields and synchronization
  * attributes (like _status and last_modified)
  * @param {Object} a    A record to compare.
  * @param {Object} b    A record to compare.
@@ -2739,17 +915,17 @@ class SyncResultObject {
    */
   constructor() {
     /**
      * Current synchronization result status; becomes `false` when conflicts or
      * errors are registered.
      * @type {Boolean}
      */
     this.ok = true;
-    (0, _assign2.default)(this, SyncResultObject.defaults);
+    Object.assign(this, SyncResultObject.defaults);
   }
 
   /**
    * Adds entries for a given result type.
    *
    * @param {String} type    The result type.
    * @param {Array}  entries The result entries.
    * @return {SyncResultObject}
@@ -2791,17 +967,17 @@ function createUUIDSchema() {
 
     validate(id) {
       return (0, _utils.isUUID)(id);
     }
   };
 }
 
 function markStatus(record, status) {
-  return (0, _extends3.default)({}, record, { _status: status });
+  return _extends({}, record, { _status: status });
 }
 
 function markDeleted(record) {
   return markStatus(record, "deleted");
 }
 
 function markSynced(record) {
   return markStatus(record, "synced");
@@ -2825,17 +1001,17 @@ function importChange(transaction, remot
     }
     const synced = markSynced(remote);
     transaction.create(synced);
     return { type: "created", data: synced };
   }
   // Compare local and remote, ignoring local fields.
   const isIdentical = recordsEqual(local, remote, localFields);
   // Apply remote changes on local record.
-  const synced = (0, _extends3.default)({}, local, markSynced(remote));
+  const synced = _extends({}, local, markSynced(remote));
   // Detect or ignore conflicts if record has also been modified locally.
   if (local._status !== "synced") {
     // Locally deleted, unsynced: scheduled for remote deletion.
     if (local._status === "deleted") {
       return { type: "skipped", data: local };
     }
     if (isIdentical) {
       // If records are identical, import anyway, so we bump the
@@ -3076,49 +1252,49 @@ class Collection {
    * Deletes every records in the current collection and marks the collection as
    * never synced.
    *
    * @return {Promise}
    */
   clear() {
     var _this = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       yield _this.db.clear();
       yield _this.db.saveLastModified(null);
       return { data: [], permissions: {} };
     })();
   }
 
   /**
    * Encodes a record.
    *
    * @param  {String} type   Either "remote" or "local".
    * @param  {Object} record The record object to encode.
    * @return {Promise}
    */
   _encodeRecord(type, record) {
     if (!this[`${ type }Transformers`].length) {
-      return _promise2.default.resolve(record);
+      return Promise.resolve(record);
     }
     return (0, _utils.waterfall)(this[`${ type }Transformers`].map(transformer => {
       return record => transformer.encode(record);
     }), record);
   }
 
   /**
    * Decodes a record.
    *
    * @param  {String} type   Either "remote" or "local".
    * @param  {Object} record The record object to decode.
    * @return {Promise}
    */
   _decodeRecord(type, record) {
     if (!this[`${ type }Transformers`].length) {
-      return _promise2.default.resolve(record);
+      return Promise.resolve(record);
     }
     return (0, _utils.waterfall)(this[`${ type }Transformers`].reverse().map(transformer => {
       return record => transformer.decode(record);
     }), record);
   }
 
   /**
    * Adds a record to the local database, asserting that none
@@ -3138,27 +1314,27 @@ class Collection {
    * @param  {Object} record
    * @param  {Object} options
    * @return {Promise}
    */
   create(record, options = { useRecordId: false, synced: false }) {
     // Validate the record and its ID (if any), even though this
     // validation is also done in the CollectionTransaction method,
     // because we need to pass the ID to preloadIds.
-    const reject = msg => _promise2.default.reject(new Error(msg));
+    const reject = msg => Promise.reject(new Error(msg));
     if (typeof record !== "object") {
       return reject("Record is not an object.");
     }
     if ((options.synced || options.useRecordId) && !record.hasOwnProperty("id")) {
       return reject("Missing required Id; synced and useRecordId options require one");
     }
     if (!options.synced && !options.useRecordId && record.hasOwnProperty("id")) {
       return reject("Extraneous Id; can't create a record having one set.");
     }
-    const newRecord = (0, _extends3.default)({}, record, {
+    const newRecord = _extends({}, record, {
       id: options.synced || options.useRecordId ? record.id : this.idSchema.generate(),
       _status: options.synced ? "synced" : "created"
     });
     if (!this.idSchema.validate(newRecord.id)) {
       return reject(`Invalid Id: ${ newRecord.id }`);
     }
     return this.execute(txn => txn.create(newRecord), { preloadIds: [newRecord.id] }).catch(err => {
       if (options.useRecordId) {
@@ -3180,46 +1356,46 @@ class Collection {
    * @param  {Object} options
    * @return {Promise}
    */
   update(record, options = { synced: false, patch: false }) {
     // Validate the record and its ID, even though this validation is
     // also done in the CollectionTransaction method, because we need
     // to pass the ID to preloadIds.
     if (typeof record !== "object") {
-      return _promise2.default.reject(new Error("Record is not an object."));
+      return Promise.reject(new Error("Record is not an object."));
     }
     if (!record.hasOwnProperty("id")) {
-      return _promise2.default.reject(new Error("Cannot update a record missing id."));
+      return Promise.reject(new Error("Cannot update a record missing id."));
     }
     if (!this.idSchema.validate(record.id)) {
-      return _promise2.default.reject(new Error(`Invalid Id: ${ record.id }`));
+      return Promise.reject(new Error(`Invalid Id: ${ record.id }`));
     }
 
     return this.execute(txn => txn.update(record, options), { preloadIds: [record.id] });
   }
 
   /**
    * Like {@link CollectionTransaction#upsert}, but wrapped in its own transaction.
    *
    * @param  {Object} record
    * @return {Promise}
    */
   upsert(record) {
     // Validate the record and its ID, even though this validation is
     // also done in the CollectionTransaction method, because we need
     // to pass the ID to preloadIds.
     if (typeof record !== "object") {
-      return _promise2.default.reject(new Error("Record is not an object."));
+      return Promise.reject(new Error("Record is not an object."));
     }
     if (!record.hasOwnProperty("id")) {
-      return _promise2.default.reject(new Error("Cannot update a record missing id."));
+      return Promise.reject(new Error("Cannot update a record missing id."));
     }
     if (!this.idSchema.validate(record.id)) {
-      return _promise2.default.reject(new Error(`Invalid Id: ${ record.id }`));
+      return Promise.reject(new Error(`Invalid Id: ${ record.id }`));
     }
 
     return this.execute(txn => txn.upsert(record), { preloadIds: [record.id] });
   }
 
   /**
    * Like {@link CollectionTransaction#get}, but wrapped in its own transaction.
    *
@@ -3284,18 +1460,18 @@ class Collection {
    *
    * @param  {Object} params  The filters and order to apply to the results.
    * @param  {Object} options The options object.
    * @return {Promise}
    */
   list(params = {}, options = { includeDeleted: false }) {
     var _this2 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
-      params = (0, _extends3.default)({ order: "-last_modified", filters: {} }, params);
+    return _asyncToGenerator(function* () {
+      params = _extends({ order: "-last_modified", filters: {} }, params);
       const results = yield _this2.db.list(params);
       let data = results;
       if (!options.includeDeleted) {
         data = results.filter(function (record) {
           return record._status !== "deleted";
         });
       }
       return { data, permissions: {} };
@@ -3309,17 +1485,17 @@ class Collection {
    * @param  {SyncResultObject} syncResultObject The sync result object.
    * @param  {Array}            decodedChanges   The list of changes to import in the local database.
    * @param  {String}           strategy         The {@link Collection.strategy} (default: MANUAL)
    * @return {Promise}
    */
   importChanges(syncResultObject, decodedChanges, strategy = Collection.strategy.MANUAL) {
     var _this3 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       // Retrieve records matching change ids.
       try {
         const { imports, resolved } = yield _this3.db.execute(function (transaction) {
           const imports = decodedChanges.map(function (remote) {
             // Store remote change into local database.
             return importChange(transaction, remote, _this3.localFields);
           });
           const conflicts = imports.filter(function (i) {
@@ -3364,17 +1540,17 @@ class Collection {
    * @param  {Array}            toApplyLocally   The list of changes to import in the local database.
    * @param  {Array}            conflicts        The list of conflicts that have to be resolved.
    * @param  {String}           strategy         The {@link Collection.strategy}.
    * @return {Promise}
    */
   _applyPushedResults(syncResultObject, toApplyLocally, conflicts, strategy = Collection.strategy.MANUAL) {
     var _this4 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const toDeleteLocally = toApplyLocally.filter(function (r) {
         return r.deleted;
       });
       const toUpdateLocally = toApplyLocally.filter(function (r) {
         return !r.deleted;
       });
 
       const { published, resolved } = yield _this4.db.execute(function (transaction) {
@@ -3442,17 +1618,17 @@ class Collection {
    *   the transaction
    *
    * @return {Promise} Resolves with the result of the given function
    *    when the transaction commits.
    */
   execute(doOperations, { preloadIds = [] } = {}) {
     for (let id of preloadIds) {
       if (!this.idSchema.validate(id)) {
-        return _promise2.default.reject(Error(`Invalid Id: ${ id }`));
+        return Promise.reject(Error(`Invalid Id: ${ id }`));
       }
     }
 
     return this.db.execute(transaction => {
       const txn = new CollectionTransaction(this, transaction);
       const result = doOperations(txn);
       txn.emitEvents();
       return result;
@@ -3466,26 +1642,26 @@ class Collection {
    * A next call to {@link Collection.sync} will thus republish the whole
    * content of the local collection to the server.
    *
    * @return {Promise} Resolves with the number of processed records.
    */
   resetSyncStatus() {
     var _this5 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const unsynced = yield _this5.list({ filters: { _status: ["deleted", "synced"] }, order: "" }, { includeDeleted: true });
       yield _this5.db.execute(function (transaction) {
         unsynced.data.forEach(function (record) {
           if (record._status === "deleted") {
             // Garbage collect deleted records.
             transaction.delete(record.id);
           } else {
             // Records that were synced become «created».
-            transaction.update((0, _extends3.default)({}, record, {
+            transaction.update(_extends({}, record, {
               last_modified: undefined,
               _status: "created"
             }));
           }
         });
       });
       _this5._lastModified = null;
       yield _this5.db.saveLastModified(null);
@@ -3499,22 +1675,22 @@ class Collection {
    * - `toDelete`: unsynced deleted records we can safely delete;
    * - `toSync`: local updates to send to the server.
    *
    * @return {Promise}
    */
   gatherLocalChanges() {
     var _this6 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const unsynced = yield _this6.list({ filters: { _status: ["created", "updated"] }, order: "" });
       const deleted = yield _this6.list({ filters: { _status: "deleted" }, order: "" }, { includeDeleted: true });
 
-      const toSync = yield _promise2.default.all(unsynced.data.map(_this6._encodeRecord.bind(_this6, "remote")));
-      const toDelete = yield _promise2.default.all(deleted.data.map(_this6._encodeRecord.bind(_this6, "remote")));
+      const toSync = yield Promise.all(unsynced.data.map(_this6._encodeRecord.bind(_this6, "remote")));
+      const toDelete = yield Promise.all(deleted.data.map(_this6._encodeRecord.bind(_this6, "remote")));
 
       return { toSync, toDelete };
     })();
   }
 
   /**
    * Fetch remote changes, import them to the local database, and handle
    * conflicts according to `options.strategy`. Then, updates the passed
@@ -3526,24 +1702,24 @@ class Collection {
    * @param  {KintoClient.Collection} client           Kinto client Collection instance.
    * @param  {SyncResultObject}       syncResultObject The sync result object.
    * @param  {Object}                 options
    * @return {Promise}
    */
   pullChanges(client, syncResultObject, options = {}) {
     var _this7 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       if (!syncResultObject.ok) {
         return syncResultObject;
       }
 
       const since = _this7.lastModified ? _this7.lastModified : yield _this7.db.getLastModified();
 
-      options = (0, _extends3.default)({
+      options = _extends({
         strategy: Collection.strategy.MANUAL,
         lastModified: since,
         headers: {}
       }, options);
 
       // Optionally ignore some records when pulling for changes.
       // (avoid redownloading our own changes on last step of #sync())
       let filters;
@@ -3576,17 +1752,17 @@ class Collection {
       const emptyCollection = data.length === 0;
       if (!options.exclude && localSynced && serverChanged && emptyCollection) {
         throw Error("Server has been flushed.");
       }
 
       syncResultObject.lastModified = unquoted;
 
       // Decode incoming changes.
-      const decodedChanges = yield _promise2.default.all(data.map(function (change) {
+      const decodedChanges = yield Promise.all(data.map(function (change) {
         return _this7._decodeRecord("remote", change);
       }));
       // Hook receives decoded records.
       const payload = { lastModified: unquoted, changes: decodedChanges };
       const afterHooks = yield _this7.applyHook("incoming-changes", payload);
 
       // No change, nothing to import.
       if (afterHooks.changes.length > 0) {
@@ -3594,25 +1770,25 @@ class Collection {
         yield _this7.importChanges(syncResultObject, afterHooks.changes, options.strategy);
       }
       return syncResultObject;
     })();
   }
 
   applyHook(hookName, payload) {
     if (typeof this.hooks[hookName] == "undefined") {
-      return _promise2.default.resolve(payload);
+      return Promise.resolve(payload);
     }
     return (0, _utils.waterfall)(this.hooks[hookName].map(hook => {
       return record => {
         const result = hook(payload, this);
         const resultThenable = result && typeof result.then === "function";
         const resultChanges = result && result.hasOwnProperty("changes");
         if (!(resultThenable || resultChanges)) {
-          throw new Error(`Invalid return value for hook: ${ (0, _stringify2.default)(result) } has no 'then()' or 'changes' properties`);
+          throw new Error(`Invalid return value for hook: ${ JSON.stringify(result) } has no 'then()' or 'changes' properties`);
         }
         return result;
       };
     }), payload);
   }
 
   /**
    * Publish local changes to the remote server and updates the passed
@@ -3624,17 +1800,17 @@ class Collection {
    * @param  {Array}                  changes.toDelete The list of records to delete.
    * @param  {Array}                  changes.toSync   The list of records to create/update.
    * @param  {Object}                 options          The options object.
    * @return {Promise}
    */
   pushChanges(client, { toDelete = [], toSync }, syncResultObject, options = {}) {
     var _this8 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       if (!syncResultObject.ok) {
         return syncResultObject;
       }
       const safe = !options.strategy || options.strategy !== Collection.CLIENT_WINS;
 
       // Perform a batch request with every changes.
       const synced = yield client.batch(function (batch) {
         toDelete.forEach(function (r) {
@@ -3651,17 +1827,17 @@ class Collection {
           } else {
             batch.updateRecord(published);
           }
         });
       }, { headers: options.headers, safe, aggregate: true });
 
       // Store outgoing errors into sync result object
       syncResultObject.add("errors", synced.errors.map(function (e) {
-        return (0, _extends3.default)({}, e, { type: "outgoing" });
+        return _extends({}, e, { type: "outgoing" });
       }));
 
       // Store outgoing conflicts into sync result object
       const conflicts = [];
       for (let { type, local, remote } of synced.conflicts) {
         // Note: we ensure that local data are actually available, as they may
         // be missing in the case of a published deletion.
         const safeLocal = local && local.data || { id: remote.id };
@@ -3670,30 +1846,30 @@ class Collection {
         const conflict = { type, local: realLocal, remote: realRemote };
         conflicts.push(conflict);
       }
       syncResultObject.add("conflicts", conflicts);
 
       // Records that must be deleted are either deletions that were pushed
       // to server (published) or deleted records that were never pushed (skipped).
       const missingRemotely = synced.skipped.map(function (r) {
-        return (0, _extends3.default)({}, r, { deleted: true });
+        return _extends({}, r, { deleted: true });
       });
 
       // For created and updated records, the last_modified coming from server
       // will be stored locally.
       // Reflect publication results locally using the response from
       // the batch request.
       const published = synced.published.map(function (c) {
         return c.data;
       });
       const toApplyLocally = published.concat(missingRemotely);
 
       // Apply the decode transformers, if any
-      const decoded = yield _promise2.default.all(toApplyLocally.map(function (record) {
+      const decoded = yield Promise.all(toApplyLocally.map(function (record) {
         return _this8._decodeRecord("remote", record);
       }));
 
       // We have to update the local records with the responses of the server
       // (eg. last_modified values etc.).
       if (decoded.length > 0 || conflicts.length > 0) {
         yield _this8._applyPushedResults(syncResultObject, decoded, conflicts, options.strategy);
       }
@@ -3729,17 +1905,17 @@ class Collection {
       return { data: updated, permissions: {} };
     });
   }
 
   /**
    * @private
    */
   _resolveRaw(conflict, resolution) {
-    const resolved = (0, _extends3.default)({}, resolution, {
+    const resolved = _extends({}, resolution, {
       // Ensure local record has the latest authoritative timestamp
       last_modified: conflict.remote.last_modified
     });
     // If the resolution object is strictly equal to the
     // remote record, then we can mark it as synced locally.
     // Otherwise, mark it as updated (so that the resolution is pushed).
     const synced = (0, _utils.deepEqual)(resolved, conflict.remote);
     return markStatus(resolved, synced ? "synced" : "updated");
@@ -3770,25 +1946,25 @@ class Collection {
     headers: {},
     ignoreBackoff: false,
     bucket: null,
     collection: null,
     remote: null
   }) {
     var _this9 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       const previousRemote = _this9.api.remote;
       if (options.remote) {
         // Note: setting the remote ensures it's valid, throws when invalid.
         _this9.api.remote = options.remote;
       }
       if (!options.ignoreBackoff && _this9.api.backoff > 0) {
         const seconds = Math.ceil(_this9.api.backoff / 1000);
-        return _promise2.default.reject(new Error(`Server is asking clients to back off; retry in ${ seconds }s or use the ignoreBackoff option.`));
+        return Promise.reject(new Error(`Server is asking clients to back off; retry in ${ seconds }s or use the ignoreBackoff option.`));
       }
 
       const client = _this9.api.bucket(options.bucket || _this9.bucket).collection(options.collection || _this9.name);
 
       const result = new SyncResultObject();
       try {
         // Fetch last changes from the server.
         yield _this9.pullChanges(client, result, options);
@@ -3800,24 +1976,24 @@ class Collection {
         // Publish local changes and pull local resolutions
         yield _this9.pushChanges(client, { toDelete, toSync }, result, options);
 
         // Publish local resolution of push conflicts to server (on CLIENT_WINS)
         const resolvedUnsynced = result.resolved.filter(function (r) {
           return r._status !== "synced";
         });
         if (resolvedUnsynced.length > 0) {
-          const resolvedEncoded = yield _promise2.default.all(resolvedUnsynced.map(_this9._encodeRecord.bind(_this9, "remote")));
+          const resolvedEncoded = yield Promise.all(resolvedUnsynced.map(_this9._encodeRecord.bind(_this9, "remote")));
           yield _this9.pushChanges(client, { toSync: resolvedEncoded }, result, options);
         }
         // Perform a last pull to catch changes that occured after the last pull,
         // while local changes were pushed. Do not do it nothing was pushed.
         if (result.published.length > 0) {
           // Avoid redownloading our own changes during the last pull.
-          const pullOpts = (0, _extends3.default)({}, options, { lastModified, exclude: result.published });
+          const pullOpts = _extends({}, options, { lastModified, exclude: result.published });
           yield _this9.pullChanges(client, result, pullOpts);
         }
 
         // Don't persist lastModified value if any conflict or error occured
         if (result.ok) {
           // No conflict occured, persist collection's lastModified value
           _this9._lastModified = yield _this9.db.saveLastModified(result.lastModified);
         }
@@ -3836,28 +2012,28 @@ class Collection {
    * or superior to those being loaded will be ignored.
    *
    * @param  {Array} records The previously exported list of records to load.
    * @return {Promise} with the effectively imported records.
    */
   loadDump(records) {
     var _this10 = this;
 
-    return (0, _asyncToGenerator3.default)(function* () {
+    return _asyncToGenerator(function* () {
       if (!Array.isArray(records)) {
         throw new Error("Records is not an array.");
       }
 
       for (let record of records) {
         if (!record.hasOwnProperty("id") || !_this10.idSchema.validate(record.id)) {
-          throw new Error("Record has invalid ID: " + (0, _stringify2.default)(record));
+          throw new Error("Record has invalid ID: " + JSON.stringify(record));
         }
 
         if (!record.last_modified) {
-          throw new Error("Record has no last_modified value: " + (0, _stringify2.default)(record));
+          throw new Error("Record has no last_modified value: " + JSON.stringify(record));
         }
       }
 
       // Fetch all existing records from local database,
       // and skip those who are newer or not marked as synced.
 
       // XXX filter by status / ids in records
 
@@ -3910,17 +2086,17 @@ class CollectionTransaction {
    * Emit queued events, to be called once every transaction operations have
    * been executed successfully.
    */
   emitEvents() {
     for (let { action, payload } of this._events) {
       this.collection.events.emit(action, payload);
     }
     if (this._events.length > 0) {
-      const targets = this._events.map(({ action, payload }) => (0, _extends3.default)({ action }, payload));
+      const targets = this._events.map(({ action, payload }) => _extends({ action }, payload));
       this.collection.events.emit("change", { targets });
     }
     this._events = [];
   }
 
   /**
    * Retrieve a record by its id from the local database, or
    * undefined if none exists.
@@ -3991,17 +2167,17 @@ class CollectionTransaction {
    * @return {Object}
    */
   deleteAny(id) {
     const existing = this.adapterTransaction.get(id);
     if (existing) {
       this.adapterTransaction.update(markDeleted(existing));
       this._queueEvent("delete", { data: existing });
     }
-    return { data: (0, _extends3.default)({ id }, existing), deleted: !!existing, permissions: {} };
+    return { data: _extends({ id }, existing), deleted: !!existing, permissions: {} };
   }
 
   /**
    * Adds a record to the local database, asserting that none
    * already exist with this ID.
    *
    * @param  {Object} record, which must contain an ID
    * @return {Object}
@@ -4044,33 +2220,33 @@ class CollectionTransaction {
     if (!this.collection.idSchema.validate(record.id)) {
       throw new Error(`Invalid Id: ${ record.id }`);
     }
 
     const oldRecord = this.adapterTransaction.get(record.id);
     if (!oldRecord) {
       throw new Error(`Record with id=${ record.id } not found.`);
     }
-    const newRecord = options.patch ? (0, _extends3.default)({}, oldRecord, record) : record;
+    const newRecord = options.patch ? _extends({}, oldRecord, record) : record;
     const updated = this._updateRaw(oldRecord, newRecord, options);
     this.adapterTransaction.update(updated);
     this._queueEvent("update", { data: updated, oldRecord });
     return { data: updated, oldRecord, permissions: {} };
   }
 
   /**
    * Lower-level primitive for updating a record while respecting
    * _status and last_modified.
    *
    * @param  {Object} oldRecord: the record retrieved from the DB
    * @param  {Object} newRecord: the record to replace it with
    * @return {Object}
    */
   _updateRaw(oldRecord, newRecord, { synced = false } = {}) {
-    const updated = (0, _extends3.default)({}, newRecord);
+    const updated = _extends({}, newRecord);
     // Make sure to never loose the existing timestamp.
     if (oldRecord && oldRecord.last_modified && !updated.last_modified) {
       updated.last_modified = oldRecord.last_modified;
     }
     // If only local fields have changed, then keep record as synced.
     // If status is created, keep record as created.
     // If status is deleted, mark as updated.
     const isIdentical = oldRecord && recordsEqual(oldRecord, updated, this.localFields);
@@ -4113,42 +2289,29 @@ class CollectionTransaction {
     } else {
       this._queueEvent("create", { data: updated });
     }
     return { data: updated, oldRecord, permissions: {} };
   }
 }
 exports.CollectionTransaction = CollectionTransaction;
 
-},{"./adapters/IDB":84,"./adapters/base":85,"./utils":87,"babel-runtime/core-js/json/stringify":3,"babel-runtime/core-js/object/assign":4,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/asyncToGenerator":7,"babel-runtime/helpers/extends":8,"uuid":9}],87:[function(require,module,exports){
+},{"./adapters/IDB":4,"./adapters/base":5,"./utils":7,"uuid":2}],7:[function(require,module,exports){
 "use strict";
 
 Object.defineProperty(exports, "__esModule", {
   value: true
 });
-exports.RE_UUID = undefined;
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _keys = require("babel-runtime/core-js/object/keys");
-
-var _keys2 = _interopRequireDefault(_keys);
-
 exports.sortObjects = sortObjects;
 exports.filterObject = filterObject;
 exports.filterObjects = filterObjects;
 exports.isUUID = isUUID;
 exports.waterfall = waterfall;
 exports.deepEqual = deepEqual;
 exports.omitKeys = omitKeys;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
 const RE_UUID = exports.RE_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
 
 /**
  * Checks if a value is undefined.
  * @param  {Any}  value
  * @return {Boolean}
  */
 function _isUndefined(value) {
@@ -4183,17 +2346,17 @@ function sortObjects(order, list) {
 /**
  * Test if a single object matches all given filters.
  *
  * @param  {Object} filters  The filters object.
  * @param  {Object} entry    The object to filter.
  * @return {Function}
  */
 function filterObject(filters, entry) {
-  return (0, _keys2.default)(filters).every(filter => {
+  return Object.keys(filters).every(filter => {
     const value = filters[filter];
     if (Array.isArray(value)) {
       return value.some(candidate => candidate === entry[filter]);
     }
     return entry[filter] === value;
   });
 }
 
@@ -4225,21 +2388,21 @@ function isUUID(uuid) {
  * case of async, functions must return a promise.
  *
  * @param  {Array} fns  The list of functions.
  * @param  {Any}   init The initial value.
  * @return {Promise}
  */
 function waterfall(fns, init) {
   if (!fns.length) {
-    return _promise2.default.resolve(init);
+    return Promise.resolve(init);
   }
   return fns.reduce((promise, nextFn) => {
     return promise.then(nextFn);
-  }, _promise2.default.resolve(init));
+  }, Promise.resolve(init));
 }
 
 /**
  * Simple deep object comparison function. This only supports comparison of
  * serializable JavaScript objects.
  *
  * @param  {Object} a The source object.
  * @param  {Object} b The compared object.
@@ -4250,17 +2413,17 @@ function deepEqual(a, b) {
     return true;
   }
   if (typeof a !== typeof b) {
     return false;
   }
   if (!(a && typeof a == "object") || !(b && typeof b == "object")) {
     return false;
   }
-  if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) {
+  if (Object.keys(a).length !== Object.keys(b).length) {
     return false;
   }
   for (let k in a) {
     if (!deepEqual(a[k], b[k])) {
       return false;
     }
   }
   return true;
@@ -4269,18 +2432,18 @@ function deepEqual(a, b) {
 /**
  * Return an object without the specified keys.
  *
  * @param  {Object} obj        The original object.
  * @param  {Array}  keys       The list of keys to exclude.
  * @return {Object}            A copy without the specified keys.
  */
 function omitKeys(obj, keys = []) {
-  return (0, _keys2.default)(obj).reduce((acc, key) => {
+  return Object.keys(obj).reduce((acc, key) => {
     if (keys.indexOf(key) === -1) {
       acc[key] = obj[key];
     }
     return acc;
   }, {});
 }
 
-},{"babel-runtime/core-js/object/keys":5,"babel-runtime/core-js/promise":6}]},{},[2])(2)
+},{}]},{},[1])(1)
 });
\ No newline at end of file
copy from services/common/kinto-offline-client.js
copy to services/common/kinto-storage-adapter.js
--- a/services/common/kinto-offline-client.js
+++ b/services/common/kinto-storage-adapter.js
@@ -1,80 +1,113 @@
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * This file is generated from kinto.js - do not modify directly.
- */
-
-this.EXPORTED_SYMBOLS = ["loadKinto"];
-
-/*
- * Version 5.1.0 - 8beb61d
- */
-
-(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.loadKinto = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-var _stringify = require("babel-runtime/core-js/json/stringify");
-
-var _stringify2 = _interopRequireDefault(_stringify);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-exports.reduceRecords = reduceRecords;
-
-var _base = require("../src/adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
-
-var _utils = require("../src/utils");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
 /*
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
  * You may obtain a copy of the License at
  *
  *     http://www.apache.org/licenses/LICENSE-2.0
  *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-Components.utils.import("resource://gre/modules/Sqlite.jsm");
-Components.utils.import("resource://gre/modules/Task.jsm");
+const { utils: Cu } = Components;
+const { Sqlite } = Cu.import("resource://gre/modules/Sqlite.jsm");
+const { Task } = Cu.import("resource://gre/modules/Task.jsm");
+const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js");
 
 const SQLITE_PATH = "kinto.sqlite";
 
+/**
+ * Filter and sort list against provided filters and order.
+ *
+ * @param  {Object} filters  The filters to apply.
+ * @param  {String} order    The order to apply.
+ * @param  {Array}  list     The list to reduce.
+ * @return {Array}
+ */
+function reduceRecords(filters, order, list) {
+  const filtered = filters ? filterObjects(filters, list) : list;
+  return order ? sortObjects(order, filtered) : filtered;
+}
+
+/**
+ * Checks if a value is undefined.
+ *
+ * This is a copy of `_isUndefined` from kinto.js/src/utils.js.
+ * @param  {Any}  value
+ * @return {Boolean}
+ */
+function _isUndefined(value) {
+  return typeof value === "undefined";
+}
+
+/**
+ * Sorts records in a list according to a given ordering.
+ *
+ * This is a copy of `sortObjects` from kinto.js/src/utils.js.
+ *
+ * @param  {String} order The ordering, eg. `-last_modified`.
+ * @param  {Array}  list  The collection to order.
+ * @return {Array}
+ */
+function sortObjects(order, list) {
+  const hasDash = order[0] === "-";
+  const field = hasDash ? order.slice(1) : order;
+  const direction = hasDash ? -1 : 1;
+  return list.slice().sort((a, b) => {
+    if (a[field] && _isUndefined(b[field])) {
+      return direction;
+    }
+    if (b[field] && _isUndefined(a[field])) {
+      return -direction;
+    }
+    if (_isUndefined(a[field]) && _isUndefined(b[field])) {
+      return 0;
+    }
+    return a[field] > b[field] ? direction : -direction;
+  });
+}
+
+/**
+ * Test if a single object matches all given filters.
+ *
+ * This is a copy of `filterObject` from kinto.js/src/utils.js.
+ *
+ * @param  {Object} filters  The filters object.
+ * @param  {Object} entry    The object to filter.
+ * @return {Function}
+ */
+function filterObject(filters, entry) {
+  return Object.keys(filters).every(filter => {
+    const value = filters[filter];
+    if (Array.isArray(value)) {
+      return value.some(candidate => candidate === entry[filter]);
+    }
+    return entry[filter] === value;
+  });
+}
+
+/**
+ * Filters records in a list matching all given filters.
+ *
+ * This is a copy of `filterObjects` from kinto.js/src/utils.js.
+ *
+ * @param  {Object} filters  The filters object.
+ * @param  {Array}  list     The collection to filter.
+ * @return {Array}
+ */
+function filterObjects(filters, list) {
+  return list.filter((entry) => {
+    return filterObject(filters, entry);
+  });
+}
+
 const statements = {
   "createCollectionData": `
     CREATE TABLE collection_data (
       collection_name TEXT,
       record_id TEXT,
       record TEXT
     );`,
 
@@ -134,35 +167,37 @@ const statements = {
           AND record_id IN `,
 
   "importData": `
     REPLACE INTO collection_data (collection_name, record_id, record)
       VALUES (:collection_name, :record_id, :record);`,
 
   "scanAllRecords": `SELECT * FROM collection_data;`,
 
-  "clearCollectionMetadata": `DELETE FROM collection_metadata;`
+  "clearCollectionMetadata": `DELETE FROM collection_metadata;`,
 };
 
-const createStatements = ["createCollectionData", "createCollectionMetadata", "createCollectionDataRecordIdIndex"];
+const createStatements = ["createCollectionData",
+                          "createCollectionMetadata",
+                          "createCollectionDataRecordIdIndex"];
 
 const currentSchemaVersion = 1;
 
 /**
  * Firefox adapter.
  *
  * Uses Sqlite as a backing store.
  *
  * Options:
  *  - path: the filename/path for the Sqlite database. If absent, use SQLITE_PATH.
  */
-class FirefoxAdapter extends _base2.default {
-  constructor(collection, options = {}) {
+class FirefoxAdapter extends Kinto.adapters.BaseAdapter {
+  constructor(collection, options={}) {
     super();
-    const { sqliteHandle = null } = options;
+    const {sqliteHandle=null} = options;
     this.collection = collection;
     this._connection = sqliteHandle;
     this._options = options;
   }
 
   // We need to be capable of calling this from "outside" the adapter
   // so that someone can initialize a connection and pass it to us in
   // adapterOptions.
@@ -181,108 +216,117 @@ class FirefoxAdapter extends _base2.defa
         } else if (schema != 1) {
           throw new Error("Unknown database schema: " + schema);
         }
       });
       return connection;
     });
   }
 
-  _executeStatement(statement, params) {
+  _executeStatement(statement, params){
     if (!this._connection) {
       throw new Error("The storage adapter is not open");
     }
     return this._connection.executeCached(statement, params);
   }
 
+
   open() {
     const self = this;
-    return Task.spawn(function* () {
+    return Task.spawn(function* (){
       if (!self._connection) {
         const path = self._options.path || SQLITE_PATH;
         const opts = { path, sharedMemoryCache: false };
         self._connection = yield Sqlite.openConnection(opts).then(FirefoxAdapter._init);
       }
     });
   }
 
   close() {
     if (this._connection) {
       const promise = this._connection.close();
       this._connection = null;
       return promise;
     }
-    return _promise2.default.resolve();
+    return Promise.resolve();
   }
 
   clear() {
-    const params = { collection_name: this.collection };
+    const params = {collection_name: this.collection};
     return this._executeStatement(statements.clearData, params);
   }
 
-  execute(callback, options = { preload: [] }) {
+  execute(callback, options={preload: []}) {
     if (!this._connection) {
       throw new Error("The storage adapter is not open");
     }
 
     let result;
     const conn = this._connection;
     const collection = this.collection;
 
     return conn.executeTransaction(function* doExecuteTransaction() {
       // Preload specified records from DB, within transaction.
-      const parameters = [collection, ...options.preload];
+      const parameters = [
+        collection,
+        ...options.preload
+      ];
       const placeholders = options.preload.map(_ => "?");
       const stmt = statements.listRecordsById + "(" + placeholders.join(",") + ");";
-      const rows = yield conn.execute(stmt, parameters);
+      const rows = yield conn.execute(stmt,
+                                      parameters);
 
       const preloaded = rows.reduce((acc, row) => {
         const record = JSON.parse(row.getResultByName("record"));
         acc[row.getResultByName("record_id")] = record;
         return acc;
       }, {});
 
       const proxy = transactionProxy(collection, preloaded);
       result = callback(proxy);
 
-      for (let { statement, params } of proxy.operations) {
+      for (let {statement, params} of proxy.operations) {
         yield conn.executeCached(statement, params);
       }
-    }, conn.TRANSACTION_EXCLUSIVE).then(_ => result);
+    }, conn.TRANSACTION_EXCLUSIVE)
+    .then(_ => result);
   }
 
   get(id) {
     const params = {
       collection_name: this.collection,
-      record_id: id
+      record_id: id,
     };
-    return this._executeStatement(statements.getRecord, params).then(result => {
-      if (result.length == 0) {
-        return;
-      }
-      return JSON.parse(result[0].getResultByName("record"));
-    });
+    return this._executeStatement(statements.getRecord, params)
+      .then(result => {
+        if (result.length == 0) {
+          return;
+        }
+        return JSON.parse(result[0].getResultByName("record"));
+      });
   }
 
-  list(params = { filters: {}, order: "" }) {
+  list(params={filters: {}, order: ""}) {
     const parameters = {
-      collection_name: this.collection
+      collection_name: this.collection,
     };
-    return this._executeStatement(statements.listRecords, parameters).then(result => {
-      const records = [];
-      for (let k = 0; k < result.length; k++) {
-        const row = result[k];
-        records.push(JSON.parse(row.getResultByName("record")));
-      }
-      return records;
-    }).then(results => {
-      // The resulting list of records is filtered and sorted.
-      // XXX: with some efforts, this could be implemented using SQL.
-      return reduceRecords(params.filters, params.order, results);
-    });
+    return this._executeStatement(statements.listRecords, parameters)
+      .then(result => {
+        const records = [];
+        for (let k = 0; k < result.length; k++) {
+          const row = result[k];
+          records.push(JSON.parse(row.getResultByName("record")));
+        }
+        return records;
+      })
+      .then(results => {
+        // The resulting list of records is filtered and sorted.
+        // XXX: with some efforts, this could be implemented using SQL.
+        return reduceRecords(params.filters, params.order, results);
+      });
   }
 
   /**
    * Load a list of records into the local database.
    *
    * Note: The adapter is not in charge of filtering the already imported
    * records. This is done in `Collection#loadDump()`, as a common behaviour
    * between every adapters.
@@ -294,121 +338,126 @@ class FirefoxAdapter extends _base2.defa
     const connection = this._connection;
     const collection_name = this.collection;
     return Task.spawn(function* () {
       yield connection.executeTransaction(function* doImport() {
         for (let record of records) {
           const params = {
             collection_name: collection_name,
             record_id: record.id,
-            record: (0, _stringify2.default)(record)
+            record: JSON.stringify(record)
           };
           yield connection.execute(statements.importData, params);
         }
         const lastModified = Math.max(...records.map(record => record.last_modified));
         const params = {
           collection_name: collection_name
         };
-        const previousLastModified = yield connection.execute(statements.getLastModified, params).then(result => {
-          return result.length > 0 ? result[0].getResultByName("last_modified") : -1;
-        });
+        const previousLastModified = yield connection.execute(
+          statements.getLastModified, params).then(result => {
+            return result.length > 0 ?
+              result[0].getResultByName("last_modified") : -1;
+          });
         if (lastModified > previousLastModified) {
           const params = {
             collection_name: collection_name,
             last_modified: lastModified
           };
           yield connection.execute(statements.saveLastModified, params);
         }
       });
       return records;
     });
   }
 
   saveLastModified(lastModified) {
     const parsedLastModified = parseInt(lastModified, 10) || null;
     const params = {
       collection_name: this.collection,
-      last_modified: parsedLastModified
+      last_modified: parsedLastModified,
     };
-    return this._executeStatement(statements.saveLastModified, params).then(() => parsedLastModified);
+    return this._executeStatement(statements.saveLastModified, params)
+           .then(() => parsedLastModified);
   }
 
   getLastModified() {
     const params = {
-      collection_name: this.collection
+      collection_name: this.collection,
     };
-    return this._executeStatement(statements.getLastModified, params).then(result => {
-      if (result.length == 0) {
-        return 0;
-      }
-      return result[0].getResultByName("last_modified");
-    });
+    return this._executeStatement(statements.getLastModified, params)
+      .then(result => {
+        if (result.length == 0) {
+          return 0;
+        }
+        return result[0].getResultByName("last_modified");
+      });
   }
 
   /**
    * Reset the sync status of every record and collection we have
    * access to.
    */
   resetSyncStatus() {
     // We're going to use execute instead of executeCached, so build
     // in our own sanity check
     if (!this._connection) {
       throw new Error("The storage adapter is not open");
     }
 
     return this._connection.executeTransaction(function* (conn) {
       const promises = [];
-      yield conn.execute(statements.scanAllRecords, null, function (row) {
+      yield conn.execute(statements.scanAllRecords, null, function(row) {
         const record = JSON.parse(row.getResultByName("record"));
         const record_id = row.getResultByName("record_id");
         const collection_name = row.getResultByName("collection_name");
         if (record._status === "deleted") {
           // Garbage collect deleted records.
-          promises.push(conn.execute(statements.deleteData, { collection_name, record_id }));
-        } else {
-          const newRecord = (0, _extends3.default)({}, record, {
+          promises.push(conn.execute(statements.deleteData, {collection_name, record_id}));
+        }
+        else {
+          const newRecord = Object.assign({}, record, {
             _status: "created",
-            last_modified: undefined
+            last_modified: undefined,
           });
-          promises.push(conn.execute(statements.updateData, { record: (0, _stringify2.default)(newRecord), record_id, collection_name }));
+          promises.push(conn.execute(statements.updateData, {record: JSON.stringify(newRecord), record_id, collection_name}));
         }
       });
-      yield _promise2.default.all(promises);
+      yield Promise.all(promises);
       yield conn.execute(statements.clearCollectionMetadata);
     });
   }
 }
 
-exports.default = FirefoxAdapter;
+
 function transactionProxy(collection, preloaded) {
   const _operations = [];
 
   return {
     get operations() {
       return _operations;
     },
 
     create(record) {
       _operations.push({
         statement: statements.createData,
         params: {
           collection_name: collection,
           record_id: record.id,
-          record: (0, _stringify2.default)(record)
+          record: JSON.stringify(record)
         }
       });
     },
 
     update(record) {
       _operations.push({
         statement: statements.updateData,
         params: {
           collection_name: collection,
           record_id: record.id,
-          record: (0, _stringify2.default)(record)
+          record: JSON.stringify(record)
         }
       });
     },
 
     delete(id) {
       _operations.push({
         statement: statements.deleteData,
         params: {
@@ -419,3868 +468,11 @@ function transactionProxy(collection, pr
     },
 
     get(id) {
       // Gecko JS engine outputs undesired warnings if id is not in preloaded.
       return id in preloaded ? preloaded[id] : undefined;
     }
   };
 }
-
-/**
- * Filter and sort list against provided filters and order.
- *
- * @param  {Object} filters  The filters to apply.
- * @param  {String} order    The order to apply.
- * @param  {Array}  list     The list to reduce.
- * @return {Array}
- */
-function reduceRecords(filters, order, list) {
-  const filtered = filters ? (0, _utils.filterObjects)(filters, list) : list;
-  return order ? (0, _utils.sortObjects)(order, filtered) : filtered;
-}
-
-},{"../src/adapters/base":85,"../src/utils":87,"babel-runtime/core-js/json/stringify":3,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/extends":8}],2:[function(require,module,exports){
-/*
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-exports.default = loadKinto;
-
-var _base = require("../src/adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
-
-var _KintoBase = require("../src/KintoBase");
-
-var _KintoBase2 = _interopRequireDefault(_KintoBase);
-
-var _FirefoxStorage = require("./FirefoxStorage");
-
-var _FirefoxStorage2 = _interopRequireDefault(_FirefoxStorage);
-
-var _utils = require("../src/utils");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
-
-function loadKinto() {
-  const { EventEmitter } = Cu.import("resource://devtools/shared/event-emitter.js", {});
-  const { generateUUID } = Cc["@mozilla.org/uuid-generator;1"].getService(Ci.nsIUUIDGenerator);
-
-  // Use standalone kinto-http module landed in FFx.
-  const { KintoHttpClient } = Cu.import("resource://services-common/kinto-http-client.js");
-
-  Cu.import("resource://gre/modules/Timer.jsm");
-  Cu.importGlobalProperties(['fetch']);
-
-  // Leverage Gecko service to generate UUIDs.
-  function makeIDSchema() {
-    return {
-      validate: _utils.RE_UUID.test.bind(_utils.RE_UUID),
-      generate: function () {
-        return generateUUID().toString().replace(/[{}]/g, "");
-      }
-    };
-  }
-
-  class KintoFX extends _KintoBase2.default {
-    static get adapters() {
-      return {
-        BaseAdapter: _base2.default,
-        FirefoxAdapter: _FirefoxStorage2.default
-      };
-    }
-
-    constructor(options = {}) {
-      const emitter = {};
-      EventEmitter.decorate(emitter);
-
-      const defaults = {
-        events: emitter,
-        ApiClass: KintoHttpClient,
-        adapter: _FirefoxStorage2.default
-      };
-
-      const expandedOptions = (0, _extends3.default)({}, defaults, options);
-      super(expandedOptions);
-    }
-
-    collection(collName, options = {}) {
-      const idSchema = makeIDSchema();
-      const expandedOptions = (0, _extends3.default)({ idSchema }, options);
-      return super.collection(collName, expandedOptions);
-    }
-  }
-
-  return KintoFX;
-}
-
-// This fixes compatibility with CommonJS required by browserify.
-// See http://stackoverflow.com/questions/33505992/babel-6-changes-how-it-exports-default/33683495#33683495
-if (typeof module === "object") {
-  module.exports = loadKinto;
-}
-
-},{"../src/KintoBase":83,"../src/adapters/base":85,"../src/utils":87,"./FirefoxStorage":1,"babel-runtime/helpers/extends":8}],3:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/json/stringify"), __esModule: true };
-},{"core-js/library/fn/json/stringify":10}],4:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/object/assign"), __esModule: true };
-},{"core-js/library/fn/object/assign":11}],5:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/object/keys"), __esModule: true };
-},{"core-js/library/fn/object/keys":12}],6:[function(require,module,exports){
-module.exports = { "default": require("core-js/library/fn/promise"), __esModule: true };
-},{"core-js/library/fn/promise":13}],7:[function(require,module,exports){
-"use strict";
-
-exports.__esModule = true;
-
-var _promise = require("../core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = function (fn) {
-  return function () {
-    var gen = fn.apply(this, arguments);
-    return new _promise2.default(function (resolve, reject) {
-      function step(key, arg) {
-        try {
-          var info = gen[key](arg);
-          var value = info.value;
-        } catch (error) {
-          reject(error);
-          return;
-        }
-
-        if (info.done) {
-          resolve(value);
-        } else {
-          return _promise2.default.resolve(value).then(function (value) {
-            return step("next", value);
-          }, function (err) {
-            return step("throw", err);
-          });
-        }
-      }
-
-      return step("next");
-    });
-  };
-};
-},{"../core-js/promise":6}],8:[function(require,module,exports){
-"use strict";
-
-exports.__esModule = true;
-
-var _assign = require("../core-js/object/assign");
-
-var _assign2 = _interopRequireDefault(_assign);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-exports.default = _assign2.default || function (target) {
-  for (var i = 1; i < arguments.length; i++) {
-    var source = arguments[i];
-
-    for (var key in source) {
-      if (Object.prototype.hasOwnProperty.call(source, key)) {
-        target[key] = source[key];
-      }
-    }
-  }
-
-  return target;
-};
-},{"../core-js/object/assign":4}],9:[function(require,module,exports){
-
-},{}],10:[function(require,module,exports){
-var core  = require('../../modules/_core')
-  , $JSON = core.JSON || (core.JSON = {stringify: JSON.stringify});
-module.exports = function stringify(it){ // eslint-disable-line no-unused-vars
-  return $JSON.stringify.apply($JSON, arguments);
-};
-},{"../../modules/_core":21}],11:[function(require,module,exports){
-require('../../modules/es6.object.assign');
-module.exports = require('../../modules/_core').Object.assign;
-},{"../../modules/_core":21,"../../modules/es6.object.assign":77}],12:[function(require,module,exports){
-require('../../modules/es6.object.keys');
-module.exports = require('../../modules/_core').Object.keys;
-},{"../../modules/_core":21,"../../modules/es6.object.keys":78}],13:[function(require,module,exports){
-require('../modules/es6.object.to-string');
-require('../modules/es6.string.iterator');
-require('../modules/web.dom.iterable');
-require('../modules/es6.promise');
-module.exports = require('../modules/_core').Promise;
-},{"../modules/_core":21,"../modules/es6.object.to-string":79,"../modules/es6.promise":80,"../modules/es6.string.iterator":81,"../modules/web.dom.iterable":82}],14:[function(require,module,exports){
-module.exports = function(it){
-  if(typeof it != 'function')throw TypeError(it + ' is not a function!');
-  return it;
-};
-},{}],15:[function(require,module,exports){
-module.exports = function(){ /* empty */ };
-},{}],16:[function(require,module,exports){
-module.exports = function(it, Constructor, name, forbiddenField){
-  if(!(it instanceof Constructor) || (forbiddenField !== undefined && forbiddenField in it)){
-    throw TypeError(name + ': incorrect invocation!');
-  } return it;
-};
-},{}],17:[function(require,module,exports){
-var isObject = require('./_is-object');
-module.exports = function(it){
-  if(!isObject(it))throw TypeError(it + ' is not an object!');
-  return it;
-};
-},{"./_is-object":38}],18:[function(require,module,exports){
-// false -> Array#indexOf
-// true  -> Array#includes
-var toIObject = require('./_to-iobject')
-  , toLength  = require('./_to-length')
-  , toIndex   = require('./_to-index');
-module.exports = function(IS_INCLUDES){
-  return function($this, el, fromIndex){
-    var O      = toIObject($this)
-      , length = toLength(O.length)
-      , index  = toIndex(fromIndex, length)
-      , value;
-    // Array#includes uses SameValueZero equality algorithm
-    if(IS_INCLUDES && el != el)while(length > index){
-      value = O[index++];
-      if(value != value)return true;
-    // Array#toIndex ignores holes, Array#includes - not
-    } else for(;length > index; index++)if(IS_INCLUDES || index in O){
-      if(O[index] === el)return IS_INCLUDES || index || 0;
-    } return !IS_INCLUDES && -1;
-  };
-};
-},{"./_to-index":67,"./_to-iobject":69,"./_to-length":70}],19:[function(require,module,exports){
-// getting tag from 19.1.3.6 Object.prototype.toString()
-var cof = require('./_cof')
-  , TAG = require('./_wks')('toStringTag')
-  // ES3 wrong here
-  , ARG = cof(function(){ return arguments; }()) == 'Arguments';
-
-// fallback for IE11 Script Access Denied error
-var tryGet = function(it, key){
-  try {
-    return it[key];
-  } catch(e){ /* empty */ }
-};
-
-module.exports = function(it){
-  var O, T, B;
-  return it === undefined ? 'Undefined' : it === null ? 'Null'
-    // @@toStringTag case
-    : typeof (T = tryGet(O = Object(it), TAG)) == 'string' ? T
-    // builtinTag case
-    : ARG ? cof(O)
-    // ES3 arguments fallback
-    : (B = cof(O)) == 'Object' && typeof O.callee == 'function' ? 'Arguments' : B;
-};
-},{"./_cof":20,"./_wks":74}],20:[function(require,module,exports){
-var toString = {}.toString;
-
-module.exports = function(it){
-  return toString.call(it).slice(8, -1);
-};
-},{}],21:[function(require,module,exports){
-var core = module.exports = {version: '2.4.0'};
-if(typeof __e == 'number')__e = core; // eslint-disable-line no-undef
-},{}],22:[function(require,module,exports){
-// optional / simple context binding
-var aFunction = require('./_a-function');
-module.exports = function(fn, that, length){
-  aFunction(fn);
-  if(that === undefined)return fn;
-  switch(length){
-    case 1: return function(a){
-      return fn.call(that, a);
-    };
-    case 2: return function(a, b){
-      return fn.call(that, a, b);
-    };
-    case 3: return function(a, b, c){
-      return fn.call(that, a, b, c);
-    };
-  }
-  return function(/* ...args */){
-    return fn.apply(that, arguments);
-  };
-};
-},{"./_a-function":14}],23:[function(require,module,exports){
-// 7.2.1 RequireObjectCoercible(argument)
-module.exports = function(it){
-  if(it == undefined)throw TypeError("Can't call method on  " + it);
-  return it;
-};
-},{}],24:[function(require,module,exports){
-// Thank's IE8 for his funny defineProperty
-module.exports = !require('./_fails')(function(){
-  return Object.defineProperty({}, 'a', {get: function(){ return 7; }}).a != 7;
-});
-},{"./_fails":28}],25:[function(require,module,exports){
-var isObject = require('./_is-object')
-  , document = require('./_global').document
-  // in old IE typeof document.createElement is 'object'
-  , is = isObject(document) && isObject(document.createElement);
-module.exports = function(it){
-  return is ? document.createElement(it) : {};
-};
-},{"./_global":30,"./_is-object":38}],26:[function(require,module,exports){
-// IE 8- don't enum bug keys
-module.exports = (
-  'constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf'
-).split(',');
-},{}],27:[function(require,module,exports){
-var global    = require('./_global')
-  , core      = require('./_core')
-  , ctx       = require('./_ctx')
-  , hide      = require('./_hide')
-  , PROTOTYPE = 'prototype';
-
-var $export = function(type, name, source){
-  var IS_FORCED = type & $export.F
-    , IS_GLOBAL = type & $export.G
-    , IS_STATIC = type & $export.S
-    , IS_PROTO  = type & $export.P
-    , IS_BIND   = type & $export.B
-    , IS_WRAP   = type & $export.W
-    , exports   = IS_GLOBAL ? core : core[name] || (core[name] = {})
-    , expProto  = exports[PROTOTYPE]
-    , target    = IS_GLOBAL ? global : IS_STATIC ? global[name] : (global[name] || {})[PROTOTYPE]
-    , key, own, out;
-  if(IS_GLOBAL)source = name;
-  for(key in source){
-    // contains in native
-    own = !IS_FORCED && target && target[key] !== undefined;
-    if(own && key in exports)continue;
-    // export native or passed
-    out = own ? target[key] : source[key];
-    // prevent global pollution for namespaces
-    exports[key] = IS_GLOBAL && typeof target[key] != 'function' ? source[key]
-    // bind timers to global for call from export context
-    : IS_BIND && own ? ctx(out, global)
-    // wrap global constructors for prevent change them in library
-    : IS_WRAP && target[key] == out ? (function(C){
-      var F = function(a, b, c){
-        if(this instanceof C){
-          switch(arguments.length){
-            case 0: return new C;
-            case 1: return new C(a);
-            case 2: return new C(a, b);
-          } return new C(a, b, c);
-        } return C.apply(this, arguments);
-      };
-      F[PROTOTYPE] = C[PROTOTYPE];
-      return F;
-    // make static versions for prototype methods
-    })(out) : IS_PROTO && typeof out == 'function' ? ctx(Function.call, out) : out;
-    // export proto methods to core.%CONSTRUCTOR%.methods.%NAME%
-    if(IS_PROTO){
-      (exports.virtual || (exports.virtual = {}))[key] = out;
-      // export proto methods to core.%CONSTRUCTOR%.prototype.%NAME%
-      if(type & $export.R && expProto && !expProto[key])hide(expProto, key, out);
-    }
-  }
-};
-// type bitmap
-$export.F = 1;   // forced
-$export.G = 2;   // global
-$export.S = 4;   // static
-$export.P = 8;   // proto
-$export.B = 16;  // bind
-$export.W = 32;  // wrap
-$export.U = 64;  // safe
-$export.R = 128; // real proto method for `library` 
-module.exports = $export;
-},{"./_core":21,"./_ctx":22,"./_global":30,"./_hide":32}],28:[function(require,module,exports){
-module.exports = function(exec){
-  try {
-    return !!exec();
-  } catch(e){
-    return true;
-  }
-};
-},{}],29:[function(require,module,exports){
-var ctx         = require('./_ctx')
-  , call        = require('./_iter-call')
-  , isArrayIter = require('./_is-array-iter')
-  , anObject    = require('./_an-object')
-  , toLength    = require('./_to-length')
-  , getIterFn   = require('./core.get-iterator-method')
-  , BREAK       = {}
-  , RETURN      = {};
-var exports = module.exports = function(iterable, entries, fn, that, ITERATOR){
-  var iterFn = ITERATOR ? function(){ return iterable; } : getIterFn(iterable)
-    , f      = ctx(fn, that, entries ? 2 : 1)
-    , index  = 0
-    , length, step, iterator, result;
-  if(typeof iterFn != 'function')throw TypeError(iterable + ' is not iterable!');
-  // fast case for arrays with default iterator
-  if(isArrayIter(iterFn))for(length = toLength(iterable.length); length > index; index++){
-    result = entries ? f(anObject(step = iterable[index])[0], step[1]) : f(iterable[index]);
-    if(result === BREAK || result === RETURN)return result;
-  } else for(iterator = iterFn.call(iterable); !(step = iterator.next()).done; ){
-    result = call(iterator, f, step.value, entries);
-    if(result === BREAK || result === RETURN)return result;
-  }
-};
-exports.BREAK  = BREAK;
-exports.RETURN = RETURN;
-},{"./_an-object":17,"./_ctx":22,"./_is-array-iter":37,"./_iter-call":39,"./_to-length":70,"./core.get-iterator-method":75}],30:[function(require,module,exports){
-// https://github.com/zloirock/core-js/issues/86#issuecomment-115759028
-var global = module.exports = typeof window != 'undefined' && window.Math == Math
-  ? window : typeof self != 'undefined' && self.Math == Math ? self : Function('return this')();
-if(typeof __g == 'number')__g = global; // eslint-disable-line no-undef
-},{}],31:[function(require,module,exports){
-var hasOwnProperty = {}.hasOwnProperty;
-module.exports = function(it, key){
-  return hasOwnProperty.call(it, key);
-};
-},{}],32:[function(require,module,exports){
-var dP         = require('./_object-dp')
-  , createDesc = require('./_property-desc');
-module.exports = require('./_descriptors') ? function(object, key, value){
-  return dP.f(object, key, createDesc(1, value));
-} : function(object, key, value){
-  object[key] = value;
-  return object;
-};
-},{"./_descriptors":24,"./_object-dp":49,"./_property-desc":57}],33:[function(require,module,exports){
-module.exports = require('./_global').document && document.documentElement;
-},{"./_global":30}],34:[function(require,module,exports){
-module.exports = !require('./_descriptors') && !require('./_fails')(function(){
-  return Object.defineProperty(require('./_dom-create')('div'), 'a', {get: function(){ return 7; }}).a != 7;
-});
-},{"./_descriptors":24,"./_dom-create":25,"./_fails":28}],35:[function(require,module,exports){
-// fast apply, http://jsperf.lnkit.com/fast-apply/5
-module.exports = function(fn, args, that){
-  var un = that === undefined;
-  switch(args.length){
-    case 0: return un ? fn()
-                      : fn.call(that);
-    case 1: return un ? fn(args[0])
-                      : fn.call(that, args[0]);
-    case 2: return un ? fn(args[0], args[1])
-                      : fn.call(that, args[0], args[1]);
-    case 3: return un ? fn(args[0], args[1], args[2])
-                      : fn.call(that, args[0], args[1], args[2]);
-    case 4: return un ? fn(args[0], args[1], args[2], args[3])
-                      : fn.call(that, args[0], args[1], args[2], args[3]);
-  } return              fn.apply(that, args);
-};
-},{}],36:[function(require,module,exports){
-// fallback for non-array-like ES3 and non-enumerable old V8 strings
-var cof = require('./_cof');
-module.exports = Object('z').propertyIsEnumerable(0) ? Object : function(it){
-  return cof(it) == 'String' ? it.split('') : Object(it);
-};
-},{"./_cof":20}],37:[function(require,module,exports){
-// check on default Array iterator
-var Iterators  = require('./_iterators')
-  , ITERATOR   = require('./_wks')('iterator')
-  , ArrayProto = Array.prototype;
-
-module.exports = function(it){
-  return it !== undefined && (Iterators.Array === it || ArrayProto[ITERATOR] === it);
-};
-},{"./_iterators":44,"./_wks":74}],38:[function(require,module,exports){
-module.exports = function(it){
-  return typeof it === 'object' ? it !== null : typeof it === 'function';
-};
-},{}],39:[function(require,module,exports){
-// call something on iterator step with safe closing on error
-var anObject = require('./_an-object');
-module.exports = function(iterator, fn, value, entries){
-  try {
-    return entries ? fn(anObject(value)[0], value[1]) : fn(value);
-  // 7.4.6 IteratorClose(iterator, completion)
-  } catch(e){
-    var ret = iterator['return'];
-    if(ret !== undefined)anObject(ret.call(iterator));
-    throw e;
-  }
-};
-},{"./_an-object":17}],40:[function(require,module,exports){
-'use strict';
-var create         = require('./_object-create')
-  , descriptor     = require('./_property-desc')
-  , setToStringTag = require('./_set-to-string-tag')
-  , IteratorPrototype = {};
-
-// 25.1.2.1.1 %IteratorPrototype%[@@iterator]()
-require('./_hide')(IteratorPrototype, require('./_wks')('iterator'), function(){ return this; });
-
-module.exports = function(Constructor, NAME, next){
-  Constructor.prototype = create(IteratorPrototype, {next: descriptor(1, next)});
-  setToStringTag(Constructor, NAME + ' Iterator');
-};
-},{"./_hide":32,"./_object-create":48,"./_property-desc":57,"./_set-to-string-tag":61,"./_wks":74}],41:[function(require,module,exports){
-'use strict';
-var LIBRARY        = require('./_library')
-  , $export        = require('./_export')
-  , redefine       = require('./_redefine')
-  , hide           = require('./_hide')
-  , has            = require('./_has')
-  , Iterators      = require('./_iterators')
-  , $iterCreate    = require('./_iter-create')
-  , setToStringTag = require('./_set-to-string-tag')
-  , getPrototypeOf = require('./_object-gpo')
-  , ITERATOR       = require('./_wks')('iterator')
-  , BUGGY          = !([].keys && 'next' in [].keys()) // Safari has buggy iterators w/o `next`
-  , FF_ITERATOR    = '@@iterator'
-  , KEYS           = 'keys'
-  , VALUES         = 'values';
-
-var returnThis = function(){ return this; };
-
-module.exports = function(Base, NAME, Constructor, next, DEFAULT, IS_SET, FORCED){
-  $iterCreate(Constructor, NAME, next);
-  var getMethod = function(kind){
-    if(!BUGGY && kind in proto)return proto[kind];
-    switch(kind){
-      case KEYS: return function keys(){ return new Constructor(this, kind); };
-      case VALUES: return function values(){ return new Constructor(this, kind); };
-    } return function entries(){ return new Constructor(this, kind); };
-  };
-  var TAG        = NAME + ' Iterator'
-    , DEF_VALUES = DEFAULT == VALUES
-    , VALUES_BUG = false
-    , proto      = Base.prototype
-    , $native    = proto[ITERATOR] || proto[FF_ITERATOR] || DEFAULT && proto[DEFAULT]
-    , $default   = $native || getMethod(DEFAULT)
-    , $entries   = DEFAULT ? !DEF_VALUES ? $default : getMethod('entries') : undefined
-    , $anyNative = NAME == 'Array' ? proto.entries || $native : $native
-    , methods, key, IteratorPrototype;
-  // Fix native
-  if($anyNative){
-    IteratorPrototype = getPrototypeOf($anyNative.call(new Base));
-    if(IteratorPrototype !== Object.prototype){
-      // Set @@toStringTag to native iterators
-      setToStringTag(IteratorPrototype, TAG, true);
-      // fix for some old engines
-      if(!LIBRARY && !has(IteratorPrototype, ITERATOR))hide(IteratorPrototype, ITERATOR, returnThis);
-    }
-  }
-  // fix Array#{values, @@iterator}.name in V8 / FF
-  if(DEF_VALUES && $native && $native.name !== VALUES){
-    VALUES_BUG = true;
-    $default = function values(){ return $native.call(this); };
-  }
-  // Define iterator
-  if((!LIBRARY || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR])){
-    hide(proto, ITERATOR, $default);
-  }
-  // Plug for library
-  Iterators[NAME] = $default;
-  Iterators[TAG]  = returnThis;
-  if(DEFAULT){
-    methods = {
-      values:  DEF_VALUES ? $default : getMethod(VALUES),
-      keys:    IS_SET     ? $default : getMethod(KEYS),
-      entries: $entries
-    };
-    if(FORCED)for(key in methods){
-      if(!(key in proto))redefine(proto, key, methods[key]);
-    } else $export($export.P + $export.F * (BUGGY || VALUES_BUG), NAME, methods);
-  }
-  return methods;
-};
-},{"./_export":27,"./_has":31,"./_hide":32,"./_iter-create":40,"./_iterators":44,"./_library":45,"./_object-gpo":52,"./_redefine":59,"./_set-to-string-tag":61,"./_wks":74}],42:[function(require,module,exports){
-var ITERATOR     = require('./_wks')('iterator')
-  , SAFE_CLOSING = false;
-
-try {
-  var riter = [7][ITERATOR]();
-  riter['return'] = function(){ SAFE_CLOSING = true; };
-  Array.from(riter, function(){ throw 2; });
-} catch(e){ /* empty */ }
-
-module.exports = function(exec, skipClosing){
-  if(!skipClosing && !SAFE_CLOSING)return false;
-  var safe = false;
-  try {
-    var arr  = [7]
-      , iter = arr[ITERATOR]();
-    iter.next = function(){ return {done: safe = true}; };
-    arr[ITERATOR] = function(){ return iter; };
-    exec(arr);
-  } catch(e){ /* empty */ }
-  return safe;
-};
-},{"./_wks":74}],43:[function(require,module,exports){
-module.exports = function(done, value){
-  return {value: value, done: !!done};
-};
-},{}],44:[function(require,module,exports){
-module.exports = {};
-},{}],45:[function(require,module,exports){
-module.exports = true;
-},{}],46:[function(require,module,exports){
-var global    = require('./_global')
-  , macrotask = require('./_task').set
-  , Observer  = global.MutationObserver || global.WebKitMutationObserver
-  , process   = global.process
-  , Promise   = global.Promise
-  , isNode    = require('./_cof')(process) == 'process';
-
-module.exports = function(){
-  var head, last, notify;
-
-  var flush = function(){
-    var parent, fn;
-    if(isNode && (parent = process.domain))parent.exit();
-    while(head){
-      fn   = head.fn;
-      head = head.next;
-      try {
-        fn();
-      } catch(e){
-        if(head)notify();
-        else last = undefined;
-        throw e;
-      }
-    } last = undefined;
-    if(parent)parent.enter();
-  };
-
-  // Node.js
-  if(isNode){
-    notify = function(){
-      process.nextTick(flush);
-    };
-  // browsers with MutationObserver
-  } else if(Observer){
-    var toggle = true
-      , node   = document.createTextNode('');
-    new Observer(flush).observe(node, {characterData: true}); // eslint-disable-line no-new
-    notify = function(){
-      node.data = toggle = !toggle;
-    };
-  // environments with maybe non-completely correct, but existent Promise
-  } else if(Promise && Promise.resolve){
-    var promise = Promise.resolve();
-    notify = function(){
-      promise.then(flush);
-    };
-  // for other environments - macrotask based on:
-  // - setImmediate
-  // - MessageChannel
-  // - window.postMessag
-  // - onreadystatechange
-  // - setTimeout
-  } else {
-    notify = function(){
-      // strange IE + webpack dev server bug - use .call(global)
-      macrotask.call(global, flush);
-    };
-  }
-
-  return function(fn){
-    var task = {fn: fn, next: undefined};
-    if(last)last.next = task;
-    if(!head){
-      head = task;
-      notify();
-    } last = task;
-  };
-};
-},{"./_cof":20,"./_global":30,"./_task":66}],47:[function(require,module,exports){
-'use strict';
-// 19.1.2.1 Object.assign(target, source, ...)
-var getKeys  = require('./_object-keys')
-  , gOPS     = require('./_object-gops')
-  , pIE      = require('./_object-pie')
-  , toObject = require('./_to-object')
-  , IObject  = require('./_iobject')
-  , $assign  = Object.assign;
-
-// should work with symbols and should have deterministic property order (V8 bug)
-module.exports = !$assign || require('./_fails')(function(){
-  var A = {}
-    , B = {}
-    , S = Symbol()
-    , K = 'abcdefghijklmnopqrst';
-  A[S] = 7;
-  K.split('').forEach(function(k){ B[k] = k; });
-  return $assign({}, A)[S] != 7 || Object.keys($assign({}, B)).join('') != K;
-}) ? function assign(target, source){ // eslint-disable-line no-unused-vars
-  var T     = toObject(target)
-    , aLen  = arguments.length
-    , index = 1
-    , getSymbols = gOPS.f
-    , isEnum     = pIE.f;
-  while(aLen > index){
-    var S      = IObject(arguments[index++])
-      , keys   = getSymbols ? getKeys(S).concat(getSymbols(S)) : getKeys(S)
-      , length = keys.length
-      , j      = 0
-      , key;
-    while(length > j)if(isEnum.call(S, key = keys[j++]))T[key] = S[key];
-  } return T;
-} : $assign;
-},{"./_fails":28,"./_iobject":36,"./_object-gops":51,"./_object-keys":54,"./_object-pie":55,"./_to-object":71}],48:[function(require,module,exports){
-// 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties])
-var anObject    = require('./_an-object')
-  , dPs         = require('./_object-dps')
-  , enumBugKeys = require('./_enum-bug-keys')
-  , IE_PROTO    = require('./_shared-key')('IE_PROTO')
-  , Empty       = function(){ /* empty */ }
-  , PROTOTYPE   = 'prototype';
-
-// Create object with fake `null` prototype: use iframe Object with cleared prototype
-var createDict = function(){
-  // Thrash, waste and sodomy: IE GC bug
-  var iframe = require('./_dom-create')('iframe')
-    , i      = enumBugKeys.length
-    , lt     = '<'
-    , gt     = '>'
-    , iframeDocument;
-  iframe.style.display = 'none';
-  require('./_html').appendChild(iframe);
-  iframe.src = 'javascript:'; // eslint-disable-line no-script-url
-  // createDict = iframe.contentWindow.Object;
-  // html.removeChild(iframe);
-  iframeDocument = iframe.contentWindow.document;
-  iframeDocument.open();
-  iframeDocument.write(lt + 'script' + gt + 'document.F=Object' + lt + '/script' + gt);
-  iframeDocument.close();
-  createDict = iframeDocument.F;
-  while(i--)delete createDict[PROTOTYPE][enumBugKeys[i]];
-  return createDict();
-};
-
-module.exports = Object.create || function create(O, Properties){
-  var result;
-  if(O !== null){
-    Empty[PROTOTYPE] = anObject(O);
-    result = new Empty;
-    Empty[PROTOTYPE] = null;
-    // add "__proto__" for Object.getPrototypeOf polyfill
-    result[IE_PROTO] = O;
-  } else result = createDict();
-  return Properties === undefined ? result : dPs(result, Properties);
-};
-
-},{"./_an-object":17,"./_dom-create":25,"./_enum-bug-keys":26,"./_html":33,"./_object-dps":50,"./_shared-key":62}],49:[function(require,module,exports){
-var anObject       = require('./_an-object')
-  , IE8_DOM_DEFINE = require('./_ie8-dom-define')
-  , toPrimitive    = require('./_to-primitive')
-  , dP             = Object.defineProperty;
-
-exports.f = require('./_descriptors') ? Object.defineProperty : function defineProperty(O, P, Attributes){
-  anObject(O);
-  P = toPrimitive(P, true);
-  anObject(Attributes);
-  if(IE8_DOM_DEFINE)try {
-    return dP(O, P, Attributes);
-  } catch(e){ /* empty */ }
-  if('get' in Attributes || 'set' in Attributes)throw TypeError('Accessors not supported!');
-  if('value' in Attributes)O[P] = Attributes.value;
-  return O;
-};
-},{"./_an-object":17,"./_descriptors":24,"./_ie8-dom-define":34,"./_to-primitive":72}],50:[function(require,module,exports){
-var dP       = require('./_object-dp')
-  , anObject = require('./_an-object')
-  , getKeys  = require('./_object-keys');
-
-module.exports = require('./_descriptors') ? Object.defineProperties : function defineProperties(O, Properties){
-  anObject(O);
-  var keys   = getKeys(Properties)
-    , length = keys.length
-    , i = 0
-    , P;
-  while(length > i)dP.f(O, P = keys[i++], Properties[P]);
-  return O;
-};
-},{"./_an-object":17,"./_descriptors":24,"./_object-dp":49,"./_object-keys":54}],51:[function(require,module,exports){
-exports.f = Object.getOwnPropertySymbols;
-},{}],52:[function(require,module,exports){
-// 19.1.2.9 / 15.2.3.2 Object.getPrototypeOf(O)
-var has         = require('./_has')
-  , toObject    = require('./_to-object')
-  , IE_PROTO    = require('./_shared-key')('IE_PROTO')
-  , ObjectProto = Object.prototype;
-
-module.exports = Object.getPrototypeOf || function(O){
-  O = toObject(O);
-  if(has(O, IE_PROTO))return O[IE_PROTO];
-  if(typeof O.constructor == 'function' && O instanceof O.constructor){
-    return O.constructor.prototype;
-  } return O instanceof Object ? ObjectProto : null;
-};
-},{"./_has":31,"./_shared-key":62,"./_to-object":71}],53:[function(require,module,exports){
-var has          = require('./_has')
-  , toIObject    = require('./_to-iobject')
-  , arrayIndexOf = require('./_array-includes')(false)
-  , IE_PROTO     = require('./_shared-key')('IE_PROTO');
-
-module.exports = function(object, names){
-  var O      = toIObject(object)
-    , i      = 0
-    , result = []
-    , key;
-  for(key in O)if(key != IE_PROTO)has(O, key) && result.push(key);
-  // Don't enum bug & hidden keys
-  while(names.length > i)if(has(O, key = names[i++])){
-    ~arrayIndexOf(result, key) || result.push(key);
-  }
-  return result;
-};
-},{"./_array-includes":18,"./_has":31,"./_shared-key":62,"./_to-iobject":69}],54:[function(require,module,exports){
-// 19.1.2.14 / 15.2.3.14 Object.keys(O)
-var $keys       = require('./_object-keys-internal')
-  , enumBugKeys = require('./_enum-bug-keys');
-
-module.exports = Object.keys || function keys(O){
-  return $keys(O, enumBugKeys);
-};
-},{"./_enum-bug-keys":26,"./_object-keys-internal":53}],55:[function(require,module,exports){
-exports.f = {}.propertyIsEnumerable;
-},{}],56:[function(require,module,exports){
-// most Object methods by ES6 should accept primitives
-var $export = require('./_export')
-  , core    = require('./_core')
-  , fails   = require('./_fails');
-module.exports = function(KEY, exec){
-  var fn  = (core.Object || {})[KEY] || Object[KEY]
-    , exp = {};
-  exp[KEY] = exec(fn);
-  $export($export.S + $export.F * fails(function(){ fn(1); }), 'Object', exp);
-};
-},{"./_core":21,"./_export":27,"./_fails":28}],57:[function(require,module,exports){
-module.exports = function(bitmap, value){
-  return {
-    enumerable  : !(bitmap & 1),
-    configurable: !(bitmap & 2),
-    writable    : !(bitmap & 4),
-    value       : value
-  };
-};
-},{}],58:[function(require,module,exports){
-var hide = require('./_hide');
-module.exports = function(target, src, safe){
-  for(var key in src){
-    if(safe && target[key])target[key] = src[key];
-    else hide(target, key, src[key]);
-  } return target;
-};
-},{"./_hide":32}],59:[function(require,module,exports){
-module.exports = require('./_hide');
-},{"./_hide":32}],60:[function(require,module,exports){
-'use strict';
-var global      = require('./_global')
-  , core        = require('./_core')
-  , dP          = require('./_object-dp')
-  , DESCRIPTORS = require('./_descriptors')
-  , SPECIES     = require('./_wks')('species');
-
-module.exports = function(KEY){
-  var C = typeof core[KEY] == 'function' ? core[KEY] : global[KEY];
-  if(DESCRIPTORS && C && !C[SPECIES])dP.f(C, SPECIES, {
-    configurable: true,
-    get: function(){ return this; }
-  });
-};
-},{"./_core":21,"./_descriptors":24,"./_global":30,"./_object-dp":49,"./_wks":74}],61:[function(require,module,exports){
-var def = require('./_object-dp').f
-  , has = require('./_has')
-  , TAG = require('./_wks')('toStringTag');
-
-module.exports = function(it, tag, stat){
-  if(it && !has(it = stat ? it : it.prototype, TAG))def(it, TAG, {configurable: true, value: tag});
-};
-},{"./_has":31,"./_object-dp":49,"./_wks":74}],62:[function(require,module,exports){
-var shared = require('./_shared')('keys')
-  , uid    = require('./_uid');
-module.exports = function(key){
-  return shared[key] || (shared[key] = uid(key));
-};
-},{"./_shared":63,"./_uid":73}],63:[function(require,module,exports){
-var global = require('./_global')
-  , SHARED = '__core-js_shared__'
-  , store  = global[SHARED] || (global[SHARED] = {});
-module.exports = function(key){
-  return store[key] || (store[key] = {});
-};
-},{"./_global":30}],64:[function(require,module,exports){
-// 7.3.20 SpeciesConstructor(O, defaultConstructor)
-var anObject  = require('./_an-object')
-  , aFunction = require('./_a-function')
-  , SPECIES   = require('./_wks')('species');
-module.exports = function(O, D){
-  var C = anObject(O).constructor, S;
-  return C === undefined || (S = anObject(C)[SPECIES]) == undefined ? D : aFunction(S);
-};
-},{"./_a-function":14,"./_an-object":17,"./_wks":74}],65:[function(require,module,exports){
-var toInteger = require('./_to-integer')
-  , defined   = require('./_defined');
-// true  -> String#at
-// false -> String#codePointAt
-module.exports = function(TO_STRING){
-  return function(that, pos){
-    var s = String(defined(that))
-      , i = toInteger(pos)
-      , l = s.length
-      , a, b;
-    if(i < 0 || i >= l)return TO_STRING ? '' : undefined;
-    a = s.charCodeAt(i);
-    return a < 0xd800 || a > 0xdbff || i + 1 === l || (b = s.charCodeAt(i + 1)) < 0xdc00 || b > 0xdfff
-      ? TO_STRING ? s.charAt(i) : a
-      : TO_STRING ? s.slice(i, i + 2) : (a - 0xd800 << 10) + (b - 0xdc00) + 0x10000;
-  };
-};
-},{"./_defined":23,"./_to-integer":68}],66:[function(require,module,exports){
-var ctx                = require('./_ctx')
-  , invoke             = require('./_invoke')
-  , html               = require('./_html')
-  , cel                = require('./_dom-create')
-  , global             = require('./_global')
-  , process            = global.process
-  , setTask            = global.setImmediate
-  , clearTask          = global.clearImmediate
-  , MessageChannel     = global.MessageChannel
-  , counter            = 0
-  , queue              = {}
-  , ONREADYSTATECHANGE = 'onreadystatechange'
-  , defer, channel, port;
-var run = function(){
-  var id = +this;
-  if(queue.hasOwnProperty(id)){
-    var fn = queue[id];
-    delete queue[id];
-    fn();
-  }
-};
-var listener = function(event){
-  run.call(event.data);
-};
-// Node.js 0.9+ & IE10+ has setImmediate, otherwise:
-if(!setTask || !clearTask){
-  setTask = function setImmediate(fn){
-    var args = [], i = 1;
-    while(arguments.length > i)args.push(arguments[i++]);
-    queue[++counter] = function(){
-      invoke(typeof fn == 'function' ? fn : Function(fn), args);
-    };
-    defer(counter);
-    return counter;
-  };
-  clearTask = function clearImmediate(id){
-    delete queue[id];
-  };
-  // Node.js 0.8-
-  if(require('./_cof')(process) == 'process'){
-    defer = function(id){
-      process.nextTick(ctx(run, id, 1));
-    };
-  // Browsers with MessageChannel, includes WebWorkers
-  } else if(MessageChannel){
-    channel = new MessageChannel;
-    port    = channel.port2;
-    channel.port1.onmessage = listener;
-    defer = ctx(port.postMessage, port, 1);
-  // Browsers with postMessage, skip WebWorkers
-  // IE8 has postMessage, but it's sync & typeof its postMessage is 'object'
-  } else if(global.addEventListener && typeof postMessage == 'function' && !global.importScripts){
-    defer = function(id){
-      global.postMessage(id + '', '*');
-    };
-    global.addEventListener('message', listener, false);
-  // IE8-
-  } else if(ONREADYSTATECHANGE in cel('script')){
-    defer = function(id){
-      html.appendChild(cel('script'))[ONREADYSTATECHANGE] = function(){
-        html.removeChild(this);
-        run.call(id);
-      };
-    };
-  // Rest old browsers
-  } else {
-    defer = function(id){
-      setTimeout(ctx(run, id, 1), 0);
-    };
-  }
-}
-module.exports = {
-  set:   setTask,
-  clear: clearTask
-};
-},{"./_cof":20,"./_ctx":22,"./_dom-create":25,"./_global":30,"./_html":33,"./_invoke":35}],67:[function(require,module,exports){
-var toInteger = require('./_to-integer')
-  , max       = Math.max
-  , min       = Math.min;
-module.exports = function(index, length){
-  index = toInteger(index);
-  return index < 0 ? max(index + length, 0) : min(index, length);
-};
-},{"./_to-integer":68}],68:[function(require,module,exports){
-// 7.1.4 ToInteger
-var ceil  = Math.ceil
-  , floor = Math.floor;
-module.exports = function(it){
-  return isNaN(it = +it) ? 0 : (it > 0 ? floor : ceil)(it);
-};
-},{}],69:[function(require,module,exports){
-// to indexed object, toObject with fallback for non-array-like ES3 strings
-var IObject = require('./_iobject')
-  , defined = require('./_defined');
-module.exports = function(it){
-  return IObject(defined(it));
-};
-},{"./_defined":23,"./_iobject":36}],70:[function(require,module,exports){
-// 7.1.15 ToLength
-var toInteger = require('./_to-integer')
-  , min       = Math.min;
-module.exports = function(it){
-  return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991
-};
-},{"./_to-integer":68}],71:[function(require,module,exports){
-// 7.1.13 ToObject(argument)
-var defined = require('./_defined');
-module.exports = function(it){
-  return Object(defined(it));
-};
-},{"./_defined":23}],72:[function(require,module,exports){
-// 7.1.1 ToPrimitive(input [, PreferredType])
-var isObject = require('./_is-object');
-// instead of the ES6 spec version, we didn't implement @@toPrimitive case
-// and the second argument - flag - preferred type is a string
-module.exports = function(it, S){
-  if(!isObject(it))return it;
-  var fn, val;
-  if(S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
-  if(typeof (fn = it.valueOf) == 'function' && !isObject(val = fn.call(it)))return val;
-  if(!S && typeof (fn = it.toString) == 'function' && !isObject(val = fn.call(it)))return val;
-  throw TypeError("Can't convert object to primitive value");
-};
-},{"./_is-object":38}],73:[function(require,module,exports){
-var id = 0
-  , px = Math.random();
-module.exports = function(key){
-  return 'Symbol('.concat(key === undefined ? '' : key, ')_', (++id + px).toString(36));
-};
-},{}],74:[function(require,module,exports){
-var store      = require('./_shared')('wks')
-  , uid        = require('./_uid')
-  , Symbol     = require('./_global').Symbol
-  , USE_SYMBOL = typeof Symbol == 'function';
-
-var $exports = module.exports = function(name){
-  return store[name] || (store[name] =
-    USE_SYMBOL && Symbol[name] || (USE_SYMBOL ? Symbol : uid)('Symbol.' + name));
-};
-
-$exports.store = store;
-},{"./_global":30,"./_shared":63,"./_uid":73}],75:[function(require,module,exports){
-var classof   = require('./_classof')
-  , ITERATOR  = require('./_wks')('iterator')
-  , Iterators = require('./_iterators');
-module.exports = require('./_core').getIteratorMethod = function(it){
-  if(it != undefined)return it[ITERATOR]
-    || it['@@iterator']
-    || Iterators[classof(it)];
-};
-},{"./_classof":19,"./_core":21,"./_iterators":44,"./_wks":74}],76:[function(require,module,exports){
-'use strict';
-var addToUnscopables = require('./_add-to-unscopables')
-  , step             = require('./_iter-step')
-  , Iterators        = require('./_iterators')
-  , toIObject        = require('./_to-iobject');
-
-// 22.1.3.4 Array.prototype.entries()
-// 22.1.3.13 Array.prototype.keys()
-// 22.1.3.29 Array.prototype.values()
-// 22.1.3.30 Array.prototype[@@iterator]()
-module.exports = require('./_iter-define')(Array, 'Array', function(iterated, kind){
-  this._t = toIObject(iterated); // target
-  this._i = 0;                   // next index
-  this._k = kind;                // kind
-// 22.1.5.2.1 %ArrayIteratorPrototype%.next()
-}, function(){
-  var O     = this._t
-    , kind  = this._k
-    , index = this._i++;
-  if(!O || index >= O.length){
-    this._t = undefined;
-    return step(1);
-  }
-  if(kind == 'keys'  )return step(0, index);
-  if(kind == 'values')return step(0, O[index]);
-  return step(0, [index, O[index]]);
-}, 'values');
-
-// argumentsList[@@iterator] is %ArrayProto_values% (9.4.4.6, 9.4.4.7)
-Iterators.Arguments = Iterators.Array;
-
-addToUnscopables('keys');
-addToUnscopables('values');
-addToUnscopables('entries');
-},{"./_add-to-unscopables":15,"./_iter-define":41,"./_iter-step":43,"./_iterators":44,"./_to-iobject":69}],77:[function(require,module,exports){
-// 19.1.3.1 Object.assign(target, source)
-var $export = require('./_export');
-
-$export($export.S + $export.F, 'Object', {assign: require('./_object-assign')});
-},{"./_export":27,"./_object-assign":47}],78:[function(require,module,exports){
-// 19.1.2.14 Object.keys(O)
-var toObject = require('./_to-object')
-  , $keys    = require('./_object-keys');
-
-require('./_object-sap')('keys', function(){
-  return function keys(it){
-    return $keys(toObject(it));
-  };
-});
-},{"./_object-keys":54,"./_object-sap":56,"./_to-object":71}],79:[function(require,module,exports){
-arguments[4][9][0].apply(exports,arguments)
-},{"dup":9}],80:[function(require,module,exports){
-'use strict';
-var LIBRARY            = require('./_library')
-  , global             = require('./_global')
-  , ctx                = require('./_ctx')
-  , classof            = require('./_classof')
-  , $export            = require('./_export')
-  , isObject           = require('./_is-object')
-  , aFunction          = require('./_a-function')
-  , anInstance         = require('./_an-instance')
-  , forOf              = require('./_for-of')
-  , speciesConstructor = require('./_species-constructor')
-  , task               = require('./_task').set
-  , microtask          = require('./_microtask')()
-  , PROMISE            = 'Promise'
-  , TypeError          = global.TypeError
-  , process            = global.process
-  , $Promise           = global[PROMISE]
-  , process            = global.process
-  , isNode             = classof(process) == 'process'
-  , empty              = function(){ /* empty */ }
-  , Internal, GenericPromiseCapability, Wrapper;
-
-var USE_NATIVE = !!function(){
-  try {
-    // correct subclassing with @@species support
-    var promise     = $Promise.resolve(1)
-      , FakePromise = (promise.constructor = {})[require('./_wks')('species')] = function(exec){ exec(empty, empty); };
-    // unhandled rejections tracking support, NodeJS Promise without it fails @@species test
-    return (isNode || typeof PromiseRejectionEvent == 'function') && promise.then(empty) instanceof FakePromise;
-  } catch(e){ /* empty */ }
-}();
-
-// helpers
-var sameConstructor = function(a, b){
-  // with library wrapper special case
-  return a === b || a === $Promise && b === Wrapper;
-};
-var isThenable = function(it){
-  var then;
-  return isObject(it) && typeof (then = it.then) == 'function' ? then : false;
-};
-var newPromiseCapability = function(C){
-  return sameConstructor($Promise, C)
-    ? new PromiseCapability(C)
-    : new GenericPromiseCapability(C);
-};
-var PromiseCapability = GenericPromiseCapability = function(C){
-  var resolve, reject;
-  this.promise = new C(function($$resolve, $$reject){
-    if(resolve !== undefined || reject !== undefined)throw TypeError('Bad Promise constructor');
-    resolve = $$resolve;
-    reject  = $$reject;
-  });
-  this.resolve = aFunction(resolve);
-  this.reject  = aFunction(reject);
-};
-var perform = function(exec){
-  try {
-    exec();
-  } catch(e){
-    return {error: e};
-  }
-};
-var notify = function(promise, isReject){
-  if(promise._n)return;
-  promise._n = true;
-  var chain = promise._c;
-  microtask(function(){
-    var value = promise._v
-      , ok    = promise._s == 1
-      , i     = 0;
-    var run = function(reaction){
-      var handler = ok ? reaction.ok : reaction.fail
-        , resolve = reaction.resolve
-        , reject  = reaction.reject
-        , domain  = reaction.domain
-        , result, then;
-      try {
-        if(handler){
-          if(!ok){
-            if(promise._h == 2)onHandleUnhandled(promise);
-            promise._h = 1;
-          }
-          if(handler === true)result = value;
-          else {
-            if(domain)domain.enter();
-            result = handler(value);
-            if(domain)domain.exit();
-          }
-          if(result === reaction.promise){
-            reject(TypeError('Promise-chain cycle'));
-          } else if(then = isThenable(result)){
-            then.call(result, resolve, reject);
-          } else resolve(result);
-        } else reject(value);
-      } catch(e){
-        reject(e);
-      }
-    };
-    while(chain.length > i)run(chain[i++]); // variable length - can't use forEach
-    promise._c = [];
-    promise._n = false;
-    if(isReject && !promise._h)onUnhandled(promise);
-  });
-};
-var onUnhandled = function(promise){
-  task.call(global, function(){
-    var value = promise._v
-      , abrupt, handler, console;
-    if(isUnhandled(promise)){
-      abrupt = perform(function(){
-        if(isNode){
-          process.emit('unhandledRejection', value, promise);
-        } else if(handler = global.onunhandledrejection){
-          handler({promise: promise, reason: value});
-        } else if((console = global.console) && console.error){
-          console.error('Unhandled promise rejection', value);
-        }
-      });
-      // Browsers should not trigger `rejectionHandled` event if it was handled here, NodeJS - should
-      promise._h = isNode || isUnhandled(promise) ? 2 : 1;
-    } promise._a = undefined;
-    if(abrupt)throw abrupt.error;
-  });
-};
-var isUnhandled = function(promise){
-  if(promise._h == 1)return false;
-  var chain = promise._a || promise._c
-    , i     = 0
-    , reaction;
-  while(chain.length > i){
-    reaction = chain[i++];
-    if(reaction.fail || !isUnhandled(reaction.promise))return false;
-  } return true;
-};
-var onHandleUnhandled = function(promise){
-  task.call(global, function(){
-    var handler;
-    if(isNode){
-      process.emit('rejectionHandled', promise);
-    } else if(handler = global.onrejectionhandled){
-      handler({promise: promise, reason: promise._v});
-    }
-  });
-};
-var $reject = function(value){
-  var promise = this;
-  if(promise._d)return;
-  promise._d = true;
-  promise = promise._w || promise; // unwrap
-  promise._v = value;
-  promise._s = 2;
-  if(!promise._a)promise._a = promise._c.slice();
-  notify(promise, true);
-};
-var $resolve = function(value){
-  var promise = this
-    , then;
-  if(promise._d)return;
-  promise._d = true;
-  promise = promise._w || promise; // unwrap
-  try {
-    if(promise === value)throw TypeError("Promise can't be resolved itself");
-    if(then = isThenable(value)){
-      microtask(function(){
-        var wrapper = {_w: promise, _d: false}; // wrap
-        try {
-          then.call(value, ctx($resolve, wrapper, 1), ctx($reject, wrapper, 1));
-        } catch(e){
-          $reject.call(wrapper, e);
-        }
-      });
-    } else {
-      promise._v = value;
-      promise._s = 1;
-      notify(promise, false);
-    }
-  } catch(e){
-    $reject.call({_w: promise, _d: false}, e); // wrap
-  }
-};
-
-// constructor polyfill
-if(!USE_NATIVE){
-  // 25.4.3.1 Promise(executor)
-  $Promise = function Promise(executor){
-    anInstance(this, $Promise, PROMISE, '_h');
-    aFunction(executor);
-    Internal.call(this);
-    try {
-      executor(ctx($resolve, this, 1), ctx($reject, this, 1));
-    } catch(err){
-      $reject.call(this, err);
-    }
-  };
-  Internal = function Promise(executor){
-    this._c = [];             // <- awaiting reactions
-    this._a = undefined;      // <- checked in isUnhandled reactions
-    this._s = 0;              // <- state
-    this._d = false;          // <- done
-    this._v = undefined;      // <- value
-    this._h = 0;              // <- rejection state, 0 - default, 1 - handled, 2 - unhandled
-    this._n = false;          // <- notify
-  };
-  Internal.prototype = require('./_redefine-all')($Promise.prototype, {
-    // 25.4.5.3 Promise.prototype.then(onFulfilled, onRejected)
-    then: function then(onFulfilled, onRejected){
-      var reaction    = newPromiseCapability(speciesConstructor(this, $Promise));
-      reaction.ok     = typeof onFulfilled == 'function' ? onFulfilled : true;
-      reaction.fail   = typeof onRejected == 'function' && onRejected;
-      reaction.domain = isNode ? process.domain : undefined;
-      this._c.push(reaction);
-      if(this._a)this._a.push(reaction);
-      if(this._s)notify(this, false);
-      return reaction.promise;
-    },
-    // 25.4.5.1 Promise.prototype.catch(onRejected)
-    'catch': function(onRejected){
-      return this.then(undefined, onRejected);
-    }
-  });
-  PromiseCapability = function(){
-    var promise  = new Internal;
-    this.promise = promise;
-    this.resolve = ctx($resolve, promise, 1);
-    this.reject  = ctx($reject, promise, 1);
-  };
-}
-
-$export($export.G + $export.W + $export.F * !USE_NATIVE, {Promise: $Promise});
-require('./_set-to-string-tag')($Promise, PROMISE);
-require('./_set-species')(PROMISE);
-Wrapper = require('./_core')[PROMISE];
-
-// statics
-$export($export.S + $export.F * !USE_NATIVE, PROMISE, {
-  // 25.4.4.5 Promise.reject(r)
-  reject: function reject(r){
-    var capability = newPromiseCapability(this)
-      , $$reject   = capability.reject;
-    $$reject(r);
-    return capability.promise;
-  }
-});
-$export($export.S + $export.F * (LIBRARY || !USE_NATIVE), PROMISE, {
-  // 25.4.4.6 Promise.resolve(x)
-  resolve: function resolve(x){
-    // instanceof instead of internal slot check because we should fix it without replacement native Promise core
-    if(x instanceof $Promise && sameConstructor(x.constructor, this))return x;
-    var capability = newPromiseCapability(this)
-      , $$resolve  = capability.resolve;
-    $$resolve(x);
-    return capability.promise;
-  }
-});
-$export($export.S + $export.F * !(USE_NATIVE && require('./_iter-detect')(function(iter){
-  $Promise.all(iter)['catch'](empty);
-})), PROMISE, {
-  // 25.4.4.1 Promise.all(iterable)
-  all: function all(iterable){
-    var C          = this
-      , capability = newPromiseCapability(C)
-      , resolve    = capability.resolve
-      , reject     = capability.reject;
-    var abrupt = perform(function(){
-      var values    = []
-        , index     = 0
-        , remaining = 1;
-      forOf(iterable, false, function(promise){
-        var $index        = index++
-          , alreadyCalled = false;
-        values.push(undefined);
-        remaining++;
-        C.resolve(promise).then(function(value){
-          if(alreadyCalled)return;
-          alreadyCalled  = true;
-          values[$index] = value;
-          --remaining || resolve(values);
-        }, reject);
-      });
-      --remaining || resolve(values);
-    });
-    if(abrupt)reject(abrupt.error);
-    return capability.promise;
-  },
-  // 25.4.4.4 Promise.race(iterable)
-  race: function race(iterable){
-    var C          = this
-      , capability = newPromiseCapability(C)
-      , reject     = capability.reject;
-    var abrupt = perform(function(){
-      forOf(iterable, false, function(promise){
-        C.resolve(promise).then(capability.resolve, reject);
-      });
-    });
-    if(abrupt)reject(abrupt.error);
-    return capability.promise;
-  }
-});
-},{"./_a-function":14,"./_an-instance":16,"./_classof":19,"./_core":21,"./_ctx":22,"./_export":27,"./_for-of":29,"./_global":30,"./_is-object":38,"./_iter-detect":42,"./_library":45,"./_microtask":46,"./_redefine-all":58,"./_set-species":60,"./_set-to-string-tag":61,"./_species-constructor":64,"./_task":66,"./_wks":74}],81:[function(require,module,exports){
-'use strict';
-var $at  = require('./_string-at')(true);
-
-// 21.1.3.27 String.prototype[@@iterator]()
-require('./_iter-define')(String, 'String', function(iterated){
-  this._t = String(iterated); // target
-  this._i = 0;                // next index
-// 21.1.5.2.1 %StringIteratorPrototype%.next()
-}, function(){
-  var O     = this._t
-    , index = this._i
-    , point;
-  if(index >= O.length)return {value: undefined, done: true};
-  point = $at(O, index);
-  this._i += point.length;
-  return {value: point, done: false};
-});
-},{"./_iter-define":41,"./_string-at":65}],82:[function(require,module,exports){
-require('./es6.array.iterator');
-var global        = require('./_global')
-  , hide          = require('./_hide')
-  , Iterators     = require('./_iterators')
-  , TO_STRING_TAG = require('./_wks')('toStringTag');
-
-for(var collections = ['NodeList', 'DOMTokenList', 'MediaList', 'StyleSheetList', 'CSSRuleList'], i = 0; i < 5; i++){
-  var NAME       = collections[i]
-    , Collection = global[NAME]
-    , proto      = Collection && Collection.prototype;
-  if(proto && !proto[TO_STRING_TAG])hide(proto, TO_STRING_TAG, NAME);
-  Iterators[NAME] = Iterators.Array;
-}
-},{"./_global":30,"./_hide":32,"./_iterators":44,"./_wks":74,"./es6.array.iterator":76}],83:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-var _collection = require("./collection");
-
-var _collection2 = _interopRequireDefault(_collection);
-
-var _base = require("./adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const DEFAULT_BUCKET_NAME = "default";
-const DEFAULT_REMOTE = "http://localhost:8888/v1";
-
-/**
- * KintoBase class.
- */
-class KintoBase {
-  /**
-   * Provides a public access to the base adapter class. Users can create a
-   * custom DB adapter by extending {@link BaseAdapter}.
-   *
-   * @type {Object}
-   */
-  static get adapters() {
-    return {
-      BaseAdapter: _base2.default
-    };
-  }
-
-  /**
-   * Synchronization strategies. Available strategies are:
-   *
-   * - `MANUAL`: Conflicts will be reported in a dedicated array.
-   * - `SERVER_WINS`: Conflicts are resolved using remote data.
-   * - `CLIENT_WINS`: Conflicts are resolved using local data.
-   *
-   * @type {Object}
-   */
-  static get syncStrategy() {
-    return _collection2.default.strategy;
-  }
-
-  /**
-   * Constructor.
-   *
-   * Options:
-   * - `{String}`       `remote`         The server URL to use.
-   * - `{String}`       `bucket`         The collection bucket name.
-   * - `{EventEmitter}` `events`         Events handler.
-   * - `{BaseAdapter}`  `adapter`        The base DB adapter class.
-   * - `{Object}`       `adapterOptions` Options given to the adapter.
-   * - `{String}`       `dbPrefix`       The DB name prefix.
-   * - `{Object}`       `headers`        The HTTP headers to use.
-   * - `{String}`       `requestMode`    The HTTP CORS mode to use.
-   * - `{Number}`       `timeout`        The requests timeout in ms (default: `5000`).
-   *
-   * @param  {Object} options The options object.
-   */
-  constructor(options = {}) {
-    const defaults = {
-      bucket: DEFAULT_BUCKET_NAME,
-      remote: DEFAULT_REMOTE
-    };
-    this._options = (0, _extends3.default)({}, defaults, options);
-    if (!this._options.adapter) {
-      throw new Error("No adapter provided");
-    }
-
-    const { remote, events, headers, requestMode, timeout, ApiClass } = this._options;
-
-    // public properties
-
-    /**
-     * The kinto HTTP client instance.
-     * @type {KintoClient}
-     */
-    this.api = new ApiClass(remote, { events, headers, requestMode, timeout });
-    /**
-     * The event emitter instance.
-     * @type {EventEmitter}
-     */
-    this.events = this._options.events;
-  }
-
-  /**
-   * Creates a {@link Collection} instance. The second (optional) parameter
-   * will set collection-level options like e.g. `remoteTransformers`.
-   *
-   * @param  {String} collName The collection name.
-   * @param  {Object} options  May contain the following fields:
-   *                           remoteTransformers: Array<RemoteTransformer>
-   * @return {Collection}
-   */
-  collection(collName, options = {}) {
-    if (!collName) {
-      throw new Error("missing collection name");
-    }
-
-    const bucket = this._options.bucket;
-    return new _collection2.default(bucket, collName, this.api, {
-      events: this._options.events,
-      adapter: this._options.adapter,
-      adapterOptions: this._options.adapterOptions,
-      dbPrefix: this._options.dbPrefix,
-      idSchema: options.idSchema,
-      remoteTransformers: options.remoteTransformers,
-      hooks: options.hooks
-    });
-  }
-}
-exports.default = KintoBase;
-
-},{"./adapters/base":85,"./collection":86,"babel-runtime/helpers/extends":8}],84:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
-
-var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _keys = require("babel-runtime/core-js/object/keys");
-
-var _keys2 = _interopRequireDefault(_keys);
-
-var _base = require("./base.js");
-
-var _base2 = _interopRequireDefault(_base);
-
-var _utils = require("../utils");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const INDEXED_FIELDS = ["id", "_status", "last_modified"];
-
-/**
- * IDB cursor handlers.
- * @type {Object}
- */
-const cursorHandlers = {
-  all(filters, done) {
-    const results = [];
-    return function (event) {
-      const cursor = event.target.result;
-      if (cursor) {
-        if ((0, _utils.filterObject)(filters, cursor.value)) {
-          results.push(cursor.value);
-        }
-        cursor.continue();
-      } else {
-        done(results);
-      }
-    };
-  },
-
-  in(values, done) {
-    if (values.length === 0) {
-      return done([]);
-    }
-    const sortedValues = [].slice.call(values).sort();
-    const results = [];
-    return function (event) {
-      const cursor = event.target.result;
-      if (!cursor) {
-        done(results);
-        return;
-      }
-      const { key, value } = cursor;
-      let i = 0;
-      while (key > sortedValues[i]) {
-        // The cursor has passed beyond this key. Check next.
-        ++i;
-        if (i === sortedValues.length) {
-          done(results); // There is no next. Stop searching.
-          return;
-        }
-      }
-      if (key === sortedValues[i]) {
-        results.push(value);
-        cursor.continue();
-      } else {
-        cursor.continue(sortedValues[i]);
-      }
-    };
-  }
-};
-
-/**
- * Extract from filters definition the first indexed field. Since indexes were
- * created on single-columns, extracting a single one makes sense.
- *
- * @param  {Object} filters The filters object.
- * @return {String|undefined}
- */
-function findIndexedField(filters) {
-  const filteredFields = (0, _keys2.default)(filters);
-  const indexedFields = filteredFields.filter(field => {
-    return INDEXED_FIELDS.indexOf(field) !== -1;
-  });
-  return indexedFields[0];
-}
-
-/**
- * Creates an IDB request and attach it the appropriate cursor event handler to
- * perform a list query.
- *
- * Multiple matching values are handled by passing an array.
- *
- * @param  {IDBStore}         store      The IDB store.
- * @param  {String|undefined} indexField The indexed field to query, if any.
- * @param  {Any}              value      The value to filter, if any.
- * @param  {Object}           filters    More filters.
- * @param  {Function}         done       The operation completion handler.
- * @return {IDBRequest}
- */
-function createListRequest(store, indexField, value, filters, done) {
-  if (!indexField) {
-    // Get all records.
-    const request = store.openCursor();
-    request.onsuccess = cursorHandlers.all(filters, done);
-    return request;
-  }
-
-  // WHERE IN equivalent clause
-  if (Array.isArray(value)) {
-    const request = store.index(indexField).openCursor();
-    request.onsuccess = cursorHandlers.in(value, done);
-    return request;
-  }
-
-  // WHERE field = value clause
-  const request = store.index(indexField).openCursor(IDBKeyRange.only(value));
-  request.onsuccess = cursorHandlers.all(filters, done);
-  return request;
-}
-
-/**
- * IndexedDB adapter.
- *
- * This adapter doesn't support any options.
- */
-class IDB extends _base2.default {
-  /**
-   * Constructor.
-   *
-   * @param  {String} dbname The database nale.
-   */
-  constructor(dbname) {
-    super();
-    this._db = null;
-    // public properties
-    /**
-     * The database name.
-     * @type {String}
-     */
-    this.dbname = dbname;
-  }
-
-  _handleError(method, err) {
-    const error = new Error(method + "() " + err.message);
-    error.stack = err.stack;
-    throw error;
-  }
-
-  /**
-   * Ensures a connection to the IndexedDB database has been opened.
-   *
-   * @override
-   * @return {Promise}
-   */
-  open() {
-    if (this._db) {
-      return _promise2.default.resolve(this);
-    }
-    return new _promise2.default((resolve, reject) => {
-      const request = indexedDB.open(this.dbname, 1);
-      request.onupgradeneeded = event => {
-        // DB object
-        const db = event.target.result;
-        // Main collection store
-        const collStore = db.createObjectStore(this.dbname, {
-          keyPath: "id"
-        });
-        // Primary key (generated by IdSchema, UUID by default)
-        collStore.createIndex("id", "id", { unique: true });
-        // Local record status ("synced", "created", "updated", "deleted")
-        collStore.createIndex("_status", "_status");
-        // Last modified field
-        collStore.createIndex("last_modified", "last_modified");
-
-        // Metadata store
-        const metaStore = db.createObjectStore("__meta__", {
-          keyPath: "name"
-        });
-        metaStore.createIndex("name", "name", { unique: true });
-      };
-      request.onerror = event => reject(event.target.error);
-      request.onsuccess = event => {
-        this._db = event.target.result;
-        resolve(this);
-      };
-    });
-  }
-
-  /**
-   * Closes current connection to the database.
-   *
-   * @override
-   * @return {Promise}
-   */
-  close() {
-    if (this._db) {
-      this._db.close(); // indexedDB.close is synchronous
-      this._db = null;
-    }
-    return super.close();
-  }
-
-  /**
-   * Returns a transaction and a store objects for this collection.
-   *
-   * To determine if a transaction has completed successfully, we should rather
-   * listen to the transaction’s complete event rather than the IDBObjectStore
-   * request’s success event, because the transaction may still fail after the
-   * success event fires.
-   *
-   * @param  {String}      mode  Transaction mode ("readwrite" or undefined)
-   * @param  {String|null} name  Store name (defaults to coll name)
-   * @return {Object}
-   */
-  prepare(mode = undefined, name = null) {
-    const storeName = name || this.dbname;
-    // On Safari, calling IDBDatabase.transaction with mode == undefined raises
-    // a TypeError.
-    const transaction = mode ? this._db.transaction([storeName], mode) : this._db.transaction([storeName]);
-    const store = transaction.objectStore(storeName);
-    return { transaction, store };
-  }
-
-  /**
-   * Deletes every records in the current collection.
-   *
-   * @override
-   * @return {Promise}
-   */
-  clear() {
-    var _this = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      try {
-        yield _this.open();
-        return new _promise2.default(function (resolve, reject) {
-          const { transaction, store } = _this.prepare("readwrite");
-          store.clear();
-          transaction.onerror = function (event) {
-            return reject(new Error(event.target.error));
-          };
-          transaction.oncomplete = function () {
-            return resolve();
-          };
-        });
-      } catch (e) {
-        _this._handleError("clear", e);
-      }
-    })();
-  }
-
-  /**
-   * Executes the set of synchronous CRUD operations described in the provided
-   * callback within an IndexedDB transaction, for current db store.
-   *
-   * The callback will be provided an object exposing the following synchronous
-   * CRUD operation methods: get, create, update, delete.
-   *
-   * Important note: because limitations in IndexedDB implementations, no
-   * asynchronous code should be performed within the provided callback; the
-   * promise will therefore be rejected if the callback returns a Promise.
-   *
-   * Options:
-   * - {Array} preload: The list of record IDs to fetch and make available to
-   *   the transaction object get() method (default: [])
-   *
-   * @example
-   * const db = new IDB("example");
-   * db.execute(transaction => {
-   *   transaction.create({id: 1, title: "foo"});
-   *   transaction.update({id: 2, title: "bar"});
-   *   transaction.delete(3);
-   *   return "foo";
-   * })
-   *   .catch(console.error.bind(console));
-   *   .then(console.log.bind(console)); // => "foo"
-   *
-   * @param  {Function} callback The operation description callback.
-   * @param  {Object}   options  The options object.
-   * @return {Promise}
-   */
-  execute(callback, options = { preload: [] }) {
-    var _this2 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      // Transactions in IndexedDB are autocommited when a callback does not
-      // perform any additional operation.
-      // The way Promises are implemented in Firefox (see https://bugzilla.mozilla.org/show_bug.cgi?id=1193394)
-      // prevents using within an opened transaction.
-      // To avoid managing asynchronocity in the specified `callback`, we preload
-      // a list of record in order to execute the `callback` synchronously.
-      // See also:
-      // - http://stackoverflow.com/a/28388805/330911
-      // - http://stackoverflow.com/a/10405196
-      // - https://jakearchibald.com/2015/tasks-microtasks-queues-and-schedules/
-      yield _this2.open();
-      return new _promise2.default(function (resolve, reject) {
-        // Start transaction.
-        const { transaction, store } = _this2.prepare("readwrite");
-        // Preload specified records using index.
-        const ids = options.preload;
-        store.index("id").openCursor().onsuccess = cursorHandlers.in(ids, function (records) {
-          // Store obtained records by id.
-          const preloaded = records.reduce(function (acc, record) {
-            acc[record.id] = record;
-            return acc;
-          }, {});
-          // Expose a consistent API for every adapter instead of raw store methods.
-          const proxy = transactionProxy(store, preloaded);
-          // The callback is executed synchronously within the same transaction.
-          let result;
-          try {
-            result = callback(proxy);
-          } catch (e) {
-            transaction.abort();
-            reject(e);
-          }
-          if (result instanceof _promise2.default) {
-            // XXX: investigate how to provide documentation details in error.
-            reject(new Error("execute() callback should not return a Promise."));
-          }
-          // XXX unsure if we should manually abort the transaction on error
-          transaction.onerror = function (event) {
-            return reject(new Error(event.target.error));
-          };
-          transaction.oncomplete = function (event) {
-            return resolve(result);
-          };
-        });
-      });
-    })();
-  }
+this.FirefoxAdapter = FirefoxAdapter;
 
-  /**
-   * Retrieve a record by its primary key from the IndexedDB database.
-   *
-   * @override
-   * @param  {String} id The record id.
-   * @return {Promise}
-   */
-  get(id) {
-    var _this3 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      try {
-        yield _this3.open();
-        return new _promise2.default(function (resolve, reject) {
-          const { transaction, store } = _this3.prepare();
-          const request = store.get(id);
-          transaction.onerror = function (event) {
-            return reject(new Error(event.target.error));
-          };
-          transaction.oncomplete = function () {
-            return resolve(request.result);
-          };
-        });
-      } catch (e) {
-        _this3._handleError("get", e);
-      }
-    })();
-  }
-
-  /**
-   * Lists all records from the IndexedDB database.
-   *
-   * @override
-   * @return {Promise}
-   */
-  list(params = { filters: {} }) {
-    var _this4 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const { filters } = params;
-      const indexField = findIndexedField(filters);
-      const value = filters[indexField];
-      try {
-        yield _this4.open();
-        const results = yield new _promise2.default(function (resolve, reject) {
-          let results = [];
-          // If `indexField` was used already, don't filter again.
-          const remainingFilters = (0, _utils.omitKeys)(filters, indexField);
-
-          const { transaction, store } = _this4.prepare();
-          createListRequest(store, indexField, value, remainingFilters, function (_results) {
-            // we have received all requested records, parking them within
-            // current scope
-            results = _results;
-          });
-          transaction.onerror = function (event) {
-            return reject(new Error(event.target.error));
-          };
-          transaction.oncomplete = function (event) {
-            return resolve(results);
-          };
-        });
-
-        // The resulting list of records is sorted.
-        // XXX: with some efforts, this could be fully implemented using IDB API.
-        return params.order ? (0, _utils.sortObjects)(params.order, results) : results;
-      } catch (e) {
-        _this4._handleError("list", e);
-      }
-    })();
-  }
-
-  /**
-   * Store the lastModified value into metadata store.
-   *
-   * @override
-   * @param  {Number}  lastModified
-   * @return {Promise}
-   */
-  saveLastModified(lastModified) {
-    var _this5 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const value = parseInt(lastModified, 10) || null;
-      yield _this5.open();
-      return new _promise2.default(function (resolve, reject) {
-        const { transaction, store } = _this5.prepare("readwrite", "__meta__");
-        store.put({ name: "lastModified", value: value });
-        transaction.onerror = function (event) {
-          return reject(event.target.error);
-        };
-        transaction.oncomplete = function (event) {
-          return resolve(value);
-        };
-      });
-    })();
-  }
-
-  /**
-   * Retrieve saved lastModified value.
-   *
-   * @override
-   * @return {Promise}
-   */
-  getLastModified() {
-    var _this6 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      yield _this6.open();
-      return new _promise2.default(function (resolve, reject) {
-        const { transaction, store } = _this6.prepare(undefined, "__meta__");
-        const request = store.get("lastModified");
-        transaction.onerror = function (event) {
-          return reject(event.target.error);
-        };
-        transaction.oncomplete = function (event) {
-          resolve(request.result && request.result.value || null);
-        };
-      });
-    })();
-  }
-
-  /**
-   * Load a dump of records exported from a server.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  loadDump(records) {
-    var _this7 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      try {
-        yield _this7.execute(function (transaction) {
-          records.forEach(function (record) {
-            return transaction.update(record);
-          });
-        });
-        const previousLastModified = yield _this7.getLastModified();
-        const lastModified = Math.max(...records.map(function (record) {
-          return record.last_modified;
-        }));
-        if (lastModified > previousLastModified) {
-          yield _this7.saveLastModified(lastModified);
-        }
-        return records;
-      } catch (e) {
-        _this7._handleError("loadDump", e);
-      }
-    })();
-  }
-}
-
-exports.default = IDB; /**
-                        * IDB transaction proxy.
-                        *
-                        * @param  {IDBStore} store     The IndexedDB database store.
-                        * @param  {Array}    preloaded The list of records to make available to
-                        *                              get() (default: []).
-                        * @return {Object}
-                        */
-
-function transactionProxy(store, preloaded = []) {
-  return {
-    create(record) {
-      store.add(record);
-    },
-
-    update(record) {
-      store.put(record);
-    },
-
-    delete(id) {
-      store.delete(id);
-    },
-
-    get(id) {
-      return preloaded[id];
-    }
-  };
-}
-
-},{"../utils":87,"./base.js":85,"babel-runtime/core-js/object/keys":5,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/asyncToGenerator":7}],85:[function(require,module,exports){
-"use strict";
-
-/**
- * Base db adapter.
- *
- * @abstract
- */
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-class BaseAdapter {
-  /**
-   * Opens a connection to the database.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  open() {
-    return _promise2.default.resolve();
-  }
-
-  /**
-   * Closes current connection to the database.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  close() {
-    return _promise2.default.resolve();
-  }
-
-  /**
-   * Deletes every records present in the database.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  clear() {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Executes a batch of operations within a single transaction.
-   *
-   * @abstract
-   * @param  {Function} callback The operation callback.
-   * @param  {Object}   options  The options object.
-   * @return {Promise}
-   */
-  execute(callback, options = { preload: [] }) {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Retrieve a record by its primary key from the database.
-   *
-   * @abstract
-   * @param  {String} id The record id.
-   * @return {Promise}
-   */
-  get(id) {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Lists all records from the database.
-   *
-   * @abstract
-   * @param  {Object} params  The filters and order to apply to the results.
-   * @return {Promise}
-   */
-  list(params = { filters: {}, order: "" }) {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Store the lastModified value.
-   *
-   * @abstract
-   * @param  {Number}  lastModified
-   * @return {Promise}
-   */
-  saveLastModified(lastModified) {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Retrieve saved lastModified value.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  getLastModified() {
-    throw new Error("Not Implemented.");
-  }
-
-  /**
-   * Load a dump of records exported from a server.
-   *
-   * @abstract
-   * @return {Promise}
-   */
-  loadDump(records) {
-    throw new Error("Not Implemented.");
-  }
-}
-exports.default = BaseAdapter;
-
-},{"babel-runtime/core-js/promise":6}],86:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.CollectionTransaction = exports.SyncResultObject = undefined;
-
-var _stringify = require("babel-runtime/core-js/json/stringify");
-
-var _stringify2 = _interopRequireDefault(_stringify);
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _asyncToGenerator2 = require("babel-runtime/helpers/asyncToGenerator");
-
-var _asyncToGenerator3 = _interopRequireDefault(_asyncToGenerator2);
-
-var _extends2 = require("babel-runtime/helpers/extends");
-
-var _extends3 = _interopRequireDefault(_extends2);
-
-var _assign = require("babel-runtime/core-js/object/assign");
-
-var _assign2 = _interopRequireDefault(_assign);
-
-exports.recordsEqual = recordsEqual;
-
-var _base = require("./adapters/base");
-
-var _base2 = _interopRequireDefault(_base);
-
-var _IDB = require("./adapters/IDB");
-
-var _IDB2 = _interopRequireDefault(_IDB);
-
-var _utils = require("./utils");
-
-var _uuid = require("uuid");
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const RECORD_FIELDS_TO_CLEAN = ["_status"];
-const AVAILABLE_HOOKS = ["incoming-changes"];
-
-/**
- * Compare two records omitting local fields and synchronization
- * attributes (like _status and last_modified)
- * @param {Object} a    A record to compare.
- * @param {Object} b    A record to compare.
- * @return {boolean}
- */
-function recordsEqual(a, b, localFields = []) {
-  const fieldsToClean = RECORD_FIELDS_TO_CLEAN.concat(["last_modified"]).concat(localFields);
-  const cleanLocal = r => (0, _utils.omitKeys)(r, fieldsToClean);
-  return (0, _utils.deepEqual)(cleanLocal(a), cleanLocal(b));
-}
-
-/**
- * Synchronization result object.
- */
-class SyncResultObject {
-  /**
-   * Object default values.
-   * @type {Object}
-   */
-  static get defaults() {
-    return {
-      ok: true,
-      lastModified: null,
-      errors: [],
-      created: [],
-      updated: [],
-      deleted: [],
-      published: [],
-      conflicts: [],
-      skipped: [],
-      resolved: []
-    };
-  }
-
-  /**
-   * Public constructor.
-   */
-  constructor() {
-    /**
-     * Current synchronization result status; becomes `false` when conflicts or
-     * errors are registered.
-     * @type {Boolean}
-     */
-    this.ok = true;
-    (0, _assign2.default)(this, SyncResultObject.defaults);
-  }
-
-  /**
-   * Adds entries for a given result type.
-   *
-   * @param {String} type    The result type.
-   * @param {Array}  entries The result entries.
-   * @return {SyncResultObject}
-   */
-  add(type, entries) {
-    if (!Array.isArray(this[type])) {
-      return;
-    }
-    // Deduplicate entries by id. If the values don't have `id` attribute, just
-    // keep all.
-    const deduplicated = this[type].concat(entries).reduce((acc, cur) => {
-      const existing = acc.filter(r => cur.id && r.id ? cur.id != r.id : true);
-      return existing.concat(cur);
-    }, []);
-    this[type] = deduplicated;
-    this.ok = this.errors.length + this.conflicts.length === 0;
-    return this;
-  }
-
-  /**
-   * Reinitializes result entries for a given result type.
-   *
-   * @param  {String} type The result type.
-   * @return {SyncResultObject}
-   */
-  reset(type) {
-    this[type] = SyncResultObject.defaults[type];
-    this.ok = this.errors.length + this.conflicts.length === 0;
-    return this;
-  }
-}
-
-exports.SyncResultObject = SyncResultObject;
-function createUUIDSchema() {
-  return {
-    generate() {
-      return (0, _uuid.v4)();
-    },
-
-    validate(id) {
-      return (0, _utils.isUUID)(id);
-    }
-  };
-}
-
-function markStatus(record, status) {
-  return (0, _extends3.default)({}, record, { _status: status });
-}
-
-function markDeleted(record) {
-  return markStatus(record, "deleted");
-}
-
-function markSynced(record) {
-  return markStatus(record, "synced");
-}
-
-/**
- * Import a remote change into the local database.
- *
- * @param  {IDBTransactionProxy} transaction The transaction handler.
- * @param  {Object}              remote      The remote change object to import.
- * @param  {Array<String>}       localFields The list of fields that remain local.
- * @return {Object}
- */
-function importChange(transaction, remote, localFields) {
-  const local = transaction.get(remote.id);
-  if (!local) {
-    // Not found locally but remote change is marked as deleted; skip to
-    // avoid recreation.
-    if (remote.deleted) {
-      return { type: "skipped", data: remote };
-    }
-    const synced = markSynced(remote);
-    transaction.create(synced);
-    return { type: "created", data: synced };
-  }
-  // Compare local and remote, ignoring local fields.
-  const isIdentical = recordsEqual(local, remote, localFields);
-  // Apply remote changes on local record.
-  const synced = (0, _extends3.default)({}, local, markSynced(remote));
-  // Detect or ignore conflicts if record has also been modified locally.
-  if (local._status !== "synced") {
-    // Locally deleted, unsynced: scheduled for remote deletion.
-    if (local._status === "deleted") {
-      return { type: "skipped", data: local };
-    }
-    if (isIdentical) {
-      // If records are identical, import anyway, so we bump the
-      // local last_modified value from the server and set record
-      // status to "synced".
-      transaction.update(synced);
-      return { type: "updated", data: { old: local, new: synced } };
-    }
-    if (local.last_modified !== undefined && local.last_modified === remote.last_modified) {
-      // If our local version has the same last_modified as the remote
-      // one, this represents an object that corresponds to a resolved
-      // conflict. Our local version represents the final output, so
-      // we keep that one. (No transaction operation to do.)
-      // But if our last_modified is undefined,
-      // that means we've created the same object locally as one on
-      // the server, which *must* be a conflict.
-      return { type: "void" };
-    }
-    return {
-      type: "conflicts",
-      data: { type: "incoming", local: local, remote: remote }
-    };
-  }
-  // Local record was synced.
-  if (remote.deleted) {
-    transaction.delete(remote.id);
-    return { type: "deleted", data: local };
-  }
-  // Import locally.
-  transaction.update(synced);
-  // if identical, simply exclude it from all SyncResultObject lists
-  const type = isIdentical ? "void" : "updated";
-  return { type, data: { old: local, new: synced } };
-}
-
-/**
- * Abstracts a collection of records stored in the local database, providing
- * CRUD operations and synchronization helpers.
- */
-class Collection {
-  /**
-   * Constructor.
-   *
-   * Options:
-   * - `{BaseAdapter} adapter` The DB adapter (default: `IDB`)
-   * - `{String} dbPrefix`     The DB name prefix (default: `""`)
-   *
-   * @param  {String} bucket  The bucket identifier.
-   * @param  {String} name    The collection name.
-   * @param  {Api}    api     The Api instance.
-   * @param  {Object} options The options object.
-   */
-  constructor(bucket, name, api, options = {}) {
-    this._bucket = bucket;
-    this._name = name;
-    this._lastModified = null;
-
-    const DBAdapter = options.adapter || _IDB2.default;
-    if (!DBAdapter) {
-      throw new Error("No adapter provided");
-    }
-    const dbPrefix = options.dbPrefix || "";
-    const db = new DBAdapter(`${ dbPrefix }${ bucket }/${ name }`, options.adapterOptions);
-    if (!(db instanceof _base2.default)) {
-      throw new Error("Unsupported adapter.");
-    }
-    // public properties
-    /**
-     * The db adapter instance
-     * @type {BaseAdapter}
-     */
-    this.db = db;
-    /**
-     * The Api instance.
-     * @type {KintoClient}
-     */
-    this.api = api;
-    /**
-     * The event emitter instance.
-     * @type {EventEmitter}
-     */
-    this.events = options.events;
-    /**
-     * The IdSchema instance.
-     * @type {Object}
-     */
-    this.idSchema = this._validateIdSchema(options.idSchema);
-    /**
-     * The list of remote transformers.
-     * @type {Array}
-     */
-    this.remoteTransformers = this._validateRemoteTransformers(options.remoteTransformers);
-    /**
-     * The list of hooks.
-     * @type {Object}
-     */
-    this.hooks = this._validateHooks(options.hooks);
-    /**
-     * The list of fields names that will remain local.
-     * @type {Array}
-     */
-    this.localFields = options.localFields || [];
-  }
-
-  /**
-   * The collection name.
-   * @type {String}
-   */
-  get name() {
-    return this._name;
-  }
-
-  /**
-   * The bucket name.
-   * @type {String}
-   */
-  get bucket() {
-    return this._bucket;
-  }
-
-  /**
-   * The last modified timestamp.
-   * @type {Number}
-   */
-  get lastModified() {
-    return this._lastModified;
-  }
-
-  /**
-   * Synchronization strategies. Available strategies are:
-   *
-   * - `MANUAL`: Conflicts will be reported in a dedicated array.
-   * - `SERVER_WINS`: Conflicts are resolved using remote data.
-   * - `CLIENT_WINS`: Conflicts are resolved using local data.
-   *
-   * @type {Object}
-   */
-  static get strategy() {
-    return {
-      CLIENT_WINS: "client_wins",
-      SERVER_WINS: "server_wins",
-      MANUAL: "manual"
-    };
-  }
-
-  /**
-   * Validates an idSchema.
-   *
-   * @param  {Object|undefined} idSchema
-   * @return {Object}
-   */
-  _validateIdSchema(idSchema) {
-    if (typeof idSchema === "undefined") {
-      return createUUIDSchema();
-    }
-    if (typeof idSchema !== "object") {
-      throw new Error("idSchema must be an object.");
-    } else if (typeof idSchema.generate !== "function") {
-      throw new Error("idSchema must provide a generate function.");
-    } else if (typeof idSchema.validate !== "function") {
-      throw new Error("idSchema must provide a validate function.");
-    }
-    return idSchema;
-  }
-
-  /**
-   * Validates a list of remote transformers.
-   *
-   * @param  {Array|undefined} remoteTransformers
-   * @return {Array}
-   */
-  _validateRemoteTransformers(remoteTransformers) {
-    if (typeof remoteTransformers === "undefined") {
-      return [];
-    }
-    if (!Array.isArray(remoteTransformers)) {
-      throw new Error("remoteTransformers should be an array.");
-    }
-    return remoteTransformers.map(transformer => {
-      if (typeof transformer !== "object") {
-        throw new Error("A transformer must be an object.");
-      } else if (typeof transformer.encode !== "function") {
-        throw new Error("A transformer must provide an encode function.");
-      } else if (typeof transformer.decode !== "function") {
-        throw new Error("A transformer must provide a decode function.");
-      }
-      return transformer;
-    });
-  }
-
-  /**
-   * Validate the passed hook is correct.
-   *
-   * @param {Array|undefined} hook.
-   * @return {Array}
-   **/
-  _validateHook(hook) {
-    if (!Array.isArray(hook)) {
-      throw new Error("A hook definition should be an array of functions.");
-    }
-    return hook.map(fn => {
-      if (typeof fn !== "function") {
-        throw new Error("A hook definition should be an array of functions.");
-      }
-      return fn;
-    });
-  }
-
-  /**
-   * Validates a list of hooks.
-   *
-   * @param  {Object|undefined} hooks
-   * @return {Object}
-   */
-  _validateHooks(hooks) {
-    if (typeof hooks === "undefined") {
-      return {};
-    }
-    if (Array.isArray(hooks)) {
-      throw new Error("hooks should be an object, not an array.");
-    }
-    if (typeof hooks !== "object") {
-      throw new Error("hooks should be an object.");
-    }
-
-    const validatedHooks = {};
-
-    for (let hook in hooks) {
-      if (AVAILABLE_HOOKS.indexOf(hook) === -1) {
-        throw new Error("The hook should be one of " + AVAILABLE_HOOKS.join(", "));
-      }
-      validatedHooks[hook] = this._validateHook(hooks[hook]);
-    }
-    return validatedHooks;
-  }
-
-  /**
-   * Deletes every records in the current collection and marks the collection as
-   * never synced.
-   *
-   * @return {Promise}
-   */
-  clear() {
-    var _this = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      yield _this.db.clear();
-      yield _this.db.saveLastModified(null);
-      return { data: [], permissions: {} };
-    })();
-  }
-
-  /**
-   * Encodes a record.
-   *
-   * @param  {String} type   Either "remote" or "local".
-   * @param  {Object} record The record object to encode.
-   * @return {Promise}
-   */
-  _encodeRecord(type, record) {
-    if (!this[`${ type }Transformers`].length) {
-      return _promise2.default.resolve(record);
-    }
-    return (0, _utils.waterfall)(this[`${ type }Transformers`].map(transformer => {
-      return record => transformer.encode(record);
-    }), record);
-  }
-
-  /**
-   * Decodes a record.
-   *
-   * @param  {String} type   Either "remote" or "local".
-   * @param  {Object} record The record object to decode.
-   * @return {Promise}
-   */
-  _decodeRecord(type, record) {
-    if (!this[`${ type }Transformers`].length) {
-      return _promise2.default.resolve(record);
-    }
-    return (0, _utils.waterfall)(this[`${ type }Transformers`].reverse().map(transformer => {
-      return record => transformer.decode(record);
-    }), record);
-  }
-
-  /**
-   * Adds a record to the local database, asserting that none
-   * already exist with this ID.
-   *
-   * Note: If either the `useRecordId` or `synced` options are true, then the
-   * record object must contain the id field to be validated. If none of these
-   * options are true, an id is generated using the current IdSchema; in this
-   * case, the record passed must not have an id.
-   *
-   * Options:
-   * - {Boolean} synced       Sets record status to "synced" (default: `false`).
-   * - {Boolean} useRecordId  Forces the `id` field from the record to be used,
-   *                          instead of one that is generated automatically
-   *                          (default: `false`).
-   *
-   * @param  {Object} record
-   * @param  {Object} options
-   * @return {Promise}
-   */
-  create(record, options = { useRecordId: false, synced: false }) {
-    // Validate the record and its ID (if any), even though this
-    // validation is also done in the CollectionTransaction method,
-    // because we need to pass the ID to preloadIds.
-    const reject = msg => _promise2.default.reject(new Error(msg));
-    if (typeof record !== "object") {
-      return reject("Record is not an object.");
-    }
-    if ((options.synced || options.useRecordId) && !record.hasOwnProperty("id")) {
-      return reject("Missing required Id; synced and useRecordId options require one");
-    }
-    if (!options.synced && !options.useRecordId && record.hasOwnProperty("id")) {
-      return reject("Extraneous Id; can't create a record having one set.");
-    }
-    const newRecord = (0, _extends3.default)({}, record, {
-      id: options.synced || options.useRecordId ? record.id : this.idSchema.generate(),
-      _status: options.synced ? "synced" : "created"
-    });
-    if (!this.idSchema.validate(newRecord.id)) {
-      return reject(`Invalid Id: ${ newRecord.id }`);
-    }
-    return this.execute(txn => txn.create(newRecord), { preloadIds: [newRecord.id] }).catch(err => {
-      if (options.useRecordId) {
-        throw new Error("Couldn't create record. It may have been virtually deleted.");
-      }
-      throw err;
-    });
-  }
-
-  /**
-   * Like {@link CollectionTransaction#update}, but wrapped in its own transaction.
-   *
-   * Options:
-   * - {Boolean} synced: Sets record status to "synced" (default: false)
-   * - {Boolean} patch:  Extends the existing record instead of overwriting it
-   *   (default: false)
-   *
-   * @param  {Object} record
-   * @param  {Object} options
-   * @return {Promise}
-   */
-  update(record, options = { synced: false, patch: false }) {
-    // Validate the record and its ID, even though this validation is
-    // also done in the CollectionTransaction method, because we need
-    // to pass the ID to preloadIds.
-    if (typeof record !== "object") {
-      return _promise2.default.reject(new Error("Record is not an object."));
-    }
-    if (!record.hasOwnProperty("id")) {
-      return _promise2.default.reject(new Error("Cannot update a record missing id."));
-    }
-    if (!this.idSchema.validate(record.id)) {
-      return _promise2.default.reject(new Error(`Invalid Id: ${ record.id }`));
-    }
-
-    return this.execute(txn => txn.update(record, options), { preloadIds: [record.id] });
-  }
-
-  /**
-   * Like {@link CollectionTransaction#upsert}, but wrapped in its own transaction.
-   *
-   * @param  {Object} record
-   * @return {Promise}
-   */
-  upsert(record) {
-    // Validate the record and its ID, even though this validation is
-    // also done in the CollectionTransaction method, because we need
-    // to pass the ID to preloadIds.
-    if (typeof record !== "object") {
-      return _promise2.default.reject(new Error("Record is not an object."));
-    }
-    if (!record.hasOwnProperty("id")) {
-      return _promise2.default.reject(new Error("Cannot update a record missing id."));
-    }
-    if (!this.idSchema.validate(record.id)) {
-      return _promise2.default.reject(new Error(`Invalid Id: ${ record.id }`));
-    }
-
-    return this.execute(txn => txn.upsert(record), { preloadIds: [record.id] });
-  }
-
-  /**
-   * Like {@link CollectionTransaction#get}, but wrapped in its own transaction.
-   *
-   * Options:
-   * - {Boolean} includeDeleted: Include virtually deleted records.
-   *
-   * @param  {String} id
-   * @param  {Object} options
-   * @return {Promise}
-   */
-  get(id, options = { includeDeleted: false }) {
-    return this.execute(txn => txn.get(id, options), { preloadIds: [id] });
-  }
-
-  /**
-   * Like {@link CollectionTransaction#getAny}, but wrapped in its own transaction.
-   *
-   * @param  {String} id
-   * @return {Promise}
-   */
-  getAny(id) {
-    return this.execute(txn => txn.getAny(id), { preloadIds: [id] });
-  }
-
-  /**
-   * Same as {@link Collection#delete}, but wrapped in its own transaction.
-   *
-   * Options:
-   * - {Boolean} virtual: When set to `true`, doesn't actually delete the record,
-   *   update its `_status` attribute to `deleted` instead (default: true)
-   *
-   * @param  {String} id       The record's Id.
-   * @param  {Object} options  The options object.
-   * @return {Promise}
-   */
-  delete(id, options = { virtual: true }) {
-    return this.execute(transaction => {
-      return transaction.delete(id, options);
-    }, { preloadIds: [id] });
-  }
-
-  /**
-   * The same as {@link CollectionTransaction#deleteAny}, but wrapped
-   * in its own transaction.
-   *
-   * @param  {String} id       The record's Id.
-   * @return {Promise}
-   */
-  deleteAny(id) {
-    return this.execute(txn => txn.deleteAny(id), { preloadIds: [id] });
-  }
-
-  /**
-   * Lists records from the local database.
-   *
-   * Params:
-   * - {Object} filters Filter the results (default: `{}`).
-   * - {String} order   The order to apply   (default: `-last_modified`).
-   *
-   * Options:
-   * - {Boolean} includeDeleted: Include virtually deleted records.
-   *
-   * @param  {Object} params  The filters and order to apply to the results.
-   * @param  {Object} options The options object.
-   * @return {Promise}
-   */
-  list(params = {}, options = { includeDeleted: false }) {
-    var _this2 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      params = (0, _extends3.default)({ order: "-last_modified", filters: {} }, params);
-      const results = yield _this2.db.list(params);
-      let data = results;
-      if (!options.includeDeleted) {
-        data = results.filter(function (record) {
-          return record._status !== "deleted";
-        });
-      }
-      return { data, permissions: {} };
-    })();
-  }
-
-  /**
-   * Imports remote changes into the local database.
-   * This method is in charge of detecting the conflicts, and resolve them
-   * according to the specified strategy.
-   * @param  {SyncResultObject} syncResultObject The sync result object.
-   * @param  {Array}            decodedChanges   The list of changes to import in the local database.
-   * @param  {String}           strategy         The {@link Collection.strategy} (default: MANUAL)
-   * @return {Promise}
-   */
-  importChanges(syncResultObject, decodedChanges, strategy = Collection.strategy.MANUAL) {
-    var _this3 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      // Retrieve records matching change ids.
-      try {
-        const { imports, resolved } = yield _this3.db.execute(function (transaction) {
-          const imports = decodedChanges.map(function (remote) {
-            // Store remote change into local database.
-            return importChange(transaction, remote, _this3.localFields);
-          });
-          const conflicts = imports.filter(function (i) {
-            return i.type === "conflicts";
-          }).map(function (i) {
-            return i.data;
-          });
-          const resolved = _this3._handleConflicts(transaction, conflicts, strategy);
-          return { imports, resolved };
-        }, { preload: decodedChanges.map(function (record) {
-            return record.id;
-          }) });
-
-        // Lists of created/updated/deleted records
-        imports.forEach(function ({ type, data }) {
-          return syncResultObject.add(type, data);
-        });
-
-        // Automatically resolved conflicts (if not manual)
-        if (resolved.length > 0) {
-          syncResultObject.reset("conflicts").add("resolved", resolved);
-        }
-      } catch (err) {
-        const data = {
-          type: "incoming",
-          message: err.message,
-          stack: err.stack
-        };
-        // XXX one error of the whole transaction instead of per atomic op
-        syncResultObject.add("errors", data);
-      }
-
-      return syncResultObject;
-    })();
-  }
-
-  /**
-   * Imports the responses of pushed changes into the local database.
-   * Basically it stores the timestamp assigned by the server into the local
-   * database.
-   * @param  {SyncResultObject} syncResultObject The sync result object.
-   * @param  {Array}            toApplyLocally   The list of changes to import in the local database.
-   * @param  {Array}            conflicts        The list of conflicts that have to be resolved.
-   * @param  {String}           strategy         The {@link Collection.strategy}.
-   * @return {Promise}
-   */
-  _applyPushedResults(syncResultObject, toApplyLocally, conflicts, strategy = Collection.strategy.MANUAL) {
-    var _this4 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const toDeleteLocally = toApplyLocally.filter(function (r) {
-        return r.deleted;
-      });
-      const toUpdateLocally = toApplyLocally.filter(function (r) {
-        return !r.deleted;
-      });
-
-      const { published, resolved } = yield _this4.db.execute(function (transaction) {
-        const updated = toUpdateLocally.map(function (record) {
-          const synced = markSynced(record);
-          transaction.update(synced);
-          return synced;
-        });
-        const deleted = toDeleteLocally.map(function (record) {
-          transaction.delete(record.id);
-          // Amend result data with the deleted attribute set
-          return { id: record.id, deleted: true };
-        });
-        const published = updated.concat(deleted);
-        // Handle conflicts, if any
-        const resolved = _this4._handleConflicts(transaction, conflicts, strategy);
-        return { published, resolved };
-      });
-
-      syncResultObject.add("published", published);
-
-      if (resolved.length > 0) {
-        syncResultObject.reset("conflicts").reset("resolved").add("resolved", resolved);
-      }
-      return syncResultObject;
-    })();
-  }
-
-  /**
-   * Handles synchronization conflicts according to specified strategy.
-   *
-   * @param  {SyncResultObject} result    The sync result object.
-   * @param  {String}           strategy  The {@link Collection.strategy}.
-   * @return {Promise}
-   */
-  _handleConflicts(transaction, conflicts, strategy) {
-    if (strategy === Collection.strategy.MANUAL) {
-      return [];
-    }
-    return conflicts.map(conflict => {
-      const resolution = strategy === Collection.strategy.CLIENT_WINS ? conflict.local : conflict.remote;
-      const updated = this._resolveRaw(conflict, resolution);
-      transaction.update(updated);
-      return updated;
-    });
-  }
-
-  /**
-   * Execute a bunch of operations in a transaction.
-   *
-   * This transaction should be atomic -- either all of its operations
-   * will succeed, or none will.
-   *
-   * The argument to this function is itself a function which will be
-   * called with a {@link CollectionTransaction}. Collection methods
-   * are available on this transaction, but instead of returning
-   * promises, they are synchronous. execute() returns a Promise whose
-   * value will be the return value of the provided function.
-   *
-   * Most operations will require access to the record itself, which
-   * must be preloaded by passing its ID in the preloadIds option.
-   *
-   * Options:
-   * - {Array} preloadIds: list of IDs to fetch at the beginning of
-   *   the transaction
-   *
-   * @return {Promise} Resolves with the result of the given function
-   *    when the transaction commits.
-   */
-  execute(doOperations, { preloadIds = [] } = {}) {
-    for (let id of preloadIds) {
-      if (!this.idSchema.validate(id)) {
-        return _promise2.default.reject(Error(`Invalid Id: ${ id }`));
-      }
-    }
-
-    return this.db.execute(transaction => {
-      const txn = new CollectionTransaction(this, transaction);
-      const result = doOperations(txn);
-      txn.emitEvents();
-      return result;
-    }, { preload: preloadIds });
-  }
-
-  /**
-   * Resets the local records as if they were never synced; existing records are
-   * marked as newly created, deleted records are dropped.
-   *
-   * A next call to {@link Collection.sync} will thus republish the whole
-   * content of the local collection to the server.
-   *
-   * @return {Promise} Resolves with the number of processed records.
-   */
-  resetSyncStatus() {
-    var _this5 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const unsynced = yield _this5.list({ filters: { _status: ["deleted", "synced"] }, order: "" }, { includeDeleted: true });
-      yield _this5.db.execute(function (transaction) {
-        unsynced.data.forEach(function (record) {
-          if (record._status === "deleted") {
-            // Garbage collect deleted records.
-            transaction.delete(record.id);
-          } else {
-            // Records that were synced become «created».
-            transaction.update((0, _extends3.default)({}, record, {
-              last_modified: undefined,
-              _status: "created"
-            }));
-          }
-        });
-      });
-      _this5._lastModified = null;
-      yield _this5.db.saveLastModified(null);
-      return unsynced.data.length;
-    })();
-  }
-
-  /**
-   * Returns an object containing two lists:
-   *
-   * - `toDelete`: unsynced deleted records we can safely delete;
-   * - `toSync`: local updates to send to the server.
-   *
-   * @return {Promise}
-   */
-  gatherLocalChanges() {
-    var _this6 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const unsynced = yield _this6.list({ filters: { _status: ["created", "updated"] }, order: "" });
-      const deleted = yield _this6.list({ filters: { _status: "deleted" }, order: "" }, { includeDeleted: true });
-
-      const toSync = yield _promise2.default.all(unsynced.data.map(_this6._encodeRecord.bind(_this6, "remote")));
-      const toDelete = yield _promise2.default.all(deleted.data.map(_this6._encodeRecord.bind(_this6, "remote")));
-
-      return { toSync, toDelete };
-    })();
-  }
-
-  /**
-   * Fetch remote changes, import them to the local database, and handle
-   * conflicts according to `options.strategy`. Then, updates the passed
-   * {@link SyncResultObject} with import results.
-   *
-   * Options:
-   * - {String} strategy: The selected sync strategy.
-   *
-   * @param  {KintoClient.Collection} client           Kinto client Collection instance.
-   * @param  {SyncResultObject}       syncResultObject The sync result object.
-   * @param  {Object}                 options
-   * @return {Promise}
-   */
-  pullChanges(client, syncResultObject, options = {}) {
-    var _this7 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      if (!syncResultObject.ok) {
-        return syncResultObject;
-      }
-
-      const since = _this7.lastModified ? _this7.lastModified : yield _this7.db.getLastModified();
-
-      options = (0, _extends3.default)({
-        strategy: Collection.strategy.MANUAL,
-        lastModified: since,
-        headers: {}
-      }, options);
-
-      // Optionally ignore some records when pulling for changes.
-      // (avoid redownloading our own changes on last step of #sync())
-      let filters;
-      if (options.exclude) {
-        // Limit the list of excluded records to the first 50 records in order
-        // to remain under de-facto URL size limit (~2000 chars).
-        // http://stackoverflow.com/questions/417142/what-is-the-maximum-length-of-a-url-in-different-browsers/417184#417184
-        const exclude_id = options.exclude.slice(0, 50).map(function (r) {
-          return r.id;
-        }).join(",");
-        filters = { exclude_id };
-      }
-      // First fetch remote changes from the server
-      const { data, last_modified } = yield client.listRecords({
-        // Since should be ETag (see https://github.com/Kinto/kinto.js/issues/356)
-        since: options.lastModified ? `${ options.lastModified }` : undefined,
-        headers: options.headers,
-        filters
-      });
-      // last_modified is the ETag header value (string).
-      // For retro-compatibility with first kinto.js versions
-      // parse it to integer.
-      const unquoted = last_modified ? parseInt(last_modified, 10) : undefined;
-
-      // Check if server was flushed.
-      // This is relevant for the Kinto demo server
-      // (and thus for many new comers).
-      const localSynced = options.lastModified;
-      const serverChanged = unquoted > options.lastModified;
-      const emptyCollection = data.length === 0;
-      if (!options.exclude && localSynced && serverChanged && emptyCollection) {
-        throw Error("Server has been flushed.");
-      }
-
-      syncResultObject.lastModified = unquoted;
-
-      // Decode incoming changes.
-      const decodedChanges = yield _promise2.default.all(data.map(function (change) {
-        return _this7._decodeRecord("remote", change);
-      }));
-      // Hook receives decoded records.
-      const payload = { lastModified: unquoted, changes: decodedChanges };
-      const afterHooks = yield _this7.applyHook("incoming-changes", payload);
-
-      // No change, nothing to import.
-      if (afterHooks.changes.length > 0) {
-        // Reflect these changes locally
-        yield _this7.importChanges(syncResultObject, afterHooks.changes, options.strategy);
-      }
-      return syncResultObject;
-    })();
-  }
-
-  applyHook(hookName, payload) {
-    if (typeof this.hooks[hookName] == "undefined") {
-      return _promise2.default.resolve(payload);
-    }
-    return (0, _utils.waterfall)(this.hooks[hookName].map(hook => {
-      return record => {
-        const result = hook(payload, this);
-        const resultThenable = result && typeof result.then === "function";
-        const resultChanges = result && result.hasOwnProperty("changes");
-        if (!(resultThenable || resultChanges)) {
-          throw new Error(`Invalid return value for hook: ${ (0, _stringify2.default)(result) } has no 'then()' or 'changes' properties`);
-        }
-        return result;
-      };
-    }), payload);
-  }
-
-  /**
-   * Publish local changes to the remote server and updates the passed
-   * {@link SyncResultObject} with publication results.
-   *
-   * @param  {KintoClient.Collection} client           Kinto client Collection instance.
-   * @param  {SyncResultObject}       syncResultObject The sync result object.
-   * @param  {Object}                 changes          The change object.
-   * @param  {Array}                  changes.toDelete The list of records to delete.
-   * @param  {Array}                  changes.toSync   The list of records to create/update.
-   * @param  {Object}                 options          The options object.
-   * @return {Promise}
-   */
-  pushChanges(client, { toDelete = [], toSync }, syncResultObject, options = {}) {
-    var _this8 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      if (!syncResultObject.ok) {
-        return syncResultObject;
-      }
-      const safe = !options.strategy || options.strategy !== Collection.CLIENT_WINS;
-
-      // Perform a batch request with every changes.
-      const synced = yield client.batch(function (batch) {
-        toDelete.forEach(function (r) {
-          // never published locally deleted records should not be pusblished
-          if (r.last_modified) {
-            batch.deleteRecord(r);
-          }
-        });
-        toSync.forEach(function (r) {
-          // Clean local fields (like _status) before sending to server.
-          const published = _this8.cleanLocalFields(r);
-          if (r._status === "created") {
-            batch.createRecord(published);
-          } else {
-            batch.updateRecord(published);
-          }
-        });
-      }, { headers: options.headers, safe, aggregate: true });
-
-      // Store outgoing errors into sync result object
-      syncResultObject.add("errors", synced.errors.map(function (e) {
-        return (0, _extends3.default)({}, e, { type: "outgoing" });
-      }));
-
-      // Store outgoing conflicts into sync result object
-      const conflicts = [];
-      for (let { type, local, remote } of synced.conflicts) {
-        // Note: we ensure that local data are actually available, as they may
-        // be missing in the case of a published deletion.
-        const safeLocal = local && local.data || { id: remote.id };
-        const realLocal = yield _this8._decodeRecord("remote", safeLocal);
-        const realRemote = yield _this8._decodeRecord("remote", remote);
-        const conflict = { type, local: realLocal, remote: realRemote };
-        conflicts.push(conflict);
-      }
-      syncResultObject.add("conflicts", conflicts);
-
-      // Records that must be deleted are either deletions that were pushed
-      // to server (published) or deleted records that were never pushed (skipped).
-      const missingRemotely = synced.skipped.map(function (r) {
-        return (0, _extends3.default)({}, r, { deleted: true });
-      });
-
-      // For created and updated records, the last_modified coming from server
-      // will be stored locally.
-      // Reflect publication results locally using the response from
-      // the batch request.
-      const published = synced.published.map(function (c) {
-        return c.data;
-      });
-      const toApplyLocally = published.concat(missingRemotely);
-
-      // Apply the decode transformers, if any
-      const decoded = yield _promise2.default.all(toApplyLocally.map(function (record) {
-        return _this8._decodeRecord("remote", record);
-      }));
-
-      // We have to update the local records with the responses of the server
-      // (eg. last_modified values etc.).
-      if (decoded.length > 0 || conflicts.length > 0) {
-        yield _this8._applyPushedResults(syncResultObject, decoded, conflicts, options.strategy);
-      }
-
-      return syncResultObject;
-    })();
-  }
-
-  /**
-   * Return a copy of the specified record without the local fields.
-   *
-   * @param  {Object} record  A record with potential local fields.
-   * @return {Object}
-   */
-  cleanLocalFields(record) {
-    const localKeys = RECORD_FIELDS_TO_CLEAN.concat(this.localFields);
-    return (0, _utils.omitKeys)(record, localKeys);
-  }
-
-  /**
-   * Resolves a conflict, updating local record according to proposed
-   * resolution — keeping remote record `last_modified` value as a reference for
-   * further batch sending.
-   *
-   * @param  {Object} conflict   The conflict object.
-   * @param  {Object} resolution The proposed record.
-   * @return {Promise}
-   */
-  resolve(conflict, resolution) {
-    return this.db.execute(transaction => {
-      const updated = this._resolveRaw(conflict, resolution);
-      transaction.update(updated);
-      return { data: updated, permissions: {} };
-    });
-  }
-
-  /**
-   * @private
-   */
-  _resolveRaw(conflict, resolution) {
-    const resolved = (0, _extends3.default)({}, resolution, {
-      // Ensure local record has the latest authoritative timestamp
-      last_modified: conflict.remote.last_modified
-    });
-    // If the resolution object is strictly equal to the
-    // remote record, then we can mark it as synced locally.
-    // Otherwise, mark it as updated (so that the resolution is pushed).
-    const synced = (0, _utils.deepEqual)(resolved, conflict.remote);
-    return markStatus(resolved, synced ? "synced" : "updated");
-  }
-
-  /**
-   * Synchronize remote and local data. The promise will resolve with a
-   * {@link SyncResultObject}, though will reject:
-   *
-   * - if the server is currently backed off;
-   * - if the server has been detected flushed.
-   *
-   * Options:
-   * - {Object} headers: HTTP headers to attach to outgoing requests.
-   * - {Collection.strategy} strategy: See {@link Collection.strategy}.
-   * - {Boolean} ignoreBackoff: Force synchronization even if server is currently
-   *   backed off.
-   * - {String} bucket: The remove bucket id to use (default: null)
-   * - {String} collection: The remove collection id to use (default: null)
-   * - {String} remote The remote Kinto server endpoint to use (default: null).
-   *
-   * @param  {Object} options Options.
-   * @return {Promise}
-   * @throws {Error} If an invalid remote option is passed.
-   */
-  sync(options = {
-    strategy: Collection.strategy.MANUAL,
-    headers: {},
-    ignoreBackoff: false,
-    bucket: null,
-    collection: null,
-    remote: null
-  }) {
-    var _this9 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      const previousRemote = _this9.api.remote;
-      if (options.remote) {
-        // Note: setting the remote ensures it's valid, throws when invalid.
-        _this9.api.remote = options.remote;
-      }
-      if (!options.ignoreBackoff && _this9.api.backoff > 0) {
-        const seconds = Math.ceil(_this9.api.backoff / 1000);
-        return _promise2.default.reject(new Error(`Server is asking clients to back off; retry in ${ seconds }s or use the ignoreBackoff option.`));
-      }
-
-      const client = _this9.api.bucket(options.bucket || _this9.bucket).collection(options.collection || _this9.name);
-
-      const result = new SyncResultObject();
-      try {
-        // Fetch last changes from the server.
-        yield _this9.pullChanges(client, result, options);
-        const { lastModified } = result;
-
-        // Fetch local changes
-        const { toDelete, toSync } = yield _this9.gatherLocalChanges();
-
-        // Publish local changes and pull local resolutions
-        yield _this9.pushChanges(client, { toDelete, toSync }, result, options);
-
-        // Publish local resolution of push conflicts to server (on CLIENT_WINS)
-        const resolvedUnsynced = result.resolved.filter(function (r) {
-          return r._status !== "synced";
-        });
-        if (resolvedUnsynced.length > 0) {
-          const resolvedEncoded = yield _promise2.default.all(resolvedUnsynced.map(_this9._encodeRecord.bind(_this9, "remote")));
-          yield _this9.pushChanges(client, { toSync: resolvedEncoded }, result, options);
-        }
-        // Perform a last pull to catch changes that occured after the last pull,
-        // while local changes were pushed. Do not do it nothing was pushed.
-        if (result.published.length > 0) {
-          // Avoid redownloading our own changes during the last pull.
-          const pullOpts = (0, _extends3.default)({}, options, { lastModified, exclude: result.published });
-          yield _this9.pullChanges(client, result, pullOpts);
-        }
-
-        // Don't persist lastModified value if any conflict or error occured
-        if (result.ok) {
-          // No conflict occured, persist collection's lastModified value
-          _this9._lastModified = yield _this9.db.saveLastModified(result.lastModified);
-        }
-      } finally {
-        // Ensure API default remote is reverted if a custom one's been used
-        _this9.api.remote = previousRemote;
-      }
-      return result;
-    })();
-  }
-
-  /**
-   * Load a list of records already synced with the remote server.
-   *
-   * The local records which are unsynced or whose timestamp is either missing
-   * or superior to those being loaded will be ignored.
-   *
-   * @param  {Array} records The previously exported list of records to load.
-   * @return {Promise} with the effectively imported records.
-   */
-  loadDump(records) {
-    var _this10 = this;
-
-    return (0, _asyncToGenerator3.default)(function* () {
-      if (!Array.isArray(records)) {
-        throw new Error("Records is not an array.");
-      }
-
-      for (let record of records) {
-        if (!record.hasOwnProperty("id") || !_this10.idSchema.validate(record.id)) {
-          throw new Error("Record has invalid ID: " + (0, _stringify2.default)(record));
-        }
-
-        if (!record.last_modified) {
-          throw new Error("Record has no last_modified value: " + (0, _stringify2.default)(record));
-        }
-      }
-
-      // Fetch all existing records from local database,
-      // and skip those who are newer or not marked as synced.
-
-      // XXX filter by status / ids in records
-
-      const { data } = yield _this10.list({}, { includeDeleted: true });
-      const existingById = data.reduce(function (acc, record) {
-        acc[record.id] = record;
-        return acc;
-      }, {});
-
-      const newRecords = records.filter(function (record) {
-        const localRecord = existingById[record.id];
-        const shouldKeep =
-        // No local record with this id.
-        localRecord === undefined ||
-        // Or local record is synced
-        localRecord._status === "synced" &&
-        // And was synced from server
-        localRecord.last_modified !== undefined &&
-        // And is older than imported one.
-        record.last_modified > localRecord.last_modified;
-        return shouldKeep;
-      });
-
-      return yield _this10.db.loadDump(newRecords.map(markSynced));
-    })();
-  }
-}
-
-exports.default = Collection; /**
-                               * A Collection-oriented wrapper for an adapter's transaction.
-                               *
-                               * This defines the high-level functions available on a collection.
-                               * The collection itself offers functions of the same name. These will
-                               * perform just one operation in its own transaction.
-                               */
-
-class CollectionTransaction {
-  constructor(collection, adapterTransaction) {
-    this.collection = collection;
-    this.adapterTransaction = adapterTransaction;
-
-    this._events = [];
-  }
-
-  _queueEvent(action, payload) {
-    this._events.push({ action, payload });
-  }
-
-  /**
-   * Emit queued events, to be called once every transaction operations have
-   * been executed successfully.
-   */
-  emitEvents() {
-    for (let { action, payload } of this._events) {
-      this.collection.events.emit(action, payload);
-    }
-    if (this._events.length > 0) {
-      const targets = this._events.map(({ action, payload }) => (0, _extends3.default)({ action }, payload));
-      this.collection.events.emit("change", { targets });
-    }
-    this._events = [];
-  }
-
-  /**
-   * Retrieve a record by its id from the local database, or
-   * undefined if none exists.
-   *
-   * This will also return virtually deleted records.
-   *
-   * @param  {String} id
-   * @return {Object}
-   */
-  getAny(id) {
-    const record = this.adapterTransaction.get(id);
-    return { data: record, permissions: {} };
-  }
-
-  /**
-   * Retrieve a record by its id from the local database.
-   *
-   * Options:
-   * - {Boolean} includeDeleted: Include virtually deleted records.
-   *
-   * @param  {String} id
-   * @param  {Object} options
-   * @return {Object}
-   */
-  get(id, options = { includeDeleted: false }) {
-    const res = this.getAny(id);
-    if (!res.data || !options.includeDeleted && res.data._status === "deleted") {
-      throw new Error(`Record with id=${ id } not found.`);
-    }
-
-    return res;
-  }
-
-  /**
-   * Deletes a record from the local database.
-   *
-   * Options:
-   * - {Boolean} virtual: When set to `true`, doesn't actually delete the record,
-   *   update its `_status` attribute to `deleted` instead (default: true)
-   *
-   * @param  {String} id       The record's Id.
-   * @param  {Object} options  The options object.
-   * @return {Object}
-   */
-  delete(id, options = { virtual: true }) {
-    // Ensure the record actually exists.
-    const existing = this.adapterTransaction.get(id);
-    const alreadyDeleted = existing && existing._status == "deleted";
-    if (!existing || alreadyDeleted && options.virtual) {
-      throw new Error(`Record with id=${ id } not found.`);
-    }
-    // Virtual updates status.
-    if (options.virtual) {
-      this.adapterTransaction.update(markDeleted(existing));
-    } else {
-      // Delete for real.
-      this.adapterTransaction.delete(id);
-    }
-    this._queueEvent("delete", { data: existing });
-    return { data: existing, permissions: {} };
-  }
-
-  /**
-   * Deletes a record from the local database, if any exists.
-   * Otherwise, do nothing.
-   *
-   * @param  {String} id       The record's Id.
-   * @return {Object}
-   */
-  deleteAny(id) {
-    const existing = this.adapterTransaction.get(id);
-    if (existing) {
-      this.adapterTransaction.update(markDeleted(existing));
-      this._queueEvent("delete", { data: existing });
-    }
-    return { data: (0, _extends3.default)({ id }, existing), deleted: !!existing, permissions: {} };
-  }
-
-  /**
-   * Adds a record to the local database, asserting that none
-   * already exist with this ID.
-   *
-   * @param  {Object} record, which must contain an ID
-   * @return {Object}
-   */
-  create(record) {
-    if (typeof record !== "object") {
-      throw new Error("Record is not an object.");
-    }
-    if (!record.hasOwnProperty("id")) {
-      throw new Error("Cannot create a record missing id");
-    }
-    if (!this.collection.idSchema.validate(record.id)) {
-      throw new Error(`Invalid Id: ${ record.id }`);
-    }
-
-    this.adapterTransaction.create(record);
-    this._queueEvent("create", { data: record });
-    return { data: record, permissions: {} };
-  }
-
-  /**
-   * Updates a record from the local database.
-   *
-   * Options:
-   * - {Boolean} synced: Sets record status to "synced" (default: false)
-   * - {Boolean} patch:  Extends the existing record instead of overwriting it
-   *   (default: false)
-   *
-   * @param  {Object} record
-   * @param  {Object} options
-   * @return {Object}
-   */
-  update(record, options = { synced: false, patch: false }) {
-    if (typeof record !== "object") {
-      throw new Error("Record is not an object.");
-    }
-    if (!record.hasOwnProperty("id")) {
-      throw new Error("Cannot update a record missing id.");
-    }
-    if (!this.collection.idSchema.validate(record.id)) {
-      throw new Error(`Invalid Id: ${ record.id }`);
-    }
-
-    const oldRecord = this.adapterTransaction.get(record.id);
-    if (!oldRecord) {
-      throw new Error(`Record with id=${ record.id } not found.`);
-    }
-    const newRecord = options.patch ? (0, _extends3.default)({}, oldRecord, record) : record;
-    const updated = this._updateRaw(oldRecord, newRecord, options);
-    this.adapterTransaction.update(updated);
-    this._queueEvent("update", { data: updated, oldRecord });
-    return { data: updated, oldRecord, permissions: {} };
-  }
-
-  /**
-   * Lower-level primitive for updating a record while respecting
-   * _status and last_modified.
-   *
-   * @param  {Object} oldRecord: the record retrieved from the DB
-   * @param  {Object} newRecord: the record to replace it with
-   * @return {Object}
-   */
-  _updateRaw(oldRecord, newRecord, { synced = false } = {}) {
-    const updated = (0, _extends3.default)({}, newRecord);
-    // Make sure to never loose the existing timestamp.
-    if (oldRecord && oldRecord.last_modified && !updated.last_modified) {
-      updated.last_modified = oldRecord.last_modified;
-    }
-    // If only local fields have changed, then keep record as synced.
-    // If status is created, keep record as created.
-    // If status is deleted, mark as updated.
-    const isIdentical = oldRecord && recordsEqual(oldRecord, updated, this.localFields);
-    const keepSynced = isIdentical && oldRecord._status == "synced";
-    const neverSynced = !oldRecord || oldRecord && oldRecord._status == "created";
-    const newStatus = keepSynced || synced ? "synced" : neverSynced ? "created" : "updated";
-    return markStatus(updated, newStatus);
-  }
-
-  /**
-   * Upsert a record into the local database.
-   *
-   * This record must have an ID.
-   *
-   * If a record with this ID already exists, it will be replaced.
-   * Otherwise, this record will be inserted.
-   *
-   * @param  {Object} record
-   * @return {Object}
-   */
-  upsert(record) {
-    if (typeof record !== "object") {
-      throw new Error("Record is not an object.");
-    }
-    if (!record.hasOwnProperty("id")) {
-      throw new Error("Cannot update a record missing id.");
-    }
-    if (!this.collection.idSchema.validate(record.id)) {
-      throw new Error(`Invalid Id: ${ record.id }`);
-    }
-    let oldRecord = this.adapterTransaction.get(record.id);
-    const updated = this._updateRaw(oldRecord, record);
-    this.adapterTransaction.update(updated);
-    // Don't return deleted records -- pretend they are gone
-    if (oldRecord && oldRecord._status == "deleted") {
-      oldRecord = undefined;
-    }
-    if (oldRecord) {
-      this._queueEvent("update", { data: updated, oldRecord });
-    } else {
-      this._queueEvent("create", { data: updated });
-    }
-    return { data: updated, oldRecord, permissions: {} };
-  }
-}
-exports.CollectionTransaction = CollectionTransaction;
-
-},{"./adapters/IDB":84,"./adapters/base":85,"./utils":87,"babel-runtime/core-js/json/stringify":3,"babel-runtime/core-js/object/assign":4,"babel-runtime/core-js/promise":6,"babel-runtime/helpers/asyncToGenerator":7,"babel-runtime/helpers/extends":8,"uuid":9}],87:[function(require,module,exports){
-"use strict";
-
-Object.defineProperty(exports, "__esModule", {
-  value: true
-});
-exports.RE_UUID = undefined;
-
-var _promise = require("babel-runtime/core-js/promise");
-
-var _promise2 = _interopRequireDefault(_promise);
-
-var _keys = require("babel-runtime/core-js/object/keys");
-
-var _keys2 = _interopRequireDefault(_keys);
-
-exports.sortObjects = sortObjects;
-exports.filterObject = filterObject;
-exports.filterObjects = filterObjects;
-exports.isUUID = isUUID;
-exports.waterfall = waterfall;
-exports.deepEqual = deepEqual;
-exports.omitKeys = omitKeys;
-
-function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
-
-const RE_UUID = exports.RE_UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
-
-/**
- * Checks if a value is undefined.
- * @param  {Any}  value
- * @return {Boolean}
- */
-function _isUndefined(value) {
-  return typeof value === "undefined";
-}
-
-/**
- * Sorts records in a list according to a given ordering.
- *
- * @param  {String} order The ordering, eg. `-last_modified`.
- * @param  {Array}  list  The collection to order.
- * @return {Array}
- */
-function sortObjects(order, list) {
-  const hasDash = order[0] === "-";
-  const field = hasDash ? order.slice(1) : order;
-  const direction = hasDash ? -1 : 1;
-  return list.slice().sort((a, b) => {
-    if (a[field] && _isUndefined(b[field])) {
-      return direction;
-    }
-    if (b[field] && _isUndefined(a[field])) {
-      return -direction;
-    }
-    if (_isUndefined(a[field]) && _isUndefined(b[field])) {
-      return 0;
-    }
-    return a[field] > b[field] ? direction : -direction;
-  });
-}
-
-/**
- * Test if a single object matches all given filters.
- *
- * @param  {Object} filters  The filters object.
- * @param  {Object} entry    The object to filter.
- * @return {Function}
- */
-function filterObject(filters, entry) {
-  return (0, _keys2.default)(filters).every(filter => {
-    const value = filters[filter];
-    if (Array.isArray(value)) {
-      return value.some(candidate => candidate === entry[filter]);
-    }
-    return entry[filter] === value;
-  });
-}
-
-/**
- * Filters records in a list matching all given filters.
- *
- * @param  {Object} filters  The filters object.
- * @param  {Array}  list     The collection to filter.
- * @return {Array}
- */
-function filterObjects(filters, list) {
-  return list.filter(entry => {
-    return filterObject(filters, entry);
-  });
-}
-
-/**
- * Checks if a string is an UUID.
- *
- * @param  {String} uuid The uuid to validate.
- * @return {Boolean}
- */
-function isUUID(uuid) {
-  return RE_UUID.test(uuid);
-}
-
-/**
- * Resolves a list of functions sequentially, which can be sync or async; in
- * case of async, functions must return a promise.
- *
- * @param  {Array} fns  The list of functions.
- * @param  {Any}   init The initial value.
- * @return {Promise}
- */
-function waterfall(fns, init) {
-  if (!fns.length) {
-    return _promise2.default.resolve(init);
-  }
-  return fns.reduce((promise, nextFn) => {
-    return promise.then(nextFn);
-  }, _promise2.default.resolve(init));
-}
-
-/**
- * Simple deep object comparison function. This only supports comparison of
- * serializable JavaScript objects.
- *
- * @param  {Object} a The source object.
- * @param  {Object} b The compared object.
- * @return {Boolean}
- */
-function deepEqual(a, b) {
-  if (a === b) {
-    return true;
-  }
-  if (typeof a !== typeof b) {
-    return false;
-  }
-  if (!(a && typeof a == "object") || !(b && typeof b == "object")) {
-    return false;
-  }
-  if ((0, _keys2.default)(a).length !== (0, _keys2.default)(b).length) {
-    return false;
-  }
-  for (let k in a) {
-    if (!deepEqual(a[k], b[k])) {
-      return false;
-    }
-  }
-  return true;
-}
-
-/**
- * Return an object without the specified keys.
- *
- * @param  {Object} obj        The original object.
- * @param  {Array}  keys       The list of keys to exclude.
- * @return {Object}            A copy without the specified keys.
- */
-function omitKeys(obj, keys = []) {
-  return (0, _keys2.default)(obj).reduce((acc, key) => {
-    if (keys.indexOf(key) === -1) {
-      acc[key] = obj[key];
-    }
-    return acc;
-  }, {});
-}
-
-},{"babel-runtime/core-js/object/keys":5,"babel-runtime/core-js/promise":6}]},{},[2])(2)
-});
\ No newline at end of file
+this.EXPORTED_SYMBOLS = ["FirefoxAdapter"];
--- a/services/common/moz.build
+++ b/services/common/moz.build
@@ -14,16 +14,17 @@ EXTRA_COMPONENTS += [
 ]
 
 EXTRA_JS_MODULES['services-common'] += [
     'async.js',
     'blocklist-clients.js',
     'blocklist-updater.js',
     'kinto-http-client.js',
     'kinto-offline-client.js',
+    'kinto-storage-adapter.js',
     'logmanager.js',
     'observers.js',
     'rest.js',
     'stringbundle.js',
     'utils.js',
 ]
 
 if CONFIG['MOZ_WIDGET_TOOLKIT'] != 'android':
--- a/services/common/tests/unit/test_blocklist_certificates.js
+++ b/services/common/tests/unit/test_blocklist_certificates.js
@@ -1,23 +1,22 @@
 const { Constructor: CC } = Components;
 
 Cu.import("resource://testing-common/httpd.js");
 
 const { OneCRLBlocklistClient } = Cu.import("resource://services-common/blocklist-clients.js");
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js");
 
 const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
   "nsIBinaryInputStream", "setInputStream");
 
 let server;
 
 // set up what we need to make storage adapters
-const Kinto = loadKinto();
-const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
 const kintoFilename = "kinto.sqlite";
 
 let kintoClient;
 
 function do_get_kinto_collection(collectionName) {
   if (!kintoClient) {
     let config = {
       // Set the remote to be some server that will cause test failure when
--- a/services/common/tests/unit/test_blocklist_clients.js
+++ b/services/common/tests/unit/test_blocklist_clients.js
@@ -3,17 +3,18 @@ const { Constructor: CC } = Components;
 const KEY_PROFILEDIR = "ProfD";
 
 Cu.import("resource://gre/modules/Services.jsm");
 Cu.import("resource://testing-common/httpd.js");
 Cu.import("resource://gre/modules/Timer.jsm");
 const { FileUtils } = Cu.import("resource://gre/modules/FileUtils.jsm");
 const { OS } = Cu.import("resource://gre/modules/osfile.jsm");
 
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js");
 const BlocklistClients = Cu.import("resource://services-common/blocklist-clients.js");
 
 const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1",
   "nsIBinaryInputStream", "setInputStream");
 
 const gBlocklistClients = [
   {client: BlocklistClients.AddonBlocklistClient, filename: BlocklistClients.FILENAME_ADDONS_JSON, testData: ["i808","i720", "i539"]},
   {client: BlocklistClients.PluginBlocklistClient, filename: BlocklistClients.FILENAME_PLUGINS_JSON, testData: ["p1044","p32","p28"]},
@@ -21,18 +22,16 @@ const gBlocklistClients = [
 ];
 
 
 let server;
 let kintoClient;
 
 function kintoCollection(collectionName) {
   if (!kintoClient) {
-    const Kinto = loadKinto();
-    const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
     const config = {
       // Set the remote to be some server that will cause test failure when
       // hit since we should never hit the server directly, only via maybeSync()
       remote: "https://firefox.settings.services.mozilla.com/v1/",
       adapter: FirefoxAdapter,
       bucket: "blocklists"
     };
     kintoClient = new Kinto(config);
--- a/services/common/tests/unit/test_blocklist_signatures.js
+++ b/services/common/tests/unit/test_blocklist_signatures.js
@@ -1,14 +1,15 @@
 "use strict";
 
 Cu.import("resource://services-common/blocklist-updater.js");
 Cu.import("resource://testing-common/httpd.js");
 
-const { loadKinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { Kinto } = Cu.import("resource://services-common/kinto-offline-client.js");
+const { FirefoxAdapter } = Cu.import("resource://services-common/kinto-storage-adapter.js");
 const { NetUtil } = Cu.import("resource://gre/modules/NetUtil.jsm", {});
 const { OneCRLBlocklistClient } = Cu.import("resource://services-common/blocklist-clients.js");
 
 let server;
 
 const PREF_BLOCKLIST_BUCKET            = "services.blocklist.bucket";
 const PREF_BLOCKLIST_ENFORCE_SIGNING   = "services.blocklist.signing.enforced";
 const PREF_BLOCKLIST_ONECRL_COLLECTION = "services.blocklist.onecrl.collection";
@@ -55,20 +56,16 @@ function getCertChain() {
 
 function* checkRecordCount(count) {
   // open the collection manually
   const base = Services.prefs.getCharPref(PREF_SETTINGS_SERVER);
   const bucket = Services.prefs.getCharPref(PREF_BLOCKLIST_BUCKET);
   const collectionName =
       Services.prefs.getCharPref(PREF_BLOCKLIST_ONECRL_COLLECTION);
 
-  const Kinto = loadKinto();
-
-  const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
-
   const config = {
     remote: base,
     bucket: bucket,
     adapter: FirefoxAdapter,
   };
 
   const db = new Kinto(config);
   const collection = db.collection(collectionName);
--- a/services/common/tests/unit/test_kinto.js
+++ b/services/common/tests/unit/test_kinto.js
@@ -1,22 +1,21 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 Cu.import("resource://services-common/kinto-offline-client.js");
+Cu.import("resource://services-common/kinto-storage-adapter.js");
 Cu.import("resource://testing-common/httpd.js");
 
 const BinaryInputStream = Components.Constructor("@mozilla.org/binaryinputstream;1",
   "nsIBinaryInputStream", "setInputStream");
 
 var server;
 
 // set up what we need to make storage adapters
-const Kinto = loadKinto();
-const FirefoxAdapter = Kinto.adapters.FirefoxAdapter;
 const kintoFilename = "kinto.sqlite";
 
 let kintoClient;
 
 function do_get_kinto_collection() {
   if (!kintoClient) {
     let config = {
       remote:`http://localhost:${server.identity.primaryPort}/v1/`,
--- a/toolkit/components/extensions/ExtensionStorageSync.jsm
+++ b/toolkit/components/extensions/ExtensionStorageSync.jsm
@@ -51,18 +51,20 @@ XPCOMUtils.defineLazyModuleGetter(this, 
 XPCOMUtils.defineLazyModuleGetter(this, "EncryptionRemoteTransformer",
                                   "resource://services-sync/engines/extension-storage.js");
 XPCOMUtils.defineLazyModuleGetter(this, "ExtensionStorage",
                                   "resource://gre/modules/ExtensionStorage.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "fxAccounts",
                                   "resource://gre/modules/FxAccounts.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "KintoHttpClient",
                                   "resource://services-common/kinto-http-client.js");
-XPCOMUtils.defineLazyModuleGetter(this, "loadKinto",
+XPCOMUtils.defineLazyModuleGetter(this, "Kinto",
                                   "resource://services-common/kinto-offline-client.js");
+XPCOMUtils.defineLazyModuleGetter(this, "FirefoxAdapter",
+                                  "resource://services-common/kinto-storage-adapter.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Log",
                                   "resource://gre/modules/Log.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Observers",
                                   "resource://services-common/observers.js");
 XPCOMUtils.defineLazyModuleGetter(this, "Sqlite",
                                   "resource://gre/modules/Sqlite.jsm");
 XPCOMUtils.defineLazyModuleGetter(this, "Task",
                                   "resource://gre/modules/Task.jsm");
@@ -90,25 +92,24 @@ const log = Log.repository.getLogger("Sy
  *
  * Fields in the object returned by this Promise:
  *
  * - connection: a Sqlite connection. Meant for internal use only.
  * - kinto: a KintoBase object, suitable for using in Firefox. All
  *   collections in this database will use the same Sqlite connection.
  */
 const storageSyncInit = Task.spawn(function* () {
-  const Kinto = loadKinto();
   const path = "storage-sync.sqlite";
   const opts = {path, sharedMemoryCache: false};
   const connection = yield Sqlite.openConnection(opts);
-  yield Kinto.adapters.FirefoxAdapter._init(connection);
+  yield FirefoxAdapter._init(connection);
   return {
     connection,
     kinto: new Kinto({
-      adapter: Kinto.adapters.FirefoxAdapter,
+      adapter: FirefoxAdapter,
       adapterOptions: {sqliteHandle: connection},
       timeout: KINTO_REQUEST_TIMEOUT,
     }),
   };
 });
 
 AsyncShutdown.profileBeforeChange.addBlocker(
   "ExtensionStorageSync: close Sqlite handle",