(#5197) - detect WebSQL invalid on WKWebView
diff --git a/packages/pouchdb-adapter-websql/package.json b/packages/pouchdb-adapter-websql/package.json
index 34ffcf4..c0bb58d 100644
--- a/packages/pouchdb-adapter-websql/package.json
+++ b/packages/pouchdb-adapter-websql/package.json
@@ -14,6 +14,7 @@
   ],
   "dependencies": {
     "js-extend": "1.0.1",
-    "pouchdb-adapter-websql-core": "5.4.0-prerelease"
+    "pouchdb-adapter-websql-core": "5.4.0-prerelease",
+    "pouchdb-utils": "5.4.0-prerelease"
   }
 }
diff --git a/packages/pouchdb-adapter-websql/src/index.js b/packages/pouchdb-adapter-websql/src/index.js
index 1f9c034..7081a9f 100644
--- a/packages/pouchdb-adapter-websql/src/index.js
+++ b/packages/pouchdb-adapter-websql/src/index.js
@@ -1,5 +1,6 @@
 import WebSqlPouchCore from 'pouchdb-adapter-websql-core';
 import { extend } from 'js-extend';
+import valid from './valid';
 
 function websql(optsOrName, version, description, size) {
   if (typeof sqlitePlugin !== 'undefined') {
@@ -22,13 +23,7 @@
   WebSqlPouchCore.call(this, _opts, callback);
 }
 
-WebSQLPouch.valid = function () {
-  // SQLitePlugin leaks this global object, which we can use
-  // to detect if it's installed or not. The benefit is that it's
-  // declared immediately, before the 'deviceready' event has fired.
-  return typeof openDatabase !== 'undefined' ||
-    typeof SQLitePlugin !== 'undefined';
-};
+WebSQLPouch.valid = valid;
 
 WebSQLPouch.use_prefix = true;
 
diff --git a/packages/pouchdb-adapter-websql/src/valid.js b/packages/pouchdb-adapter-websql/src/valid.js
new file mode 100644
index 0000000..41dbe42
--- /dev/null
+++ b/packages/pouchdb-adapter-websql/src/valid.js
@@ -0,0 +1,64 @@
+import { hasLocalStorage } from 'pouchdb-utils';
+
+function canOpenTestDB() {
+  try {
+    openDatabase('_pouch_validate_websql', 1, '', 1);
+    return true;
+  } catch (err) {
+    return false;
+  }
+}
+
+// WKWebView had a bug where WebSQL would throw a DOM Exception 18
+// (see https://bugs.webkit.org/show_bug.cgi?id=137760 and
+// https://github.com/pouchdb/pouchdb/issues/5079)
+// This has been fixed in latest WebKit, so we try to detect it here.
+function isValidWebSQL() {
+  // WKWebView UA:
+  //   Mozilla/5.0 (iPhone; CPU iPhone OS 9_2 like Mac OS X)
+  //   AppleWebKit/601.1.46 (KHTML, like Gecko) Mobile/13C75
+  // Chrome for iOS UA:
+  //   Mozilla/5.0 (iPhone; U; CPU iPhone OS 5_1_1 like Mac OS X; en)
+  //   AppleWebKit/534.46.0 (KHTML, like Gecko) CriOS/19.0.1084.60
+  //   Mobile/9B206 Safari/7534.48.3
+  // Firefox for iOS UA:
+  //   Mozilla/5.0 (iPhone; CPU iPhone OS 8_3 like Mac OS X) AppleWebKit/600.1.4
+  //   (KHTML, like Gecko) FxiOS/1.0 Mobile/12F69 Safari/600.1.4
+
+  // typeof indexedDB is null on some UIWebViews and undefined in others
+  if (typeof indexedDB !== 'object' ||
+      !/iP(hone|od|ad)/.test(navigator.userAgent)) {
+    // definitely not WKWebView, avoid creating an unnecessary database
+    return true;
+  }
+  // Cache the result in LocalStorage. Reason we do this is because if we
+  // call openDatabase() too many times, Safari craps out in SauceLabs and
+  // starts throwing DOM Exception 14s.
+  var hasLS = hasLocalStorage();
+  // Include user agent in the hash, so that if Safari is upgraded, we don't
+  // continually think it's broken.
+  var localStorageKey = '_pouch__websqldb_valid_' + navigator.userAgent;
+  if (hasLS && localStorage[localStorageKey]) {
+    return localStorage[localStorageKey] === '1';
+  }
+  var openedTestDB = canOpenTestDB();
+  if (hasLS) {
+    localStorage[localStorageKey] = openedTestDB ? '1' : '0';
+  }
+  return openedTestDB;
+}
+
+function valid() {
+  // SQLitePlugin leaks this global object, which we can use
+  // to detect if it's installed or not. The benefit is that it's
+  // declared immediately, before the 'deviceready' event has fired.
+  if (typeof SQLitePlugin !== 'undefined') {
+    return true;
+  }
+  if (typeof openDatabase === 'undefined') {
+    return false;
+  }
+  return isValidWebSQL();
+}
+
+export default valid;
\ No newline at end of file