UNPKG

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