Improve IDB error reporting

Hope this can help with
https://github.com/vector-im/hydrogen-web/issues/50
This commit is contained in:
Bruno Windels 2020-08-18 17:27:40 +02:00
parent 991f5fee4c
commit cc4c9d7893
3 changed files with 32 additions and 10 deletions

View file

@ -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";
}
}

View file

@ -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);
}
}
}

View file

@ -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"], "<unknown store>");
const databaseName = readPath(request, ["source", "transaction", "db", "name"], "<unknown db>");
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)));
});
}