@metamask/snaps-utils
Version:
A collection of utilities for MetaMask Snaps
189 lines • 7.99 kB
JavaScript
"use strict";
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _WrappedSnapError_error, _WrappedSnapError_message, _WrappedSnapError_stack;
Object.defineProperty(exports, "__esModule", { value: true });
exports.unwrapError = exports.isWrappedSnapError = exports.isSerializedSnapError = exports.isSnapError = exports.WrappedSnapError = exports.SNAP_ERROR_WRAPPER_MESSAGE = exports.SNAP_ERROR_WRAPPER_CODE = void 0;
const rpc_errors_1 = require("@metamask/rpc-errors");
const snaps_sdk_1 = require("@metamask/snaps-sdk");
const utils_1 = require("@metamask/utils");
exports.SNAP_ERROR_WRAPPER_CODE = -31001;
exports.SNAP_ERROR_WRAPPER_MESSAGE = 'Wrapped Snap Error';
class WrappedSnapError extends Error {
/**
* Create a new `WrappedSnapError`.
*
* @param error - The error to create the `WrappedSnapError` from.
*/
constructor(error) {
const message = (0, snaps_sdk_1.getErrorMessage)(error);
super(message);
_WrappedSnapError_error.set(this, void 0);
_WrappedSnapError_message.set(this, void 0);
_WrappedSnapError_stack.set(this, void 0);
__classPrivateFieldSet(this, _WrappedSnapError_error, error, "f");
__classPrivateFieldSet(this, _WrappedSnapError_message, message, "f");
__classPrivateFieldSet(this, _WrappedSnapError_stack, (0, snaps_sdk_1.getErrorStack)(error), "f");
}
/**
* The error name.
*
* @returns The error name.
*/
get name() {
return 'WrappedSnapError';
}
/**
* The error message.
*
* @returns The error message.
*/
get message() {
return __classPrivateFieldGet(this, _WrappedSnapError_message, "f");
}
/**
* The error stack.
*
* @returns The error stack.
*/
get stack() {
return __classPrivateFieldGet(this, _WrappedSnapError_stack, "f");
}
/**
* Convert the error to a JSON object.
*
* @returns The JSON object.
*/
toJSON() {
const cause = isSnapError(__classPrivateFieldGet(this, _WrappedSnapError_error, "f"))
? __classPrivateFieldGet(this, _WrappedSnapError_error, "f").serialize()
: (0, rpc_errors_1.serializeCause)(__classPrivateFieldGet(this, _WrappedSnapError_error, "f"));
return {
code: exports.SNAP_ERROR_WRAPPER_CODE,
message: exports.SNAP_ERROR_WRAPPER_MESSAGE,
data: {
cause,
},
};
}
/**
* Serialize the error to a JSON object. This is called by
* `@metamask/rpc-errors` when serializing the error.
*
* @returns The JSON object.
*/
serialize() {
return this.toJSON();
}
}
exports.WrappedSnapError = WrappedSnapError;
_WrappedSnapError_error = new WeakMap(), _WrappedSnapError_message = new WeakMap(), _WrappedSnapError_stack = new WeakMap();
/**
* Check if an object is a `SnapError`.
*
* @param error - The object to check.
* @returns Whether the object is a `SnapError`.
*/
function isSnapError(error) {
if ((0, utils_1.isObject)(error) &&
'serialize' in error &&
typeof error.serialize === 'function') {
const serialized = error.serialize();
return (0, utils_1.isJsonRpcError)(serialized) && isSerializedSnapError(serialized);
}
return false;
}
exports.isSnapError = isSnapError;
/**
* Check if a JSON-RPC error is a `SnapError`.
*
* @param error - The object to check.
* @returns Whether the object is a `SnapError`.
*/
function isSerializedSnapError(error) {
return error.code === snaps_sdk_1.SNAP_ERROR_CODE && error.message === snaps_sdk_1.SNAP_ERROR_MESSAGE;
}
exports.isSerializedSnapError = isSerializedSnapError;
/**
* Check if a JSON-RPC error is a `WrappedSnapError`.
*
* @param error - The object to check.
* @returns Whether the object is a `WrappedSnapError`.
*/
function isWrappedSnapError(error) {
return ((0, utils_1.isJsonRpcError)(error) &&
error.code === exports.SNAP_ERROR_WRAPPER_CODE &&
error.message === exports.SNAP_ERROR_WRAPPER_MESSAGE);
}
exports.isWrappedSnapError = isWrappedSnapError;
/**
* Get a JSON-RPC error with the given code, message, stack, and data.
*
* @param code - The error code.
* @param message - The error message.
* @param stack - The error stack.
* @param data - Additional data for the error.
* @returns The JSON-RPC error.
*/
function getJsonRpcError(code, message, stack, data) {
const error = new rpc_errors_1.JsonRpcError(code, message, data);
error.stack = stack;
return error;
}
/**
* Attempt to unwrap an unknown error to a `JsonRpcError`. This function will
* try to get the error code, message, and data from the error, and return a
* `JsonRpcError` with those properties.
*
* @param error - The error to unwrap.
* @returns A tuple containing the unwrapped error and a boolean indicating
* whether the error was handled.
*/
function unwrapError(error) {
// This logic is a bit complicated, but it's necessary to handle all the
// different types of errors that can be thrown by a Snap.
// If the error is a wrapped Snap error, unwrap it.
if (isWrappedSnapError(error)) {
// The wrapped error can be a JSON-RPC error, or an unknown error. If it's
// a JSON-RPC error, we can unwrap it further.
if ((0, utils_1.isJsonRpcError)(error.data.cause)) {
// If the JSON-RPC error is a wrapped Snap error, unwrap it further.
if (isSerializedSnapError(error.data.cause)) {
const { code, message, stack, data } = error.data.cause.data.cause;
return [getJsonRpcError(code, message, stack, data), true];
}
// Otherwise, we use the original JSON-RPC error.
const { code, message, stack, data } = error.data.cause;
return [getJsonRpcError(code, message, stack, data), false];
}
// Otherwise, we throw an internal error with the wrapped error as the
// message.
return [
getJsonRpcError(rpc_errors_1.errorCodes.rpc.internal, (0, snaps_sdk_1.getErrorMessage)(error.data.cause), (0, snaps_sdk_1.getErrorStack)(error.data.cause)),
false,
];
}
// The error can be a non-wrapped JSON-RPC error, in which case we can just
// re-throw it with the same code, message, and data.
if ((0, utils_1.isJsonRpcError)(error)) {
const { code, message, stack, data } = error;
return [getJsonRpcError(code, message, stack, data), false];
}
// If the error is not a wrapped error, we don't know how to handle it, so we
// throw an internal error with the error as the message.
return [
getJsonRpcError(rpc_errors_1.errorCodes.rpc.internal, (0, snaps_sdk_1.getErrorMessage)(error), (0, snaps_sdk_1.getErrorStack)(error)),
false,
];
}
exports.unwrapError = unwrapError;
//# sourceMappingURL=errors.cjs.map