You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by am...@apache.org on 2021/10/18 19:02:43 UTC

[couchdb-fauxton] branch main updated: Remove dependencies to pouchdb packages (#1325)

This is an automated email from the ASF dual-hosted git repository.

amaranhao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/couchdb-fauxton.git


The following commit(s) were added to refs/heads/main by this push:
     new ae42fd2  Remove dependencies to pouchdb packages (#1325)
ae42fd2 is described below

commit ae42fd2ff60fd3bb4e2a33645a6848cb338f4325
Author: Antonio Maranhao <30...@users.noreply.github.com>
AuthorDate: Mon Oct 18 14:01:32 2021 -0400

    Remove dependencies to pouchdb packages (#1325)
    
    Replace pouchdb related packages with our own implementation to simplify the dependency tree.
    Major motivation is that some of these packages haven't had new releases in years, which is a problem
    when a sub-dependency requires security fixes.
---
 .eslintrc                                         |   3 +-
 app/addons/documents/__tests__/docFetcher.test.js |  83 ++++++++
 app/addons/documents/__tests__/getTree.test.js    |  87 +++++++++
 app/addons/documents/rev-browser/actions.js       |  30 +--
 app/addons/documents/rev-browser/docFetcher.js    |  78 ++++++++
 app/addons/documents/rev-browser/getTree.js       |  38 ++++
 package-lock.json                                 | 226 ++++------------------
 package.json                                      |   4 +-
 8 files changed, 340 insertions(+), 209 deletions(-)

diff --git a/.eslintrc b/.eslintrc
index 37e2aa0..defe228 100644
--- a/.eslintrc
+++ b/.eslintrc
@@ -82,7 +82,8 @@
     "define": true,
     "expect": true,
     "prettyPrint": true,
-    "jest": true
+    "jest": true,
+    "fail": true
   },
 
   "settings": {
diff --git a/app/addons/documents/__tests__/docFetcher.test.js b/app/addons/documents/__tests__/docFetcher.test.js
new file mode 100644
index 0000000..4e3599e
--- /dev/null
+++ b/app/addons/documents/__tests__/docFetcher.test.js
@@ -0,0 +1,83 @@
+// 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.
+
+import docFetcher from '../rev-browser/docFetcher';
+import fetchMock from 'fetch-mock';
+
+describe('docFetcher', () => {
+
+  describe('constructor', () => {
+    it('throws with an invalid db URL', () => {
+      expect(() => {
+        docFetcher('not_a_url');
+      }).toThrow('Invalid database URL: not_a_url');
+
+      expect(() => {
+        docFetcher(null);
+      }).toThrow('Invalid database URL: null');
+    });
+  });
+
+  describe('getDoc', () => {
+    const dbURL = 'http://localhost/testdb';
+    const docID = 'doc1';
+    const docURL = `${dbURL}/${docID}`;
+    const mockDoc = {
+      _id: '1234',
+      _rev: '1-fdsafdsa',
+      afield: 'avalue'
+    };
+
+    it('resolves the json doc', () => {
+      const fetcher = docFetcher(dbURL);
+      fetchMock.getOnce(docURL, mockDoc);
+
+      return fetcher.getDoc(docID).then(doc => {
+        expect(doc).toEqual(mockDoc);
+      });
+    });
+
+    it('fetches with the given params', () => {
+      const fetcher = docFetcher(dbURL);
+      fetchMock.getOnce(docURL + '?revs=true&rev=2-abc', mockDoc);
+
+      return fetcher.getDoc(docID, {revs: true, rev:'2-abc'}).then(doc => {
+        expect(doc).toEqual(mockDoc);
+      });
+    });
+
+    it('rejects in case of error', () => {
+      const fetcher = docFetcher(dbURL);
+      const url = `${dbURL}/docNotFound`;
+      fetchMock.getOnce(url, {
+        body:  {error: 'not_found', reason: 'doc not found'},
+        status: 404
+      });
+
+      return fetcher.getDoc('docNotFound').then(() => {
+        fail('Should not succeed');
+      }).catch(err => {
+        expect(err.message).toEqual('not_found');
+      });
+    });
+
+    it('rejects when given an invalid doc ID', () => {
+      const fetcher = docFetcher(dbURL);
+      return fetcher.getDoc('').then(() => {
+        fail('Should not succeed');
+      }).catch(err => {
+        expect(err.message).toEqual('Invalid document ID');
+      });
+    });
+
+  });
+});
diff --git a/app/addons/documents/__tests__/getTree.test.js b/app/addons/documents/__tests__/getTree.test.js
new file mode 100644
index 0000000..b088556
--- /dev/null
+++ b/app/addons/documents/__tests__/getTree.test.js
@@ -0,0 +1,87 @@
+// 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.
+
+import getTree from '../rev-browser/getTree';
+
+describe('getTree', () => {
+  const docRevs = [
+    {
+      ok:{
+        _id:"zebra",
+        _rev:"2-0d9d2a9b5593f85539ec002751199602",
+        color:"white",
+        _revisions:{
+          start:2,
+          ids:["0d9d2a9b5593f85539ec002751199602", "1db655657f34c1742e9a0367342cfef9"]
+        }
+      }
+    },
+    {
+      ok:{
+        _id:"zebra",
+        _rev:"2-34e3d563be7f242a42a4c232d5fc477e",
+        color:"green",
+        _revisions:{
+          start:2,
+          ids:["34e3d563be7f242a42a4c232d5fc477e", "1db655657f34c1742e9a0367342cfef9"]
+        }
+      }
+    },
+    {
+      ok:{
+        _id:"zebra",
+        _rev:"2-a09738203402f0b1a78f4a889fbd97e9",
+        _deleted: true,
+        _revisions:{
+          start:2,
+          ids:["a09738203402f0b1a78f4a889fbd97e9", "1db655657f34c1742e9a0367342cfef9"]
+        }
+      }
+    }
+  ];
+
+  describe('getDoc', () => {
+    it('resolves the rev tree', () => {
+      const fetcher = {
+        getDoc: () => Promise.resolve(docRevs),
+      };
+      const mockDoc = {_id: 'zebra', _rev:"2-0d9d2a9b5593f85539ec002751199602"};
+      return getTree(fetcher, mockDoc).then(tree => {
+        expect(tree).toStrictEqual({
+          paths: [
+            ["2-0d9d2a9b5593f85539ec002751199602", "1-1db655657f34c1742e9a0367342cfef9"],
+            ["2-34e3d563be7f242a42a4c232d5fc477e", "1-1db655657f34c1742e9a0367342cfef9"],
+            ["2-a09738203402f0b1a78f4a889fbd97e9", "1-1db655657f34c1742e9a0367342cfef9"],
+          ],
+          deleted: {
+            "2-a09738203402f0b1a78f4a889fbd97e9": true
+          },
+          winner: mockDoc._rev
+        });
+      });
+    });
+
+    it('rejects in case of error', () => {
+      const fetcher = {
+        getDoc: () => Promise.reject(new Error('Failed to fetch doc')),
+      };
+      const mockDoc = {_id: 'zebra', _rev:"2-0d9d2a9b5593f85539ec002751199602"};
+
+      return getTree(fetcher, mockDoc).then(() => {
+        fail('Should not succeed');
+      }).catch(err => {
+        expect(err.message).toEqual('Failed to fetch doc');
+      });
+    });
+
+  });
+});
diff --git a/app/addons/documents/rev-browser/actions.js b/app/addons/documents/rev-browser/actions.js
index e1cf443..35c12e1 100644
--- a/app/addons/documents/rev-browser/actions.js
+++ b/app/addons/documents/rev-browser/actions.js
@@ -13,19 +13,20 @@
 import FauxtonAPI from "../../../core/api";
 import {post} from "../../../core/ajax";
 import ActionTypes from "./actiontypes";
-import getTree from "visualize-rev-tree/lib/getTree";
-import PouchDB from "pouchdb-core";
-import PouchHttpAdapter from 'pouchdb-adapter-http';
-PouchDB.plugin(PouchHttpAdapter);
+import getTree from './getTree';
+import docFetcher from './docFetcher';
 
-let db;
+let fetcher;
 
-export const initDiffEditor = (dbName, docId) => dispatch => {
-  // We have to use API url here because PouchDB doesn't take relative urls.
-  const url = FauxtonAPI.urls('databaseBaseURL', 'apiurl', dbName);
-  db = PouchDB(url);
+export const initDiffEditor = (dbName, docId) => (dispatch) => {
+  const url = FauxtonAPI.urls("databaseBaseURL", "apiurl", dbName);
+  fetcher = docFetcher(url);
 
-  Promise.all([db.get(docId), getTree(db, docId)])
+  fetcher
+    .getDoc(docId)
+    .then((doc) => {
+      return Promise.all([Promise.resolve(doc), getTree(fetcher, doc)]);
+    })
     .then(([doc, tree]) => {
       const conflictingRevs = getConflictingRevs(tree.paths, tree.winner, Object.keys(tree.deleted));
       const initialRev = conflictingRevs[0];
@@ -34,10 +35,9 @@ export const initDiffEditor = (dbName, docId) => dispatch => {
         return dispatch(treeLoaded(tree, doc, conflictingRevs, null, dbName));
       }
 
-      db.get(doc._id, {rev: initialRev})
-        .then((conflictDoc) => {
-          dispatch(treeLoaded(tree, doc, conflictingRevs, conflictDoc, dbName));
-        });
+      fetcher.getDoc(doc._id, { rev: initialRev }).then(conflictDoc => {
+        dispatch(treeLoaded(tree, doc, conflictingRevs, conflictDoc, dbName));
+      });
     });
 };
 
@@ -78,7 +78,7 @@ export const toggleDiffView = (enableDiff) => {
 };
 
 export const chooseLeaves = (doc, revTheirs) => dispatch => {
-  db.get(doc._id, {rev: revTheirs})
+  fetcher.getDoc(doc._id, { rev: revTheirs })
     .then((res) => {
       dispatch(docsToDiff(doc, res));
     });
diff --git a/app/addons/documents/rev-browser/docFetcher.js b/app/addons/documents/rev-browser/docFetcher.js
new file mode 100644
index 0000000..74f4250
--- /dev/null
+++ b/app/addons/documents/rev-browser/docFetcher.js
@@ -0,0 +1,78 @@
+// 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.
+
+import app from '../../../app';
+import { get } from "../../../core/ajax";
+
+/**
+ * Object able to fetch documents from a CouchDB database.
+ * @typedef {Object} DocFetcher
+ * @property {function} getDoc - Function to retrieve a document
+ */
+
+
+/**
+ * Create a document fetcher object for retrieving documents from
+ * a CouchDB database.
+ *
+ * @param {string} databaseURL
+ * @returns {DocFetcher} a new fetcher
+ */
+function docFetcher(databaseURL) {
+  try {
+    new URL(databaseURL);
+  } catch (_) {
+    throw new Error(`Invalid database URL: ${databaseURL}`);
+  }
+  return {
+    getDoc: (docId, params) => {
+      return getDbDoc(databaseURL, docId, params);
+    }
+  };
+}
+
+/**
+ * Fetches a CouchDB document.
+ *
+ * @param {*} databaseURL Databse URL
+ * @param {*} docId Document ID
+ * @param {*} params Query parameters allowed on GET /{db}/{doc} endpoint
+ * @returns {Promise}
+ */
+function getDbDoc(databaseURL, docId, params) {
+  if (!docId) {
+    return Promise.reject(new Error("Invalid document ID"));
+  }
+  let queryParameters = "";
+  if (params && typeof params === "object") {
+    queryParameters = "?" + app.utils.queryParams(params);
+  }
+  let docURLPath = '';
+  if (docId.startsWith("_design/")) {
+    const ddocName = docId.substring(8);
+    docURLPath = "_design/" + encodeURIComponent(ddocName);
+  } else {
+    docURLPath = encodeURIComponent(docId);
+  }
+  const docURL = `${databaseURL}/${docURLPath}${queryParameters}`;
+  return get(docURL).then(json => {
+    if (json.error) {
+      const err = new Error(json.error);
+      err.reason = json.reason;
+      err.error = json.error;
+      throw err;
+    }
+    return json;
+  });
+}
+
+export default docFetcher;
diff --git a/app/addons/documents/rev-browser/getTree.js b/app/addons/documents/rev-browser/getTree.js
new file mode 100644
index 0000000..e5cfb90
--- /dev/null
+++ b/app/addons/documents/rev-browser/getTree.js
@@ -0,0 +1,38 @@
+// 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.
+
+function getTree(fetcher, doc) {
+  const winningRev = doc._rev;
+
+  return fetcher.getDoc(doc._id, { revs: true, open_revs: "all" })
+    .then(results => {
+      const deleted = {};
+      const paths = results.map(res => {
+        res = res.ok;
+        if (res._deleted) {
+          deleted[res._rev] = true;
+        }
+        const revs = res._revisions;
+        return revs.ids.map(function (id, i) {
+          return revs.start - i + "-" + id;
+        });
+      });
+      return {
+        paths: paths,
+        deleted: deleted,
+        winner: winningRev,
+      };
+    });
+}
+
+
+export default getTree;
diff --git a/package-lock.json b/package-lock.json
index 8923b73..8caf647 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -2041,14 +2041,6 @@
       "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
       "dev": true
     },
-    "abort-controller": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
-      "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
-      "requires": {
-        "event-target-shim": "^5.0.0"
-      }
-    },
     "accepts": {
       "version": "1.3.7",
       "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
@@ -2191,9 +2183,9 @@
       "dev": true
     },
     "ansi-regex": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
-      "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+      "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="
     },
     "ansi-styles": {
       "version": "3.2.1",
@@ -2254,11 +2246,6 @@
         "sprintf-js": "~1.0.2"
       }
     },
-    "argsarray": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/argsarray/-/argsarray-0.0.1.tgz",
-      "integrity": "sha1-bnIHtOzbObCviDA/pa4ivajfYcs="
-    },
     "arr-diff": {
       "version": "4.0.0",
       "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
@@ -3132,7 +3119,8 @@
     "buffer-from": {
       "version": "1.1.1",
       "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A=="
+      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
+      "dev": true
     },
     "buffer-indexof": {
       "version": "1.1.1",
@@ -3603,11 +3591,6 @@
       "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=",
       "dev": true
     },
-    "clone-buffer": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
-      "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg="
-    },
     "clone-deep": {
       "version": "4.0.1",
       "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz",
@@ -5128,11 +5111,6 @@
       "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
       "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
     },
-    "event-target-shim": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
-      "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
-    },
     "eventemitter2": {
       "version": "0.4.14",
       "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz",
@@ -5500,14 +5478,6 @@
         "bser": "2.1.1"
       }
     },
-    "fetch-cookie": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/fetch-cookie/-/fetch-cookie-0.10.1.tgz",
-      "integrity": "sha512-beB+VEd4cNeVG1PY+ee74+PkuCQnik78pgLi5Ah/7qdUfov8IctU0vLUbBT8/10Ma5GMBeI4wtxhGrEfKNYs2g==",
-      "requires": {
-        "tough-cookie": "^2.3.3 || ^3.0.1 || ^4.0.0"
-      }
-    },
     "fetch-mock": {
       "version": "9.11.0",
       "resolved": "https://registry.npmjs.org/fetch-mock/-/fetch-mock-9.11.0.tgz",
@@ -7338,11 +7308,6 @@
       "dev": true,
       "optional": true
     },
-    "immediate": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.3.0.tgz",
-      "integrity": "sha512-HR7EVodfFUdQCTIeySw+WDRFJlPcLOJbXfwwZ7Oom6tjsvZ3bOkCDJHehQC3nxJrv7+f9XecwazynjU8e4Vw3Q=="
-    },
     "import-fresh": {
       "version": "3.3.0",
       "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
@@ -10334,9 +10299,37 @@
       }
     },
     "node-fetch": {
-      "version": "2.6.0",
-      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.0.tgz",
-      "integrity": "sha512-8dG4H5ujfvFiqDmVu9fQ5bOHUC15JMjMY/Zumv26oOvvVJjM67KF8koCWIabKQ1GJIa9r2mMZscBq/TbdOcmNA=="
+      "version": "2.6.5",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.5.tgz",
+      "integrity": "sha512-mmlIVHJEu5rnIxgEgez6b9GgWXbkZj5YZ7fx+2r94a2E+Uirsp6HsPTPlomfdHtpt/B0cdKviwkoaM6pyvUOpQ==",
+      "dev": true,
+      "requires": {
+        "whatwg-url": "^5.0.0"
+      },
+      "dependencies": {
+        "tr46": {
+          "version": "0.0.3",
+          "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+          "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
+          "dev": true
+        },
+        "webidl-conversions": {
+          "version": "3.0.1",
+          "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+          "integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=",
+          "dev": true
+        },
+        "whatwg-url": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+          "integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
+          "dev": true,
+          "requires": {
+            "tr46": "~0.0.3",
+            "webidl-conversions": "^3.0.0"
+          }
+        }
+      }
     },
     "node-forge": {
       "version": "0.10.0",
@@ -11687,143 +11680,6 @@
       "integrity": "sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ==",
       "dev": true
     },
-    "pouchdb-adapter-http": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-adapter-http/-/pouchdb-adapter-http-7.2.2.tgz",
-      "integrity": "sha512-6Z6umJq7b5sRXwDM3CLfHrGhJPMR02M5osUxkwH1PpqcTF0EXPJvX+PtzTjSPcXWfaK6kgH3zNrRKQDdpzjI9A==",
-      "requires": {
-        "argsarray": "0.0.1",
-        "pouchdb-binary-utils": "7.2.2",
-        "pouchdb-errors": "7.2.2",
-        "pouchdb-fetch": "7.2.2",
-        "pouchdb-utils": "7.2.2"
-      }
-    },
-    "pouchdb-binary-utils": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-binary-utils/-/pouchdb-binary-utils-7.2.2.tgz",
-      "integrity": "sha512-shacxlmyHbUrNfE6FGYpfyAJx7Q0m91lDdEAaPoKZM3SzAmbtB1i+OaDNtYFztXjJl16yeudkDb3xOeokVL3Qw==",
-      "requires": {
-        "buffer-from": "1.1.1"
-      }
-    },
-    "pouchdb-changes-filter": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-changes-filter/-/pouchdb-changes-filter-7.2.2.tgz",
-      "integrity": "sha512-1txJnTtL/C7zrq+spLt3pH9EDHTWmLLwp2zx8zUQrkt6eQtuLuXUI7G84xe+hfpU0rQvUzp/APYMnko0/6Rw0A==",
-      "requires": {
-        "pouchdb-errors": "7.2.2",
-        "pouchdb-selector-core": "7.2.2",
-        "pouchdb-utils": "7.2.2"
-      }
-    },
-    "pouchdb-collate": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-collate/-/pouchdb-collate-7.2.2.tgz",
-      "integrity": "sha512-/SMY9GGasslknivWlCVwXMRMnQ8myKHs4WryQ5535nq1Wj/ehpqWloMwxEQGvZE1Sda3LOm7/5HwLTcB8Our+w=="
-    },
-    "pouchdb-collections": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-collections/-/pouchdb-collections-7.2.2.tgz",
-      "integrity": "sha512-6O9zyAYlp3UdtfneiMYuOCWdUCQNo2bgdjvNsMSacQX+3g8WvIoFQCYJjZZCpTttQGb+MHeRMr8m2U95lhJTew=="
-    },
-    "pouchdb-core": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-core/-/pouchdb-core-7.2.2.tgz",
-      "integrity": "sha512-AnMmSH+xx12Vk6oASDRQoElXfV9fSn8MIwfus0oa2lqkxowx4bvidofZbhZfKEiE6QgKwFEOBzs56MS3znI8TQ==",
-      "requires": {
-        "argsarray": "0.0.1",
-        "inherits": "2.0.4",
-        "pouchdb-changes-filter": "7.2.2",
-        "pouchdb-collections": "7.2.2",
-        "pouchdb-errors": "7.2.2",
-        "pouchdb-fetch": "7.2.2",
-        "pouchdb-merge": "7.2.2",
-        "pouchdb-utils": "7.2.2"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-        }
-      }
-    },
-    "pouchdb-errors": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-errors/-/pouchdb-errors-7.2.2.tgz",
-      "integrity": "sha512-6GQsiWc+7uPfgEHeavG+7wuzH3JZW29Dnrvz8eVbDFE50kVFxNDVm3EkYHskvo5isG7/IkOx7PV7RPTA3keG3g==",
-      "requires": {
-        "inherits": "2.0.4"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-        }
-      }
-    },
-    "pouchdb-fetch": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-fetch/-/pouchdb-fetch-7.2.2.tgz",
-      "integrity": "sha512-lUHmaG6U3zjdMkh8Vob9GvEiRGwJfXKE02aZfjiVQgew+9SLkuOxNw3y2q4d1B6mBd273y1k2Lm0IAziRNxQnA==",
-      "requires": {
-        "abort-controller": "3.0.0",
-        "fetch-cookie": "0.10.1",
-        "node-fetch": "2.6.0"
-      }
-    },
-    "pouchdb-md5": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-md5/-/pouchdb-md5-7.2.2.tgz",
-      "integrity": "sha512-c/RvLp2oSh8PLAWU5vFBnp6ejJABIdKqboZwRRUrWcfGDf+oyX8RgmJFlYlzMMOh4XQLUT1IoaDV8cwlsuryZw==",
-      "requires": {
-        "pouchdb-binary-utils": "7.2.2",
-        "spark-md5": "3.0.1"
-      }
-    },
-    "pouchdb-merge": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-merge/-/pouchdb-merge-7.2.2.tgz",
-      "integrity": "sha512-6yzKJfjIchBaS7Tusuk8280WJdESzFfQ0sb4jeMUNnrqs4Cx3b0DIEOYTRRD9EJDM+je7D3AZZ4AT0tFw8gb4A=="
-    },
-    "pouchdb-selector-core": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-selector-core/-/pouchdb-selector-core-7.2.2.tgz",
-      "integrity": "sha512-XYKCNv9oiNmSXV5+CgR9pkEkTFqxQGWplnVhO3W9P154H08lU0ZoNH02+uf+NjZ2kjse7Q1fxV4r401LEcGMMg==",
-      "requires": {
-        "pouchdb-collate": "7.2.2",
-        "pouchdb-utils": "7.2.2"
-      }
-    },
-    "pouchdb-utils": {
-      "version": "7.2.2",
-      "resolved": "https://registry.npmjs.org/pouchdb-utils/-/pouchdb-utils-7.2.2.tgz",
-      "integrity": "sha512-XmeM5ioB4KCfyB2MGZXu1Bb2xkElNwF1qG+zVFbQsKQij0zvepdOUfGuWvLRHxTOmt4muIuSOmWZObZa3NOgzQ==",
-      "requires": {
-        "argsarray": "0.0.1",
-        "clone-buffer": "1.0.0",
-        "immediate": "3.3.0",
-        "inherits": "2.0.4",
-        "pouchdb-collections": "7.2.2",
-        "pouchdb-errors": "7.2.2",
-        "pouchdb-md5": "7.2.2",
-        "uuid": "8.1.0"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-        },
-        "uuid": {
-          "version": "8.1.0",
-          "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.1.0.tgz",
-          "integrity": "sha512-CI18flHDznR0lq54xBycOVmphdCYnQLKn8abKn7PXUiKUGdEd+/l9LWNJmugXel4hXq7S+RMNl34ecyC9TntWg=="
-        }
-      }
-    },
     "prelude-ls": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@@ -13497,11 +13353,6 @@
       "integrity": "sha512-cPiFOTLUKvJFIg4SKVScy4ilPPW6rFgMgfuZJPNoDuMs3nC1HbMUycBoJw77xFIp6z1UJQJOfx6C9GMH80DiTw==",
       "dev": true
     },
-    "spark-md5": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/spark-md5/-/spark-md5-3.0.1.tgz",
-      "integrity": "sha512-0tF3AGSD1ppQeuffsLDIOWlKUd3lS92tFxcsrh5Pe3ZphhnoK+oXIBTzOAThZCiuINZLvpiLH/1VS1/ANEJVig=="
-    },
     "spawn-wrap": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/spawn-wrap/-/spawn-wrap-2.0.0.tgz",
@@ -16064,11 +15915,6 @@
         "extsprintf": "^1.2.0"
       }
     },
-    "visualize-rev-tree": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/visualize-rev-tree/-/visualize-rev-tree-0.0.1.tgz",
-      "integrity": "sha512-FWGun8R+BCINc7GBAWS8cEu9Nry40ZH3mM8XGgsqMFNJ0nFzeF9YecesK45EO5Pwgt8rBntdTdZfCV/JS1gjVw=="
-    },
     "vm-browserify": {
       "version": "1.1.2",
       "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
diff --git a/package.json b/package.json
index d32603c..0709cb5 100644
--- a/package.json
+++ b/package.json
@@ -52,6 +52,7 @@
     "mini-css-extract-plugin": "^0.7.0",
     "mock-local-storage": "^1.1.17",
     "nightwatch": "^1.7.2",
+    "node-fetch": "^2.6.5",
     "redux-mock-store": "^1.5.4",
     "sinon": "^7.5.0",
     "style-loader": "^0.23.1",
@@ -84,8 +85,6 @@
     "mkdirp": "^0.5.1",
     "moment": "^2.29.1",
     "nano": "~8.0.0",
-    "pouchdb-adapter-http": "^7.2.2",
-    "pouchdb-core": "^7.2.2",
     "prop-types": "^15.7.2",
     "rc-slider": "^9.5.4",
     "react": "^16.14.0",
@@ -106,7 +105,6 @@
     "url": "~0.7.9",
     "urls": "~0.0.3",
     "uuid": "^3.4.0",
-    "visualize-rev-tree": "0.0.1",
     "whatwg-fetch": "^2.0.4",
     "yargs": "^16.2.0"
   },