From a2d0c77ba653d9a9abba971620d36a217792002e Mon Sep 17 00:00:00 2001 From: Pavel Tiunov Date: Tue, 22 Oct 2019 19:44:01 -0700 Subject: [PATCH] fix: Support `apiToken` to be an async function: first request sends incorrect token --- docs/Cube.js-Frontend/@cubejs-client-core.md | 1 + .../dist/cubejs-client-core.esm.js | 102 +++++++++++++----- .../dist/cubejs-client-core.js | 102 +++++++++++++----- .../dist/cubejs-client-core.umd.js | 102 +++++++++++++----- packages/cubejs-client-core/src/index.js | 32 ++++-- .../cubejs-react/dist/cubejs-react.umd.js | 4 +- packages/cubejs-vue/dist/cubejs-vue.umd.js | 4 +- 7 files changed, 256 insertions(+), 91 deletions(-) diff --git a/docs/Cube.js-Frontend/@cubejs-client-core.md b/docs/Cube.js-Frontend/@cubejs-client-core.md index ea0ac4a25291b..2329ed465ea6b 100644 --- a/docs/Cube.js-Frontend/@cubejs-client-core.md +++ b/docs/Cube.js-Frontend/@cubejs-client-core.md @@ -28,6 +28,7 @@ API entry point. - `apiToken` - [API token](security) is used to authorize requests and determine SQL database you're accessing. In the development mode, Cube.js Backend will print the API token to the console on on startup. +Can be an async function without arguments that returns API token. - `options` - options object. - `options.apiUrl` - URL of your Cube.js Backend. By default, in the development environment it is `http://localhost:4000/cubejs-api/v1`. diff --git a/packages/cubejs-client-core/dist/cubejs-client-core.esm.js b/packages/cubejs-client-core/dist/cubejs-client-core.esm.js index 0cee35d6c88f2..74bf18b5bdb48 100644 --- a/packages/cubejs-client-core/dist/cubejs-client-core.esm.js +++ b/packages/cubejs-client-core/dist/cubejs-client-core.esm.js @@ -842,7 +842,7 @@ function () { this.apiToken = apiToken; this.apiUrl = options.apiUrl || API_URL; this.transport = options.transport || new HttpTransport({ - authorization: apiToken, + authorization: typeof apiToken === 'function' ? undefined : apiToken, apiUrl: this.apiUrl }); this.pollInterval = options.pollInterval || 5; @@ -872,7 +872,9 @@ function () { options.mutexObj[mutexKey] = mutexValue; } - var requestInstance = request(); + var requestPromise = this.updateTransportAuthorization().then(function () { + return request(); + }); var unsubscribed = false; var checkMutex = @@ -881,29 +883,36 @@ function () { var _ref = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee() { + var requestInstance; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: + _context.next = 2; + return requestPromise; + + case 2: + requestInstance = _context.sent; + if (!(options.mutexObj && options.mutexObj[mutexKey] !== mutexValue)) { - _context.next = 6; + _context.next = 9; break; } unsubscribed = true; if (!requestInstance.unsubscribe) { - _context.next = 5; + _context.next = 8; break; } - _context.next = 5; + _context.next = 8; return requestInstance.unsubscribe(); - case 5: + case 8: throw MUTEX_ERROR; - case 6: + case 9: case "end": return _context.stop(); } @@ -922,11 +931,17 @@ function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee4(response, next) { - var subscribeNext, continueWait, token, body, error, result; + var requestInstance, subscribeNext, continueWait, body, error, result; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: + _context4.next = 2; + return requestPromise; + + case 2: + requestInstance = _context4.sent; + subscribeNext = /*#__PURE__*/ function () { @@ -1022,20 +1037,8 @@ function () { }; }(); - if (!(typeof _this.apiToken === 'function')) { - _context4.next = 7; - break; - } - - _context4.next = 5; - return _this.apiToken(); - - case 5: - token = _context4.sent; - - if (_this.transport.authorization !== token) { - _this.transport.authorization = token; - } + _context4.next = 7; + return _this.updateTransportAuthorization(); case 7: if (!(response.status === 502)) { @@ -1151,7 +1154,9 @@ function () { }; }(); - var promise = mutexPromise(requestInstance.subscribe(loadImpl)); + var promise = requestPromise.then(function (requestInstance) { + return mutexPromise(requestInstance.subscribe(loadImpl)); + }); if (callback) { return { @@ -1159,23 +1164,29 @@ function () { var _unsubscribe = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee5() { + var requestInstance; return _regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: + _context5.next = 2; + return requestPromise; + + case 2: + requestInstance = _context5.sent; unsubscribed = true; if (!requestInstance.unsubscribe) { - _context5.next = 3; + _context5.next = 6; break; } return _context5.abrupt("return", requestInstance.unsubscribe()); - case 3: + case 6: return _context5.abrupt("return", null); - case 4: + case 7: case "end": return _context5.stop(); } @@ -1192,6 +1203,44 @@ function () { return promise; } } + }, { + key: "updateTransportAuthorization", + value: function () { + var _updateTransportAuthorization = _asyncToGenerator( + /*#__PURE__*/ + _regeneratorRuntime.mark(function _callee6() { + var token; + return _regeneratorRuntime.wrap(function _callee6$(_context6) { + while (1) { + switch (_context6.prev = _context6.next) { + case 0: + if (!(typeof this.apiToken === 'function')) { + _context6.next = 5; + break; + } + + _context6.next = 3; + return this.apiToken(); + + case 3: + token = _context6.sent; + + if (this.transport.authorization !== token) { + this.transport.authorization = token; + } + + case 5: + case "end": + return _context6.stop(); + } + } + }, _callee6, this); + })); + + return function updateTransportAuthorization() { + return _updateTransportAuthorization.apply(this, arguments); + }; + }() /** * Fetch data for passed `query`. * @@ -1306,6 +1355,7 @@ function () { * @name cubejs * @param apiToken - [API token](security) is used to authorize requests and determine SQL database you're accessing. * In the development mode, Cube.js Backend will print the API token to the console on on startup. + * Can be an async function without arguments that returns API token. * @param options - options object. * @param options.apiUrl - URL of your Cube.js Backend. * By default, in the development environment it is `http://localhost:4000/cubejs-api/v1`. diff --git a/packages/cubejs-client-core/dist/cubejs-client-core.js b/packages/cubejs-client-core/dist/cubejs-client-core.js index b8744cf948551..879fada137d70 100644 --- a/packages/cubejs-client-core/dist/cubejs-client-core.js +++ b/packages/cubejs-client-core/dist/cubejs-client-core.js @@ -848,7 +848,7 @@ function () { this.apiToken = apiToken; this.apiUrl = options.apiUrl || API_URL; this.transport = options.transport || new HttpTransport({ - authorization: apiToken, + authorization: typeof apiToken === 'function' ? undefined : apiToken, apiUrl: this.apiUrl }); this.pollInterval = options.pollInterval || 5; @@ -878,7 +878,9 @@ function () { options.mutexObj[mutexKey] = mutexValue; } - var requestInstance = request(); + var requestPromise = this.updateTransportAuthorization().then(function () { + return request(); + }); var unsubscribed = false; var checkMutex = @@ -887,29 +889,36 @@ function () { var _ref = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee() { + var requestInstance; return _regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: + _context.next = 2; + return requestPromise; + + case 2: + requestInstance = _context.sent; + if (!(options.mutexObj && options.mutexObj[mutexKey] !== mutexValue)) { - _context.next = 6; + _context.next = 9; break; } unsubscribed = true; if (!requestInstance.unsubscribe) { - _context.next = 5; + _context.next = 8; break; } - _context.next = 5; + _context.next = 8; return requestInstance.unsubscribe(); - case 5: + case 8: throw MUTEX_ERROR; - case 6: + case 9: case "end": return _context.stop(); } @@ -928,11 +937,17 @@ function () { var _ref2 = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee4(response, next) { - var subscribeNext, continueWait, token, body, error, result; + var requestInstance, subscribeNext, continueWait, body, error, result; return _regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: + _context4.next = 2; + return requestPromise; + + case 2: + requestInstance = _context4.sent; + subscribeNext = /*#__PURE__*/ function () { @@ -1028,20 +1043,8 @@ function () { }; }(); - if (!(typeof _this.apiToken === 'function')) { - _context4.next = 7; - break; - } - - _context4.next = 5; - return _this.apiToken(); - - case 5: - token = _context4.sent; - - if (_this.transport.authorization !== token) { - _this.transport.authorization = token; - } + _context4.next = 7; + return _this.updateTransportAuthorization(); case 7: if (!(response.status === 502)) { @@ -1157,7 +1160,9 @@ function () { }; }(); - var promise = mutexPromise(requestInstance.subscribe(loadImpl)); + var promise = requestPromise.then(function (requestInstance) { + return mutexPromise(requestInstance.subscribe(loadImpl)); + }); if (callback) { return { @@ -1165,23 +1170,29 @@ function () { var _unsubscribe = _asyncToGenerator( /*#__PURE__*/ _regeneratorRuntime.mark(function _callee5() { + var requestInstance; return _regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: + _context5.next = 2; + return requestPromise; + + case 2: + requestInstance = _context5.sent; unsubscribed = true; if (!requestInstance.unsubscribe) { - _context5.next = 3; + _context5.next = 6; break; } return _context5.abrupt("return", requestInstance.unsubscribe()); - case 3: + case 6: return _context5.abrupt("return", null); - case 4: + case 7: case "end": return _context5.stop(); } @@ -1198,6 +1209,44 @@ function () { return promise; } } + }, { + key: "updateTransportAuthorization", + value: function () { + var _updateTransportAuthorization = _asyncToGenerator( + /*#__PURE__*/ + _regeneratorRuntime.mark(function _callee6() { + var token; + return _regeneratorRuntime.wrap(function _callee6$(_context6) { + while (1) { + switch (_context6.prev = _context6.next) { + case 0: + if (!(typeof this.apiToken === 'function')) { + _context6.next = 5; + break; + } + + _context6.next = 3; + return this.apiToken(); + + case 3: + token = _context6.sent; + + if (this.transport.authorization !== token) { + this.transport.authorization = token; + } + + case 5: + case "end": + return _context6.stop(); + } + } + }, _callee6, this); + })); + + return function updateTransportAuthorization() { + return _updateTransportAuthorization.apply(this, arguments); + }; + }() /** * Fetch data for passed `query`. * @@ -1312,6 +1361,7 @@ function () { * @name cubejs * @param apiToken - [API token](security) is used to authorize requests and determine SQL database you're accessing. * In the development mode, Cube.js Backend will print the API token to the console on on startup. + * Can be an async function without arguments that returns API token. * @param options - options object. * @param options.apiUrl - URL of your Cube.js Backend. * By default, in the development environment it is `http://localhost:4000/cubejs-api/v1`. diff --git a/packages/cubejs-client-core/dist/cubejs-client-core.umd.js b/packages/cubejs-client-core/dist/cubejs-client-core.umd.js index ee900355064c9..68d3586a0ba17 100644 --- a/packages/cubejs-client-core/dist/cubejs-client-core.umd.js +++ b/packages/cubejs-client-core/dist/cubejs-client-core.umd.js @@ -15168,7 +15168,7 @@ this.apiToken = apiToken; this.apiUrl = options.apiUrl || API_URL; this.transport = options.transport || new HttpTransport({ - authorization: apiToken, + authorization: typeof apiToken === 'function' ? undefined : apiToken, apiUrl: this.apiUrl }); this.pollInterval = options.pollInterval || 5; @@ -15198,7 +15198,9 @@ options.mutexObj[mutexKey] = mutexValue; } - var requestInstance = request(); + var requestPromise = this.updateTransportAuthorization().then(function () { + return request(); + }); var unsubscribed = false; var checkMutex = @@ -15207,29 +15209,36 @@ var _ref = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee() { + var requestInstance; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: + _context.next = 2; + return requestPromise; + + case 2: + requestInstance = _context.sent; + if (!(options.mutexObj && options.mutexObj[mutexKey] !== mutexValue)) { - _context.next = 6; + _context.next = 9; break; } unsubscribed = true; if (!requestInstance.unsubscribe) { - _context.next = 5; + _context.next = 8; break; } - _context.next = 5; + _context.next = 8; return requestInstance.unsubscribe(); - case 5: + case 8: throw MUTEX_ERROR; - case 6: + case 9: case "end": return _context.stop(); } @@ -15248,11 +15257,17 @@ var _ref2 = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee4(response, next) { - var subscribeNext, continueWait, token, body, error, result; + var requestInstance, subscribeNext, continueWait, body, error, result; return regeneratorRuntime.wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: + _context4.next = 2; + return requestPromise; + + case 2: + requestInstance = _context4.sent; + subscribeNext = /*#__PURE__*/ function () { @@ -15348,20 +15363,8 @@ }; }(); - if (!(typeof _this.apiToken === 'function')) { - _context4.next = 7; - break; - } - - _context4.next = 5; - return _this.apiToken(); - - case 5: - token = _context4.sent; - - if (_this.transport.authorization !== token) { - _this.transport.authorization = token; - } + _context4.next = 7; + return _this.updateTransportAuthorization(); case 7: if (!(response.status === 502)) { @@ -15477,7 +15480,9 @@ }; }(); - var promise = mutexPromise(requestInstance.subscribe(loadImpl)); + var promise = requestPromise.then(function (requestInstance) { + return mutexPromise(requestInstance.subscribe(loadImpl)); + }); if (callback) { return { @@ -15485,23 +15490,29 @@ var _unsubscribe = _asyncToGenerator( /*#__PURE__*/ regeneratorRuntime.mark(function _callee5() { + var requestInstance; return regeneratorRuntime.wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: + _context5.next = 2; + return requestPromise; + + case 2: + requestInstance = _context5.sent; unsubscribed = true; if (!requestInstance.unsubscribe) { - _context5.next = 3; + _context5.next = 6; break; } return _context5.abrupt("return", requestInstance.unsubscribe()); - case 3: + case 6: return _context5.abrupt("return", null); - case 4: + case 7: case "end": return _context5.stop(); } @@ -15518,6 +15529,44 @@ return promise; } } + }, { + key: "updateTransportAuthorization", + value: function () { + var _updateTransportAuthorization = _asyncToGenerator( + /*#__PURE__*/ + regeneratorRuntime.mark(function _callee6() { + var token; + return regeneratorRuntime.wrap(function _callee6$(_context6) { + while (1) { + switch (_context6.prev = _context6.next) { + case 0: + if (!(typeof this.apiToken === 'function')) { + _context6.next = 5; + break; + } + + _context6.next = 3; + return this.apiToken(); + + case 3: + token = _context6.sent; + + if (this.transport.authorization !== token) { + this.transport.authorization = token; + } + + case 5: + case "end": + return _context6.stop(); + } + } + }, _callee6, this); + })); + + return function updateTransportAuthorization() { + return _updateTransportAuthorization.apply(this, arguments); + }; + }() /** * Fetch data for passed `query`. * @@ -15632,6 +15681,7 @@ * @name cubejs * @param apiToken - [API token](security) is used to authorize requests and determine SQL database you're accessing. * In the development mode, Cube.js Backend will print the API token to the console on on startup. + * Can be an async function without arguments that returns API token. * @param options - options object. * @param options.apiUrl - URL of your Cube.js Backend. * By default, in the development environment it is `http://localhost:4000/cubejs-api/v1`. diff --git a/packages/cubejs-client-core/src/index.js b/packages/cubejs-client-core/src/index.js index b51333381462f..351c4351ab832 100644 --- a/packages/cubejs-client-core/src/index.js +++ b/packages/cubejs-client-core/src/index.js @@ -35,7 +35,10 @@ class CubejsApi { options = options || {}; this.apiToken = apiToken; this.apiUrl = options.apiUrl || API_URL; - this.transport = options.transport || new HttpTransport({ authorization: apiToken, apiUrl: this.apiUrl }); + this.transport = options.transport || new HttpTransport({ + authorization: typeof apiToken === 'function' ? undefined : apiToken, + apiUrl: this.apiUrl + }); this.pollInterval = options.pollInterval || 5; } @@ -57,11 +60,13 @@ class CubejsApi { options.mutexObj[mutexKey] = mutexValue; } - const requestInstance = request(); + const requestPromise = this.updateTransportAuthorization().then(() => request()); let unsubscribed = false; const checkMutex = async () => { + const requestInstance = await requestPromise; + if (options.mutexObj && options.mutexObj[mutexKey] !== mutexValue) { unsubscribed = true; if (requestInstance.unsubscribe) { @@ -72,6 +77,8 @@ class CubejsApi { }; const loadImpl = async (response, next) => { + const requestInstance = await requestPromise; + const subscribeNext = async () => { if (options.subscribe && !unsubscribed) { if (requestInstance.unsubscribe) { @@ -94,12 +101,7 @@ class CubejsApi { return null; }; - if (typeof this.apiToken === 'function') { - const token = await this.apiToken(); - if (this.transport.authorization !== token) { - this.transport.authorization = token; - } - } + await this.updateTransportAuthorization(); if (response.status === 502) { await checkMutex(); @@ -141,11 +143,13 @@ class CubejsApi { return subscribeNext(); }; - const promise = mutexPromise(requestInstance.subscribe(loadImpl)); + const promise = requestPromise.then(requestInstance => mutexPromise(requestInstance.subscribe(loadImpl))); if (callback) { return { unsubscribe: async () => { + const requestInstance = await requestPromise; + unsubscribed = true; if (requestInstance.unsubscribe) { return requestInstance.unsubscribe(); @@ -158,6 +162,15 @@ class CubejsApi { } } + async updateTransportAuthorization() { + if (typeof this.apiToken === 'function') { + const token = await this.apiToken(); + if (this.transport.authorization !== token) { + this.transport.authorization = token; + } + } + } + /** * Fetch data for passed `query`. * @@ -250,6 +263,7 @@ class CubejsApi { * @name cubejs * @param apiToken - [API token](security) is used to authorize requests and determine SQL database you're accessing. * In the development mode, Cube.js Backend will print the API token to the console on on startup. + * Can be an async function without arguments that returns API token. * @param options - options object. * @param options.apiUrl - URL of your Cube.js Backend. * By default, in the development environment it is `http://localhost:4000/cubejs-api/v1`. diff --git a/packages/cubejs-react/dist/cubejs-react.umd.js b/packages/cubejs-react/dist/cubejs-react.umd.js index 05d4a709b4ae0..51f72faa9f404 100644 --- a/packages/cubejs-react/dist/cubejs-react.umd.js +++ b/packages/cubejs-react/dist/cubejs-react.umd.js @@ -1420,7 +1420,7 @@ // Set @@toStringTag to native iterators _setToStringTag(IteratorPrototype, TAG, true); // fix for some old engines - if (!_library && typeof IteratorPrototype[ITERATOR$3] != 'function') _hide(IteratorPrototype, ITERATOR$3, returnThis); + if (typeof IteratorPrototype[ITERATOR$3] != 'function') _hide(IteratorPrototype, ITERATOR$3, returnThis); } } // fix Array#{values, @@iterator}.name in V8 / FF @@ -1429,7 +1429,7 @@ $default = function values() { return $native.call(this); }; } // Define iterator - if ((!_library || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR$3])) { + if (BUGGY || VALUES_BUG || !proto[ITERATOR$3]) { _hide(proto, ITERATOR$3, $default); } // Plug for library diff --git a/packages/cubejs-vue/dist/cubejs-vue.umd.js b/packages/cubejs-vue/dist/cubejs-vue.umd.js index 364f099c52b56..5714a5f977b33 100644 --- a/packages/cubejs-vue/dist/cubejs-vue.umd.js +++ b/packages/cubejs-vue/dist/cubejs-vue.umd.js @@ -1315,7 +1315,7 @@ // Set @@toStringTag to native iterators _setToStringTag(IteratorPrototype, TAG, true); // fix for some old engines - if (!_library && typeof IteratorPrototype[ITERATOR$3] != 'function') _hide(IteratorPrototype, ITERATOR$3, returnThis); + if (typeof IteratorPrototype[ITERATOR$3] != 'function') _hide(IteratorPrototype, ITERATOR$3, returnThis); } } // fix Array#{values, @@iterator}.name in V8 / FF @@ -1324,7 +1324,7 @@ $default = function values() { return $native.call(this); }; } // Define iterator - if ((!_library || FORCED) && (BUGGY || VALUES_BUG || !proto[ITERATOR$3])) { + if (BUGGY || VALUES_BUG || !proto[ITERATOR$3]) { _hide(proto, ITERATOR$3, $default); } // Plug for library