diff --git a/src/matrix/storage/common.js b/src/matrix/storage/common.js index d83c3ffb..87c81e17 100644 --- a/src/matrix/storage/common.js +++ b/src/matrix/storage/common.js @@ -39,6 +39,11 @@ export class StorageError extends Error { if (typeof cause.code === "number") { fullMessage += `(code: ${cause.name}) `; } + } + if (value) { + fullMessage += `(value: ${JSON.stringify(value)}) `; + } + if (cause) { fullMessage += cause.message; } super(fullMessage); @@ -48,4 +53,8 @@ export class StorageError extends Error { this.cause = cause; this.value = value; } + + get name() { + return "StorageError"; + } } diff --git a/src/matrix/storage/idb/Store.js b/src/matrix/storage/idb/Store.js index aee5455f..8cb8fd4c 100644 --- a/src/matrix/storage/idb/Store.js +++ b/src/matrix/storage/idb/Store.js @@ -114,7 +114,7 @@ export class Store extends QueryTarget { return await reqAsPromise(this._idbStore.put(value)); } catch(err) { const originalErr = err.cause; - throw new StorageError(`put on ${this._idbStore.name} failed`, originalErr, value); + throw new StorageError(`put on ${err.databaseName}.${err.storeName} failed`, originalErr, value); } } @@ -123,11 +123,17 @@ export class Store extends QueryTarget { return await reqAsPromise(this._idbStore.add(value)); } catch(err) { const originalErr = err.cause; - throw new StorageError(`add on ${this._idbStore.name} failed`, originalErr, value); + throw new StorageError(`add on ${err.databaseName}.${err.storeName} failed`, originalErr, value); } } - delete(keyOrKeyRange) { - return reqAsPromise(this._idbStore.delete(keyOrKeyRange)); + async delete(keyOrKeyRange) { + try { + return await reqAsPromise(this._idbStore.delete(keyOrKeyRange)); + } catch(err) { + const originalErr = err.cause; + throw new StorageError(`delete on ${err.databaseName}.${err.storeName} failed`, originalErr, keyOrKeyRange); + } + } } diff --git a/src/matrix/storage/idb/utils.js b/src/matrix/storage/idb/utils.js index 610456ad..18126177 100644 --- a/src/matrix/storage/idb/utils.js +++ b/src/matrix/storage/idb/utils.js @@ -15,7 +15,18 @@ limitations under the License. */ import { StorageError } from "../common.js"; +import { readPath } from "../../../utils/validate.js"; +class WrappedDOMException extends StorageError { + constructor(request) { + // protect against browsers not implementing any of these properties by using readPath + const storeName = readPath(request, ["source", "name"], ""); + const databaseName = readPath(request, ["source", "transaction", "db", "name"], ""); + super(`Failed IDBRequest on ${databaseName}.${storeName}`, request.error); + this.storeName = storeName; + this.databaseName = databaseName; + } +} // storage keys are defined to be unsigned 32bit numbers in WebPlatform.js, which is assumed by idb export function encodeUint32(n) { @@ -37,21 +48,17 @@ export function openDatabase(name, createObjectStore, version) { return reqAsPromise(req); } -function wrapError(err) { - return new StorageError(`wrapped DOMException`, err); -} - export function reqAsPromise(req) { return new Promise((resolve, reject) => { req.addEventListener("success", event => resolve(event.target.result)); - req.addEventListener("error", event => reject(wrapError(event.target.error))); + req.addEventListener("error", event => reject(new WrappedDOMException(event.target))); }); } export function txnAsPromise(txn) { return new Promise((resolve, reject) => { txn.addEventListener("complete", resolve); - txn.addEventListener("abort", event => reject(wrapError(event.target.error))); + txn.addEventListener("abort", event => reject(new WrappedDOMException(event.target))); }); }