graphql icon indicating copy to clipboard operation
graphql copied to clipboard

Runs outside Fiber while using inside a Meteor package

Open kamilkisiela opened this issue 8 years ago • 2 comments

Issue

The issue occurs when using @accounts/graphql-api inside of a meteor package. If we'd create the same logic but inside an app, it'd work.

const resolver = {
  User: {
    foo: () => FooCollection.findOne()
  }
};
mutation login {
  loginWithPassword( /*...*/ ) {
    user {
      username
      foo {
        id
      }
    }
  }
}

Gives:

{
  "data": {
    "loginWithPassword": {
      "user": {
        "username": "foo",
        "foo": null
      }
    }
  },
  "errors": [
    {
      "message": "Can't wait without a fiber",
      "locations": [
        {
          "line": 5,
          "column": 7
        }
      ],
      "path": [
        "loginWithPassword",
        "user",
        "foo"
      ]
    }
  ]
}

Reproduction

Run it and go to http://localhost:3000. It should display SUCCESS or FAILURE.

Failure:

Meteor@1.5.2 or less https://github.com/kamilkisiela/js-accounts-meteor-fiber/tree/failure

Success:

Meteor@1.6-alpha.0 at least https://github.com/kamilkisiela/js-accounts-meteor-fiber/tree/success

Differences

https://github.com/kamilkisiela/js-accounts-meteor-fiber/compare/failure...success

Idea

For me it's something to do with async/await and Promise. async/await is being compiled to something that uses asyncGeneratorFunction from babel-runtime's helpers and there's a Promise inside of it. For me, that Promise is not wrapped with a Fiber as it'd normally be in Meteor's environment.

kamilkisiela avatar Sep 02 '17 19:09 kamilkisiela

babel-runtime/helpers/asyncToGenerator module uses a Promise from the core-js package.

Inside of core-js:

https://github.com/zloirock/core-js/blob/9bf000955a615307254cdb8861bfdc19c7184d77/library/modules/es6.promise.js#L26-L36

As you can see, USE_NATIVE value is boolean that tells if it should use native Promise or a polyfill.

I did some deep digging and it seems like at the time when an anonymous function executes to return a value for USE_NATIVE, there is a Promise available and it's wrapped with Fiber which is what we're looking for.

USE_NATIVE should be true but it's false. It happens because inside the try/catch an error occurs.

TypeError: es6PromiseThen.call is not a function

It points to this part of a code from meteor-promise package:

https://github.com/meteor/promise/blob/master/promise_server.js#L29-L33

kamilkisiela avatar Sep 07 '17 12:09 kamilkisiela

Thanks for the research @kamilkisiela! I've actually faced this issue myself in a recent project (not in a package) and have just used the rawCollection() function of the meteor collection in order to get the native mongo driver Collection object and then ran my queries as documented by mongo.

I guess there is not much we can do here but wait to 1.6 to release and it will just give us a free fix :)

Leaving this open for anyone else that faces this issue.

davidyaha avatar Sep 09 '17 13:09 davidyaha