@firebase/storage 0.9.10 → 0.9.11-20221010190246
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 +11 -0
- package/dist/index.browser.cjs.js +122 -39
- package/dist/index.browser.cjs.js.map +1 -1
- package/dist/index.esm2017.js +113 -39
- package/dist/index.esm2017.js.map +1 -1
- package/dist/index.esm5.js +122 -39
- package/dist/index.esm5.js.map +1 -1
- package/dist/index.node.cjs.js +113 -39
- package/dist/index.node.cjs.js.map +1 -1
- package/dist/node-esm/index.node.esm.js +113 -39
- 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.esm5.js
CHANGED
|
@@ -41,7 +41,11 @@ var DEFAULT_MAX_OPERATION_RETRY_TIME = 2 * 60 * 1000;
|
|
|
41
41
|
*
|
|
42
42
|
* The timeout for upload.
|
|
43
43
|
*/
|
|
44
|
-
var DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
|
|
44
|
+
var DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
|
|
45
|
+
/**
|
|
46
|
+
* 1 second
|
|
47
|
+
*/
|
|
48
|
+
var DEFAULT_MIN_SLEEP_TIME_MILLIS = 1000;
|
|
45
49
|
|
|
46
50
|
/**
|
|
47
51
|
* @license
|
|
@@ -69,9 +73,12 @@ var StorageError = /** @class */ (function (_super) {
|
|
|
69
73
|
* @param code - A StorageErrorCode string to be prefixed with 'storage/' and
|
|
70
74
|
* added to the end of the message.
|
|
71
75
|
* @param message - Error message.
|
|
76
|
+
* @param status_ - Corresponding HTTP Status Code
|
|
72
77
|
*/
|
|
73
|
-
function StorageError(code, message) {
|
|
78
|
+
function StorageError(code, message, status_) {
|
|
79
|
+
if (status_ === void 0) { status_ = 0; }
|
|
74
80
|
var _this = _super.call(this, prependCode(code), "Firebase Storage: " + message + " (" + prependCode(code) + ")") || this;
|
|
81
|
+
_this.status_ = status_;
|
|
75
82
|
/**
|
|
76
83
|
* Stores custom error data unque to StorageError.
|
|
77
84
|
*/
|
|
@@ -82,6 +89,16 @@ var StorageError = /** @class */ (function (_super) {
|
|
|
82
89
|
Object.setPrototypeOf(_this, StorageError.prototype);
|
|
83
90
|
return _this;
|
|
84
91
|
}
|
|
92
|
+
Object.defineProperty(StorageError.prototype, "status", {
|
|
93
|
+
get: function () {
|
|
94
|
+
return this.status_;
|
|
95
|
+
},
|
|
96
|
+
set: function (status) {
|
|
97
|
+
this.status_ = status;
|
|
98
|
+
},
|
|
99
|
+
enumerable: false,
|
|
100
|
+
configurable: true
|
|
101
|
+
});
|
|
85
102
|
/**
|
|
86
103
|
* Compares a StorageErrorCode against this error's code, filtering out the prefix.
|
|
87
104
|
*/
|
|
@@ -357,14 +374,20 @@ var FailRequest = /** @class */ (function () {
|
|
|
357
374
|
* limitations under the License.
|
|
358
375
|
*/
|
|
359
376
|
/**
|
|
360
|
-
*
|
|
361
|
-
*
|
|
362
|
-
*
|
|
363
|
-
*
|
|
377
|
+
* Accepts a callback for an action to perform (`doRequest`),
|
|
378
|
+
* and then a callback for when the backoff has completed (`backoffCompleteCb`).
|
|
379
|
+
* The callback sent to start requires an argument to call (`onRequestComplete`).
|
|
380
|
+
* When `start` calls `doRequest`, it passes a callback for when the request has
|
|
381
|
+
* completed, `onRequestComplete`. Based on this, the backoff continues, with
|
|
382
|
+
* another call to `doRequest` and the above loop continues until the timeout
|
|
383
|
+
* is hit, or a successful response occurs.
|
|
384
|
+
* @description
|
|
385
|
+
* @param doRequest Callback to perform request
|
|
386
|
+
* @param backoffCompleteCb Callback to call when backoff has been completed
|
|
364
387
|
*/
|
|
365
|
-
function start(
|
|
388
|
+
function start(doRequest,
|
|
366
389
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
367
|
-
|
|
390
|
+
backoffCompleteCb, timeout) {
|
|
368
391
|
// TODO(andysoto): make this code cleaner (probably refactor into an actual
|
|
369
392
|
// type instead of a bunch of functions with state shared in the closure)
|
|
370
393
|
var waitSeconds = 1;
|
|
@@ -387,13 +410,13 @@ callback, timeout) {
|
|
|
387
410
|
}
|
|
388
411
|
if (!triggeredCallback) {
|
|
389
412
|
triggeredCallback = true;
|
|
390
|
-
|
|
413
|
+
backoffCompleteCb.apply(null, args);
|
|
391
414
|
}
|
|
392
415
|
}
|
|
393
416
|
function callWithDelay(millis) {
|
|
394
417
|
retryTimeoutId = setTimeout(function () {
|
|
395
418
|
retryTimeoutId = null;
|
|
396
|
-
|
|
419
|
+
doRequest(responseHandler, canceled());
|
|
397
420
|
}, millis);
|
|
398
421
|
}
|
|
399
422
|
function clearGlobalTimeout() {
|
|
@@ -401,7 +424,7 @@ callback, timeout) {
|
|
|
401
424
|
clearTimeout(globalTimeoutId);
|
|
402
425
|
}
|
|
403
426
|
}
|
|
404
|
-
function
|
|
427
|
+
function responseHandler(success) {
|
|
405
428
|
var args = [];
|
|
406
429
|
for (var _i = 1; _i < arguments.length; _i++) {
|
|
407
430
|
args[_i - 1] = arguments[_i];
|
|
@@ -583,6 +606,43 @@ var ErrorCode;
|
|
|
583
606
|
ErrorCode[ErrorCode["ABORT"] = 2] = "ABORT";
|
|
584
607
|
})(ErrorCode || (ErrorCode = {}));
|
|
585
608
|
|
|
609
|
+
/**
|
|
610
|
+
* @license
|
|
611
|
+
* Copyright 2022 Google LLC
|
|
612
|
+
*
|
|
613
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
614
|
+
* you may not use this file except in compliance with the License.
|
|
615
|
+
* You may obtain a copy of the License at
|
|
616
|
+
*
|
|
617
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
618
|
+
*
|
|
619
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
620
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
621
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
622
|
+
* See the License for the specific language governing permissions and
|
|
623
|
+
* limitations under the License.
|
|
624
|
+
*/
|
|
625
|
+
/**
|
|
626
|
+
* Checks the status code to see if the action should be retried.
|
|
627
|
+
*
|
|
628
|
+
* @param status Current HTTP status code returned by server.
|
|
629
|
+
* @param additionalRetryCodes additional retry codes to check against
|
|
630
|
+
*/
|
|
631
|
+
function isRetryStatusCode(status, additionalRetryCodes) {
|
|
632
|
+
// The codes for which to retry came from this page:
|
|
633
|
+
// https://cloud.google.com/storage/docs/exponential-backoff
|
|
634
|
+
var isFiveHundredCode = status >= 500 && status < 600;
|
|
635
|
+
var extraRetryCodes = [
|
|
636
|
+
// Request Timeout: web server didn't receive full request in time.
|
|
637
|
+
408,
|
|
638
|
+
// Too Many Requests: you're getting rate-limited, basically.
|
|
639
|
+
429
|
|
640
|
+
];
|
|
641
|
+
var isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
|
|
642
|
+
var isAdditionalRetryCode = additionalRetryCodes.indexOf(status) !== -1;
|
|
643
|
+
return isFiveHundredCode || isExtraRetryCode || isAdditionalRetryCode;
|
|
644
|
+
}
|
|
645
|
+
|
|
586
646
|
/**
|
|
587
647
|
* @license
|
|
588
648
|
* Copyright 2017 Google LLC
|
|
@@ -608,8 +668,9 @@ var ErrorCode;
|
|
|
608
668
|
* happens in the specified `callback_`.
|
|
609
669
|
*/
|
|
610
670
|
var NetworkRequest = /** @class */ (function () {
|
|
611
|
-
function NetworkRequest(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_) {
|
|
671
|
+
function NetworkRequest(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_, retry) {
|
|
612
672
|
var _this = this;
|
|
673
|
+
if (retry === void 0) { retry = true; }
|
|
613
674
|
this.url_ = url_;
|
|
614
675
|
this.method_ = method_;
|
|
615
676
|
this.headers_ = headers_;
|
|
@@ -621,6 +682,7 @@ var NetworkRequest = /** @class */ (function () {
|
|
|
621
682
|
this.timeout_ = timeout_;
|
|
622
683
|
this.progressCallback_ = progressCallback_;
|
|
623
684
|
this.connectionFactory_ = connectionFactory_;
|
|
685
|
+
this.retry = retry;
|
|
624
686
|
this.pendingConnection_ = null;
|
|
625
687
|
this.backoffId_ = null;
|
|
626
688
|
this.canceled_ = false;
|
|
@@ -645,9 +707,7 @@ var NetworkRequest = /** @class */ (function () {
|
|
|
645
707
|
_this.pendingConnection_ = connection;
|
|
646
708
|
var progressListener = function (progressEvent) {
|
|
647
709
|
var loaded = progressEvent.loaded;
|
|
648
|
-
var total = progressEvent.lengthComputable
|
|
649
|
-
? progressEvent.total
|
|
650
|
-
: -1;
|
|
710
|
+
var total = progressEvent.lengthComputable ? progressEvent.total : -1;
|
|
651
711
|
if (_this.progressCallback_ !== null) {
|
|
652
712
|
_this.progressCallback_(loaded, total);
|
|
653
713
|
}
|
|
@@ -666,7 +726,9 @@ var NetworkRequest = /** @class */ (function () {
|
|
|
666
726
|
_this.pendingConnection_ = null;
|
|
667
727
|
var hitServer = connection.getErrorCode() === ErrorCode.NO_ERROR;
|
|
668
728
|
var status = connection.getStatus();
|
|
669
|
-
if (!hitServer ||
|
|
729
|
+
if ((!hitServer ||
|
|
730
|
+
isRetryStatusCode(status, _this.additionalRetryCodes_)) &&
|
|
731
|
+
_this.retry) {
|
|
670
732
|
var wasCanceled = connection.getErrorCode() === ErrorCode.ABORT;
|
|
671
733
|
backoffCallback(false, new RequestEndStatus(false, null, wasCanceled));
|
|
672
734
|
return;
|
|
@@ -742,20 +804,6 @@ var NetworkRequest = /** @class */ (function () {
|
|
|
742
804
|
this.pendingConnection_.abort();
|
|
743
805
|
}
|
|
744
806
|
};
|
|
745
|
-
NetworkRequest.prototype.isRetryStatusCode_ = function (status) {
|
|
746
|
-
// The codes for which to retry came from this page:
|
|
747
|
-
// https://cloud.google.com/storage/docs/exponential-backoff
|
|
748
|
-
var isFiveHundredCode = status >= 500 && status < 600;
|
|
749
|
-
var extraRetryCodes = [
|
|
750
|
-
// Request Timeout: web server didn't receive full request in time.
|
|
751
|
-
408,
|
|
752
|
-
// Too Many Requests: you're getting rate-limited, basically.
|
|
753
|
-
429
|
|
754
|
-
];
|
|
755
|
-
var isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
|
|
756
|
-
var isRequestSpecificRetryCode = this.additionalRetryCodes_.indexOf(status) !== -1;
|
|
757
|
-
return isFiveHundredCode || isExtraRetryCode || isRequestSpecificRetryCode;
|
|
758
|
-
};
|
|
759
807
|
return NetworkRequest;
|
|
760
808
|
}());
|
|
761
809
|
/**
|
|
@@ -789,7 +837,8 @@ function addAppCheckHeader_(headers, appCheckToken) {
|
|
|
789
837
|
headers['X-Firebase-AppCheck'] = appCheckToken;
|
|
790
838
|
}
|
|
791
839
|
}
|
|
792
|
-
function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion) {
|
|
840
|
+
function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion, retry) {
|
|
841
|
+
if (retry === void 0) { retry = true; }
|
|
793
842
|
var queryPart = makeQueryString(requestInfo.urlParams);
|
|
794
843
|
var url = requestInfo.url + queryPart;
|
|
795
844
|
var headers = Object.assign({}, requestInfo.headers);
|
|
@@ -797,7 +846,7 @@ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactor
|
|
|
797
846
|
addAuthHeader_(headers, authToken);
|
|
798
847
|
addVersionHeader_(headers, firebaseVersion);
|
|
799
848
|
addAppCheckHeader_(headers, appCheckToken);
|
|
800
|
-
return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory);
|
|
849
|
+
return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory, retry);
|
|
801
850
|
}
|
|
802
851
|
|
|
803
852
|
/**
|
|
@@ -1629,6 +1678,7 @@ function sharedErrorHandler(location) {
|
|
|
1629
1678
|
}
|
|
1630
1679
|
}
|
|
1631
1680
|
}
|
|
1681
|
+
newErr.status = xhr.getStatus();
|
|
1632
1682
|
newErr.serverResponse = err.serverResponse;
|
|
1633
1683
|
return newErr;
|
|
1634
1684
|
}
|
|
@@ -1914,7 +1964,16 @@ function continueResumableUpload(location, service, url, blob, chunkSize, mappin
|
|
|
1914
1964
|
}
|
|
1915
1965
|
var startByte = status_.current;
|
|
1916
1966
|
var endByte = startByte + bytesToUpload;
|
|
1917
|
-
var uploadCommand =
|
|
1967
|
+
var uploadCommand = '';
|
|
1968
|
+
if (bytesToUpload === 0) {
|
|
1969
|
+
uploadCommand = 'finalize';
|
|
1970
|
+
}
|
|
1971
|
+
else if (bytesLeft === bytesToUpload) {
|
|
1972
|
+
uploadCommand = 'upload, finalize';
|
|
1973
|
+
}
|
|
1974
|
+
else {
|
|
1975
|
+
uploadCommand = 'upload';
|
|
1976
|
+
}
|
|
1918
1977
|
var headers = {
|
|
1919
1978
|
'X-Goog-Upload-Command': uploadCommand,
|
|
1920
1979
|
'X-Goog-Upload-Offset': "" + status_.current
|
|
@@ -2298,6 +2357,18 @@ var UploadTask = /** @class */ (function () {
|
|
|
2298
2357
|
_this.completeTransitions_();
|
|
2299
2358
|
}
|
|
2300
2359
|
else {
|
|
2360
|
+
var backoffExpired = _this.isExponentialBackoffExpired();
|
|
2361
|
+
if (isRetryStatusCode(error.status, [])) {
|
|
2362
|
+
if (backoffExpired) {
|
|
2363
|
+
error = retryLimitExceeded();
|
|
2364
|
+
}
|
|
2365
|
+
else {
|
|
2366
|
+
_this.sleepTime = Math.max(_this.sleepTime * 2, DEFAULT_MIN_SLEEP_TIME_MILLIS);
|
|
2367
|
+
_this._needToFetchStatus = true;
|
|
2368
|
+
_this.completeTransitions_();
|
|
2369
|
+
return;
|
|
2370
|
+
}
|
|
2371
|
+
}
|
|
2301
2372
|
_this._error = error;
|
|
2302
2373
|
_this._transition("error" /* ERROR */);
|
|
2303
2374
|
}
|
|
@@ -2312,6 +2383,8 @@ var UploadTask = /** @class */ (function () {
|
|
|
2312
2383
|
_this._transition("error" /* ERROR */);
|
|
2313
2384
|
}
|
|
2314
2385
|
};
|
|
2386
|
+
this.sleepTime = 0;
|
|
2387
|
+
this.maxSleepTime = this._ref.storage.maxUploadRetryTime;
|
|
2315
2388
|
this._promise = new Promise(function (resolve, reject) {
|
|
2316
2389
|
_this._resolve = resolve;
|
|
2317
2390
|
_this._reject = reject;
|
|
@@ -2321,6 +2394,9 @@ var UploadTask = /** @class */ (function () {
|
|
|
2321
2394
|
// to the top level with a dummy handler.
|
|
2322
2395
|
this._promise.then(null, function () { });
|
|
2323
2396
|
}
|
|
2397
|
+
UploadTask.prototype.isExponentialBackoffExpired = function () {
|
|
2398
|
+
return this.sleepTime > this.maxSleepTime;
|
|
2399
|
+
};
|
|
2324
2400
|
UploadTask.prototype._makeProgressCallback = function () {
|
|
2325
2401
|
var _this = this;
|
|
2326
2402
|
var sizeBefore = this._transferred;
|
|
@@ -2330,6 +2406,7 @@ var UploadTask = /** @class */ (function () {
|
|
|
2330
2406
|
return blob.size() > 256 * 1024;
|
|
2331
2407
|
};
|
|
2332
2408
|
UploadTask.prototype._start = function () {
|
|
2409
|
+
var _this = this;
|
|
2333
2410
|
if (this._state !== "running" /* RUNNING */) {
|
|
2334
2411
|
// This can happen if someone pauses us in a resume callback, for example.
|
|
2335
2412
|
return;
|
|
@@ -2351,7 +2428,9 @@ var UploadTask = /** @class */ (function () {
|
|
|
2351
2428
|
this._fetchMetadata();
|
|
2352
2429
|
}
|
|
2353
2430
|
else {
|
|
2354
|
-
|
|
2431
|
+
setTimeout(function () {
|
|
2432
|
+
_this._continueUpload();
|
|
2433
|
+
}, this.sleepTime);
|
|
2355
2434
|
}
|
|
2356
2435
|
}
|
|
2357
2436
|
}
|
|
@@ -2432,7 +2511,9 @@ var UploadTask = /** @class */ (function () {
|
|
|
2432
2511
|
_this._transition("error" /* ERROR */);
|
|
2433
2512
|
return;
|
|
2434
2513
|
}
|
|
2435
|
-
var uploadRequest = _this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken
|
|
2514
|
+
var uploadRequest = _this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken,
|
|
2515
|
+
/*retry=*/ false // Upload requests should not be retried as each retry should be preceded by another query request. Which is handled in this file.
|
|
2516
|
+
);
|
|
2436
2517
|
_this._request = uploadRequest;
|
|
2437
2518
|
uploadRequest.getPromise().then(function (newStatus) {
|
|
2438
2519
|
_this._increaseMultiplier();
|
|
@@ -2451,7 +2532,7 @@ var UploadTask = /** @class */ (function () {
|
|
|
2451
2532
|
UploadTask.prototype._increaseMultiplier = function () {
|
|
2452
2533
|
var currentSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
|
|
2453
2534
|
// Max chunk size is 32M.
|
|
2454
|
-
if (currentSize < 32 * 1024 * 1024) {
|
|
2535
|
+
if (currentSize * 2 < 32 * 1024 * 1024) {
|
|
2455
2536
|
this._chunkMultiplier *= 2;
|
|
2456
2537
|
}
|
|
2457
2538
|
};
|
|
@@ -2607,6 +2688,7 @@ var UploadTask = /** @class */ (function () {
|
|
|
2607
2688
|
*/
|
|
2608
2689
|
UploadTask.prototype.on = function (type, nextOrObserver, error, completed) {
|
|
2609
2690
|
var _this = this;
|
|
2691
|
+
// Note: `type` isn't being used. Its type is also incorrect. TaskEvent should not be a string.
|
|
2610
2692
|
var observer = new Observer(nextOrObserver || undefined, error || undefined, completed || undefined);
|
|
2611
2693
|
this._addObserver(observer);
|
|
2612
2694
|
return function () {
|
|
@@ -3370,10 +3452,11 @@ var FirebaseStorageImpl = /** @class */ (function () {
|
|
|
3370
3452
|
* @param requestInfo - HTTP RequestInfo object
|
|
3371
3453
|
* @param authToken - Firebase auth token
|
|
3372
3454
|
*/
|
|
3373
|
-
FirebaseStorageImpl.prototype._makeRequest = function (requestInfo, requestFactory, authToken, appCheckToken) {
|
|
3455
|
+
FirebaseStorageImpl.prototype._makeRequest = function (requestInfo, requestFactory, authToken, appCheckToken, retry) {
|
|
3374
3456
|
var _this = this;
|
|
3457
|
+
if (retry === void 0) { retry = true; }
|
|
3375
3458
|
if (!this._deleted) {
|
|
3376
|
-
var request_1 = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion);
|
|
3459
|
+
var request_1 = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion, retry);
|
|
3377
3460
|
this._requests.add(request_1);
|
|
3378
3461
|
// Request removes itself from set when complete.
|
|
3379
3462
|
request_1.getPromise().then(function () { return _this._requests.delete(request_1); }, function () { return _this._requests.delete(request_1); });
|
|
@@ -3403,7 +3486,7 @@ var FirebaseStorageImpl = /** @class */ (function () {
|
|
|
3403
3486
|
}());
|
|
3404
3487
|
|
|
3405
3488
|
var name = "@firebase/storage";
|
|
3406
|
-
var version = "0.9.
|
|
3489
|
+
var version = "0.9.11-20221010190246";
|
|
3407
3490
|
|
|
3408
3491
|
/**
|
|
3409
3492
|
* @license
|