box-node-sdk 1.36.0 → 1.38.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/CHANGELOG.md +45 -3
  2. package/README.md +3 -1
  3. package/lib/api-request-manager.d.ts +38 -0
  4. package/lib/api-request-manager.js +48 -55
  5. package/lib/api-request-manager.js.map +1 -0
  6. package/lib/api-request.d.ts +137 -0
  7. package/lib/api-request.js +202 -281
  8. package/lib/api-request.js.map +1 -0
  9. package/lib/box-client.d.ts +269 -0
  10. package/lib/box-client.js +551 -713
  11. package/lib/box-client.js.map +1 -0
  12. package/lib/box-node-sdk.d.ts +216 -0
  13. package/lib/box-node-sdk.js +317 -352
  14. package/lib/box-node-sdk.js.map +1 -0
  15. package/lib/chunked-uploader.d.ts +129 -0
  16. package/lib/chunked-uploader.js +287 -358
  17. package/lib/chunked-uploader.js.map +1 -0
  18. package/lib/enterprise-event-stream.d.ts +82 -0
  19. package/lib/enterprise-event-stream.js +189 -203
  20. package/lib/enterprise-event-stream.js.map +1 -0
  21. package/lib/event-stream.d.ts +92 -0
  22. package/lib/event-stream.js +274 -302
  23. package/lib/event-stream.js.map +1 -0
  24. package/lib/managers/collaboration-allowlist.d.ts +137 -0
  25. package/lib/managers/collaboration-allowlist.js +200 -0
  26. package/lib/managers/collaboration-allowlist.js.map +1 -0
  27. package/lib/managers/collaboration-whitelist.d.ts +3 -0
  28. package/lib/managers/collaboration-whitelist.js +8 -222
  29. package/lib/managers/collaboration-whitelist.js.map +1 -0
  30. package/lib/managers/collaborations.d.ts +166 -0
  31. package/lib/managers/collaborations.js +225 -258
  32. package/lib/managers/collaborations.js.map +1 -0
  33. package/lib/managers/collections.d.ts +42 -0
  34. package/lib/managers/collections.js +45 -50
  35. package/lib/managers/collections.js.map +1 -0
  36. package/lib/managers/comments.d.ts +103 -0
  37. package/lib/managers/comments.js +158 -173
  38. package/lib/managers/comments.js.map +1 -0
  39. package/lib/managers/device-pins.d.ts +52 -0
  40. package/lib/managers/device-pins.js +75 -88
  41. package/lib/managers/device-pins.js.map +1 -0
  42. package/lib/managers/enterprise.d.ts +162 -0
  43. package/lib/managers/enterprise.js +168 -199
  44. package/lib/managers/enterprise.js.map +1 -0
  45. package/lib/managers/events.d.ts +179 -0
  46. package/lib/managers/events.js +232 -254
  47. package/lib/managers/events.js.map +1 -0
  48. package/lib/managers/files.d.ts +773 -0
  49. package/lib/managers/files.js +1401 -1602
  50. package/lib/managers/files.js.map +1 -0
  51. package/lib/managers/folders.d.ts +347 -0
  52. package/lib/managers/folders.js +551 -630
  53. package/lib/managers/folders.js.map +1 -0
  54. package/lib/managers/groups.d.ts +202 -0
  55. package/lib/managers/groups.js +238 -288
  56. package/lib/managers/groups.js.map +1 -0
  57. package/lib/managers/legal-hold-policies.d.ts +190 -0
  58. package/lib/managers/legal-hold-policies.js +228 -272
  59. package/lib/managers/legal-hold-policies.js.map +1 -0
  60. package/lib/managers/metadata.d.ts +228 -0
  61. package/lib/managers/metadata.js +265 -328
  62. package/lib/managers/metadata.js.map +1 -0
  63. package/lib/managers/recent-items.d.ts +38 -0
  64. package/lib/managers/recent-items.js +32 -39
  65. package/lib/managers/recent-items.js.map +1 -0
  66. package/lib/managers/retention-policies.d.ts +251 -0
  67. package/lib/managers/retention-policies.js +278 -281
  68. package/lib/managers/retention-policies.js.map +1 -0
  69. package/lib/managers/search.d.ts +82 -0
  70. package/lib/managers/search.js +68 -88
  71. package/lib/managers/search.js.map +1 -0
  72. package/lib/managers/shared-items.d.ts +33 -0
  73. package/lib/managers/shared-items.js +54 -62
  74. package/lib/managers/shared-items.js.map +1 -0
  75. package/lib/managers/storage-policies.d.ts +86 -0
  76. package/lib/managers/storage-policies.js +108 -142
  77. package/lib/managers/storage-policies.js.map +1 -0
  78. package/lib/managers/tasks.d.ts +161 -0
  79. package/lib/managers/tasks.js +219 -260
  80. package/lib/managers/tasks.js.map +1 -0
  81. package/lib/managers/terms-of-service.d.ts +161 -0
  82. package/lib/managers/terms-of-service.js +250 -273
  83. package/lib/managers/terms-of-service.js.map +1 -0
  84. package/lib/managers/trash.d.ts +30 -0
  85. package/lib/managers/trash.js +30 -41
  86. package/lib/managers/trash.js.map +1 -0
  87. package/lib/managers/users.d.ts +130 -0
  88. package/lib/managers/users.js +160 -203
  89. package/lib/managers/users.js.map +1 -0
  90. package/lib/managers/web-links.d.ts +127 -0
  91. package/lib/managers/web-links.js +183 -209
  92. package/lib/managers/web-links.js.map +1 -0
  93. package/lib/managers/webhooks.d.ts +166 -0
  94. package/lib/managers/webhooks.js +312 -305
  95. package/lib/managers/webhooks.js.map +1 -0
  96. package/lib/sessions/anonymous-session.d.ts +69 -0
  97. package/lib/sessions/anonymous-session.js +88 -102
  98. package/lib/sessions/anonymous-session.js.map +1 -0
  99. package/lib/sessions/app-auth-session.d.ts +92 -0
  100. package/lib/sessions/app-auth-session.js +140 -160
  101. package/lib/sessions/app-auth-session.js.map +1 -0
  102. package/lib/sessions/basic-session.d.ts +56 -0
  103. package/lib/sessions/basic-session.js +40 -50
  104. package/lib/sessions/basic-session.js.map +1 -0
  105. package/lib/sessions/persistent-session.d.ts +96 -0
  106. package/lib/sessions/persistent-session.js +191 -211
  107. package/lib/sessions/persistent-session.js.map +1 -0
  108. package/lib/token-manager.d.ts +191 -0
  109. package/lib/token-manager.js +390 -465
  110. package/lib/token-manager.js.map +1 -0
  111. package/lib/util/config.d.ts +86 -0
  112. package/lib/util/config.js +146 -152
  113. package/lib/util/config.js.map +1 -0
  114. package/lib/util/errors.d.ts +50 -0
  115. package/lib/util/errors.js +134 -145
  116. package/lib/util/errors.js.map +1 -0
  117. package/lib/util/exponential-backoff.d.ts +11 -0
  118. package/lib/util/exponential-backoff.js +10 -22
  119. package/lib/util/exponential-backoff.js.map +1 -0
  120. package/lib/util/paging-iterator.d.ts +53 -0
  121. package/lib/util/paging-iterator.js +202 -218
  122. package/lib/util/paging-iterator.js.map +1 -0
  123. package/lib/util/url-path.d.ts +16 -0
  124. package/lib/util/url-path.js +20 -35
  125. package/lib/util/url-path.js.map +1 -0
  126. package/package.json +14 -3
@@ -1,378 +1,307 @@
1
+ "use strict";
1
2
  /**
2
3
  * @fileoverview Upload manager for large file uploads
3
4
  */
4
-
5
- 'use strict';
6
-
7
- const Promise = require('bluebird');
8
-
9
- // -----------------------------------------------------------------------------
10
- // Typedefs
11
- // -----------------------------------------------------------------------------
12
-
13
- /**
14
- * Chunk uploaded event
15
- * @event Chunk#uploaded
16
- * @param {UploadPart} data The data of the uploaded chunk
17
- * @private
18
- */
19
-
20
- /**
21
- * Chunk error event
22
- * @event Chunk#error
23
- * @param {Error} err The error that occurred
24
- * @private
25
- */
26
-
27
- /**
28
- * Event for when the upload is successfully aborted
29
- * @event ChunkedUploader#aborted
30
- */
31
-
32
- /**
33
- * Event for when the abort fails because the upload session is not destroyed.
34
- * In general, the abort can be retried, and no new chunks will be uploaded.
35
- * @event ChunkedUploader#abortFailed
36
- * @param {Error} err The error that occurred
37
- */
38
-
39
- /**
40
- * Event for when a chunk fails to upload. Note that the chunk will automatically
41
- * retry until it is successfully uploaded.
42
- * @event ChunkedUploader#chunkError
43
- * @param {Error} err The error that occurred during chunk upload
44
- */
45
-
46
- /**
47
- * Event for when a chunk is successfully uploaded
48
- * @event ChunkedUploader#chunkUploaded
49
- * @param {UploadPart} data The data for the uploaded chunk
50
- */
51
-
52
- /**
53
- * Event for when the entire upload is complete
54
- * @event ChunkedUploader#uploadComplete
55
- * @param {Object} file The file object for the newly-uploaded file
56
- */
57
-
58
- /**
59
- * Event for when an upload fails
60
- * @event ChunkedUploader#error
61
- * @param {Error} err The error that occurred
62
- */
63
-
5
+ var __extends = (this && this.__extends) || (function () {
6
+ var extendStatics = function (d, b) {
7
+ extendStatics = Object.setPrototypeOf ||
8
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
9
+ function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
10
+ return extendStatics(d, b);
11
+ };
12
+ return function (d, b) {
13
+ if (typeof b !== "function" && b !== null)
14
+ throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
15
+ extendStatics(d, b);
16
+ function __() { this.constructor = d; }
17
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
18
+ };
19
+ })();
20
+ var __importDefault = (this && this.__importDefault) || function (mod) {
21
+ return (mod && mod.__esModule) ? mod : { "default": mod };
22
+ };
23
+ var bluebird_1 = require("bluebird");
64
24
  // -----------------------------------------------------------------------------
65
25
  // Requirements
66
26
  // -----------------------------------------------------------------------------
67
-
68
- const EventEmitter = require('events').EventEmitter,
69
- ReadableStream = require('stream').Readable,
70
- crypto = require('crypto');
71
-
27
+ var events_1 = require("events");
28
+ var stream_1 = require("stream");
29
+ var crypto_1 = __importDefault(require("crypto"));
72
30
  // -----------------------------------------------------------------------------
73
31
  // Private
74
32
  // -----------------------------------------------------------------------------
75
-
76
- const DEFAULT_OPTIONS = Object.freeze({
77
- parallelism: 4,
78
- retryInterval: 1000
33
+ var DEFAULT_OPTIONS = Object.freeze({
34
+ parallelism: 4,
35
+ retryInterval: 1000,
79
36
  });
80
-
81
37
  /**
82
38
  * Chunk of a file to be uploaded, which handles trying to upload itself until
83
39
  * it succeeds.
84
40
  * @private
85
41
  */
86
- class Chunk extends EventEmitter {
87
-
88
- /**
89
- * Create a Chunk, representing a part of a file being uploaded
90
- * @param {BoxClient} client The Box SDK client
91
- * @param {string} sessionID The ID of the upload session the chunk belongs to
92
- * @param {Buffer|string} chunk The chunk that was uploaded
93
- * @param {int} offset The byte offset within the file where this chunk begins
94
- * @param {int} totalSize The total size of the file this chunk belongs to
95
- * @param {Object} options The options from the ChunkedUploader
96
- * @param {int} options.retryInterval The number of ms to wait before retrying a chunk upload
97
- */
98
- constructor(client, sessionID, chunk, offset, totalSize, options) {
99
-
100
- super();
101
-
102
- this.client = client;
103
- this.sessionID = sessionID;
104
- this.chunk = chunk;
105
- this.length = chunk.length;
106
- this.offset = offset;
107
- this.totalSize = totalSize;
108
- this.options = options;
109
- this.data = null;
110
- this.retry = null;
111
- this.canceled = false;
112
- }
113
-
114
- /**
115
- * Get the final object representation of this chunk for the API
116
- * @returns {UploadPart} The chunk object
117
- */
118
- getData() {
119
-
120
- return this.data.part;
121
- }
122
-
123
- /**
124
- * Upload a chunk to the API
125
- * @returns {void}
126
- * @emits Chunk#uploaded
127
- * @emits Chunk#error
128
- */
129
- upload() {
130
-
131
- this.client.files.uploadPart(this.sessionID, this.chunk, this.offset, this.totalSize, (err, data) => {
132
-
133
- if (this.canceled) {
134
- this.chunk = null;
135
- return;
136
- }
137
-
138
- if (err) {
139
- // handle the error or retry
140
- if (err.statusCode) {
141
- // an API error, probably not retryable!
142
- this.emit('error', err);
143
- } else {
144
- // maybe a network error, retry
145
- this.retry = setTimeout(() => this.upload(), this.options.retryInterval);
146
- }
147
- return;
148
- }
149
-
150
- // Record the chunk data for commit, and try to free up the chunk buffer
151
- this.data = data;
152
- this.chunk = null;
153
- this.emit('uploaded', data);
154
- });
155
- }
156
-
157
- /**
158
- * Cancel trying to upload a chunk, preventing it from retrying and clearing
159
- * the associated buffer
160
- * @returns {void}
161
- */
162
- cancel() {
163
-
164
- clearTimeout(this.retry);
165
- this.chunk = null;
166
- this.canceled = true;
167
- }
168
- }
169
-
42
+ var Chunk = /** @class */ (function (_super) {
43
+ __extends(Chunk, _super);
44
+ /**
45
+ * Create a Chunk, representing a part of a file being uploaded
46
+ * @param {BoxClient} client The Box SDK client
47
+ * @param {string} sessionID The ID of the upload session the chunk belongs to
48
+ * @param {Buffer|string} chunk The chunk that was uploaded
49
+ * @param {int} offset The byte offset within the file where this chunk begins
50
+ * @param {int} totalSize The total size of the file this chunk belongs to
51
+ * @param {Object} options The options from the ChunkedUploader
52
+ * @param {int} options.retryInterval The number of ms to wait before retrying a chunk upload
53
+ */
54
+ function Chunk(client, sessionID, chunk, offset, totalSize, options) {
55
+ var _this = _super.call(this) || this;
56
+ _this.client = client;
57
+ _this.sessionID = sessionID;
58
+ _this.chunk = chunk;
59
+ _this.length = chunk.length;
60
+ _this.offset = offset;
61
+ _this.totalSize = totalSize;
62
+ _this.options = options;
63
+ _this.data = null;
64
+ _this.retry = null;
65
+ _this.canceled = false;
66
+ return _this;
67
+ }
68
+ /**
69
+ * Get the final object representation of this chunk for the API
70
+ * @returns {UploadPart} The chunk object
71
+ */
72
+ Chunk.prototype.getData = function () {
73
+ return this.data.part;
74
+ };
75
+ /**
76
+ * Upload a chunk to the API
77
+ * @returns {void}
78
+ * @emits Chunk#uploaded
79
+ * @emits Chunk#error
80
+ */
81
+ Chunk.prototype.upload = function () {
82
+ var _this = this;
83
+ this.client.files.uploadPart(this.sessionID, this.chunk, this.offset, this.totalSize, function (err /* FIXME */, data /* FIXME */) {
84
+ if (_this.canceled) {
85
+ _this.chunk = null;
86
+ return;
87
+ }
88
+ if (err) {
89
+ // handle the error or retry
90
+ if (err.statusCode) {
91
+ // an API error, probably not retryable!
92
+ _this.emit('error', err);
93
+ }
94
+ else {
95
+ // maybe a network error, retry
96
+ _this.retry = setTimeout(function () { return _this.upload(); }, _this.options.retryInterval);
97
+ }
98
+ return;
99
+ }
100
+ // Record the chunk data for commit, and try to free up the chunk buffer
101
+ _this.data = data;
102
+ _this.chunk = null;
103
+ _this.emit('uploaded', data);
104
+ });
105
+ };
106
+ /**
107
+ * Cancel trying to upload a chunk, preventing it from retrying and clearing
108
+ * the associated buffer
109
+ * @returns {void}
110
+ */
111
+ Chunk.prototype.cancel = function () {
112
+ clearTimeout(this.retry); // number or NodeJS.Timeout
113
+ this.chunk = null;
114
+ this.canceled = true;
115
+ };
116
+ return Chunk;
117
+ }(events_1.EventEmitter));
170
118
  // -----------------------------------------------------------------------------
171
119
  // Public
172
120
  // -----------------------------------------------------------------------------
173
-
174
121
  /** Manager for uploading a file in chunks */
175
- class ChunkedUploader extends EventEmitter {
176
-
177
- /**
178
- * Create an upload manager
179
- * @param {BoxClient} client The client to use to upload the file
180
- * @param {Object} uploadSessionInfo The upload session info to use for chunked upload
181
- * @param {ReadableStream|Buffer|string} file The file to upload
182
- * @param {int} size The size of the file to be uploaded
183
- * @param {Object} [options] Optional parameters
184
- * @param {int} [options.retryInterval=1000] The number of ms to wait before retrying operations
185
- * @param {int} [options.parallelism=4] The number of concurrent chunks to upload
186
- * @param {Object} [options.fileAttributes] Attributes to set on the file during commit
187
- */
188
- constructor(client, uploadSessionInfo, file, size, options) {
189
-
190
- super();
191
-
192
- this._client = client;
193
- this._sessionID = uploadSessionInfo.id;
194
- this._partSize = uploadSessionInfo.part_size;
195
- this._uploadSessionInfo = uploadSessionInfo;
196
-
197
- if (file instanceof ReadableStream) {
198
- // Pause the stream so we can read specific chunks from it
199
- this._stream = file.pause();
200
- this._streamBuffer = [];
201
- } else if (file instanceof Buffer || typeof file === 'string') {
202
- this._file = file;
203
- } else {
204
- throw new TypeError('file must be a Stream, Buffer, or string!');
205
- }
206
-
207
- this._size = size;
208
- this._options = Object.assign({}, DEFAULT_OPTIONS, options);
209
-
210
- this._isStarted = false;
211
- this._numChunksInFlight = 0;
212
- this._chunks = [];
213
- this._position = 0;
214
- this._fileHash = crypto.createHash('sha1');
215
- }
216
-
217
- /**
218
- * Start an upload
219
- * @returns {Promise<Object>} A promise resolving to the uploaded file
220
- */
221
- start() {
222
-
223
- if (this._isStarted) {
224
- return this._promise;
225
- }
226
-
227
- // Create the initial chunks
228
- for (let i = 0; i < this._options.parallelism; i++) {
229
- this._getNextChunk(chunk => (chunk ? this._uploadChunk(chunk) : this._commit()));
230
- }
231
- this._isStarted = true;
232
-
233
- /* eslint-disable promise/avoid-new */
234
- this._promise = new Promise((resolve, reject) => {
235
- this._resolve = resolve;
236
- this._reject = reject;
237
- });
238
- /* eslint-enable promise/avoid-new */
239
-
240
- return this._promise;
241
- }
242
-
243
- /**
244
- * Abort a running upload, which cancels all currently uploading chunks,
245
- * attempts to free up held memory, and aborts the upload session. This
246
- * cannot be undone or resumed.
247
- * @returns {Promise} A promise resolving when the upload is aborted
248
- * @emits ChunkedUploader#aborted
249
- * @emits ChunkedUploader#abortFailed
250
- */
251
- abort() {
252
-
253
- this._chunks.forEach(chunk => chunk.removeAllListeners().cancel());
254
- this._chunks = [];
255
- this._file = null;
256
- this._stream = null;
257
-
258
- return this._client.files.abortUploadSession(this._sessionID)
259
- /* eslint-disable promise/always-return */
260
- .then(() => {
261
- this.emit('aborted');
262
- })
263
- /* eslint-enable promise/always-return */
264
- .catch(err => {
265
- this.emit('abortFailed', err);
266
- throw err;
267
- });
268
- }
269
-
270
- /**
271
- * Get the next chunk of the file to be uploaded
272
- * @param {Function} callback Called with the next chunk of the file to be uploaded
273
- * @returns {void}
274
- * @private
275
- */
276
- _getNextChunk(callback) {
277
-
278
- if (this._position >= this._size) {
279
- callback(null);
280
- return;
281
- }
282
-
283
- let buf;
284
-
285
- if (this._file) {
286
-
287
- // Buffer/string case, just get the slice we need
288
- buf = this._file.slice(this._position, this._position + this._partSize);
289
- } else if (this._streamBuffer.length > 0) {
290
-
291
- buf = this._streamBuffer.shift();
292
- } else {
293
-
294
- // Stream case, need to read
295
- buf = this._stream.read(this._partSize);
296
-
297
- if (!buf) {
298
- // stream needs to read more, retry later
299
- setImmediate(() => this._getNextChunk(callback));
300
- return;
301
- } else if (buf.length > this._partSize) {
302
-
303
- // stream is done reading and had extra data, buffer the remainder of the file
304
- for (let i = 0; i < buf.length; i += this._partSize) {
305
-
306
- this._streamBuffer.push(buf.slice(i, i + this._partSize));
307
- }
308
- buf = this._streamBuffer.shift();
309
- }
310
- }
311
-
312
- this._fileHash.update(buf);
313
- let chunk = new Chunk(this._client, this._sessionID, buf, this._position, this._size, this._options);
314
- this._position += buf.length;
315
- callback(chunk);
316
- }
317
-
318
- /**
319
- * Upload a chunk
320
- * @param {Chunk} chunk The chunk to upload
321
- * @returns {void}
322
- * @emits ChunkedUploader#chunkError
323
- * @emits ChunkedUploader#chunkUploaded
324
- */
325
- _uploadChunk(chunk) {
326
-
327
- this._numChunksInFlight += 1;
328
-
329
- chunk.on('error', err => this.emit('chunkError', err));
330
- chunk.on('uploaded', data => {
331
-
332
- this._numChunksInFlight -= 1;
333
-
334
- this.emit('chunkUploaded', data);
335
- this._getNextChunk(nextChunk => (nextChunk ? this._uploadChunk(nextChunk) : this._commit()));
336
- });
337
- chunk.upload();
338
- this._chunks.push(chunk);
339
- }
340
-
341
- /**
342
- * Commit the upload, finalizing it
343
- * @returns {void}
344
- * @emits ChunkedUploader#uploadComplete
345
- * @emits ChunkedUploader#error
346
- */
347
- _commit() {
348
-
349
- if (!this._isStarted || this._numChunksInFlight > 0) {
350
- return;
351
- }
352
-
353
- let hash = this._fileHash.digest('base64');
354
- this._isStarted = false;
355
- let options = Object.assign({
356
- parts: this._chunks.map(c => c.getData())
357
- }, this._options.fileAttributes);
358
- this._client.files.commitUploadSession(this._sessionID, hash, options, (err, file) => {
359
-
360
- // It's not clear what the SDK can do here, so we just return the error and session info
361
- // so users can retry if they wish
362
- if (err) {
363
- this.emit('error', {
364
- uploadSession: this._uploadSessionInfo,
365
- error: err
366
- });
367
- this._reject(err);
368
- return;
369
- }
370
-
371
- this.emit('uploadComplete', file);
372
- this._resolve(file);
373
- });
374
- }
375
-
376
- }
377
-
122
+ var ChunkedUploader = /** @class */ (function (_super) {
123
+ __extends(ChunkedUploader, _super);
124
+ /**
125
+ * Create an upload manager
126
+ * @param {BoxClient} client The client to use to upload the file
127
+ * @param {Object} uploadSessionInfo The upload session info to use for chunked upload
128
+ * @param {ReadableStream|Buffer|string} file The file to upload
129
+ * @param {int} size The size of the file to be uploaded
130
+ * @param {Object} [options] Optional parameters
131
+ * @param {int} [options.retryInterval=1000] The number of ms to wait before retrying operations
132
+ * @param {int} [options.parallelism=4] The number of concurrent chunks to upload
133
+ * @param {Object} [options.fileAttributes] Attributes to set on the file during commit
134
+ */
135
+ function ChunkedUploader(client, uploadSessionInfo, file, size, options) {
136
+ var _this = _super.call(this) || this;
137
+ _this._client = client;
138
+ _this._sessionID = uploadSessionInfo.id;
139
+ _this._partSize = uploadSessionInfo.part_size;
140
+ _this._uploadSessionInfo = uploadSessionInfo;
141
+ if (file instanceof stream_1.Readable) {
142
+ // Pause the stream so we can read specific chunks from it
143
+ _this._stream = file.pause();
144
+ _this._streamBuffer = [];
145
+ }
146
+ else if (file instanceof Buffer || typeof file === 'string') {
147
+ _this._file = file;
148
+ }
149
+ else {
150
+ throw new TypeError('file must be a Stream, Buffer, or string!');
151
+ }
152
+ _this._size = size;
153
+ _this._options = Object.assign({}, DEFAULT_OPTIONS, options);
154
+ _this._isStarted = false;
155
+ _this._numChunksInFlight = 0;
156
+ _this._chunks = [];
157
+ _this._position = 0;
158
+ _this._fileHash = crypto_1.default.createHash('sha1');
159
+ return _this;
160
+ }
161
+ /**
162
+ * Start an upload
163
+ * @returns {Promise<Object>} A promise resolving to the uploaded file
164
+ */
165
+ ChunkedUploader.prototype.start = function () {
166
+ var _this = this;
167
+ if (this._isStarted) {
168
+ return this._promise;
169
+ }
170
+ // Create the initial chunks
171
+ for (var i = 0; i < this._options.parallelism; i++) {
172
+ this._getNextChunk(function (chunk /* FIXME */) {
173
+ return chunk ? _this._uploadChunk(chunk) : _this._commit();
174
+ });
175
+ }
176
+ this._isStarted = true;
177
+ /* eslint-disable promise/avoid-new */
178
+ this._promise = new bluebird_1.Promise(function (resolve, reject) {
179
+ _this._resolve = resolve;
180
+ _this._reject = reject;
181
+ });
182
+ /* eslint-enable promise/avoid-new */
183
+ return this._promise;
184
+ };
185
+ /**
186
+ * Abort a running upload, which cancels all currently uploading chunks,
187
+ * attempts to free up held memory, and aborts the upload session. This
188
+ * cannot be undone or resumed.
189
+ * @returns {Promise} A promise resolving when the upload is aborted
190
+ * @emits ChunkedUploader#aborted
191
+ * @emits ChunkedUploader#abortFailed
192
+ */
193
+ ChunkedUploader.prototype.abort = function () {
194
+ var _this = this;
195
+ this._chunks.forEach(function (chunk) { return chunk.removeAllListeners().cancel(); });
196
+ this._chunks = [];
197
+ this._file = null;
198
+ this._stream = null;
199
+ return (this._client.files
200
+ .abortUploadSession(this._sessionID)
201
+ /* eslint-disable promise/always-return */
202
+ .then(function () {
203
+ _this.emit('aborted');
204
+ })
205
+ /* eslint-enable promise/always-return */
206
+ .catch(function (err /* FIXME */) {
207
+ _this.emit('abortFailed', err);
208
+ throw err;
209
+ }));
210
+ };
211
+ /**
212
+ * Get the next chunk of the file to be uploaded
213
+ * @param {Function} callback Called with the next chunk of the file to be uploaded
214
+ * @returns {void}
215
+ * @private
216
+ */
217
+ ChunkedUploader.prototype._getNextChunk = function (callback) {
218
+ var _this = this;
219
+ if (this._position >= this._size) {
220
+ callback(null);
221
+ return;
222
+ }
223
+ var buf;
224
+ if (this._file) {
225
+ // Buffer/string case, just get the slice we need
226
+ buf = this._file.slice(this._position, this._position + this._partSize);
227
+ }
228
+ else if (this._streamBuffer.length > 0) {
229
+ buf = this._streamBuffer.shift();
230
+ }
231
+ else {
232
+ // Stream case, need to read
233
+ buf = this._stream.read(this._partSize);
234
+ if (!buf) {
235
+ // stream needs to read more, retry later
236
+ setImmediate(function () { return _this._getNextChunk(callback); });
237
+ return;
238
+ }
239
+ else if (buf.length > this._partSize) {
240
+ // stream is done reading and had extra data, buffer the remainder of the file
241
+ for (var i = 0; i < buf.length; i += this._partSize) {
242
+ this._streamBuffer.push(buf.slice(i, i + this._partSize));
243
+ }
244
+ buf = this._streamBuffer.shift();
245
+ }
246
+ }
247
+ this._fileHash.update(buf);
248
+ var chunk = new Chunk(this._client, this._sessionID, buf, this._position, this._size, this._options);
249
+ this._position += buf.length;
250
+ callback(chunk);
251
+ };
252
+ /**
253
+ * Upload a chunk
254
+ * @param {Chunk} chunk The chunk to upload
255
+ * @returns {void}
256
+ * @emits ChunkedUploader#chunkError
257
+ * @emits ChunkedUploader#chunkUploaded
258
+ */
259
+ ChunkedUploader.prototype._uploadChunk = function (chunk /* FIXME */) {
260
+ var _this = this;
261
+ this._numChunksInFlight += 1;
262
+ chunk.on('error', function (err /* FIXME */) { return _this.emit('chunkError', err); });
263
+ chunk.on('uploaded', function (data /* FIXME */) {
264
+ _this._numChunksInFlight -= 1;
265
+ _this.emit('chunkUploaded', data);
266
+ _this._getNextChunk(function (nextChunk /* FIXME */) {
267
+ return nextChunk ? _this._uploadChunk(nextChunk) : _this._commit();
268
+ });
269
+ });
270
+ chunk.upload();
271
+ this._chunks.push(chunk);
272
+ };
273
+ /**
274
+ * Commit the upload, finalizing it
275
+ * @returns {void}
276
+ * @emits ChunkedUploader#uploadComplete
277
+ * @emits ChunkedUploader#error
278
+ */
279
+ ChunkedUploader.prototype._commit = function () {
280
+ var _this = this;
281
+ if (!this._isStarted || this._numChunksInFlight > 0) {
282
+ return;
283
+ }
284
+ var hash = this._fileHash.digest('base64');
285
+ this._isStarted = false;
286
+ var options = Object.assign({
287
+ parts: this._chunks.map(function (c) { return c.getData(); }),
288
+ }, this._options.fileAttributes);
289
+ this._client.files.commitUploadSession(this._sessionID, hash, options, function (err /* FIMXE */, file /* FIMXE */) {
290
+ // It's not clear what the SDK can do here, so we just return the error and session info
291
+ // so users can retry if they wish
292
+ if (err) {
293
+ _this.emit('error', {
294
+ uploadSession: _this._uploadSessionInfo,
295
+ error: err,
296
+ });
297
+ _this._reject(err);
298
+ return;
299
+ }
300
+ _this.emit('uploadComplete', file);
301
+ _this._resolve(file);
302
+ });
303
+ };
304
+ return ChunkedUploader;
305
+ }(events_1.EventEmitter));
378
306
  module.exports = ChunkedUploader;
307
+ //# sourceMappingURL=chunked-uploader.js.map