files.com 1.0.295 → 1.0.297

Sign up to get free protection for your applications and to get access to all the features.
package/_VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.295
1
+ 1.0.297
@@ -8,7 +8,7 @@
8
8
  "automation": "create_folder",
9
9
  "deleted": true,
10
10
  "disabled": true,
11
- "trigger": "realtime",
11
+ "trigger": "daily",
12
12
  "interval": "week",
13
13
  "last_modified_at": "2000-01-01T01:00:00Z",
14
14
  "name": "example",
@@ -49,13 +49,13 @@
49
49
  * `automation` (string): Automation type
50
50
  * `deleted` (boolean): Indicates if the automation has been deleted.
51
51
  * `disabled` (boolean): If true, this automation will not run.
52
- * `trigger` (string): How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
52
+ * `trigger` (string): How this automation is triggered to run.
53
53
  * `interval` (string): If trigger is `daily`, this specifies how often to run this automation. One of: `day`, `week`, `week_end`, `month`, `month_end`, `quarter`, `quarter_end`, `year`, `year_end`
54
54
  * `last_modified_at` (date-time): Time when automation was last modified. Does not change for name or description updates.
55
55
  * `name` (string): Name for this automation.
56
56
  * `schedule` (object): If trigger is `custom_schedule`, Custom schedule description for when the automation should be run.
57
57
  * `source` (string): Source Path
58
- * `destinations` (array): Destination Path
58
+ * `destinations` (array): Destination Paths
59
59
  * `destination_replace_from` (string): If set, this string in the destination path will be replaced with the value in `destination_replace_to`.
60
60
  * `destination_replace_to` (string): If set, this string will replace the value `destination_replace_from` in the destination filename. You can use special patterns here.
61
61
  * `description` (string): Description for the this Automation.
@@ -126,7 +126,7 @@ await Automation.create({
126
126
  'description': "example",
127
127
  'disabled': true,
128
128
  'name': "example",
129
- 'trigger': "realtime",
129
+ 'trigger': "daily",
130
130
  'trigger_actions': ["create"],
131
131
  'value': {"limit":"1"},
132
132
  'recurring_day': 25,
@@ -151,7 +151,7 @@ await Automation.create({
151
151
  * `description` (string): Description for the this Automation.
152
152
  * `disabled` (boolean): If true, this automation will not run.
153
153
  * `name` (string): Name for this automation.
154
- * `trigger` (string): How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
154
+ * `trigger` (string): How this automation is triggered to run.
155
155
  * `trigger_actions` (array(string)): If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
156
156
  * `value` (object): A Hash of attributes specific to the automation type.
157
157
  * `recurring_day` (int64): If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
@@ -193,7 +193,7 @@ await automation.update({
193
193
  'description': "example",
194
194
  'disabled': true,
195
195
  'name': "example",
196
- 'trigger': "realtime",
196
+ 'trigger': "daily",
197
197
  'trigger_actions': ["create"],
198
198
  'value': {"limit":"1"},
199
199
  'recurring_day': 25,
@@ -218,7 +218,7 @@ await automation.update({
218
218
  * `description` (string): Description for the this Automation.
219
219
  * `disabled` (boolean): If true, this automation will not run.
220
220
  * `name` (string): Name for this automation.
221
- * `trigger` (string): How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
221
+ * `trigger` (string): How this automation is triggered to run.
222
222
  * `trigger_actions` (array(string)): If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
223
223
  * `value` (object): A Hash of attributes specific to the automation type.
224
224
  * `recurring_day` (int64): If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
@@ -232,7 +232,7 @@ await automation.update({
232
232
  "automation": "create_folder",
233
233
  "deleted": true,
234
234
  "disabled": true,
235
- "trigger": "realtime",
235
+ "trigger": "daily",
236
236
  "interval": "week",
237
237
  "last_modified_at": "2000-01-01T01:00:00Z",
238
238
  "name": "example",
package/lib/Api.js CHANGED
@@ -7,92 +7,192 @@ exports.default = void 0;
7
7
  var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
8
8
  var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
9
9
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
10
- var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
11
10
  var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
12
11
  var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
13
12
  var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
14
- var _axios = _interopRequireDefault(require("axios"));
15
- var _axiosRetry = _interopRequireDefault(require("axios-retry"));
13
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
14
+ var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties"));
15
+ var _crossFetch = _interopRequireDefault(require("cross-fetch"));
16
16
  var _Files = _interopRequireDefault(require("./Files"));
17
17
  var errors = _interopRequireWildcard(require("./Errors"));
18
18
  var _Logger = _interopRequireDefault(require("./Logger"));
19
19
  var _utils = require("./utils");
20
+ var _excluded = ["timeoutSecs"];
20
21
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
21
22
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
22
23
  function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; }
23
24
  function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { (0, _defineProperty2.default)(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; }
25
+ var _fetchWithTimeout = function _fetchWithTimeout(url) {
26
+ var _ref = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {},
27
+ timeoutSecs = _ref.timeoutSecs,
28
+ options = (0, _objectWithoutProperties2.default)(_ref, _excluded);
29
+ return timeoutSecs <= 0 ? (0, _crossFetch.default)(url, options) : Promise.race([(0, _crossFetch.default)(url, options), new Promise(function (_, reject) {
30
+ setTimeout(function () {
31
+ return reject(new errors.FilesError('Request timed out'));
32
+ }, timeoutSecs * 1000);
33
+ })]);
34
+ };
35
+ var fetchWithRetry = /*#__PURE__*/function () {
36
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(url, options) {
37
+ var retries,
38
+ maxRetries,
39
+ minRetryDelaySecs,
40
+ maxRetryDelaySecs,
41
+ nextRetries,
42
+ delaySecs,
43
+ _args = arguments;
44
+ return _regenerator.default.wrap(function _callee$(_context) {
45
+ while (1) switch (_context.prev = _context.next) {
46
+ case 0:
47
+ retries = _args.length > 2 && _args[2] !== undefined ? _args[2] : 0;
48
+ maxRetries = _Files.default.getMaxNetworkRetries();
49
+ minRetryDelaySecs = _Files.default.getMinNetworkRetryDelay();
50
+ maxRetryDelaySecs = _Files.default.getMaxNetworkRetryDelay();
51
+ _context.prev = 4;
52
+ _context.next = 7;
53
+ return _fetchWithTimeout(url, options);
54
+ case 7:
55
+ return _context.abrupt("return", _context.sent);
56
+ case 10:
57
+ _context.prev = 10;
58
+ _context.t0 = _context["catch"](4);
59
+ _Logger.default.info("Request #".concat(retries + 1, " failed: ").concat(_context.t0.message));
60
+ if (!(retries >= maxRetries)) {
61
+ _context.next = 17;
62
+ break;
63
+ }
64
+ throw _context.t0;
65
+ case 17:
66
+ nextRetries = retries + 1;
67
+ _Logger.default.info("Retrying request (retry ".concat(nextRetries, " of ").concat(maxRetries, ")"));
68
+ delaySecs = Math.min(minRetryDelaySecs * Math.pow(2, retries), maxRetryDelaySecs); // exponential backoff
69
+ _context.next = 22;
70
+ return new Promise(function (resolve) {
71
+ return setTimeout(resolve, delaySecs * 1000);
72
+ });
73
+ case 22:
74
+ return _context.abrupt("return", fetchWithRetry(url, options, nextRetries));
75
+ case 23:
76
+ case "end":
77
+ return _context.stop();
78
+ }
79
+ }, _callee, null, [[4, 10]]);
80
+ }));
81
+ return function fetchWithRetry(_x, _x2) {
82
+ return _ref2.apply(this, arguments);
83
+ };
84
+ }();
24
85
  var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
25
86
  (0, _classCallCheck2.default)(this, Api);
26
87
  });
27
- (0, _defineProperty2.default)(Api, "_configureAutoRetry", function () {
28
- (0, _axiosRetry.default)(_axios.default, {
29
- retries: _Files.default.getMaxNetworkRetries(),
30
- retryDelay: function retryDelay(retries) {
31
- _Logger.default.info("Retrying request (retry ".concat(retries, " of ").concat(_Files.default.getMaxNetworkRetries(), ")"));
32
- return Math.min(retries * _Files.default.getMinNetworkRetryDelay() * 1000, _Files.default.getMaxNetworkRetryDelay() * 1000);
33
- }
34
- });
35
- });
36
88
  (0, _defineProperty2.default)(Api, "_sendVerbatim", /*#__PURE__*/function () {
37
- var _ref = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee(path, verb, options) {
38
- var isExternal, baseUrl, url, response;
39
- return _regenerator.default.wrap(function _callee$(_context) {
40
- while (1) switch (_context.prev = _context.next) {
89
+ var _ref3 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(path, verb, options) {
90
+ var isExternal, baseUrl, url, agent, response, headers, contentType, data, normalizedResponse;
91
+ return _regenerator.default.wrap(function _callee2$(_context2) {
92
+ while (1) switch (_context2.prev = _context2.next) {
41
93
  case 0:
42
94
  isExternal = /^[a-zA-Z]+:\/\//.test(path);
43
95
  baseUrl = _Files.default.getBaseUrl();
44
96
  if (!(!isExternal && !baseUrl)) {
45
- _context.next = 4;
97
+ _context2.next = 4;
46
98
  break;
47
99
  }
48
100
  throw new errors.ConfigurationError('Base URL has not been set - use Files.setBaseUrl() to set it');
49
101
  case 4:
50
102
  url = isExternal ? path : "".concat(baseUrl).concat(_Files.default.getEndpointPrefix()).concat(path);
51
103
  _Logger.default.debug("Sending request: ".concat(verb, " ").concat(url));
52
- _Logger.default.debug('Sending options:', _objectSpread(_objectSpread({}, options), {}, {
104
+ _Logger.default.debug('Sending options:', _objectSpread(_objectSpread({
105
+ method: verb
106
+ }, options), {}, {
53
107
  headers: _objectSpread(_objectSpread({}, options.headers), {}, {
54
108
  'X-FilesAPI-Key': '<redacted>'
55
109
  })
56
110
  }));
57
- Api._configureAutoRetry();
58
- _context.prev = 8;
59
- _context.next = 11;
60
- return (0, _axios.default)(_objectSpread({
111
+ _context2.prev = 7;
112
+ agent = (options === null || options === void 0 ? void 0 : options.agent) || (options === null || options === void 0 ? void 0 : options.httpsAgent) || (options === null || options === void 0 ? void 0 : options.httpAgent);
113
+ _context2.next = 11;
114
+ return fetchWithRetry(url, _objectSpread({
115
+ agent: agent,
61
116
  method: verb,
62
- timeout: _Files.default.getNetworkTimeout() * 1000,
63
- url: url
117
+ timeoutSecs: _Files.default.getNetworkTimeout()
64
118
  }, options));
65
119
  case 11:
66
- response = _context.sent;
120
+ response = _context2.sent;
121
+ headers = Object.fromEntries(response.headers.entries());
67
122
  _Logger.default.debug("Status: ".concat(response.status, " ").concat(response.statusText));
68
123
  if (_Files.default.shouldDebugResponseHeaders()) {
69
124
  _Logger.default.debug('Response Headers: ');
70
- _Logger.default.debug(response.headers);
125
+ _Logger.default.debug(headers);
126
+ }
127
+ contentType = headers['content-type'] || '';
128
+ if (!contentType.includes('application/json')) {
129
+ _context2.next = 22;
130
+ break;
131
+ }
132
+ _context2.next = 19;
133
+ return response.json();
134
+ case 19:
135
+ data = _context2.sent;
136
+ _context2.next = 35;
137
+ break;
138
+ case 22:
139
+ if (!contentType.includes('text/')) {
140
+ _context2.next = 28;
141
+ break;
71
142
  }
72
- return _context.abrupt("return", {
143
+ _context2.next = 25;
144
+ return response.text();
145
+ case 25:
146
+ data = _context2.sent;
147
+ _context2.next = 35;
148
+ break;
149
+ case 28:
150
+ if (!contentType.includes('multipart/form-data')) {
151
+ _context2.next = 34;
152
+ break;
153
+ }
154
+ _context2.next = 31;
155
+ return response.formData();
156
+ case 31:
157
+ data = _context2.sent;
158
+ _context2.next = 35;
159
+ break;
160
+ case 34:
161
+ data = response.body;
162
+ case 35:
163
+ normalizedResponse = {
73
164
  status: response.status,
74
165
  reason: response.statusText,
75
- headers: response.headers,
76
- data: response.data
77
- });
78
- case 17:
79
- _context.prev = 17;
80
- _context.t0 = _context["catch"](8);
81
- errors.handleErrorResponse(_context.t0);
82
- case 20:
166
+ headers: headers,
167
+ data: data
168
+ };
169
+ if (response.ok) {
170
+ _context2.next = 38;
171
+ break;
172
+ }
173
+ throw {
174
+ response: normalizedResponse
175
+ };
176
+ case 38:
177
+ return _context2.abrupt("return", normalizedResponse);
178
+ case 41:
179
+ _context2.prev = 41;
180
+ _context2.t0 = _context2["catch"](7);
181
+ errors.handleErrorResponse(_context2.t0);
182
+ case 44:
83
183
  case "end":
84
- return _context.stop();
184
+ return _context2.stop();
85
185
  }
86
- }, _callee, null, [[8, 17]]);
186
+ }, _callee2, null, [[7, 41]]);
87
187
  }));
88
- return function (_x, _x2, _x3) {
89
- return _ref.apply(this, arguments);
188
+ return function (_x3, _x4, _x5) {
189
+ return _ref3.apply(this, arguments);
90
190
  };
91
191
  }());
92
192
  (0, _defineProperty2.default)(Api, "sendFilePart", function (externalUrl, verb, data) {
93
193
  var headers = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
94
194
  var params = {
95
- data: data
195
+ body: data
96
196
  };
97
197
  if (headers) {
98
198
  params.headers = headers;
@@ -100,20 +200,20 @@ var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
100
200
  return Api._sendVerbatim(externalUrl, verb, params);
101
201
  });
102
202
  (0, _defineProperty2.default)(Api, "_autoPaginate", /*#__PURE__*/function () {
103
- var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(path, verb, params, options, response, metadata) {
203
+ var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(path, verb, params, options, response, metadata) {
104
204
  var _options$autoPaginate;
105
- var _response$headers, nextCursor, _ref3, autoPaginateCount, previousAutoPaginateData, nextPage, nextParams, nextMetadata;
106
- return _regenerator.default.wrap(function _callee2$(_context2) {
107
- while (1) switch (_context2.prev = _context2.next) {
205
+ var _response$headers, nextCursor, _ref5, autoPaginateCount, previousAutoPaginateData, nextPage, nextParams, nextMetadata;
206
+ return _regenerator.default.wrap(function _callee3$(_context3) {
207
+ while (1) switch (_context3.prev = _context3.next) {
108
208
  case 0:
109
209
  if (!((_options$autoPaginate = options.autoPaginate) !== null && _options$autoPaginate !== void 0 ? _options$autoPaginate : _Files.default.getAutoPaginate())) {
110
- _context2.next = 12;
210
+ _context3.next = 12;
111
211
  break;
112
212
  }
113
213
  nextCursor = response === null || response === void 0 || (_response$headers = response.headers) === null || _response$headers === void 0 ? void 0 : _response$headers['x-files-cursor'];
114
- _ref3 = metadata || {}, autoPaginateCount = _ref3.autoPaginateCount, previousAutoPaginateData = _ref3.previousAutoPaginateData;
214
+ _ref5 = metadata || {}, autoPaginateCount = _ref5.autoPaginateCount, previousAutoPaginateData = _ref5.previousAutoPaginateData;
115
215
  if (!nextCursor) {
116
- _context2.next = 10;
216
+ _context3.next = 10;
117
217
  break;
118
218
  }
119
219
  nextPage = (Number(params === null || params === void 0 ? void 0 : params.page) || 1) + 1;
@@ -125,30 +225,30 @@ var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
125
225
  autoPaginateCount: (autoPaginateCount || 1) + 1,
126
226
  previousAutoPaginateData: [].concat((0, _toConsumableArray2.default)(previousAutoPaginateData || []), (0, _toConsumableArray2.default)((response === null || response === void 0 ? void 0 : response.data) || []))
127
227
  };
128
- return _context2.abrupt("return", Api.sendRequest(path, verb, nextParams, options, nextMetadata));
228
+ return _context3.abrupt("return", Api.sendRequest(path, verb, nextParams, options, nextMetadata));
129
229
  case 10:
130
230
  if (!previousAutoPaginateData) {
131
- _context2.next = 12;
231
+ _context3.next = 12;
132
232
  break;
133
233
  }
134
- return _context2.abrupt("return", _objectSpread(_objectSpread({}, response), {}, {
234
+ return _context3.abrupt("return", _objectSpread(_objectSpread({}, response), {}, {
135
235
  autoPaginateRequests: autoPaginateCount,
136
236
  data: [].concat((0, _toConsumableArray2.default)(previousAutoPaginateData), (0, _toConsumableArray2.default)((response === null || response === void 0 ? void 0 : response.data) || []))
137
237
  }));
138
238
  case 12:
139
- return _context2.abrupt("return", response);
239
+ return _context3.abrupt("return", response);
140
240
  case 13:
141
241
  case "end":
142
- return _context2.stop();
242
+ return _context3.stop();
143
243
  }
144
- }, _callee2);
244
+ }, _callee3);
145
245
  }));
146
- return function (_x4, _x5, _x6, _x7, _x8, _x9) {
147
- return _ref2.apply(this, arguments);
246
+ return function (_x6, _x7, _x8, _x9, _x10, _x11) {
247
+ return _ref4.apply(this, arguments);
148
248
  };
149
249
  }());
150
250
  (0, _defineProperty2.default)(Api, "sendRequest", /*#__PURE__*/function () {
151
- var _ref4 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee3(path, verb) {
251
+ var _ref6 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee4(path, verb) {
152
252
  var params,
153
253
  options,
154
254
  metadata,
@@ -162,13 +262,13 @@ var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
162
262
  hasParams,
163
263
  pairs,
164
264
  response,
165
- _args3 = arguments;
166
- return _regenerator.default.wrap(function _callee3$(_context3) {
167
- while (1) switch (_context3.prev = _context3.next) {
265
+ _args4 = arguments;
266
+ return _regenerator.default.wrap(function _callee4$(_context4) {
267
+ while (1) switch (_context4.prev = _context4.next) {
168
268
  case 0:
169
- params = _args3.length > 2 && _args3[2] !== undefined ? _args3[2] : null;
170
- options = _args3.length > 3 && _args3[3] !== undefined ? _args3[3] : {};
171
- metadata = _args3.length > 4 && _args3[4] !== undefined ? _args3[4] : null;
269
+ params = _args4.length > 2 && _args4[2] !== undefined ? _args4[2] : null;
270
+ options = _args4.length > 3 && _args4[3] !== undefined ? _args4[3] : {};
271
+ metadata = _args4.length > 4 && _args4[4] !== undefined ? _args4[4] : null;
172
272
  headers = _objectSpread(_objectSpread({
173
273
  Accept: 'application/json'
174
274
  }, options.headers), {}, {
@@ -176,26 +276,26 @@ var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
176
276
  });
177
277
  isExternal = /^[a-zA-Z]+:\/\//.test(path);
178
278
  if (isExternal) {
179
- _context3.next = 17;
279
+ _context4.next = 17;
180
280
  break;
181
281
  }
182
282
  sessionId = options.sessionId || _Files.default.getSessionId();
183
283
  if (!sessionId) {
184
- _context3.next = 11;
284
+ _context4.next = 11;
185
285
  break;
186
286
  }
187
287
  headers['X-FilesAPI-Auth'] = sessionId;
188
- _context3.next = 17;
288
+ _context4.next = 17;
189
289
  break;
190
290
  case 11:
191
291
  isCreatingSession = path === '/sessions' && verb.toUpperCase() === 'POST'; // api key cannot be used when creating a session
192
292
  if (isCreatingSession) {
193
- _context3.next = 17;
293
+ _context4.next = 17;
194
294
  break;
195
295
  }
196
296
  apiKey = options.apiKey || _Files.default.getApiKey();
197
297
  if (apiKey) {
198
- _context3.next = 16;
298
+ _context4.next = 16;
199
299
  break;
200
300
  }
201
301
  throw new errors.ConfigurationError('API key has not been set - use Files.setApiKey() to set it');
@@ -209,41 +309,41 @@ var Api = /*#__PURE__*/(0, _createClass2.default)(function Api() {
209
309
  hasParams = (0, _utils.isObject)(params) && !(0, _utils.isEmpty)(params);
210
310
  if (hasParams) {
211
311
  if (verb.toUpperCase() === 'GET') {
212
- pairs = Object.entries(params).map(function (_ref5) {
213
- var _ref6 = (0, _slicedToArray2.default)(_ref5, 2),
214
- key = _ref6[0],
215
- value = _ref6[1];
312
+ pairs = Object.entries(params).map(function (_ref7) {
313
+ var _ref8 = (0, _slicedToArray2.default)(_ref7, 2),
314
+ key = _ref8[0],
315
+ value = _ref8[1];
216
316
  return "".concat(encodeURIComponent(key), "=").concat(encodeURIComponent(value));
217
317
  });
218
318
  requestPath += path.includes('?') ? '&' : '?';
219
319
  requestPath += pairs.join('&');
220
320
  } else {
221
- updatedOptions.data = JSON.stringify(params);
321
+ updatedOptions.body = JSON.stringify(params);
222
322
  headers['Content-Type'] = 'application/json';
223
323
  }
224
324
  }
225
325
  if (_Files.default.shouldDebugRequest()) {
226
326
  _Logger.default.debug('Request Options:');
227
327
  _Logger.default.debug(_objectSpread(_objectSpread({}, updatedOptions), {}, {
228
- data: hasParams ? "payload keys: ".concat(Object.keys(params).join(', ')) : '(none)',
328
+ body: hasParams ? "payload keys: ".concat(Object.keys(params).join(', ')) : '(none)',
229
329
  headers: _objectSpread(_objectSpread({}, headers), {}, {
230
330
  'X-FilesAPI-Key': '<redacted>'
231
331
  })
232
332
  }));
233
333
  }
234
- _context3.next = 24;
334
+ _context4.next = 24;
235
335
  return Api._sendVerbatim(requestPath, verb, updatedOptions);
236
336
  case 24:
237
- response = _context3.sent;
238
- return _context3.abrupt("return", Api._autoPaginate(path, verb, params, updatedOptions, response, metadata));
337
+ response = _context4.sent;
338
+ return _context4.abrupt("return", Api._autoPaginate(path, verb, params, updatedOptions, response, metadata));
239
339
  case 26:
240
340
  case "end":
241
- return _context3.stop();
341
+ return _context4.stop();
242
342
  }
243
- }, _callee3);
343
+ }, _callee4);
244
344
  }));
245
- return function (_x10, _x11) {
246
- return _ref4.apply(this, arguments);
345
+ return function (_x12, _x13) {
346
+ return _ref6.apply(this, arguments);
247
347
  };
248
348
  }());
249
349
  var _default = Api;
package/lib/Errors.js CHANGED
@@ -56,14 +56,14 @@ var handleErrorResponse = function handleErrorResponse(error) {
56
56
  var message = ((_errorData = errorData) === null || _errorData === void 0 ? void 0 : _errorData.error) || (response === null || response === void 0 ? void 0 : response.statusText) || error.message;
57
57
  var code = (response === null || response === void 0 ? void 0 : response.status) || ((_errorData2 = errorData) === null || _errorData2 === void 0 ? void 0 : _errorData2['http-code']) || 0;
58
58
  if (!errorData) {
59
- _Logger.default.error('FilesApiError Exception >', code, message);
59
+ _Logger.default.error('FilesApiError Exception:', code, message);
60
60
  throw new FilesApiError(message, code);
61
61
  }
62
62
  if (Array.isArray(errorData)) {
63
63
  errorData = errorData[0];
64
64
  }
65
65
  if (!errorData.type) {
66
- _Logger.default.error('FilesApiError Exception >', code, message);
66
+ _Logger.default.error('FilesApiError Exception:', code, message);
67
67
  throw new FilesApiError(message, code);
68
68
  }
69
69
  var parts = errorData.type.split('/');
@@ -24,8 +24,12 @@ var saveUrlToStream = /*#__PURE__*/function () {
24
24
  var https = require('https');
25
25
  https.get(url, function (response) {
26
26
  response.pipe(stream);
27
- stream.on('finish', resolve);
27
+ stream.on('finish', function () {
28
+ stream.close();
29
+ resolve();
30
+ });
28
31
  }).on('error', function (error) {
32
+ stream.close();
29
33
  reject(error);
30
34
  });
31
35
  }));
@@ -80,8 +84,6 @@ var saveUrlToFile = /*#__PURE__*/function () {
80
84
  _context3.next = 3;
81
85
  return saveUrlToStream(url, stream);
82
86
  case 3:
83
- stream.close();
84
- case 4:
85
87
  case "end":
86
88
  return _context3.stop();
87
89
  }
@@ -59,7 +59,7 @@ var Automation = /*#__PURE__*/(0, _createClass2.default)(function Automation() {
59
59
  (0, _defineProperty2.default)(this, "setDisabled", function (value) {
60
60
  _this.attributes.disabled = value;
61
61
  });
62
- // string # How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
62
+ // string # How this automation is triggered to run.
63
63
  (0, _defineProperty2.default)(this, "getTrigger", function () {
64
64
  return _this.attributes.trigger;
65
65
  });
@@ -101,7 +101,7 @@ var Automation = /*#__PURE__*/(0, _createClass2.default)(function Automation() {
101
101
  (0, _defineProperty2.default)(this, "setSource", function (value) {
102
102
  _this.attributes.source = value;
103
103
  });
104
- // array # Destination Path
104
+ // array # Destination Paths
105
105
  (0, _defineProperty2.default)(this, "getDestinations", function () {
106
106
  return _this.attributes.destinations;
107
107
  });
@@ -267,7 +267,7 @@ var Automation = /*#__PURE__*/(0, _createClass2.default)(function Automation() {
267
267
  // description - string - Description for the this Automation.
268
268
  // disabled - boolean - If true, this automation will not run.
269
269
  // name - string - Name for this automation.
270
- // trigger - string - How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
270
+ // trigger - string - How this automation is triggered to run.
271
271
  // trigger_actions - array(string) - If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
272
272
  // value - object - A Hash of attributes specific to the automation type.
273
273
  // recurring_day - int64 - If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
@@ -616,7 +616,7 @@ var Automation = /*#__PURE__*/(0, _createClass2.default)(function Automation() {
616
616
  // description - string - Description for the this Automation.
617
617
  // disabled - boolean - If true, this automation will not run.
618
618
  // name - string - Name for this automation.
619
- // trigger - string - How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
619
+ // trigger - string - How this automation is triggered to run.
620
620
  // trigger_actions - array(string) - If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
621
621
  // value - object - A Hash of attributes specific to the automation type.
622
622
  // recurring_day - int64 - If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "files.com",
3
- "version": "1.0.295",
3
+ "version": "1.0.297",
4
4
  "description": "Files.com SDK for JavaScript",
5
5
  "keywords": [
6
6
  "files.com",
@@ -20,8 +20,7 @@
20
20
  "main": "lib/files.js",
21
21
  "dependencies": {
22
22
  "@babel/runtime": "^7.10.3",
23
- "axios": "^1.4.0",
24
- "axios-retry": "^3.5.0",
23
+ "cross-fetch": "^4.0.0",
25
24
  "readable-stream": "^4.4.0",
26
25
  "safe-buffer": "^5.2.1"
27
26
  },
package/src/Api.js CHANGED
@@ -1,29 +1,45 @@
1
- import axios from 'axios'
2
- import axiosRetry from 'axios-retry'
1
+ import fetch from 'cross-fetch'
3
2
 
4
3
  import Files from './Files'
5
4
  import * as errors from './Errors'
6
5
  import Logger from './Logger'
7
6
  import { isEmpty, isObject } from './utils'
8
7
 
9
- class Api {
10
- static _configureAutoRetry = () => {
11
- axiosRetry(
12
- axios,
13
- {
14
- retries: Files.getMaxNetworkRetries(),
15
- retryDelay: retries => {
16
- Logger.info(`Retrying request (retry ${retries} of ${Files.getMaxNetworkRetries()})`)
17
-
18
- return Math.min(
19
- retries * Files.getMinNetworkRetryDelay() * 1000,
20
- Files.getMaxNetworkRetryDelay() * 1000
21
- )
22
- },
23
- }
24
- )
8
+ const _fetchWithTimeout = (url, { timeoutSecs, ...options } = {}) =>
9
+ timeoutSecs <= 0
10
+ ? fetch(url, options)
11
+ : Promise.race([
12
+ fetch(url, options),
13
+ new Promise((_, reject) => {
14
+ setTimeout(() => reject(new errors.FilesError('Request timed out')), timeoutSecs * 1000)
15
+ })
16
+ ])
17
+
18
+ const fetchWithRetry = async (url, options, retries = 0) => {
19
+ const maxRetries = Files.getMaxNetworkRetries()
20
+ const minRetryDelaySecs = Files.getMinNetworkRetryDelay()
21
+ const maxRetryDelaySecs = Files.getMaxNetworkRetryDelay()
22
+
23
+ try {
24
+ return await _fetchWithTimeout(url, options)
25
+ } catch (error) {
26
+ Logger.info(`Request #${retries + 1} failed: ${error.message}`)
27
+
28
+ if (retries >= maxRetries) {
29
+ throw error
30
+ } else {
31
+ const nextRetries = retries + 1
32
+ Logger.info(`Retrying request (retry ${nextRetries} of ${maxRetries})`)
33
+
34
+ const delaySecs = Math.min(minRetryDelaySecs * 2 ** retries, maxRetryDelaySecs) // exponential backoff
35
+ await new Promise(resolve => setTimeout(resolve, delaySecs * 1000))
36
+
37
+ return fetchWithRetry(url, options, nextRetries)
38
+ }
25
39
  }
40
+ }
26
41
 
42
+ class Api {
27
43
  static _sendVerbatim = async (path, verb, options) => {
28
44
  const isExternal = /^[a-zA-Z]+:\/\//.test(path)
29
45
  const baseUrl = Files.getBaseUrl()
@@ -39,6 +55,7 @@ class Api {
39
55
  Logger.debug(`Sending request: ${verb} ${url}`)
40
56
 
41
57
  Logger.debug('Sending options:', {
58
+ method: verb,
42
59
  ...options,
43
60
  headers: {
44
61
  ...options.headers,
@@ -46,36 +63,57 @@ class Api {
46
63
  },
47
64
  })
48
65
 
49
- Api._configureAutoRetry()
50
-
51
66
  try {
52
- const response = await axios({
67
+ const agent = options?.agent || options?.httpsAgent || options?.httpAgent
68
+
69
+ const response = await fetchWithRetry(url, {
70
+ agent,
53
71
  method: verb,
54
- timeout: Files.getNetworkTimeout() * 1000,
55
- url,
72
+ timeoutSecs: Files.getNetworkTimeout(),
56
73
  ...options,
57
74
  })
58
75
 
76
+ const headers = Object.fromEntries(response.headers.entries())
77
+
59
78
  Logger.debug(`Status: ${response.status} ${response.statusText}`)
60
79
 
61
80
  if (Files.shouldDebugResponseHeaders()) {
62
81
  Logger.debug('Response Headers: ')
63
- Logger.debug(response.headers)
82
+ Logger.debug(headers)
83
+ }
84
+
85
+ const contentType = headers['content-type'] || ''
86
+ let data
87
+
88
+ if (contentType.includes('application/json')) {
89
+ data = await response.json()
90
+ } else if (contentType.includes('text/')) {
91
+ data = await response.text()
92
+ } else if (contentType.includes('multipart/form-data')) {
93
+ data = await response.formData()
94
+ } else {
95
+ data = response.body
64
96
  }
65
97
 
66
- return {
98
+ const normalizedResponse = {
67
99
  status: response.status,
68
100
  reason: response.statusText,
69
- headers: response.headers,
70
- data: response.data,
101
+ headers,
102
+ data,
103
+ }
104
+
105
+ if (!response.ok) {
106
+ throw { response: normalizedResponse }
71
107
  }
108
+
109
+ return normalizedResponse
72
110
  } catch (error) {
73
111
  errors.handleErrorResponse(error)
74
112
  }
75
113
  }
76
114
 
77
115
  static sendFilePart = (externalUrl, verb, data, headers = {}) => {
78
- const params = { data }
116
+ const params = { body: data }
79
117
 
80
118
  if (headers) {
81
119
  params.headers = headers
@@ -166,7 +204,7 @@ class Api {
166
204
  requestPath += path.includes('?') ? '&' : '?'
167
205
  requestPath += pairs.join('&')
168
206
  } else {
169
- updatedOptions.data = JSON.stringify(params)
207
+ updatedOptions.body = JSON.stringify(params)
170
208
  headers['Content-Type'] = 'application/json'
171
209
  }
172
210
  }
@@ -175,7 +213,7 @@ class Api {
175
213
  Logger.debug('Request Options:')
176
214
  Logger.debug({
177
215
  ...updatedOptions,
178
- data: hasParams
216
+ body: hasParams
179
217
  ? `payload keys: ${Object.keys(params).join(', ')}`
180
218
  : '(none)',
181
219
  headers: {
package/src/Errors.js CHANGED
@@ -32,7 +32,7 @@ export const handleErrorResponse = error => {
32
32
  const code = response?.status || errorData?.['http-code'] || 0
33
33
 
34
34
  if (!errorData) {
35
- Logger.error('FilesApiError Exception >', code, message)
35
+ Logger.error('FilesApiError Exception:', code, message)
36
36
  throw new FilesApiError(message, code)
37
37
  }
38
38
 
@@ -41,7 +41,7 @@ export const handleErrorResponse = error => {
41
41
  }
42
42
 
43
43
  if (!errorData.type) {
44
- Logger.error('FilesApiError Exception >', code, message)
44
+ Logger.error('FilesApiError Exception:', code, message)
45
45
  throw new FilesApiError(message, code)
46
46
  }
47
47
 
@@ -14,9 +14,13 @@ const saveUrlToStream = async (url, stream) => new Promise((resolve, reject) =>
14
14
  https.get(url, response => {
15
15
  response.pipe(stream)
16
16
 
17
- stream.on('finish', resolve)
17
+ stream.on('finish', () => {
18
+ stream.close()
19
+ resolve()
20
+ })
18
21
  })
19
22
  .on('error', error => {
23
+ stream.close()
20
24
  reject(error)
21
25
  })
22
26
  })
@@ -37,7 +41,6 @@ const saveUrlToString = async url => new Promise((resolve, reject) => {
37
41
  const saveUrlToFile = async (url, destinationPath) => {
38
42
  const stream = openDiskFileWriteStream(destinationPath)
39
43
  await saveUrlToStream(url, stream)
40
- stream.close()
41
44
  }
42
45
 
43
46
  export {
@@ -51,7 +51,7 @@ class Automation {
51
51
  this.attributes.disabled = value
52
52
  }
53
53
 
54
- // string # How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
54
+ // string # How this automation is triggered to run.
55
55
  getTrigger = () => this.attributes.trigger
56
56
 
57
57
  setTrigger = value => {
@@ -93,7 +93,7 @@ class Automation {
93
93
  this.attributes.source = value
94
94
  }
95
95
 
96
- // array # Destination Path
96
+ // array # Destination Paths
97
97
  getDestinations = () => this.attributes.destinations
98
98
 
99
99
  setDestinations = value => {
@@ -235,7 +235,7 @@ class Automation {
235
235
  // description - string - Description for the this Automation.
236
236
  // disabled - boolean - If true, this automation will not run.
237
237
  // name - string - Name for this automation.
238
- // trigger - string - How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
238
+ // trigger - string - How this automation is triggered to run.
239
239
  // trigger_actions - array(string) - If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
240
240
  // value - object - A Hash of attributes specific to the automation type.
241
241
  // recurring_day - int64 - If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
@@ -422,7 +422,7 @@ class Automation {
422
422
  // description - string - Description for the this Automation.
423
423
  // disabled - boolean - If true, this automation will not run.
424
424
  // name - string - Name for this automation.
425
- // trigger - string - How this automation is triggered to run. One of: `realtime`, `daily`, `custom_schedule`, `webhook`, `email`, or `action`.
425
+ // trigger - string - How this automation is triggered to run.
426
426
  // trigger_actions - array(string) - If trigger is `action`, this is the list of action types on which to trigger the automation. Valid actions are create, read, update, destroy, move, copy
427
427
  // value - object - A Hash of attributes specific to the automation type.
428
428
  // recurring_day - int64 - If trigger type is `daily`, this specifies a day number to run in one of the supported intervals: `week`, `month`, `quarter`, `year`.
package/test/package.json CHANGED
@@ -8,7 +8,8 @@
8
8
  "dependencies": {
9
9
  "@babel/runtime": "^7.10.3",
10
10
  "files.com": "file:../",
11
- "readable-stream": "^3.6.0"
11
+ "readable-stream": "^3.6.0",
12
+ "tiny-invariant": "^1.3.1"
12
13
  },
13
14
  "devDependencies": {
14
15
  "@babel/cli": "^7.10.3",
package/test/src/index.js CHANGED
@@ -1,6 +1,3 @@
1
- import assert from 'assert'
2
- // import * as errors from 'files.com/lib/Errors'
3
- const errors = require('files.com/lib/Errors')
4
1
  import Files from 'files.com/lib/Files'
5
2
  import Logger, { LogLevel } from 'files.com/lib/Logger'
6
3
  import ApiKey from 'files.com/lib/models/ApiKey'
@@ -9,6 +6,9 @@ import Folder from 'files.com/lib/models/Folder'
9
6
  import Session from 'files.com/lib/models/Session'
10
7
  import User from 'files.com/lib/models/User'
11
8
  import { isBrowser } from 'files.com/lib/utils'
9
+ import invariant from 'tiny-invariant'
10
+
11
+ const errors = require('files.com/lib/Errors')
12
12
 
13
13
  // name of an existing folder in your root to create/delete test files and folders
14
14
  const SDK_TEST_ROOT_FOLDER = 'sdk-test'
@@ -32,11 +32,17 @@ if (apiDomain.substr(-10) === 'staging.av') {
32
32
  process.env.NODE_TLS_REJECT_UNAUTHORIZED = 0
33
33
  }
34
34
 
35
- Files.setLogLevel(LogLevel.INFO)
35
+ const DEBUG_MODE = false
36
+
37
+ Files.setLogLevel(DEBUG_MODE ? LogLevel.DEBUG : LogLevel.INFO)
36
38
 
37
39
  Files.configureDebugging({
38
- debugRequest: false,
39
- debugResponseHeaders: false,
40
+ debugRequest: DEBUG_MODE,
41
+ debugResponseHeaders: DEBUG_MODE,
42
+ })
43
+
44
+ Files.configureNetwork({
45
+ networkTimeout: DEBUG_MODE ? 10 : 30,
40
46
  })
41
47
 
42
48
  const testSuite = async () => {
@@ -49,7 +55,7 @@ const testSuite = async () => {
49
55
 
50
56
  const firstPageItems = await Folder.listFor('/', { per_page: 1 })
51
57
 
52
- assert(firstPageItems.length === 1)
58
+ invariant(firstPageItems.length === 1, 'First page should have 1 item')
53
59
 
54
60
  Files.configureNetwork({
55
61
  autoPaginate: true,
@@ -59,7 +65,7 @@ const testSuite = async () => {
59
65
  const allPageItems = await Folder.listFor('/', { per_page: 1 })
60
66
 
61
67
  // if auto-pagination executed, we'll have found more than just the 1 we requested
62
- assert(allPageItems.length > 1)
68
+ invariant(allPageItems.length > 1, 'Auto-pagination should have found more than 1 item across all pages')
63
69
 
64
70
  Logger.info('***** testFolderListAutoPagination() succeeded! *****')
65
71
  }
@@ -72,18 +78,20 @@ const testSuite = async () => {
72
78
 
73
79
  const file = await File.uploadFile(destinationPath, sourceFilePath)
74
80
 
75
- assert(!!file.path)
76
- assert(file.display_name === displayName)
81
+ invariant(!!file.path, 'Uploaded file response object should have a path')
82
+ invariant(file.display_name === displayName, 'Uploaded file response object should have the same display_name as the file we uploaded')
77
83
 
78
84
  const foundFile = await File.find(destinationPath)
79
85
 
80
- assert(foundFile.path === destinationPath)
81
- assert(foundFile.display_name === displayName)
82
- assert(typeof foundFile.getDownloadUri() === 'undefined')
86
+ invariant(foundFile.path === destinationPath, 'Found file should have the same path as the file we uploaded')
87
+ invariant(foundFile.display_name === displayName, 'Found file should have the same display_name as the file we uploaded')
88
+ invariant(typeof foundFile.getDownloadUri() === 'undefined', 'Found file should not have a download uri yet')
83
89
 
84
90
  if (!isBrowser()) {
85
91
  const downloadableFile = await foundFile.download()
86
- assert(typeof downloadableFile.getDownloadUri() !== 'undefined')
92
+
93
+ invariant(downloadableFile.size > 0, 'Uploaded file should not be empty')
94
+ invariant(typeof downloadableFile.getDownloadUri() !== 'undefined', 'Downloadable file should have a download uri')
87
95
 
88
96
  const downloadPath = `./${displayName}`
89
97
  await downloadableFile.downloadToFile(downloadPath)
@@ -92,7 +100,8 @@ const testSuite = async () => {
92
100
  const originalBuffer = fs.readFileSync(sourceFilePath)
93
101
  const downloadedBuffer = fs.readFileSync(downloadPath)
94
102
 
95
- assert(originalBuffer.equals(downloadedBuffer))
103
+ invariant(originalBuffer.length === downloadedBuffer.length, 'Source file length should match downloaded file length')
104
+ invariant(originalBuffer.equals(downloadedBuffer), 'Source file contents should match downloaded file contents')
96
105
 
97
106
  fs.unlinkSync(downloadPath)
98
107
  }
@@ -109,22 +118,22 @@ const testSuite = async () => {
109
118
  const sourceFileContents = 'The quick brown fox jumped over the lazy dogs.'
110
119
  const file = await File.uploadData(destinationPath, sourceFileContents)
111
120
 
112
- assert(!!file.path)
113
- assert(file.display_name === displayName)
121
+ invariant(!!file.path, 'Uploaded file response object should have a path')
122
+ invariant(file.display_name === displayName, 'Uploaded file response object should have the same display_name as the file we uploaded')
114
123
 
115
124
  const foundFile = await File.find(destinationPath)
116
125
 
117
- assert(foundFile.path === destinationPath)
118
- assert(foundFile.display_name === displayName)
119
- assert(typeof foundFile.getDownloadUri() === 'undefined')
126
+ invariant(foundFile.path === destinationPath, 'Found file should have the same path as the file we uploaded')
127
+ invariant(foundFile.display_name === displayName, 'Found file should have the same display_name as the file we uploaded')
128
+ invariant(typeof foundFile.getDownloadUri() === 'undefined', 'Found file should not have a download uri yet')
120
129
 
121
130
  if (!isBrowser()) {
122
131
  const downloadableFile = await foundFile.download()
123
- assert(typeof downloadableFile.getDownloadUri() !== 'undefined')
132
+ invariant(typeof downloadableFile.getDownloadUri() !== 'undefined', 'Downloadable file should have a download uri')
124
133
 
125
134
  const downloadedFileContents = await downloadableFile.downloadToString()
126
135
 
127
- assert(sourceFileContents === downloadedFileContents)
136
+ invariant(sourceFileContents === downloadedFileContents, 'Source file contents should match downloaded file contents')
128
137
  }
129
138
 
130
139
  await file.delete()
@@ -141,14 +150,14 @@ const testSuite = async () => {
141
150
 
142
151
  const file = await File.uploadFile(destinationPath, sourceFilePath)
143
152
 
144
- assert(!!file.path)
145
- assert(file.display_name === displayName)
153
+ invariant(!!file.path, 'Uploaded file response object should have a path')
154
+ invariant(file.display_name === displayName, 'Uploaded file response object should have the same display_name as the file we uploaded')
146
155
 
147
156
  const foundFile = await File.find(destinationPath)
148
157
 
149
- assert(foundFile.path === destinationPath)
150
- assert(foundFile.display_name === displayName)
151
- assert(typeof foundFile.getDownloadUri() === 'undefined')
158
+ invariant(foundFile.path === destinationPath, 'Found file should have the same path as the file we uploaded')
159
+ invariant(foundFile.display_name === displayName, 'Found file should have the same display_name as the file we uploaded')
160
+ invariant(typeof foundFile.getDownloadUri() === 'undefined', 'Found file should not have a download uri yet')
152
161
 
153
162
  await file.delete()
154
163
 
@@ -167,7 +176,7 @@ const testSuite = async () => {
167
176
 
168
177
  const session = await Session.create({ username, password })
169
178
 
170
- assert(!!session.id)
179
+ invariant(!!session.id, 'Session should have an id')
171
180
 
172
181
  const manual = await ApiKey.list({ user_id: 0 }, { sessionId: session.id })
173
182
 
@@ -175,7 +184,7 @@ const testSuite = async () => {
175
184
 
176
185
  const auto = await ApiKey.list({ user_id: 0 })
177
186
 
178
- assert(JSON.stringify(manual.attributes) === JSON.stringify(auto.attributes))
187
+ invariant(JSON.stringify(manual.attributes) === JSON.stringify(auto.attributes), 'Manual and auto session API key lists should match')
179
188
 
180
189
  await Session.destroy()
181
190
 
@@ -197,7 +206,7 @@ const testSuite = async () => {
197
206
  caughtInvalidCredentialsError = error instanceof errors.NotAuthenticated_InvalidCredentialsError
198
207
  }
199
208
 
200
- assert(caughtInvalidCredentialsError === true)
209
+ invariant(caughtInvalidCredentialsError === true, 'should have caught an invalid credentials error')
201
210
 
202
211
  // restore valid api key
203
212
  Files.setApiKey(apiKey)
@@ -218,9 +227,9 @@ const testSuite = async () => {
218
227
 
219
228
  const updatedUser = await User.find(firstUser.id)
220
229
 
221
- assert(updatedUser.isLoaded())
222
- assert(oldName !== newName)
223
- assert(updatedUser.name === newName)
230
+ invariant(updatedUser.isLoaded(), 'updated user should be loaded')
231
+ invariant(oldName !== newName, 'old name should not equal new name')
232
+ invariant(updatedUser.name === newName, 'updated user name should match new name')
224
233
 
225
234
  Logger.info('***** testUserListAndUpdate() succeeded! *****');
226
235
  }
@@ -229,13 +238,18 @@ const testSuite = async () => {
229
238
  // execute all tests
230
239
  //
231
240
 
232
- await testFolderListAutoPagination()
233
- await testUploadAndDownloadToFile()
234
- await testUploadAndDownloadToString()
235
- // await testUploadHugeFile() // to run this test, put a file (or symlink) at huge-file.ext
236
- await testSession()
237
- await testFailure()
238
- await testUserListAndUpdate()
241
+ try {
242
+ await testFolderListAutoPagination()
243
+ await testUploadAndDownloadToFile()
244
+ await testUploadAndDownloadToString()
245
+ // await testUploadHugeFile() // to run this test, put a file (or symlink) at huge-file.ext
246
+ await testSession()
247
+ await testFailure()
248
+ await testUserListAndUpdate()
249
+ } catch (error) {
250
+ console.log('*** TEST SUITE FAILED ***')
251
+ console.error(error)
252
+ }
239
253
  }
240
254
 
241
255
  export default testSuite