I have a Greasemonkey userscript which runs most of its code in an unprivileged context by inserting a <script> tag like so:
function code {
  ...
}
var script = document.createElement("script");
script.type = "application/javascript";
script.innerHTML = "(" + code + ")();";
document.body.appendChild(script);
This avoids the need to do dangerous things with unsafeWindow.
However, I my code needs to get information from an API on another domain which doesn't support JSONP.  GM_xmlhttpRequest can access other domains, but is only available in the privileged Greasemonkey context.
I'd like to write a function which provides a limited interface and makes exactly the API call I need using GM_xmlhttpRequest, and then expose that (theoretically safe) function to the normal page context.  My first attempt at that was something like:
unsafeWindow.foo = function() {
  console.log("Foo!");
  console.log(GM_xmlhttpRequest.toString());
  GM_xmlhttpRequest({
    method: "GET",
    url: "http://www.example.net/",
    headers: {
      "User-Agent": navigator.userAgent,
      "Accept": "text/html"
    },
    onload: function(response) {
      console.log(response);
      unsafeWindow.console.log(response);
      alert(response);
      unsafeWindow.alert(response);
    }
  });
  console.log("Bar!");
};
Interestingly, when I call foo() from the page context, I see "Foo!", the stringified GM_xmlhttpRequest and "Bar!" in the console log.  However, I never get the response in the console or in an alert.  If I make the GM_xmlhttpRequest on its own in the GM context, I get both alerts and log messages.
The question is: is what I'm trying to do even possible? Or is there another way to accomplish the same thing?