UNPKG

@metamask/snaps-rpc-methods

Version:
222 lines 9.23 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getDialogImplementation = exports.dialogBuilder = exports.DIALOG_APPROVAL_TYPES = void 0; const permission_controller_1 = require("@metamask/permission-controller"); const rpc_errors_1 = require("@metamask/rpc-errors"); const snaps_sdk_1 = require("@metamask/snaps-sdk"); const superstruct_1 = require("@metamask/superstruct"); const utils_1 = require("@metamask/utils"); const methodName = 'snap_dialog'; exports.DIALOG_APPROVAL_TYPES = { [snaps_sdk_1.DialogType.Alert]: `${methodName}:alert`, [snaps_sdk_1.DialogType.Confirmation]: `${methodName}:confirmation`, [snaps_sdk_1.DialogType.Prompt]: `${methodName}:prompt`, default: methodName, }; const PlaceholderStruct = (0, superstruct_1.optional)((0, superstruct_1.size)((0, superstruct_1.string)(), 1, 40)); /** * The specification builder for the `snap_dialog` permission. `snap_dialog` * lets the Snap display one of the following dialogs to the user: * - An alert, for displaying information. * - A confirmation, for accepting or rejecting some action. * - A prompt, for inputting some information. * * @param options - The specification builder options. * @param options.allowedCaveats - The optional allowed caveats for the * permission. * @param options.methodHooks - The RPC method hooks needed by the method * implementation. * @returns The specification for the `snap_dialog` permission. */ const specificationBuilder = ({ allowedCaveats = null, methodHooks, }) => { return { permissionType: permission_controller_1.PermissionType.RestrictedMethod, targetName: methodName, allowedCaveats, methodImplementation: getDialogImplementation(methodHooks), subjectTypes: [permission_controller_1.SubjectType.Snap], }; }; const methodHooks = { requestUserApproval: true, createInterface: true, getInterface: true, }; exports.dialogBuilder = Object.freeze({ targetName: methodName, specificationBuilder, methodHooks, }); const AlertParametersWithContentStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Alert), content: snaps_sdk_1.ComponentOrElementStruct, }); const AlertParametersWithIdStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Alert), id: (0, superstruct_1.string)(), }); const AlertParametersStruct = (0, snaps_sdk_1.selectiveUnion)((value) => { if ((0, utils_1.isPlainObject)(value) && (0, utils_1.hasProperty)(value, 'id')) { return AlertParametersWithIdStruct; } return AlertParametersWithContentStruct; }); const ConfirmationParametersWithContentStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Confirmation), content: snaps_sdk_1.ComponentOrElementStruct, }); const ConfirmationParametersWithIdStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Confirmation), id: (0, superstruct_1.string)(), }); const ConfirmationParametersStruct = (0, snaps_sdk_1.selectiveUnion)((value) => { if ((0, utils_1.isPlainObject)(value) && (0, utils_1.hasProperty)(value, 'id')) { return ConfirmationParametersWithIdStruct; } return ConfirmationParametersWithContentStruct; }); const PromptParametersWithContentStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Prompt), content: snaps_sdk_1.ComponentOrElementStruct, placeholder: PlaceholderStruct, }); const PromptParametersWithIdStruct = (0, superstruct_1.object)({ type: (0, snaps_sdk_1.enumValue)(snaps_sdk_1.DialogType.Prompt), id: (0, superstruct_1.string)(), placeholder: PlaceholderStruct, }); const PromptParametersStruct = (0, snaps_sdk_1.selectiveUnion)((value) => { if ((0, utils_1.isPlainObject)(value) && (0, utils_1.hasProperty)(value, 'id')) { return PromptParametersWithIdStruct; } return PromptParametersWithContentStruct; }); const DefaultParametersWithContentStruct = (0, superstruct_1.object)({ content: snaps_sdk_1.ComponentOrElementStruct, }); const DefaultParametersWithIdStruct = (0, superstruct_1.object)({ id: (0, superstruct_1.string)(), }); const DefaultParametersStruct = (0, snaps_sdk_1.selectiveUnion)((value) => { if ((0, utils_1.isPlainObject)(value) && (0, utils_1.hasProperty)(value, 'id')) { return DefaultParametersWithIdStruct; } return DefaultParametersWithContentStruct; }); const DialogParametersStruct = (0, snaps_sdk_1.selectiveUnion)((value) => { if ((0, utils_1.isPlainObject)(value) && (0, utils_1.hasProperty)(value, 'type')) { switch (value.type) { // We cannot use typedUnion here unfortunately. case snaps_sdk_1.DialogType.Alert: return AlertParametersStruct; case snaps_sdk_1.DialogType.Confirmation: return ConfirmationParametersStruct; case snaps_sdk_1.DialogType.Prompt: return PromptParametersStruct; default: throw new Error(`The "type" property must be one of: ${Object.values(snaps_sdk_1.DialogType).join(', ')}.`); } } return DefaultParametersStruct; }); /** * Builds the method implementation for `snap_dialog`. * * @param hooks - The RPC method hooks. * @param hooks.requestUserApproval - A function that creates a new Approval in the ApprovalController. * This function should return a Promise that resolves with the appropriate value when the user has approved or rejected the request. * @param hooks.createInterface - A function that creates the interface in SnapInterfaceController. * @param hooks.getInterface - A function that gets an interface from SnapInterfaceController. * @returns The method implementation which return value depends on the dialog * type, valid return types are: string, boolean, null. */ function getDialogImplementation({ requestUserApproval, createInterface, getInterface, }) { return async function dialogImplementation(args) { const { params, context: { origin }, } = args; if (!(0, utils_1.isObject)(params)) { throw rpc_errors_1.rpcErrors.invalidParams({ message: 'Invalid params: Expected params to be a single object.', }); } const validatedParams = getValidatedParams(params); const placeholder = isPromptDialog(validatedParams) ? validatedParams.placeholder : undefined; const validatedType = (0, utils_1.hasProperty)(validatedParams, 'type') ? validatedParams.type : 'default'; const approvalType = exports.DIALOG_APPROVAL_TYPES[validatedType]; if ((0, utils_1.hasProperty)(validatedParams, 'content')) { const id = await createInterface(origin, validatedParams.content); return requestUserApproval({ id: approvalType === exports.DIALOG_APPROVAL_TYPES.default ? id : undefined, origin, type: approvalType, requestData: { id, placeholder }, }); } validateInterface(origin, validatedParams.id, getInterface); return requestUserApproval({ id: approvalType === exports.DIALOG_APPROVAL_TYPES.default ? validatedParams.id : undefined, origin, type: approvalType, requestData: { id: validatedParams.id, placeholder }, }); }; } exports.getDialogImplementation = getDialogImplementation; /** * Validate that the interface ID is valid. * * @param origin - The origin of the request. * @param id - The interface ID. * @param getInterface - The function to get the interface. */ function validateInterface(origin, id, getInterface) { try { getInterface(origin, id); } catch (error) { throw rpc_errors_1.rpcErrors.invalidParams({ message: `Invalid params: ${error.message}`, }); } } /** * Gets the dialog type from the dialog parameters. * * @param params - The dialog parameters. * @returns The dialog type. */ function getDialogType(params) { return (0, utils_1.hasProperty)(params, 'type') ? params.type : undefined; } /** * Checks if the dialog parameters are for a prompt dialog. * * @param params - The dialog parameters. * @returns `true` if the dialog parameters are for a prompt dialog, `false` otherwise. */ function isPromptDialog(params) { return getDialogType(params) === snaps_sdk_1.DialogType.Prompt; } /** * Validates the confirm method `params` and returns them cast to the correct * type. Throws if validation fails. * * @param params - The unvalidated params object from the method request. * @returns The validated confirm method parameter object. */ function getValidatedParams(params) { try { return (0, superstruct_1.create)(params, DialogParametersStruct); } catch (error) { throw rpc_errors_1.rpcErrors.invalidParams({ message: `Invalid params: ${error.message}`, }); } } //# sourceMappingURL=dialog.cjs.map