diff options
| author | Florian Dold <florian@dold.me> | 2021-02-16 10:31:55 +0100 | 
|---|---|---|
| committer | Florian Dold <florian@dold.me> | 2021-02-16 13:47:00 +0100 | 
| commit | d1f00aeaa26af6835ea3f47ac280b1e67d672fa2 (patch) | |
| tree | 9a5a364f8a5eb1e038bca936d621c015dab53304 /packages/idb-bridge | |
| parent | d384bd5c62198f1160119e60776350109a8ca7d3 (diff) | |
get IDB tests to pass again, add new one
Diffstat (limited to 'packages/idb-bridge')
| -rw-r--r-- | packages/idb-bridge/src/backend-interface.ts | 1 | ||||
| -rw-r--r-- | packages/idb-bridge/src/bridge-idb.ts | 256 | ||||
| -rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/abort-in-initial-upgradeneeded.test.ts | 34 | ||||
| -rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/value.test.ts | 37 | ||||
| -rw-r--r-- | packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts | 12 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/FakeEventTarget.ts | 15 | ||||
| -rw-r--r-- | packages/idb-bridge/src/util/validateKeyPath.ts | 2 | ||||
| -rw-r--r-- | packages/idb-bridge/tsconfig.json | 1 | 
8 files changed, 239 insertions, 119 deletions
| diff --git a/packages/idb-bridge/src/backend-interface.ts b/packages/idb-bridge/src/backend-interface.ts index a9e3e960e..14b5da64a 100644 --- a/packages/idb-bridge/src/backend-interface.ts +++ b/packages/idb-bridge/src/backend-interface.ts @@ -17,7 +17,6 @@  import { BridgeIDBDatabaseInfo, BridgeIDBKeyRange } from "./bridge-idb";  import {    IDBCursorDirection, -  IDBKeyPath,    IDBTransactionMode,    IDBValidKey,  } from "./idbtypes"; diff --git a/packages/idb-bridge/src/bridge-idb.ts b/packages/idb-bridge/src/bridge-idb.ts index ce09fcb8e..c4c589790 100644 --- a/packages/idb-bridge/src/bridge-idb.ts +++ b/packages/idb-bridge/src/bridge-idb.ts @@ -61,7 +61,11 @@ import FakeEventTarget from "./util/FakeEventTarget";  import { normalizeKeyPath } from "./util/normalizeKeyPath";  import openPromise from "./util/openPromise";  import queueTask from "./util/queueTask"; -import { structuredClone, structuredEncapsulate, structuredRevive } from "./util/structuredClone"; +import { +  structuredClone, +  structuredEncapsulate, +  structuredRevive, +} from "./util/structuredClone";  import validateKeyPath from "./util/validateKeyPath";  import valueToKey from "./util/valueToKey"; @@ -266,7 +270,7 @@ export class BridgeIDBCursor implements IDBCursor {      const transaction = this._effectiveObjectStore._transaction; -    if (transaction._state !== "active") { +    if (!transaction._active) {        throw new TransactionInactiveError();      } @@ -322,7 +326,7 @@ export class BridgeIDBCursor implements IDBCursor {    public continue(key?: IDBValidKey) {      const transaction = this._effectiveObjectStore._transaction; -    if (transaction._state !== "active") { +    if (!transaction._active) {        throw new TransactionInactiveError();      } @@ -384,7 +388,7 @@ export class BridgeIDBCursor implements IDBCursor {    public delete() {      const transaction = this._effectiveObjectStore._transaction; -    if (transaction._state !== "active") { +    if (!transaction._active) {        throw new TransactionInactiveError();      } @@ -455,7 +459,7 @@ export class BridgeIDBCursorWithValue extends BridgeIDBCursor {   * Ensure that an active version change transaction is currently running.   */  const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => { -  if (!database._runningVersionchangeTransaction) { +  if (!database._upgradeTransaction) {      throw new InvalidStateError();    } @@ -467,11 +471,11 @@ const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => {    );    const transaction = transactions[transactions.length - 1]; -  if (!transaction || transaction._state === "finished") { +  if (!transaction || transaction._finished) {      throw new InvalidStateError();    } -  if (transaction._state !== "active") { +  if (!transaction._active) {      throw new TransactionInactiveError();    } @@ -480,12 +484,13 @@ const confirmActiveVersionchangeTransaction = (database: BridgeIDBDatabase) => {  // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface  /** @public */ -export class BridgeIDBDatabase extends FakeEventTarget { +export class BridgeIDBDatabase extends FakeEventTarget implements IDBDatabase {    _closePending = false;    _closed = false; -  _runningVersionchangeTransaction = false;    _transactions: Array<BridgeIDBTransaction> = []; +  _upgradeTransaction: BridgeIDBTransaction | null = null; +    _backendConnection: DatabaseConnection;    _backend: Backend; @@ -499,8 +504,10 @@ export class BridgeIDBDatabase extends FakeEventTarget {      return this._schema.databaseVersion;    } -  get objectStoreNames(): FakeDOMStringList { -    return fakeDOMStringList(Object.keys(this._schema.objectStores)).sort(); +  get objectStoreNames(): DOMStringList { +    return fakeDOMStringList( +      Object.keys(this._schema.objectStores), +    ).sort() as DOMStringList;    }    /** @@ -509,9 +516,11 @@ export class BridgeIDBDatabase extends FakeEventTarget {    _closeConnection() {      this._closePending = true; +    // Spec is unclear what "complete" means, we assume it's +    // the same as "finished".      const transactionsComplete = this._transactions.every(        (transaction: BridgeIDBTransaction) => { -        return transaction._state === "finished"; +        return transaction._finished;        },      ); @@ -525,6 +534,13 @@ export class BridgeIDBDatabase extends FakeEventTarget {      }    } +  /** +   * Refresh the schema by querying it from the backend. +   */ +  _refreshSchema() { +    this._schema = this._backend.getSchema(this._backendConnection); +  } +    constructor(backend: Backend, backendConnection: DatabaseConnection) {      super(); @@ -537,7 +553,10 @@ export class BridgeIDBDatabase extends FakeEventTarget {    // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore    public createObjectStore(      name: string, -    options: { autoIncrement?: boolean; keyPath?: IDBKeyPath } | null = {}, +    options: { +      autoIncrement?: boolean; +      keyPath?: null | IDBKeyPath | IDBKeyPath[]; +    } | null = {},    ): BridgeIDBObjectStore {      if (name === undefined) {        throw new TypeError(); @@ -572,7 +591,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {      transaction._backend.createObjectStore(        backendTx,        name, -      (keyPath !== null) ? normalizeKeyPath(keyPath) : null, +      keyPath !== null ? normalizeKeyPath(keyPath) : null,        autoIncrement,      ); @@ -593,6 +612,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {      storeNames: string | string[],      mode?: IDBTransactionMode,      backendTransaction?: DatabaseTransaction, +    openRequest?: BridgeIDBOpenDBRequest,    ): BridgeIDBTransaction {      mode = mode !== undefined ? mode : "readonly";      if ( @@ -603,16 +623,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {        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) { +    if (this._upgradeTransaction) {        throw new InvalidStateError();      } @@ -627,7 +638,7 @@ export class BridgeIDBDatabase extends FakeEventTarget {        throw new InvalidAccessError();      }      for (const storeName of storeNames) { -      if (this.objectStoreNames.indexOf(storeName) < 0) { +      if (!this.objectStoreNames.contains(storeName)) {          throw new NotFoundError(            "No objectStore named " + storeName + " in this database",          ); @@ -639,9 +650,12 @@ export class BridgeIDBDatabase extends FakeEventTarget {        mode,        this,        backendTransaction, +      openRequest,      );      this._transactions.push(tx);      queueTask(() => tx._start()); +    // "When a transaction is created its active flag is initially set." +    tx._active = true;      return tx;    } @@ -809,20 +823,25 @@ export class BridgeIDBFactory {            dbconn,            requestedVersion,          ); -        db._runningVersionchangeTransaction = true;          const transaction = db._internalTransaction(            [],            "versionchange",            backendTransaction, +          request,          ); + +        db._upgradeTransaction = transaction; +          const event = new BridgeIDBVersionChangeEvent("upgradeneeded", {            newVersion: version,            oldVersion: existingVersion,          }); -        request.result = db; +        transaction._active = true; +          request.readyState = "done"; +        request.result = db;          request.transaction = transaction;          request.dispatchEvent(event); @@ -832,15 +851,30 @@ export class BridgeIDBFactory {          // We don't explicitly exit the versionchange transaction,          // since this is already done by the BridgeIDBTransaction. -        db._runningVersionchangeTransaction = false; +        db._upgradeTransaction = null; -        const event2 = new FakeEvent("success", { -          bubbles: false, -          cancelable: false, -        }); -        event2.eventPath = [request]; +        // We re-use the same transaction (as per spec) here. +        transaction._active = true; +        if (transaction._aborted) { +          request.result = undefined; +          request.error = new AbortError(); +          request.readyState = "done"; +          const event2 = new FakeEvent("error", { +            bubbles: false, +            cancelable: false, +          }); +          event2.eventPath = [request]; +          request.dispatchEvent(event2); +        } else { +          console.log(`dispatching success event, _active=${transaction._active}`); +          const event2 = new FakeEvent("success", { +            bubbles: false, +            cancelable: false, +          }); +          event2.eventPath = [request]; -        request.dispatchEvent(event2); +          request.dispatchEvent(event2); +        }        }        this.connections.push(db); @@ -871,7 +905,7 @@ const confirmActiveTransaction = (      throw new InvalidStateError();    } -  if (index._objectStore._transaction._state !== "active") { +  if (!index._objectStore._transaction._active) {      throw new TransactionInactiveError();    } @@ -931,11 +965,11 @@ export class BridgeIDBIndex implements IDBIndex {    set name(name: any) {      const transaction = this._objectStore._transaction; -    if (!transaction._db._runningVersionchangeTransaction) { +    if (!transaction._db._upgradeTransaction) {        throw new InvalidStateError();      } -    if (transaction._state !== "active") { +    if (!transaction._active) {        throw new TransactionInactiveError();      } @@ -1282,7 +1316,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {    get _indexNames(): FakeDOMStringList {      return fakeDOMStringList(        Object.keys(this._schema.objectStores[this._name].indexes), -    ).sort() +    ).sort();    }    get indexNames(): DOMStringList { @@ -1330,7 +1364,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {    set name(newName: any) {      const transaction = this._transaction; -    if (!transaction._db._runningVersionchangeTransaction) { +    if (!transaction._db._upgradeTransaction) {        throw new InvalidStateError();      } @@ -1581,7 +1615,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {        throw new TypeError();      } -    if (!this._transaction._db._runningVersionchangeTransaction) { +    if (!this._transaction._db._upgradeTransaction) {        throw new InvalidStateError();      } @@ -1628,7 +1662,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {        throw new TypeError();      } -    if (this._transaction._state === "finished") { +    if (this._transaction._finished) {        throw new InvalidStateError();      } @@ -1649,7 +1683,7 @@ export class BridgeIDBObjectStore implements IDBObjectStore {        throw new InvalidStateError();      } -    if (!this._transaction._db._runningVersionchangeTransaction) { +    if (!this._transaction._db._upgradeTransaction) {        throw new InvalidStateError();      } @@ -1755,6 +1789,7 @@ export class BridgeIDBRequest extends FakeEventTarget implements IDBRequest {        cancelable: true,      });      event.eventPath = []; +      this.dispatchEvent(event);    } @@ -1791,24 +1826,41 @@ export class BridgeIDBOpenDBRequest  export class BridgeIDBTransaction    extends FakeEventTarget    implements IDBTransaction { -  public _state: "active" | "inactive" | "committing" | "finished" = "active"; -  public _started = false; -  public _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map(); +  _committed: boolean = false; +  /** +   * A transaction is active as long as new operations can be +   * placed against it. +   */ +  _active: boolean = false; +  _started: boolean = false; +  _aborted: boolean = false; +  _objectStoresCache: Map<string, BridgeIDBObjectStore> = new Map(); + +  /** +   * https://www.w3.org/TR/IndexedDB-2/#transaction-lifetime-concept +   * +   * When a transaction is committed or aborted, it is said to be finished. +   */ +  get _finished(): boolean { +    return this._committed || this._aborted; +  } + +  _openRequest: BridgeIDBOpenDBRequest | null = null; -  public _backendTransaction?: DatabaseTransaction; +  _backendTransaction?: DatabaseTransaction; -  public _objectStoreNames: FakeDOMStringList; +  _objectStoreNames: FakeDOMStringList;    get objectStoreNames(): DOMStringList {      return this._objectStoreNames as DOMStringList;    } -  public mode: IDBTransactionMode; -  public _db: BridgeIDBDatabase; +  mode: IDBTransactionMode; +  _db: BridgeIDBDatabase;    get db(): IDBDatabase { -    return this.db; +    return this._db;    } -  public _error: Error | null = null; +  _error: Error | null = null;    get error(): DOMException {      return this._error as DOMException; @@ -1823,7 +1875,7 @@ export class BridgeIDBTransaction    public _scope: Set<string>;    private _requests: Array<{ -    operation: () => void; +    operation: () => Promise<void>;      request: BridgeIDBRequest;    }> = []; @@ -1836,6 +1888,7 @@ export class BridgeIDBTransaction      mode: IDBTransactionMode,      db: BridgeIDBDatabase,      backendTransaction?: DatabaseTransaction, +    openRequest?: BridgeIDBOpenDBRequest,    ) {      super(); @@ -1850,11 +1903,17 @@ export class BridgeIDBTransaction      this._objectStoreNames = fakeDOMStringList(Array.from(this._scope).sort());      this._db._transactions.push(this); + +    this._openRequest = openRequest ?? null;    }    // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-steps-for-aborting-a-transaction    async _abort(errName: string | null) { -    this._state = "finished"; +    if (BridgeIDBFactory.enableTracing) { +      console.log("TRACE: aborting transaction"); +    } + +    this._aborted = true;      if (errName !== null) {        const e = new Error(); @@ -1862,30 +1921,45 @@ export class BridgeIDBTransaction        this._error = e;      } +    if (BridgeIDBFactory.enableTracing) { +      console.log(`TRACE: aborting ${this._requests.length} requests`); +    } +      // Should this directly remove from _requests?      for (const { request } of this._requests) { +      console.log("ready state:", request.readyState);        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); +        // This will cancel execution of this request's operation +        request.readyState = "done"; +        if (BridgeIDBFactory.enableTracing) { +          console.log("dispatching error event");          } +        request.result = undefined; +        request.error = new AbortError(); + +        const event = new FakeEvent("error", { +          bubbles: true, +          cancelable: true, +        }); +        event.eventPath = [request, this, this._db]; +        console.log("dispatching error event for request after abort"); +        request.dispatchEvent(event);        }      } +    // ("abort a transaction", step 5.1) +    if (this._openRequest) { +      this._db._upgradeTransaction = null; +    } +      // Only roll back if we actually executed the scheduled operations.      const maybeBtx = this._backendTransaction;      if (maybeBtx) {        await this._backend.rollback(maybeBtx);      } +    this._db._refreshSchema(); +      queueTask(() => {        const event = new FakeEvent("abort", {          bubbles: true, @@ -1894,20 +1968,24 @@ export class BridgeIDBTransaction        event.eventPath = [this._db];        this.dispatchEvent(event);      }); + +    if (this._openRequest) { +      this._openRequest.transaction = null; +      this._openRequest.result = undefined; +      this._openRequest.readyState = "pending"; +    }    }    public abort() { -    if (this._state === "committing" || this._state === "finished") { +    if (this._finished) {        throw new InvalidStateError();      } -    this._state = "active"; -      this._abort(null);    }    // http://w3c.github.io/IndexedDB/#dom-idbtransaction-objectstore    public objectStore(name: string): BridgeIDBObjectStore { -    if (this._state !== "active") { +    if (!this._active) {        throw new InvalidStateError();      } @@ -1925,7 +2003,7 @@ export class BridgeIDBTransaction      const operation = obj.operation;      let request = obj.hasOwnProperty("request") ? obj.request : null; -    if (this._state !== "active") { +    if (!this._active) {        throw new TransactionInactiveError();      } @@ -2001,10 +2079,8 @@ export class BridgeIDBTransaction            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"; -          } +          // https://www.w3.org/TR/IndexedDB-2/#fire-error-event +          this._active = true;            event = new FakeEvent("success", {              bubbles: false,              cancelable: false, @@ -2014,9 +2090,11 @@ export class BridgeIDBTransaction              event.eventPath = [request, this, this._db];              request.dispatchEvent(event);            } catch (err) { -            if (this._state !== "committing") { -              this._abort("AbortError"); +            if (BridgeIDBFactory.enableTracing) { +              console.log("TRACING: caught error in transaction success event handler");              } +            this._abort("AbortError"); +            this._active = false;              throw err;            }          } catch (err) { @@ -2028,9 +2106,7 @@ export class BridgeIDBTransaction            request.error = err;            // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-fire-an-error-event -          if (this._state === "inactive") { -            this._state = "active"; -          } +          this._active = true;            event = new FakeEvent("error", {              bubbles: true,              cancelable: true, @@ -2040,9 +2116,7 @@ export class BridgeIDBTransaction              event.eventPath = [this._db, this];              request.dispatchEvent(event);            } catch (err) { -            if (this._state !== "committing") { -              this._abort("AbortError"); -            } +            this._abort("AbortError");              throw err;            }            if (!event.canceled) { @@ -2061,17 +2135,13 @@ export class BridgeIDBTransaction        return;      } -    if (this._state !== "finished" && this._state !== "committing") { +    if (!this._finished && !this._committed) {        if (BridgeIDBFactory.enableTracing) {          console.log("finishing transaction");        } -      this._state = "committing"; -        await this._backend.commit(this._backendTransaction); - -      this._state = "finished"; - +      this._committed = true;        if (!this._error) {          if (BridgeIDBFactory.enableTracing) {            console.log("dispatching 'complete' event on transaction"); @@ -2089,15 +2159,19 @@ export class BridgeIDBTransaction        this._resolveWait();      } +    if (this._aborted) { +      this._resolveWait(); +    }    }    public commit() { -    if (this._state !== "active") { +    // The current spec doesn't even have an explicit commit method. +    // We still support it, effectively as a "no-operation" that +    // prevents new operations from being scheduled. +    if (!this._active) {        throw new InvalidStateError();      } - -    this._state = "committing"; -    // We now just wait for auto-commit ... +    this._active = false;    }    public toString() { diff --git a/packages/idb-bridge/src/idb-wpt-ported/abort-in-initial-upgradeneeded.test.ts b/packages/idb-bridge/src/idb-wpt-ported/abort-in-initial-upgradeneeded.test.ts new file mode 100644 index 000000000..da9ed2632 --- /dev/null +++ b/packages/idb-bridge/src/idb-wpt-ported/abort-in-initial-upgradeneeded.test.ts @@ -0,0 +1,34 @@ +import test from "ava"; +import { createdb } from "./wptsupport"; + +test("WPT test abort-in-initial-upgradeneeded.htm", async (t) => { +  await new Promise<void>((resolve, reject) => { +    var db: any; +    var open_rq = createdb(t, undefined, 2); + +    open_rq.onupgradeneeded = function (e) { +      const tgt = e.target as any; +      db = tgt.result; +      t.assert(db.version === 2); +      var transaction = tgt.transaction; +      transaction.oncomplete = () => t.fail("unexpected transaction.complete"); +      transaction.onabort = function (e: any) { +        console.log(`version: ${e.target.db.version}`); +        t.deepEqual(e.target.db.version, 0); +      }; +      db.onabort = function () {}; +      transaction.abort(); +    }; + +    open_rq.onerror = function (e) { +      const tgt = e.target as any; +      t.deepEqual(open_rq, e.target); +      t.deepEqual(tgt.result, undefined); +      t.deepEqual(tgt.error.name, "AbortError"); +      console.log(`version (onerror): ${db.version}`); +      t.deepEqual(db.version, 0); +      t.deepEqual(open_rq.transaction, null); +      resolve(); +    }; +  }); +}); diff --git a/packages/idb-bridge/src/idb-wpt-ported/value.test.ts b/packages/idb-bridge/src/idb-wpt-ported/value.test.ts index c4a8315c6..b1c2b3bee 100644 --- a/packages/idb-bridge/src/idb-wpt-ported/value.test.ts +++ b/packages/idb-bridge/src/idb-wpt-ported/value.test.ts @@ -24,23 +24,24 @@ test.cb("WPT test value.htm, array", (t) => {  });  test.cb("WPT test value.htm, date", (t) => { -    const value = new Date(); -    const _instanceof = Date; -   -    t.plan(1); -   -    createdb(t).onupgradeneeded = function (e: IDBVersionChangeEvent) { -      (e.target as any).result.createObjectStore("store").add(value, 1); -      (e.target as any).onsuccess = (e: any) => { -        console.log("in first onsuccess"); -        e.target.result -          .transaction("store") -          .objectStore("store") -          .get(1).onsuccess = (e: any) => { -          t.assert(e.target.result instanceof _instanceof, "instanceof"); -          t.end(); -        }; +  const value = new Date(); +  const _instanceof = Date; + +  t.plan(1); + +  createdb(t).onupgradeneeded = function (e: IDBVersionChangeEvent) { +    (e.target as any).result.createObjectStore("store").add(value, 1); +    (e.target as any).onsuccess = (e: any) => { +      console.log("in first onsuccess"); +      e.target.result +        .transaction("store") +        .objectStore("store") +        .get(1).onsuccess = (e: any) => { +          console.log("target", e.target); +          console.log("result", e.target.result); +        t.assert(e.target.result instanceof _instanceof, "instanceof"); +        t.end();        };      }; -  }); -  
\ No newline at end of file +  }; +}); diff --git a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts index 10c11b7a6..f7b065f23 100644 --- a/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts +++ b/packages/idb-bridge/src/idb-wpt-ported/wptsupport.ts @@ -23,8 +23,18 @@ export function createdb(    return rq_open;  } -export function assert_key_equals(actual: any, expected: any, description?: string) { +export function assert_key_equals( +  actual: any, +  expected: any, +  description?: string, +) {    if (0 != compareKeys(actual, expected)) {      throw Error("expected keys to be the same");    }  } + +export function assert_equals(actual: any, expected: any) { +  if (actual !== expected) { +    throw Error("assert_equals failed"); +  } +} diff --git a/packages/idb-bridge/src/util/FakeEventTarget.ts b/packages/idb-bridge/src/util/FakeEventTarget.ts index d2f46c98f..95489b4ac 100644 --- a/packages/idb-bridge/src/util/FakeEventTarget.ts +++ b/packages/idb-bridge/src/util/FakeEventTarget.ts @@ -97,13 +97,14 @@ abstract class FakeEventTarget implements EventTarget {    public readonly listeners: Listener[] = [];    // These will be overridden in individual subclasses and made not readonly -  public readonly onabort: EventListener | null | undefined; -  public readonly onblocked: EventListener | null | undefined; -  public readonly oncomplete: EventListener | null | undefined; -  public readonly onerror: EventListener | null | undefined; -  public readonly onsuccess: EventListener | null | undefined; -  public readonly onupgradeneeded: EventListener | null | undefined; -  public readonly onversionchange: EventListener | null | undefined; +  public readonly onabort: EventListener | null = null; +  public readonly onblocked: EventListener | null = null; +  public readonly oncomplete: EventListener | null = null; +  public readonly onerror: EventListener | null = null; +  public readonly onsuccess: EventListener | null = null; +  public readonly onclose: EventListener | null = null; +  public readonly onupgradeneeded: EventListener | null = null; +  public readonly onversionchange: EventListener | null = null;    static enableTracing: boolean = false; diff --git a/packages/idb-bridge/src/util/validateKeyPath.ts b/packages/idb-bridge/src/util/validateKeyPath.ts index 8057172df..2beb3c468 100644 --- a/packages/idb-bridge/src/util/validateKeyPath.ts +++ b/packages/idb-bridge/src/util/validateKeyPath.ts @@ -17,7 +17,7 @@  import { IDBKeyPath } from "../idbtypes";  // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#dfn-valid-key-path -const validateKeyPath = (keyPath: IDBKeyPath, parent?: "array" | "string") => { +const validateKeyPath = (keyPath: IDBKeyPath | 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; diff --git a/packages/idb-bridge/tsconfig.json b/packages/idb-bridge/tsconfig.json index 99c5e6e3c..4f730e1c5 100644 --- a/packages/idb-bridge/tsconfig.json +++ b/packages/idb-bridge/tsconfig.json @@ -5,6 +5,7 @@          "module": "ESNext",          "moduleResolution": "node",          "target": "ES6", +        "allowJs": true,          "noImplicitAny": true,          "outDir": "lib",          "declaration": true, | 
