@firebase/storage 0.9.10 → 0.9.11-20221010203322
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.
- package/CHANGELOG.md +14 -0
- package/dist/index.browser.cjs.js +125 -60
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.esm2017.js +117 -45
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +126 -61
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +116 -44
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/node-esm/index.node.esm.js +117 -45
- package/dist/node-esm/index.node.esm.js.map +1 -1
- package/dist/node-esm/src/implementation/backoff.d.ts +11 -5
- package/dist/node-esm/src/implementation/constants.d.ts +4 -0
- package/dist/node-esm/src/implementation/error.d.ts +5 -1
- package/dist/node-esm/src/implementation/request.d.ts +1 -1
- package/dist/node-esm/src/implementation/utils.d.ts +23 -0
- package/dist/node-esm/src/service.d.ts +1 -1
- package/dist/node-esm/src/task.d.ts +5 -1
- package/dist/node-esm/test/unit/testshared.d.ts +14 -1
- package/dist/node-esm/test/unit/utils.test.d.ts +17 -0
- package/dist/src/implementation/backoff.d.ts +11 -5
- package/dist/src/implementation/constants.d.ts +4 -0
- package/dist/src/implementation/error.d.ts +5 -1
- package/dist/src/implementation/request.d.ts +1 -1
- package/dist/src/implementation/utils.d.ts +23 -0
- package/dist/src/service.d.ts +1 -1
- package/dist/src/task.d.ts +5 -1
- package/dist/storage.d.ts +10 -3
- package/dist/test/unit/testshared.d.ts +14 -1
- package/dist/test/unit/utils.test.d.ts +17 -0
- package/package.json +6 -6
package/dist/index.node.cjs.js
CHANGED
|
@@ -50,7 +50,11 @@ const DEFAULT_MAX_OPERATION_RETRY_TIME = 2 * 60 * 1000;
|
|
|
50
50
|
*
|
|
51
51
|
* The timeout for upload.
|
|
52
52
|
*/
|
|
53
|
-
const DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
|
|
53
|
+
const DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
|
|
54
|
+
/**
|
|
55
|
+
* 1 second
|
|
56
|
+
*/
|
|
57
|
+
const DEFAULT_MIN_SLEEP_TIME_MILLIS = 1000;
|
|
54
58
|
|
|
55
59
|
/**
|
|
56
60
|
* @license
|
|
@@ -77,9 +81,11 @@ class StorageError extends util.FirebaseError {
|
|
|
77
81
|
* @param code - A StorageErrorCode string to be prefixed with 'storage/' and
|
|
78
82
|
* added to the end of the message.
|
|
79
83
|
* @param message - Error message.
|
|
84
|
+
* @param status_ - Corresponding HTTP Status Code
|
|
80
85
|
*/
|
|
81
|
-
constructor(code, message) {
|
|
86
|
+
constructor(code, message, status_ = 0) {
|
|
82
87
|
super(prependCode(code), `Firebase Storage: ${message} (${prependCode(code)})`);
|
|
88
|
+
this.status_ = status_;
|
|
83
89
|
/**
|
|
84
90
|
* Stores custom error data unque to StorageError.
|
|
85
91
|
*/
|
|
@@ -89,6 +95,12 @@ class StorageError extends util.FirebaseError {
|
|
|
89
95
|
// returns false.
|
|
90
96
|
Object.setPrototypeOf(this, StorageError.prototype);
|
|
91
97
|
}
|
|
98
|
+
get status() {
|
|
99
|
+
return this.status_;
|
|
100
|
+
}
|
|
101
|
+
set status(status) {
|
|
102
|
+
this.status_ = status;
|
|
103
|
+
}
|
|
92
104
|
/**
|
|
93
105
|
* Compares a StorageErrorCode against this error's code, filtering out the prefix.
|
|
94
106
|
*/
|
|
@@ -348,14 +360,20 @@ class FailRequest {
|
|
|
348
360
|
* limitations under the License.
|
|
349
361
|
*/
|
|
350
362
|
/**
|
|
351
|
-
*
|
|
352
|
-
*
|
|
353
|
-
*
|
|
354
|
-
*
|
|
363
|
+
* Accepts a callback for an action to perform (`doRequest`),
|
|
364
|
+
* and then a callback for when the backoff has completed (`backoffCompleteCb`).
|
|
365
|
+
* The callback sent to start requires an argument to call (`onRequestComplete`).
|
|
366
|
+
* When `start` calls `doRequest`, it passes a callback for when the request has
|
|
367
|
+
* completed, `onRequestComplete`. Based on this, the backoff continues, with
|
|
368
|
+
* another call to `doRequest` and the above loop continues until the timeout
|
|
369
|
+
* is hit, or a successful response occurs.
|
|
370
|
+
* @description
|
|
371
|
+
* @param doRequest Callback to perform request
|
|
372
|
+
* @param backoffCompleteCb Callback to call when backoff has been completed
|
|
355
373
|
*/
|
|
356
|
-
function start(
|
|
374
|
+
function start(doRequest,
|
|
357
375
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
358
|
-
|
|
376
|
+
backoffCompleteCb, timeout) {
|
|
359
377
|
// TODO(andysoto): make this code cleaner (probably refactor into an actual
|
|
360
378
|
// type instead of a bunch of functions with state shared in the closure)
|
|
361
379
|
let waitSeconds = 1;
|
|
@@ -374,13 +392,13 @@ callback, timeout) {
|
|
|
374
392
|
function triggerCallback(...args) {
|
|
375
393
|
if (!triggeredCallback) {
|
|
376
394
|
triggeredCallback = true;
|
|
377
|
-
|
|
395
|
+
backoffCompleteCb.apply(null, args);
|
|
378
396
|
}
|
|
379
397
|
}
|
|
380
398
|
function callWithDelay(millis) {
|
|
381
399
|
retryTimeoutId = setTimeout(() => {
|
|
382
400
|
retryTimeoutId = null;
|
|
383
|
-
|
|
401
|
+
doRequest(responseHandler, canceled());
|
|
384
402
|
}, millis);
|
|
385
403
|
}
|
|
386
404
|
function clearGlobalTimeout() {
|
|
@@ -388,7 +406,7 @@ callback, timeout) {
|
|
|
388
406
|
clearTimeout(globalTimeoutId);
|
|
389
407
|
}
|
|
390
408
|
}
|
|
391
|
-
function
|
|
409
|
+
function responseHandler(success, ...args) {
|
|
392
410
|
if (triggeredCallback) {
|
|
393
411
|
clearGlobalTimeout();
|
|
394
412
|
return;
|
|
@@ -566,6 +584,43 @@ var ErrorCode;
|
|
|
566
584
|
ErrorCode[ErrorCode["ABORT"] = 2] = "ABORT";
|
|
567
585
|
})(ErrorCode || (ErrorCode = {}));
|
|
568
586
|
|
|
587
|
+
/**
|
|
588
|
+
* @license
|
|
589
|
+
* Copyright 2022 Google LLC
|
|
590
|
+
*
|
|
591
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
592
|
+
* you may not use this file except in compliance with the License.
|
|
593
|
+
* You may obtain a copy of the License at
|
|
594
|
+
*
|
|
595
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
596
|
+
*
|
|
597
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
598
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
599
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
600
|
+
* See the License for the specific language governing permissions and
|
|
601
|
+
* limitations under the License.
|
|
602
|
+
*/
|
|
603
|
+
/**
|
|
604
|
+
* Checks the status code to see if the action should be retried.
|
|
605
|
+
*
|
|
606
|
+
* @param status Current HTTP status code returned by server.
|
|
607
|
+
* @param additionalRetryCodes additional retry codes to check against
|
|
608
|
+
*/
|
|
609
|
+
function isRetryStatusCode(status, additionalRetryCodes) {
|
|
610
|
+
// The codes for which to retry came from this page:
|
|
611
|
+
// https://cloud.google.com/storage/docs/exponential-backoff
|
|
612
|
+
const isFiveHundredCode = status >= 500 && status < 600;
|
|
613
|
+
const extraRetryCodes = [
|
|
614
|
+
// Request Timeout: web server didn't receive full request in time.
|
|
615
|
+
408,
|
|
616
|
+
// Too Many Requests: you're getting rate-limited, basically.
|
|
617
|
+
429
|
|
618
|
+
];
|
|
619
|
+
const isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
|
|
620
|
+
const isAdditionalRetryCode = additionalRetryCodes.indexOf(status) !== -1;
|
|
621
|
+
return isFiveHundredCode || isExtraRetryCode || isAdditionalRetryCode;
|
|
622
|
+
}
|
|
623
|
+
|
|
569
624
|
/**
|
|
570
625
|
* @license
|
|
571
626
|
* Copyright 2017 Google LLC
|
|
@@ -591,7 +646,7 @@ var ErrorCode;
|
|
|
591
646
|
* happens in the specified `callback_`.
|
|
592
647
|
*/
|
|
593
648
|
class NetworkRequest {
|
|
594
|
-
constructor(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_) {
|
|
649
|
+
constructor(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_, retry = true) {
|
|
595
650
|
this.url_ = url_;
|
|
596
651
|
this.method_ = method_;
|
|
597
652
|
this.headers_ = headers_;
|
|
@@ -603,6 +658,7 @@ class NetworkRequest {
|
|
|
603
658
|
this.timeout_ = timeout_;
|
|
604
659
|
this.progressCallback_ = progressCallback_;
|
|
605
660
|
this.connectionFactory_ = connectionFactory_;
|
|
661
|
+
this.retry = retry;
|
|
606
662
|
this.pendingConnection_ = null;
|
|
607
663
|
this.backoffId_ = null;
|
|
608
664
|
this.canceled_ = false;
|
|
@@ -626,9 +682,7 @@ class NetworkRequest {
|
|
|
626
682
|
this.pendingConnection_ = connection;
|
|
627
683
|
const progressListener = progressEvent => {
|
|
628
684
|
const loaded = progressEvent.loaded;
|
|
629
|
-
const total = progressEvent.lengthComputable
|
|
630
|
-
? progressEvent.total
|
|
631
|
-
: -1;
|
|
685
|
+
const total = progressEvent.lengthComputable ? progressEvent.total : -1;
|
|
632
686
|
if (this.progressCallback_ !== null) {
|
|
633
687
|
this.progressCallback_(loaded, total);
|
|
634
688
|
}
|
|
@@ -647,7 +701,9 @@ class NetworkRequest {
|
|
|
647
701
|
this.pendingConnection_ = null;
|
|
648
702
|
const hitServer = connection.getErrorCode() === ErrorCode.NO_ERROR;
|
|
649
703
|
const status = connection.getStatus();
|
|
650
|
-
if (!hitServer ||
|
|
704
|
+
if ((!hitServer ||
|
|
705
|
+
isRetryStatusCode(status, this.additionalRetryCodes_)) &&
|
|
706
|
+
this.retry) {
|
|
651
707
|
const wasCanceled = connection.getErrorCode() === ErrorCode.ABORT;
|
|
652
708
|
backoffCallback(false, new RequestEndStatus(false, null, wasCanceled));
|
|
653
709
|
return;
|
|
@@ -723,20 +779,6 @@ class NetworkRequest {
|
|
|
723
779
|
this.pendingConnection_.abort();
|
|
724
780
|
}
|
|
725
781
|
}
|
|
726
|
-
isRetryStatusCode_(status) {
|
|
727
|
-
// The codes for which to retry came from this page:
|
|
728
|
-
// https://cloud.google.com/storage/docs/exponential-backoff
|
|
729
|
-
const isFiveHundredCode = status >= 500 && status < 600;
|
|
730
|
-
const extraRetryCodes = [
|
|
731
|
-
// Request Timeout: web server didn't receive full request in time.
|
|
732
|
-
408,
|
|
733
|
-
// Too Many Requests: you're getting rate-limited, basically.
|
|
734
|
-
429
|
|
735
|
-
];
|
|
736
|
-
const isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
|
|
737
|
-
const isRequestSpecificRetryCode = this.additionalRetryCodes_.indexOf(status) !== -1;
|
|
738
|
-
return isFiveHundredCode || isExtraRetryCode || isRequestSpecificRetryCode;
|
|
739
|
-
}
|
|
740
782
|
}
|
|
741
783
|
/**
|
|
742
784
|
* A collection of information about the result of a network request.
|
|
@@ -768,7 +810,7 @@ function addAppCheckHeader_(headers, appCheckToken) {
|
|
|
768
810
|
headers['X-Firebase-AppCheck'] = appCheckToken;
|
|
769
811
|
}
|
|
770
812
|
}
|
|
771
|
-
function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion) {
|
|
813
|
+
function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion, retry = true) {
|
|
772
814
|
const queryPart = makeQueryString(requestInfo.urlParams);
|
|
773
815
|
const url = requestInfo.url + queryPart;
|
|
774
816
|
const headers = Object.assign({}, requestInfo.headers);
|
|
@@ -776,7 +818,7 @@ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactor
|
|
|
776
818
|
addAuthHeader_(headers, authToken);
|
|
777
819
|
addVersionHeader_(headers, firebaseVersion);
|
|
778
820
|
addAppCheckHeader_(headers, appCheckToken);
|
|
779
|
-
return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory);
|
|
821
|
+
return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory, retry);
|
|
780
822
|
}
|
|
781
823
|
|
|
782
824
|
/**
|
|
@@ -1598,6 +1640,7 @@ function sharedErrorHandler(location) {
|
|
|
1598
1640
|
}
|
|
1599
1641
|
}
|
|
1600
1642
|
}
|
|
1643
|
+
newErr.status = xhr.getStatus();
|
|
1601
1644
|
newErr.serverResponse = err.serverResponse;
|
|
1602
1645
|
return newErr;
|
|
1603
1646
|
}
|
|
@@ -1882,7 +1925,16 @@ function continueResumableUpload(location, service, url, blob, chunkSize, mappin
|
|
|
1882
1925
|
}
|
|
1883
1926
|
const startByte = status_.current;
|
|
1884
1927
|
const endByte = startByte + bytesToUpload;
|
|
1885
|
-
|
|
1928
|
+
let uploadCommand = '';
|
|
1929
|
+
if (bytesToUpload === 0) {
|
|
1930
|
+
uploadCommand = 'finalize';
|
|
1931
|
+
}
|
|
1932
|
+
else if (bytesLeft === bytesToUpload) {
|
|
1933
|
+
uploadCommand = 'upload, finalize';
|
|
1934
|
+
}
|
|
1935
|
+
else {
|
|
1936
|
+
uploadCommand = 'upload';
|
|
1937
|
+
}
|
|
1886
1938
|
const headers = {
|
|
1887
1939
|
'X-Goog-Upload-Command': uploadCommand,
|
|
1888
1940
|
'X-Goog-Upload-Offset': `${status_.current}`
|
|
@@ -2257,6 +2309,18 @@ class UploadTask {
|
|
|
2257
2309
|
this.completeTransitions_();
|
|
2258
2310
|
}
|
|
2259
2311
|
else {
|
|
2312
|
+
const backoffExpired = this.isExponentialBackoffExpired();
|
|
2313
|
+
if (isRetryStatusCode(error.status, [])) {
|
|
2314
|
+
if (backoffExpired) {
|
|
2315
|
+
error = retryLimitExceeded();
|
|
2316
|
+
}
|
|
2317
|
+
else {
|
|
2318
|
+
this.sleepTime = Math.max(this.sleepTime * 2, DEFAULT_MIN_SLEEP_TIME_MILLIS);
|
|
2319
|
+
this._needToFetchStatus = true;
|
|
2320
|
+
this.completeTransitions_();
|
|
2321
|
+
return;
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2260
2324
|
this._error = error;
|
|
2261
2325
|
this._transition("error" /* ERROR */);
|
|
2262
2326
|
}
|
|
@@ -2271,6 +2335,8 @@ class UploadTask {
|
|
|
2271
2335
|
this._transition("error" /* ERROR */);
|
|
2272
2336
|
}
|
|
2273
2337
|
};
|
|
2338
|
+
this.sleepTime = 0;
|
|
2339
|
+
this.maxSleepTime = this._ref.storage.maxUploadRetryTime;
|
|
2274
2340
|
this._promise = new Promise((resolve, reject) => {
|
|
2275
2341
|
this._resolve = resolve;
|
|
2276
2342
|
this._reject = reject;
|
|
@@ -2280,6 +2346,9 @@ class UploadTask {
|
|
|
2280
2346
|
// to the top level with a dummy handler.
|
|
2281
2347
|
this._promise.then(null, () => { });
|
|
2282
2348
|
}
|
|
2349
|
+
isExponentialBackoffExpired() {
|
|
2350
|
+
return this.sleepTime > this.maxSleepTime;
|
|
2351
|
+
}
|
|
2283
2352
|
_makeProgressCallback() {
|
|
2284
2353
|
const sizeBefore = this._transferred;
|
|
2285
2354
|
return loaded => this._updateProgress(sizeBefore + loaded);
|
|
@@ -2309,7 +2378,9 @@ class UploadTask {
|
|
|
2309
2378
|
this._fetchMetadata();
|
|
2310
2379
|
}
|
|
2311
2380
|
else {
|
|
2312
|
-
|
|
2381
|
+
setTimeout(() => {
|
|
2382
|
+
this._continueUpload();
|
|
2383
|
+
}, this.sleepTime);
|
|
2313
2384
|
}
|
|
2314
2385
|
}
|
|
2315
2386
|
}
|
|
@@ -2385,7 +2456,9 @@ class UploadTask {
|
|
|
2385
2456
|
this._transition("error" /* ERROR */);
|
|
2386
2457
|
return;
|
|
2387
2458
|
}
|
|
2388
|
-
const uploadRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken
|
|
2459
|
+
const uploadRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken,
|
|
2460
|
+
/*retry=*/ false // Upload requests should not be retried as each retry should be preceded by another query request. Which is handled in this file.
|
|
2461
|
+
);
|
|
2389
2462
|
this._request = uploadRequest;
|
|
2390
2463
|
uploadRequest.getPromise().then((newStatus) => {
|
|
2391
2464
|
this._increaseMultiplier();
|
|
@@ -2404,7 +2477,7 @@ class UploadTask {
|
|
|
2404
2477
|
_increaseMultiplier() {
|
|
2405
2478
|
const currentSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
|
|
2406
2479
|
// Max chunk size is 32M.
|
|
2407
|
-
if (currentSize < 32 * 1024 * 1024) {
|
|
2480
|
+
if (currentSize * 2 < 32 * 1024 * 1024) {
|
|
2408
2481
|
this._chunkMultiplier *= 2;
|
|
2409
2482
|
}
|
|
2410
2483
|
}
|
|
@@ -2553,6 +2626,7 @@ class UploadTask {
|
|
|
2553
2626
|
* callbacks.
|
|
2554
2627
|
*/
|
|
2555
2628
|
on(type, nextOrObserver, error, completed) {
|
|
2629
|
+
// Note: `type` isn't being used. Its type is also incorrect. TaskEvent should not be a string.
|
|
2556
2630
|
const observer = new Observer(nextOrObserver || undefined, error || undefined, completed || undefined);
|
|
2557
2631
|
this._addObserver(observer);
|
|
2558
2632
|
return () => {
|
|
@@ -3255,9 +3329,9 @@ class FirebaseStorageImpl {
|
|
|
3255
3329
|
* @param requestInfo - HTTP RequestInfo object
|
|
3256
3330
|
* @param authToken - Firebase auth token
|
|
3257
3331
|
*/
|
|
3258
|
-
_makeRequest(requestInfo, requestFactory, authToken, appCheckToken) {
|
|
3332
|
+
_makeRequest(requestInfo, requestFactory, authToken, appCheckToken, retry = true) {
|
|
3259
3333
|
if (!this._deleted) {
|
|
3260
|
-
const request = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion);
|
|
3334
|
+
const request = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion, retry);
|
|
3261
3335
|
this._requests.add(request);
|
|
3262
3336
|
// Request removes itself from set when complete.
|
|
3263
3337
|
request.getPromise().then(() => this._requests.delete(request), () => this._requests.delete(request));
|
|
@@ -3277,7 +3351,7 @@ class FirebaseStorageImpl {
|
|
|
3277
3351
|
}
|
|
3278
3352
|
|
|
3279
3353
|
const name = "@firebase/storage";
|
|
3280
|
-
const version = "0.9.
|
|
3354
|
+
const version = "0.9.11-20221010203322";
|
|
3281
3355
|
|
|
3282
3356
|
/**
|
|
3283
3357
|
* @license
|
|
@@ -3492,11 +3566,9 @@ function getStorage(app$1 = app.getApp(), bucketUrl) {
|
|
|
3492
3566
|
const storageInstance = storageProvider.getImmediate({
|
|
3493
3567
|
identifier: bucketUrl
|
|
3494
3568
|
});
|
|
3495
|
-
const
|
|
3496
|
-
if (
|
|
3497
|
-
|
|
3498
|
-
// eslint-disable-next-line no-restricted-globals
|
|
3499
|
-
connectStorageEmulator(storageInstance, host, parseInt(port, 10));
|
|
3569
|
+
const emulator = util.getDefaultEmulatorHostnameAndPort('storage');
|
|
3570
|
+
if (emulator) {
|
|
3571
|
+
connectStorageEmulator(storageInstance, ...emulator);
|
|
3500
3572
|
}
|
|
3501
3573
|
return storageInstance;
|
|
3502
3574
|
}
|