RESTController.js 13 KB

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