{"version":3,"file":"invokeSnap.mjs","sourceRoot":"","sources":["../../src/restricted/invokeSnap.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,cAAc,EAAE,wCAAwC;AACjE,OAAO,EAAE,SAAS,EAAE,6BAA6B;AAOjD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,8BAA8B;AAKpE,MAAM,CAAC,MAAM,0BAA0B,GAAG,aAAa,CAAC;AAsCxD;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAGX,KAAK,EAAE,EAAE,WAAW,EAAE,SAAS,EAAE,EAAE,EAAE;IACtD,MAAM,KAAK,GAAG,WAAW,CAAC,WAAW,CAAC,0BAA0B,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;SAC3E,KAA2B,CAAC;IAE/B,MAAM,cAAc,GAAG,SAAS,CAAC,IAAI,CACnC,kCAAkC,EAClC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAC5B,CAAC;IAEF,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,CAC5C,CAAC,aAAa,EAAE,IAAI,EAAE,EAAE;QACtB,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,aAAa,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,CAAC;QACD,OAAO,aAAa,CAAC;IACvB,CAAC,EACD,EAAE,CACH,CAAC;IAEF,OAAO,SAAS,CAAC,IAAI,CACnB,6BAA6B,EAC7B,WAAW,CAAC,QAAQ,CAAC,MAAM,EAC3B,YAAY,CACb,CAAC;AACJ,CAAC,CAAC;AACF;;;;;;;;;;;GAWG;AACH,MAAM,oBAAoB,GAItB,CAAC,EAAE,SAAS,EAAyC,EAAE,EAAE;IAC3D,OAAO;QACL,cAAc,EAAE,cAAc,CAAC,gBAAgB;QAC/C,UAAU,EAAE,0BAA0B;QACtC,cAAc,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC;QACxC,oBAAoB,EAAE,2BAA2B,CAAC;YAChD,SAAS;SACV,CAAC;QACF,SAAS,EAAE,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE;YACzB,IAAI,OAAO,EAAE,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,cAAc,CAAC,OAAO,EAAE,CAAC;gBACxE,MAAM,SAAS,CAAC,aAAa,CAAC;oBAC5B,OAAO,EAAE,sBAAsB,cAAc,CAAC,OAAO,WAAW;iBACjE,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QACD,UAAU,EAAE;YACV,WAAW,EAAE,iBAAiB;SAC/B;KACF,CAAC;AACJ,CAAC,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,MAAM,CAAC,MAAM,CAAC;IAC7C,UAAU,EAAE,0BAA0B;IACtC,oBAAoB;IACpB,WAAW,EAAE,CAAC,8BAA8B,CAAC;CACrC,CAAC,CAAC;AAEZ;;;;;;;GAOG;AACH,MAAM,UAAU,2BAA2B,CAAC,EAC1C,SAAS,GAC6B;IACtC,OAAO,KAAK,UAAU,UAAU,CAC9B,OAAkD;QAElD,MAAM,EAAE,MAAM,GAAG,EAAE,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAEzC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,MAA0B,CAAC;QAEvD,MAAM,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC;QAE3B,OAAO,CAAC,MAAM,SAAS,CAAC,IAAI,CAAC,8BAA8B,EAAE;YAC3D,MAAM;YACN,MAAM;YACN,OAAO;YACP,OAAO,EAAE,WAAW,CAAC,YAAY;SAClC,CAAC,CAAS,CAAC;IACd,CAAC,CAAC;AACJ,CAAC","sourcesContent":["import type { Messenger } from '@metamask/messenger';\nimport type {\n  PermissionSpecificationBuilder,\n  RestrictedMethodOptions,\n  ValidPermissionSpecification,\n  PermissionValidatorConstraint,\n  PermissionSideEffect,\n} from '@metamask/permission-controller';\nimport { PermissionType } from '@metamask/permission-controller';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport type {\n  InvokeSnapParams,\n  InvokeSnapResult,\n  RequestSnapsParams,\n  RequestSnapsResult,\n} from '@metamask/snaps-sdk';\nimport { HandlerType, SnapCaveatType } from '@metamask/snaps-utils';\nimport type { Json, NonEmptyArray } from '@metamask/utils';\n\nimport type { SnapControllerHandleRequestAction } from '../types';\n\nexport const WALLET_SNAP_PERMISSION_KEY = 'wallet_snap';\n\n// Redeclare installSnaps action type to avoid circular dependencies\nexport type SnapControllerInstallSnapsAction = {\n  type: `SnapController:installSnaps`;\n  handler: (\n    origin: string,\n    requestedSnaps: RequestSnapsParams,\n  ) => Promise<RequestSnapsResult>;\n};\n\nexport type SnapControllerGetPermittedSnapsAction = {\n  type: `SnapController:getPermittedSnaps`;\n  handler: (origin: string) => RequestSnapsResult;\n};\n\ntype AllowedActions =\n  | SnapControllerInstallSnapsAction\n  | SnapControllerGetPermittedSnapsAction;\n\nexport type InvokeSnapMessengerActions = SnapControllerHandleRequestAction;\n\ntype InvokeSnapSpecificationBuilderOptions = {\n  allowedCaveats?: Readonly<NonEmptyArray<string>> | null;\n  messenger: Messenger<string, InvokeSnapMessengerActions>;\n};\n\ntype InvokeSnapSpecification = ValidPermissionSpecification<{\n  permissionType: PermissionType.RestrictedMethod;\n  targetName: typeof WALLET_SNAP_PERMISSION_KEY;\n  methodImplementation: ReturnType<typeof getInvokeSnapImplementation>;\n  allowedCaveats: Readonly<NonEmptyArray<string>> | null;\n  validator: PermissionValidatorConstraint;\n  sideEffect: {\n    onPermitted: PermissionSideEffect<AllowedActions, never>['onPermitted'];\n  };\n}>;\n\n/**\n * The side-effect method to handle the snap install.\n *\n * @param params - The side-effect params.\n * @param params.requestData - The request data associated to the requested permission.\n * @param params.messenger - The messenger to call an action.\n * @returns The result of the Snap installation.\n */\nexport const handleSnapInstall: PermissionSideEffect<\n  AllowedActions,\n  never\n>['onPermitted'] = async ({ requestData, messenger }) => {\n  const snaps = requestData.permissions[WALLET_SNAP_PERMISSION_KEY].caveats?.[0]\n    .value as RequestSnapsParams;\n\n  const permittedSnaps = messenger.call(\n    `SnapController:getPermittedSnaps`,\n    requestData.metadata.origin,\n  );\n\n  const dedupedSnaps = Object.keys(snaps).reduce<RequestSnapsParams>(\n    (filteredSnaps, snap) => {\n      if (!permittedSnaps[snap]) {\n        filteredSnaps[snap] = snaps[snap];\n      }\n      return filteredSnaps;\n    },\n    {},\n  );\n\n  return messenger.call(\n    `SnapController:installSnaps`,\n    requestData.metadata.origin,\n    dedupedSnaps,\n  );\n};\n/**\n * The specification builder for the `wallet_snap_*` permission.\n *\n * `wallet_snap_*` attempts to invoke an RPC method of the specified Snap.\n *\n * Requesting its corresponding permission will attempt to connect to the Snap,\n * and install it if it's not available yet.\n *\n * @param options - The specification builder options.\n * @param options.messenger - The messenger.\n * @returns The specification for the `wallet_snap_*` permission.\n */\nconst specificationBuilder: PermissionSpecificationBuilder<\n  PermissionType.RestrictedMethod,\n  InvokeSnapSpecificationBuilderOptions,\n  InvokeSnapSpecification\n> = ({ messenger }: InvokeSnapSpecificationBuilderOptions) => {\n  return {\n    permissionType: PermissionType.RestrictedMethod,\n    targetName: WALLET_SNAP_PERMISSION_KEY,\n    allowedCaveats: [SnapCaveatType.SnapIds],\n    methodImplementation: getInvokeSnapImplementation({\n      messenger,\n    }),\n    validator: ({ caveats }) => {\n      if (caveats?.length !== 1 || caveats[0].type !== SnapCaveatType.SnapIds) {\n        throw rpcErrors.invalidParams({\n          message: `Expected a single \"${SnapCaveatType.SnapIds}\" caveat.`,\n        });\n      }\n    },\n    sideEffect: {\n      onPermitted: handleSnapInstall,\n    },\n  };\n};\n\n/**\n * Calls the specified JSON-RPC API method of the specified Snap. The Snap\n * must be installed and the dapp must have permission to communicate with the\n * Snap, or the request is rejected. The dapp can install the Snap and request\n * permission to communicate with it using\n * [`wallet_requestSnaps`](http://docs.metamask.io/snaps/reference/snaps-api/wallet_requestsnaps).\n *\n * @example\n * ```ts\n * const result = await ethereum.request({\n *   method: 'wallet_snap',\n *   params: {\n *     snapId: 'npm:my-snap',\n *     request: {\n *       method: 'hello',\n *       params: { name: 'world' },\n *     },\n *   },\n * });\n * console.log(result); // \"Hello, world!\"\n * ```\n */\nexport const invokeSnapBuilder = Object.freeze({\n  targetName: WALLET_SNAP_PERMISSION_KEY,\n  specificationBuilder,\n  actionNames: ['SnapController:handleRequest'],\n} as const);\n\n/**\n * Builds the method implementation for `wallet_snap_*`.\n *\n * @param options - The options.\n * @param options.messenger - The messenger.\n * @returns The method implementation which returns the result of `SnapController:handleRequest`.\n * @throws If the params are invalid.\n */\nexport function getInvokeSnapImplementation({\n  messenger,\n}: InvokeSnapSpecificationBuilderOptions) {\n  return async function invokeSnap(\n    options: RestrictedMethodOptions<InvokeSnapParams>,\n  ): Promise<InvokeSnapResult> {\n    const { params = {}, context } = options;\n\n    const { snapId, request } = params as InvokeSnapParams;\n\n    const { origin } = context;\n\n    return (await messenger.call('SnapController:handleRequest', {\n      snapId,\n      origin,\n      request,\n      handler: HandlerType.OnRpcRequest,\n    })) as Json;\n  };\n}\n"]}