@firebase/storage 0.10.1 → 0.11.0-20230201003102

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.
@@ -0,0 +1,3688 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var app = require('@firebase/app');
6
+ var util = require('@firebase/util');
7
+ var component = require('@firebase/component');
8
+
9
+ /**
10
+ * @license
11
+ * Copyright 2017 Google LLC
12
+ *
13
+ * Licensed under the Apache License, Version 2.0 (the "License");
14
+ * you may not use this file except in compliance with the License.
15
+ * You may obtain a copy of the License at
16
+ *
17
+ * http://www.apache.org/licenses/LICENSE-2.0
18
+ *
19
+ * Unless required by applicable law or agreed to in writing, software
20
+ * distributed under the License is distributed on an "AS IS" BASIS,
21
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22
+ * See the License for the specific language governing permissions and
23
+ * limitations under the License.
24
+ */
25
+ /**
26
+ * @fileoverview Constants used in the Firebase Storage library.
27
+ */
28
+ /**
29
+ * Domain name for firebase storage.
30
+ */
31
+ const DEFAULT_HOST = 'firebasestorage.googleapis.com';
32
+ /**
33
+ * The key in Firebase config json for the storage bucket.
34
+ */
35
+ const CONFIG_STORAGE_BUCKET_KEY = 'storageBucket';
36
+ /**
37
+ * 2 minutes
38
+ *
39
+ * The timeout for all operations except upload.
40
+ */
41
+ const DEFAULT_MAX_OPERATION_RETRY_TIME = 2 * 60 * 1000;
42
+ /**
43
+ * 10 minutes
44
+ *
45
+ * The timeout for upload.
46
+ */
47
+ const DEFAULT_MAX_UPLOAD_RETRY_TIME = 10 * 60 * 1000;
48
+ /**
49
+ * 1 second
50
+ */
51
+ const DEFAULT_MIN_SLEEP_TIME_MILLIS = 1000;
52
+
53
+ /**
54
+ * @license
55
+ * Copyright 2017 Google LLC
56
+ *
57
+ * Licensed under the Apache License, Version 2.0 (the "License");
58
+ * you may not use this file except in compliance with the License.
59
+ * You may obtain a copy of the License at
60
+ *
61
+ * http://www.apache.org/licenses/LICENSE-2.0
62
+ *
63
+ * Unless required by applicable law or agreed to in writing, software
64
+ * distributed under the License is distributed on an "AS IS" BASIS,
65
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
66
+ * See the License for the specific language governing permissions and
67
+ * limitations under the License.
68
+ */
69
+ /**
70
+ * An error returned by the Firebase Storage SDK.
71
+ * @public
72
+ */
73
+ class StorageError extends util.FirebaseError {
74
+ /**
75
+ * @param code - A StorageErrorCode string to be prefixed with 'storage/' and
76
+ * added to the end of the message.
77
+ * @param message - Error message.
78
+ * @param status_ - Corresponding HTTP Status Code
79
+ */
80
+ constructor(code, message, status_ = 0) {
81
+ super(prependCode(code), `Firebase Storage: ${message} (${prependCode(code)})`);
82
+ this.status_ = status_;
83
+ /**
84
+ * Stores custom error data unque to StorageError.
85
+ */
86
+ this.customData = { serverResponse: null };
87
+ this._baseMessage = this.message;
88
+ // Without this, `instanceof StorageError`, in tests for example,
89
+ // returns false.
90
+ Object.setPrototypeOf(this, StorageError.prototype);
91
+ }
92
+ get status() {
93
+ return this.status_;
94
+ }
95
+ set status(status) {
96
+ this.status_ = status;
97
+ }
98
+ /**
99
+ * Compares a StorageErrorCode against this error's code, filtering out the prefix.
100
+ */
101
+ _codeEquals(code) {
102
+ return prependCode(code) === this.code;
103
+ }
104
+ /**
105
+ * Optional response message that was added by the server.
106
+ */
107
+ get serverResponse() {
108
+ return this.customData.serverResponse;
109
+ }
110
+ set serverResponse(serverResponse) {
111
+ this.customData.serverResponse = serverResponse;
112
+ if (this.customData.serverResponse) {
113
+ this.message = `${this._baseMessage}\n${this.customData.serverResponse}`;
114
+ }
115
+ else {
116
+ this.message = this._baseMessage;
117
+ }
118
+ }
119
+ }
120
+ /**
121
+ * @public
122
+ * Error codes that can be attached to `StorageError`s.
123
+ */
124
+ exports.StorageErrorCode = void 0;
125
+ (function (StorageErrorCode) {
126
+ // Shared between all platforms
127
+ StorageErrorCode["UNKNOWN"] = "unknown";
128
+ StorageErrorCode["OBJECT_NOT_FOUND"] = "object-not-found";
129
+ StorageErrorCode["BUCKET_NOT_FOUND"] = "bucket-not-found";
130
+ StorageErrorCode["PROJECT_NOT_FOUND"] = "project-not-found";
131
+ StorageErrorCode["QUOTA_EXCEEDED"] = "quota-exceeded";
132
+ StorageErrorCode["UNAUTHENTICATED"] = "unauthenticated";
133
+ StorageErrorCode["UNAUTHORIZED"] = "unauthorized";
134
+ StorageErrorCode["UNAUTHORIZED_APP"] = "unauthorized-app";
135
+ StorageErrorCode["RETRY_LIMIT_EXCEEDED"] = "retry-limit-exceeded";
136
+ StorageErrorCode["INVALID_CHECKSUM"] = "invalid-checksum";
137
+ StorageErrorCode["CANCELED"] = "canceled";
138
+ // JS specific
139
+ StorageErrorCode["INVALID_EVENT_NAME"] = "invalid-event-name";
140
+ StorageErrorCode["INVALID_URL"] = "invalid-url";
141
+ StorageErrorCode["INVALID_DEFAULT_BUCKET"] = "invalid-default-bucket";
142
+ StorageErrorCode["NO_DEFAULT_BUCKET"] = "no-default-bucket";
143
+ StorageErrorCode["CANNOT_SLICE_BLOB"] = "cannot-slice-blob";
144
+ StorageErrorCode["SERVER_FILE_WRONG_SIZE"] = "server-file-wrong-size";
145
+ StorageErrorCode["NO_DOWNLOAD_URL"] = "no-download-url";
146
+ StorageErrorCode["INVALID_ARGUMENT"] = "invalid-argument";
147
+ StorageErrorCode["INVALID_ARGUMENT_COUNT"] = "invalid-argument-count";
148
+ StorageErrorCode["APP_DELETED"] = "app-deleted";
149
+ StorageErrorCode["INVALID_ROOT_OPERATION"] = "invalid-root-operation";
150
+ StorageErrorCode["INVALID_FORMAT"] = "invalid-format";
151
+ StorageErrorCode["INTERNAL_ERROR"] = "internal-error";
152
+ StorageErrorCode["UNSUPPORTED_ENVIRONMENT"] = "unsupported-environment";
153
+ })(exports.StorageErrorCode || (exports.StorageErrorCode = {}));
154
+ function prependCode(code) {
155
+ return 'storage/' + code;
156
+ }
157
+ function unknown() {
158
+ const message = 'An unknown error occurred, please check the error payload for ' +
159
+ 'server response.';
160
+ return new StorageError(exports.StorageErrorCode.UNKNOWN, message);
161
+ }
162
+ function objectNotFound(path) {
163
+ return new StorageError(exports.StorageErrorCode.OBJECT_NOT_FOUND, "Object '" + path + "' does not exist.");
164
+ }
165
+ function quotaExceeded(bucket) {
166
+ return new StorageError(exports.StorageErrorCode.QUOTA_EXCEEDED, "Quota for bucket '" +
167
+ bucket +
168
+ "' exceeded, please view quota on " +
169
+ 'https://firebase.google.com/pricing/.');
170
+ }
171
+ function unauthenticated() {
172
+ const message = 'User is not authenticated, please authenticate using Firebase ' +
173
+ 'Authentication and try again.';
174
+ return new StorageError(exports.StorageErrorCode.UNAUTHENTICATED, message);
175
+ }
176
+ function unauthorizedApp() {
177
+ return new StorageError(exports.StorageErrorCode.UNAUTHORIZED_APP, 'This app does not have permission to access Firebase Storage on this project.');
178
+ }
179
+ function unauthorized(path) {
180
+ return new StorageError(exports.StorageErrorCode.UNAUTHORIZED, "User does not have permission to access '" + path + "'.");
181
+ }
182
+ function retryLimitExceeded() {
183
+ return new StorageError(exports.StorageErrorCode.RETRY_LIMIT_EXCEEDED, 'Max retry time for operation exceeded, please try again.');
184
+ }
185
+ function canceled() {
186
+ return new StorageError(exports.StorageErrorCode.CANCELED, 'User canceled the upload/download.');
187
+ }
188
+ function invalidUrl(url) {
189
+ return new StorageError(exports.StorageErrorCode.INVALID_URL, "Invalid URL '" + url + "'.");
190
+ }
191
+ function invalidDefaultBucket(bucket) {
192
+ return new StorageError(exports.StorageErrorCode.INVALID_DEFAULT_BUCKET, "Invalid default bucket '" + bucket + "'.");
193
+ }
194
+ function noDefaultBucket() {
195
+ return new StorageError(exports.StorageErrorCode.NO_DEFAULT_BUCKET, 'No default bucket ' +
196
+ "found. Did you set the '" +
197
+ CONFIG_STORAGE_BUCKET_KEY +
198
+ "' property when initializing the app?");
199
+ }
200
+ function cannotSliceBlob() {
201
+ return new StorageError(exports.StorageErrorCode.CANNOT_SLICE_BLOB, 'Cannot slice blob for upload. Please retry the upload.');
202
+ }
203
+ function serverFileWrongSize() {
204
+ return new StorageError(exports.StorageErrorCode.SERVER_FILE_WRONG_SIZE, 'Server recorded incorrect upload file size, please retry the upload.');
205
+ }
206
+ function noDownloadURL() {
207
+ return new StorageError(exports.StorageErrorCode.NO_DOWNLOAD_URL, 'The given file does not have any download URLs.');
208
+ }
209
+ function missingPolyFill(polyFill) {
210
+ return new StorageError(exports.StorageErrorCode.UNSUPPORTED_ENVIRONMENT, `${polyFill} is missing. Make sure to install the required polyfills. See https://firebase.google.com/docs/web/environments-js-sdk#polyfills for more information.`);
211
+ }
212
+ /**
213
+ * @internal
214
+ */
215
+ function invalidArgument(message) {
216
+ return new StorageError(exports.StorageErrorCode.INVALID_ARGUMENT, message);
217
+ }
218
+ function appDeleted() {
219
+ return new StorageError(exports.StorageErrorCode.APP_DELETED, 'The Firebase app was deleted.');
220
+ }
221
+ /**
222
+ * @param name - The name of the operation that was invalid.
223
+ *
224
+ * @internal
225
+ */
226
+ function invalidRootOperation(name) {
227
+ return new StorageError(exports.StorageErrorCode.INVALID_ROOT_OPERATION, "The operation '" +
228
+ name +
229
+ "' cannot be performed on a root reference, create a non-root " +
230
+ "reference using child, such as .child('file.png').");
231
+ }
232
+ /**
233
+ * @param format - The format that was not valid.
234
+ * @param message - A message describing the format violation.
235
+ */
236
+ function invalidFormat(format, message) {
237
+ return new StorageError(exports.StorageErrorCode.INVALID_FORMAT, "String does not match format '" + format + "': " + message);
238
+ }
239
+ /**
240
+ * @param message - A message describing the internal error.
241
+ */
242
+ function internalError(message) {
243
+ throw new StorageError(exports.StorageErrorCode.INTERNAL_ERROR, 'Internal error: ' + message);
244
+ }
245
+
246
+ /**
247
+ * @license
248
+ * Copyright 2017 Google LLC
249
+ *
250
+ * Licensed under the Apache License, Version 2.0 (the "License");
251
+ * you may not use this file except in compliance with the License.
252
+ * You may obtain a copy of the License at
253
+ *
254
+ * http://www.apache.org/licenses/LICENSE-2.0
255
+ *
256
+ * Unless required by applicable law or agreed to in writing, software
257
+ * distributed under the License is distributed on an "AS IS" BASIS,
258
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259
+ * See the License for the specific language governing permissions and
260
+ * limitations under the License.
261
+ */
262
+ /**
263
+ * Firebase Storage location data.
264
+ *
265
+ * @internal
266
+ */
267
+ class Location {
268
+ constructor(bucket, path) {
269
+ this.bucket = bucket;
270
+ this.path_ = path;
271
+ }
272
+ get path() {
273
+ return this.path_;
274
+ }
275
+ get isRoot() {
276
+ return this.path.length === 0;
277
+ }
278
+ fullServerUrl() {
279
+ const encode = encodeURIComponent;
280
+ return '/b/' + encode(this.bucket) + '/o/' + encode(this.path);
281
+ }
282
+ bucketOnlyServerUrl() {
283
+ const encode = encodeURIComponent;
284
+ return '/b/' + encode(this.bucket) + '/o';
285
+ }
286
+ static makeFromBucketSpec(bucketString, host) {
287
+ let bucketLocation;
288
+ try {
289
+ bucketLocation = Location.makeFromUrl(bucketString, host);
290
+ }
291
+ catch (e) {
292
+ // Not valid URL, use as-is. This lets you put bare bucket names in
293
+ // config.
294
+ return new Location(bucketString, '');
295
+ }
296
+ if (bucketLocation.path === '') {
297
+ return bucketLocation;
298
+ }
299
+ else {
300
+ throw invalidDefaultBucket(bucketString);
301
+ }
302
+ }
303
+ static makeFromUrl(url, host) {
304
+ let location = null;
305
+ const bucketDomain = '([A-Za-z0-9.\\-_]+)';
306
+ function gsModify(loc) {
307
+ if (loc.path.charAt(loc.path.length - 1) === '/') {
308
+ loc.path_ = loc.path_.slice(0, -1);
309
+ }
310
+ }
311
+ const gsPath = '(/(.*))?$';
312
+ const gsRegex = new RegExp('^gs://' + bucketDomain + gsPath, 'i');
313
+ const gsIndices = { bucket: 1, path: 3 };
314
+ function httpModify(loc) {
315
+ loc.path_ = decodeURIComponent(loc.path);
316
+ }
317
+ const version = 'v[A-Za-z0-9_]+';
318
+ const firebaseStorageHost = host.replace(/[.]/g, '\\.');
319
+ const firebaseStoragePath = '(/([^?#]*).*)?$';
320
+ const firebaseStorageRegExp = new RegExp(`^https?://${firebaseStorageHost}/${version}/b/${bucketDomain}/o${firebaseStoragePath}`, 'i');
321
+ const firebaseStorageIndices = { bucket: 1, path: 3 };
322
+ const cloudStorageHost = host === DEFAULT_HOST
323
+ ? '(?:storage.googleapis.com|storage.cloud.google.com)'
324
+ : host;
325
+ const cloudStoragePath = '([^?#]*)';
326
+ const cloudStorageRegExp = new RegExp(`^https?://${cloudStorageHost}/${bucketDomain}/${cloudStoragePath}`, 'i');
327
+ const cloudStorageIndices = { bucket: 1, path: 2 };
328
+ const groups = [
329
+ { regex: gsRegex, indices: gsIndices, postModify: gsModify },
330
+ {
331
+ regex: firebaseStorageRegExp,
332
+ indices: firebaseStorageIndices,
333
+ postModify: httpModify
334
+ },
335
+ {
336
+ regex: cloudStorageRegExp,
337
+ indices: cloudStorageIndices,
338
+ postModify: httpModify
339
+ }
340
+ ];
341
+ for (let i = 0; i < groups.length; i++) {
342
+ const group = groups[i];
343
+ const captures = group.regex.exec(url);
344
+ if (captures) {
345
+ const bucketValue = captures[group.indices.bucket];
346
+ let pathValue = captures[group.indices.path];
347
+ if (!pathValue) {
348
+ pathValue = '';
349
+ }
350
+ location = new Location(bucketValue, pathValue);
351
+ group.postModify(location);
352
+ break;
353
+ }
354
+ }
355
+ if (location == null) {
356
+ throw invalidUrl(url);
357
+ }
358
+ return location;
359
+ }
360
+ }
361
+
362
+ /**
363
+ * A request whose promise always fails.
364
+ */
365
+ class FailRequest {
366
+ constructor(error) {
367
+ this.promise_ = Promise.reject(error);
368
+ }
369
+ /** @inheritDoc */
370
+ getPromise() {
371
+ return this.promise_;
372
+ }
373
+ /** @inheritDoc */
374
+ cancel(_appDelete = false) { }
375
+ }
376
+
377
+ /**
378
+ * @license
379
+ * Copyright 2017 Google LLC
380
+ *
381
+ * Licensed under the Apache License, Version 2.0 (the "License");
382
+ * you may not use this file except in compliance with the License.
383
+ * You may obtain a copy of the License at
384
+ *
385
+ * http://www.apache.org/licenses/LICENSE-2.0
386
+ *
387
+ * Unless required by applicable law or agreed to in writing, software
388
+ * distributed under the License is distributed on an "AS IS" BASIS,
389
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
390
+ * See the License for the specific language governing permissions and
391
+ * limitations under the License.
392
+ */
393
+ /**
394
+ * Accepts a callback for an action to perform (`doRequest`),
395
+ * and then a callback for when the backoff has completed (`backoffCompleteCb`).
396
+ * The callback sent to start requires an argument to call (`onRequestComplete`).
397
+ * When `start` calls `doRequest`, it passes a callback for when the request has
398
+ * completed, `onRequestComplete`. Based on this, the backoff continues, with
399
+ * another call to `doRequest` and the above loop continues until the timeout
400
+ * is hit, or a successful response occurs.
401
+ * @description
402
+ * @param doRequest Callback to perform request
403
+ * @param backoffCompleteCb Callback to call when backoff has been completed
404
+ */
405
+ function start(doRequest,
406
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
407
+ backoffCompleteCb, timeout) {
408
+ // TODO(andysoto): make this code cleaner (probably refactor into an actual
409
+ // type instead of a bunch of functions with state shared in the closure)
410
+ let waitSeconds = 1;
411
+ // Would type this as "number" but that doesn't work for Node so ¯\_(ツ)_/¯
412
+ // TODO: find a way to exclude Node type definition for storage because storage only works in browser
413
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
414
+ let retryTimeoutId = null;
415
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
416
+ let globalTimeoutId = null;
417
+ let hitTimeout = false;
418
+ let cancelState = 0;
419
+ function canceled() {
420
+ return cancelState === 2;
421
+ }
422
+ let triggeredCallback = false;
423
+ function triggerCallback(...args) {
424
+ if (!triggeredCallback) {
425
+ triggeredCallback = true;
426
+ backoffCompleteCb.apply(null, args);
427
+ }
428
+ }
429
+ function callWithDelay(millis) {
430
+ retryTimeoutId = setTimeout(() => {
431
+ retryTimeoutId = null;
432
+ doRequest(responseHandler, canceled());
433
+ }, millis);
434
+ }
435
+ function clearGlobalTimeout() {
436
+ if (globalTimeoutId) {
437
+ clearTimeout(globalTimeoutId);
438
+ }
439
+ }
440
+ function responseHandler(success, ...args) {
441
+ if (triggeredCallback) {
442
+ clearGlobalTimeout();
443
+ return;
444
+ }
445
+ if (success) {
446
+ clearGlobalTimeout();
447
+ triggerCallback.call(null, success, ...args);
448
+ return;
449
+ }
450
+ const mustStop = canceled() || hitTimeout;
451
+ if (mustStop) {
452
+ clearGlobalTimeout();
453
+ triggerCallback.call(null, success, ...args);
454
+ return;
455
+ }
456
+ if (waitSeconds < 64) {
457
+ /* TODO(andysoto): don't back off so quickly if we know we're offline. */
458
+ waitSeconds *= 2;
459
+ }
460
+ let waitMillis;
461
+ if (cancelState === 1) {
462
+ cancelState = 2;
463
+ waitMillis = 0;
464
+ }
465
+ else {
466
+ waitMillis = (waitSeconds + Math.random()) * 1000;
467
+ }
468
+ callWithDelay(waitMillis);
469
+ }
470
+ let stopped = false;
471
+ function stop(wasTimeout) {
472
+ if (stopped) {
473
+ return;
474
+ }
475
+ stopped = true;
476
+ clearGlobalTimeout();
477
+ if (triggeredCallback) {
478
+ return;
479
+ }
480
+ if (retryTimeoutId !== null) {
481
+ if (!wasTimeout) {
482
+ cancelState = 2;
483
+ }
484
+ clearTimeout(retryTimeoutId);
485
+ callWithDelay(0);
486
+ }
487
+ else {
488
+ if (!wasTimeout) {
489
+ cancelState = 1;
490
+ }
491
+ }
492
+ }
493
+ callWithDelay(0);
494
+ globalTimeoutId = setTimeout(() => {
495
+ hitTimeout = true;
496
+ stop(true);
497
+ }, timeout);
498
+ return stop;
499
+ }
500
+ /**
501
+ * Stops the retry loop from repeating.
502
+ * If the function is currently "in between" retries, it is invoked immediately
503
+ * with the second parameter as "true". Otherwise, it will be invoked once more
504
+ * after the current invocation finishes iff the current invocation would have
505
+ * triggered another retry.
506
+ */
507
+ function stop(id) {
508
+ id(false);
509
+ }
510
+
511
+ /**
512
+ * @license
513
+ * Copyright 2017 Google LLC
514
+ *
515
+ * Licensed under the Apache License, Version 2.0 (the "License");
516
+ * you may not use this file except in compliance with the License.
517
+ * You may obtain a copy of the License at
518
+ *
519
+ * http://www.apache.org/licenses/LICENSE-2.0
520
+ *
521
+ * Unless required by applicable law or agreed to in writing, software
522
+ * distributed under the License is distributed on an "AS IS" BASIS,
523
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
524
+ * See the License for the specific language governing permissions and
525
+ * limitations under the License.
526
+ */
527
+ function isJustDef(p) {
528
+ return p !== void 0;
529
+ }
530
+ // eslint-disable-next-line @typescript-eslint/ban-types
531
+ function isFunction(p) {
532
+ return typeof p === 'function';
533
+ }
534
+ function isNonArrayObject(p) {
535
+ return typeof p === 'object' && !Array.isArray(p);
536
+ }
537
+ function isString(p) {
538
+ return typeof p === 'string' || p instanceof String;
539
+ }
540
+ function isNativeBlob(p) {
541
+ return isNativeBlobDefined() && p instanceof Blob;
542
+ }
543
+ function isNativeBlobDefined() {
544
+ // Note: The `isNode()` check can be removed when `node-fetch` adds native Blob support
545
+ // PR: https://github.com/node-fetch/node-fetch/pull/1664
546
+ return typeof Blob !== 'undefined' && !util.isNode();
547
+ }
548
+ function validateNumber(argument, minValue, maxValue, value) {
549
+ if (value < minValue) {
550
+ throw invalidArgument(`Invalid value for '${argument}'. Expected ${minValue} or greater.`);
551
+ }
552
+ if (value > maxValue) {
553
+ throw invalidArgument(`Invalid value for '${argument}'. Expected ${maxValue} or less.`);
554
+ }
555
+ }
556
+
557
+ /**
558
+ * @license
559
+ * Copyright 2017 Google LLC
560
+ *
561
+ * Licensed under the Apache License, Version 2.0 (the "License");
562
+ * you may not use this file except in compliance with the License.
563
+ * You may obtain a copy of the License at
564
+ *
565
+ * http://www.apache.org/licenses/LICENSE-2.0
566
+ *
567
+ * Unless required by applicable law or agreed to in writing, software
568
+ * distributed under the License is distributed on an "AS IS" BASIS,
569
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
570
+ * See the License for the specific language governing permissions and
571
+ * limitations under the License.
572
+ */
573
+ function makeUrl(urlPart, host, protocol) {
574
+ let origin = host;
575
+ if (protocol == null) {
576
+ origin = `https://${host}`;
577
+ }
578
+ return `${protocol}://${origin}/v0${urlPart}`;
579
+ }
580
+ function makeQueryString(params) {
581
+ const encode = encodeURIComponent;
582
+ let queryPart = '?';
583
+ for (const key in params) {
584
+ if (params.hasOwnProperty(key)) {
585
+ const nextPart = encode(key) + '=' + encode(params[key]);
586
+ queryPart = queryPart + nextPart + '&';
587
+ }
588
+ }
589
+ // Chop off the extra '&' or '?' on the end
590
+ queryPart = queryPart.slice(0, -1);
591
+ return queryPart;
592
+ }
593
+
594
+ /**
595
+ * @license
596
+ * Copyright 2017 Google LLC
597
+ *
598
+ * Licensed under the Apache License, Version 2.0 (the "License");
599
+ * you may not use this file except in compliance with the License.
600
+ * You may obtain a copy of the License at
601
+ *
602
+ * http://www.apache.org/licenses/LICENSE-2.0
603
+ *
604
+ * Unless required by applicable law or agreed to in writing, software
605
+ * distributed under the License is distributed on an "AS IS" BASIS,
606
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
607
+ * See the License for the specific language governing permissions and
608
+ * limitations under the License.
609
+ */
610
+ /**
611
+ * Error codes for requests made by the the XhrIo wrapper.
612
+ */
613
+ var ErrorCode;
614
+ (function (ErrorCode) {
615
+ ErrorCode[ErrorCode["NO_ERROR"] = 0] = "NO_ERROR";
616
+ ErrorCode[ErrorCode["NETWORK_ERROR"] = 1] = "NETWORK_ERROR";
617
+ ErrorCode[ErrorCode["ABORT"] = 2] = "ABORT";
618
+ })(ErrorCode || (ErrorCode = {}));
619
+
620
+ /**
621
+ * @license
622
+ * Copyright 2022 Google LLC
623
+ *
624
+ * Licensed under the Apache License, Version 2.0 (the "License");
625
+ * you may not use this file except in compliance with the License.
626
+ * You may obtain a copy of the License at
627
+ *
628
+ * http://www.apache.org/licenses/LICENSE-2.0
629
+ *
630
+ * Unless required by applicable law or agreed to in writing, software
631
+ * distributed under the License is distributed on an "AS IS" BASIS,
632
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
633
+ * See the License for the specific language governing permissions and
634
+ * limitations under the License.
635
+ */
636
+ /**
637
+ * Checks the status code to see if the action should be retried.
638
+ *
639
+ * @param status Current HTTP status code returned by server.
640
+ * @param additionalRetryCodes additional retry codes to check against
641
+ */
642
+ function isRetryStatusCode(status, additionalRetryCodes) {
643
+ // The codes for which to retry came from this page:
644
+ // https://cloud.google.com/storage/docs/exponential-backoff
645
+ const isFiveHundredCode = status >= 500 && status < 600;
646
+ const extraRetryCodes = [
647
+ // Request Timeout: web server didn't receive full request in time.
648
+ 408,
649
+ // Too Many Requests: you're getting rate-limited, basically.
650
+ 429
651
+ ];
652
+ const isExtraRetryCode = extraRetryCodes.indexOf(status) !== -1;
653
+ const isAdditionalRetryCode = additionalRetryCodes.indexOf(status) !== -1;
654
+ return isFiveHundredCode || isExtraRetryCode || isAdditionalRetryCode;
655
+ }
656
+
657
+ /**
658
+ * @license
659
+ * Copyright 2017 Google LLC
660
+ *
661
+ * Licensed under the Apache License, Version 2.0 (the "License");
662
+ * you may not use this file except in compliance with the License.
663
+ * You may obtain a copy of the License at
664
+ *
665
+ * http://www.apache.org/licenses/LICENSE-2.0
666
+ *
667
+ * Unless required by applicable law or agreed to in writing, software
668
+ * distributed under the License is distributed on an "AS IS" BASIS,
669
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
670
+ * See the License for the specific language governing permissions and
671
+ * limitations under the License.
672
+ */
673
+ /**
674
+ * Handles network logic for all Storage Requests, including error reporting and
675
+ * retries with backoff.
676
+ *
677
+ * @param I - the type of the backend's network response.
678
+ * @param - O the output type used by the rest of the SDK. The conversion
679
+ * happens in the specified `callback_`.
680
+ */
681
+ class NetworkRequest {
682
+ constructor(url_, method_, headers_, body_, successCodes_, additionalRetryCodes_, callback_, errorCallback_, timeout_, progressCallback_, connectionFactory_, retry = true) {
683
+ this.url_ = url_;
684
+ this.method_ = method_;
685
+ this.headers_ = headers_;
686
+ this.body_ = body_;
687
+ this.successCodes_ = successCodes_;
688
+ this.additionalRetryCodes_ = additionalRetryCodes_;
689
+ this.callback_ = callback_;
690
+ this.errorCallback_ = errorCallback_;
691
+ this.timeout_ = timeout_;
692
+ this.progressCallback_ = progressCallback_;
693
+ this.connectionFactory_ = connectionFactory_;
694
+ this.retry = retry;
695
+ this.pendingConnection_ = null;
696
+ this.backoffId_ = null;
697
+ this.canceled_ = false;
698
+ this.appDelete_ = false;
699
+ this.promise_ = new Promise((resolve, reject) => {
700
+ this.resolve_ = resolve;
701
+ this.reject_ = reject;
702
+ this.start_();
703
+ });
704
+ }
705
+ /**
706
+ * Actually starts the retry loop.
707
+ */
708
+ start_() {
709
+ const doTheRequest = (backoffCallback, canceled) => {
710
+ if (canceled) {
711
+ backoffCallback(false, new RequestEndStatus(false, null, true));
712
+ return;
713
+ }
714
+ const connection = this.connectionFactory_();
715
+ this.pendingConnection_ = connection;
716
+ const progressListener = progressEvent => {
717
+ const loaded = progressEvent.loaded;
718
+ const total = progressEvent.lengthComputable ? progressEvent.total : -1;
719
+ if (this.progressCallback_ !== null) {
720
+ this.progressCallback_(loaded, total);
721
+ }
722
+ };
723
+ if (this.progressCallback_ !== null) {
724
+ connection.addUploadProgressListener(progressListener);
725
+ }
726
+ // connection.send() never rejects, so we don't need to have a error handler or use catch on the returned promise.
727
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
728
+ connection
729
+ .send(this.url_, this.method_, this.body_, this.headers_)
730
+ .then(() => {
731
+ if (this.progressCallback_ !== null) {
732
+ connection.removeUploadProgressListener(progressListener);
733
+ }
734
+ this.pendingConnection_ = null;
735
+ const hitServer = connection.getErrorCode() === ErrorCode.NO_ERROR;
736
+ const status = connection.getStatus();
737
+ if (!hitServer ||
738
+ (isRetryStatusCode(status, this.additionalRetryCodes_) &&
739
+ this.retry)) {
740
+ const wasCanceled = connection.getErrorCode() === ErrorCode.ABORT;
741
+ backoffCallback(false, new RequestEndStatus(false, null, wasCanceled));
742
+ return;
743
+ }
744
+ const successCode = this.successCodes_.indexOf(status) !== -1;
745
+ backoffCallback(true, new RequestEndStatus(successCode, connection));
746
+ });
747
+ };
748
+ /**
749
+ * @param requestWentThrough - True if the request eventually went
750
+ * through, false if it hit the retry limit or was canceled.
751
+ */
752
+ const backoffDone = (requestWentThrough, status) => {
753
+ const resolve = this.resolve_;
754
+ const reject = this.reject_;
755
+ const connection = status.connection;
756
+ if (status.wasSuccessCode) {
757
+ try {
758
+ const result = this.callback_(connection, connection.getResponse());
759
+ if (isJustDef(result)) {
760
+ resolve(result);
761
+ }
762
+ else {
763
+ resolve();
764
+ }
765
+ }
766
+ catch (e) {
767
+ reject(e);
768
+ }
769
+ }
770
+ else {
771
+ if (connection !== null) {
772
+ const err = unknown();
773
+ err.serverResponse = connection.getErrorText();
774
+ if (this.errorCallback_) {
775
+ reject(this.errorCallback_(connection, err));
776
+ }
777
+ else {
778
+ reject(err);
779
+ }
780
+ }
781
+ else {
782
+ if (status.canceled) {
783
+ const err = this.appDelete_ ? appDeleted() : canceled();
784
+ reject(err);
785
+ }
786
+ else {
787
+ const err = retryLimitExceeded();
788
+ reject(err);
789
+ }
790
+ }
791
+ }
792
+ };
793
+ if (this.canceled_) {
794
+ backoffDone(false, new RequestEndStatus(false, null, true));
795
+ }
796
+ else {
797
+ this.backoffId_ = start(doTheRequest, backoffDone, this.timeout_);
798
+ }
799
+ }
800
+ /** @inheritDoc */
801
+ getPromise() {
802
+ return this.promise_;
803
+ }
804
+ /** @inheritDoc */
805
+ cancel(appDelete) {
806
+ this.canceled_ = true;
807
+ this.appDelete_ = appDelete || false;
808
+ if (this.backoffId_ !== null) {
809
+ stop(this.backoffId_);
810
+ }
811
+ if (this.pendingConnection_ !== null) {
812
+ this.pendingConnection_.abort();
813
+ }
814
+ }
815
+ }
816
+ /**
817
+ * A collection of information about the result of a network request.
818
+ * @param opt_canceled - Defaults to false.
819
+ */
820
+ class RequestEndStatus {
821
+ constructor(wasSuccessCode, connection, canceled) {
822
+ this.wasSuccessCode = wasSuccessCode;
823
+ this.connection = connection;
824
+ this.canceled = !!canceled;
825
+ }
826
+ }
827
+ function addAuthHeader_(headers, authToken) {
828
+ if (authToken !== null && authToken.length > 0) {
829
+ headers['Authorization'] = 'Firebase ' + authToken;
830
+ }
831
+ }
832
+ function addVersionHeader_(headers, firebaseVersion) {
833
+ headers['X-Firebase-Storage-Version'] =
834
+ 'webjs/' + (firebaseVersion !== null && firebaseVersion !== void 0 ? firebaseVersion : 'AppManager');
835
+ }
836
+ function addGmpidHeader_(headers, appId) {
837
+ if (appId) {
838
+ headers['X-Firebase-GMPID'] = appId;
839
+ }
840
+ }
841
+ function addAppCheckHeader_(headers, appCheckToken) {
842
+ if (appCheckToken !== null) {
843
+ headers['X-Firebase-AppCheck'] = appCheckToken;
844
+ }
845
+ }
846
+ function makeRequest(requestInfo, appId, authToken, appCheckToken, requestFactory, firebaseVersion, retry = true) {
847
+ const queryPart = makeQueryString(requestInfo.urlParams);
848
+ const url = requestInfo.url + queryPart;
849
+ const headers = Object.assign({}, requestInfo.headers);
850
+ addGmpidHeader_(headers, appId);
851
+ addAuthHeader_(headers, authToken);
852
+ addVersionHeader_(headers, firebaseVersion);
853
+ addAppCheckHeader_(headers, appCheckToken);
854
+ return new NetworkRequest(url, requestInfo.method, headers, requestInfo.body, requestInfo.successCodes, requestInfo.additionalRetryCodes, requestInfo.handler, requestInfo.errorHandler, requestInfo.timeout, requestInfo.progressCallback, requestFactory, retry);
855
+ }
856
+
857
+ /**
858
+ * @license
859
+ * Copyright 2017 Google LLC
860
+ *
861
+ * Licensed under the Apache License, Version 2.0 (the "License");
862
+ * you may not use this file except in compliance with the License.
863
+ * You may obtain a copy of the License at
864
+ *
865
+ * http://www.apache.org/licenses/LICENSE-2.0
866
+ *
867
+ * Unless required by applicable law or agreed to in writing, software
868
+ * distributed under the License is distributed on an "AS IS" BASIS,
869
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
870
+ * See the License for the specific language governing permissions and
871
+ * limitations under the License.
872
+ */
873
+ function getBlobBuilder() {
874
+ if (typeof BlobBuilder !== 'undefined') {
875
+ return BlobBuilder;
876
+ }
877
+ else if (typeof WebKitBlobBuilder !== 'undefined') {
878
+ return WebKitBlobBuilder;
879
+ }
880
+ else {
881
+ return undefined;
882
+ }
883
+ }
884
+ /**
885
+ * Concatenates one or more values together and converts them to a Blob.
886
+ *
887
+ * @param args The values that will make up the resulting blob.
888
+ * @return The blob.
889
+ */
890
+ function getBlob$1(...args) {
891
+ const BlobBuilder = getBlobBuilder();
892
+ if (BlobBuilder !== undefined) {
893
+ const bb = new BlobBuilder();
894
+ for (let i = 0; i < args.length; i++) {
895
+ bb.append(args[i]);
896
+ }
897
+ return bb.getBlob();
898
+ }
899
+ else {
900
+ if (isNativeBlobDefined()) {
901
+ return new Blob(args);
902
+ }
903
+ else {
904
+ throw new StorageError(exports.StorageErrorCode.UNSUPPORTED_ENVIRONMENT, "This browser doesn't seem to support creating Blobs");
905
+ }
906
+ }
907
+ }
908
+ /**
909
+ * Slices the blob. The returned blob contains data from the start byte
910
+ * (inclusive) till the end byte (exclusive). Negative indices cannot be used.
911
+ *
912
+ * @param blob The blob to be sliced.
913
+ * @param start Index of the starting byte.
914
+ * @param end Index of the ending byte.
915
+ * @return The blob slice or null if not supported.
916
+ */
917
+ function sliceBlob(blob, start, end) {
918
+ if (blob.webkitSlice) {
919
+ return blob.webkitSlice(start, end);
920
+ }
921
+ else if (blob.mozSlice) {
922
+ return blob.mozSlice(start, end);
923
+ }
924
+ else if (blob.slice) {
925
+ return blob.slice(start, end);
926
+ }
927
+ return null;
928
+ }
929
+
930
+ /**
931
+ * @license
932
+ * Copyright 2021 Google LLC
933
+ *
934
+ * Licensed under the Apache License, Version 2.0 (the "License");
935
+ * you may not use this file except in compliance with the License.
936
+ * You may obtain a copy of the License at
937
+ *
938
+ * http://www.apache.org/licenses/LICENSE-2.0
939
+ *
940
+ * Unless required by applicable law or agreed to in writing, software
941
+ * distributed under the License is distributed on an "AS IS" BASIS,
942
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
943
+ * See the License for the specific language governing permissions and
944
+ * limitations under the License.
945
+ */
946
+ /** Converts a Base64 encoded string to a binary string. */
947
+ function decodeBase64(encoded) {
948
+ if (typeof atob === 'undefined') {
949
+ throw missingPolyFill('base-64');
950
+ }
951
+ return atob(encoded);
952
+ }
953
+
954
+ /**
955
+ * @license
956
+ * Copyright 2017 Google LLC
957
+ *
958
+ * Licensed under the Apache License, Version 2.0 (the "License");
959
+ * you may not use this file except in compliance with the License.
960
+ * You may obtain a copy of the License at
961
+ *
962
+ * http://www.apache.org/licenses/LICENSE-2.0
963
+ *
964
+ * Unless required by applicable law or agreed to in writing, software
965
+ * distributed under the License is distributed on an "AS IS" BASIS,
966
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
967
+ * See the License for the specific language governing permissions and
968
+ * limitations under the License.
969
+ */
970
+ /**
971
+ * An enumeration of the possible string formats for upload.
972
+ * @public
973
+ */
974
+ const StringFormat = {
975
+ /**
976
+ * Indicates the string should be interpreted "raw", that is, as normal text.
977
+ * The string will be interpreted as UTF-16, then uploaded as a UTF-8 byte
978
+ * sequence.
979
+ * Example: The string 'Hello! \\ud83d\\ude0a' becomes the byte sequence
980
+ * 48 65 6c 6c 6f 21 20 f0 9f 98 8a
981
+ */
982
+ RAW: 'raw',
983
+ /**
984
+ * Indicates the string should be interpreted as base64-encoded data.
985
+ * Padding characters (trailing '='s) are optional.
986
+ * Example: The string 'rWmO++E6t7/rlw==' becomes the byte sequence
987
+ * ad 69 8e fb e1 3a b7 bf eb 97
988
+ */
989
+ BASE64: 'base64',
990
+ /**
991
+ * Indicates the string should be interpreted as base64url-encoded data.
992
+ * Padding characters (trailing '='s) are optional.
993
+ * Example: The string 'rWmO--E6t7_rlw==' becomes the byte sequence
994
+ * ad 69 8e fb e1 3a b7 bf eb 97
995
+ */
996
+ BASE64URL: 'base64url',
997
+ /**
998
+ * Indicates the string is a data URL, such as one obtained from
999
+ * canvas.toDataURL().
1000
+ * Example: the string 'data:application/octet-stream;base64,aaaa'
1001
+ * becomes the byte sequence
1002
+ * 69 a6 9a
1003
+ * (the content-type "application/octet-stream" is also applied, but can
1004
+ * be overridden in the metadata object).
1005
+ */
1006
+ DATA_URL: 'data_url'
1007
+ };
1008
+ class StringData {
1009
+ constructor(data, contentType) {
1010
+ this.data = data;
1011
+ this.contentType = contentType || null;
1012
+ }
1013
+ }
1014
+ /**
1015
+ * @internal
1016
+ */
1017
+ function dataFromString(format, stringData) {
1018
+ switch (format) {
1019
+ case StringFormat.RAW:
1020
+ return new StringData(utf8Bytes_(stringData));
1021
+ case StringFormat.BASE64:
1022
+ case StringFormat.BASE64URL:
1023
+ return new StringData(base64Bytes_(format, stringData));
1024
+ case StringFormat.DATA_URL:
1025
+ return new StringData(dataURLBytes_(stringData), dataURLContentType_(stringData));
1026
+ // do nothing
1027
+ }
1028
+ // assert(false);
1029
+ throw unknown();
1030
+ }
1031
+ function utf8Bytes_(value) {
1032
+ const b = [];
1033
+ for (let i = 0; i < value.length; i++) {
1034
+ let c = value.charCodeAt(i);
1035
+ if (c <= 127) {
1036
+ b.push(c);
1037
+ }
1038
+ else {
1039
+ if (c <= 2047) {
1040
+ b.push(192 | (c >> 6), 128 | (c & 63));
1041
+ }
1042
+ else {
1043
+ if ((c & 64512) === 55296) {
1044
+ // The start of a surrogate pair.
1045
+ const valid = i < value.length - 1 && (value.charCodeAt(i + 1) & 64512) === 56320;
1046
+ if (!valid) {
1047
+ // The second surrogate wasn't there.
1048
+ b.push(239, 191, 189);
1049
+ }
1050
+ else {
1051
+ const hi = c;
1052
+ const lo = value.charCodeAt(++i);
1053
+ c = 65536 | ((hi & 1023) << 10) | (lo & 1023);
1054
+ b.push(240 | (c >> 18), 128 | ((c >> 12) & 63), 128 | ((c >> 6) & 63), 128 | (c & 63));
1055
+ }
1056
+ }
1057
+ else {
1058
+ if ((c & 64512) === 56320) {
1059
+ // Invalid low surrogate.
1060
+ b.push(239, 191, 189);
1061
+ }
1062
+ else {
1063
+ b.push(224 | (c >> 12), 128 | ((c >> 6) & 63), 128 | (c & 63));
1064
+ }
1065
+ }
1066
+ }
1067
+ }
1068
+ }
1069
+ return new Uint8Array(b);
1070
+ }
1071
+ function percentEncodedBytes_(value) {
1072
+ let decoded;
1073
+ try {
1074
+ decoded = decodeURIComponent(value);
1075
+ }
1076
+ catch (e) {
1077
+ throw invalidFormat(StringFormat.DATA_URL, 'Malformed data URL.');
1078
+ }
1079
+ return utf8Bytes_(decoded);
1080
+ }
1081
+ function base64Bytes_(format, value) {
1082
+ switch (format) {
1083
+ case StringFormat.BASE64: {
1084
+ const hasMinus = value.indexOf('-') !== -1;
1085
+ const hasUnder = value.indexOf('_') !== -1;
1086
+ if (hasMinus || hasUnder) {
1087
+ const invalidChar = hasMinus ? '-' : '_';
1088
+ throw invalidFormat(format, "Invalid character '" +
1089
+ invalidChar +
1090
+ "' found: is it base64url encoded?");
1091
+ }
1092
+ break;
1093
+ }
1094
+ case StringFormat.BASE64URL: {
1095
+ const hasPlus = value.indexOf('+') !== -1;
1096
+ const hasSlash = value.indexOf('/') !== -1;
1097
+ if (hasPlus || hasSlash) {
1098
+ const invalidChar = hasPlus ? '+' : '/';
1099
+ throw invalidFormat(format, "Invalid character '" + invalidChar + "' found: is it base64 encoded?");
1100
+ }
1101
+ value = value.replace(/-/g, '+').replace(/_/g, '/');
1102
+ break;
1103
+ }
1104
+ // do nothing
1105
+ }
1106
+ let bytes;
1107
+ try {
1108
+ bytes = decodeBase64(value);
1109
+ }
1110
+ catch (e) {
1111
+ if (e.message.includes('polyfill')) {
1112
+ throw e;
1113
+ }
1114
+ throw invalidFormat(format, 'Invalid character found');
1115
+ }
1116
+ const array = new Uint8Array(bytes.length);
1117
+ for (let i = 0; i < bytes.length; i++) {
1118
+ array[i] = bytes.charCodeAt(i);
1119
+ }
1120
+ return array;
1121
+ }
1122
+ class DataURLParts {
1123
+ constructor(dataURL) {
1124
+ this.base64 = false;
1125
+ this.contentType = null;
1126
+ const matches = dataURL.match(/^data:([^,]+)?,/);
1127
+ if (matches === null) {
1128
+ throw invalidFormat(StringFormat.DATA_URL, "Must be formatted 'data:[<mediatype>][;base64],<data>");
1129
+ }
1130
+ const middle = matches[1] || null;
1131
+ if (middle != null) {
1132
+ this.base64 = endsWith(middle, ';base64');
1133
+ this.contentType = this.base64
1134
+ ? middle.substring(0, middle.length - ';base64'.length)
1135
+ : middle;
1136
+ }
1137
+ this.rest = dataURL.substring(dataURL.indexOf(',') + 1);
1138
+ }
1139
+ }
1140
+ function dataURLBytes_(dataUrl) {
1141
+ const parts = new DataURLParts(dataUrl);
1142
+ if (parts.base64) {
1143
+ return base64Bytes_(StringFormat.BASE64, parts.rest);
1144
+ }
1145
+ else {
1146
+ return percentEncodedBytes_(parts.rest);
1147
+ }
1148
+ }
1149
+ function dataURLContentType_(dataUrl) {
1150
+ const parts = new DataURLParts(dataUrl);
1151
+ return parts.contentType;
1152
+ }
1153
+ function endsWith(s, end) {
1154
+ const longEnough = s.length >= end.length;
1155
+ if (!longEnough) {
1156
+ return false;
1157
+ }
1158
+ return s.substring(s.length - end.length) === end;
1159
+ }
1160
+
1161
+ /**
1162
+ * @license
1163
+ * Copyright 2017 Google LLC
1164
+ *
1165
+ * Licensed under the Apache License, Version 2.0 (the "License");
1166
+ * you may not use this file except in compliance with the License.
1167
+ * You may obtain a copy of the License at
1168
+ *
1169
+ * http://www.apache.org/licenses/LICENSE-2.0
1170
+ *
1171
+ * Unless required by applicable law or agreed to in writing, software
1172
+ * distributed under the License is distributed on an "AS IS" BASIS,
1173
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1174
+ * See the License for the specific language governing permissions and
1175
+ * limitations under the License.
1176
+ */
1177
+ /**
1178
+ * @param opt_elideCopy - If true, doesn't copy mutable input data
1179
+ * (e.g. Uint8Arrays). Pass true only if you know the objects will not be
1180
+ * modified after this blob's construction.
1181
+ *
1182
+ * @internal
1183
+ */
1184
+ class FbsBlob {
1185
+ constructor(data, elideCopy) {
1186
+ let size = 0;
1187
+ let blobType = '';
1188
+ if (isNativeBlob(data)) {
1189
+ this.data_ = data;
1190
+ size = data.size;
1191
+ blobType = data.type;
1192
+ }
1193
+ else if (data instanceof ArrayBuffer) {
1194
+ if (elideCopy) {
1195
+ this.data_ = new Uint8Array(data);
1196
+ }
1197
+ else {
1198
+ this.data_ = new Uint8Array(data.byteLength);
1199
+ this.data_.set(new Uint8Array(data));
1200
+ }
1201
+ size = this.data_.length;
1202
+ }
1203
+ else if (data instanceof Uint8Array) {
1204
+ if (elideCopy) {
1205
+ this.data_ = data;
1206
+ }
1207
+ else {
1208
+ this.data_ = new Uint8Array(data.length);
1209
+ this.data_.set(data);
1210
+ }
1211
+ size = data.length;
1212
+ }
1213
+ this.size_ = size;
1214
+ this.type_ = blobType;
1215
+ }
1216
+ size() {
1217
+ return this.size_;
1218
+ }
1219
+ type() {
1220
+ return this.type_;
1221
+ }
1222
+ slice(startByte, endByte) {
1223
+ if (isNativeBlob(this.data_)) {
1224
+ const realBlob = this.data_;
1225
+ const sliced = sliceBlob(realBlob, startByte, endByte);
1226
+ if (sliced === null) {
1227
+ return null;
1228
+ }
1229
+ return new FbsBlob(sliced);
1230
+ }
1231
+ else {
1232
+ const slice = new Uint8Array(this.data_.buffer, startByte, endByte - startByte);
1233
+ return new FbsBlob(slice, true);
1234
+ }
1235
+ }
1236
+ static getBlob(...args) {
1237
+ if (isNativeBlobDefined()) {
1238
+ const blobby = args.map((val) => {
1239
+ if (val instanceof FbsBlob) {
1240
+ return val.data_;
1241
+ }
1242
+ else {
1243
+ return val;
1244
+ }
1245
+ });
1246
+ return new FbsBlob(getBlob$1.apply(null, blobby));
1247
+ }
1248
+ else {
1249
+ const uint8Arrays = args.map((val) => {
1250
+ if (isString(val)) {
1251
+ return dataFromString(StringFormat.RAW, val).data;
1252
+ }
1253
+ else {
1254
+ // Blobs don't exist, so this has to be a Uint8Array.
1255
+ return val.data_;
1256
+ }
1257
+ });
1258
+ let finalLength = 0;
1259
+ uint8Arrays.forEach((array) => {
1260
+ finalLength += array.byteLength;
1261
+ });
1262
+ const merged = new Uint8Array(finalLength);
1263
+ let index = 0;
1264
+ uint8Arrays.forEach((array) => {
1265
+ for (let i = 0; i < array.length; i++) {
1266
+ merged[index++] = array[i];
1267
+ }
1268
+ });
1269
+ return new FbsBlob(merged, true);
1270
+ }
1271
+ }
1272
+ uploadData() {
1273
+ return this.data_;
1274
+ }
1275
+ }
1276
+
1277
+ /**
1278
+ * @license
1279
+ * Copyright 2017 Google LLC
1280
+ *
1281
+ * Licensed under the Apache License, Version 2.0 (the "License");
1282
+ * you may not use this file except in compliance with the License.
1283
+ * You may obtain a copy of the License at
1284
+ *
1285
+ * http://www.apache.org/licenses/LICENSE-2.0
1286
+ *
1287
+ * Unless required by applicable law or agreed to in writing, software
1288
+ * distributed under the License is distributed on an "AS IS" BASIS,
1289
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1290
+ * See the License for the specific language governing permissions and
1291
+ * limitations under the License.
1292
+ */
1293
+ /**
1294
+ * Returns the Object resulting from parsing the given JSON, or null if the
1295
+ * given string does not represent a JSON object.
1296
+ */
1297
+ function jsonObjectOrNull(s) {
1298
+ let obj;
1299
+ try {
1300
+ obj = JSON.parse(s);
1301
+ }
1302
+ catch (e) {
1303
+ return null;
1304
+ }
1305
+ if (isNonArrayObject(obj)) {
1306
+ return obj;
1307
+ }
1308
+ else {
1309
+ return null;
1310
+ }
1311
+ }
1312
+
1313
+ /**
1314
+ * @license
1315
+ * Copyright 2017 Google LLC
1316
+ *
1317
+ * Licensed under the Apache License, Version 2.0 (the "License");
1318
+ * you may not use this file except in compliance with the License.
1319
+ * You may obtain a copy of the License at
1320
+ *
1321
+ * http://www.apache.org/licenses/LICENSE-2.0
1322
+ *
1323
+ * Unless required by applicable law or agreed to in writing, software
1324
+ * distributed under the License is distributed on an "AS IS" BASIS,
1325
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1326
+ * See the License for the specific language governing permissions and
1327
+ * limitations under the License.
1328
+ */
1329
+ /**
1330
+ * @fileoverview Contains helper methods for manipulating paths.
1331
+ */
1332
+ /**
1333
+ * @return Null if the path is already at the root.
1334
+ */
1335
+ function parent(path) {
1336
+ if (path.length === 0) {
1337
+ return null;
1338
+ }
1339
+ const index = path.lastIndexOf('/');
1340
+ if (index === -1) {
1341
+ return '';
1342
+ }
1343
+ const newPath = path.slice(0, index);
1344
+ return newPath;
1345
+ }
1346
+ function child(path, childPath) {
1347
+ const canonicalChildPath = childPath
1348
+ .split('/')
1349
+ .filter(component => component.length > 0)
1350
+ .join('/');
1351
+ if (path.length === 0) {
1352
+ return canonicalChildPath;
1353
+ }
1354
+ else {
1355
+ return path + '/' + canonicalChildPath;
1356
+ }
1357
+ }
1358
+ /**
1359
+ * Returns the last component of a path.
1360
+ * '/foo/bar' -> 'bar'
1361
+ * '/foo/bar/baz/' -> 'baz/'
1362
+ * '/a' -> 'a'
1363
+ */
1364
+ function lastComponent(path) {
1365
+ const index = path.lastIndexOf('/', path.length - 2);
1366
+ if (index === -1) {
1367
+ return path;
1368
+ }
1369
+ else {
1370
+ return path.slice(index + 1);
1371
+ }
1372
+ }
1373
+
1374
+ /**
1375
+ * @license
1376
+ * Copyright 2017 Google LLC
1377
+ *
1378
+ * Licensed under the Apache License, Version 2.0 (the "License");
1379
+ * you may not use this file except in compliance with the License.
1380
+ * You may obtain a copy of the License at
1381
+ *
1382
+ * http://www.apache.org/licenses/LICENSE-2.0
1383
+ *
1384
+ * Unless required by applicable law or agreed to in writing, software
1385
+ * distributed under the License is distributed on an "AS IS" BASIS,
1386
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1387
+ * See the License for the specific language governing permissions and
1388
+ * limitations under the License.
1389
+ */
1390
+ function noXform_(metadata, value) {
1391
+ return value;
1392
+ }
1393
+ class Mapping {
1394
+ constructor(server, local, writable, xform) {
1395
+ this.server = server;
1396
+ this.local = local || server;
1397
+ this.writable = !!writable;
1398
+ this.xform = xform || noXform_;
1399
+ }
1400
+ }
1401
+ let mappings_ = null;
1402
+ function xformPath(fullPath) {
1403
+ if (!isString(fullPath) || fullPath.length < 2) {
1404
+ return fullPath;
1405
+ }
1406
+ else {
1407
+ return lastComponent(fullPath);
1408
+ }
1409
+ }
1410
+ function getMappings() {
1411
+ if (mappings_) {
1412
+ return mappings_;
1413
+ }
1414
+ const mappings = [];
1415
+ mappings.push(new Mapping('bucket'));
1416
+ mappings.push(new Mapping('generation'));
1417
+ mappings.push(new Mapping('metageneration'));
1418
+ mappings.push(new Mapping('name', 'fullPath', true));
1419
+ function mappingsXformPath(_metadata, fullPath) {
1420
+ return xformPath(fullPath);
1421
+ }
1422
+ const nameMapping = new Mapping('name');
1423
+ nameMapping.xform = mappingsXformPath;
1424
+ mappings.push(nameMapping);
1425
+ /**
1426
+ * Coerces the second param to a number, if it is defined.
1427
+ */
1428
+ function xformSize(_metadata, size) {
1429
+ if (size !== undefined) {
1430
+ return Number(size);
1431
+ }
1432
+ else {
1433
+ return size;
1434
+ }
1435
+ }
1436
+ const sizeMapping = new Mapping('size');
1437
+ sizeMapping.xform = xformSize;
1438
+ mappings.push(sizeMapping);
1439
+ mappings.push(new Mapping('timeCreated'));
1440
+ mappings.push(new Mapping('updated'));
1441
+ mappings.push(new Mapping('md5Hash', null, true));
1442
+ mappings.push(new Mapping('cacheControl', null, true));
1443
+ mappings.push(new Mapping('contentDisposition', null, true));
1444
+ mappings.push(new Mapping('contentEncoding', null, true));
1445
+ mappings.push(new Mapping('contentLanguage', null, true));
1446
+ mappings.push(new Mapping('contentType', null, true));
1447
+ mappings.push(new Mapping('metadata', 'customMetadata', true));
1448
+ mappings_ = mappings;
1449
+ return mappings_;
1450
+ }
1451
+ function addRef(metadata, service) {
1452
+ function generateRef() {
1453
+ const bucket = metadata['bucket'];
1454
+ const path = metadata['fullPath'];
1455
+ const loc = new Location(bucket, path);
1456
+ return service._makeStorageReference(loc);
1457
+ }
1458
+ Object.defineProperty(metadata, 'ref', { get: generateRef });
1459
+ }
1460
+ function fromResource(service, resource, mappings) {
1461
+ const metadata = {};
1462
+ metadata['type'] = 'file';
1463
+ const len = mappings.length;
1464
+ for (let i = 0; i < len; i++) {
1465
+ const mapping = mappings[i];
1466
+ metadata[mapping.local] = mapping.xform(metadata, resource[mapping.server]);
1467
+ }
1468
+ addRef(metadata, service);
1469
+ return metadata;
1470
+ }
1471
+ function fromResourceString(service, resourceString, mappings) {
1472
+ const obj = jsonObjectOrNull(resourceString);
1473
+ if (obj === null) {
1474
+ return null;
1475
+ }
1476
+ const resource = obj;
1477
+ return fromResource(service, resource, mappings);
1478
+ }
1479
+ function downloadUrlFromResourceString(metadata, resourceString, host, protocol) {
1480
+ const obj = jsonObjectOrNull(resourceString);
1481
+ if (obj === null) {
1482
+ return null;
1483
+ }
1484
+ if (!isString(obj['downloadTokens'])) {
1485
+ // This can happen if objects are uploaded through GCS and retrieved
1486
+ // through list, so we don't want to throw an Error.
1487
+ return null;
1488
+ }
1489
+ const tokens = obj['downloadTokens'];
1490
+ if (tokens.length === 0) {
1491
+ return null;
1492
+ }
1493
+ const encode = encodeURIComponent;
1494
+ const tokensList = tokens.split(',');
1495
+ const urls = tokensList.map((token) => {
1496
+ const bucket = metadata['bucket'];
1497
+ const path = metadata['fullPath'];
1498
+ const urlPart = '/b/' + encode(bucket) + '/o/' + encode(path);
1499
+ const base = makeUrl(urlPart, host, protocol);
1500
+ const queryString = makeQueryString({
1501
+ alt: 'media',
1502
+ token
1503
+ });
1504
+ return base + queryString;
1505
+ });
1506
+ return urls[0];
1507
+ }
1508
+ function toResourceString(metadata, mappings) {
1509
+ const resource = {};
1510
+ const len = mappings.length;
1511
+ for (let i = 0; i < len; i++) {
1512
+ const mapping = mappings[i];
1513
+ if (mapping.writable) {
1514
+ resource[mapping.server] = metadata[mapping.local];
1515
+ }
1516
+ }
1517
+ return JSON.stringify(resource);
1518
+ }
1519
+
1520
+ /**
1521
+ * @license
1522
+ * Copyright 2019 Google LLC
1523
+ *
1524
+ * Licensed under the Apache License, Version 2.0 (the "License");
1525
+ * you may not use this file except in compliance with the License.
1526
+ * You may obtain a copy of the License at
1527
+ *
1528
+ * http://www.apache.org/licenses/LICENSE-2.0
1529
+ *
1530
+ * Unless required by applicable law or agreed to in writing, software
1531
+ * distributed under the License is distributed on an "AS IS" BASIS,
1532
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1533
+ * See the License for the specific language governing permissions and
1534
+ * limitations under the License.
1535
+ */
1536
+ const PREFIXES_KEY = 'prefixes';
1537
+ const ITEMS_KEY = 'items';
1538
+ function fromBackendResponse(service, bucket, resource) {
1539
+ const listResult = {
1540
+ prefixes: [],
1541
+ items: [],
1542
+ nextPageToken: resource['nextPageToken']
1543
+ };
1544
+ if (resource[PREFIXES_KEY]) {
1545
+ for (const path of resource[PREFIXES_KEY]) {
1546
+ const pathWithoutTrailingSlash = path.replace(/\/$/, '');
1547
+ const reference = service._makeStorageReference(new Location(bucket, pathWithoutTrailingSlash));
1548
+ listResult.prefixes.push(reference);
1549
+ }
1550
+ }
1551
+ if (resource[ITEMS_KEY]) {
1552
+ for (const item of resource[ITEMS_KEY]) {
1553
+ const reference = service._makeStorageReference(new Location(bucket, item['name']));
1554
+ listResult.items.push(reference);
1555
+ }
1556
+ }
1557
+ return listResult;
1558
+ }
1559
+ function fromResponseString(service, bucket, resourceString) {
1560
+ const obj = jsonObjectOrNull(resourceString);
1561
+ if (obj === null) {
1562
+ return null;
1563
+ }
1564
+ const resource = obj;
1565
+ return fromBackendResponse(service, bucket, resource);
1566
+ }
1567
+
1568
+ /**
1569
+ * Contains a fully specified request.
1570
+ *
1571
+ * @param I - the type of the backend's network response.
1572
+ * @param O - the output response type used by the rest of the SDK.
1573
+ */
1574
+ class RequestInfo {
1575
+ constructor(url, method,
1576
+ /**
1577
+ * Returns the value with which to resolve the request's promise. Only called
1578
+ * if the request is successful. Throw from this function to reject the
1579
+ * returned Request's promise with the thrown error.
1580
+ * Note: The XhrIo passed to this function may be reused after this callback
1581
+ * returns. Do not keep a reference to it in any way.
1582
+ */
1583
+ handler, timeout) {
1584
+ this.url = url;
1585
+ this.method = method;
1586
+ this.handler = handler;
1587
+ this.timeout = timeout;
1588
+ this.urlParams = {};
1589
+ this.headers = {};
1590
+ this.body = null;
1591
+ this.errorHandler = null;
1592
+ /**
1593
+ * Called with the current number of bytes uploaded and total size (-1 if not
1594
+ * computable) of the request body (i.e. used to report upload progress).
1595
+ */
1596
+ this.progressCallback = null;
1597
+ this.successCodes = [200];
1598
+ this.additionalRetryCodes = [];
1599
+ }
1600
+ }
1601
+
1602
+ /**
1603
+ * @license
1604
+ * Copyright 2017 Google LLC
1605
+ *
1606
+ * Licensed under the Apache License, Version 2.0 (the "License");
1607
+ * you may not use this file except in compliance with the License.
1608
+ * You may obtain a copy of the License at
1609
+ *
1610
+ * http://www.apache.org/licenses/LICENSE-2.0
1611
+ *
1612
+ * Unless required by applicable law or agreed to in writing, software
1613
+ * distributed under the License is distributed on an "AS IS" BASIS,
1614
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1615
+ * See the License for the specific language governing permissions and
1616
+ * limitations under the License.
1617
+ */
1618
+ /**
1619
+ * Throws the UNKNOWN StorageError if cndn is false.
1620
+ */
1621
+ function handlerCheck(cndn) {
1622
+ if (!cndn) {
1623
+ throw unknown();
1624
+ }
1625
+ }
1626
+ function metadataHandler(service, mappings) {
1627
+ function handler(xhr, text) {
1628
+ const metadata = fromResourceString(service, text, mappings);
1629
+ handlerCheck(metadata !== null);
1630
+ return metadata;
1631
+ }
1632
+ return handler;
1633
+ }
1634
+ function listHandler(service, bucket) {
1635
+ function handler(xhr, text) {
1636
+ const listResult = fromResponseString(service, bucket, text);
1637
+ handlerCheck(listResult !== null);
1638
+ return listResult;
1639
+ }
1640
+ return handler;
1641
+ }
1642
+ function downloadUrlHandler(service, mappings) {
1643
+ function handler(xhr, text) {
1644
+ const metadata = fromResourceString(service, text, mappings);
1645
+ handlerCheck(metadata !== null);
1646
+ return downloadUrlFromResourceString(metadata, text, service.host, service._protocol);
1647
+ }
1648
+ return handler;
1649
+ }
1650
+ function sharedErrorHandler(location) {
1651
+ function errorHandler(xhr, err) {
1652
+ let newErr;
1653
+ if (xhr.getStatus() === 401) {
1654
+ if (
1655
+ // This exact message string is the only consistent part of the
1656
+ // server's error response that identifies it as an App Check error.
1657
+ xhr.getErrorText().includes('Firebase App Check token is invalid')) {
1658
+ newErr = unauthorizedApp();
1659
+ }
1660
+ else {
1661
+ newErr = unauthenticated();
1662
+ }
1663
+ }
1664
+ else {
1665
+ if (xhr.getStatus() === 402) {
1666
+ newErr = quotaExceeded(location.bucket);
1667
+ }
1668
+ else {
1669
+ if (xhr.getStatus() === 403) {
1670
+ newErr = unauthorized(location.path);
1671
+ }
1672
+ else {
1673
+ newErr = err;
1674
+ }
1675
+ }
1676
+ }
1677
+ newErr.status = xhr.getStatus();
1678
+ newErr.serverResponse = err.serverResponse;
1679
+ return newErr;
1680
+ }
1681
+ return errorHandler;
1682
+ }
1683
+ function objectErrorHandler(location) {
1684
+ const shared = sharedErrorHandler(location);
1685
+ function errorHandler(xhr, err) {
1686
+ let newErr = shared(xhr, err);
1687
+ if (xhr.getStatus() === 404) {
1688
+ newErr = objectNotFound(location.path);
1689
+ }
1690
+ newErr.serverResponse = err.serverResponse;
1691
+ return newErr;
1692
+ }
1693
+ return errorHandler;
1694
+ }
1695
+ function getMetadata$2(service, location, mappings) {
1696
+ const urlPart = location.fullServerUrl();
1697
+ const url = makeUrl(urlPart, service.host, service._protocol);
1698
+ const method = 'GET';
1699
+ const timeout = service.maxOperationRetryTime;
1700
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1701
+ requestInfo.errorHandler = objectErrorHandler(location);
1702
+ return requestInfo;
1703
+ }
1704
+ function list$2(service, location, delimiter, pageToken, maxResults) {
1705
+ const urlParams = {};
1706
+ if (location.isRoot) {
1707
+ urlParams['prefix'] = '';
1708
+ }
1709
+ else {
1710
+ urlParams['prefix'] = location.path + '/';
1711
+ }
1712
+ if (delimiter && delimiter.length > 0) {
1713
+ urlParams['delimiter'] = delimiter;
1714
+ }
1715
+ if (pageToken) {
1716
+ urlParams['pageToken'] = pageToken;
1717
+ }
1718
+ if (maxResults) {
1719
+ urlParams['maxResults'] = maxResults;
1720
+ }
1721
+ const urlPart = location.bucketOnlyServerUrl();
1722
+ const url = makeUrl(urlPart, service.host, service._protocol);
1723
+ const method = 'GET';
1724
+ const timeout = service.maxOperationRetryTime;
1725
+ const requestInfo = new RequestInfo(url, method, listHandler(service, location.bucket), timeout);
1726
+ requestInfo.urlParams = urlParams;
1727
+ requestInfo.errorHandler = sharedErrorHandler(location);
1728
+ return requestInfo;
1729
+ }
1730
+ function getBytes$1(service, location, maxDownloadSizeBytes) {
1731
+ const urlPart = location.fullServerUrl();
1732
+ const url = makeUrl(urlPart, service.host, service._protocol) + '?alt=media';
1733
+ const method = 'GET';
1734
+ const timeout = service.maxOperationRetryTime;
1735
+ const requestInfo = new RequestInfo(url, method, (_, data) => data, timeout);
1736
+ requestInfo.errorHandler = objectErrorHandler(location);
1737
+ if (maxDownloadSizeBytes !== undefined) {
1738
+ requestInfo.headers['Range'] = `bytes=0-${maxDownloadSizeBytes}`;
1739
+ requestInfo.successCodes = [200 /* OK */, 206 /* Partial Content */];
1740
+ }
1741
+ return requestInfo;
1742
+ }
1743
+ function getDownloadUrl(service, location, mappings) {
1744
+ const urlPart = location.fullServerUrl();
1745
+ const url = makeUrl(urlPart, service.host, service._protocol);
1746
+ const method = 'GET';
1747
+ const timeout = service.maxOperationRetryTime;
1748
+ const requestInfo = new RequestInfo(url, method, downloadUrlHandler(service, mappings), timeout);
1749
+ requestInfo.errorHandler = objectErrorHandler(location);
1750
+ return requestInfo;
1751
+ }
1752
+ function updateMetadata$2(service, location, metadata, mappings) {
1753
+ const urlPart = location.fullServerUrl();
1754
+ const url = makeUrl(urlPart, service.host, service._protocol);
1755
+ const method = 'PATCH';
1756
+ const body = toResourceString(metadata, mappings);
1757
+ const headers = { 'Content-Type': 'application/json; charset=utf-8' };
1758
+ const timeout = service.maxOperationRetryTime;
1759
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1760
+ requestInfo.headers = headers;
1761
+ requestInfo.body = body;
1762
+ requestInfo.errorHandler = objectErrorHandler(location);
1763
+ return requestInfo;
1764
+ }
1765
+ function deleteObject$2(service, location) {
1766
+ const urlPart = location.fullServerUrl();
1767
+ const url = makeUrl(urlPart, service.host, service._protocol);
1768
+ const method = 'DELETE';
1769
+ const timeout = service.maxOperationRetryTime;
1770
+ function handler(_xhr, _text) { }
1771
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1772
+ requestInfo.successCodes = [200, 204];
1773
+ requestInfo.errorHandler = objectErrorHandler(location);
1774
+ return requestInfo;
1775
+ }
1776
+ function determineContentType_(metadata, blob) {
1777
+ return ((metadata && metadata['contentType']) ||
1778
+ (blob && blob.type()) ||
1779
+ 'application/octet-stream');
1780
+ }
1781
+ function metadataForUpload_(location, blob, metadata) {
1782
+ const metadataClone = Object.assign({}, metadata);
1783
+ metadataClone['fullPath'] = location.path;
1784
+ metadataClone['size'] = blob.size();
1785
+ if (!metadataClone['contentType']) {
1786
+ metadataClone['contentType'] = determineContentType_(null, blob);
1787
+ }
1788
+ return metadataClone;
1789
+ }
1790
+ /**
1791
+ * Prepare RequestInfo for uploads as Content-Type: multipart.
1792
+ */
1793
+ function multipartUpload(service, location, mappings, blob, metadata) {
1794
+ const urlPart = location.bucketOnlyServerUrl();
1795
+ const headers = {
1796
+ 'X-Goog-Upload-Protocol': 'multipart'
1797
+ };
1798
+ function genBoundary() {
1799
+ let str = '';
1800
+ for (let i = 0; i < 2; i++) {
1801
+ str = str + Math.random().toString().slice(2);
1802
+ }
1803
+ return str;
1804
+ }
1805
+ const boundary = genBoundary();
1806
+ headers['Content-Type'] = 'multipart/related; boundary=' + boundary;
1807
+ const metadata_ = metadataForUpload_(location, blob, metadata);
1808
+ const metadataString = toResourceString(metadata_, mappings);
1809
+ const preBlobPart = '--' +
1810
+ boundary +
1811
+ '\r\n' +
1812
+ 'Content-Type: application/json; charset=utf-8\r\n\r\n' +
1813
+ metadataString +
1814
+ '\r\n--' +
1815
+ boundary +
1816
+ '\r\n' +
1817
+ 'Content-Type: ' +
1818
+ metadata_['contentType'] +
1819
+ '\r\n\r\n';
1820
+ const postBlobPart = '\r\n--' + boundary + '--';
1821
+ const body = FbsBlob.getBlob(preBlobPart, blob, postBlobPart);
1822
+ if (body === null) {
1823
+ throw cannotSliceBlob();
1824
+ }
1825
+ const urlParams = { name: metadata_['fullPath'] };
1826
+ const url = makeUrl(urlPart, service.host, service._protocol);
1827
+ const method = 'POST';
1828
+ const timeout = service.maxUploadRetryTime;
1829
+ const requestInfo = new RequestInfo(url, method, metadataHandler(service, mappings), timeout);
1830
+ requestInfo.urlParams = urlParams;
1831
+ requestInfo.headers = headers;
1832
+ requestInfo.body = body.uploadData();
1833
+ requestInfo.errorHandler = sharedErrorHandler(location);
1834
+ return requestInfo;
1835
+ }
1836
+ /**
1837
+ * @param current The number of bytes that have been uploaded so far.
1838
+ * @param total The total number of bytes in the upload.
1839
+ * @param opt_finalized True if the server has finished the upload.
1840
+ * @param opt_metadata The upload metadata, should
1841
+ * only be passed if opt_finalized is true.
1842
+ */
1843
+ class ResumableUploadStatus {
1844
+ constructor(current, total, finalized, metadata) {
1845
+ this.current = current;
1846
+ this.total = total;
1847
+ this.finalized = !!finalized;
1848
+ this.metadata = metadata || null;
1849
+ }
1850
+ }
1851
+ function checkResumeHeader_(xhr, allowed) {
1852
+ let status = null;
1853
+ try {
1854
+ status = xhr.getResponseHeader('X-Goog-Upload-Status');
1855
+ }
1856
+ catch (e) {
1857
+ handlerCheck(false);
1858
+ }
1859
+ const allowedStatus = allowed || ['active'];
1860
+ handlerCheck(!!status && allowedStatus.indexOf(status) !== -1);
1861
+ return status;
1862
+ }
1863
+ function createResumableUpload(service, location, mappings, blob, metadata) {
1864
+ const urlPart = location.bucketOnlyServerUrl();
1865
+ const metadataForUpload = metadataForUpload_(location, blob, metadata);
1866
+ const urlParams = { name: metadataForUpload['fullPath'] };
1867
+ const url = makeUrl(urlPart, service.host, service._protocol);
1868
+ const method = 'POST';
1869
+ const headers = {
1870
+ 'X-Goog-Upload-Protocol': 'resumable',
1871
+ 'X-Goog-Upload-Command': 'start',
1872
+ 'X-Goog-Upload-Header-Content-Length': `${blob.size()}`,
1873
+ 'X-Goog-Upload-Header-Content-Type': metadataForUpload['contentType'],
1874
+ 'Content-Type': 'application/json; charset=utf-8'
1875
+ };
1876
+ const body = toResourceString(metadataForUpload, mappings);
1877
+ const timeout = service.maxUploadRetryTime;
1878
+ function handler(xhr) {
1879
+ checkResumeHeader_(xhr);
1880
+ let url;
1881
+ try {
1882
+ url = xhr.getResponseHeader('X-Goog-Upload-URL');
1883
+ }
1884
+ catch (e) {
1885
+ handlerCheck(false);
1886
+ }
1887
+ handlerCheck(isString(url));
1888
+ return url;
1889
+ }
1890
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1891
+ requestInfo.urlParams = urlParams;
1892
+ requestInfo.headers = headers;
1893
+ requestInfo.body = body;
1894
+ requestInfo.errorHandler = sharedErrorHandler(location);
1895
+ return requestInfo;
1896
+ }
1897
+ /**
1898
+ * @param url From a call to fbs.requests.createResumableUpload.
1899
+ */
1900
+ function getResumableUploadStatus(service, location, url, blob) {
1901
+ const headers = { 'X-Goog-Upload-Command': 'query' };
1902
+ function handler(xhr) {
1903
+ const status = checkResumeHeader_(xhr, ['active', 'final']);
1904
+ let sizeString = null;
1905
+ try {
1906
+ sizeString = xhr.getResponseHeader('X-Goog-Upload-Size-Received');
1907
+ }
1908
+ catch (e) {
1909
+ handlerCheck(false);
1910
+ }
1911
+ if (!sizeString) {
1912
+ // null or empty string
1913
+ handlerCheck(false);
1914
+ }
1915
+ const size = Number(sizeString);
1916
+ handlerCheck(!isNaN(size));
1917
+ return new ResumableUploadStatus(size, blob.size(), status === 'final');
1918
+ }
1919
+ const method = 'POST';
1920
+ const timeout = service.maxUploadRetryTime;
1921
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
1922
+ requestInfo.headers = headers;
1923
+ requestInfo.errorHandler = sharedErrorHandler(location);
1924
+ return requestInfo;
1925
+ }
1926
+ /**
1927
+ * Any uploads via the resumable upload API must transfer a number of bytes
1928
+ * that is a multiple of this number.
1929
+ */
1930
+ const RESUMABLE_UPLOAD_CHUNK_SIZE = 256 * 1024;
1931
+ /**
1932
+ * @param url From a call to fbs.requests.createResumableUpload.
1933
+ * @param chunkSize Number of bytes to upload.
1934
+ * @param status The previous status.
1935
+ * If not passed or null, we start from the beginning.
1936
+ * @throws fbs.Error If the upload is already complete, the passed in status
1937
+ * has a final size inconsistent with the blob, or the blob cannot be sliced
1938
+ * for upload.
1939
+ */
1940
+ function continueResumableUpload(location, service, url, blob, chunkSize, mappings, status, progressCallback) {
1941
+ // TODO(andysoto): standardize on internal asserts
1942
+ // assert(!(opt_status && opt_status.finalized));
1943
+ const status_ = new ResumableUploadStatus(0, 0);
1944
+ if (status) {
1945
+ status_.current = status.current;
1946
+ status_.total = status.total;
1947
+ }
1948
+ else {
1949
+ status_.current = 0;
1950
+ status_.total = blob.size();
1951
+ }
1952
+ if (blob.size() !== status_.total) {
1953
+ throw serverFileWrongSize();
1954
+ }
1955
+ const bytesLeft = status_.total - status_.current;
1956
+ let bytesToUpload = bytesLeft;
1957
+ if (chunkSize > 0) {
1958
+ bytesToUpload = Math.min(bytesToUpload, chunkSize);
1959
+ }
1960
+ const startByte = status_.current;
1961
+ const endByte = startByte + bytesToUpload;
1962
+ let uploadCommand = '';
1963
+ if (bytesToUpload === 0) {
1964
+ uploadCommand = 'finalize';
1965
+ }
1966
+ else if (bytesLeft === bytesToUpload) {
1967
+ uploadCommand = 'upload, finalize';
1968
+ }
1969
+ else {
1970
+ uploadCommand = 'upload';
1971
+ }
1972
+ const headers = {
1973
+ 'X-Goog-Upload-Command': uploadCommand,
1974
+ 'X-Goog-Upload-Offset': `${status_.current}`
1975
+ };
1976
+ const body = blob.slice(startByte, endByte);
1977
+ if (body === null) {
1978
+ throw cannotSliceBlob();
1979
+ }
1980
+ function handler(xhr, text) {
1981
+ // TODO(andysoto): Verify the MD5 of each uploaded range:
1982
+ // the 'x-range-md5' header comes back with status code 308 responses.
1983
+ // We'll only be able to bail out though, because you can't re-upload a
1984
+ // range that you previously uploaded.
1985
+ const uploadStatus = checkResumeHeader_(xhr, ['active', 'final']);
1986
+ const newCurrent = status_.current + bytesToUpload;
1987
+ const size = blob.size();
1988
+ let metadata;
1989
+ if (uploadStatus === 'final') {
1990
+ metadata = metadataHandler(service, mappings)(xhr, text);
1991
+ }
1992
+ else {
1993
+ metadata = null;
1994
+ }
1995
+ return new ResumableUploadStatus(newCurrent, size, uploadStatus === 'final', metadata);
1996
+ }
1997
+ const method = 'POST';
1998
+ const timeout = service.maxUploadRetryTime;
1999
+ const requestInfo = new RequestInfo(url, method, handler, timeout);
2000
+ requestInfo.headers = headers;
2001
+ requestInfo.body = body.uploadData();
2002
+ requestInfo.progressCallback = progressCallback || null;
2003
+ requestInfo.errorHandler = sharedErrorHandler(location);
2004
+ return requestInfo;
2005
+ }
2006
+
2007
+ /**
2008
+ * @license
2009
+ * Copyright 2017 Google LLC
2010
+ *
2011
+ * Licensed under the Apache License, Version 2.0 (the "License");
2012
+ * you may not use this file except in compliance with the License.
2013
+ * You may obtain a copy of the License at
2014
+ *
2015
+ * http://www.apache.org/licenses/LICENSE-2.0
2016
+ *
2017
+ * Unless required by applicable law or agreed to in writing, software
2018
+ * distributed under the License is distributed on an "AS IS" BASIS,
2019
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2020
+ * See the License for the specific language governing permissions and
2021
+ * limitations under the License.
2022
+ */
2023
+ /**
2024
+ * An event that is triggered on a task.
2025
+ * @internal
2026
+ */
2027
+ const TaskEvent = {
2028
+ /**
2029
+ * For this event,
2030
+ * <ul>
2031
+ * <li>The `next` function is triggered on progress updates and when the
2032
+ * task is paused/resumed with an `UploadTaskSnapshot` as the first
2033
+ * argument.</li>
2034
+ * <li>The `error` function is triggered if the upload is canceled or fails
2035
+ * for another reason.</li>
2036
+ * <li>The `complete` function is triggered if the upload completes
2037
+ * successfully.</li>
2038
+ * </ul>
2039
+ */
2040
+ STATE_CHANGED: 'state_changed'
2041
+ };
2042
+ // type keys = keyof TaskState
2043
+ /**
2044
+ * Represents the current state of a running upload.
2045
+ * @internal
2046
+ */
2047
+ const TaskState = {
2048
+ /** The task is currently transferring data. */
2049
+ RUNNING: 'running',
2050
+ /** The task was paused by the user. */
2051
+ PAUSED: 'paused',
2052
+ /** The task completed successfully. */
2053
+ SUCCESS: 'success',
2054
+ /** The task was canceled. */
2055
+ CANCELED: 'canceled',
2056
+ /** The task failed with an error. */
2057
+ ERROR: 'error'
2058
+ };
2059
+ function taskStateFromInternalTaskState(state) {
2060
+ switch (state) {
2061
+ case "running" /* InternalTaskState.RUNNING */:
2062
+ case "pausing" /* InternalTaskState.PAUSING */:
2063
+ case "canceling" /* InternalTaskState.CANCELING */:
2064
+ return TaskState.RUNNING;
2065
+ case "paused" /* InternalTaskState.PAUSED */:
2066
+ return TaskState.PAUSED;
2067
+ case "success" /* InternalTaskState.SUCCESS */:
2068
+ return TaskState.SUCCESS;
2069
+ case "canceled" /* InternalTaskState.CANCELED */:
2070
+ return TaskState.CANCELED;
2071
+ case "error" /* InternalTaskState.ERROR */:
2072
+ return TaskState.ERROR;
2073
+ default:
2074
+ // TODO(andysoto): assert(false);
2075
+ return TaskState.ERROR;
2076
+ }
2077
+ }
2078
+
2079
+ /**
2080
+ * @license
2081
+ * Copyright 2017 Google LLC
2082
+ *
2083
+ * Licensed under the Apache License, Version 2.0 (the "License");
2084
+ * you may not use this file except in compliance with the License.
2085
+ * You may obtain a copy of the License at
2086
+ *
2087
+ * http://www.apache.org/licenses/LICENSE-2.0
2088
+ *
2089
+ * Unless required by applicable law or agreed to in writing, software
2090
+ * distributed under the License is distributed on an "AS IS" BASIS,
2091
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2092
+ * See the License for the specific language governing permissions and
2093
+ * limitations under the License.
2094
+ */
2095
+ class Observer {
2096
+ constructor(nextOrObserver, error, complete) {
2097
+ const asFunctions = isFunction(nextOrObserver) || error != null || complete != null;
2098
+ if (asFunctions) {
2099
+ this.next = nextOrObserver;
2100
+ this.error = error !== null && error !== void 0 ? error : undefined;
2101
+ this.complete = complete !== null && complete !== void 0 ? complete : undefined;
2102
+ }
2103
+ else {
2104
+ const observer = nextOrObserver;
2105
+ this.next = observer.next;
2106
+ this.error = observer.error;
2107
+ this.complete = observer.complete;
2108
+ }
2109
+ }
2110
+ }
2111
+
2112
+ /**
2113
+ * @license
2114
+ * Copyright 2017 Google LLC
2115
+ *
2116
+ * Licensed under the Apache License, Version 2.0 (the "License");
2117
+ * you may not use this file except in compliance with the License.
2118
+ * You may obtain a copy of the License at
2119
+ *
2120
+ * http://www.apache.org/licenses/LICENSE-2.0
2121
+ *
2122
+ * Unless required by applicable law or agreed to in writing, software
2123
+ * distributed under the License is distributed on an "AS IS" BASIS,
2124
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2125
+ * See the License for the specific language governing permissions and
2126
+ * limitations under the License.
2127
+ */
2128
+ /**
2129
+ * Returns a function that invokes f with its arguments asynchronously as a
2130
+ * microtask, i.e. as soon as possible after the current script returns back
2131
+ * into browser code.
2132
+ */
2133
+ // eslint-disable-next-line @typescript-eslint/ban-types
2134
+ function async(f) {
2135
+ return (...argsToForward) => {
2136
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
2137
+ Promise.resolve().then(() => f(...argsToForward));
2138
+ };
2139
+ }
2140
+
2141
+ /**
2142
+ * @license
2143
+ * Copyright 2017 Google LLC
2144
+ *
2145
+ * Licensed under the Apache License, Version 2.0 (the "License");
2146
+ * you may not use this file except in compliance with the License.
2147
+ * You may obtain a copy of the License at
2148
+ *
2149
+ * http://www.apache.org/licenses/LICENSE-2.0
2150
+ *
2151
+ * Unless required by applicable law or agreed to in writing, software
2152
+ * distributed under the License is distributed on an "AS IS" BASIS,
2153
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2154
+ * See the License for the specific language governing permissions and
2155
+ * limitations under the License.
2156
+ */
2157
+ /** An override for the text-based Connection. Used in tests. */
2158
+ let textFactoryOverride = null;
2159
+ /**
2160
+ * Network layer for browsers. We use this instead of goog.net.XhrIo because
2161
+ * goog.net.XhrIo is hyuuuuge and doesn't work in React Native on Android.
2162
+ */
2163
+ class XhrConnection {
2164
+ constructor() {
2165
+ this.sent_ = false;
2166
+ this.xhr_ = new XMLHttpRequest();
2167
+ this.initXhr();
2168
+ this.errorCode_ = ErrorCode.NO_ERROR;
2169
+ this.sendPromise_ = new Promise(resolve => {
2170
+ this.xhr_.addEventListener('abort', () => {
2171
+ this.errorCode_ = ErrorCode.ABORT;
2172
+ resolve();
2173
+ });
2174
+ this.xhr_.addEventListener('error', () => {
2175
+ this.errorCode_ = ErrorCode.NETWORK_ERROR;
2176
+ resolve();
2177
+ });
2178
+ this.xhr_.addEventListener('load', () => {
2179
+ resolve();
2180
+ });
2181
+ });
2182
+ }
2183
+ send(url, method, body, headers) {
2184
+ if (this.sent_) {
2185
+ throw internalError('cannot .send() more than once');
2186
+ }
2187
+ this.sent_ = true;
2188
+ this.xhr_.open(method, url, true);
2189
+ if (headers !== undefined) {
2190
+ for (const key in headers) {
2191
+ if (headers.hasOwnProperty(key)) {
2192
+ this.xhr_.setRequestHeader(key, headers[key].toString());
2193
+ }
2194
+ }
2195
+ }
2196
+ if (body !== undefined) {
2197
+ this.xhr_.send(body);
2198
+ }
2199
+ else {
2200
+ this.xhr_.send();
2201
+ }
2202
+ return this.sendPromise_;
2203
+ }
2204
+ getErrorCode() {
2205
+ if (!this.sent_) {
2206
+ throw internalError('cannot .getErrorCode() before sending');
2207
+ }
2208
+ return this.errorCode_;
2209
+ }
2210
+ getStatus() {
2211
+ if (!this.sent_) {
2212
+ throw internalError('cannot .getStatus() before sending');
2213
+ }
2214
+ try {
2215
+ return this.xhr_.status;
2216
+ }
2217
+ catch (e) {
2218
+ return -1;
2219
+ }
2220
+ }
2221
+ getResponse() {
2222
+ if (!this.sent_) {
2223
+ throw internalError('cannot .getResponse() before sending');
2224
+ }
2225
+ return this.xhr_.response;
2226
+ }
2227
+ getErrorText() {
2228
+ if (!this.sent_) {
2229
+ throw internalError('cannot .getErrorText() before sending');
2230
+ }
2231
+ return this.xhr_.statusText;
2232
+ }
2233
+ /** Aborts the request. */
2234
+ abort() {
2235
+ this.xhr_.abort();
2236
+ }
2237
+ getResponseHeader(header) {
2238
+ return this.xhr_.getResponseHeader(header);
2239
+ }
2240
+ addUploadProgressListener(listener) {
2241
+ if (this.xhr_.upload != null) {
2242
+ this.xhr_.upload.addEventListener('progress', listener);
2243
+ }
2244
+ }
2245
+ removeUploadProgressListener(listener) {
2246
+ if (this.xhr_.upload != null) {
2247
+ this.xhr_.upload.removeEventListener('progress', listener);
2248
+ }
2249
+ }
2250
+ }
2251
+ class XhrTextConnection extends XhrConnection {
2252
+ initXhr() {
2253
+ this.xhr_.responseType = 'text';
2254
+ }
2255
+ }
2256
+ function newTextConnection() {
2257
+ return textFactoryOverride ? textFactoryOverride() : new XhrTextConnection();
2258
+ }
2259
+ class XhrBytesConnection extends XhrConnection {
2260
+ initXhr() {
2261
+ this.xhr_.responseType = 'arraybuffer';
2262
+ }
2263
+ }
2264
+ function newBytesConnection() {
2265
+ return new XhrBytesConnection();
2266
+ }
2267
+ class XhrBlobConnection extends XhrConnection {
2268
+ initXhr() {
2269
+ this.xhr_.responseType = 'blob';
2270
+ }
2271
+ }
2272
+ function newBlobConnection() {
2273
+ return new XhrBlobConnection();
2274
+ }
2275
+
2276
+ /**
2277
+ * @license
2278
+ * Copyright 2017 Google LLC
2279
+ *
2280
+ * Licensed under the Apache License, Version 2.0 (the "License");
2281
+ * you may not use this file except in compliance with the License.
2282
+ * You may obtain a copy of the License at
2283
+ *
2284
+ * http://www.apache.org/licenses/LICENSE-2.0
2285
+ *
2286
+ * Unless required by applicable law or agreed to in writing, software
2287
+ * distributed under the License is distributed on an "AS IS" BASIS,
2288
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2289
+ * See the License for the specific language governing permissions and
2290
+ * limitations under the License.
2291
+ */
2292
+ /**
2293
+ * Represents a blob being uploaded. Can be used to pause/resume/cancel the
2294
+ * upload and manage callbacks for various events.
2295
+ * @internal
2296
+ */
2297
+ class UploadTask {
2298
+ /**
2299
+ * @param ref - The firebaseStorage.Reference object this task came
2300
+ * from, untyped to avoid cyclic dependencies.
2301
+ * @param blob - The blob to upload.
2302
+ */
2303
+ constructor(ref, blob, metadata = null) {
2304
+ /**
2305
+ * Number of bytes transferred so far.
2306
+ */
2307
+ this._transferred = 0;
2308
+ this._needToFetchStatus = false;
2309
+ this._needToFetchMetadata = false;
2310
+ this._observers = [];
2311
+ this._error = undefined;
2312
+ this._uploadUrl = undefined;
2313
+ this._request = undefined;
2314
+ this._chunkMultiplier = 1;
2315
+ this._resolve = undefined;
2316
+ this._reject = undefined;
2317
+ this._ref = ref;
2318
+ this._blob = blob;
2319
+ this._metadata = metadata;
2320
+ this._mappings = getMappings();
2321
+ this._resumable = this._shouldDoResumable(this._blob);
2322
+ this._state = "running" /* InternalTaskState.RUNNING */;
2323
+ this._errorHandler = error => {
2324
+ this._request = undefined;
2325
+ this._chunkMultiplier = 1;
2326
+ if (error._codeEquals(exports.StorageErrorCode.CANCELED)) {
2327
+ this._needToFetchStatus = true;
2328
+ this.completeTransitions_();
2329
+ }
2330
+ else {
2331
+ const backoffExpired = this.isExponentialBackoffExpired();
2332
+ if (isRetryStatusCode(error.status, [])) {
2333
+ if (backoffExpired) {
2334
+ error = retryLimitExceeded();
2335
+ }
2336
+ else {
2337
+ this.sleepTime = Math.max(this.sleepTime * 2, DEFAULT_MIN_SLEEP_TIME_MILLIS);
2338
+ this._needToFetchStatus = true;
2339
+ this.completeTransitions_();
2340
+ return;
2341
+ }
2342
+ }
2343
+ this._error = error;
2344
+ this._transition("error" /* InternalTaskState.ERROR */);
2345
+ }
2346
+ };
2347
+ this._metadataErrorHandler = error => {
2348
+ this._request = undefined;
2349
+ if (error._codeEquals(exports.StorageErrorCode.CANCELED)) {
2350
+ this.completeTransitions_();
2351
+ }
2352
+ else {
2353
+ this._error = error;
2354
+ this._transition("error" /* InternalTaskState.ERROR */);
2355
+ }
2356
+ };
2357
+ this.sleepTime = 0;
2358
+ this.maxSleepTime = this._ref.storage.maxUploadRetryTime;
2359
+ this._promise = new Promise((resolve, reject) => {
2360
+ this._resolve = resolve;
2361
+ this._reject = reject;
2362
+ this._start();
2363
+ });
2364
+ // Prevent uncaught rejections on the internal promise from bubbling out
2365
+ // to the top level with a dummy handler.
2366
+ this._promise.then(null, () => { });
2367
+ }
2368
+ isExponentialBackoffExpired() {
2369
+ return this.sleepTime > this.maxSleepTime;
2370
+ }
2371
+ _makeProgressCallback() {
2372
+ const sizeBefore = this._transferred;
2373
+ return loaded => this._updateProgress(sizeBefore + loaded);
2374
+ }
2375
+ _shouldDoResumable(blob) {
2376
+ return blob.size() > 256 * 1024;
2377
+ }
2378
+ _start() {
2379
+ if (this._state !== "running" /* InternalTaskState.RUNNING */) {
2380
+ // This can happen if someone pauses us in a resume callback, for example.
2381
+ return;
2382
+ }
2383
+ if (this._request !== undefined) {
2384
+ return;
2385
+ }
2386
+ if (this._resumable) {
2387
+ if (this._uploadUrl === undefined) {
2388
+ this._createResumable();
2389
+ }
2390
+ else {
2391
+ if (this._needToFetchStatus) {
2392
+ this._fetchStatus();
2393
+ }
2394
+ else {
2395
+ if (this._needToFetchMetadata) {
2396
+ // Happens if we miss the metadata on upload completion.
2397
+ this._fetchMetadata();
2398
+ }
2399
+ else {
2400
+ this.pendingTimeout = setTimeout(() => {
2401
+ this.pendingTimeout = undefined;
2402
+ this._continueUpload();
2403
+ }, this.sleepTime);
2404
+ }
2405
+ }
2406
+ }
2407
+ }
2408
+ else {
2409
+ this._oneShotUpload();
2410
+ }
2411
+ }
2412
+ _resolveToken(callback) {
2413
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
2414
+ Promise.all([
2415
+ this._ref.storage._getAuthToken(),
2416
+ this._ref.storage._getAppCheckToken()
2417
+ ]).then(([authToken, appCheckToken]) => {
2418
+ switch (this._state) {
2419
+ case "running" /* InternalTaskState.RUNNING */:
2420
+ callback(authToken, appCheckToken);
2421
+ break;
2422
+ case "canceling" /* InternalTaskState.CANCELING */:
2423
+ this._transition("canceled" /* InternalTaskState.CANCELED */);
2424
+ break;
2425
+ case "pausing" /* InternalTaskState.PAUSING */:
2426
+ this._transition("paused" /* InternalTaskState.PAUSED */);
2427
+ break;
2428
+ }
2429
+ });
2430
+ }
2431
+ // TODO(andysoto): assert false
2432
+ _createResumable() {
2433
+ this._resolveToken((authToken, appCheckToken) => {
2434
+ const requestInfo = createResumableUpload(this._ref.storage, this._ref._location, this._mappings, this._blob, this._metadata);
2435
+ const createRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken);
2436
+ this._request = createRequest;
2437
+ createRequest.getPromise().then((url) => {
2438
+ this._request = undefined;
2439
+ this._uploadUrl = url;
2440
+ this._needToFetchStatus = false;
2441
+ this.completeTransitions_();
2442
+ }, this._errorHandler);
2443
+ });
2444
+ }
2445
+ _fetchStatus() {
2446
+ // TODO(andysoto): assert(this.uploadUrl_ !== null);
2447
+ const url = this._uploadUrl;
2448
+ this._resolveToken((authToken, appCheckToken) => {
2449
+ const requestInfo = getResumableUploadStatus(this._ref.storage, this._ref._location, url, this._blob);
2450
+ const statusRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken);
2451
+ this._request = statusRequest;
2452
+ statusRequest.getPromise().then(status => {
2453
+ status = status;
2454
+ this._request = undefined;
2455
+ this._updateProgress(status.current);
2456
+ this._needToFetchStatus = false;
2457
+ if (status.finalized) {
2458
+ this._needToFetchMetadata = true;
2459
+ }
2460
+ this.completeTransitions_();
2461
+ }, this._errorHandler);
2462
+ });
2463
+ }
2464
+ _continueUpload() {
2465
+ const chunkSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
2466
+ const status = new ResumableUploadStatus(this._transferred, this._blob.size());
2467
+ // TODO(andysoto): assert(this.uploadUrl_ !== null);
2468
+ const url = this._uploadUrl;
2469
+ this._resolveToken((authToken, appCheckToken) => {
2470
+ let requestInfo;
2471
+ try {
2472
+ requestInfo = continueResumableUpload(this._ref._location, this._ref.storage, url, this._blob, chunkSize, this._mappings, status, this._makeProgressCallback());
2473
+ }
2474
+ catch (e) {
2475
+ this._error = e;
2476
+ this._transition("error" /* InternalTaskState.ERROR */);
2477
+ return;
2478
+ }
2479
+ const uploadRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken,
2480
+ /*retry=*/ false // Upload requests should not be retried as each retry should be preceded by another query request. Which is handled in this file.
2481
+ );
2482
+ this._request = uploadRequest;
2483
+ uploadRequest.getPromise().then((newStatus) => {
2484
+ this._increaseMultiplier();
2485
+ this._request = undefined;
2486
+ this._updateProgress(newStatus.current);
2487
+ if (newStatus.finalized) {
2488
+ this._metadata = newStatus.metadata;
2489
+ this._transition("success" /* InternalTaskState.SUCCESS */);
2490
+ }
2491
+ else {
2492
+ this.completeTransitions_();
2493
+ }
2494
+ }, this._errorHandler);
2495
+ });
2496
+ }
2497
+ _increaseMultiplier() {
2498
+ const currentSize = RESUMABLE_UPLOAD_CHUNK_SIZE * this._chunkMultiplier;
2499
+ // Max chunk size is 32M.
2500
+ if (currentSize * 2 < 32 * 1024 * 1024) {
2501
+ this._chunkMultiplier *= 2;
2502
+ }
2503
+ }
2504
+ _fetchMetadata() {
2505
+ this._resolveToken((authToken, appCheckToken) => {
2506
+ const requestInfo = getMetadata$2(this._ref.storage, this._ref._location, this._mappings);
2507
+ const metadataRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken);
2508
+ this._request = metadataRequest;
2509
+ metadataRequest.getPromise().then(metadata => {
2510
+ this._request = undefined;
2511
+ this._metadata = metadata;
2512
+ this._transition("success" /* InternalTaskState.SUCCESS */);
2513
+ }, this._metadataErrorHandler);
2514
+ });
2515
+ }
2516
+ _oneShotUpload() {
2517
+ this._resolveToken((authToken, appCheckToken) => {
2518
+ const requestInfo = multipartUpload(this._ref.storage, this._ref._location, this._mappings, this._blob, this._metadata);
2519
+ const multipartRequest = this._ref.storage._makeRequest(requestInfo, newTextConnection, authToken, appCheckToken);
2520
+ this._request = multipartRequest;
2521
+ multipartRequest.getPromise().then(metadata => {
2522
+ this._request = undefined;
2523
+ this._metadata = metadata;
2524
+ this._updateProgress(this._blob.size());
2525
+ this._transition("success" /* InternalTaskState.SUCCESS */);
2526
+ }, this._errorHandler);
2527
+ });
2528
+ }
2529
+ _updateProgress(transferred) {
2530
+ const old = this._transferred;
2531
+ this._transferred = transferred;
2532
+ // A progress update can make the "transferred" value smaller (e.g. a
2533
+ // partial upload not completed by server, after which the "transferred"
2534
+ // value may reset to the value at the beginning of the request).
2535
+ if (this._transferred !== old) {
2536
+ this._notifyObservers();
2537
+ }
2538
+ }
2539
+ _transition(state) {
2540
+ if (this._state === state) {
2541
+ return;
2542
+ }
2543
+ switch (state) {
2544
+ case "canceling" /* InternalTaskState.CANCELING */:
2545
+ case "pausing" /* InternalTaskState.PAUSING */:
2546
+ // TODO(andysoto):
2547
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2548
+ // this.state_ === InternalTaskState.PAUSING);
2549
+ this._state = state;
2550
+ if (this._request !== undefined) {
2551
+ this._request.cancel();
2552
+ }
2553
+ else if (this.pendingTimeout) {
2554
+ clearTimeout(this.pendingTimeout);
2555
+ this.pendingTimeout = undefined;
2556
+ this.completeTransitions_();
2557
+ }
2558
+ break;
2559
+ case "running" /* InternalTaskState.RUNNING */:
2560
+ // TODO(andysoto):
2561
+ // assert(this.state_ === InternalTaskState.PAUSED ||
2562
+ // this.state_ === InternalTaskState.PAUSING);
2563
+ const wasPaused = this._state === "paused" /* InternalTaskState.PAUSED */;
2564
+ this._state = state;
2565
+ if (wasPaused) {
2566
+ this._notifyObservers();
2567
+ this._start();
2568
+ }
2569
+ break;
2570
+ case "paused" /* InternalTaskState.PAUSED */:
2571
+ // TODO(andysoto):
2572
+ // assert(this.state_ === InternalTaskState.PAUSING);
2573
+ this._state = state;
2574
+ this._notifyObservers();
2575
+ break;
2576
+ case "canceled" /* InternalTaskState.CANCELED */:
2577
+ // TODO(andysoto):
2578
+ // assert(this.state_ === InternalTaskState.PAUSED ||
2579
+ // this.state_ === InternalTaskState.CANCELING);
2580
+ this._error = canceled();
2581
+ this._state = state;
2582
+ this._notifyObservers();
2583
+ break;
2584
+ case "error" /* InternalTaskState.ERROR */:
2585
+ // TODO(andysoto):
2586
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2587
+ // this.state_ === InternalTaskState.PAUSING ||
2588
+ // this.state_ === InternalTaskState.CANCELING);
2589
+ this._state = state;
2590
+ this._notifyObservers();
2591
+ break;
2592
+ case "success" /* InternalTaskState.SUCCESS */:
2593
+ // TODO(andysoto):
2594
+ // assert(this.state_ === InternalTaskState.RUNNING ||
2595
+ // this.state_ === InternalTaskState.PAUSING ||
2596
+ // this.state_ === InternalTaskState.CANCELING);
2597
+ this._state = state;
2598
+ this._notifyObservers();
2599
+ break;
2600
+ }
2601
+ }
2602
+ completeTransitions_() {
2603
+ switch (this._state) {
2604
+ case "pausing" /* InternalTaskState.PAUSING */:
2605
+ this._transition("paused" /* InternalTaskState.PAUSED */);
2606
+ break;
2607
+ case "canceling" /* InternalTaskState.CANCELING */:
2608
+ this._transition("canceled" /* InternalTaskState.CANCELED */);
2609
+ break;
2610
+ case "running" /* InternalTaskState.RUNNING */:
2611
+ this._start();
2612
+ break;
2613
+ }
2614
+ }
2615
+ /**
2616
+ * A snapshot of the current task state.
2617
+ */
2618
+ get snapshot() {
2619
+ const externalState = taskStateFromInternalTaskState(this._state);
2620
+ return {
2621
+ bytesTransferred: this._transferred,
2622
+ totalBytes: this._blob.size(),
2623
+ state: externalState,
2624
+ metadata: this._metadata,
2625
+ task: this,
2626
+ ref: this._ref
2627
+ };
2628
+ }
2629
+ /**
2630
+ * Adds a callback for an event.
2631
+ * @param type - The type of event to listen for.
2632
+ * @param nextOrObserver -
2633
+ * The `next` function, which gets called for each item in
2634
+ * the event stream, or an observer object with some or all of these three
2635
+ * properties (`next`, `error`, `complete`).
2636
+ * @param error - A function that gets called with a `StorageError`
2637
+ * if the event stream ends due to an error.
2638
+ * @param completed - A function that gets called if the
2639
+ * event stream ends normally.
2640
+ * @returns
2641
+ * If only the event argument is passed, returns a function you can use to
2642
+ * add callbacks (see the examples above). If more than just the event
2643
+ * argument is passed, returns a function you can call to unregister the
2644
+ * callbacks.
2645
+ */
2646
+ on(type, nextOrObserver, error, completed) {
2647
+ // Note: `type` isn't being used. Its type is also incorrect. TaskEvent should not be a string.
2648
+ const observer = new Observer(nextOrObserver || undefined, error || undefined, completed || undefined);
2649
+ this._addObserver(observer);
2650
+ return () => {
2651
+ this._removeObserver(observer);
2652
+ };
2653
+ }
2654
+ /**
2655
+ * This object behaves like a Promise, and resolves with its snapshot data
2656
+ * when the upload completes.
2657
+ * @param onFulfilled - The fulfillment callback. Promise chaining works as normal.
2658
+ * @param onRejected - The rejection callback.
2659
+ */
2660
+ then(onFulfilled, onRejected) {
2661
+ // These casts are needed so that TypeScript can infer the types of the
2662
+ // resulting Promise.
2663
+ return this._promise.then(onFulfilled, onRejected);
2664
+ }
2665
+ /**
2666
+ * Equivalent to calling `then(null, onRejected)`.
2667
+ */
2668
+ catch(onRejected) {
2669
+ return this.then(null, onRejected);
2670
+ }
2671
+ /**
2672
+ * Adds the given observer.
2673
+ */
2674
+ _addObserver(observer) {
2675
+ this._observers.push(observer);
2676
+ this._notifyObserver(observer);
2677
+ }
2678
+ /**
2679
+ * Removes the given observer.
2680
+ */
2681
+ _removeObserver(observer) {
2682
+ const i = this._observers.indexOf(observer);
2683
+ if (i !== -1) {
2684
+ this._observers.splice(i, 1);
2685
+ }
2686
+ }
2687
+ _notifyObservers() {
2688
+ this._finishPromise();
2689
+ const observers = this._observers.slice();
2690
+ observers.forEach(observer => {
2691
+ this._notifyObserver(observer);
2692
+ });
2693
+ }
2694
+ _finishPromise() {
2695
+ if (this._resolve !== undefined) {
2696
+ let triggered = true;
2697
+ switch (taskStateFromInternalTaskState(this._state)) {
2698
+ case TaskState.SUCCESS:
2699
+ async(this._resolve.bind(null, this.snapshot))();
2700
+ break;
2701
+ case TaskState.CANCELED:
2702
+ case TaskState.ERROR:
2703
+ const toCall = this._reject;
2704
+ async(toCall.bind(null, this._error))();
2705
+ break;
2706
+ default:
2707
+ triggered = false;
2708
+ break;
2709
+ }
2710
+ if (triggered) {
2711
+ this._resolve = undefined;
2712
+ this._reject = undefined;
2713
+ }
2714
+ }
2715
+ }
2716
+ _notifyObserver(observer) {
2717
+ const externalState = taskStateFromInternalTaskState(this._state);
2718
+ switch (externalState) {
2719
+ case TaskState.RUNNING:
2720
+ case TaskState.PAUSED:
2721
+ if (observer.next) {
2722
+ async(observer.next.bind(observer, this.snapshot))();
2723
+ }
2724
+ break;
2725
+ case TaskState.SUCCESS:
2726
+ if (observer.complete) {
2727
+ async(observer.complete.bind(observer))();
2728
+ }
2729
+ break;
2730
+ case TaskState.CANCELED:
2731
+ case TaskState.ERROR:
2732
+ if (observer.error) {
2733
+ async(observer.error.bind(observer, this._error))();
2734
+ }
2735
+ break;
2736
+ default:
2737
+ // TODO(andysoto): assert(false);
2738
+ if (observer.error) {
2739
+ async(observer.error.bind(observer, this._error))();
2740
+ }
2741
+ }
2742
+ }
2743
+ /**
2744
+ * Resumes a paused task. Has no effect on a currently running or failed task.
2745
+ * @returns True if the operation took effect, false if ignored.
2746
+ */
2747
+ resume() {
2748
+ const valid = this._state === "paused" /* InternalTaskState.PAUSED */ ||
2749
+ this._state === "pausing" /* InternalTaskState.PAUSING */;
2750
+ if (valid) {
2751
+ this._transition("running" /* InternalTaskState.RUNNING */);
2752
+ }
2753
+ return valid;
2754
+ }
2755
+ /**
2756
+ * Pauses a currently running task. Has no effect on a paused or failed task.
2757
+ * @returns True if the operation took effect, false if ignored.
2758
+ */
2759
+ pause() {
2760
+ const valid = this._state === "running" /* InternalTaskState.RUNNING */;
2761
+ if (valid) {
2762
+ this._transition("pausing" /* InternalTaskState.PAUSING */);
2763
+ }
2764
+ return valid;
2765
+ }
2766
+ /**
2767
+ * Cancels a currently running or paused task. Has no effect on a complete or
2768
+ * failed task.
2769
+ * @returns True if the operation took effect, false if ignored.
2770
+ */
2771
+ cancel() {
2772
+ const valid = this._state === "running" /* InternalTaskState.RUNNING */ ||
2773
+ this._state === "pausing" /* InternalTaskState.PAUSING */;
2774
+ if (valid) {
2775
+ this._transition("canceling" /* InternalTaskState.CANCELING */);
2776
+ }
2777
+ return valid;
2778
+ }
2779
+ }
2780
+
2781
+ /**
2782
+ * @license
2783
+ * Copyright 2019 Google LLC
2784
+ *
2785
+ * Licensed under the Apache License, Version 2.0 (the "License");
2786
+ * you may not use this file except in compliance with the License.
2787
+ * You may obtain a copy of the License at
2788
+ *
2789
+ * http://www.apache.org/licenses/LICENSE-2.0
2790
+ *
2791
+ * Unless required by applicable law or agreed to in writing, software
2792
+ * distributed under the License is distributed on an "AS IS" BASIS,
2793
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
2794
+ * See the License for the specific language governing permissions and
2795
+ * limitations under the License.
2796
+ */
2797
+ /**
2798
+ * Provides methods to interact with a bucket in the Firebase Storage service.
2799
+ * @internal
2800
+ * @param _location - An fbs.location, or the URL at
2801
+ * which to base this object, in one of the following forms:
2802
+ * gs://<bucket>/<object-path>
2803
+ * http[s]://firebasestorage.googleapis.com/
2804
+ * <api-version>/b/<bucket>/o/<object-path>
2805
+ * Any query or fragment strings will be ignored in the http[s]
2806
+ * format. If no value is passed, the storage object will use a URL based on
2807
+ * the project ID of the base firebase.App instance.
2808
+ */
2809
+ class Reference {
2810
+ constructor(_service, location) {
2811
+ this._service = _service;
2812
+ if (location instanceof Location) {
2813
+ this._location = location;
2814
+ }
2815
+ else {
2816
+ this._location = Location.makeFromUrl(location, _service.host);
2817
+ }
2818
+ }
2819
+ /**
2820
+ * Returns the URL for the bucket and path this object references,
2821
+ * in the form gs://<bucket>/<object-path>
2822
+ * @override
2823
+ */
2824
+ toString() {
2825
+ return 'gs://' + this._location.bucket + '/' + this._location.path;
2826
+ }
2827
+ _newRef(service, location) {
2828
+ return new Reference(service, location);
2829
+ }
2830
+ /**
2831
+ * A reference to the root of this object's bucket.
2832
+ */
2833
+ get root() {
2834
+ const location = new Location(this._location.bucket, '');
2835
+ return this._newRef(this._service, location);
2836
+ }
2837
+ /**
2838
+ * The name of the bucket containing this reference's object.
2839
+ */
2840
+ get bucket() {
2841
+ return this._location.bucket;
2842
+ }
2843
+ /**
2844
+ * The full path of this object.
2845
+ */
2846
+ get fullPath() {
2847
+ return this._location.path;
2848
+ }
2849
+ /**
2850
+ * The short name of this object, which is the last component of the full path.
2851
+ * For example, if fullPath is 'full/path/image.png', name is 'image.png'.
2852
+ */
2853
+ get name() {
2854
+ return lastComponent(this._location.path);
2855
+ }
2856
+ /**
2857
+ * The `StorageService` instance this `StorageReference` is associated with.
2858
+ */
2859
+ get storage() {
2860
+ return this._service;
2861
+ }
2862
+ /**
2863
+ * A `StorageReference` pointing to the parent location of this `StorageReference`, or null if
2864
+ * this reference is the root.
2865
+ */
2866
+ get parent() {
2867
+ const newPath = parent(this._location.path);
2868
+ if (newPath === null) {
2869
+ return null;
2870
+ }
2871
+ const location = new Location(this._location.bucket, newPath);
2872
+ return new Reference(this._service, location);
2873
+ }
2874
+ /**
2875
+ * Utility function to throw an error in methods that do not accept a root reference.
2876
+ */
2877
+ _throwIfRoot(name) {
2878
+ if (this._location.path === '') {
2879
+ throw invalidRootOperation(name);
2880
+ }
2881
+ }
2882
+ }
2883
+ /**
2884
+ * Download the bytes at the object's location.
2885
+ * @returns A Promise containing the downloaded bytes.
2886
+ */
2887
+ function getBytesInternal(ref, maxDownloadSizeBytes) {
2888
+ ref._throwIfRoot('getBytes');
2889
+ const requestInfo = getBytes$1(ref.storage, ref._location, maxDownloadSizeBytes);
2890
+ return ref.storage
2891
+ .makeRequestWithTokens(requestInfo, newBytesConnection)
2892
+ .then(bytes => maxDownloadSizeBytes !== undefined
2893
+ ? // GCS may not honor the Range header for small files
2894
+ bytes.slice(0, maxDownloadSizeBytes)
2895
+ : bytes);
2896
+ }
2897
+ /**
2898
+ * Download the bytes at the object's location.
2899
+ * @returns A Promise containing the downloaded blob.
2900
+ */
2901
+ function getBlobInternal(ref, maxDownloadSizeBytes) {
2902
+ ref._throwIfRoot('getBlob');
2903
+ const requestInfo = getBytes$1(ref.storage, ref._location, maxDownloadSizeBytes);
2904
+ return ref.storage
2905
+ .makeRequestWithTokens(requestInfo, newBlobConnection)
2906
+ .then(blob => maxDownloadSizeBytes !== undefined
2907
+ ? // GCS may not honor the Range header for small files
2908
+ blob.slice(0, maxDownloadSizeBytes)
2909
+ : blob);
2910
+ }
2911
+ /**
2912
+ * Uploads data to this object's location.
2913
+ * The upload is not resumable.
2914
+ *
2915
+ * @param ref - StorageReference where data should be uploaded.
2916
+ * @param data - The data to upload.
2917
+ * @param metadata - Metadata for the newly uploaded data.
2918
+ * @returns A Promise containing an UploadResult
2919
+ */
2920
+ function uploadBytes$1(ref, data, metadata) {
2921
+ ref._throwIfRoot('uploadBytes');
2922
+ const requestInfo = multipartUpload(ref.storage, ref._location, getMappings(), new FbsBlob(data, true), metadata);
2923
+ return ref.storage
2924
+ .makeRequestWithTokens(requestInfo, newTextConnection)
2925
+ .then(finalMetadata => {
2926
+ return {
2927
+ metadata: finalMetadata,
2928
+ ref
2929
+ };
2930
+ });
2931
+ }
2932
+ /**
2933
+ * Uploads data to this object's location.
2934
+ * The upload can be paused and resumed, and exposes progress updates.
2935
+ * @public
2936
+ * @param ref - StorageReference where data should be uploaded.
2937
+ * @param data - The data to upload.
2938
+ * @param metadata - Metadata for the newly uploaded data.
2939
+ * @returns An UploadTask
2940
+ */
2941
+ function uploadBytesResumable$1(ref, data, metadata) {
2942
+ ref._throwIfRoot('uploadBytesResumable');
2943
+ return new UploadTask(ref, new FbsBlob(data), metadata);
2944
+ }
2945
+ /**
2946
+ * Uploads a string to this object's location.
2947
+ * The upload is not resumable.
2948
+ * @public
2949
+ * @param ref - StorageReference where string should be uploaded.
2950
+ * @param value - The string to upload.
2951
+ * @param format - The format of the string to upload.
2952
+ * @param metadata - Metadata for the newly uploaded string.
2953
+ * @returns A Promise containing an UploadResult
2954
+ */
2955
+ function uploadString$1(ref, value, format = StringFormat.RAW, metadata) {
2956
+ ref._throwIfRoot('uploadString');
2957
+ const data = dataFromString(format, value);
2958
+ const metadataClone = Object.assign({}, metadata);
2959
+ if (metadataClone['contentType'] == null && data.contentType != null) {
2960
+ metadataClone['contentType'] = data.contentType;
2961
+ }
2962
+ return uploadBytes$1(ref, data.data, metadataClone);
2963
+ }
2964
+ /**
2965
+ * List all items (files) and prefixes (folders) under this storage reference.
2966
+ *
2967
+ * This is a helper method for calling list() repeatedly until there are
2968
+ * no more results. The default pagination size is 1000.
2969
+ *
2970
+ * Note: The results may not be consistent if objects are changed while this
2971
+ * operation is running.
2972
+ *
2973
+ * Warning: listAll may potentially consume too many resources if there are
2974
+ * too many results.
2975
+ * @public
2976
+ * @param ref - StorageReference to get list from.
2977
+ *
2978
+ * @returns A Promise that resolves with all the items and prefixes under
2979
+ * the current storage reference. `prefixes` contains references to
2980
+ * sub-directories and `items` contains references to objects in this
2981
+ * folder. `nextPageToken` is never returned.
2982
+ */
2983
+ function listAll$1(ref) {
2984
+ const accumulator = {
2985
+ prefixes: [],
2986
+ items: []
2987
+ };
2988
+ return listAllHelper(ref, accumulator).then(() => accumulator);
2989
+ }
2990
+ /**
2991
+ * Separated from listAll because async functions can't use "arguments".
2992
+ * @param ref
2993
+ * @param accumulator
2994
+ * @param pageToken
2995
+ */
2996
+ async function listAllHelper(ref, accumulator, pageToken) {
2997
+ const opt = {
2998
+ // maxResults is 1000 by default.
2999
+ pageToken
3000
+ };
3001
+ const nextPage = await list$1(ref, opt);
3002
+ accumulator.prefixes.push(...nextPage.prefixes);
3003
+ accumulator.items.push(...nextPage.items);
3004
+ if (nextPage.nextPageToken != null) {
3005
+ await listAllHelper(ref, accumulator, nextPage.nextPageToken);
3006
+ }
3007
+ }
3008
+ /**
3009
+ * List items (files) and prefixes (folders) under this storage reference.
3010
+ *
3011
+ * List API is only available for Firebase Rules Version 2.
3012
+ *
3013
+ * GCS is a key-blob store. Firebase Storage imposes the semantic of '/'
3014
+ * delimited folder structure.
3015
+ * Refer to GCS's List API if you want to learn more.
3016
+ *
3017
+ * To adhere to Firebase Rules's Semantics, Firebase Storage does not
3018
+ * support objects whose paths end with "/" or contain two consecutive
3019
+ * "/"s. Firebase Storage List API will filter these unsupported objects.
3020
+ * list() may fail if there are too many unsupported objects in the bucket.
3021
+ * @public
3022
+ *
3023
+ * @param ref - StorageReference to get list from.
3024
+ * @param options - See ListOptions for details.
3025
+ * @returns A Promise that resolves with the items and prefixes.
3026
+ * `prefixes` contains references to sub-folders and `items`
3027
+ * contains references to objects in this folder. `nextPageToken`
3028
+ * can be used to get the rest of the results.
3029
+ */
3030
+ function list$1(ref, options) {
3031
+ if (options != null) {
3032
+ if (typeof options.maxResults === 'number') {
3033
+ validateNumber('options.maxResults',
3034
+ /* minValue= */ 1,
3035
+ /* maxValue= */ 1000, options.maxResults);
3036
+ }
3037
+ }
3038
+ const op = options || {};
3039
+ const requestInfo = list$2(ref.storage, ref._location,
3040
+ /*delimiter= */ '/', op.pageToken, op.maxResults);
3041
+ return ref.storage.makeRequestWithTokens(requestInfo, newTextConnection);
3042
+ }
3043
+ /**
3044
+ * A `Promise` that resolves with the metadata for this object. If this
3045
+ * object doesn't exist or metadata cannot be retreived, the promise is
3046
+ * rejected.
3047
+ * @public
3048
+ * @param ref - StorageReference to get metadata from.
3049
+ */
3050
+ function getMetadata$1(ref) {
3051
+ ref._throwIfRoot('getMetadata');
3052
+ const requestInfo = getMetadata$2(ref.storage, ref._location, getMappings());
3053
+ return ref.storage.makeRequestWithTokens(requestInfo, newTextConnection);
3054
+ }
3055
+ /**
3056
+ * Updates the metadata for this object.
3057
+ * @public
3058
+ * @param ref - StorageReference to update metadata for.
3059
+ * @param metadata - The new metadata for the object.
3060
+ * Only values that have been explicitly set will be changed. Explicitly
3061
+ * setting a value to null will remove the metadata.
3062
+ * @returns A `Promise` that resolves
3063
+ * with the new metadata for this object.
3064
+ * See `firebaseStorage.Reference.prototype.getMetadata`
3065
+ */
3066
+ function updateMetadata$1(ref, metadata) {
3067
+ ref._throwIfRoot('updateMetadata');
3068
+ const requestInfo = updateMetadata$2(ref.storage, ref._location, metadata, getMappings());
3069
+ return ref.storage.makeRequestWithTokens(requestInfo, newTextConnection);
3070
+ }
3071
+ /**
3072
+ * Returns the download URL for the given Reference.
3073
+ * @public
3074
+ * @returns A `Promise` that resolves with the download
3075
+ * URL for this object.
3076
+ */
3077
+ function getDownloadURL$1(ref) {
3078
+ ref._throwIfRoot('getDownloadURL');
3079
+ const requestInfo = getDownloadUrl(ref.storage, ref._location, getMappings());
3080
+ return ref.storage
3081
+ .makeRequestWithTokens(requestInfo, newTextConnection)
3082
+ .then(url => {
3083
+ if (url === null) {
3084
+ throw noDownloadURL();
3085
+ }
3086
+ return url;
3087
+ });
3088
+ }
3089
+ /**
3090
+ * Deletes the object at this location.
3091
+ * @public
3092
+ * @param ref - StorageReference for object to delete.
3093
+ * @returns A `Promise` that resolves if the deletion succeeds.
3094
+ */
3095
+ function deleteObject$1(ref) {
3096
+ ref._throwIfRoot('deleteObject');
3097
+ const requestInfo = deleteObject$2(ref.storage, ref._location);
3098
+ return ref.storage.makeRequestWithTokens(requestInfo, newTextConnection);
3099
+ }
3100
+ /**
3101
+ * Returns reference for object obtained by appending `childPath` to `ref`.
3102
+ *
3103
+ * @param ref - StorageReference to get child of.
3104
+ * @param childPath - Child path from provided ref.
3105
+ * @returns A reference to the object obtained by
3106
+ * appending childPath, removing any duplicate, beginning, or trailing
3107
+ * slashes.
3108
+ *
3109
+ */
3110
+ function _getChild$1(ref, childPath) {
3111
+ const newPath = child(ref._location.path, childPath);
3112
+ const location = new Location(ref._location.bucket, newPath);
3113
+ return new Reference(ref.storage, location);
3114
+ }
3115
+
3116
+ /**
3117
+ * @license
3118
+ * Copyright 2017 Google LLC
3119
+ *
3120
+ * Licensed under the Apache License, Version 2.0 (the "License");
3121
+ * you may not use this file except in compliance with the License.
3122
+ * You may obtain a copy of the License at
3123
+ *
3124
+ * http://www.apache.org/licenses/LICENSE-2.0
3125
+ *
3126
+ * Unless required by applicable law or agreed to in writing, software
3127
+ * distributed under the License is distributed on an "AS IS" BASIS,
3128
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3129
+ * See the License for the specific language governing permissions and
3130
+ * limitations under the License.
3131
+ */
3132
+ function isUrl(path) {
3133
+ return /^[A-Za-z]+:\/\//.test(path);
3134
+ }
3135
+ /**
3136
+ * Returns a firebaseStorage.Reference for the given url.
3137
+ */
3138
+ function refFromURL(service, url) {
3139
+ return new Reference(service, url);
3140
+ }
3141
+ /**
3142
+ * Returns a firebaseStorage.Reference for the given path in the default
3143
+ * bucket.
3144
+ */
3145
+ function refFromPath(ref, path) {
3146
+ if (ref instanceof FirebaseStorageImpl) {
3147
+ const service = ref;
3148
+ if (service._bucket == null) {
3149
+ throw noDefaultBucket();
3150
+ }
3151
+ const reference = new Reference(service, service._bucket);
3152
+ if (path != null) {
3153
+ return refFromPath(reference, path);
3154
+ }
3155
+ else {
3156
+ return reference;
3157
+ }
3158
+ }
3159
+ else {
3160
+ // ref is a Reference
3161
+ if (path !== undefined) {
3162
+ return _getChild$1(ref, path);
3163
+ }
3164
+ else {
3165
+ return ref;
3166
+ }
3167
+ }
3168
+ }
3169
+ function ref$1(serviceOrRef, pathOrUrl) {
3170
+ if (pathOrUrl && isUrl(pathOrUrl)) {
3171
+ if (serviceOrRef instanceof FirebaseStorageImpl) {
3172
+ return refFromURL(serviceOrRef, pathOrUrl);
3173
+ }
3174
+ else {
3175
+ throw invalidArgument('To use ref(service, url), the first argument must be a Storage instance.');
3176
+ }
3177
+ }
3178
+ else {
3179
+ return refFromPath(serviceOrRef, pathOrUrl);
3180
+ }
3181
+ }
3182
+ function extractBucket(host, config) {
3183
+ const bucketString = config === null || config === void 0 ? void 0 : config[CONFIG_STORAGE_BUCKET_KEY];
3184
+ if (bucketString == null) {
3185
+ return null;
3186
+ }
3187
+ return Location.makeFromBucketSpec(bucketString, host);
3188
+ }
3189
+ function connectStorageEmulator$1(storage, host, port, options = {}) {
3190
+ storage.host = `${host}:${port}`;
3191
+ storage._protocol = 'http';
3192
+ const { mockUserToken } = options;
3193
+ if (mockUserToken) {
3194
+ storage._overrideAuthToken =
3195
+ typeof mockUserToken === 'string'
3196
+ ? mockUserToken
3197
+ : util.createMockUserToken(mockUserToken, storage.app.options.projectId);
3198
+ }
3199
+ }
3200
+ /**
3201
+ * A service that provides Firebase Storage Reference instances.
3202
+ * @param opt_url - gs:// url to a custom Storage Bucket
3203
+ *
3204
+ * @internal
3205
+ */
3206
+ class FirebaseStorageImpl {
3207
+ constructor(
3208
+ /**
3209
+ * FirebaseApp associated with this StorageService instance.
3210
+ */
3211
+ app, _authProvider,
3212
+ /**
3213
+ * @internal
3214
+ */
3215
+ _appCheckProvider,
3216
+ /**
3217
+ * @internal
3218
+ */
3219
+ _url, _firebaseVersion) {
3220
+ this.app = app;
3221
+ this._authProvider = _authProvider;
3222
+ this._appCheckProvider = _appCheckProvider;
3223
+ this._url = _url;
3224
+ this._firebaseVersion = _firebaseVersion;
3225
+ this._bucket = null;
3226
+ /**
3227
+ * This string can be in the formats:
3228
+ * - host
3229
+ * - host:port
3230
+ */
3231
+ this._host = DEFAULT_HOST;
3232
+ this._protocol = 'https';
3233
+ this._appId = null;
3234
+ this._deleted = false;
3235
+ this._maxOperationRetryTime = DEFAULT_MAX_OPERATION_RETRY_TIME;
3236
+ this._maxUploadRetryTime = DEFAULT_MAX_UPLOAD_RETRY_TIME;
3237
+ this._requests = new Set();
3238
+ if (_url != null) {
3239
+ this._bucket = Location.makeFromBucketSpec(_url, this._host);
3240
+ }
3241
+ else {
3242
+ this._bucket = extractBucket(this._host, this.app.options);
3243
+ }
3244
+ }
3245
+ /**
3246
+ * The host string for this service, in the form of `host` or
3247
+ * `host:port`.
3248
+ */
3249
+ get host() {
3250
+ return this._host;
3251
+ }
3252
+ set host(host) {
3253
+ this._host = host;
3254
+ if (this._url != null) {
3255
+ this._bucket = Location.makeFromBucketSpec(this._url, host);
3256
+ }
3257
+ else {
3258
+ this._bucket = extractBucket(host, this.app.options);
3259
+ }
3260
+ }
3261
+ /**
3262
+ * The maximum time to retry uploads in milliseconds.
3263
+ */
3264
+ get maxUploadRetryTime() {
3265
+ return this._maxUploadRetryTime;
3266
+ }
3267
+ set maxUploadRetryTime(time) {
3268
+ validateNumber('time',
3269
+ /* minValue=*/ 0,
3270
+ /* maxValue= */ Number.POSITIVE_INFINITY, time);
3271
+ this._maxUploadRetryTime = time;
3272
+ }
3273
+ /**
3274
+ * The maximum time to retry operations other than uploads or downloads in
3275
+ * milliseconds.
3276
+ */
3277
+ get maxOperationRetryTime() {
3278
+ return this._maxOperationRetryTime;
3279
+ }
3280
+ set maxOperationRetryTime(time) {
3281
+ validateNumber('time',
3282
+ /* minValue=*/ 0,
3283
+ /* maxValue= */ Number.POSITIVE_INFINITY, time);
3284
+ this._maxOperationRetryTime = time;
3285
+ }
3286
+ async _getAuthToken() {
3287
+ if (this._overrideAuthToken) {
3288
+ return this._overrideAuthToken;
3289
+ }
3290
+ const auth = this._authProvider.getImmediate({ optional: true });
3291
+ if (auth) {
3292
+ const tokenData = await auth.getToken();
3293
+ if (tokenData !== null) {
3294
+ return tokenData.accessToken;
3295
+ }
3296
+ }
3297
+ return null;
3298
+ }
3299
+ async _getAppCheckToken() {
3300
+ const appCheck = this._appCheckProvider.getImmediate({ optional: true });
3301
+ if (appCheck) {
3302
+ const result = await appCheck.getToken();
3303
+ // TODO: What do we want to do if there is an error getting the token?
3304
+ // Context: appCheck.getToken() will never throw even if an error happened. In the error case, a dummy token will be
3305
+ // returned along with an error field describing the error. In general, we shouldn't care about the error condition and just use
3306
+ // the token (actual or dummy) to send requests.
3307
+ return result.token;
3308
+ }
3309
+ return null;
3310
+ }
3311
+ /**
3312
+ * Stop running requests and prevent more from being created.
3313
+ */
3314
+ _delete() {
3315
+ if (!this._deleted) {
3316
+ this._deleted = true;
3317
+ this._requests.forEach(request => request.cancel());
3318
+ this._requests.clear();
3319
+ }
3320
+ return Promise.resolve();
3321
+ }
3322
+ /**
3323
+ * Returns a new firebaseStorage.Reference object referencing this StorageService
3324
+ * at the given Location.
3325
+ */
3326
+ _makeStorageReference(loc) {
3327
+ return new Reference(this, loc);
3328
+ }
3329
+ /**
3330
+ * @param requestInfo - HTTP RequestInfo object
3331
+ * @param authToken - Firebase auth token
3332
+ */
3333
+ _makeRequest(requestInfo, requestFactory, authToken, appCheckToken, retry = true) {
3334
+ if (!this._deleted) {
3335
+ const request = makeRequest(requestInfo, this._appId, authToken, appCheckToken, requestFactory, this._firebaseVersion, retry);
3336
+ this._requests.add(request);
3337
+ // Request removes itself from set when complete.
3338
+ request.getPromise().then(() => this._requests.delete(request), () => this._requests.delete(request));
3339
+ return request;
3340
+ }
3341
+ else {
3342
+ return new FailRequest(appDeleted());
3343
+ }
3344
+ }
3345
+ async makeRequestWithTokens(requestInfo, requestFactory) {
3346
+ const [authToken, appCheckToken] = await Promise.all([
3347
+ this._getAuthToken(),
3348
+ this._getAppCheckToken()
3349
+ ]);
3350
+ return this._makeRequest(requestInfo, requestFactory, authToken, appCheckToken).getPromise();
3351
+ }
3352
+ }
3353
+
3354
+ const name = "@firebase/storage";
3355
+ const version = "0.11.0-20230201003102";
3356
+
3357
+ /**
3358
+ * @license
3359
+ * Copyright 2020 Google LLC
3360
+ *
3361
+ * Licensed under the Apache License, Version 2.0 (the "License");
3362
+ * you may not use this file except in compliance with the License.
3363
+ * You may obtain a copy of the License at
3364
+ *
3365
+ * http://www.apache.org/licenses/LICENSE-2.0
3366
+ *
3367
+ * Unless required by applicable law or agreed to in writing, software
3368
+ * distributed under the License is distributed on an "AS IS" BASIS,
3369
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3370
+ * See the License for the specific language governing permissions and
3371
+ * limitations under the License.
3372
+ */
3373
+ /**
3374
+ * Type constant for Firebase Storage.
3375
+ */
3376
+ const STORAGE_TYPE = 'storage';
3377
+
3378
+ /**
3379
+ * @license
3380
+ * Copyright 2020 Google LLC
3381
+ *
3382
+ * Licensed under the Apache License, Version 2.0 (the "License");
3383
+ * you may not use this file except in compliance with the License.
3384
+ * You may obtain a copy of the License at
3385
+ *
3386
+ * http://www.apache.org/licenses/LICENSE-2.0
3387
+ *
3388
+ * Unless required by applicable law or agreed to in writing, software
3389
+ * distributed under the License is distributed on an "AS IS" BASIS,
3390
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3391
+ * See the License for the specific language governing permissions and
3392
+ * limitations under the License.
3393
+ */
3394
+ /**
3395
+ * Downloads the data at the object's location. Returns an error if the object
3396
+ * is not found.
3397
+ *
3398
+ * To use this functionality, you have to whitelist your app's origin in your
3399
+ * Cloud Storage bucket. See also
3400
+ * https://cloud.google.com/storage/docs/configuring-cors
3401
+ *
3402
+ * @public
3403
+ * @param ref - StorageReference where data should be downloaded.
3404
+ * @param maxDownloadSizeBytes - If set, the maximum allowed size in bytes to
3405
+ * retrieve.
3406
+ * @returns A Promise containing the object's bytes
3407
+ */
3408
+ function getBytes(ref, maxDownloadSizeBytes) {
3409
+ ref = util.getModularInstance(ref);
3410
+ return getBytesInternal(ref, maxDownloadSizeBytes);
3411
+ }
3412
+ /**
3413
+ * Uploads data to this object's location.
3414
+ * The upload is not resumable.
3415
+ * @public
3416
+ * @param ref - {@link StorageReference} where data should be uploaded.
3417
+ * @param data - The data to upload.
3418
+ * @param metadata - Metadata for the data to upload.
3419
+ * @returns A Promise containing an UploadResult
3420
+ */
3421
+ function uploadBytes(ref, data, metadata) {
3422
+ ref = util.getModularInstance(ref);
3423
+ return uploadBytes$1(ref, data, metadata);
3424
+ }
3425
+ /**
3426
+ * Uploads a string to this object's location.
3427
+ * The upload is not resumable.
3428
+ * @public
3429
+ * @param ref - {@link StorageReference} where string should be uploaded.
3430
+ * @param value - The string to upload.
3431
+ * @param format - The format of the string to upload.
3432
+ * @param metadata - Metadata for the string to upload.
3433
+ * @returns A Promise containing an UploadResult
3434
+ */
3435
+ function uploadString(ref, value, format, metadata) {
3436
+ ref = util.getModularInstance(ref);
3437
+ return uploadString$1(ref, value, format, metadata);
3438
+ }
3439
+ /**
3440
+ * Uploads data to this object's location.
3441
+ * The upload can be paused and resumed, and exposes progress updates.
3442
+ * @public
3443
+ * @param ref - {@link StorageReference} where data should be uploaded.
3444
+ * @param data - The data to upload.
3445
+ * @param metadata - Metadata for the data to upload.
3446
+ * @returns An UploadTask
3447
+ */
3448
+ function uploadBytesResumable(ref, data, metadata) {
3449
+ ref = util.getModularInstance(ref);
3450
+ return uploadBytesResumable$1(ref, data, metadata);
3451
+ }
3452
+ /**
3453
+ * A `Promise` that resolves with the metadata for this object. If this
3454
+ * object doesn't exist or metadata cannot be retreived, the promise is
3455
+ * rejected.
3456
+ * @public
3457
+ * @param ref - {@link StorageReference} to get metadata from.
3458
+ */
3459
+ function getMetadata(ref) {
3460
+ ref = util.getModularInstance(ref);
3461
+ return getMetadata$1(ref);
3462
+ }
3463
+ /**
3464
+ * Updates the metadata for this object.
3465
+ * @public
3466
+ * @param ref - {@link StorageReference} to update metadata for.
3467
+ * @param metadata - The new metadata for the object.
3468
+ * Only values that have been explicitly set will be changed. Explicitly
3469
+ * setting a value to null will remove the metadata.
3470
+ * @returns A `Promise` that resolves with the new metadata for this object.
3471
+ */
3472
+ function updateMetadata(ref, metadata) {
3473
+ ref = util.getModularInstance(ref);
3474
+ return updateMetadata$1(ref, metadata);
3475
+ }
3476
+ /**
3477
+ * List items (files) and prefixes (folders) under this storage reference.
3478
+ *
3479
+ * List API is only available for Firebase Rules Version 2.
3480
+ *
3481
+ * GCS is a key-blob store. Firebase Storage imposes the semantic of '/'
3482
+ * delimited folder structure.
3483
+ * Refer to GCS's List API if you want to learn more.
3484
+ *
3485
+ * To adhere to Firebase Rules's Semantics, Firebase Storage does not
3486
+ * support objects whose paths end with "/" or contain two consecutive
3487
+ * "/"s. Firebase Storage List API will filter these unsupported objects.
3488
+ * list() may fail if there are too many unsupported objects in the bucket.
3489
+ * @public
3490
+ *
3491
+ * @param ref - {@link StorageReference} to get list from.
3492
+ * @param options - See {@link ListOptions} for details.
3493
+ * @returns A `Promise` that resolves with the items and prefixes.
3494
+ * `prefixes` contains references to sub-folders and `items`
3495
+ * contains references to objects in this folder. `nextPageToken`
3496
+ * can be used to get the rest of the results.
3497
+ */
3498
+ function list(ref, options) {
3499
+ ref = util.getModularInstance(ref);
3500
+ return list$1(ref, options);
3501
+ }
3502
+ /**
3503
+ * List all items (files) and prefixes (folders) under this storage reference.
3504
+ *
3505
+ * This is a helper method for calling list() repeatedly until there are
3506
+ * no more results. The default pagination size is 1000.
3507
+ *
3508
+ * Note: The results may not be consistent if objects are changed while this
3509
+ * operation is running.
3510
+ *
3511
+ * Warning: `listAll` may potentially consume too many resources if there are
3512
+ * too many results.
3513
+ * @public
3514
+ * @param ref - {@link StorageReference} to get list from.
3515
+ *
3516
+ * @returns A `Promise` that resolves with all the items and prefixes under
3517
+ * the current storage reference. `prefixes` contains references to
3518
+ * sub-directories and `items` contains references to objects in this
3519
+ * folder. `nextPageToken` is never returned.
3520
+ */
3521
+ function listAll(ref) {
3522
+ ref = util.getModularInstance(ref);
3523
+ return listAll$1(ref);
3524
+ }
3525
+ /**
3526
+ * Returns the download URL for the given {@link StorageReference}.
3527
+ * @public
3528
+ * @param ref - {@link StorageReference} to get the download URL for.
3529
+ * @returns A `Promise` that resolves with the download
3530
+ * URL for this object.
3531
+ */
3532
+ function getDownloadURL(ref) {
3533
+ ref = util.getModularInstance(ref);
3534
+ return getDownloadURL$1(ref);
3535
+ }
3536
+ /**
3537
+ * Deletes the object at this location.
3538
+ * @public
3539
+ * @param ref - {@link StorageReference} for object to delete.
3540
+ * @returns A `Promise` that resolves if the deletion succeeds.
3541
+ */
3542
+ function deleteObject(ref) {
3543
+ ref = util.getModularInstance(ref);
3544
+ return deleteObject$1(ref);
3545
+ }
3546
+ function ref(serviceOrRef, pathOrUrl) {
3547
+ serviceOrRef = util.getModularInstance(serviceOrRef);
3548
+ return ref$1(serviceOrRef, pathOrUrl);
3549
+ }
3550
+ /**
3551
+ * @internal
3552
+ */
3553
+ function _getChild(ref, childPath) {
3554
+ return _getChild$1(ref, childPath);
3555
+ }
3556
+ /**
3557
+ * Gets a {@link FirebaseStorage} instance for the given Firebase app.
3558
+ * @public
3559
+ * @param app - Firebase app to get {@link FirebaseStorage} instance for.
3560
+ * @param bucketUrl - The gs:// url to your Firebase Storage Bucket.
3561
+ * If not passed, uses the app's default Storage Bucket.
3562
+ * @returns A {@link FirebaseStorage} instance.
3563
+ */
3564
+ function getStorage(app$1 = app.getApp(), bucketUrl) {
3565
+ app$1 = util.getModularInstance(app$1);
3566
+ const storageProvider = app._getProvider(app$1, STORAGE_TYPE);
3567
+ const storageInstance = storageProvider.getImmediate({
3568
+ identifier: bucketUrl
3569
+ });
3570
+ const emulator = util.getDefaultEmulatorHostnameAndPort('storage');
3571
+ if (emulator) {
3572
+ connectStorageEmulator(storageInstance, ...emulator);
3573
+ }
3574
+ return storageInstance;
3575
+ }
3576
+ /**
3577
+ * Modify this {@link FirebaseStorage} instance to communicate with the Cloud Storage emulator.
3578
+ *
3579
+ * @param storage - The {@link FirebaseStorage} instance
3580
+ * @param host - The emulator host (ex: localhost)
3581
+ * @param port - The emulator port (ex: 5001)
3582
+ * @param options - Emulator options. `options.mockUserToken` is the mock auth
3583
+ * token to use for unit testing Security Rules.
3584
+ * @public
3585
+ */
3586
+ function connectStorageEmulator(storage, host, port, options = {}) {
3587
+ connectStorageEmulator$1(storage, host, port, options);
3588
+ }
3589
+
3590
+ /**
3591
+ * @license
3592
+ * Copyright 2021 Google LLC
3593
+ *
3594
+ * Licensed under the Apache License, Version 2.0 (the "License");
3595
+ * you may not use this file except in compliance with the License.
3596
+ * You may obtain a copy of the License at
3597
+ *
3598
+ * http://www.apache.org/licenses/LICENSE-2.0
3599
+ *
3600
+ * Unless required by applicable law or agreed to in writing, software
3601
+ * distributed under the License is distributed on an "AS IS" BASIS,
3602
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
3603
+ * See the License for the specific language governing permissions and
3604
+ * limitations under the License.
3605
+ */
3606
+ /**
3607
+ * Downloads the data at the object's location. Returns an error if the object
3608
+ * is not found.
3609
+ *
3610
+ * To use this functionality, you have to whitelist your app's origin in your
3611
+ * Cloud Storage bucket. See also
3612
+ * https://cloud.google.com/storage/docs/configuring-cors
3613
+ *
3614
+ * This API is not available in Node.
3615
+ *
3616
+ * @public
3617
+ * @param ref - StorageReference where data should be downloaded.
3618
+ * @param maxDownloadSizeBytes - If set, the maximum allowed size in bytes to
3619
+ * retrieve.
3620
+ * @returns A Promise that resolves with a Blob containing the object's bytes
3621
+ */
3622
+ function getBlob(ref, maxDownloadSizeBytes) {
3623
+ ref = util.getModularInstance(ref);
3624
+ return getBlobInternal(ref, maxDownloadSizeBytes);
3625
+ }
3626
+ /**
3627
+ * Downloads the data at the object's location. Raises an error event if the
3628
+ * object is not found.
3629
+ *
3630
+ * This API is only available in Node.
3631
+ *
3632
+ * @public
3633
+ * @param ref - StorageReference where data should be downloaded.
3634
+ * @param maxDownloadSizeBytes - If set, the maximum allowed size in bytes to
3635
+ * retrieve.
3636
+ * @returns A stream with the object's data as bytes
3637
+ */
3638
+ function getStream(ref, maxDownloadSizeBytes) {
3639
+ throw new Error('getStream() is only supported by NodeJS builds');
3640
+ }
3641
+
3642
+ /**
3643
+ * Cloud Storage for Firebase
3644
+ *
3645
+ * @packageDocumentation
3646
+ */
3647
+ function factory(container, { instanceIdentifier: url }) {
3648
+ const app$1 = container.getProvider('app').getImmediate();
3649
+ const authProvider = container.getProvider('auth-internal');
3650
+ const appCheckProvider = container.getProvider('app-check-internal');
3651
+ return new FirebaseStorageImpl(app$1, authProvider, appCheckProvider, url, app.SDK_VERSION);
3652
+ }
3653
+ function registerStorage() {
3654
+ app._registerComponent(new component.Component(STORAGE_TYPE, factory, "PUBLIC" /* ComponentType.PUBLIC */).setMultipleInstances(true));
3655
+ //RUNTIME_ENV will be replaced during the compilation to "node" for nodejs and an empty string for browser
3656
+ app.registerVersion(name, version, '');
3657
+ // BUILD_TARGET will be replaced by values like esm5, esm2017, cjs5, etc during the compilation
3658
+ app.registerVersion(name, version, 'cjs2017');
3659
+ }
3660
+ registerStorage();
3661
+
3662
+ exports.StorageError = StorageError;
3663
+ exports.StringFormat = StringFormat;
3664
+ exports._FbsBlob = FbsBlob;
3665
+ exports._Location = Location;
3666
+ exports._TaskEvent = TaskEvent;
3667
+ exports._TaskState = TaskState;
3668
+ exports._UploadTask = UploadTask;
3669
+ exports._dataFromString = dataFromString;
3670
+ exports._getChild = _getChild;
3671
+ exports._invalidArgument = invalidArgument;
3672
+ exports._invalidRootOperation = invalidRootOperation;
3673
+ exports.connectStorageEmulator = connectStorageEmulator;
3674
+ exports.deleteObject = deleteObject;
3675
+ exports.getBlob = getBlob;
3676
+ exports.getBytes = getBytes;
3677
+ exports.getDownloadURL = getDownloadURL;
3678
+ exports.getMetadata = getMetadata;
3679
+ exports.getStorage = getStorage;
3680
+ exports.getStream = getStream;
3681
+ exports.list = list;
3682
+ exports.listAll = listAll;
3683
+ exports.ref = ref;
3684
+ exports.updateMetadata = updateMetadata;
3685
+ exports.uploadBytes = uploadBytes;
3686
+ exports.uploadBytesResumable = uploadBytesResumable;
3687
+ exports.uploadString = uploadString;
3688
+ //# sourceMappingURL=index.cjs.js.map