RESTController.js 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
  4. var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
  5. var _CoreManager = _interopRequireDefault(require("./CoreManager"));
  6. var _ParseError = _interopRequireDefault(require("./ParseError"));
  7. function ownKeys(object, enumerableOnly) {
  8. var keys = Object.keys(object);
  9. if (Object.getOwnPropertySymbols) {
  10. var symbols = Object.getOwnPropertySymbols(object);
  11. if (enumerableOnly) symbols = symbols.filter(function (sym) {
  12. return Object.getOwnPropertyDescriptor(object, sym).enumerable;
  13. });
  14. keys.push.apply(keys, symbols);
  15. }
  16. return keys;
  17. }
  18. function _objectSpread(target) {
  19. for (var i = 1; i < arguments.length; i++) {
  20. var source = arguments[i] != null ? arguments[i] : {};
  21. if (i % 2) {
  22. ownKeys(source, true).forEach(function (key) {
  23. (0, _defineProperty2.default)(target, key, source[key]);
  24. });
  25. } else if (Object.getOwnPropertyDescriptors) {
  26. Object.defineProperties(target, Object.getOwnPropertyDescriptors(source));
  27. } else {
  28. ownKeys(source).forEach(function (key) {
  29. Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
  30. });
  31. }
  32. }
  33. return target;
  34. }
  35. var XHR = null;
  36. if (typeof XMLHttpRequest !== 'undefined') {
  37. XHR = XMLHttpRequest;
  38. }
  39. var useXDomainRequest = false;
  40. if (typeof XDomainRequest !== 'undefined' && !('withCredentials' in new XMLHttpRequest())) {
  41. useXDomainRequest = true;
  42. }
  43. function ajaxIE9(method
  44. /*: string*/
  45. , url
  46. /*: string*/
  47. , data
  48. /*: any*/
  49. , options
  50. /*:: ?: FullOptions*/
  51. ) {
  52. return new Promise(function (resolve, reject) {
  53. var xdr = new XDomainRequest();
  54. xdr.onload = function () {
  55. var response;
  56. try {
  57. response = JSON.parse(xdr.responseText);
  58. } catch (e) {
  59. reject(e);
  60. }
  61. if (response) {
  62. resolve({
  63. response: response
  64. });
  65. }
  66. };
  67. xdr.onerror = xdr.ontimeout = function () {
  68. // Let's fake a real error message.
  69. var fakeResponse = {
  70. responseText: JSON.stringify({
  71. code: _ParseError.default.X_DOMAIN_REQUEST,
  72. error: 'IE\'s XDomainRequest does not supply error info.'
  73. })
  74. };
  75. reject(fakeResponse);
  76. };
  77. xdr.onprogress = function () {
  78. if (options && typeof options.progress === 'function') {
  79. options.progress(xdr.responseText);
  80. }
  81. };
  82. xdr.open(method, url);
  83. xdr.send(data);
  84. });
  85. }
  86. var RESTController = {
  87. ajax: function (method
  88. /*: string*/
  89. , url
  90. /*: string*/
  91. , data
  92. /*: any*/
  93. , headers
  94. /*:: ?: any*/
  95. , options
  96. /*:: ?: FullOptions*/
  97. ) {
  98. if (useXDomainRequest) {
  99. return ajaxIE9(method, url, data, headers, options);
  100. }
  101. var res, rej;
  102. var promise = new Promise(function (resolve, reject) {
  103. res = resolve;
  104. rej = reject;
  105. });
  106. promise.resolve = res;
  107. promise.reject = rej;
  108. var attempts = 0;
  109. var dispatch = function dispatch() {
  110. if (XHR == null) {
  111. throw new Error('Cannot make a request: No definition of XMLHttpRequest was found.');
  112. }
  113. var handled = false;
  114. var xhr = new XHR();
  115. xhr.onreadystatechange = function () {
  116. if (xhr.readyState !== 4 || handled) {
  117. return;
  118. }
  119. handled = true;
  120. if (xhr.status >= 200 && xhr.status < 300) {
  121. var response;
  122. try {
  123. response = JSON.parse(xhr.responseText);
  124. if (typeof xhr.getResponseHeader === 'function') {
  125. if ((xhr.getAllResponseHeaders() || '').includes('x-parse-job-status-id: ')) {
  126. response = xhr.getResponseHeader('x-parse-job-status-id');
  127. }
  128. }
  129. } catch (e) {
  130. promise.reject(e.toString());
  131. }
  132. if (response) {
  133. promise.resolve({
  134. response: response,
  135. status: xhr.status,
  136. xhr: xhr
  137. });
  138. }
  139. } else if (xhr.status >= 500 || xhr.status === 0) {
  140. // retry on 5XX or node-xmlhttprequest error
  141. if (++attempts < _CoreManager.default.get('REQUEST_ATTEMPT_LIMIT')) {
  142. // Exponentially-growing random delay
  143. var delay = Math.round(Math.random() * 125 * Math.pow(2, attempts));
  144. setTimeout(dispatch, delay);
  145. } else if (xhr.status === 0) {
  146. promise.reject('Unable to connect to the Parse API');
  147. } else {
  148. // After the retry limit is reached, fail
  149. promise.reject(xhr);
  150. }
  151. } else {
  152. promise.reject(xhr);
  153. }
  154. };
  155. headers = headers || {};
  156. if (typeof headers['Content-Type'] !== 'string') {
  157. headers['Content-Type'] = 'text/plain'; // Avoid pre-flight
  158. }
  159. if (_CoreManager.default.get('IS_NODE')) {
  160. headers['User-Agent'] = 'Parse/' + _CoreManager.default.get('VERSION') + ' (NodeJS ' + process.versions.node + ')';
  161. }
  162. if (_CoreManager.default.get('SERVER_AUTH_TYPE') && _CoreManager.default.get('SERVER_AUTH_TOKEN')) {
  163. headers['Authorization'] = _CoreManager.default.get('SERVER_AUTH_TYPE') + ' ' + _CoreManager.default.get('SERVER_AUTH_TOKEN');
  164. }
  165. if (options && typeof options.progress === 'function') {
  166. if (xhr.upload) {
  167. xhr.upload.addEventListener('progress', function (oEvent) {
  168. if (oEvent.lengthComputable) {
  169. options.progress(oEvent.loaded / oEvent.total);
  170. } else {
  171. options.progress(null);
  172. }
  173. });
  174. } else if (xhr.addEventListener) {
  175. xhr.addEventListener('progress', function (oEvent) {
  176. if (oEvent.lengthComputable) {
  177. options.progress(oEvent.loaded / oEvent.total);
  178. } else {
  179. options.progress(null);
  180. }
  181. });
  182. }
  183. }
  184. xhr.open(method, url, true);
  185. for (var h in headers) {
  186. xhr.setRequestHeader(h, headers[h]);
  187. }
  188. xhr.send(data);
  189. };
  190. dispatch();
  191. return promise;
  192. },
  193. request: function (method
  194. /*: string*/
  195. , path
  196. /*: string*/
  197. , data
  198. /*: mixed*/
  199. , options
  200. /*:: ?: RequestOptions*/
  201. ) {
  202. options = options || {};
  203. var url = _CoreManager.default.get('SERVER_URL');
  204. if (url[url.length - 1] !== '/') {
  205. url += '/';
  206. }
  207. url += path;
  208. var payload = {};
  209. if (data && (0, _typeof2.default)(data) === 'object') {
  210. for (var k in data) {
  211. payload[k] = data[k];
  212. }
  213. }
  214. if (method !== 'POST') {
  215. payload._method = method;
  216. method = 'POST';
  217. }
  218. payload._ApplicationId = _CoreManager.default.get('APPLICATION_ID');
  219. var jsKey = _CoreManager.default.get('JAVASCRIPT_KEY');
  220. if (jsKey) {
  221. payload._JavaScriptKey = jsKey;
  222. }
  223. payload._ClientVersion = _CoreManager.default.get('VERSION');
  224. var useMasterKey = options.useMasterKey;
  225. if (typeof useMasterKey === 'undefined') {
  226. useMasterKey = _CoreManager.default.get('USE_MASTER_KEY');
  227. }
  228. if (useMasterKey) {
  229. if (_CoreManager.default.get('MASTER_KEY')) {
  230. delete payload._JavaScriptKey;
  231. payload._MasterKey = _CoreManager.default.get('MASTER_KEY');
  232. } else {
  233. throw new Error('Cannot use the Master Key, it has not been provided.');
  234. }
  235. }
  236. if (_CoreManager.default.get('FORCE_REVOCABLE_SESSION')) {
  237. payload._RevocableSession = '1';
  238. }
  239. var installationId = options.installationId;
  240. var installationIdPromise;
  241. if (installationId && typeof installationId === 'string') {
  242. installationIdPromise = Promise.resolve(installationId);
  243. } else {
  244. var installationController = _CoreManager.default.getInstallationController();
  245. installationIdPromise = installationController.currentInstallationId();
  246. }
  247. return installationIdPromise.then(function (iid) {
  248. payload._InstallationId = iid;
  249. var userController = _CoreManager.default.getUserController();
  250. if (options && typeof options.sessionToken === 'string') {
  251. return Promise.resolve(options.sessionToken);
  252. } else if (userController) {
  253. return userController.currentUserAsync().then(function (user) {
  254. if (user) {
  255. return Promise.resolve(user.getSessionToken());
  256. }
  257. return Promise.resolve(null);
  258. });
  259. }
  260. return Promise.resolve(null);
  261. }).then(function (token) {
  262. if (token) {
  263. payload._SessionToken = token;
  264. }
  265. var payloadString = JSON.stringify(payload);
  266. return RESTController.ajax(method, url, payloadString, {}, options).then(function (_ref) {
  267. var response = _ref.response,
  268. status = _ref.status;
  269. if (options.returnStatus) {
  270. return _objectSpread({}, response, {
  271. _status: status
  272. });
  273. } else {
  274. return response;
  275. }
  276. });
  277. }).catch(function (response
  278. /*: { responseText: string }*/
  279. ) {
  280. // Transform the error into an instance of ParseError by trying to parse
  281. // the error string as JSON
  282. var error;
  283. if (response && response.responseText) {
  284. try {
  285. var errorJSON = JSON.parse(response.responseText);
  286. error = new _ParseError.default(errorJSON.code, errorJSON.error);
  287. } catch (e) {
  288. // If we fail to parse the error text, that's okay.
  289. error = new _ParseError.default(_ParseError.default.INVALID_JSON, 'Received an error with invalid JSON from Parse: ' + response.responseText);
  290. }
  291. } else {
  292. error = new _ParseError.default(_ParseError.default.CONNECTION_FAILED, 'XMLHttpRequest failed: ' + JSON.stringify(response));
  293. }
  294. return Promise.reject(error);
  295. });
  296. },
  297. _setXHR: function (xhr
  298. /*: any*/
  299. ) {
  300. XHR = xhr;
  301. }
  302. };
  303. module.exports = RESTController;