RequestClient.js 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. 'use strict';
  2. let _Symbol$for;
  3. function _classPrivateFieldLooseBase(receiver, privateKey) { if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) { throw new TypeError("attempted to use private field on non-instance"); } return receiver; }
  4. var id = 0;
  5. function _classPrivateFieldLooseKey(name) { return "__private_" + id++ + "_" + name; }
  6. const fetchWithNetworkError = require("@uppy/utils/lib/fetchWithNetworkError");
  7. const ErrorWithCause = require("@uppy/utils/lib/ErrorWithCause");
  8. const AuthError = require("./AuthError.js");
  9. const packageJson = {
  10. "version": "2.2.2"
  11. }; // Remove the trailing slash so we can always safely append /xyz.
  12. function stripSlash(url) {
  13. return url.replace(/\/$/, '');
  14. }
  15. async function handleJSONResponse(res) {
  16. if (res.status === 401) {
  17. throw new AuthError();
  18. }
  19. const jsonPromise = res.json();
  20. if (res.status < 200 || res.status > 300) {
  21. let errMsg = `Failed request with status: ${res.status}. ${res.statusText}`;
  22. try {
  23. const errData = await jsonPromise;
  24. errMsg = errData.message ? `${errMsg} message: ${errData.message}` : errMsg;
  25. errMsg = errData.requestId ? `${errMsg} request-Id: ${errData.requestId}` : errMsg;
  26. } finally {
  27. // eslint-disable-next-line no-unsafe-finally
  28. throw new Error(errMsg);
  29. }
  30. }
  31. return jsonPromise;
  32. }
  33. var _companionHeaders = /*#__PURE__*/_classPrivateFieldLooseKey("companionHeaders");
  34. var _getPostResponseFunc = /*#__PURE__*/_classPrivateFieldLooseKey("getPostResponseFunc");
  35. var _getUrl = /*#__PURE__*/_classPrivateFieldLooseKey("getUrl");
  36. var _errorHandler = /*#__PURE__*/_classPrivateFieldLooseKey("errorHandler");
  37. _Symbol$for = Symbol.for('uppy test: getCompanionHeaders');
  38. class RequestClient {
  39. constructor(uppy, opts) {
  40. Object.defineProperty(this, _errorHandler, {
  41. value: _errorHandler2
  42. });
  43. Object.defineProperty(this, _getUrl, {
  44. value: _getUrl2
  45. });
  46. Object.defineProperty(this, _companionHeaders, {
  47. writable: true,
  48. value: void 0
  49. });
  50. Object.defineProperty(this, _getPostResponseFunc, {
  51. writable: true,
  52. value: skip => response => skip ? response : this.onReceiveResponse(response)
  53. });
  54. this.uppy = uppy;
  55. this.opts = opts;
  56. this.onReceiveResponse = this.onReceiveResponse.bind(this);
  57. this.allowedHeaders = ['accept', 'content-type', 'uppy-auth-token'];
  58. this.preflightDone = false;
  59. _classPrivateFieldLooseBase(this, _companionHeaders)[_companionHeaders] = opts == null ? void 0 : opts.companionHeaders;
  60. }
  61. setCompanionHeaders(headers) {
  62. _classPrivateFieldLooseBase(this, _companionHeaders)[_companionHeaders] = headers;
  63. }
  64. [_Symbol$for]() {
  65. return _classPrivateFieldLooseBase(this, _companionHeaders)[_companionHeaders];
  66. }
  67. get hostname() {
  68. const {
  69. companion
  70. } = this.uppy.getState();
  71. const host = this.opts.companionUrl;
  72. return stripSlash(companion && companion[host] ? companion[host] : host);
  73. }
  74. headers() {
  75. return Promise.resolve({ ...RequestClient.defaultHeaders,
  76. ..._classPrivateFieldLooseBase(this, _companionHeaders)[_companionHeaders]
  77. });
  78. }
  79. onReceiveResponse(response) {
  80. const state = this.uppy.getState();
  81. const companion = state.companion || {};
  82. const host = this.opts.companionUrl;
  83. const {
  84. headers
  85. } = response; // Store the self-identified domain name for the Companion instance we just hit.
  86. if (headers.has('i-am') && headers.get('i-am') !== companion[host]) {
  87. this.uppy.setState({
  88. companion: { ...companion,
  89. [host]: headers.get('i-am')
  90. }
  91. });
  92. }
  93. return response;
  94. }
  95. preflight(path) {
  96. if (this.preflightDone) {
  97. return Promise.resolve(this.allowedHeaders.slice());
  98. }
  99. return fetch(_classPrivateFieldLooseBase(this, _getUrl)[_getUrl](path), {
  100. method: 'OPTIONS'
  101. }).then(response => {
  102. if (response.headers.has('access-control-allow-headers')) {
  103. this.allowedHeaders = response.headers.get('access-control-allow-headers').split(',').map(headerName => headerName.trim().toLowerCase());
  104. }
  105. this.preflightDone = true;
  106. return this.allowedHeaders.slice();
  107. }).catch(err => {
  108. this.uppy.log(`[CompanionClient] unable to make preflight request ${err}`, 'warning');
  109. this.preflightDone = true;
  110. return this.allowedHeaders.slice();
  111. });
  112. }
  113. preflightAndHeaders(path) {
  114. return Promise.all([this.preflight(path), this.headers()]).then(_ref => {
  115. let [allowedHeaders, headers] = _ref;
  116. // filter to keep only allowed Headers
  117. Object.keys(headers).forEach(header => {
  118. if (!allowedHeaders.includes(header.toLowerCase())) {
  119. this.uppy.log(`[CompanionClient] excluding disallowed header ${header}`);
  120. delete headers[header]; // eslint-disable-line no-param-reassign
  121. }
  122. });
  123. return headers;
  124. });
  125. }
  126. get(path, skipPostResponse) {
  127. const method = 'get';
  128. return this.preflightAndHeaders(path).then(headers => fetchWithNetworkError(_classPrivateFieldLooseBase(this, _getUrl)[_getUrl](path), {
  129. method,
  130. headers,
  131. credentials: this.opts.companionCookiesRule || 'same-origin'
  132. })).then(_classPrivateFieldLooseBase(this, _getPostResponseFunc)[_getPostResponseFunc](skipPostResponse)).then(handleJSONResponse).catch(_classPrivateFieldLooseBase(this, _errorHandler)[_errorHandler](method, path));
  133. }
  134. post(path, data, skipPostResponse) {
  135. const method = 'post';
  136. return this.preflightAndHeaders(path).then(headers => fetchWithNetworkError(_classPrivateFieldLooseBase(this, _getUrl)[_getUrl](path), {
  137. method,
  138. headers,
  139. credentials: this.opts.companionCookiesRule || 'same-origin',
  140. body: JSON.stringify(data)
  141. })).then(_classPrivateFieldLooseBase(this, _getPostResponseFunc)[_getPostResponseFunc](skipPostResponse)).then(handleJSONResponse).catch(_classPrivateFieldLooseBase(this, _errorHandler)[_errorHandler](method, path));
  142. }
  143. delete(path, data, skipPostResponse) {
  144. const method = 'delete';
  145. return this.preflightAndHeaders(path).then(headers => fetchWithNetworkError(`${this.hostname}/${path}`, {
  146. method,
  147. headers,
  148. credentials: this.opts.companionCookiesRule || 'same-origin',
  149. body: data ? JSON.stringify(data) : null
  150. })).then(_classPrivateFieldLooseBase(this, _getPostResponseFunc)[_getPostResponseFunc](skipPostResponse)).then(handleJSONResponse).catch(_classPrivateFieldLooseBase(this, _errorHandler)[_errorHandler](method, path));
  151. }
  152. }
  153. function _getUrl2(url) {
  154. if (/^(https?:|)\/\//.test(url)) {
  155. return url;
  156. }
  157. return `${this.hostname}/${url}`;
  158. }
  159. function _errorHandler2(method, path) {
  160. return err => {
  161. var _err;
  162. if (!((_err = err) != null && _err.isAuthError)) {
  163. // eslint-disable-next-line no-param-reassign
  164. err = new ErrorWithCause(`Could not ${method} ${_classPrivateFieldLooseBase(this, _getUrl)[_getUrl](path)}`, {
  165. cause: err
  166. });
  167. }
  168. return Promise.reject(err);
  169. };
  170. }
  171. RequestClient.VERSION = packageJson.version;
  172. RequestClient.defaultHeaders = {
  173. Accept: 'application/json',
  174. 'Content-Type': 'application/json',
  175. 'Uppy-Versions': `@uppy/companion-client=${RequestClient.VERSION}`
  176. };
  177. module.exports = RequestClient;