(#3415) - open idb transactions safely
diff --git a/lib/adapters/idb/idb-bulk-docs.js b/lib/adapters/idb/idb-bulk-docs.js
index becaeda..7dcccf3 100644
--- a/lib/adapters/idb/idb-bulk-docs.js
+++ b/lib/adapters/idb/idb-bulk-docs.js
@@ -16,6 +16,7 @@
 var decodeMetadata = idbUtils.decodeMetadata;
 var encodeMetadata = idbUtils.encodeMetadata;
 var idbError = idbUtils.idbError;
+var openTransactionSafely = idbUtils.openTransactionSafely;
 
 function idbBulkDocs(req, opts, api, idb, Changes, callback) {
   var docInfos = req.docs;
@@ -60,7 +61,11 @@
       ATTACH_STORE, META_STORE,
       LOCAL_STORE, ATTACH_AND_SEQ_STORE
     ];
-    txn = idb.transaction(stores, 'readwrite');
+    var txnResult = openTransactionSafely(idb, stores, 'readwrite');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    txn = txnResult.txn;
     txn.onerror = idbError(callback);
     txn.ontimeout = idbError(callback);
     txn.oncomplete = complete;
diff --git a/lib/adapters/idb/idb-utils.js b/lib/adapters/idb/idb-utils.js
index d4a3827..4a80d75 100644
--- a/lib/adapters/idb/idb-utils.js
+++ b/lib/adapters/idb/idb-utils.js
@@ -229,3 +229,15 @@
     };
   });
 };
+
+exports.openTransactionSafely = function (idb, stores, mode) {
+  try {
+    return {
+      txn: idb.transaction(stores, mode)
+    };
+  } catch (err) {
+    return {
+      error: err
+    };
+  }
+};
\ No newline at end of file
diff --git a/lib/adapters/idb/idb.js b/lib/adapters/idb/idb.js
index 7169432..4cdae49 100644
--- a/lib/adapters/idb/idb.js
+++ b/lib/adapters/idb/idb.js
@@ -27,6 +27,7 @@
 var postProcessAttachments = idbUtils.postProcessAttachments;
 var readBlobData = idbUtils.readBlobData;
 var taskQueue = idbUtils.taskQueue;
+var openTransactionSafely = idbUtils.openTransactionSafely;
 
 var cachedDBs = {};
 var blobSupportPromise;
@@ -296,8 +297,12 @@
     if (opts.ctx) {
       txn = opts.ctx;
     } else {
-      txn =
-        idb.transaction([DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], 'readonly');
+      var txnResult = openTransactionSafely(idb,
+        [DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], 'readonly');
+      if (txnResult.error) {
+        return callback(txnResult.error);
+      }
+      txn = txnResult.txn;
     }
 
     function finish() {
@@ -344,8 +349,12 @@
     if (opts.ctx) {
       txn = opts.ctx;
     } else {
-      txn =
-        idb.transaction([DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], 'readonly');
+      var txnResult = openTransactionSafely(idb,
+        [DOC_STORE, BY_SEQ_STORE, ATTACH_STORE], 'readonly');
+      if (txnResult.error) {
+        return callback(txnResult.error);
+      }
+      txn = txnResult.txn;
     }
     var digest = attachment.digest;
     var type = attachment.content_type;
@@ -412,7 +421,11 @@
     if (opts.attachments) {
       stores.push(ATTACH_STORE);
     }
-    var transaction = idb.transaction(stores, 'readonly');
+    var txnResult = openTransactionSafely(idb, stores, 'readonly');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var transaction = txnResult.txn;
 
     function onResultsReady() {
       callback(null, {
@@ -500,7 +513,11 @@
     }
 
     var count;
-    var txn = idb.transaction([DOC_STORE], 'readonly');
+    var txnResult = openTransactionSafely(idb, [DOC_STORE], 'readonly');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var txn = txnResult.txn;
     var index = txn.objectStore(DOC_STORE).index('deletedOrLocal');
     index.count(IDBKeyRange.only("0")).onsuccess = function (e) {
       count = e.target.result;
@@ -542,7 +559,11 @@
         return callback(error);
       }
       var updateSeq = 0;
-      var txn = idb.transaction([BY_SEQ_STORE], 'readonly');
+      var txnResult = openTransactionSafely(idb, [BY_SEQ_STORE], 'readonly');
+      if (txnResult.error) {
+        return callback(txnResult.error);
+      }
+      var txn = txnResult.txn;
       txn.objectStore(BY_SEQ_STORE).openCursor(null, "prev").onsuccess =
         function (event) {
         var cursor = event.target.result;
@@ -689,7 +710,11 @@
       if (opts.attachments) {
         objectStores.push(ATTACH_STORE);
       }
-      txn = idb.transaction(objectStores, 'readonly');
+      var txnResult = openTransactionSafely(idb, objectStores, 'readonly');
+      if (txnResult.error) {
+        return opts.complete(txnResult.error);
+      }
+      txn = txnResult.txn;
       txn.onerror = idbError(opts.complete);
       txn.oncomplete = onTxnComplete;
 
@@ -745,7 +770,11 @@
   };
 
   api._getRevisionTree = function (docId, callback) {
-    var txn = idb.transaction([DOC_STORE], 'readonly');
+    var txnResult = openTransactionSafely(idb, [DOC_STORE], 'readonly');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var txn = txnResult.txn;
     var req = txn.objectStore(DOC_STORE).get(docId);
     req.onsuccess = function (event) {
       var doc = decodeMetadata(event.target.result);
@@ -761,12 +790,17 @@
   // which are listed in revs and sets this document
   // revision to to rev_tree
   api._doCompaction = function (docId, revs, callback) {
-    var txn = idb.transaction([
+    var stores = [
       DOC_STORE,
       BY_SEQ_STORE,
       ATTACH_STORE,
       ATTACH_AND_SEQ_STORE
-    ], 'readwrite');
+    ];
+    var txnResult = openTransactionSafely(idb, stores, 'readwrite');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var txn = txnResult.txn;
 
     var docStore = txn.objectStore(DOC_STORE);
 
@@ -793,7 +827,11 @@
 
 
   api._getLocal = function (id, callback) {
-    var tx = idb.transaction([LOCAL_STORE], 'readonly');
+    var txnResult = openTransactionSafely(idb, [LOCAL_STORE], 'readonly');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var tx = txnResult.txn;
     var req = tx.objectStore(LOCAL_STORE).get(id);
 
     req.onerror = idbError(callback);
@@ -825,7 +863,11 @@
     var tx = opts.ctx;
     var ret;
     if (!tx) {
-      tx = idb.transaction([LOCAL_STORE], 'readwrite');
+      var txnResult = openTransactionSafely(idb, [LOCAL_STORE], 'readwrite');
+      if (txnResult.error) {
+        return callback(txnResult.error);
+      }
+      tx = txnResult.txn;
       tx.onerror = idbError(callback);
       tx.oncomplete = function () {
         if (ret) {
@@ -870,7 +912,11 @@
   };
 
   api._removeLocal = function (doc, callback) {
-    var tx = idb.transaction([LOCAL_STORE], 'readwrite');
+    var txnResult = openTransactionSafely(idb, [LOCAL_STORE], 'readwrite');
+    if (txnResult.error) {
+      return callback(txnResult.error);
+    }
+    var tx = txnResult.txn;
     var ret;
     tx.oncomplete = function () {
       if (ret) {