gnunet-svn
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[taler-wallet-core] branch master updated: idb-bridge: remove cyclic dep


From: gnunet
Subject: [taler-wallet-core] branch master updated: idb-bridge: remove cyclic dependencies, rip out api extractor
Date: Mon, 08 Feb 2021 15:23:49 +0100

This is an automated email from the git hooks/post-receive script.

dold pushed a commit to branch master
in repository wallet-core.

The following commit(s) were added to refs/heads/master by this push:
     new 4452984a idb-bridge: remove cyclic dependencies, rip out api extractor
4452984a is described below

commit 4452984a24334e3b7afb60e3db9dc12db02d65ba
Author: Florian Dold <florian@dold.me>
AuthorDate: Mon Feb 8 15:23:44 2021 +0100

    idb-bridge: remove cyclic dependencies, rip out api extractor
---
 packages/idb-bridge/api-extractor.json             |  131 --
 packages/idb-bridge/package.json                   |   11 +-
 packages/idb-bridge/src/BridgeIDBCursor.ts         |  364 ----
 .../idb-bridge/src/BridgeIDBCursorWithValue.ts     |   48 -
 packages/idb-bridge/src/BridgeIDBDatabase.ts       |  249 ---
 packages/idb-bridge/src/BridgeIDBFactory.ts        |  226 ---
 packages/idb-bridge/src/BridgeIDBIndex.ts          |  319 ---
 packages/idb-bridge/src/BridgeIDBKeyRange.ts       |  131 --
 packages/idb-bridge/src/BridgeIDBObjectStore.ts    |  467 -----
 packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts  |   35 -
 packages/idb-bridge/src/BridgeIDBRequest.ts        |   86 -
 packages/idb-bridge/src/BridgeIDBTransaction.ts    |  326 ----
 .../idb-bridge/src/BridgeIDBVersionChangeEvent.ts  |   39 -
 packages/idb-bridge/src/MemoryBackend.test.ts      |   14 +-
 packages/idb-bridge/src/MemoryBackend.ts           |   28 +-
 packages/idb-bridge/src/backend-interface.ts       |   47 +-
 packages/idb-bridge/src/bridge-idb.ts              | 2053 ++++++++++++++++++++
 packages/idb-bridge/src/index.ts                   |   53 +-
 packages/idb-bridge/src/tree/b+tree.ts             |    2 +-
 packages/idb-bridge/src/util/FakeEvent.ts          |   11 +-
 packages/idb-bridge/src/util/FakeEventTarget.ts    |    3 +-
 packages/idb-bridge/src/util/canInjectKey.ts       |    4 +-
 packages/idb-bridge/src/util/deepEquals.ts         |    2 +-
 packages/idb-bridge/src/util/extractKey.ts         |    6 +-
 packages/idb-bridge/src/util/fakeDOMStringList.ts  |   10 +-
 packages/idb-bridge/src/util/getIndexKeys.ts       |   12 +-
 packages/idb-bridge/src/util/injectKey.ts          |   10 +-
 packages/idb-bridge/src/util/makeStoreKeyValue.ts  |   14 +-
 packages/idb-bridge/src/util/types.ts              |   84 -
 packages/idb-bridge/src/util/validateKeyPath.ts    |   35 +-
 packages/idb-bridge/src/util/valueToKey.ts         |    7 +-
 packages/idb-bridge/tsconfig.json                  |    1 +
 pnpm-lock.yaml                                     |    4 +-
 33 files changed, 2196 insertions(+), 2636 deletions(-)

diff --git a/packages/idb-bridge/api-extractor.json 
b/packages/idb-bridge/api-extractor.json
deleted file mode 100644
index f57d81d8..00000000
--- a/packages/idb-bridge/api-extractor.json
+++ /dev/null
@@ -1,131 +0,0 @@
-/**
- * Config file for API Extractor.  For more info, please visit: 
https://api-extractor.com
- */
-{
-  "$schema": 
"https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json";,
-
-  /**
-   * (REQUIRED) Specifies the .d.ts file to be used as the starting point for 
analysis.  API Extractor
-   * analyzes the symbols exported by this module.
-   *
-   * The file extension must be ".d.ts" and not ".ts".
-   *
-   * The path is resolved relative to the folder of the config file that 
contains the setting; to change this,
-   * prepend a folder token such as "<projectFolder>".
-   *
-   * SUPPORTED TOKENS: <projectFolder>, <packageName>, <unscopedPackageName>
-   */
-  "mainEntryPointFilePath": "<projectFolder>/lib/index.d.ts",
-
-  /**
-   * A list of NPM package names whose exports should be treated as part of 
this package.
-   *
-   * For example, suppose that Webpack is used to generate a distributed 
bundle for the project "library1",
-   * and another NPM package "library2" is embedded in this bundle.  Some 
types from library2 may become part
-   * of the exported API for library1, but by default API Extractor would 
generate a .d.ts rollup that explicitly
-   * imports library2.  To avoid this, we can specify:
-   *
-   *   "bundledPackages": [ "library2" ],
-   *
-   * This would direct API Extractor to embed those types directly in the 
.d.ts rollup, as if they had been
-   * local files for library1.
-   */
-  "bundledPackages": [],
-
-  /**
-   * Configures how the API report file (*.api.md) will be generated.
-   */
-  "apiReport": {
-    /**
-     * (REQUIRED) Whether to generate an API report.
-     */
-    "enabled": false
-  },
-
-  /**
-   * Configures how the doc model file (*.api.json) will be generated.
-   */
-  "docModel": {
-    /**
-     * (REQUIRED) Whether to generate a doc model file.
-     */
-    "enabled": false
-  },
-
-  /**
-   * Configures how the .d.ts rollup file will be generated.
-   */
-  "dtsRollup": {
-    /**
-     * (REQUIRED) Whether to generate the .d.ts rollup file.
-     */
-    "enabled": true
-  },
-
-  /**
-   * Configures how the tsdoc-metadata.json file will be generated.
-   */
-  "tsdocMetadata": {
-    /**
-     * Whether to generate the tsdoc-metadata.json file.
-     *
-     * DEFAULT VALUE: true
-     */
-    "enabled": false
-  },
-
-  /**
-   * Specifies what type of newlines API Extractor should use when writing 
output files.  By default, the output files
-   * will be written with Windows-style newlines.  To use POSIX-style 
newlines, specify "lf" instead.
-   * To use the OS's default newline kind, specify "os".
-   *
-   * DEFAULT VALUE: "crlf"
-   */
-  "newlineKind": "lf",
-
-  /**
-   * Configures how API Extractor reports error and warning messages produced 
during analysis.
-   *
-   * There are three sources of messages:  compiler messages, API Extractor 
messages, and TSDoc messages.
-   */
-  "messages": {
-    /**
-     * Configures handling of diagnostic messages reported by the TypeScript 
compiler engine while analyzing
-     * the input .d.ts files.
-     *
-     * TypeScript message identifiers start with "TS" followed by an integer.  
For example: "TS2551"
-     *
-     * DEFAULT VALUE:  A single "default" entry with logLevel=warning.
-     */
-    "compilerMessageReporting": {
-      /**
-       * Configures the default routing for messages that don't match an 
explicit rule in this table.
-       */
-      "default": {
-        "logLevel": "warning"
-      }
-    },
-
-    /**
-     * Configures handling of messages reported by API Extractor during its 
analysis.
-     *
-     * API Extractor message identifiers start with "ae-".  For example: 
"ae-extra-release-tag"
-     *
-     * DEFAULT VALUE: See api-extractor-defaults.json for the complete table 
of extractorMessageReporting mappings
-     */
-    "extractorMessageReporting": {
-      "default": {
-        "logLevel": "warning"
-      }
-    },
-
-    /**
-     * Configures handling of messages reported by the TSDoc parser when 
analyzing code comments.
-     */
-    "tsdocMessageReporting": {
-      "default": {
-        "logLevel": "warning"
-      }
-    }
-  }
-}
diff --git a/packages/idb-bridge/package.json b/packages/idb-bridge/package.json
index f8be8298..cfa0fa9f 100644
--- a/packages/idb-bridge/package.json
+++ b/packages/idb-bridge/package.json
@@ -4,19 +4,19 @@
   "description": "IndexedDB implementation that uses SQLite3 as storage",
   "main": "./dist/idb-bridge.js",
   "module": "./lib/index.js",
-  "types": "./dist/idb-bridge.d.ts",
+  "types": "./lib/index.d.ts",
   "author": "Florian Dold",
   "license": "AGPL-3.0-or-later",
   "private": false,
   "scripts": {
     "test": "tsc && ava",
-    "prepare": "tsc && rollup -c && api-extractor run",
-    "compile": "tsc && rollup -c && api-extractor run",
+    "prepare": "tsc && rollup -c",
+    "compile": "tsc && rollup -c",
     "clean": "rimraf dist lib tsconfig.tsbuildinfo",
     "pretty": "prettier --write src"
   },
   "devDependencies": {
-    "@microsoft/api-extractor": "^7.13.0",
+    "@types/node": "^14.14.22",
     "ava": "^3.15.0",
     "esm": "^3.2.25",
     "prettier": "^2.2.1",
@@ -25,7 +25,6 @@
     "typescript": "^4.1.3"
   },
   "dependencies": {
-    "@types/node": "^14.14.22",
     "tslib": "^2.1.0"
   },
   "ava": {
@@ -33,4 +32,4 @@
       "esm"
     ]
   }
-}
\ No newline at end of file
+}
diff --git a/packages/idb-bridge/src/BridgeIDBCursor.ts 
b/packages/idb-bridge/src/BridgeIDBCursor.ts
deleted file mode 100644
index a18c0beb..00000000
--- a/packages/idb-bridge/src/BridgeIDBCursor.ts
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
-
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- 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 { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import compareKeys from "./util/cmp";
-import {
-  DataError,
-  InvalidStateError,
-  ReadOnlyError,
-  TransactionInactiveError,
-} from "./util/errors";
-import structuredClone from "./util/structuredClone";
-import {
-  CursorRange,
-  CursorSource,
-  Key,
-  Value,
-  BridgeIDBCursorDirection,
-} from "./util/types";
-import valueToKey from "./util/valueToKey";
-import {
-  RecordGetRequest,
-  ResultLevel,
-  Backend,
-  RecordStoreRequest,
-  StoreLevel,
-} from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-
-/**
- * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
- *
- * @public
- */
-export class BridgeIDBCursor {
-  _request: BridgeIDBRequest | undefined;
-
-  private _gotValue: boolean = false;
-  private _range: CursorRange;
-  private _indexPosition = undefined; // Key of previously returned record
-  private _objectStorePosition = undefined;
-  private _keyOnly: boolean;
-
-  private _source: CursorSource;
-  private _direction: BridgeIDBCursorDirection;
-  private _key = undefined;
-  private _primaryKey: Key | undefined = undefined;
-  private _indexName: string | undefined;
-  private _objectStoreName: string;
-
-  protected _value: Value = undefined;
-
-  constructor(
-    source: CursorSource,
-    objectStoreName: string,
-    indexName: string | undefined,
-    range: CursorRange,
-    direction: BridgeIDBCursorDirection,
-    request: BridgeIDBRequest,
-    keyOnly: boolean,
-  ) {
-    this._indexName = indexName;
-    this._objectStoreName = objectStoreName;
-    this._range = range;
-    this._source = source;
-    this._direction = direction;
-    this._request = request;
-    this._keyOnly = keyOnly;
-  }
-
-  get _effectiveObjectStore(): BridgeIDBObjectStore {
-    if (this.source instanceof BridgeIDBObjectStore) {
-      return this.source;
-    }
-    return this.source.objectStore;
-  }
-
-  get _backend(): Backend {
-    return this._source._backend;
-  }
-
-  // Read only properties
-  get source() {
-    return this._source;
-  }
-  set source(val) {
-    /* For babel */
-  }
-
-  get direction() {
-    return this._direction;
-  }
-  set direction(val) {
-    /* For babel */
-  }
-
-  get key() {
-    return this._key;
-  }
-  set key(val) {
-    /* For babel */
-  }
-
-  get primaryKey() {
-    return this._primaryKey;
-  }
-
-  set primaryKey(val) {
-    /* For babel */
-  }
-
-  protected get _isValueCursor(): boolean {
-    return false;
-  }
-
-  /**
-   * https://w3c.github.io/IndexedDB/#iterate-a-cursor
-   */
-  async _iterate(key?: Key, primaryKey?: Key): Promise<any> {
-    BridgeIDBFactory.enableTracing &&
-      console.log(
-        `iterating cursor os=${this._objectStoreName},idx=${this._indexName}`,
-      );
-    BridgeIDBFactory.enableTracing &&
-      console.log("cursor type ", this.toString());
-    const recordGetRequest: RecordGetRequest = {
-      direction: this.direction,
-      indexName: this._indexName,
-      lastIndexPosition: this._indexPosition,
-      lastObjectStorePosition: this._objectStorePosition,
-      limit: 1,
-      range: this._range,
-      objectStoreName: this._objectStoreName,
-      advanceIndexKey: key,
-      advancePrimaryKey: primaryKey,
-      resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
-    };
-
-    const { btx } = this.source._confirmActiveTransaction();
-
-    let response = await this._backend.getRecords(btx, recordGetRequest);
-
-    if (response.count === 0) {
-      if (BridgeIDBFactory.enableTracing) {
-        console.log("cursor is returning empty result");
-      }
-      this._gotValue = false;
-      return null;
-    }
-
-    if (response.count !== 1) {
-      throw Error("invariant failed");
-    }
-
-    if (BridgeIDBFactory.enableTracing) {
-      console.log("request is:", JSON.stringify(recordGetRequest));
-      console.log("get response is:", JSON.stringify(response));
-    }
-
-    if (this._indexName !== undefined) {
-      this._key = response.indexKeys![0];
-    } else {
-      this._key = response.primaryKeys![0];
-    }
-
-    this._primaryKey = response.primaryKeys![0];
-
-    if (!this._keyOnly) {
-      this._value = response.values![0];
-    }
-
-    this._gotValue = true;
-    this._objectStorePosition = structuredClone(response.primaryKeys![0]);
-    if (response.indexKeys !== undefined && response.indexKeys.length > 0) {
-      this._indexPosition = structuredClone(response.indexKeys[0]);
-    }
-
-    return this;
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
-  public update(value: Value) {
-    if (value === undefined) {
-      throw new TypeError();
-    }
-
-    const transaction = this._effectiveObjectStore.transaction;
-
-    if (transaction._state !== "active") {
-      throw new TransactionInactiveError();
-    }
-
-    if (transaction.mode === "readonly") {
-      throw new ReadOnlyError();
-    }
-
-    if (this._effectiveObjectStore._deleted) {
-      throw new InvalidStateError();
-    }
-
-    if (
-      !(this.source instanceof BridgeIDBObjectStore) &&
-      this.source._deleted
-    ) {
-      throw new InvalidStateError();
-    }
-
-    if (!this._gotValue || !this._isValueCursor) {
-      throw new InvalidStateError();
-    }
-
-    const storeReq: RecordStoreRequest = {
-      key: this._primaryKey,
-      value: value,
-      objectStoreName: this._objectStoreName,
-      storeLevel: StoreLevel.UpdateExisting,
-    };
-
-    const operation = async () => {
-      if (BridgeIDBFactory.enableTracing) {
-        console.log("updating at cursor");
-      }
-      const { btx } = this.source._confirmActiveTransaction();
-      await this._backend.storeRecord(btx, storeReq);
-    };
-    return transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  /**
-   * 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
-   */
-  public advance(count: number) {
-    throw Error("not implemented");
-  }
-
-  /**
-   * 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
-   */
-  public continue(key?: Key) {
-    const transaction = this._effectiveObjectStore.transaction;
-
-    if (transaction._state !== "active") {
-      throw new TransactionInactiveError();
-    }
-
-    if (this._effectiveObjectStore._deleted) {
-      throw new InvalidStateError();
-    }
-    if (
-      !(this.source instanceof BridgeIDBObjectStore) &&
-      this.source._deleted
-    ) {
-      throw new InvalidStateError();
-    }
-
-    if (!this._gotValue) {
-      throw new InvalidStateError();
-    }
-
-    if (key !== undefined) {
-      key = valueToKey(key);
-      let lastKey =
-        this._indexName === undefined
-          ? this._objectStorePosition
-          : this._indexPosition;
-
-      const cmpResult = compareKeys(key, lastKey);
-
-      if (
-        (cmpResult <= 0 &&
-          (this.direction === "next" || this.direction === "nextunique")) ||
-        (cmpResult >= 0 &&
-          (this.direction === "prev" || this.direction === "prevunique"))
-      ) {
-        throw new DataError();
-      }
-    }
-
-    if (this._request) {
-      this._request.readyState = "pending";
-    }
-
-    const operation = async () => {
-      return this._iterate(key);
-    };
-
-    transaction._execRequestAsync({
-      operation,
-      request: this._request,
-      source: this.source,
-    });
-
-    this._gotValue = false;
-  }
-
-  // https://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
-  public continuePrimaryKey(key: Key, primaryKey: Key) {
-    throw Error("not implemented");
-  }
-
-  public delete() {
-    const transaction = this._effectiveObjectStore.transaction;
-
-    if (transaction._state !== "active") {
-      throw new TransactionInactiveError();
-    }
-
-    if (transaction.mode === "readonly") {
-      throw new ReadOnlyError();
-    }
-
-    if (this._effectiveObjectStore._deleted) {
-      throw new InvalidStateError();
-    }
-    if (
-      !(this.source instanceof BridgeIDBObjectStore) &&
-      this.source._deleted
-    ) {
-      throw new InvalidStateError();
-    }
-
-    if (!this._gotValue || !this._isValueCursor) {
-      throw new InvalidStateError();
-    }
-
-    const operation = async () => {
-      const { btx } = this.source._confirmActiveTransaction();
-      this._backend.deleteRecord(
-        btx,
-        this._objectStoreName,
-        BridgeIDBKeyRange._valueToKeyRange(this._primaryKey),
-      );
-    };
-
-    return transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  public toString() {
-    return "[object IDBCursor]";
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts 
b/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
deleted file mode 100644
index 8561879c..00000000
--- a/packages/idb-bridge/src/BridgeIDBCursorWithValue.ts
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
-
- 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 { BridgeIDBCursor } from "./BridgeIDBCursor";
-import {
-  CursorRange,
-  CursorSource,
-  BridgeIDBCursorDirection,
-  Value,
-} from "./util/types";
-
-export class BridgeIDBCursorWithValue extends BridgeIDBCursor {
-  get value(): Value {
-    return this._value;
-  }
-
-  protected get _isValueCursor(): boolean {
-    return true;
-  }
-
-  constructor(
-    source: CursorSource,
-    objectStoreName: string,
-    indexName: string | undefined,
-    range: CursorRange,
-    direction: BridgeIDBCursorDirection,
-    request?: any,
-  ) {
-    super(source, objectStoreName, indexName, range, direction, request, 
false);
-  }
-
-  public toString() {
-    return "[object IDBCursorWithValue]";
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBDatabase.ts 
b/packages/idb-bridge/src/BridgeIDBDatabase.ts
deleted file mode 100644
index ffd897f9..00000000
--- a/packages/idb-bridge/src/BridgeIDBDatabase.ts
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- *
- * 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 { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import {
-  ConstraintError,
-  InvalidAccessError,
-  InvalidStateError,
-  NotFoundError,
-  TransactionInactiveError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import FakeEventTarget from "./util/FakeEventTarget";
-import { FakeDOMStringList, KeyPath, TransactionMode } from "./util/types";
-import validateKeyPath from "./util/validateKeyPath";
-import queueTask from "./util/queueTask";
-import {
-  Backend,
-  DatabaseConnection,
-  Schema,
-  DatabaseTransaction,
-} from "./backend-interface";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-
-/**
- * Ensure that an active version change transaction is currently running.
- */
-const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => 
{
-  if (!database._runningVersionchangeTransaction) {
-    throw new InvalidStateError();
-  }
-
-  // Find the latest versionchange transaction
-  const transactions = database._transactions.filter(
-    (tx: BridgeIDBTransaction) => {
-      return tx.mode === "versionchange";
-    },
-  );
-  const transaction = transactions[transactions.length - 1];
-
-  if (!transaction || transaction._state === "finished") {
-    throw new InvalidStateError();
-  }
-
-  if (transaction._state !== "active") {
-    throw new TransactionInactiveError();
-  }
-
-  return transaction;
-};
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
-/** @public */
-export class BridgeIDBDatabase extends FakeEventTarget {
-  _closePending = false;
-  _closed = false;
-  _runningVersionchangeTransaction = false;
-  _transactions: Array<BridgeIDBTransaction> = [];
-
-  _backendConnection: DatabaseConnection;
-  _backend: Backend;
-
-  _schema: Schema;
-
-  get name(): string {
-    return this._schema.databaseName;
-  }
-
-  get version(): number {
-    return this._schema.databaseVersion;
-  }
-
-  get objectStoreNames(): FakeDOMStringList {
-    return fakeDOMStringList(Object.keys(this._schema.objectStores)).sort();
-  }
-
-  /**
-   * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
-   */
-  _closeConnection() {
-    this._closePending = true;
-
-    const transactionsComplete = this._transactions.every(
-      (transaction: BridgeIDBTransaction) => {
-        return transaction._state === "finished";
-      },
-    );
-
-    if (transactionsComplete) {
-      this._closed = true;
-      this._backend.close(this._backendConnection);
-    } else {
-      queueTask(() => {
-        this._closeConnection();
-      });
-    }
-  }
-
-  constructor(backend: Backend, backendConnection: DatabaseConnection) {
-    super();
-
-    this._schema = backend.getSchema(backendConnection);
-
-    this._backend = backend;
-    this._backendConnection = backendConnection;
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
-  public createObjectStore(
-    name: string,
-    options: { autoIncrement?: boolean; keyPath?: KeyPath } | null = {},
-  ): BridgeIDBObjectStore {
-    if (name === undefined) {
-      throw new TypeError();
-    }
-    const transaction = confirmActiveVersionchangeTransaction(this);
-    const backendTx = transaction._backendTransaction;
-    if (!backendTx) {
-      throw Error("invariant violated");
-    }
-
-    const keyPath =
-      options !== null && options.keyPath !== undefined
-        ? options.keyPath
-        : null;
-    const autoIncrement =
-      options !== null && options.autoIncrement !== undefined
-        ? options.autoIncrement
-        : false;
-
-    if (keyPath !== null) {
-      validateKeyPath(keyPath);
-    }
-
-    if (Object.keys(this._schema.objectStores).includes(name)) {
-      throw new ConstraintError();
-    }
-
-    if (autoIncrement && (keyPath === "" || Array.isArray(keyPath))) {
-      throw new InvalidAccessError();
-    }
-
-    transaction._backend.createObjectStore(
-      backendTx,
-      name,
-      keyPath,
-      autoIncrement,
-    );
-
-    this._schema = this._backend.getSchema(this._backendConnection);
-
-    return transaction.objectStore(name);
-  }
-
-  public deleteObjectStore(name: string): void {
-    if (name === undefined) {
-      throw new TypeError();
-    }
-    const transaction = confirmActiveVersionchangeTransaction(this);
-    transaction._objectStoresCache.delete(name);
-  }
-
-  public _internalTransaction(
-    storeNames: string | string[],
-    mode?: TransactionMode,
-    backendTransaction?: DatabaseTransaction,
-  ): BridgeIDBTransaction {
-    mode = mode !== undefined ? mode : "readonly";
-    if (
-      mode !== "readonly" &&
-      mode !== "readwrite" &&
-      mode !== "versionchange"
-    ) {
-      throw new TypeError("Invalid mode: " + mode);
-    }
-
-    const hasActiveVersionchange = this._transactions.some(
-      (transaction: BridgeIDBTransaction) => {
-        return (
-          transaction._state === "active" &&
-          transaction.mode === "versionchange" &&
-          transaction.db === this
-        );
-      },
-    );
-    if (hasActiveVersionchange) {
-      throw new InvalidStateError();
-    }
-
-    if (this._closePending) {
-      throw new InvalidStateError();
-    }
-
-    if (!Array.isArray(storeNames)) {
-      storeNames = [storeNames];
-    }
-    if (storeNames.length === 0 && mode !== "versionchange") {
-      throw new InvalidAccessError();
-    }
-    for (const storeName of storeNames) {
-      if (this.objectStoreNames.indexOf(storeName) < 0) {
-        throw new NotFoundError(
-          "No objectStore named " + storeName + " in this database",
-        );
-      }
-    }
-
-    const tx = new BridgeIDBTransaction(
-      storeNames,
-      mode,
-      this,
-      backendTransaction,
-    );
-    this._transactions.push(tx);
-    queueTask(() => tx._start());
-    return tx;
-  }
-
-  public transaction(
-    storeNames: string | string[],
-    mode?: TransactionMode,
-  ): BridgeIDBTransaction {
-    if (mode === "versionchange") {
-      throw new TypeError("Invalid mode: " + mode);
-    }
-    return this._internalTransaction(storeNames, mode);
-  }
-
-  public close() {
-    this._closeConnection();
-  }
-
-  public toString() {
-    return "[object IDBDatabase]";
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBFactory.ts 
b/packages/idb-bridge/src/BridgeIDBFactory.ts
deleted file mode 100644
index 7954cdd9..00000000
--- a/packages/idb-bridge/src/BridgeIDBFactory.ts
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- * Copyright 2019 Florian Dold
- *
- * 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 { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBOpenDBRequest } from "./BridgeIDBOpenDBRequest";
-import { BridgeIDBVersionChangeEvent } from "./BridgeIDBVersionChangeEvent";
-import compareKeys from "./util/cmp";
-import enforceRange from "./util/enforceRange";
-import { AbortError, VersionError } from "./util/errors";
-import FakeEvent from "./util/FakeEvent";
-import { Backend, DatabaseConnection } from "./backend-interface";
-import queueTask from "./util/queueTask";
-
-/** @public */
-export type DatabaseList = Array<{ name: string; version: number }>;
-
-/** @public */
-export class BridgeIDBFactory {
-  public cmp = compareKeys;
-  private backend: Backend;
-  private connections: BridgeIDBDatabase[] = [];
-  static enableTracing: boolean = false;
-
-  public constructor(backend: Backend) {
-    this.backend = backend;
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
-  public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
-    const request = new BridgeIDBOpenDBRequest();
-    request.source = null;
-
-    queueTask(async () => {
-      const databases = await this.backend.getDatabases();
-      const dbInfo = databases.find((x) => x.name == name);
-      if (!dbInfo) {
-        // Database already doesn't exist, success!
-        const event = new BridgeIDBVersionChangeEvent("success", {
-          newVersion: null,
-          oldVersion: 0,
-        });
-        request.dispatchEvent(event);
-        return;
-      }
-      const oldVersion = dbInfo.version;
-
-      try {
-        const dbconn = await this.backend.connectDatabase(name);
-        const backendTransaction = await this.backend.enterVersionChange(
-          dbconn,
-          0,
-        );
-        await this.backend.deleteDatabase(backendTransaction, name);
-        await this.backend.commit(backendTransaction);
-        await this.backend.close(dbconn);
-
-        request.result = undefined;
-        request.readyState = "done";
-
-        const event2 = new BridgeIDBVersionChangeEvent("success", {
-          newVersion: null,
-          oldVersion,
-        });
-        request.dispatchEvent(event2);
-      } catch (err) {
-        request.error = new Error();
-        request.error.name = err.name;
-        request.readyState = "done";
-
-        const event = new FakeEvent("error", {
-          bubbles: true,
-          cancelable: true,
-        });
-        event.eventPath = [];
-        request.dispatchEvent(event);
-      }
-    });
-
-    return request;
-  }
-
-  // tslint:disable-next-line max-line-length
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-open-IDBOpenDBRequest-DOMString-name-unsigned-long-long-version
-  public open(name: string, version?: number) {
-    if (arguments.length > 1 && version !== undefined) {
-      // Based on spec, not sure why "MAX_SAFE_INTEGER" instead of "unsigned 
long long", but it's needed to pass
-      // tests
-      version = enforceRange(version, "MAX_SAFE_INTEGER");
-    }
-    if (version === 0) {
-      throw new TypeError();
-    }
-
-    const request = new BridgeIDBOpenDBRequest();
-
-    queueTask(async () => {
-      let dbconn: DatabaseConnection;
-      try {
-        dbconn = await this.backend.connectDatabase(name);
-      } catch (err) {
-        request._finishWithError(err);
-        return;
-      }
-
-      const schema = this.backend.getSchema(dbconn);
-      const existingVersion = schema.databaseVersion;
-
-      if (version === undefined) {
-        version = existingVersion !== 0 ? existingVersion : 1;
-      }
-
-      const requestedVersion = version;
-
-      BridgeIDBFactory.enableTracing &&
-        console.log(
-          `TRACE: existing version ${existingVersion}, requested version 
${requestedVersion}`,
-        );
-
-      if (existingVersion > requestedVersion) {
-        request._finishWithError(new VersionError());
-        return;
-      }
-
-      const db = new BridgeIDBDatabase(this.backend, dbconn);
-
-      if (existingVersion == requestedVersion) {
-        request.result = db;
-        request.readyState = "done";
-
-        const event2 = new FakeEvent("success", {
-          bubbles: false,
-          cancelable: false,
-        });
-        event2.eventPath = [request];
-        request.dispatchEvent(event2);
-      }
-
-      if (existingVersion < requestedVersion) {
-        // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
-
-        for (const otherConn of this.connections) {
-          const event = new BridgeIDBVersionChangeEvent("versionchange", {
-            newVersion: version,
-            oldVersion: existingVersion,
-          });
-          otherConn.dispatchEvent(event);
-        }
-
-        if (this._anyOpen()) {
-          const event = new BridgeIDBVersionChangeEvent("blocked", {
-            newVersion: version,
-            oldVersion: existingVersion,
-          });
-          request.dispatchEvent(event);
-        }
-
-        const backendTransaction = await this.backend.enterVersionChange(
-          dbconn,
-          requestedVersion,
-        );
-        db._runningVersionchangeTransaction = true;
-
-        const transaction = db._internalTransaction(
-          [],
-          "versionchange",
-          backendTransaction,
-        );
-        const event = new BridgeIDBVersionChangeEvent("upgradeneeded", {
-          newVersion: version,
-          oldVersion: existingVersion,
-        });
-
-        request.result = db;
-        request.readyState = "done";
-        request.transaction = transaction;
-        request.dispatchEvent(event);
-
-        await transaction._waitDone();
-
-        // We don't explicitly exit the versionchange transaction,
-        // since this is already done by the BridgeIDBTransaction.
-        db._runningVersionchangeTransaction = false;
-
-        const event2 = new FakeEvent("success", {
-          bubbles: false,
-          cancelable: false,
-        });
-        event2.eventPath = [request];
-
-        request.dispatchEvent(event2);
-      }
-
-      this.connections.push(db);
-      return db;
-    });
-
-    return request;
-  }
-
-  // https://w3c.github.io/IndexedDB/#dom-idbfactory-databases
-  public databases(): Promise<DatabaseList> {
-    return this.backend.getDatabases();
-  }
-
-  public toString(): string {
-    return "[object IDBFactory]";
-  }
-
-  private _anyOpen(): boolean {
-    return this.connections.some((c) => !c._closed && !c._closePending);
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBIndex.ts 
b/packages/idb-bridge/src/BridgeIDBIndex.ts
deleted file mode 100644
index 9b214a23..00000000
--- a/packages/idb-bridge/src/BridgeIDBIndex.ts
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- 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 { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import {
-  ConstraintError,
-  InvalidStateError,
-  TransactionInactiveError,
-} from "./util/errors";
-import { BridgeIDBCursorDirection, Key, KeyPath } from "./util/types";
-import valueToKey from "./util/valueToKey";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import {
-  Schema,
-  Backend,
-  DatabaseTransaction,
-  RecordGetRequest,
-  ResultLevel,
-} from "./backend-interface";
-
-const confirmActiveTransaction = (
-  index: BridgeIDBIndex,
-): BridgeIDBTransaction => {
-  if (index._deleted || index.objectStore._deleted) {
-    throw new InvalidStateError();
-  }
-
-  if (index.objectStore.transaction._state !== "active") {
-    throw new TransactionInactiveError();
-  }
-
-  return index.objectStore.transaction;
-};
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
-/** @public */
-export class BridgeIDBIndex {
-  objectStore: BridgeIDBObjectStore;
-
-  get _schema(): Schema {
-    return this.objectStore.transaction.db._schema;
-  }
-
-  get keyPath(): KeyPath {
-    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
-      .keyPath;
-  }
-
-  get multiEntry(): boolean {
-    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
-      .multiEntry;
-  }
-
-  get unique(): boolean {
-    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
-      .unique;
-  }
-
-  get _backend(): Backend {
-    return this.objectStore._backend;
-  }
-
-  _confirmActiveTransaction(): { btx: DatabaseTransaction } {
-    return this.objectStore._confirmActiveTransaction();
-  }
-
-  private _name: string;
-
-  public _deleted: boolean = false;
-
-  constructor(objectStore: BridgeIDBObjectStore, name: string) {
-    this._name = name;
-    this.objectStore = objectStore;
-  }
-
-  get name() {
-    return this._name;
-  }
-
-  // https://w3c.github.io/IndexedDB/#dom-idbindex-name
-  set name(name: any) {
-    const transaction = this.objectStore.transaction;
-
-    if (!transaction.db._runningVersionchangeTransaction) {
-      throw new InvalidStateError();
-    }
-
-    if (transaction._state !== "active") {
-      throw new TransactionInactiveError();
-    }
-
-    const { btx } = this._confirmActiveTransaction();
-
-    const oldName = this._name;
-    const newName = String(name);
-
-    if (newName === oldName) {
-      return;
-    }
-
-    this._backend.renameIndex(btx, this.objectStore.name, oldName, newName);
-
-    if (this.objectStore.indexNames.indexOf(name) >= 0) {
-      throw new ConstraintError();
-    }
-  }
-
-  // tslint:disable-next-line max-line-length
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openCursor-IDBRequest-any-range-IDBCursorDirection-direction
-  public openCursor(
-    range?: BridgeIDBKeyRange | Key | null | undefined,
-    direction: BridgeIDBCursorDirection = "next",
-  ) {
-    confirmActiveTransaction(this);
-
-    if (range === null) {
-      range = undefined;
-    }
-    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
-      range = BridgeIDBKeyRange.only(valueToKey(range));
-    }
-
-    const request = new BridgeIDBRequest();
-    request.source = this;
-    request.transaction = this.objectStore.transaction;
-
-    const cursor = new BridgeIDBCursorWithValue(
-      this,
-      this.objectStore.name,
-      this._name,
-      range,
-      direction,
-      request,
-    );
-
-    const operation = async () => {
-      return cursor._iterate();
-    };
-
-    return this.objectStore.transaction._execRequestAsync({
-      operation,
-      request,
-      source: this,
-    });
-  }
-
-  // tslint:disable-next-line max-line-length
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openKeyCursor-IDBRequest-any-range-IDBCursorDirection-direction
-  public openKeyCursor(
-    range?: BridgeIDBKeyRange | Key | null | undefined,
-    direction: BridgeIDBCursorDirection = "next",
-  ) {
-    confirmActiveTransaction(this);
-
-    if (range === null) {
-      range = undefined;
-    }
-    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
-      range = BridgeIDBKeyRange.only(valueToKey(range));
-    }
-
-    const request = new BridgeIDBRequest();
-    request.source = this;
-    request.transaction = this.objectStore.transaction;
-
-    const cursor = new BridgeIDBCursor(
-      this,
-      this.objectStore.name,
-      this._name,
-      range,
-      direction,
-      request,
-      true,
-    );
-
-    return this.objectStore.transaction._execRequestAsync({
-      operation: cursor._iterate.bind(cursor),
-      request,
-      source: this,
-    });
-  }
-
-  public get(key: BridgeIDBKeyRange | Key) {
-    confirmActiveTransaction(this);
-
-    if (!(key instanceof BridgeIDBKeyRange)) {
-      key = BridgeIDBKeyRange._valueToKeyRange(key);
-    }
-
-    const getReq: RecordGetRequest = {
-      direction: "next",
-      indexName: this._name,
-      limit: 1,
-      range: key,
-      objectStoreName: this.objectStore._name,
-      resultLevel: ResultLevel.Full,
-    };
-
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.getRecords(btx, getReq);
-      if (result.count == 0) {
-        return undefined;
-      }
-      const values = result.values;
-      if (!values) {
-        throw Error("invariant violated");
-      }
-      return values[0];
-    };
-
-    return this.objectStore.transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbindex-getall
-  public getAll(query?: BridgeIDBKeyRange | Key, count?: number) {
-    throw Error("not implemented");
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-getKey-IDBRequest-any-key
-  public getKey(key: BridgeIDBKeyRange | Key) {
-    confirmActiveTransaction(this);
-
-    if (!(key instanceof BridgeIDBKeyRange)) {
-      key = BridgeIDBKeyRange._valueToKeyRange(key);
-    }
-
-    const getReq: RecordGetRequest = {
-      direction: "next",
-      indexName: this._name,
-      limit: 1,
-      range: key,
-      objectStoreName: this.objectStore._name,
-      resultLevel: ResultLevel.OnlyKeys,
-    };
-
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.getRecords(btx, getReq);
-      if (result.count == 0) {
-        return undefined;
-      }
-      const primaryKeys = result.primaryKeys;
-      if (!primaryKeys) {
-        throw Error("invariant violated");
-      }
-      return primaryKeys[0];
-    };
-
-    return this.objectStore.transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
-  public getAllKeys(query?: BridgeIDBKeyRange | Key, count?: number) {
-    throw Error("not implemented");
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-count-IDBRequest-any-key
-  public count(key: BridgeIDBKeyRange | Key | null | undefined) {
-    confirmActiveTransaction(this);
-
-    if (key === null) {
-      key = undefined;
-    }
-    if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
-      key = BridgeIDBKeyRange.only(valueToKey(key));
-    }
-
-    const getReq: RecordGetRequest = {
-      direction: "next",
-      indexName: this._name,
-      limit: 1,
-      range: key,
-      objectStoreName: this.objectStore._name,
-      resultLevel: ResultLevel.OnlyCount,
-    };
-
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.getRecords(btx, getReq);
-      return result.count;
-    };
-
-    return this.objectStore.transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  public toString() {
-    return "[object IDBIndex]";
-  }
-}
-
-export default BridgeIDBIndex;
diff --git a/packages/idb-bridge/src/BridgeIDBKeyRange.ts 
b/packages/idb-bridge/src/BridgeIDBKeyRange.ts
deleted file mode 100644
index d2eaa2d1..00000000
--- a/packages/idb-bridge/src/BridgeIDBKeyRange.ts
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
-  Copyright 2019 Florian Dold
-  Copyright 2017 Jeremy Scheff
-
-  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 compareKeys from "./util/cmp";
-import { DataError } from "./util/errors";
-import { Key } from "./util/types";
-import valueToKey from "./util/valueToKey";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#range-concept
-/** @public */
-export class BridgeIDBKeyRange {
-  public static only(value: Key) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    value = valueToKey(value);
-    return new BridgeIDBKeyRange(value, value, false, false);
-  }
-
-  static lowerBound(lower: Key, open: boolean = false) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    lower = valueToKey(lower);
-    return new BridgeIDBKeyRange(lower, undefined, open, true);
-  }
-
-  static upperBound(upper: Key, open: boolean = false) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    upper = valueToKey(upper);
-    return new BridgeIDBKeyRange(undefined, upper, true, open);
-  }
-
-  static bound(
-    lower: Key,
-    upper: Key,
-    lowerOpen: boolean = false,
-    upperOpen: boolean = false,
-  ) {
-    if (arguments.length < 2) {
-      throw new TypeError();
-    }
-
-    const cmpResult = compareKeys(lower, upper);
-    if (cmpResult === 1 || (cmpResult === 0 && (lowerOpen || upperOpen))) {
-      throw new DataError();
-    }
-
-    lower = valueToKey(lower);
-    upper = valueToKey(upper);
-    return new BridgeIDBKeyRange(lower, upper, lowerOpen, upperOpen);
-  }
-
-  readonly lower: Key | undefined;
-  readonly upper: Key | undefined;
-  readonly lowerOpen: boolean;
-  readonly upperOpen: boolean;
-
-  constructor(
-    lower: Key | undefined,
-    upper: Key | undefined,
-    lowerOpen: boolean,
-    upperOpen: boolean,
-  ) {
-    this.lower = lower;
-    this.upper = upper;
-    this.lowerOpen = lowerOpen;
-    this.upperOpen = upperOpen;
-  }
-
-  // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes
-  includes(key: Key) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    key = valueToKey(key);
-
-    if (this.lower !== undefined) {
-      const cmpResult = compareKeys(this.lower, key);
-
-      if (cmpResult === 1 || (cmpResult === 0 && this.lowerOpen)) {
-        return false;
-      }
-    }
-    if (this.upper !== undefined) {
-      const cmpResult = compareKeys(this.upper, key);
-
-      if (cmpResult === -1 || (cmpResult === 0 && this.upperOpen)) {
-        return false;
-      }
-    }
-    return true;
-  }
-
-  toString() {
-    return "[object IDBKeyRange]";
-  }
-
-  static _valueToKeyRange(value: any, nullDisallowedFlag: boolean = false) {
-    if (value instanceof BridgeIDBKeyRange) {
-      return value;
-    }
-
-    if (value === null || value === undefined) {
-      if (nullDisallowedFlag) {
-        throw new DataError();
-      }
-      return new BridgeIDBKeyRange(undefined, undefined, false, false);
-    }
-
-    const key = valueToKey(value);
-
-    return BridgeIDBKeyRange.only(key);
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBObjectStore.ts 
b/packages/idb-bridge/src/BridgeIDBObjectStore.ts
deleted file mode 100644
index 6fdf3520..00000000
--- a/packages/idb-bridge/src/BridgeIDBObjectStore.ts
+++ /dev/null
@@ -1,467 +0,0 @@
-/*
- Copyright 2019 Florian Dold
- Copyright 2017 Jeremy Scheff
-
- 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 { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-
-import {
-  ConstraintError,
-  InvalidAccessError,
-  InvalidStateError,
-  ReadOnlyError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import {
-  FakeDOMStringList,
-  BridgeIDBCursorDirection,
-  Key,
-  KeyPath,
-  Value,
-} from "./util/types";
-import validateKeyPath from "./util/validateKeyPath";
-import valueToKey from "./util/valueToKey";
-import {
-  DatabaseTransaction,
-  RecordGetRequest,
-  ResultLevel,
-  StoreLevel,
-  Schema,
-  Backend,
-  DatabaseConnection,
-} from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
-/** @public */
-export class BridgeIDBObjectStore {
-  _indexesCache: Map<string, BridgeIDBIndex> = new Map();
-
-  transaction: BridgeIDBTransaction;
-
-  get autoIncrement(): boolean {
-    return this._schema.objectStores[this._name].autoIncrement;
-  }
-
-  get indexNames(): FakeDOMStringList {
-    return fakeDOMStringList(
-      Object.keys(this._schema.objectStores[this._name].indexes),
-    ).sort();
-  }
-
-  get keyPath(): KeyPath | null {
-    return this._schema.objectStores[this._name].keyPath;
-  }
-
-  _name: string;
-
-  get _schema(): Schema {
-    return this.transaction.db._schema;
-  }
-
-  _deleted: boolean = false;
-
-  constructor(transaction: BridgeIDBTransaction, name: string) {
-    this._name = name;
-    this.transaction = transaction;
-  }
-
-  get name() {
-    return this._name;
-  }
-
-  get _backend(): Backend {
-    return this.transaction.db._backend;
-  }
-
-  get _backendConnection(): DatabaseConnection {
-    return this.transaction.db._backendConnection;
-  }
-
-  _confirmActiveTransaction(): { btx: DatabaseTransaction } {
-    const btx = this.transaction._backendTransaction;
-    if (!btx) {
-      throw new InvalidStateError();
-    }
-    return { btx };
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
-  set name(newName: any) {
-    const transaction = this.transaction;
-
-    if (!transaction.db._runningVersionchangeTransaction) {
-      throw new InvalidStateError();
-    }
-
-    let { btx } = this._confirmActiveTransaction();
-
-    newName = String(newName);
-
-    const oldName = this._name;
-
-    if (newName === oldName) {
-      return;
-    }
-
-    this._backend.renameObjectStore(btx, oldName, newName);
-    this.transaction.db._schema = this._backend.getSchema(
-      this._backendConnection,
-    );
-  }
-
-  public _store(value: Value, key: Key | undefined, overwrite: boolean) {
-    if (BridgeIDBFactory.enableTracing) {
-      console.log(`TRACE: IDBObjectStore._store`);
-    }
-    if (this.transaction.mode === "readonly") {
-      throw new ReadOnlyError();
-    }
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.storeRecord(btx, {
-        objectStoreName: this._name,
-        key: key,
-        value: value,
-        storeLevel: overwrite
-          ? StoreLevel.AllowOverwrite
-          : StoreLevel.NoOverwrite,
-      });
-      return result.key;
-    };
-
-    return this.transaction._execRequestAsync({ operation, source: this });
-  }
-
-  public put(value: Value, key?: Key) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    return this._store(value, key, true);
-  }
-
-  public add(value: Value, key?: Key) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-    return this._store(value, key, false);
-  }
-
-  public delete(key: Key | BridgeIDBKeyRange) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-
-    if (this.transaction.mode === "readonly") {
-      throw new ReadOnlyError();
-    }
-
-    let keyRange: BridgeIDBKeyRange;
-
-    if (key instanceof BridgeIDBKeyRange) {
-      keyRange = key;
-    } else {
-      keyRange = BridgeIDBKeyRange.only(valueToKey(key));
-    }
-
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      return this._backend.deleteRecord(btx, this._name, keyRange);
-    };
-
-    return this.transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  public get(key?: BridgeIDBKeyRange | Key) {
-    if (BridgeIDBFactory.enableTracing) {
-      console.log(`getting from object store ${this._name} key ${key}`);
-    }
-
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-
-    let keyRange: BridgeIDBKeyRange;
-
-    if (key instanceof BridgeIDBKeyRange) {
-      keyRange = key;
-    } else {
-      try {
-        keyRange = BridgeIDBKeyRange.only(valueToKey(key));
-      } catch (e) {
-        throw Error(
-          `invalid key (type ${typeof key}) for object store ${this._name}`,
-        );
-      }
-    }
-
-    const recordRequest: RecordGetRequest = {
-      objectStoreName: this._name,
-      indexName: undefined,
-      lastIndexPosition: undefined,
-      lastObjectStorePosition: undefined,
-      direction: "next",
-      limit: 1,
-      resultLevel: ResultLevel.Full,
-      range: keyRange,
-    };
-
-    const operation = async () => {
-      if (BridgeIDBFactory.enableTracing) {
-        console.log("running get operation:", recordRequest);
-      }
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.getRecords(btx, recordRequest);
-
-      if (BridgeIDBFactory.enableTracing) {
-        console.log("get operation result count:", result.count);
-      }
-
-      if (result.count === 0) {
-        return undefined;
-      }
-      const values = result.values;
-      if (!values) {
-        throw Error("invariant violated");
-      }
-      return values[0];
-    };
-
-    return this.transaction._execRequestAsync({
-      operation,
-      source: this,
-    });
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
-  public getAll(query?: BridgeIDBKeyRange | Key, count?: number) {
-    throw Error("not implemented");
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
-  public getKey(key?: BridgeIDBKeyRange | Key) {
-    throw Error("not implemented");
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
-  public getAllKeys(query?: BridgeIDBKeyRange | Key, count?: number) {
-    throw Error("not implemented");
-  }
-
-  public clear() {
-    throw Error("not implemented");
-  }
-
-  public openCursor(
-    range?: BridgeIDBKeyRange | Key,
-    direction: BridgeIDBCursorDirection = "next",
-  ) {
-    if (range === null) {
-      range = undefined;
-    }
-    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
-      range = BridgeIDBKeyRange.only(valueToKey(range));
-    }
-
-    const request = new BridgeIDBRequest();
-    request.source = this;
-    request.transaction = this.transaction;
-
-    const cursor = new BridgeIDBCursorWithValue(
-      this,
-      this._name,
-      undefined,
-      range,
-      direction,
-      request,
-    );
-
-    return this.transaction._execRequestAsync({
-      operation: () => cursor._iterate(),
-      request,
-      source: this,
-    });
-  }
-
-  public openKeyCursor(
-    range?: BridgeIDBKeyRange | Key,
-    direction?: BridgeIDBCursorDirection,
-  ) {
-    if (range === null) {
-      range = undefined;
-    }
-    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
-      range = BridgeIDBKeyRange.only(valueToKey(range));
-    }
-
-    if (!direction) {
-      direction = "next";
-    }
-
-    const request = new BridgeIDBRequest();
-    request.source = this;
-    request.transaction = this.transaction;
-
-    const cursor = new BridgeIDBCursor(
-      this,
-      this._name,
-      undefined,
-      range,
-      direction,
-      request,
-      true,
-    );
-
-    return this.transaction._execRequestAsync({
-      operation: cursor._iterate.bind(cursor),
-      request,
-      source: this,
-    });
-  }
-
-  // tslint:disable-next-line max-line-length
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-createIndex-IDBIndex-DOMString-name-DOMString-sequence-DOMString--keyPath-IDBIndexParameters-optionalParameters
-  public createIndex(
-    indexName: string,
-    keyPath: KeyPath,
-    optionalParameters: { multiEntry?: boolean; unique?: boolean } = {},
-  ) {
-    if (arguments.length < 2) {
-      throw new TypeError();
-    }
-
-    if (!this.transaction.db._runningVersionchangeTransaction) {
-      throw new InvalidStateError();
-    }
-
-    const { btx } = this._confirmActiveTransaction();
-
-    const multiEntry =
-      optionalParameters.multiEntry !== undefined
-        ? optionalParameters.multiEntry
-        : false;
-    const unique =
-      optionalParameters.unique !== undefined
-        ? optionalParameters.unique
-        : false;
-
-    if (this.transaction.mode !== "versionchange") {
-      throw new InvalidStateError();
-    }
-
-    if (this.indexNames.indexOf(indexName) >= 0) {
-      throw new ConstraintError();
-    }
-
-    validateKeyPath(keyPath);
-
-    if (Array.isArray(keyPath) && multiEntry) {
-      throw new InvalidAccessError();
-    }
-
-    this._backend.createIndex(
-      btx,
-      indexName,
-      this._name,
-      keyPath,
-      multiEntry,
-      unique,
-    );
-
-    return new BridgeIDBIndex(this, indexName);
-  }
-
-  // https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
-  public index(name: string) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-
-    if (this.transaction._state === "finished") {
-      throw new InvalidStateError();
-    }
-
-    const index = this._indexesCache.get(name);
-    if (index !== undefined) {
-      return index;
-    }
-
-    return new BridgeIDBIndex(this, name);
-  }
-
-  public deleteIndex(indexName: string) {
-    if (arguments.length === 0) {
-      throw new TypeError();
-    }
-
-    if (this.transaction.mode !== "versionchange") {
-      throw new InvalidStateError();
-    }
-
-    if (!this.transaction.db._runningVersionchangeTransaction) {
-      throw new InvalidStateError();
-    }
-
-    const { btx } = this._confirmActiveTransaction();
-
-    const index = this._indexesCache.get(indexName);
-    if (index !== undefined) {
-      index._deleted = true;
-    }
-
-    this._backend.deleteIndex(btx, this._name, indexName);
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-count-IDBRequest-any-key
-  public count(key?: Key | BridgeIDBKeyRange) {
-    if (key === null) {
-      key = undefined;
-    }
-    if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
-      key = BridgeIDBKeyRange.only(valueToKey(key));
-    }
-
-    const recordGetRequest: RecordGetRequest = {
-      direction: "next",
-      indexName: undefined,
-      lastIndexPosition: undefined,
-      limit: -1,
-      objectStoreName: this._name,
-      lastObjectStorePosition: undefined,
-      range: key,
-      resultLevel: ResultLevel.OnlyCount,
-    };
-
-    const operation = async () => {
-      const { btx } = this._confirmActiveTransaction();
-      const result = await this._backend.getRecords(btx, recordGetRequest);
-      return result.count;
-    };
-
-    return this.transaction._execRequestAsync({ operation, source: this });
-  }
-
-  public toString() {
-    return "[object IDBObjectStore]";
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts 
b/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts
deleted file mode 100644
index 306edcb7..00000000
--- a/packages/idb-bridge/src/BridgeIDBOpenDBRequest.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
-  Copyright 2019 Florian Dold
-  Copyright 2017 Jeremy Scheff
-
-  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 { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { EventListener } from "./idbtypes";
-
-/** @public */
-export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
-  public onupgradeneeded: EventListener | null = null;
-  public onblocked: EventListener | null = null;
-
-  constructor() {
-    super();
-    // https://www.w3.org/TR/IndexedDB/#open-requests
-    this.source = null;
-  }
-
-  public toString() {
-    return "[object IDBOpenDBRequest]";
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBRequest.ts 
b/packages/idb-bridge/src/BridgeIDBRequest.ts
deleted file mode 100644
index 4800a058..00000000
--- a/packages/idb-bridge/src/BridgeIDBRequest.ts
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * Copyright 2017 Jeremy Scheff
- * Copyright 2019 Florian Dold
- *
- * 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 { BridgeIDBCursor as BridgeFIBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { InvalidStateError } from "./util/errors";
-import FakeEventTarget from "./util/FakeEventTarget";
-import FakeEvent from "./util/FakeEvent";
-import { EventListener } from "./idbtypes";
-
-/** @public */
-export class BridgeIDBRequest extends FakeEventTarget {
-  _result: any = null;
-  _error: Error | null | undefined = null;
-  source: BridgeFIBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null = 
null;
-  transaction: BridgeIDBTransaction | null = null;
-  readyState: "done" | "pending" = "pending";
-  onsuccess: EventListener | null = null;
-  onerror: EventListener | null = null;
-
-  get error() {
-    if (this.readyState === "pending") {
-      throw new InvalidStateError();
-    }
-    return this._error;
-  }
-
-  set error(value: any) {
-    this._error = value;
-  }
-
-  get result() {
-    if (this.readyState === "pending") {
-      throw new InvalidStateError();
-    }
-    return this._result;
-  }
-
-  set result(value: any) {
-    this._result = value;
-  }
-
-  toString() {
-    return "[object IDBRequest]";
-  }
-
-  _finishWithError(err: Error) {
-    this.result = undefined;
-    this.readyState = "done";
-
-    this.error = new Error(err.message);
-    this.error.name = err.name;
-
-    const event = new FakeEvent("error", {
-      bubbles: true,
-      cancelable: true,
-    });
-    event.eventPath = [];
-    this.dispatchEvent(event);
-  }
-
-  _finishWithResult(result: any) {
-    this.result = result;
-    this.readyState = "done";
-
-    const event = new FakeEvent("success");
-    event.eventPath = [];
-    this.dispatchEvent(event);
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBTransaction.ts 
b/packages/idb-bridge/src/BridgeIDBTransaction.ts
deleted file mode 100644
index b064d069..00000000
--- a/packages/idb-bridge/src/BridgeIDBTransaction.ts
+++ /dev/null
@@ -1,326 +0,0 @@
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import {
-  AbortError,
-  InvalidStateError,
-  NotFoundError,
-  TransactionInactiveError,
-} from "./util/errors";
-import fakeDOMStringList from "./util/fakeDOMStringList";
-import FakeEvent from "./util/FakeEvent";
-import FakeEventTarget from "./util/FakeEventTarget";
-import { FakeDOMStringList, RequestObj, TransactionMode } from "./util/types";
-import queueTask from "./util/queueTask";
-import openPromise from "./util/openPromise";
-import { DatabaseTransaction, Backend } from "./backend-interface";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-import { EventListener } from "./idbtypes";
-
-// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
-/** @public */
-export class BridgeIDBTransaction extends FakeEventTarget {
-  public _state: "active" | "inactive" | "committing" | "finished" = "active";
-  public _started = false;
-  public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
-
-  public _backendTransaction?: DatabaseTransaction;
-
-  public objectStoreNames: FakeDOMStringList;
-  public mode: TransactionMode;
-  public db: BridgeIDBDatabase;
-  public error: Error | null = null;
-  public onabort: EventListener | null = null;
-  public oncomplete: EventListener | null = null;
-  public onerror: EventListener | null = null;
-
-  private _waitPromise: Promise<void>;
-  private _resolveWait: () => void;
-
-  public _scope: Set<string>;
-  private _requests: Array<{
-    operation: () => void;
-    request: BridgeIDBRequest;
-  }> = [];
-
-  get _backend(): Backend {
-    return this.db._backend;
-  }
-
-  constructor(
-    storeNames: string[],
-    mode: TransactionMode,
-    db: BridgeIDBDatabase,
-    backendTransaction?: DatabaseTransaction,
-  ) {
-    super();
-
-    const myOpenPromise = openPromise<void>();
-    this._waitPromise = myOpenPromise.promise;
-    this._resolveWait = myOpenPromise.resolve;
-
-    this._scope = new Set(storeNames);
-    this._backendTransaction = backendTransaction;
-    this.mode = mode;
-    this.db = db;
-    this.objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
-
-    this.db._transactions.push(this);
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
-  async _abort(errName: string | null) {
-    this._state = "finished";
-
-    if (errName !== null) {
-      const e = new Error();
-      e.name = errName;
-      this.error = e;
-    }
-
-    // Should this directly remove from _requests?
-    for (const { request } of this._requests) {
-      if (request.readyState !== "done") {
-        request.readyState = "done"; // This will cancel execution of this 
request's operation
-        if (request.source) {
-          request.result = undefined;
-          request.error = new AbortError();
-
-          const event = new FakeEvent("error", {
-            bubbles: true,
-            cancelable: true,
-          });
-          event.eventPath = [this.db, this];
-          request.dispatchEvent(event);
-        }
-      }
-    }
-
-    // Only roll back if we actually executed the scheduled operations.
-    const maybeBtx = this._backendTransaction;
-    if (maybeBtx) {
-      await this._backend.rollback(maybeBtx);
-    }
-
-    queueTask(() => {
-      const event = new FakeEvent("abort", {
-        bubbles: true,
-        cancelable: false,
-      });
-      event.eventPath = [this.db];
-      this.dispatchEvent(event);
-    });
-  }
-
-  public abort() {
-    if (this._state === "committing" || this._state === "finished") {
-      throw new InvalidStateError();
-    }
-    this._state = "active";
-
-    this._abort(null);
-  }
-
-  // http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
-  public objectStore(name: string) {
-    if (this._state !== "active") {
-      throw new InvalidStateError();
-    }
-
-    const objectStore = this._objectStoresCache.get(name);
-    if (objectStore !== undefined) {
-      return objectStore;
-    }
-
-    return new BridgeIDBObjectStore(this, name);
-  }
-
-  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-asynchronously-executing-a-request
-  public _execRequestAsync(obj: RequestObj) {
-    const source = obj.source;
-    const operation = obj.operation;
-    let request = obj.hasOwnProperty("request") ? obj.request : null;
-
-    if (this._state !== "active") {
-      throw new TransactionInactiveError();
-    }
-
-    // Request should only be passed for cursors
-    if (!request) {
-      if (!source) {
-        // Special requests like indexes that just need to run some code
-        request = new BridgeIDBRequest();
-      } else {
-        request = new BridgeIDBRequest();
-        request.source = source;
-        request.transaction = (source as any).transaction;
-      }
-    }
-
-    this._requests.push({
-      operation,
-      request,
-    });
-
-    return request;
-  }
-
-  /**
-   * Actually execute the scheduled work for this transaction.
-   */
-  public async _start() {
-    if (BridgeIDBFactory.enableTracing) {
-      console.log(
-        `TRACE: IDBTransaction._start, ${this._requests.length} queued`,
-      );
-    }
-    this._started = true;
-
-    if (!this._backendTransaction) {
-      this._backendTransaction = await this._backend.beginTransaction(
-        this.db._backendConnection,
-        Array.from(this._scope),
-        this.mode,
-      );
-    }
-
-    // Remove from request queue - cursor ones will be added back if necessary 
by cursor.continue and such
-    let operation;
-    let request;
-    while (this._requests.length > 0) {
-      const r = this._requests.shift();
-
-      // This should only be false if transaction was aborted
-      if (r && r.request.readyState !== "done") {
-        request = r.request;
-        operation = r.operation;
-        break;
-      }
-    }
-
-    if (request && operation) {
-      if (!request.source) {
-        // Special requests like indexes that just need to run some code, with 
error handling already built into
-        // operation
-        await operation();
-      } else {
-        let event;
-        try {
-          BridgeIDBFactory.enableTracing &&
-            console.log("TRACE: running operation in transaction");
-          const result = await operation();
-          BridgeIDBFactory.enableTracing &&
-            console.log(
-              "TRACE: operation in transaction finished with success",
-            );
-          request.readyState = "done";
-          request.result = result;
-          request.error = undefined;
-
-          // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-a-success-event
-          if (this._state === "inactive") {
-            this._state = "active";
-          }
-          event = new FakeEvent("success", {
-            bubbles: false,
-            cancelable: false,
-          });
-
-          try {
-            event.eventPath = [request, this, this.db];
-            request.dispatchEvent(event);
-          } catch (err) {
-            if (this._state !== "committing") {
-              this._abort("AbortError");
-            }
-            throw err;
-          }
-        } catch (err) {
-          if (BridgeIDBFactory.enableTracing) {
-            console.log("TRACING: error during operation: ", err);
-          }
-          request.readyState = "done";
-          request.result = undefined;
-          request.error = err;
-
-          // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
-          if (this._state === "inactive") {
-            this._state = "active";
-          }
-          event = new FakeEvent("error", {
-            bubbles: true,
-            cancelable: true,
-          });
-
-          try {
-            event.eventPath = [this.db, this];
-            request.dispatchEvent(event);
-          } catch (err) {
-            if (this._state !== "committing") {
-              this._abort("AbortError");
-            }
-            throw err;
-          }
-          if (!event.canceled) {
-            this._abort(err.name);
-          }
-        }
-      }
-
-      // On to the next one
-      if (this._requests.length > 0) {
-        this._start();
-      } else {
-        // Give it another chance for new handlers to be set before finishing
-        queueTask(() => this._start());
-      }
-      return;
-    }
-
-    if (this._state !== "finished" && this._state !== "committing") {
-      if (BridgeIDBFactory.enableTracing) {
-        console.log("finishing transaction");
-      }
-
-      this._state = "committing";
-
-      await this._backend.commit(this._backendTransaction);
-
-      this._state = "finished";
-
-      if (!this.error) {
-        if (BridgeIDBFactory.enableTracing) {
-          console.log("dispatching 'complete' event on transaction");
-        }
-        const event = new FakeEvent("complete");
-        event.eventPath = [this, this.db];
-        this.dispatchEvent(event);
-      }
-
-      const idx = this.db._transactions.indexOf(this);
-      if (idx < 0) {
-        throw Error("invariant failed");
-      }
-      this.db._transactions.splice(idx, 1);
-
-      this._resolveWait();
-    }
-  }
-
-  public commit() {
-    if (this._state !== "active") {
-      throw new InvalidStateError();
-    }
-
-    this._state = "committing";
-    // We now just wait for auto-commit ...
-  }
-
-  public toString() {
-    return "[object IDBRequest]";
-  }
-
-  _waitDone(): Promise<void> {
-    return this._waitPromise;
-  }
-}
diff --git a/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts 
b/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts
deleted file mode 100644
index 43e822d8..00000000
--- a/packages/idb-bridge/src/BridgeIDBVersionChangeEvent.ts
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
-  Copyright 2019 Florian Dold
-  Copyright 2017 Jeremy Scheff
-
-  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 FakeEvent from "./util/FakeEvent";
-
-export class BridgeIDBVersionChangeEvent extends FakeEvent {
-  public newVersion: number | null;
-  public oldVersion: number;
-
-  constructor(
-    type: "blocked" | "success" | "upgradeneeded" | "versionchange",
-    parameters: { newVersion?: number | null; oldVersion?: number } = {},
-  ) {
-    super(type);
-
-    this.newVersion =
-      parameters.newVersion !== undefined ? parameters.newVersion : null;
-    this.oldVersion =
-      parameters.oldVersion !== undefined ? parameters.oldVersion : 0;
-  }
-
-  public toString() {
-    return "[object IDBVersionChangeEvent]";
-  }
-}
diff --git a/packages/idb-bridge/src/MemoryBackend.test.ts 
b/packages/idb-bridge/src/MemoryBackend.test.ts
index 737b83d9..281a72e3 100644
--- a/packages/idb-bridge/src/MemoryBackend.test.ts
+++ b/packages/idb-bridge/src/MemoryBackend.test.ts
@@ -15,13 +15,15 @@
  */
 
 import test from "ava";
+import {
+  BridgeIDBCursorWithValue,
+  BridgeIDBDatabase,
+  BridgeIDBFactory,
+  BridgeIDBKeyRange,
+  BridgeIDBRequest,
+  BridgeIDBTransaction,
+} from "./bridge-idb";
 import MemoryBackend from "./MemoryBackend";
-import { BridgeIDBFactory } from "./BridgeIDBFactory";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBCursorWithValue } from "./BridgeIDBCursorWithValue";
 
 function promiseFromRequest(request: BridgeIDBRequest): Promise<any> {
   return new Promise((resolve, reject) => {
diff --git a/packages/idb-bridge/src/MemoryBackend.ts 
b/packages/idb-bridge/src/MemoryBackend.ts
index 531a7f29..6a52a555 100644
--- a/packages/idb-bridge/src/MemoryBackend.ts
+++ b/packages/idb-bridge/src/MemoryBackend.ts
@@ -36,11 +36,14 @@ import {
 } from "./util/errors";
 import BTree, { ISortedMapF } from "./tree/b+tree";
 import compareKeys from "./util/cmp";
-import { Key, Value, KeyPath, TransactionMode } from "./util/types";
 import { StoreKeyResult, makeStoreKeyValue } from "./util/makeStoreKeyValue";
 import getIndexKeys from "./util/getIndexKeys";
 import openPromise from "./util/openPromise";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
+import { IDBKeyPath, IDBKeyRange, IDBTransactionMode, IDBValidKey } from 
"./idbtypes";
+import { BridgeIDBKeyRange } from "./bridge-idb";
+
+type Key = IDBValidKey;
+type Value = unknown;
 
 enum TransactionLevel {
   Disconnected = 0,
@@ -476,7 +479,7 @@ export class MemoryBackend implements Backend {
   async beginTransaction(
     conn: DatabaseConnection,
     objectStores: string[],
-    mode: TransactionMode,
+    mode: IDBTransactionMode,
   ): Promise<DatabaseTransaction> {
     if (this.enableTracing) {
       console.log(`TRACING: beginTransaction`);
@@ -773,6 +776,9 @@ export class MemoryBackend implements Backend {
     if (!schema) {
       throw Error("no schema for versionchange tx");
     }
+    if (Array.isArray(keyPath)) {
+      throw Error("array key path not supported for object stores");
+    }
     schema.objectStores[name] = {
       autoIncrement,
       keyPath,
@@ -785,7 +791,7 @@ export class MemoryBackend implements Backend {
     btx: DatabaseTransaction,
     indexName: string,
     objectStoreName: string,
-    keyPath: KeyPath,
+    keyPath: IDBKeyPath,
     multiEntry: boolean,
     unique: boolean,
   ): void {
@@ -843,7 +849,7 @@ export class MemoryBackend implements Backend {
   async deleteRecord(
     btx: DatabaseTransaction,
     objectStoreName: string,
-    range: BridgeIDBKeyRange,
+    range: IDBKeyRange,
   ): Promise<void> {
     if (this.enableTracing) {
       console.log(`TRACING: deleteRecord from store ${objectStoreName}`);
@@ -900,6 +906,10 @@ export class MemoryBackend implements Backend {
       }
     }
 
+    if (currKey === undefined) {
+      throw Error("invariant violated");
+    }
+
     // make sure that currKey is either undefined or pointing to an
     // existing object.
     let firstValue = modifiedData.get(currKey);
@@ -1112,6 +1122,10 @@ export class MemoryBackend implements Backend {
         indexPos = forward ? indexData.minKey() : indexData.maxKey();
       }
 
+      if (indexPos === undefined) {
+        throw Error("invariant violated");
+      }
+
       let indexEntry: IndexRecord | undefined;
       indexEntry = indexData.get(indexPos);
       if (!indexEntry) {
@@ -1191,13 +1205,13 @@ export class MemoryBackend implements Backend {
           primkeySubPos < 0 ||
           primkeySubPos >= indexEntry.primaryKeys.length
         ) {
-          const res = forward
+          const res: any = forward
             ? indexData.nextHigherPair(indexPos)
             : indexData.nextLowerPair(indexPos);
           if (res) {
             indexPos = res[1].indexKey;
             indexEntry = res[1];
-            primkeySubPos = forward ? 0 : indexEntry.primaryKeys.length - 1;
+            primkeySubPos = forward ? 0 : indexEntry!.primaryKeys.length - 1;
             continue;
           } else {
             break;
diff --git a/packages/idb-bridge/src/backend-interface.ts 
b/packages/idb-bridge/src/backend-interface.ts
index 4d1f107b..756a5b96 100644
--- a/packages/idb-bridge/src/backend-interface.ts
+++ b/packages/idb-bridge/src/backend-interface.ts
@@ -14,26 +14,25 @@
  permissions and limitations under the License.
  */
 
+import { BridgeIDBDatabaseInfo, BridgeIDBKeyRange } from "./bridge-idb";
 import {
-  TransactionMode,
-  Value,
-  BridgeIDBCursorDirection,
-  Key,
-  KeyPath,
-  BridgeIDBDatabaseInfo,
-} from "./util/types";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
+  IDBCursorDirection,
+  IDBKeyPath,
+  IDBTransactionMode,
+  IDBValidKey,
+} from "./idbtypes";
+
 
 /** @public */
 export interface ObjectStoreProperties {
-  keyPath: KeyPath | null;
+  keyPath: IDBKeyPath | null;
   autoIncrement: boolean;
   indexes: { [nameame: string]: IndexProperties };
 }
 
 /** @public */
 export interface IndexProperties {
-  keyPath: KeyPath;
+  keyPath: IDBKeyPath;
   multiEntry: boolean;
   unique: boolean;
 }
@@ -71,7 +70,7 @@ export enum StoreLevel {
 
 /** @public */
 export interface RecordGetRequest {
-  direction: BridgeIDBCursorDirection;
+  direction: IDBCursorDirection;
   objectStoreName: string;
   indexName: string | undefined;
   /**
@@ -79,7 +78,7 @@ export interface RecordGetRequest {
    * If indexName is defined, the range refers to the index keys.
    * Otherwise it refers to the object store keys.
    */
-  range: BridgeIDBKeyRange | undefined;
+  range: BridgeIDBKeyRange | undefined | null;
   /**
    * Last cursor position in terms of the index key.
    * Can only be specified if indexName is defined and
@@ -87,23 +86,23 @@ export interface RecordGetRequest {
    *
    * Must either be undefined or within range.
    */
-  lastIndexPosition?: Key;
+  lastIndexPosition?: IDBValidKey;
   /**
    * Last position in terms of the object store key.
    */
-  lastObjectStorePosition?: Key;
+  lastObjectStorePosition?: IDBValidKey;
   /**
    * If specified, the index key of the results must be
    * greater or equal to advanceIndexKey.
    *
    * Only applicable if indexName is specified.
    */
-  advanceIndexKey?: Key;
+  advanceIndexKey?: IDBValidKey;
   /**
    * If specified, the primary key of the results must be greater
    * or equal to advancePrimaryKey.
    */
-  advancePrimaryKey?: Key;
+  advancePrimaryKey?: IDBValidKey;
   /**
    * Maximum number of resuts to return.
    * If -1, return all available results
@@ -114,17 +113,17 @@ export interface RecordGetRequest {
 
 /** @public */
 export interface RecordGetResponse {
-  values: Value[] | undefined;
-  indexKeys: Key[] | undefined;
-  primaryKeys: Key[] | undefined;
+  values: any[] | undefined;
+  indexKeys: IDBValidKey[] | undefined;
+  primaryKeys: IDBValidKey[] | undefined;
   count: number;
 }
 
 /** @public */
 export interface RecordStoreRequest {
   objectStoreName: string;
-  value: Value;
-  key: Key | undefined;
+  value: any;
+  key: IDBValidKey | undefined;
   storeLevel: StoreLevel;
 }
 
@@ -133,7 +132,7 @@ export interface RecordStoreResponse {
   /**
    * Key that the record was stored under in the object store.
    */
-  key: Key;
+  key: IDBValidKey;
 }
 
 /** @public */
@@ -145,7 +144,7 @@ export interface Backend {
   beginTransaction(
     conn: DatabaseConnection,
     objectStores: string[],
-    mode: TransactionMode,
+    mode: IDBTransactionMode,
   ): Promise<DatabaseTransaction>;
 
   enterVersionChange(
@@ -200,7 +199,7 @@ export interface Backend {
     btx: DatabaseTransaction,
     indexName: string,
     objectStoreName: string,
-    keyPath: KeyPath,
+    keyPath: IDBKeyPath,
     multiEntry: boolean,
     unique: boolean,
   ): void;
diff --git a/packages/idb-bridge/src/bridge-idb.ts 
b/packages/idb-bridge/src/bridge-idb.ts
new file mode 100644
index 00000000..2bced800
--- /dev/null
+++ b/packages/idb-bridge/src/bridge-idb.ts
@@ -0,0 +1,2053 @@
+/*
+ Copyright 2017 Jeremy Scheff
+ Copyright 2019-2021 Taler Systems S.A.
+
+ 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 {
+  Backend,
+  DatabaseConnection,
+  DatabaseTransaction,
+  RecordGetRequest,
+  RecordStoreRequest,
+  ResultLevel,
+  Schema,
+  StoreLevel,
+} from "./backend-interface";
+import { EventListener, IDBCursorDirection, IDBKeyPath, IDBKeyRange, 
IDBTransactionMode, IDBValidKey } from "./idbtypes";
+import compareKeys from "./util/cmp";
+import enforceRange from "./util/enforceRange";
+import {
+  AbortError,
+  ConstraintError,
+  DataError,
+  InvalidAccessError,
+  InvalidStateError,
+  NotFoundError,
+  ReadOnlyError,
+  TransactionInactiveError,
+  VersionError,
+} from "./util/errors";
+import { fakeDOMStringList } from "./util/fakeDOMStringList";
+import FakeEvent from "./util/FakeEvent";
+import FakeEventTarget from "./util/FakeEventTarget";
+import openPromise from "./util/openPromise";
+import queueTask from "./util/queueTask";
+import structuredClone from "./util/structuredClone";
+import validateKeyPath from "./util/validateKeyPath";
+import valueToKey from "./util/valueToKey";
+
+/** @public */
+export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore;
+
+/** @public */
+export interface FakeDOMStringList extends Array<string> {
+  contains: (value: string) => boolean;
+  item: (i: number) => string | undefined;
+}
+
+/** @public */
+export interface RequestObj {
+  operation: () => Promise<any>;
+  request?: BridgeIDBRequest | undefined;
+  source?: any;
+}
+
+/** @public */
+export interface BridgeIDBDatabaseInfo {
+  name: string;
+  version: number;
+}
+
+function simplifyRange(
+  r: IDBValidKey | IDBKeyRange | undefined | null,
+): IDBKeyRange | null {
+  if (r && typeof r === "object" && "lower" in r) {
+    return r;
+  }
+  if (r === undefined || r === null) {
+    return null;
+  }
+  return BridgeIDBKeyRange.bound(r, r, false, false);
+}
+
+/**
+ * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
+ *
+ * @public
+ */
+export class BridgeIDBCursor {
+  _request: BridgeIDBRequest | undefined;
+
+  private _gotValue: boolean = false;
+  private _range: IDBValidKey | IDBKeyRange | undefined | null;
+  private _indexPosition = undefined; // Key of previously returned record
+  private _objectStorePosition = undefined;
+  private _keyOnly: boolean;
+
+  private _source: CursorSource;
+  private _direction: IDBCursorDirection;
+  private _key: IDBValidKey | undefined = undefined;
+  private _primaryKey: IDBValidKey | undefined = undefined;
+  private _indexName: string | undefined;
+  private _objectStoreName: string;
+
+  protected _value: any = undefined;
+
+  constructor(
+    source: CursorSource,
+    objectStoreName: string,
+    indexName: string | undefined,
+    range: IDBValidKey | IDBKeyRange | null | undefined,
+    direction: IDBCursorDirection,
+    request: BridgeIDBRequest,
+    keyOnly: boolean,
+  ) {
+    this._indexName = indexName;
+    this._objectStoreName = objectStoreName;
+    this._range = range;
+    this._source = source;
+    this._direction = direction;
+    this._request = request;
+    this._keyOnly = keyOnly;
+  }
+
+  get _effectiveObjectStore(): BridgeIDBObjectStore {
+    if (this.source instanceof BridgeIDBObjectStore) {
+      return this.source;
+    }
+    return this.source.objectStore;
+  }
+
+  get _backend(): Backend {
+    return this._source._backend;
+  }
+
+  // Read only properties
+  get source() {
+    return this._source;
+  }
+  set source(val) {
+    /* For babel */
+  }
+
+  get direction() {
+    return this._direction;
+  }
+  set direction(val) {
+    /* For babel */
+  }
+
+  get key() {
+    return this._key;
+  }
+  set key(val) {
+    /* For babel */
+  }
+
+  get primaryKey() {
+    return this._primaryKey;
+  }
+
+  set primaryKey(val) {
+    /* For babel */
+  }
+
+  protected get _isValueCursor(): boolean {
+    return false;
+  }
+
+  /**
+   * https://w3c.github.io/IndexedDB/#iterate-a-cursor
+   */
+  async _iterate(key?: IDBValidKey, primaryKey?: IDBValidKey): Promise<any> {
+    BridgeIDBFactory.enableTracing &&
+      console.log(
+        `iterating cursor os=${this._objectStoreName},idx=${this._indexName}`,
+      );
+    BridgeIDBFactory.enableTracing &&
+      console.log("cursor type ", this.toString());
+    const recordGetRequest: RecordGetRequest = {
+      direction: this.direction,
+      indexName: this._indexName,
+      lastIndexPosition: this._indexPosition,
+      lastObjectStorePosition: this._objectStorePosition,
+      limit: 1,
+      range: simplifyRange(this._range),
+      objectStoreName: this._objectStoreName,
+      advanceIndexKey: key,
+      advancePrimaryKey: primaryKey,
+      resultLevel: this._keyOnly ? ResultLevel.OnlyKeys : ResultLevel.Full,
+    };
+
+    const { btx } = this.source._confirmActiveTransaction();
+
+    let response = await this._backend.getRecords(btx, recordGetRequest);
+
+    if (response.count === 0) {
+      if (BridgeIDBFactory.enableTracing) {
+        console.log("cursor is returning empty result");
+      }
+      this._gotValue = false;
+      return null;
+    }
+
+    if (response.count !== 1) {
+      throw Error("invariant failed");
+    }
+
+    if (BridgeIDBFactory.enableTracing) {
+      console.log("request is:", JSON.stringify(recordGetRequest));
+      console.log("get response is:", JSON.stringify(response));
+    }
+
+    if (this._indexName !== undefined) {
+      this._key = response.indexKeys![0];
+    } else {
+      this._key = response.primaryKeys![0];
+    }
+
+    this._primaryKey = response.primaryKeys![0];
+
+    if (!this._keyOnly) {
+      this._value = response.values![0];
+    }
+
+    this._gotValue = true;
+    this._objectStorePosition = structuredClone(response.primaryKeys![0]);
+    if (response.indexKeys !== undefined && response.indexKeys.length > 0) {
+      this._indexPosition = structuredClone(response.indexKeys[0]);
+    }
+
+    return this;
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
+  public update(value: any) {
+    if (value === undefined) {
+      throw new TypeError();
+    }
+
+    const transaction = this._effectiveObjectStore.transaction;
+
+    if (transaction._state !== "active") {
+      throw new TransactionInactiveError();
+    }
+
+    if (transaction.mode === "readonly") {
+      throw new ReadOnlyError();
+    }
+
+    if (this._effectiveObjectStore._deleted) {
+      throw new InvalidStateError();
+    }
+
+    if (
+      !(this.source instanceof BridgeIDBObjectStore) &&
+      this.source._deleted
+    ) {
+      throw new InvalidStateError();
+    }
+
+    if (!this._gotValue || !this._isValueCursor) {
+      throw new InvalidStateError();
+    }
+
+    const storeReq: RecordStoreRequest = {
+      key: this._primaryKey,
+      value: value,
+      objectStoreName: this._objectStoreName,
+      storeLevel: StoreLevel.UpdateExisting,
+    };
+
+    const operation = async () => {
+      if (BridgeIDBFactory.enableTracing) {
+        console.log("updating at cursor");
+      }
+      const { btx } = this.source._confirmActiveTransaction();
+      await this._backend.storeRecord(btx, storeReq);
+    };
+    return transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  /**
+   * 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
+   */
+  public advance(count: number) {
+    throw Error("not implemented");
+  }
+
+  /**
+   * 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
+   */
+  public continue(key?: IDBValidKey) {
+    const transaction = this._effectiveObjectStore.transaction;
+
+    if (transaction._state !== "active") {
+      throw new TransactionInactiveError();
+    }
+
+    if (this._effectiveObjectStore._deleted) {
+      throw new InvalidStateError();
+    }
+    if (
+      !(this.source instanceof BridgeIDBObjectStore) &&
+      this.source._deleted
+    ) {
+      throw new InvalidStateError();
+    }
+
+    if (!this._gotValue) {
+      throw new InvalidStateError();
+    }
+
+    if (key !== undefined) {
+      key = valueToKey(key);
+      let lastKey =
+        this._indexName === undefined
+          ? this._objectStorePosition
+          : this._indexPosition;
+
+      const cmpResult = compareKeys(key, lastKey);
+
+      if (
+        (cmpResult <= 0 &&
+          (this.direction === "next" || this.direction === "nextunique")) ||
+        (cmpResult >= 0 &&
+          (this.direction === "prev" || this.direction === "prevunique"))
+      ) {
+        throw new DataError();
+      }
+    }
+
+    if (this._request) {
+      this._request.readyState = "pending";
+    }
+
+    const operation = async () => {
+      return this._iterate(key);
+    };
+
+    transaction._execRequestAsync({
+      operation,
+      request: this._request,
+      source: this.source,
+    });
+
+    this._gotValue = false;
+  }
+
+  // https://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
+  public continuePrimaryKey(key: IDBValidKey, primaryKey: IDBValidKey) {
+    throw Error("not implemented");
+  }
+
+  public delete() {
+    const transaction = this._effectiveObjectStore.transaction;
+
+    if (transaction._state !== "active") {
+      throw new TransactionInactiveError();
+    }
+
+    if (transaction.mode === "readonly") {
+      throw new ReadOnlyError();
+    }
+
+    if (this._effectiveObjectStore._deleted) {
+      throw new InvalidStateError();
+    }
+    if (
+      !(this.source instanceof BridgeIDBObjectStore) &&
+      this.source._deleted
+    ) {
+      throw new InvalidStateError();
+    }
+
+    if (!this._gotValue || !this._isValueCursor) {
+      throw new InvalidStateError();
+    }
+
+    const operation = async () => {
+      const { btx } = this.source._confirmActiveTransaction();
+      this._backend.deleteRecord(
+        btx,
+        this._objectStoreName,
+        BridgeIDBKeyRange._valueToKeyRange(this._primaryKey),
+      );
+    };
+
+    return transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  public toString() {
+    return "[object IDBCursor]";
+  }
+}
+
+export class BridgeIDBCursorWithValue extends BridgeIDBCursor {
+  get value(): any {
+    return this._value;
+  }
+
+  protected get _isValueCursor(): boolean {
+    return true;
+  }
+
+  constructor(
+    source: CursorSource,
+    objectStoreName: string,
+    indexName: string | undefined,
+    range: IDBValidKey | IDBKeyRange | undefined | null,
+    direction: IDBCursorDirection,
+    request?: any,
+  ) {
+    super(source, objectStoreName, indexName, range, direction, request, 
false);
+  }
+
+  public toString() {
+    return "[object IDBCursorWithValue]";
+  }
+}
+
+/**
+ * Ensure that an active version change transaction is currently running.
+ */
+const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => 
{
+  if (!database._runningVersionchangeTransaction) {
+    throw new InvalidStateError();
+  }
+
+  // Find the latest versionchange transaction
+  const transactions = database._transactions.filter(
+    (tx: BridgeIDBTransaction) => {
+      return tx.mode === "versionchange";
+    },
+  );
+  const transaction = transactions[transactions.length - 1];
+
+  if (!transaction || transaction._state === "finished") {
+    throw new InvalidStateError();
+  }
+
+  if (transaction._state !== "active") {
+    throw new TransactionInactiveError();
+  }
+
+  return transaction;
+};
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
+/** @public */
+export class BridgeIDBDatabase extends FakeEventTarget {
+  _closePending = false;
+  _closed = false;
+  _runningVersionchangeTransaction = false;
+  _transactions: Array<BridgeIDBTransaction> = [];
+
+  _backendConnection: DatabaseConnection;
+  _backend: Backend;
+
+  _schema: Schema;
+
+  get name(): string {
+    return this._schema.databaseName;
+  }
+
+  get version(): number {
+    return this._schema.databaseVersion;
+  }
+
+  get objectStoreNames(): FakeDOMStringList {
+    return fakeDOMStringList(Object.keys(this._schema.objectStores)).sort();
+  }
+
+  /**
+   * http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
+   */
+  _closeConnection() {
+    this._closePending = true;
+
+    const transactionsComplete = this._transactions.every(
+      (transaction: BridgeIDBTransaction) => {
+        return transaction._state === "finished";
+      },
+    );
+
+    if (transactionsComplete) {
+      this._closed = true;
+      this._backend.close(this._backendConnection);
+    } else {
+      queueTask(() => {
+        this._closeConnection();
+      });
+    }
+  }
+
+  constructor(backend: Backend, backendConnection: DatabaseConnection) {
+    super();
+
+    this._schema = backend.getSchema(backendConnection);
+
+    this._backend = backend;
+    this._backendConnection = backendConnection;
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
+  public createObjectStore(
+    name: string,
+    options: { autoIncrement?: boolean; keyPath?: IDBKeyPath } | null = {},
+  ): BridgeIDBObjectStore {
+    if (name === undefined) {
+      throw new TypeError();
+    }
+    const transaction = confirmActiveVersionchangeTransaction(this);
+    const backendTx = transaction._backendTransaction;
+    if (!backendTx) {
+      throw Error("invariant violated");
+    }
+
+    const keyPath =
+      options !== null && options.keyPath !== undefined
+        ? options.keyPath
+        : null;
+    const autoIncrement =
+      options !== null && options.autoIncrement !== undefined
+        ? options.autoIncrement
+        : false;
+
+    if (keyPath !== null) {
+      validateKeyPath(keyPath);
+    }
+
+    if (Object.keys(this._schema.objectStores).includes(name)) {
+      throw new ConstraintError();
+    }
+
+    if (autoIncrement && (keyPath === "" || Array.isArray(keyPath))) {
+      throw new InvalidAccessError();
+    }
+
+    transaction._backend.createObjectStore(
+      backendTx,
+      name,
+      keyPath,
+      autoIncrement,
+    );
+
+    this._schema = this._backend.getSchema(this._backendConnection);
+
+    return transaction.objectStore(name);
+  }
+
+  public deleteObjectStore(name: string): void {
+    if (name === undefined) {
+      throw new TypeError();
+    }
+    const transaction = confirmActiveVersionchangeTransaction(this);
+    transaction._objectStoresCache.delete(name);
+  }
+
+  public _internalTransaction(
+    storeNames: string | string[],
+    mode?: IDBTransactionMode,
+    backendTransaction?: DatabaseTransaction,
+  ): BridgeIDBTransaction {
+    mode = mode !== undefined ? mode : "readonly";
+    if (
+      mode !== "readonly" &&
+      mode !== "readwrite" &&
+      mode !== "versionchange"
+    ) {
+      throw new TypeError("Invalid mode: " + mode);
+    }
+
+    const hasActiveVersionchange = this._transactions.some(
+      (transaction: BridgeIDBTransaction) => {
+        return (
+          transaction._state === "active" &&
+          transaction.mode === "versionchange" &&
+          transaction.db === this
+        );
+      },
+    );
+    if (hasActiveVersionchange) {
+      throw new InvalidStateError();
+    }
+
+    if (this._closePending) {
+      throw new InvalidStateError();
+    }
+
+    if (!Array.isArray(storeNames)) {
+      storeNames = [storeNames];
+    }
+    if (storeNames.length === 0 && mode !== "versionchange") {
+      throw new InvalidAccessError();
+    }
+    for (const storeName of storeNames) {
+      if (this.objectStoreNames.indexOf(storeName) < 0) {
+        throw new NotFoundError(
+          "No objectStore named " + storeName + " in this database",
+        );
+      }
+    }
+
+    const tx = new BridgeIDBTransaction(
+      storeNames,
+      mode,
+      this,
+      backendTransaction,
+    );
+    this._transactions.push(tx);
+    queueTask(() => tx._start());
+    return tx;
+  }
+
+  public transaction(
+    storeNames: string | string[],
+    mode?: IDBTransactionMode,
+  ): BridgeIDBTransaction {
+    if (mode === "versionchange") {
+      throw new TypeError("Invalid mode: " + mode);
+    }
+    return this._internalTransaction(storeNames, mode);
+  }
+
+  public close() {
+    this._closeConnection();
+  }
+
+  public toString() {
+    return "[object IDBDatabase]";
+  }
+}
+
+/** @public */
+export type DatabaseList = Array<{ name: string; version: number }>;
+
+/** @public */
+export class BridgeIDBFactory {
+  public cmp = compareKeys;
+  private backend: Backend;
+  private connections: BridgeIDBDatabase[] = [];
+  static enableTracing: boolean = false;
+
+  public constructor(backend: Backend) {
+    this.backend = backend;
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-deleteDatabase-IDBOpenDBRequest-DOMString-name
+  public deleteDatabase(name: string): BridgeIDBOpenDBRequest {
+    const request = new BridgeIDBOpenDBRequest();
+    request.source = null;
+
+    queueTask(async () => {
+      const databases = await this.backend.getDatabases();
+      const dbInfo = databases.find((x) => x.name == name);
+      if (!dbInfo) {
+        // Database already doesn't exist, success!
+        const event = new BridgeIDBVersionChangeEvent("success", {
+          newVersion: null,
+          oldVersion: 0,
+        });
+        request.dispatchEvent(event);
+        return;
+      }
+      const oldVersion = dbInfo.version;
+
+      try {
+        const dbconn = await this.backend.connectDatabase(name);
+        const backendTransaction = await this.backend.enterVersionChange(
+          dbconn,
+          0,
+        );
+        await this.backend.deleteDatabase(backendTransaction, name);
+        await this.backend.commit(backendTransaction);
+        await this.backend.close(dbconn);
+
+        request.result = undefined;
+        request.readyState = "done";
+
+        const event2 = new BridgeIDBVersionChangeEvent("success", {
+          newVersion: null,
+          oldVersion,
+        });
+        request.dispatchEvent(event2);
+      } catch (err) {
+        request.error = new Error();
+        request.error.name = err.name;
+        request.readyState = "done";
+
+        const event = new FakeEvent("error", {
+          bubbles: true,
+          cancelable: true,
+        });
+        event.eventPath = [];
+        request.dispatchEvent(event);
+      }
+    });
+
+    return request;
+  }
+
+  // tslint:disable-next-line max-line-length
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBFactory-open-IDBOpenDBRequest-DOMString-name-unsigned-long-long-version
+  public open(name: string, version?: number) {
+    if (arguments.length > 1 && version !== undefined) {
+      // Based on spec, not sure why "MAX_SAFE_INTEGER" instead of "unsigned 
long long", but it's needed to pass
+      // tests
+      version = enforceRange(version, "MAX_SAFE_INTEGER");
+    }
+    if (version === 0) {
+      throw new TypeError();
+    }
+
+    const request = new BridgeIDBOpenDBRequest();
+
+    queueTask(async () => {
+      let dbconn: DatabaseConnection;
+      try {
+        dbconn = await this.backend.connectDatabase(name);
+      } catch (err) {
+        request._finishWithError(err);
+        return;
+      }
+
+      const schema = this.backend.getSchema(dbconn);
+      const existingVersion = schema.databaseVersion;
+
+      if (version === undefined) {
+        version = existingVersion !== 0 ? existingVersion : 1;
+      }
+
+      const requestedVersion = version;
+
+      BridgeIDBFactory.enableTracing &&
+        console.log(
+          `TRACE: existing version ${existingVersion}, requested version 
${requestedVersion}`,
+        );
+
+      if (existingVersion > requestedVersion) {
+        request._finishWithError(new VersionError());
+        return;
+      }
+
+      const db = new BridgeIDBDatabase(this.backend, dbconn);
+
+      if (existingVersion == requestedVersion) {
+        request.result = db;
+        request.readyState = "done";
+
+        const event2 = new FakeEvent("success", {
+          bubbles: false,
+          cancelable: false,
+        });
+        event2.eventPath = [request];
+        request.dispatchEvent(event2);
+      }
+
+      if (existingVersion < requestedVersion) {
+        // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-running-a-versionchange-transaction
+
+        for (const otherConn of this.connections) {
+          const event = new BridgeIDBVersionChangeEvent("versionchange", {
+            newVersion: version,
+            oldVersion: existingVersion,
+          });
+          otherConn.dispatchEvent(event);
+        }
+
+        if (this._anyOpen()) {
+          const event = new BridgeIDBVersionChangeEvent("blocked", {
+            newVersion: version,
+            oldVersion: existingVersion,
+          });
+          request.dispatchEvent(event);
+        }
+
+        const backendTransaction = await this.backend.enterVersionChange(
+          dbconn,
+          requestedVersion,
+        );
+        db._runningVersionchangeTransaction = true;
+
+        const transaction = db._internalTransaction(
+          [],
+          "versionchange",
+          backendTransaction,
+        );
+        const event = new BridgeIDBVersionChangeEvent("upgradeneeded", {
+          newVersion: version,
+          oldVersion: existingVersion,
+        });
+
+        request.result = db;
+        request.readyState = "done";
+        request.transaction = transaction;
+        request.dispatchEvent(event);
+
+        await transaction._waitDone();
+
+        // We don't explicitly exit the versionchange transaction,
+        // since this is already done by the BridgeIDBTransaction.
+        db._runningVersionchangeTransaction = false;
+
+        const event2 = new FakeEvent("success", {
+          bubbles: false,
+          cancelable: false,
+        });
+        event2.eventPath = [request];
+
+        request.dispatchEvent(event2);
+      }
+
+      this.connections.push(db);
+      return db;
+    });
+
+    return request;
+  }
+
+  // https://w3c.github.io/IndexedDB/#dom-idbfactory-databases
+  public databases(): Promise<DatabaseList> {
+    return this.backend.getDatabases();
+  }
+
+  public toString(): string {
+    return "[object IDBFactory]";
+  }
+
+  private _anyOpen(): boolean {
+    return this.connections.some((c) => !c._closed && !c._closePending);
+  }
+}
+
+const confirmActiveTransaction = (
+  index: BridgeIDBIndex,
+): BridgeIDBTransaction => {
+  if (index._deleted || index.objectStore._deleted) {
+    throw new InvalidStateError();
+  }
+
+  if (index.objectStore.transaction._state !== "active") {
+    throw new TransactionInactiveError();
+  }
+
+  return index.objectStore.transaction;
+};
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#idl-def-IDBIndex
+/** @public */
+export class BridgeIDBIndex {
+  objectStore: BridgeIDBObjectStore;
+
+  get _schema(): Schema {
+    return this.objectStore.transaction.db._schema;
+  }
+
+  get keyPath(): IDBKeyPath {
+    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+      .keyPath;
+  }
+
+  get multiEntry(): boolean {
+    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+      .multiEntry;
+  }
+
+  get unique(): boolean {
+    return this._schema.objectStores[this.objectStore.name].indexes[this._name]
+      .unique;
+  }
+
+  get _backend(): Backend {
+    return this.objectStore._backend;
+  }
+
+  _confirmActiveTransaction(): { btx: DatabaseTransaction } {
+    return this.objectStore._confirmActiveTransaction();
+  }
+
+  private _name: string;
+
+  public _deleted: boolean = false;
+
+  constructor(objectStore: BridgeIDBObjectStore, name: string) {
+    this._name = name;
+    this.objectStore = objectStore;
+  }
+
+  get name() {
+    return this._name;
+  }
+
+  // https://w3c.github.io/IndexedDB/#dom-idbindex-name
+  set name(name: any) {
+    const transaction = this.objectStore.transaction;
+
+    if (!transaction.db._runningVersionchangeTransaction) {
+      throw new InvalidStateError();
+    }
+
+    if (transaction._state !== "active") {
+      throw new TransactionInactiveError();
+    }
+
+    const { btx } = this._confirmActiveTransaction();
+
+    const oldName = this._name;
+    const newName = String(name);
+
+    if (newName === oldName) {
+      return;
+    }
+
+    this._backend.renameIndex(btx, this.objectStore.name, oldName, newName);
+
+    if (this.objectStore.indexNames.indexOf(name) >= 0) {
+      throw new ConstraintError();
+    }
+  }
+
+  // tslint:disable-next-line max-line-length
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openCursor-IDBRequest-any-range-IDBCursorDirection-direction
+  public openCursor(
+    range?: BridgeIDBKeyRange | IDBValidKey | null | undefined,
+    direction: IDBCursorDirection = "next",
+  ) {
+    confirmActiveTransaction(this);
+
+    if (range === null) {
+      range = undefined;
+    }
+    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+      range = BridgeIDBKeyRange.only(valueToKey(range));
+    }
+
+    const request = new BridgeIDBRequest();
+    request.source = this;
+    request.transaction = this.objectStore.transaction;
+
+    const cursor = new BridgeIDBCursorWithValue(
+      this,
+      this.objectStore.name,
+      this._name,
+      range,
+      direction,
+      request,
+    );
+
+    const operation = async () => {
+      return cursor._iterate();
+    };
+
+    return this.objectStore.transaction._execRequestAsync({
+      operation,
+      request,
+      source: this,
+    });
+  }
+
+  // tslint:disable-next-line max-line-length
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-openKeyCursor-IDBRequest-any-range-IDBCursorDirection-direction
+  public openKeyCursor(
+    range?: BridgeIDBKeyRange | IDBValidKey | null | undefined,
+    direction: IDBCursorDirection = "next",
+  ) {
+    confirmActiveTransaction(this);
+
+    if (range === null) {
+      range = undefined;
+    }
+    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+      range = BridgeIDBKeyRange.only(valueToKey(range));
+    }
+
+    const request = new BridgeIDBRequest();
+    request.source = this;
+    request.transaction = this.objectStore.transaction;
+
+    const cursor = new BridgeIDBCursor(
+      this,
+      this.objectStore.name,
+      this._name,
+      range,
+      direction,
+      request,
+      true,
+    );
+
+    return this.objectStore.transaction._execRequestAsync({
+      operation: cursor._iterate.bind(cursor),
+      request,
+      source: this,
+    });
+  }
+
+  public get(key: BridgeIDBKeyRange | IDBValidKey) {
+    confirmActiveTransaction(this);
+
+    if (!(key instanceof BridgeIDBKeyRange)) {
+      key = BridgeIDBKeyRange._valueToKeyRange(key);
+    }
+
+    const getReq: RecordGetRequest = {
+      direction: "next",
+      indexName: this._name,
+      limit: 1,
+      range: key,
+      objectStoreName: this.objectStore._name,
+      resultLevel: ResultLevel.Full,
+    };
+
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.getRecords(btx, getReq);
+      if (result.count == 0) {
+        return undefined;
+      }
+      const values = result.values;
+      if (!values) {
+        throw Error("invariant violated");
+      }
+      return values[0];
+    };
+
+    return this.objectStore.transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbindex-getall
+  public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+    throw Error("not implemented");
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-getKey-IDBRequest-any-key
+  public getKey(key: BridgeIDBKeyRange | IDBValidKey) {
+    confirmActiveTransaction(this);
+
+    if (!(key instanceof BridgeIDBKeyRange)) {
+      key = BridgeIDBKeyRange._valueToKeyRange(key);
+    }
+
+    const getReq: RecordGetRequest = {
+      direction: "next",
+      indexName: this._name,
+      limit: 1,
+      range: key,
+      objectStoreName: this.objectStore._name,
+      resultLevel: ResultLevel.OnlyKeys,
+    };
+
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.getRecords(btx, getReq);
+      if (result.count == 0) {
+        return undefined;
+      }
+      const primaryKeys = result.primaryKeys;
+      if (!primaryKeys) {
+        throw Error("invariant violated");
+      }
+      return primaryKeys[0];
+    };
+
+    return this.objectStore.transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbindex-getallkeys
+  public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+    throw Error("not implemented");
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBIndex-count-IDBRequest-any-key
+  public count(key: BridgeIDBKeyRange | IDBValidKey | null | undefined) {
+    confirmActiveTransaction(this);
+
+    if (key === null) {
+      key = undefined;
+    }
+    if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
+      key = BridgeIDBKeyRange.only(valueToKey(key));
+    }
+
+    const getReq: RecordGetRequest = {
+      direction: "next",
+      indexName: this._name,
+      limit: 1,
+      range: key,
+      objectStoreName: this.objectStore._name,
+      resultLevel: ResultLevel.OnlyCount,
+    };
+
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.getRecords(btx, getReq);
+      return result.count;
+    };
+
+    return this.objectStore.transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  public toString() {
+    return "[object IDBIndex]";
+  }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#range-concept
+/** @public */
+export class BridgeIDBKeyRange {
+  public static only(value: IDBValidKey) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    value = valueToKey(value);
+    return new BridgeIDBKeyRange(value, value, false, false);
+  }
+
+  static lowerBound(lower: IDBValidKey, open: boolean = false) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    lower = valueToKey(lower);
+    return new BridgeIDBKeyRange(lower, undefined, open, true);
+  }
+
+  static upperBound(upper: IDBValidKey, open: boolean = false) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    upper = valueToKey(upper);
+    return new BridgeIDBKeyRange(undefined, upper, true, open);
+  }
+
+  static bound(
+    lower: IDBValidKey,
+    upper: IDBValidKey,
+    lowerOpen: boolean = false,
+    upperOpen: boolean = false,
+  ) {
+    if (arguments.length < 2) {
+      throw new TypeError();
+    }
+
+    const cmpResult = compareKeys(lower, upper);
+    if (cmpResult === 1 || (cmpResult === 0 && (lowerOpen || upperOpen))) {
+      throw new DataError();
+    }
+
+    lower = valueToKey(lower);
+    upper = valueToKey(upper);
+    return new BridgeIDBKeyRange(lower, upper, lowerOpen, upperOpen);
+  }
+
+  readonly lower: IDBValidKey | undefined;
+  readonly upper: IDBValidKey | undefined;
+  readonly lowerOpen: boolean;
+  readonly upperOpen: boolean;
+
+  constructor(
+    lower: IDBValidKey | undefined,
+    upper: IDBValidKey | undefined,
+    lowerOpen: boolean,
+    upperOpen: boolean,
+  ) {
+    this.lower = lower;
+    this.upper = upper;
+    this.lowerOpen = lowerOpen;
+    this.upperOpen = upperOpen;
+  }
+
+  // https://w3c.github.io/IndexedDB/#dom-idbkeyrange-includes
+  includes(key: IDBValidKey) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    key = valueToKey(key);
+
+    if (this.lower !== undefined) {
+      const cmpResult = compareKeys(this.lower, key);
+
+      if (cmpResult === 1 || (cmpResult === 0 && this.lowerOpen)) {
+        return false;
+      }
+    }
+    if (this.upper !== undefined) {
+      const cmpResult = compareKeys(this.upper, key);
+
+      if (cmpResult === -1 || (cmpResult === 0 && this.upperOpen)) {
+        return false;
+      }
+    }
+    return true;
+  }
+
+  toString() {
+    return "[object IDBKeyRange]";
+  }
+
+  static _valueToKeyRange(value: any, nullDisallowedFlag: boolean = false) {
+    if (value instanceof BridgeIDBKeyRange) {
+      return value;
+    }
+
+    if (value === null || value === undefined) {
+      if (nullDisallowedFlag) {
+        throw new DataError();
+      }
+      return new BridgeIDBKeyRange(undefined, undefined, false, false);
+    }
+
+    const key = valueToKey(value);
+
+    return BridgeIDBKeyRange.only(key);
+  }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#object-store
+/** @public */
+export class BridgeIDBObjectStore {
+  _indexesCache: Map<string, BridgeIDBIndex> = new Map();
+
+  transaction: BridgeIDBTransaction;
+
+  get autoIncrement(): boolean {
+    return this._schema.objectStores[this._name].autoIncrement;
+  }
+
+  get indexNames(): FakeDOMStringList {
+    return fakeDOMStringList(
+      Object.keys(this._schema.objectStores[this._name].indexes),
+    ).sort();
+  }
+
+  get keyPath(): IDBKeyPath | null {
+    return this._schema.objectStores[this._name].keyPath;
+  }
+
+  _name: string;
+
+  get _schema(): Schema {
+    return this.transaction.db._schema;
+  }
+
+  _deleted: boolean = false;
+
+  constructor(transaction: BridgeIDBTransaction, name: string) {
+    this._name = name;
+    this.transaction = transaction;
+  }
+
+  get name() {
+    return this._name;
+  }
+
+  get _backend(): Backend {
+    return this.transaction.db._backend;
+  }
+
+  get _backendConnection(): DatabaseConnection {
+    return this.transaction.db._backendConnection;
+  }
+
+  _confirmActiveTransaction(): { btx: DatabaseTransaction } {
+    const btx = this.transaction._backendTransaction;
+    if (!btx) {
+      throw new InvalidStateError();
+    }
+    return { btx };
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-name
+  set name(newName: any) {
+    const transaction = this.transaction;
+
+    if (!transaction.db._runningVersionchangeTransaction) {
+      throw new InvalidStateError();
+    }
+
+    let { btx } = this._confirmActiveTransaction();
+
+    newName = String(newName);
+
+    const oldName = this._name;
+
+    if (newName === oldName) {
+      return;
+    }
+
+    this._backend.renameObjectStore(btx, oldName, newName);
+    this.transaction.db._schema = this._backend.getSchema(
+      this._backendConnection,
+    );
+  }
+
+  public _store(value: any, key: IDBValidKey | undefined, overwrite: boolean) {
+    if (BridgeIDBFactory.enableTracing) {
+      console.log(`TRACE: IDBObjectStore._store`);
+    }
+    if (this.transaction.mode === "readonly") {
+      throw new ReadOnlyError();
+    }
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.storeRecord(btx, {
+        objectStoreName: this._name,
+        key: key,
+        value: value,
+        storeLevel: overwrite
+          ? StoreLevel.AllowOverwrite
+          : StoreLevel.NoOverwrite,
+      });
+      return result.key;
+    };
+
+    return this.transaction._execRequestAsync({ operation, source: this });
+  }
+
+  public put(value: any, key?: IDBValidKey) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    return this._store(value, key, true);
+  }
+
+  public add(value: any, key?: IDBValidKey) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+    return this._store(value, key, false);
+  }
+
+  public delete(key: IDBValidKey | BridgeIDBKeyRange) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+
+    if (this.transaction.mode === "readonly") {
+      throw new ReadOnlyError();
+    }
+
+    let keyRange: BridgeIDBKeyRange;
+
+    if (key instanceof BridgeIDBKeyRange) {
+      keyRange = key;
+    } else {
+      keyRange = BridgeIDBKeyRange.only(valueToKey(key));
+    }
+
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      return this._backend.deleteRecord(btx, this._name, keyRange);
+    };
+
+    return this.transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  public get(key?: BridgeIDBKeyRange | IDBValidKey) {
+    if (BridgeIDBFactory.enableTracing) {
+      console.log(`getting from object store ${this._name} key ${key}`);
+    }
+
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+
+    let keyRange: BridgeIDBKeyRange;
+
+    if (key instanceof BridgeIDBKeyRange) {
+      keyRange = key;
+    } else {
+      try {
+        keyRange = BridgeIDBKeyRange.only(valueToKey(key));
+      } catch (e) {
+        throw Error(
+          `invalid key (type ${typeof key}) for object store ${this._name}`,
+        );
+      }
+    }
+
+    const recordRequest: RecordGetRequest = {
+      objectStoreName: this._name,
+      indexName: undefined,
+      lastIndexPosition: undefined,
+      lastObjectStorePosition: undefined,
+      direction: "next",
+      limit: 1,
+      resultLevel: ResultLevel.Full,
+      range: keyRange,
+    };
+
+    const operation = async () => {
+      if (BridgeIDBFactory.enableTracing) {
+        console.log("running get operation:", recordRequest);
+      }
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.getRecords(btx, recordRequest);
+
+      if (BridgeIDBFactory.enableTracing) {
+        console.log("get operation result count:", result.count);
+      }
+
+      if (result.count === 0) {
+        return undefined;
+      }
+      const values = result.values;
+      if (!values) {
+        throw Error("invariant violated");
+      }
+      return values[0];
+    };
+
+    return this.transaction._execRequestAsync({
+      operation,
+      source: this,
+    });
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getall
+  public getAll(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+    throw Error("not implemented");
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getkey
+  public getKey(key?: BridgeIDBKeyRange | IDBValidKey) {
+    throw Error("not implemented");
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbobjectstore-getallkeys
+  public getAllKeys(query?: BridgeIDBKeyRange | IDBValidKey, count?: number) {
+    throw Error("not implemented");
+  }
+
+  public clear() {
+    throw Error("not implemented");
+  }
+
+  public openCursor(
+    range?: IDBKeyRange | IDBValidKey,
+    direction: IDBCursorDirection = "next",
+  ) {
+    if (range === null) {
+      range = undefined;
+    }
+    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+      range = BridgeIDBKeyRange.only(valueToKey(range));
+    }
+
+    const request = new BridgeIDBRequest();
+    request.source = this;
+    request.transaction = this.transaction;
+
+    const cursor = new BridgeIDBCursorWithValue(
+      this,
+      this._name,
+      undefined,
+      range,
+      direction,
+      request,
+    );
+
+    return this.transaction._execRequestAsync({
+      operation: () => cursor._iterate(),
+      request,
+      source: this,
+    });
+  }
+
+  public openKeyCursor(
+    range?: BridgeIDBKeyRange | IDBValidKey,
+    direction?: IDBCursorDirection,
+  ) {
+    if (range === null) {
+      range = undefined;
+    }
+    if (range !== undefined && !(range instanceof BridgeIDBKeyRange)) {
+      range = BridgeIDBKeyRange.only(valueToKey(range));
+    }
+
+    if (!direction) {
+      direction = "next";
+    }
+
+    const request = new BridgeIDBRequest();
+    request.source = this;
+    request.transaction = this.transaction;
+
+    const cursor = new BridgeIDBCursor(
+      this,
+      this._name,
+      undefined,
+      range,
+      direction,
+      request,
+      true,
+    );
+
+    return this.transaction._execRequestAsync({
+      operation: cursor._iterate.bind(cursor),
+      request,
+      source: this,
+    });
+  }
+
+  // tslint:disable-next-line max-line-length
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-createIndex-IDBIndex-DOMString-name-DOMString-sequence-DOMString--keyPath-IDBIndexParameters-optionalParameters
+  public createIndex(
+    indexName: string,
+    keyPath: IDBKeyPath,
+    optionalParameters: { multiEntry?: boolean; unique?: boolean } = {},
+  ) {
+    if (arguments.length < 2) {
+      throw new TypeError();
+    }
+
+    if (!this.transaction.db._runningVersionchangeTransaction) {
+      throw new InvalidStateError();
+    }
+
+    const { btx } = this._confirmActiveTransaction();
+
+    const multiEntry =
+      optionalParameters.multiEntry !== undefined
+        ? optionalParameters.multiEntry
+        : false;
+    const unique =
+      optionalParameters.unique !== undefined
+        ? optionalParameters.unique
+        : false;
+
+    if (this.transaction.mode !== "versionchange") {
+      throw new InvalidStateError();
+    }
+
+    if (this.indexNames.indexOf(indexName) >= 0) {
+      throw new ConstraintError();
+    }
+
+    validateKeyPath(keyPath);
+
+    if (Array.isArray(keyPath) && multiEntry) {
+      throw new InvalidAccessError();
+    }
+
+    this._backend.createIndex(
+      btx,
+      indexName,
+      this._name,
+      keyPath,
+      multiEntry,
+      unique,
+    );
+
+    return new BridgeIDBIndex(this, indexName);
+  }
+
+  // https://w3c.github.io/IndexedDB/#dom-idbobjectstore-index
+  public index(name: string) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+
+    if (this.transaction._state === "finished") {
+      throw new InvalidStateError();
+    }
+
+    const index = this._indexesCache.get(name);
+    if (index !== undefined) {
+      return index;
+    }
+
+    return new BridgeIDBIndex(this, name);
+  }
+
+  public deleteIndex(indexName: string) {
+    if (arguments.length === 0) {
+      throw new TypeError();
+    }
+
+    if (this.transaction.mode !== "versionchange") {
+      throw new InvalidStateError();
+    }
+
+    if (!this.transaction.db._runningVersionchangeTransaction) {
+      throw new InvalidStateError();
+    }
+
+    const { btx } = this._confirmActiveTransaction();
+
+    const index = this._indexesCache.get(indexName);
+    if (index !== undefined) {
+      index._deleted = true;
+    }
+
+    this._backend.deleteIndex(btx, this._name, indexName);
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBObjectStore-count-IDBRequest-any-key
+  public count(key?: IDBValidKey | BridgeIDBKeyRange) {
+    if (key === null) {
+      key = undefined;
+    }
+    if (key !== undefined && !(key instanceof BridgeIDBKeyRange)) {
+      key = BridgeIDBKeyRange.only(valueToKey(key));
+    }
+
+    const recordGetRequest: RecordGetRequest = {
+      direction: "next",
+      indexName: undefined,
+      lastIndexPosition: undefined,
+      limit: -1,
+      objectStoreName: this._name,
+      lastObjectStorePosition: undefined,
+      range: key,
+      resultLevel: ResultLevel.OnlyCount,
+    };
+
+    const operation = async () => {
+      const { btx } = this._confirmActiveTransaction();
+      const result = await this._backend.getRecords(btx, recordGetRequest);
+      return result.count;
+    };
+
+    return this.transaction._execRequestAsync({ operation, source: this });
+  }
+
+  public toString() {
+    return "[object IDBObjectStore]";
+  }
+}
+
+/** @public */
+export class BridgeIDBRequest extends FakeEventTarget {
+  _result: any = null;
+  _error: Error | null | undefined = null;
+  source: BridgeIDBCursor | BridgeIDBIndex | BridgeIDBObjectStore | null = 
null;
+  transaction: BridgeIDBTransaction | null = null;
+  readyState: "done" | "pending" = "pending";
+  onsuccess: EventListener | null = null;
+  onerror: EventListener | null = null;
+
+  get error() {
+    if (this.readyState === "pending") {
+      throw new InvalidStateError();
+    }
+    return this._error;
+  }
+
+  set error(value: any) {
+    this._error = value;
+  }
+
+  get result() {
+    if (this.readyState === "pending") {
+      throw new InvalidStateError();
+    }
+    return this._result;
+  }
+
+  set result(value: any) {
+    this._result = value;
+  }
+
+  toString() {
+    return "[object IDBRequest]";
+  }
+
+  _finishWithError(err: Error) {
+    this.result = undefined;
+    this.readyState = "done";
+
+    this.error = new Error(err.message);
+    this.error.name = err.name;
+
+    const event = new FakeEvent("error", {
+      bubbles: true,
+      cancelable: true,
+    });
+    event.eventPath = [];
+    this.dispatchEvent(event);
+  }
+
+  _finishWithResult(result: any) {
+    this.result = result;
+    this.readyState = "done";
+
+    const event = new FakeEvent("success");
+    event.eventPath = [];
+    this.dispatchEvent(event);
+  }
+}
+
+/** @public */
+export class BridgeIDBOpenDBRequest extends BridgeIDBRequest {
+  public onupgradeneeded: EventListener | null = null;
+  public onblocked: EventListener | null = null;
+
+  constructor() {
+    super();
+    // https://www.w3.org/TR/IndexedDB/#open-requests
+    this.source = null;
+  }
+
+  public toString() {
+    return "[object IDBOpenDBRequest]";
+  }
+}
+
+// http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#transaction
+/** @public */
+export class BridgeIDBTransaction extends FakeEventTarget {
+  public _state: "active" | "inactive" | "committing" | "finished" = "active";
+  public _started = false;
+  public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map();
+
+  public _backendTransaction?: DatabaseTransaction;
+
+  public objectStoreNames: FakeDOMStringList;
+  public mode: IDBTransactionMode;
+  public db: BridgeIDBDatabase;
+  public error: Error | null = null;
+  public onabort: EventListener | null = null;
+  public oncomplete: EventListener | null = null;
+  public onerror: EventListener | null = null;
+
+  private _waitPromise: Promise<void>;
+  private _resolveWait: () => void;
+
+  public _scope: Set<string>;
+  private _requests: Array<{
+    operation: () => void;
+    request: BridgeIDBRequest;
+  }> = [];
+
+  get _backend(): Backend {
+    return this.db._backend;
+  }
+
+  constructor(
+    storeNames: string[],
+    mode: IDBTransactionMode,
+    db: BridgeIDBDatabase,
+    backendTransaction?: DatabaseTransaction,
+  ) {
+    super();
+
+    const myOpenPromise = openPromise<void>();
+    this._waitPromise = myOpenPromise.promise;
+    this._resolveWait = myOpenPromise.resolve;
+
+    this._scope = new Set(storeNames);
+    this._backendTransaction = backendTransaction;
+    this.mode = mode;
+    this.db = db;
+    this.objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());
+
+    this.db._transactions.push(this);
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction
+  async _abort(errName: string | null) {
+    this._state = "finished";
+
+    if (errName !== null) {
+      const e = new Error();
+      e.name = errName;
+      this.error = e;
+    }
+
+    // Should this directly remove from _requests?
+    for (const { request } of this._requests) {
+      if (request.readyState !== "done") {
+        request.readyState = "done"; // This will cancel execution of this 
request's operation
+        if (request.source) {
+          request.result = undefined;
+          request.error = new AbortError();
+
+          const event = new FakeEvent("error", {
+            bubbles: true,
+            cancelable: true,
+          });
+          event.eventPath = [this.db, this];
+          request.dispatchEvent(event);
+        }
+      }
+    }
+
+    // Only roll back if we actually executed the scheduled operations.
+    const maybeBtx = this._backendTransaction;
+    if (maybeBtx) {
+      await this._backend.rollback(maybeBtx);
+    }
+
+    queueTask(() => {
+      const event = new FakeEvent("abort", {
+        bubbles: true,
+        cancelable: false,
+      });
+      event.eventPath = [this.db];
+      this.dispatchEvent(event);
+    });
+  }
+
+  public abort() {
+    if (this._state === "committing" || this._state === "finished") {
+      throw new InvalidStateError();
+    }
+    this._state = "active";
+
+    this._abort(null);
+  }
+
+  // http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore
+  public objectStore(name: string) {
+    if (this._state !== "active") {
+      throw new InvalidStateError();
+    }
+
+    const objectStore = this._objectStoresCache.get(name);
+    if (objectStore !== undefined) {
+      return objectStore;
+    }
+
+    return new BridgeIDBObjectStore(this, name);
+  }
+
+  // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-asynchronously-executing-a-request
+  public _execRequestAsync(obj: RequestObj) {
+    const source = obj.source;
+    const operation = obj.operation;
+    let request = obj.hasOwnProperty("request") ? obj.request : null;
+
+    if (this._state !== "active") {
+      throw new TransactionInactiveError();
+    }
+
+    // Request should only be passed for cursors
+    if (!request) {
+      if (!source) {
+        // Special requests like indexes that just need to run some code
+        request = new BridgeIDBRequest();
+      } else {
+        request = new BridgeIDBRequest();
+        request.source = source;
+        request.transaction = (source as any).transaction;
+      }
+    }
+
+    this._requests.push({
+      operation,
+      request,
+    });
+
+    return request;
+  }
+
+  /**
+   * Actually execute the scheduled work for this transaction.
+   */
+  public async _start() {
+    if (BridgeIDBFactory.enableTracing) {
+      console.log(
+        `TRACE: IDBTransaction._start, ${this._requests.length} queued`,
+      );
+    }
+    this._started = true;
+
+    if (!this._backendTransaction) {
+      this._backendTransaction = await this._backend.beginTransaction(
+        this.db._backendConnection,
+        Array.from(this._scope),
+        this.mode,
+      );
+    }
+
+    // Remove from request queue - cursor ones will be added back if necessary 
by cursor.continue and such
+    let operation;
+    let request;
+    while (this._requests.length > 0) {
+      const r = this._requests.shift();
+
+      // This should only be false if transaction was aborted
+      if (r && r.request.readyState !== "done") {
+        request = r.request;
+        operation = r.operation;
+        break;
+      }
+    }
+
+    if (request && operation) {
+      if (!request.source) {
+        // Special requests like indexes that just need to run some code, with 
error handling already built into
+        // operation
+        await operation();
+      } else {
+        let event;
+        try {
+          BridgeIDBFactory.enableTracing &&
+            console.log("TRACE: running operation in transaction");
+          const result = await operation();
+          BridgeIDBFactory.enableTracing &&
+            console.log(
+              "TRACE: operation in transaction finished with success",
+            );
+          request.readyState = "done";
+          request.result = result;
+          request.error = undefined;
+
+          // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-a-success-event
+          if (this._state === "inactive") {
+            this._state = "active";
+          }
+          event = new FakeEvent("success", {
+            bubbles: false,
+            cancelable: false,
+          });
+
+          try {
+            event.eventPath = [request, this, this.db];
+            request.dispatchEvent(event);
+          } catch (err) {
+            if (this._state !== "committing") {
+              this._abort("AbortError");
+            }
+            throw err;
+          }
+        } catch (err) {
+          if (BridgeIDBFactory.enableTracing) {
+            console.log("TRACING: error during operation: ", err);
+          }
+          request.readyState = "done";
+          request.result = undefined;
+          request.error = err;
+
+          // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event
+          if (this._state === "inactive") {
+            this._state = "active";
+          }
+          event = new FakeEvent("error", {
+            bubbles: true,
+            cancelable: true,
+          });
+
+          try {
+            event.eventPath = [this.db, this];
+            request.dispatchEvent(event);
+          } catch (err) {
+            if (this._state !== "committing") {
+              this._abort("AbortError");
+            }
+            throw err;
+          }
+          if (!event.canceled) {
+            this._abort(err.name);
+          }
+        }
+      }
+
+      // On to the next one
+      if (this._requests.length > 0) {
+        this._start();
+      } else {
+        // Give it another chance for new handlers to be set before finishing
+        queueTask(() => this._start());
+      }
+      return;
+    }
+
+    if (this._state !== "finished" && this._state !== "committing") {
+      if (BridgeIDBFactory.enableTracing) {
+        console.log("finishing transaction");
+      }
+
+      this._state = "committing";
+
+      await this._backend.commit(this._backendTransaction);
+
+      this._state = "finished";
+
+      if (!this.error) {
+        if (BridgeIDBFactory.enableTracing) {
+          console.log("dispatching 'complete' event on transaction");
+        }
+        const event = new FakeEvent("complete");
+        event.eventPath = [this, this.db];
+        this.dispatchEvent(event);
+      }
+
+      const idx = this.db._transactions.indexOf(this);
+      if (idx < 0) {
+        throw Error("invariant failed");
+      }
+      this.db._transactions.splice(idx, 1);
+
+      this._resolveWait();
+    }
+  }
+
+  public commit() {
+    if (this._state !== "active") {
+      throw new InvalidStateError();
+    }
+
+    this._state = "committing";
+    // We now just wait for auto-commit ...
+  }
+
+  public toString() {
+    return "[object IDBRequest]";
+  }
+
+  _waitDone(): Promise<void> {
+    return this._waitPromise;
+  }
+}
+
+export class BridgeIDBVersionChangeEvent extends FakeEvent {
+  public newVersion: number | null;
+  public oldVersion: number;
+
+  constructor(
+    type: "blocked" | "success" | "upgradeneeded" | "versionchange",
+    parameters: { newVersion?: number | null; oldVersion?: number } = {},
+  ) {
+    super(type);
+
+    this.newVersion =
+      parameters.newVersion !== undefined ? parameters.newVersion : null;
+    this.oldVersion =
+      parameters.oldVersion !== undefined ? parameters.oldVersion : 0;
+  }
+
+  public toString() {
+    return "[object IDBVersionChangeEvent]";
+  }
+}
diff --git a/packages/idb-bridge/src/index.ts b/packages/idb-bridge/src/index.ts
index 4c29be96..b6c15249 100644
--- a/packages/idb-bridge/src/index.ts
+++ b/packages/idb-bridge/src/index.ts
@@ -1,26 +1,3 @@
-import { BridgeIDBFactory, DatabaseList } from "./BridgeIDBFactory";
-import { BridgeIDBCursor } from "./BridgeIDBCursor";
-import { BridgeIDBIndex } from "./BridgeIDBIndex";
-import { BridgeIDBDatabase } from "./BridgeIDBDatabase";
-import { BridgeIDBKeyRange } from "./BridgeIDBKeyRange";
-import { BridgeIDBObjectStore } from "./BridgeIDBObjectStore";
-import { BridgeIDBOpenDBRequest } from "./BridgeIDBOpenDBRequest";
-import { BridgeIDBRequest } from "./BridgeIDBRequest";
-import { BridgeIDBTransaction } from "./BridgeIDBTransaction";
-import { BridgeIDBVersionChangeEvent } from "./BridgeIDBVersionChangeEvent";
-import {
-  Value,
-  CursorSource,
-  CursorRange,
-  BridgeIDBCursorDirection,
-  Key,
-  KeyPath,
-  TransactionMode,
-  FakeDOMStringList,
-  RequestObj,
-  BridgeIDBDatabaseInfo,
-  EventType,
-} from "./util/types";
 import {
   DatabaseTransaction,
   RecordGetResponse,
@@ -45,12 +22,23 @@ import {
   MemoryBackendDump,
 } from "./MemoryBackend";
 import { Event } from "./idbtypes";
+import {
+  BridgeIDBCursor,
+  BridgeIDBDatabase,
+  BridgeIDBFactory,
+  BridgeIDBIndex,
+  BridgeIDBKeyRange,
+  BridgeIDBObjectStore,
+  BridgeIDBOpenDBRequest,
+  BridgeIDBRequest,
+  BridgeIDBTransaction,
+  DatabaseList,
+  RequestObj,
+} from "./bridge-idb";
 
 export {
   BridgeIDBCursor,
-  BridgeIDBCursorDirection,
   BridgeIDBDatabase,
-  BridgeIDBDatabaseInfo,
   BridgeIDBFactory,
   BridgeIDBIndex,
   BridgeIDBKeyRange,
@@ -58,33 +46,26 @@ export {
   BridgeIDBOpenDBRequest,
   BridgeIDBRequest,
   BridgeIDBTransaction,
-  Value,
-  CursorSource,
-  CursorRange,
-  Key,
+  StoreLevel,
+  ResultLevel,
+};
+export type {
   DatabaseTransaction,
   RecordGetRequest,
   RecordGetResponse,
-  KeyPath,
   Schema,
   Backend,
-  TransactionMode,
   DatabaseList,
   RecordStoreRequest,
   RecordStoreResponse,
-  FakeEventTarget,
   DatabaseConnection,
-  FakeDOMStringList,
   ObjectStoreProperties,
   RequestObj,
-  StoreLevel,
-  ResultLevel,
   DatabaseDump,
   ObjectStoreDump,
   IndexDump,
   IndexRecord,
   ObjectStoreRecord,
-  EventType,
   IndexProperties,
   MemoryBackendDump,
   Event,
diff --git a/packages/idb-bridge/src/tree/b+tree.ts 
b/packages/idb-bridge/src/tree/b+tree.ts
index ea09d0c0..a45a9862 100644
--- a/packages/idb-bridge/src/tree/b+tree.ts
+++ b/packages/idb-bridge/src/tree/b+tree.ts
@@ -25,7 +25,7 @@ SPDX-License-Identifier: MIT
 // Original repository: https://github.com/qwertie/btree-typescript
 
 import { ISortedMap, ISortedMapF } from "./interfaces";
-export {
+export type {
   ISetSource,
   ISetSink,
   ISet,
diff --git a/packages/idb-bridge/src/util/FakeEvent.ts 
b/packages/idb-bridge/src/util/FakeEvent.ts
index 1c558d8a..c16a58fd 100644
--- a/packages/idb-bridge/src/util/FakeEvent.ts
+++ b/packages/idb-bridge/src/util/FakeEvent.ts
@@ -15,9 +15,18 @@
 */
 
 import FakeEventTarget from "./FakeEventTarget";
-import { EventType } from "./types";
 import { Event, EventTarget } from "../idbtypes";
 
+/** @public */
+export type EventType =
+  | "abort"
+  | "blocked"
+  | "complete"
+  | "error"
+  | "success"
+  | "upgradeneeded"
+  | "versionchange";
+
 export class FakeEvent implements Event {
   public eventPath: FakeEventTarget[] = [];
   public type: EventType;
diff --git a/packages/idb-bridge/src/util/FakeEventTarget.ts 
b/packages/idb-bridge/src/util/FakeEventTarget.ts
index 77df768f..d2f46c98 100644
--- a/packages/idb-bridge/src/util/FakeEventTarget.ts
+++ b/packages/idb-bridge/src/util/FakeEventTarget.ts
@@ -15,8 +15,7 @@
  */
 
 import { InvalidStateError } from "./errors";
-import FakeEvent from "./FakeEvent";
-import { EventType } from "./types";
+import FakeEvent, { EventType } from "./FakeEvent";
 import {
   EventTarget,
   Event,
diff --git a/packages/idb-bridge/src/util/canInjectKey.ts 
b/packages/idb-bridge/src/util/canInjectKey.ts
index 8a966690..09ecbd3a 100644
--- a/packages/idb-bridge/src/util/canInjectKey.ts
+++ b/packages/idb-bridge/src/util/canInjectKey.ts
@@ -14,10 +14,10 @@
  permissions and limitations under the License.
 */
 
-import { KeyPath, Value } from "./types";
+import { IDBKeyPath } from "../idbtypes";
 
 // 
http://w3c.github.io/IndexedDB/#check-that-a-key-could-be-injected-into-a-value
-const canInjectKey = (keyPath: KeyPath, value: Value) => {
+const canInjectKey = (keyPath: IDBKeyPath, value: any) => {
   if (Array.isArray(keyPath)) {
     // tslint:disable-next-line max-line-length
     throw new Error(
diff --git a/packages/idb-bridge/src/util/deepEquals.ts 
b/packages/idb-bridge/src/util/deepEquals.ts
index 716786ab..bb7c0269 100644
--- a/packages/idb-bridge/src/util/deepEquals.ts
+++ b/packages/idb-bridge/src/util/deepEquals.ts
@@ -24,7 +24,7 @@ const isArray = Array.isArray;
 const keyList = Object.keys;
 const hasProp = Object.prototype.hasOwnProperty;
 
-function deepEquals(a: any, b: any): boolean {
+export function deepEquals(a: any, b: any): boolean {
   if (a === b) return true;
 
   if (a && b && typeof a == "object" && typeof b == "object") {
diff --git a/packages/idb-bridge/src/util/extractKey.ts 
b/packages/idb-bridge/src/util/extractKey.ts
index 27f20310..7aa8bd17 100644
--- a/packages/idb-bridge/src/util/extractKey.ts
+++ b/packages/idb-bridge/src/util/extractKey.ts
@@ -15,13 +15,13 @@
  permissions and limitations under the License.
 */
 
-import { Key, KeyPath, Value } from "./types";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
 import valueToKey from "./valueToKey";
 
 // 
http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-extracting-a-key-from-a-value-using-a-key-path
-const extractKey = (keyPath: KeyPath, value: Value) => {
+const extractKey = (keyPath: IDBKeyPath | IDBKeyPath[], value: any) => {
   if (Array.isArray(keyPath)) {
-    const result: Key[] = [];
+    const result: IDBValidKey[] = [];
 
     for (let item of keyPath) {
       // This doesn't make sense to me based on the spec, but it is needed to 
pass the W3C KeyPath tests (see same
diff --git a/packages/idb-bridge/src/util/fakeDOMStringList.ts 
b/packages/idb-bridge/src/util/fakeDOMStringList.ts
index 5add1758..09ef7700 100644
--- a/packages/idb-bridge/src/util/fakeDOMStringList.ts
+++ b/packages/idb-bridge/src/util/fakeDOMStringList.ts
@@ -14,11 +14,15 @@
  * permissions and limitations under the License.
  */
 
-import { FakeDOMStringList } from "./types";
+/** @public */
+export interface FakeDOMStringList extends Array<string> {
+  contains: (value: string) => boolean;
+  item: (i: number) => string | undefined;
+}
 
 // Would be nicer to sublcass Array, but I'd have to sacrifice Node 4 support 
to do that.
 
-const fakeDOMStringList = (arr: string[]): FakeDOMStringList => {
+export const fakeDOMStringList = (arr: string[]): FakeDOMStringList => {
   const arr2 = arr.slice();
 
   Object.defineProperty(arr2, "contains", {
@@ -33,5 +37,3 @@ const fakeDOMStringList = (arr: string[]): FakeDOMStringList 
=> {
 
   return arr2 as FakeDOMStringList;
 };
-
-export default fakeDOMStringList;
diff --git a/packages/idb-bridge/src/util/getIndexKeys.ts 
b/packages/idb-bridge/src/util/getIndexKeys.ts
index 253dc57b..77b96b12 100644
--- a/packages/idb-bridge/src/util/getIndexKeys.ts
+++ b/packages/idb-bridge/src/util/getIndexKeys.ts
@@ -15,15 +15,15 @@
  permissions and limitations under the License.
 */
 
-import { Key, Value, KeyPath } from "./types";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
 import extractKey from "./extractKey";
 import valueToKey from "./valueToKey";
 
 export function getIndexKeys(
-  value: Value,
-  keyPath: KeyPath,
+  value: any,
+  keyPath: IDBKeyPath | IDBKeyPath[],
   multiEntry: boolean,
-): Key[] {
+): IDBValidKey[] {
   if (multiEntry && Array.isArray(keyPath)) {
     const keys = [];
     for (const subkeyPath of keyPath) {
@@ -36,9 +36,11 @@ export function getIndexKeys(
       }
     }
     return keys;
-  } else {
+  } else if (typeof keyPath === "string" || Array.isArray(keyPath)) {
     let key = extractKey(keyPath, value);
     return [valueToKey(key)];
+  } else {
+    throw Error(`unsupported key path: ${typeof keyPath}`);
   }
 }
 
diff --git a/packages/idb-bridge/src/util/injectKey.ts 
b/packages/idb-bridge/src/util/injectKey.ts
index 38add33b..678f42d2 100644
--- a/packages/idb-bridge/src/util/injectKey.ts
+++ b/packages/idb-bridge/src/util/injectKey.ts
@@ -15,12 +15,14 @@
  permissions and limitations under the License.
 */
 
-import { KeyPath, Value, Key } from "./types";
-import canInjectKey from "./canInjectKey";
-import { DataError } from "./errors";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
 import structuredClone from "./structuredClone";
 
-export function injectKey(keyPath: KeyPath, value: Value, key: Key): Value {
+export function injectKey(
+  keyPath: IDBKeyPath,
+  value: any,
+  key: IDBValidKey,
+): any {
   if (Array.isArray(keyPath)) {
     // tslint:disable-next-line max-line-length
     throw new Error(
diff --git a/packages/idb-bridge/src/util/makeStoreKeyValue.ts 
b/packages/idb-bridge/src/util/makeStoreKeyValue.ts
index f9006ef5..b535bced 100644
--- a/packages/idb-bridge/src/util/makeStoreKeyValue.ts
+++ b/packages/idb-bridge/src/util/makeStoreKeyValue.ts
@@ -14,25 +14,25 @@
  permissions and limitations under the License.
 */
 
-import { Value, Key, KeyPath } from "./types";
 import extractKey from "./extractKey";
 import { DataError } from "./errors";
 import valueToKey from "./valueToKey";
 import structuredClone from "./structuredClone";
 import injectKey from "./injectKey";
+import { IDBKeyPath, IDBValidKey } from "../idbtypes";
 
 export interface StoreKeyResult {
   updatedKeyGenerator: number;
-  key: Key;
-  value: Value;
+  key: IDBValidKey;
+  value: any;
 }
 
 export function makeStoreKeyValue(
-  value: Value,
-  key: Key | undefined,
+  value: any,
+  key: IDBValidKey | undefined,
   currentKeyGenerator: number,
   autoIncrement: boolean,
-  keyPath: KeyPath | null,
+  keyPath: IDBKeyPath | null,
 ): StoreKeyResult {
   const haveKey = key !== null && key !== undefined;
   const haveKeyPath = keyPath !== null && keyPath !== undefined;
@@ -89,7 +89,7 @@ export function makeStoreKeyValue(
           updatedKeyGenerator = currentKeyGenerator;
         }
         return {
-          key: key,
+          key: key!,
           value: value,
           updatedKeyGenerator,
         };
diff --git a/packages/idb-bridge/src/util/types.ts 
b/packages/idb-bridge/src/util/types.ts
deleted file mode 100644
index b07f5ad0..00000000
--- a/packages/idb-bridge/src/util/types.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- Copyright 2017 Jeremy Scheff
- Copyright 2019 Florian Dold
-
- 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 { BridgeIDBRequest } from "../BridgeIDBRequest";
-import { BridgeIDBKeyRange } from "../BridgeIDBKeyRange";
-import { BridgeIDBIndex } from "../BridgeIDBIndex";
-import { BridgeIDBObjectStore } from "../BridgeIDBObjectStore";
-import { Event } from "../idbtypes";
-
-/** @public */
-export type EventType =
-  | "abort"
-  | "blocked"
-  | "complete"
-  | "error"
-  | "success"
-  | "upgradeneeded"
-  | "versionchange";
-
-/** @public */
-export type CursorSource = BridgeIDBIndex | BridgeIDBObjectStore;
-
-/** @public */
-export interface FakeDOMStringList extends Array<string> {
-  contains: (value: string) => boolean;
-  item: (i: number) => string | undefined;
-}
-
-/**
- * @public
- */
-export type BridgeIDBCursorDirection =
-  | "next"
-  | "nextunique"
-  | "prev"
-  | "prevunique";
-
-/** @public */
-export type KeyPath = string | string[];
-
-/** @public */
-export type Key = any;
-
-/** @public */
-export type CursorRange = Key | BridgeIDBKeyRange | undefined;
-
-/** @public */
-export type Value = any;
-
-/** @public */
-export interface Record {
-  key: Key;
-  value: Key | Value; // For indexes, will be Key. For object stores, will be 
Value.
-}
-
-/** @public */
-export type TransactionMode = "readonly" | "readwrite" | "versionchange";
-
-/** @public */
-export interface BridgeIDBDatabaseInfo {
-  name: string;
-  version: number;
-}
-
-/** @public */
-export interface RequestObj {
-  operation: () => Promise<any>;
-  request?: BridgeIDBRequest | undefined;
-  source?: any;
-}
diff --git a/packages/idb-bridge/src/util/validateKeyPath.ts 
b/packages/idb-bridge/src/util/validateKeyPath.ts
index 07283219..8057172d 100644
--- a/packages/idb-bridge/src/util/validateKeyPath.ts
+++ b/packages/idb-bridge/src/util/validateKeyPath.ts
@@ -14,24 +14,25 @@
  permissions and limitations under the License.
 */
 
-import { KeyPath } from "./types";
+import { IDBKeyPath } from "../idbtypes";
 
 // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-valid-key-path
-const validateKeyPath = (keyPath: KeyPath, parent?: "array" | "string") => {
+const validateKeyPath = (keyPath: IDBKeyPath, parent?: "array" | "string") => {
   // This doesn't make sense to me based on the spec, but it is needed to pass 
the W3C KeyPath tests (see same
   // comment in extractKey)
+  let myKeyPath: IDBKeyPath | IDBKeyPath[] = keyPath;
   if (
-    keyPath !== undefined &&
-    keyPath !== null &&
-    typeof keyPath !== "string" &&
-    keyPath.toString &&
-    (parent === "array" || !Array.isArray(keyPath))
+    myKeyPath !== undefined &&
+    myKeyPath !== null &&
+    typeof myKeyPath !== "string" &&
+    (myKeyPath as any).toString &&
+    (parent === "array" || !Array.isArray(myKeyPath))
   ) {
-    keyPath = keyPath.toString();
+    myKeyPath = (myKeyPath as any).toString();
   }
 
-  if (typeof keyPath === "string") {
-    if (keyPath === "" && parent !== "string") {
+  if (typeof myKeyPath === "string") {
+    if (myKeyPath === "" && parent !== "string") {
       return;
     }
     try {
@@ -39,33 +40,33 @@ const validateKeyPath = (keyPath: KeyPath, parent?: "array" 
| "string") => {
       // reserved words at beginning removed
       // tslint:disable-next-line max-line-length
       const validIdentifierRegex = 
/^(?:[\$A-Z_a-z\xAA\xB5\xBA\xC0-\xD6\xD8-\xF6\xF8-\u02C1\u02C6-\u02D1\u02E0-\u02E4\u02EC\u02EE\u0370-\u0374\u0376\u0377\u037A-\u037D\u037F\u0386\u0388-\u038A\u038C\u038E-\u03A1\u03A3-\u03F5\u03F7-\u0481\u048A-\u052F\u0531-\u0556\u0559\u0561-\u0587\u05D0-\u05EA\u05F0-\u05F2\u0620-\u064A\u066E\u066F\u0671-\u06D3\u06D5\u06E5\u06E6\u06EE\u06EF\u06FA-\u06FC\u06FF\u0710\u0712-\u072F\u074D-\u07A5\u07B1\u07CA-\u07EA\u07F4\u07F5\u07FA\u0800-\u0815\u081A\u0824\u0
 [...]
-      if (keyPath.length >= 1 && validIdentifierRegex.test(keyPath)) {
+      if (myKeyPath.length >= 1 && validIdentifierRegex.test(myKeyPath)) {
         return;
       }
     } catch (err) {
       throw new SyntaxError(err.message);
     }
-    if (keyPath.indexOf(" ") >= 0) {
+    if (myKeyPath.indexOf(" ") >= 0) {
       throw new SyntaxError(
         "The keypath argument contains an invalid key path (no spaces 
allowed).",
       );
     }
   }
 
-  if (Array.isArray(keyPath) && keyPath.length > 0) {
+  if (Array.isArray(myKeyPath) && myKeyPath.length > 0) {
     if (parent) {
       // No nested arrays
       throw new SyntaxError(
         "The keypath argument contains an invalid key path (nested arrays).",
       );
     }
-    for (const part of keyPath) {
+    for (const part of myKeyPath) {
       validateKeyPath(part, "array");
     }
     return;
-  } else if (typeof keyPath === "string" && keyPath.indexOf(".") >= 0) {
-    keyPath = keyPath.split(".");
-    for (const part of keyPath) {
+  } else if (typeof myKeyPath === "string" && myKeyPath.indexOf(".") >= 0) {
+    myKeyPath = myKeyPath.split(".");
+    for (const part of myKeyPath) {
       validateKeyPath(part, "string");
     }
     return;
diff --git a/packages/idb-bridge/src/util/valueToKey.ts 
b/packages/idb-bridge/src/util/valueToKey.ts
index 5cf5b2b1..c3661f9a 100644
--- a/packages/idb-bridge/src/util/valueToKey.ts
+++ b/packages/idb-bridge/src/util/valueToKey.ts
@@ -14,11 +14,14 @@
  permissions and limitations under the License.
  */
 
+import { IDBValidKey } from "..";
 import { DataError } from "./errors";
-import { Key } from "./types";
 
 // https://w3c.github.io/IndexedDB/#convert-a-value-to-a-input
-function valueToKey(input: any, seen?: Set<object>): Key | Key[] {
+function valueToKey(
+  input: any,
+  seen?: Set<object>,
+): IDBValidKey | IDBValidKey[] {
   if (typeof input === "number") {
     if (isNaN(input)) {
       throw new DataError();
diff --git a/packages/idb-bridge/tsconfig.json 
b/packages/idb-bridge/tsconfig.json
index a385e964..99c5e6e3 100644
--- a/packages/idb-bridge/tsconfig.json
+++ b/packages/idb-bridge/tsconfig.json
@@ -16,6 +16,7 @@
         "rootDir": "./src",
         "esModuleInterop": true,
         "importHelpers": true,
+        "isolatedModules": true,
         "typeRoots": ["./node_modules/@types"]
     },
     "include": ["src/**/*"]
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 7ec0403c..2a75c2f2 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -3,10 +3,9 @@ importers:
     specifiers: {}
   packages/idb-bridge:
     dependencies:
-      '@types/node': 14.14.22
       tslib: 2.1.0
     devDependencies:
-      '@microsoft/api-extractor': 7.13.0
+      '@types/node': 14.14.22
       ava: 3.15.0
       esm: 3.2.25
       prettier: 2.2.1
@@ -14,7 +13,6 @@ importers:
       rollup: 2.37.1
       typescript: 4.1.3
     specifiers:
-      '@microsoft/api-extractor': ^7.13.0
       '@types/node': ^14.14.22
       ava: ^3.15.0
       esm: ^3.2.25

-- 
To stop receiving notification emails like this one, please contact
gnunet@gnunet.org.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]