UNPKG

8.52 kBJavaScriptView Raw
1import { Observable, of, from } from 'rxjs';
2import { debounceTime, map, observeOn, switchMap } from 'rxjs/operators';
3import * as i0 from '@angular/core';
4import { InjectionToken, Injectable, Inject, Optional, PLATFORM_ID, NgZone, Pipe, ChangeDetectorRef, NgModule } from '@angular/core';
5import * as i1 from '@angular/fire';
6import { ɵAngularFireSchedulers, ɵkeepUnstableUntilFirstFactory, ɵfirebaseAppFactory, ɵfetchInstance, FIREBASE_OPTIONS, FIREBASE_APP_NAME } from '@angular/fire';
7import 'firebase/storage';
8import { AsyncPipe } from '@angular/common';
9
10// Things aren't working great, I'm having to put in a lot of work-arounds for what
11// appear to be Firebase JS SDK bugs https://github.com/firebase/firebase-js-sdk/issues/4158
12function fromTask(task) {
13 return new Observable(subscriber => {
14 const progress = (snap) => subscriber.next(snap);
15 const error = e => subscriber.error(e);
16 const complete = () => subscriber.complete();
17 // emit the current snapshot, so they don't have to wait for state_changes
18 // to fire next... this is stale if the task is no longer running :(
19 progress(task.snapshot);
20 const unsub = task.on('state_changed', progress);
21 // it turns out that neither task snapshot nor 'state_changed' fire the last
22 // snapshot before completion, the one with status 'success" and 100% progress
23 // so let's use the promise form of the task for that
24 task.then(snapshot => {
25 progress(snapshot);
26 complete();
27 }, e => {
28 // TODO investigate, again this is stale, we never fire a canceled or error it seems
29 progress(task.snapshot);
30 error(e);
31 });
32 // on's type if Function, rather than () => void, need to wrap
33 return function unsubscribe() {
34 unsub();
35 };
36 }).pipe(
37 // deal with sync emissions from first emitting `task.snapshot`, this makes sure
38 // that if the task is already finished we don't emit the old running state
39 debounceTime(0));
40}
41
42/**
43 * Create an AngularFireUploadTask from a regular UploadTask from the Storage SDK.
44 * This method creates an observable of the upload and returns on object that provides
45 * multiple methods for controlling and monitoring the file upload.
46 */
47function createUploadTask(task) {
48 const inner$ = fromTask(task);
49 return {
50 task,
51 then: task.then.bind(task),
52 catch: task.catch.bind(task),
53 pause: task.pause.bind(task),
54 cancel: task.cancel.bind(task),
55 resume: task.resume.bind(task),
56 snapshotChanges: () => inner$,
57 percentageChanges: () => inner$.pipe(map(s => s.bytesTransferred / s.totalBytes * 100))
58 };
59}
60
61/**
62 * Create an AngularFire wrapped Storage Reference. This object
63 * creates observable methods from promise based methods.
64 */
65function createStorageRef(ref, schedulers, keepUnstableUntilFirst) {
66 return {
67 getDownloadURL: () => of(undefined).pipe(observeOn(schedulers.outsideAngular), switchMap(() => ref.getDownloadURL()), keepUnstableUntilFirst),
68 getMetadata: () => of(undefined).pipe(observeOn(schedulers.outsideAngular), switchMap(() => ref.getMetadata()), keepUnstableUntilFirst),
69 delete: () => from(ref.delete()),
70 child: (path) => createStorageRef(ref.child(path), schedulers, keepUnstableUntilFirst),
71 updateMetadata: (meta) => from(ref.updateMetadata(meta)),
72 put: (data, metadata) => {
73 const task = ref.put(data, metadata);
74 return createUploadTask(task);
75 },
76 putString: (data, format, metadata) => {
77 const task = ref.putString(data, format, metadata);
78 return createUploadTask(task);
79 },
80 listAll: () => from(ref.listAll())
81 };
82}
83
84const BUCKET = new InjectionToken('angularfire2.storageBucket');
85const MAX_UPLOAD_RETRY_TIME = new InjectionToken('angularfire2.storage.maxUploadRetryTime');
86const MAX_OPERATION_RETRY_TIME = new InjectionToken('angularfire2.storage.maxOperationRetryTime');
87/**
88 * AngularFireStorage Service
89 *
90 * This service is the main entry point for this feature module. It provides
91 * an API for uploading and downloading binary files from Cloud Storage for
92 * Firebase.
93 */
94class AngularFireStorage {
95 constructor(options, nameOrConfig, storageBucket,
96 // tslint:disable-next-line:ban-types
97 platformId, zone, maxUploadRetryTime, maxOperationRetryTime) {
98 this.schedulers = new ɵAngularFireSchedulers(zone);
99 this.keepUnstableUntilFirst = ɵkeepUnstableUntilFirstFactory(this.schedulers);
100 const app = ɵfirebaseAppFactory(options, zone, nameOrConfig);
101 this.storage = ɵfetchInstance(`${app.name}.storage.${storageBucket}`, 'AngularFireStorage', app, () => {
102 const storage = zone.runOutsideAngular(() => app.storage(storageBucket || undefined));
103 if (maxUploadRetryTime) {
104 storage.setMaxUploadRetryTime(maxUploadRetryTime);
105 }
106 if (maxOperationRetryTime) {
107 storage.setMaxOperationRetryTime(maxOperationRetryTime);
108 }
109 return storage;
110 }, [maxUploadRetryTime, maxOperationRetryTime]);
111 }
112 ref(path) {
113 return createStorageRef(this.storage.ref(path), this.schedulers, this.keepUnstableUntilFirst);
114 }
115 refFromURL(path) {
116 return createStorageRef(this.storage.refFromURL(path), this.schedulers, this.keepUnstableUntilFirst);
117 }
118 upload(path, data, metadata) {
119 const storageRef = this.storage.ref(path);
120 const ref = createStorageRef(storageRef, this.schedulers, this.keepUnstableUntilFirst);
121 return ref.put(data, metadata);
122 }
123}
124/** @nocollapse */ AngularFireStorage.ɵprov = i0.ɵɵdefineInjectable({ factory: function AngularFireStorage_Factory() { return new AngularFireStorage(i0.ɵɵinject(i1.FIREBASE_OPTIONS), i0.ɵɵinject(i1.FIREBASE_APP_NAME, 8), i0.ɵɵinject(BUCKET, 8), i0.ɵɵinject(i0.PLATFORM_ID), i0.ɵɵinject(i0.NgZone), i0.ɵɵinject(MAX_UPLOAD_RETRY_TIME, 8), i0.ɵɵinject(MAX_OPERATION_RETRY_TIME, 8)); }, token: AngularFireStorage, providedIn: "any" });
125AngularFireStorage.decorators = [
126 { type: Injectable, args: [{
127 providedIn: 'any'
128 },] }
129];
130/** @nocollapse */
131AngularFireStorage.ctorParameters = () => [
132 { type: undefined, decorators: [{ type: Inject, args: [FIREBASE_OPTIONS,] }] },
133 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [FIREBASE_APP_NAME,] }] },
134 { type: String, decorators: [{ type: Optional }, { type: Inject, args: [BUCKET,] }] },
135 { type: Object, decorators: [{ type: Inject, args: [PLATFORM_ID,] }] },
136 { type: NgZone },
137 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAX_UPLOAD_RETRY_TIME,] }] },
138 { type: undefined, decorators: [{ type: Optional }, { type: Inject, args: [MAX_OPERATION_RETRY_TIME,] }] }
139];
140
141/** to be used with in combination with | async */
142class GetDownloadURLPipe {
143 constructor(storage, cdr) {
144 this.storage = storage;
145 this.asyncPipe = new AsyncPipe(cdr);
146 }
147 transform(path) {
148 if (path !== this.path) {
149 this.path = path;
150 this.downloadUrl$ = this.storage.ref(path).getDownloadURL();
151 }
152 return this.asyncPipe.transform(this.downloadUrl$);
153 }
154 ngOnDestroy() {
155 this.asyncPipe.ngOnDestroy();
156 }
157}
158GetDownloadURLPipe.decorators = [
159 { type: Pipe, args: [{
160 name: 'getDownloadURL',
161 pure: false,
162 },] }
163];
164/** @nocollapse */
165GetDownloadURLPipe.ctorParameters = () => [
166 { type: AngularFireStorage },
167 { type: ChangeDetectorRef }
168];
169class GetDownloadURLPipeModule {
170}
171GetDownloadURLPipeModule.decorators = [
172 { type: NgModule, args: [{
173 declarations: [GetDownloadURLPipe],
174 exports: [GetDownloadURLPipe],
175 },] }
176];
177
178class AngularFireStorageModule {
179}
180AngularFireStorageModule.decorators = [
181 { type: NgModule, args: [{
182 exports: [GetDownloadURLPipeModule],
183 providers: [AngularFireStorage]
184 },] }
185];
186
187/**
188 * Generated bundle index. Do not edit.
189 */
190
191export { AngularFireStorage, AngularFireStorageModule, BUCKET, GetDownloadURLPipe, GetDownloadURLPipeModule, MAX_OPERATION_RETRY_TIME, MAX_UPLOAD_RETRY_TIME, createStorageRef, createUploadTask, fromTask };
192//# sourceMappingURL=angular-fire-storage.js.map