@react-native-firebase/storage 24.1.1 → 25.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/{lib → dist/module}/StorageDownloadTask.js +4 -3
  3. package/dist/module/StorageDownloadTask.js.map +1 -0
  4. package/{lib → dist/module}/StorageListResult.js +13 -8
  5. package/dist/module/StorageListResult.js.map +1 -0
  6. package/dist/module/StorageReference.js +270 -0
  7. package/dist/module/StorageReference.js.map +1 -0
  8. package/{lib → dist/module}/StorageStatics.js +5 -16
  9. package/dist/module/StorageStatics.js.map +1 -0
  10. package/{lib → dist/module}/StorageTask.js +82 -71
  11. package/dist/module/StorageTask.js.map +1 -0
  12. package/{lib → dist/module}/StorageUploadTask.js +4 -3
  13. package/dist/module/StorageUploadTask.js.map +1 -0
  14. package/dist/module/index.js +29 -0
  15. package/dist/module/index.js.map +1 -0
  16. package/{lib/modular/index.js → dist/module/modular.js} +65 -79
  17. package/dist/module/modular.js.map +1 -0
  18. package/dist/module/namespaced.js +192 -0
  19. package/dist/module/namespaced.js.map +1 -0
  20. package/dist/module/package.json +1 -0
  21. package/dist/module/types/internal.js +4 -0
  22. package/dist/module/types/internal.js.map +1 -0
  23. package/dist/module/types/namespaced.js +64 -0
  24. package/dist/module/types/namespaced.js.map +1 -0
  25. package/dist/module/types/storage.js +139 -0
  26. package/dist/module/types/storage.js.map +1 -0
  27. package/dist/module/utils.js +105 -0
  28. package/dist/module/utils.js.map +1 -0
  29. package/dist/module/version.js +5 -0
  30. package/dist/module/version.js.map +1 -0
  31. package/dist/module/web/RNFBStorageModule.android.js +6 -0
  32. package/dist/module/web/RNFBStorageModule.android.js.map +1 -0
  33. package/dist/module/web/RNFBStorageModule.ios.js +6 -0
  34. package/dist/module/web/RNFBStorageModule.ios.js.map +1 -0
  35. package/{lib → dist/module}/web/RNFBStorageModule.js +115 -197
  36. package/dist/module/web/RNFBStorageModule.js.map +1 -0
  37. package/dist/typescript/lib/StorageDownloadTask.d.ts +6 -0
  38. package/dist/typescript/lib/StorageDownloadTask.d.ts.map +1 -0
  39. package/dist/typescript/lib/StorageListResult.d.ts +13 -0
  40. package/dist/typescript/lib/StorageListResult.d.ts.map +1 -0
  41. package/dist/typescript/lib/StorageReference.d.ts +87 -0
  42. package/dist/typescript/lib/StorageReference.d.ts.map +1 -0
  43. package/dist/typescript/lib/StorageStatics.d.ts +2 -0
  44. package/dist/typescript/lib/StorageStatics.d.ts.map +1 -0
  45. package/dist/typescript/lib/StorageTask.d.ts +43 -0
  46. package/dist/typescript/lib/StorageTask.d.ts.map +1 -0
  47. package/dist/typescript/lib/StorageUploadTask.d.ts +6 -0
  48. package/dist/typescript/lib/StorageUploadTask.d.ts.map +1 -0
  49. package/dist/typescript/lib/index.d.ts +6 -0
  50. package/dist/typescript/lib/index.d.ts.map +1 -0
  51. package/dist/typescript/lib/modular.d.ts +154 -0
  52. package/dist/typescript/lib/modular.d.ts.map +1 -0
  53. package/dist/typescript/lib/namespaced.d.ts +12 -0
  54. package/dist/typescript/lib/namespaced.d.ts.map +1 -0
  55. package/dist/typescript/lib/types/internal.d.ts +131 -0
  56. package/dist/typescript/lib/types/internal.d.ts.map +1 -0
  57. package/dist/typescript/lib/types/namespaced.d.ts +1122 -0
  58. package/dist/typescript/lib/types/namespaced.d.ts.map +1 -0
  59. package/dist/typescript/lib/types/storage.d.ts +338 -0
  60. package/dist/typescript/lib/types/storage.d.ts.map +1 -0
  61. package/dist/typescript/lib/utils.d.ts +20 -0
  62. package/dist/typescript/lib/utils.d.ts.map +1 -0
  63. package/dist/typescript/lib/version.d.ts +2 -0
  64. package/dist/typescript/lib/version.d.ts.map +1 -0
  65. package/dist/typescript/lib/web/RNFBStorageModule.android.d.ts +3 -0
  66. package/dist/typescript/lib/web/RNFBStorageModule.android.d.ts.map +1 -0
  67. package/dist/typescript/lib/web/RNFBStorageModule.d.ts +142 -0
  68. package/dist/typescript/lib/web/RNFBStorageModule.d.ts.map +1 -0
  69. package/dist/typescript/lib/web/RNFBStorageModule.ios.d.ts +3 -0
  70. package/dist/typescript/lib/web/RNFBStorageModule.ios.d.ts.map +1 -0
  71. package/dist/typescript/package.json +1 -0
  72. package/lib/StorageDownloadTask.ts +30 -0
  73. package/lib/StorageListResult.ts +61 -0
  74. package/lib/{StorageReference.js → StorageReference.ts} +103 -61
  75. package/lib/StorageStatics.ts +19 -0
  76. package/lib/StorageTask.ts +336 -0
  77. package/lib/StorageUploadTask.ts +30 -0
  78. package/lib/index.ts +27 -0
  79. package/lib/modular.ts +401 -0
  80. package/lib/{index.js → namespaced.ts} +70 -28
  81. package/lib/types/internal.ts +189 -0
  82. package/lib/{index.d.ts → types/namespaced.ts} +111 -49
  83. package/lib/types/storage.ts +417 -0
  84. package/lib/{utils.js → utils.ts} +62 -15
  85. package/lib/version.ts +2 -0
  86. package/lib/web/RNFBStorageModule.android.ts +3 -0
  87. package/lib/web/RNFBStorageModule.ios.ts +3 -0
  88. package/lib/web/RNFBStorageModule.ts +557 -0
  89. package/package.json +41 -7
  90. package/tsconfig.json +23 -0
  91. package/typedoc.json +1 -1
  92. package/lib/modular/index.d.ts +0 -276
  93. package/lib/version.js +0 -2
  94. package/lib/web/RNFBStorageModule.android.js +0 -2
  95. package/lib/web/RNFBStorageModule.ios.js +0 -2
@@ -29,15 +29,28 @@ import {
29
29
  pathParent,
30
30
  ReferenceBase,
31
31
  toFilePath,
32
+ isModularCall,
32
33
  } from '@react-native-firebase/app/dist/module/common';
33
34
  import StorageDownloadTask from './StorageDownloadTask';
34
35
  import StorageListResult, { provideStorageReferenceClass } from './StorageListResult';
35
36
  import { StringFormat } from './StorageStatics';
36
37
  import StorageUploadTask from './StorageUploadTask';
37
38
  import { validateMetadata } from './utils';
38
-
39
- export default class StorageReference extends ReferenceBase {
40
- constructor(storage, path) {
39
+ import type {
40
+ StorageReference,
41
+ SettableMetadata,
42
+ UploadMetadata,
43
+ ListOptions,
44
+ FullMetadata,
45
+ Task,
46
+ FirebaseStorage,
47
+ } from './types/storage';
48
+ import type { ListResultInternal, StorageInternal } from './types/internal';
49
+
50
+ export default class Reference extends ReferenceBase implements StorageReference {
51
+ _storage: StorageInternal;
52
+
53
+ constructor(storage: StorageInternal, path: string) {
41
54
  super(path);
42
55
  this._storage = storage;
43
56
  }
@@ -45,145 +58,162 @@ export default class StorageReference extends ReferenceBase {
45
58
  /**
46
59
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#bucket
47
60
  */
48
- get bucket() {
49
- return this._storage._customUrlOrRegion.replace('gs://', '');
61
+ get bucket(): string {
62
+ return this._storage._customUrlOrRegion!.replace('gs://', '');
50
63
  }
51
64
 
52
65
  /**
53
66
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#fullPath
54
67
  */
55
- get fullPath() {
68
+ get fullPath(): string {
56
69
  return this.path;
57
70
  }
58
71
 
59
72
  /**
60
73
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#name
61
74
  */
62
- get name() {
75
+ get name(): string {
63
76
  return pathLastComponent(this.path);
64
77
  }
65
78
 
66
79
  /**
67
80
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#parent
68
81
  */
69
- get parent() {
82
+ get parent(): StorageReference | null {
70
83
  const parentPath = pathParent(this.path);
71
84
  if (parentPath === null) {
72
85
  return parentPath;
73
86
  }
74
- return new StorageReference(this._storage, parentPath);
87
+ return new Reference(this._storage, parentPath);
75
88
  }
76
89
 
77
90
  /**
78
91
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#root
79
92
  */
80
- get root() {
81
- return new StorageReference(this._storage, '/');
93
+ get root(): StorageReference {
94
+ return new Reference(this._storage, '/');
82
95
  }
83
96
 
84
97
  /**
85
98
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#storage
86
99
  */
87
- get storage() {
100
+ get storage(): FirebaseStorage {
88
101
  return this._storage;
89
102
  }
90
103
 
91
104
  /**
92
105
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#child
93
106
  */
94
- child(path) {
107
+ child(path: string): StorageReference {
95
108
  const childPath = pathChild(this.path, path);
96
- return new StorageReference(this._storage, childPath);
109
+ return new Reference(this._storage, childPath);
97
110
  }
98
111
 
99
112
  /**
100
113
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#delete
101
114
  */
102
- delete() {
115
+ delete(): Promise<void> {
103
116
  return this._storage.native.delete(this.toString());
104
117
  }
105
118
 
106
119
  /**
107
120
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getDownloadURL
108
121
  */
109
- getDownloadURL() {
122
+ getDownloadURL(): Promise<string> {
110
123
  return this._storage.native.getDownloadURL(this.toString());
111
124
  }
112
125
 
113
126
  /**
114
127
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#getMetadata
115
128
  */
116
- getMetadata() {
129
+ getMetadata(): Promise<FullMetadata> {
117
130
  return this._storage.native.getMetadata(this.toString());
118
131
  }
119
132
 
120
133
  /**
121
134
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#list
122
135
  */
123
- list(options) {
136
+ list(options?: ListOptions): Promise<StorageListResult> {
124
137
  if (!isUndefined(options) && !isObject(options)) {
125
138
  throw new Error(
126
139
  "firebase.storage.StorageReference.list(*) 'options' expected an object value.",
127
140
  );
128
141
  }
129
142
 
130
- const listOptions = {
143
+ const listOptions: { maxResults: number; pageToken?: string } = {
131
144
  maxResults: 1000,
132
145
  };
133
146
 
147
+ const isModular = isModularCall(arguments);
148
+
134
149
  if (options) {
135
150
  if (hasOwnProperty(options, 'maxResults')) {
136
- if (!isNumber(options.maxResults) || !isInteger(options.maxResults)) {
137
- throw new Error(
138
- "firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value.",
139
- );
140
- }
141
-
142
- if (options.maxResults < 1 || options.maxResults > 1000) {
143
- throw new Error(
144
- "firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value between 1-1000.",
145
- );
151
+ const maxResults = options.maxResults;
152
+ // Modular typings allow `null` for omission - ignore safely.
153
+ if (isModular && (maxResults === null || isUndefined(maxResults))) {
154
+ // no-op (keep default)
155
+ } else {
156
+ if (!isNumber(maxResults) || !isInteger(maxResults)) {
157
+ throw new Error(
158
+ "firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value.",
159
+ );
160
+ }
161
+
162
+ if (maxResults < 1 || maxResults > 1000) {
163
+ throw new Error(
164
+ "firebase.storage.StorageReference.list(*) 'options.maxResults' expected a number value between 1-1000.",
165
+ );
166
+ }
167
+
168
+ listOptions.maxResults = maxResults;
146
169
  }
147
-
148
- listOptions.maxResults = options.maxResults;
149
170
  }
150
171
 
151
- if (options.pageToken) {
152
- if (!isString(options.pageToken)) {
153
- throw new Error(
154
- "firebase.storage.StorageReference.list(*) 'options.pageToken' expected a string value.",
155
- );
172
+ if (hasOwnProperty(options, 'pageToken')) {
173
+ const pageToken = options.pageToken;
174
+ // Modular typings allow `null` for omission - ignore safely.
175
+ if (isModular && (pageToken === null || isUndefined(pageToken))) {
176
+ // no-op
177
+ } else if (!isUndefined(pageToken) && pageToken !== null) {
178
+ if (!isString(pageToken)) {
179
+ throw new Error(
180
+ "firebase.storage.StorageReference.list(*) 'options.pageToken' expected a string value.",
181
+ );
182
+ }
183
+
184
+ listOptions.pageToken = pageToken;
156
185
  }
157
-
158
- listOptions.pageToken = options.pageToken;
159
186
  }
160
187
  }
161
188
 
162
189
  return this._storage.native
163
190
  .list(this.toString(), listOptions)
164
- .then(data => new StorageListResult(this._storage, data));
191
+ .then((data: ListResultInternal) => new StorageListResult(this._storage, data));
165
192
  }
166
193
 
167
194
  /**
168
195
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#listAll
169
196
  */
170
- listAll() {
197
+ listAll(): Promise<StorageListResult> {
171
198
  return this._storage.native
172
199
  .listAll(this.toString())
173
- .then(data => new StorageListResult(this._storage, data));
200
+ .then((data: ListResultInternal) => new StorageListResult(this._storage, data));
174
201
  }
175
202
 
176
203
  /**
177
204
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#put
178
205
  */
179
- put(data, metadata) {
180
- if (!isUndefined(metadata)) {
181
- validateMetadata(metadata, false);
182
- }
206
+ put(data: Blob | Uint8Array | ArrayBuffer, metadata?: UploadMetadata): Task {
207
+ const validatedMetadata = isUndefined(metadata) ? metadata : validateMetadata(metadata, false);
183
208
 
184
209
  return new StorageUploadTask(this, task =>
185
210
  Base64.fromData(data).then(({ string, format }) => {
186
- const { _string, _format, _metadata } = this._updateString(string, format, metadata, false);
211
+ const { _string, _format, _metadata } = this._updateString(
212
+ string as string,
213
+ format,
214
+ validatedMetadata,
215
+ false,
216
+ );
187
217
  return this._storage.native.putString(
188
218
  this.toString(),
189
219
  _string,
@@ -198,7 +228,11 @@ export default class StorageReference extends ReferenceBase {
198
228
  /**
199
229
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#putString
200
230
  */
201
- putString(string, format = StringFormat.RAW, metadata) {
231
+ putString(
232
+ string: string,
233
+ format: (typeof StringFormat)[keyof typeof StringFormat] = StringFormat.RAW,
234
+ metadata?: UploadMetadata,
235
+ ): Task {
202
236
  const { _string, _format, _metadata } = this._updateString(string, format, metadata, false);
203
237
 
204
238
  return new StorageUploadTask(this, task =>
@@ -209,7 +243,7 @@ export default class StorageReference extends ReferenceBase {
209
243
  /**
210
244
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#fullPath
211
245
  */
212
- toString() {
246
+ toString(): string {
213
247
  if (this.path.length <= 1) {
214
248
  return `${this._storage._customUrlOrRegion}`;
215
249
  }
@@ -220,9 +254,9 @@ export default class StorageReference extends ReferenceBase {
220
254
  /**
221
255
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference#updateMetadata
222
256
  */
223
- updateMetadata(metadata) {
224
- validateMetadata(metadata);
225
- return this._storage.native.updateMetadata(this.toString(), metadata);
257
+ updateMetadata(metadata: SettableMetadata): Promise<FullMetadata> {
258
+ const validatedMetadata = validateMetadata(metadata);
259
+ return this._storage.native.updateMetadata(this.toString(), validatedMetadata);
226
260
  }
227
261
 
228
262
  /* ----------------------------------------
@@ -232,7 +266,7 @@ export default class StorageReference extends ReferenceBase {
232
266
  /**
233
267
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference
234
268
  */
235
- writeToFile(filePath) {
269
+ writeToFile(filePath: string): Task {
236
270
  if (!isString(filePath)) {
237
271
  throw new Error(
238
272
  "firebase.storage.StorageReference.writeToFile(*) 'filePath' expects a string value.",
@@ -247,10 +281,8 @@ export default class StorageReference extends ReferenceBase {
247
281
  /**
248
282
  * @url https://firebase.google.com/docs/reference/js/firebase.storage.Reference
249
283
  */
250
- putFile(filePath, metadata) {
251
- if (!isUndefined(metadata)) {
252
- validateMetadata(metadata, false);
253
- }
284
+ putFile(filePath: string, metadata?: UploadMetadata): Task {
285
+ const validatedMetadata = isUndefined(metadata) ? metadata : validateMetadata(metadata, false);
254
286
 
255
287
  if (!isString(filePath)) {
256
288
  throw new Error(
@@ -259,11 +291,21 @@ export default class StorageReference extends ReferenceBase {
259
291
  }
260
292
 
261
293
  return new StorageUploadTask(this, task =>
262
- this._storage.native.putFile(this.toString(), toFilePath(filePath), metadata, task._id),
294
+ this._storage.native.putFile(
295
+ this.toString(),
296
+ toFilePath(filePath),
297
+ validatedMetadata,
298
+ task._id,
299
+ ),
263
300
  );
264
301
  }
265
302
 
266
- _updateString(string, format, metadata, update = false) {
303
+ _updateString(
304
+ string: string,
305
+ format: (typeof StringFormat)[keyof typeof StringFormat],
306
+ metadata: UploadMetadata | undefined,
307
+ update = false,
308
+ ): { _string: string; _format: string; _metadata: UploadMetadata | undefined } {
267
309
  if (!isString(string)) {
268
310
  throw new Error(
269
311
  "firebase.storage.StorageReference.putString(*, _, _) 'string' expects a string value.",
@@ -279,7 +321,7 @@ export default class StorageReference extends ReferenceBase {
279
321
  }
280
322
 
281
323
  if (!isUndefined(metadata)) {
282
- validateMetadata(metadata, update);
324
+ metadata = validateMetadata(metadata, update) as UploadMetadata;
283
325
  }
284
326
 
285
327
  let _string = string;
@@ -301,7 +343,7 @@ export default class StorageReference extends ReferenceBase {
301
343
  if (isUndefined(metadata)) {
302
344
  _metadata = {};
303
345
  }
304
- _metadata.contentType = mediaType;
346
+ _metadata!.contentType = mediaType;
305
347
  _string = base64String;
306
348
  _format = StringFormat.BASE64;
307
349
  }
@@ -310,4 +352,4 @@ export default class StorageReference extends ReferenceBase {
310
352
  }
311
353
  }
312
354
 
313
- provideStorageReferenceClass(StorageReference);
355
+ provideStorageReferenceClass(Reference);
@@ -0,0 +1,19 @@
1
+ /*
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ // Runtime constants live in `types/storage.ts` (alongside their derived-union types).
19
+ export { StringFormat, TaskEvent, TaskState } from './types/storage';
@@ -0,0 +1,336 @@
1
+ /*
2
+ * Copyright (c) 2016-present Invertase Limited & Contributors
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this library except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ *
16
+ */
17
+
18
+ import { isFunction, isNull, isObject } from '@react-native-firebase/app/dist/module/common';
19
+ import type { EmitterSubscription } from 'react-native';
20
+ import { TaskEvent } from './StorageStatics';
21
+ import type { ReactNativeFirebase } from '@react-native-firebase/app';
22
+ import type {
23
+ FullMetadata,
24
+ StorageObserver,
25
+ StorageReference,
26
+ Subscribe,
27
+ Task,
28
+ TaskSnapshot,
29
+ Unsubscribe,
30
+ } from './types/storage';
31
+ import type { StorageReferenceInternal, StorageInternal } from './types/internal';
32
+
33
+ let TASK_ID = 0;
34
+
35
+ type TaskEventType = (typeof TaskEvent)[keyof typeof TaskEvent];
36
+
37
+ function createEmptyMetadata(ref: StorageReference): FullMetadata {
38
+ return {
39
+ bucket: ref.bucket,
40
+ fullPath: ref.fullPath,
41
+ generation: '',
42
+ metageneration: '',
43
+ name: ref.name,
44
+ size: 0,
45
+ timeCreated: '',
46
+ updated: '',
47
+ downloadTokens: undefined,
48
+ ref,
49
+ };
50
+ }
51
+
52
+ function wrapErrorEventListener(
53
+ listenerFn: ((error: ReactNativeFirebase.NativeFirebaseError) => void) | null | undefined,
54
+ unsubscribe: (() => void) | null | undefined,
55
+ ): (snapshot: TaskSnapshot) => void {
56
+ return (snapshot: TaskSnapshot) => {
57
+ if (unsubscribe) {
58
+ setTimeout(() => unsubscribe(), 0);
59
+ } // 1 frame = 16ms, pushing to next frame
60
+ if (isFunction(listenerFn)) {
61
+ const errorEvent = snapshot as TaskSnapshot & {
62
+ error?: ReactNativeFirebase.NativeFirebaseError;
63
+ };
64
+ if (errorEvent.error) {
65
+ listenerFn(errorEvent.error);
66
+ }
67
+ }
68
+ };
69
+ }
70
+
71
+ function wrapSnapshotEventListener(
72
+ task: StorageTask,
73
+ listenerFn: ((snapshot: TaskSnapshot) => unknown) | null | undefined,
74
+ unsubscribe: (() => void) | null | undefined,
75
+ ): ((snapshot: TaskSnapshot) => void) | null {
76
+ if (!isFunction(listenerFn)) {
77
+ return null;
78
+ }
79
+ return (snapshot: TaskSnapshot) => {
80
+ if (unsubscribe) {
81
+ setTimeout(() => unsubscribe(), 0);
82
+ } // 1 frame = 16ms, pushing to next frame
83
+ if (isFunction(listenerFn)) {
84
+ const taskSnapshot = Object.assign({}, snapshot);
85
+ taskSnapshot.task = task as Task;
86
+ taskSnapshot.ref = task._ref;
87
+
88
+ if (!taskSnapshot.metadata) {
89
+ taskSnapshot.metadata = createEmptyMetadata(task._ref);
90
+ } else {
91
+ if (!taskSnapshot.metadata.generation) taskSnapshot.metadata.generation = '';
92
+ if (!taskSnapshot.metadata.bucket) taskSnapshot.metadata.bucket = task._ref.bucket;
93
+ if (!taskSnapshot.metadata.metageneration) taskSnapshot.metadata.metageneration = '';
94
+ if (!taskSnapshot.metadata.fullPath) taskSnapshot.metadata.fullPath = task._ref.fullPath;
95
+ if (!taskSnapshot.metadata.name) taskSnapshot.metadata.name = task._ref.name;
96
+ if (!taskSnapshot.metadata.ref) taskSnapshot.metadata.ref = task._ref;
97
+ }
98
+
99
+ Object.freeze(taskSnapshot);
100
+ task._snapshot = taskSnapshot;
101
+
102
+ listenerFn(taskSnapshot);
103
+ }
104
+ };
105
+ }
106
+
107
+ function addTaskEventListener(
108
+ task: StorageTask,
109
+ eventName: string,
110
+ listener: (snapshot: TaskSnapshot) => void,
111
+ ): EmitterSubscription {
112
+ let _eventName = eventName;
113
+ if (_eventName !== TaskEvent.STATE_CHANGED) {
114
+ _eventName = `${task._type}_${eventName}`;
115
+ }
116
+
117
+ return task._storage.emitter.addListener(
118
+ task._storage.eventNameForApp(task._id, _eventName),
119
+ listener,
120
+ );
121
+ }
122
+
123
+ function subscribeToEvents(
124
+ task: StorageTask,
125
+ nextOrObserver?: ((snapshot: TaskSnapshot) => unknown) | StorageObserver<TaskSnapshot> | null,
126
+ error?: ((error: ReactNativeFirebase.NativeFirebaseError) => unknown) | null,
127
+ complete?: (() => unknown) | null,
128
+ ): () => void {
129
+ let _error: ((snapshot: TaskSnapshot) => void) | undefined;
130
+ let _errorSubscription: EmitterSubscription | undefined;
131
+
132
+ let _next: ((snapshot: TaskSnapshot) => void) | null | undefined;
133
+ let _nextSubscription: EmitterSubscription | undefined;
134
+
135
+ let _complete: ((snapshot: TaskSnapshot) => void) | null | undefined;
136
+ let _completeSubscription: EmitterSubscription | undefined;
137
+
138
+ const unsubscribe = () => {
139
+ if (_nextSubscription) {
140
+ _nextSubscription.remove();
141
+ }
142
+ if (_errorSubscription) {
143
+ _errorSubscription.remove();
144
+ }
145
+ if (_completeSubscription) {
146
+ _completeSubscription.remove();
147
+ }
148
+ };
149
+
150
+ if (isFunction(nextOrObserver)) {
151
+ _error = wrapErrorEventListener(error, unsubscribe);
152
+ _next = wrapSnapshotEventListener(task, nextOrObserver, null);
153
+ _complete = wrapSnapshotEventListener(task, complete, unsubscribe);
154
+ } else if (isObject(nextOrObserver)) {
155
+ const observer = nextOrObserver as StorageObserver<TaskSnapshot>;
156
+ _error = wrapErrorEventListener(observer.error, unsubscribe);
157
+ _next = wrapSnapshotEventListener(task, observer.next, null);
158
+ _complete = wrapSnapshotEventListener(task, observer.complete, unsubscribe);
159
+ } else if (isNull(nextOrObserver)) {
160
+ _error = wrapErrorEventListener(error, unsubscribe);
161
+ _complete = wrapSnapshotEventListener(task, complete, unsubscribe);
162
+ } else {
163
+ throw new Error(
164
+ "firebase.storage.StorageTask.on(*, _) 'nextOrObserver' must be a Function, an Object or Null.",
165
+ );
166
+ }
167
+
168
+ if (_next) {
169
+ _nextSubscription = addTaskEventListener(task, TaskEvent.STATE_CHANGED, _next);
170
+ }
171
+
172
+ if (_error) {
173
+ _errorSubscription = addTaskEventListener(task, 'failure', _error);
174
+ }
175
+
176
+ if (_complete) {
177
+ _completeSubscription = addTaskEventListener(task, 'success', _complete);
178
+ }
179
+
180
+ return unsubscribe;
181
+ }
182
+
183
+ export default class StorageTask {
184
+ _type: string;
185
+ _id: number;
186
+ _promise: Promise<TaskSnapshot> | null;
187
+ _ref: StorageReference;
188
+ _beginTask: (task: StorageTask) => Promise<TaskSnapshot>;
189
+ _storage: StorageInternal;
190
+ _snapshot: TaskSnapshot;
191
+
192
+ constructor(
193
+ type: string,
194
+ storageRef: StorageReference,
195
+ beginTaskFn: (task: StorageTask) => Promise<TaskSnapshot>,
196
+ ) {
197
+ this._type = type;
198
+ this._id = TASK_ID++;
199
+ this._promise = null;
200
+ this._ref = storageRef;
201
+ this._beginTask = beginTaskFn;
202
+ this._storage = (storageRef as StorageReferenceInternal)._storage;
203
+ this._snapshot = {
204
+ bytesTransferred: 0,
205
+ totalBytes: 0,
206
+ state: 'running',
207
+ metadata: createEmptyMetadata(storageRef),
208
+ task: this as Task,
209
+ ref: storageRef,
210
+ };
211
+ }
212
+
213
+ /**
214
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#then
215
+ */
216
+ get then(): (
217
+ onFulfilled?: ((snapshot: TaskSnapshot) => TaskSnapshot) | null,
218
+ onRejected?: ((error: ReactNativeFirebase.NativeFirebaseError) => any) | null,
219
+ ) => Promise<TaskSnapshot> {
220
+ if (!this._promise) {
221
+ this._promise = this._beginTask(this);
222
+ }
223
+
224
+ const promise = this._promise;
225
+ return (
226
+ onFulfilled?: ((snapshot: TaskSnapshot) => any) | null,
227
+ onRejected?: ((error: ReactNativeFirebase.NativeFirebaseError) => any) | null,
228
+ ) => {
229
+ return new Promise((resolve, reject) => {
230
+ promise
231
+ .then((response: any) => {
232
+ this._snapshot = {
233
+ ...response,
234
+ ref: this._ref,
235
+ task: this as Task,
236
+ state: response?.state ?? this._snapshot.state,
237
+ metadata: response?.metadata ? response.metadata : createEmptyMetadata(this._ref),
238
+ } as TaskSnapshot;
239
+ if (onFulfilled) {
240
+ resolve(onFulfilled(this._snapshot!));
241
+ } else {
242
+ resolve(response);
243
+ }
244
+ })
245
+ .catch((error: ReactNativeFirebase.NativeFirebaseError) => {
246
+ if (onRejected) {
247
+ resolve(onRejected(error));
248
+ } else {
249
+ reject(error);
250
+ }
251
+ });
252
+ });
253
+ };
254
+ }
255
+
256
+ /**
257
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#catch
258
+ */
259
+ get catch(): (
260
+ onRejected: (error: ReactNativeFirebase.NativeFirebaseError) => any,
261
+ ) => Promise<any> {
262
+ if (!this._promise) {
263
+ this._promise = this._beginTask(this);
264
+ }
265
+ return this._promise!.catch.bind(this._promise);
266
+ }
267
+
268
+ get snapshot(): TaskSnapshot {
269
+ return this._snapshot;
270
+ }
271
+
272
+ // // NOT on Web SDK
273
+ // /**
274
+ // * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#finally
275
+ // */
276
+ // get finally() {
277
+ // if (!this._promise) this._promise = this._beginTask(this);
278
+ // return this._promise.finally.bind(this._promise);
279
+ // }
280
+
281
+ /**
282
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#on
283
+ */
284
+ on(event: TaskEventType): Subscribe<TaskSnapshot>;
285
+ on(
286
+ event: TaskEventType,
287
+ nextOrObserver?: StorageObserver<TaskSnapshot> | null | ((snapshot: TaskSnapshot) => unknown),
288
+ error?: ((error: ReactNativeFirebase.NativeFirebaseError) => unknown) | null,
289
+ complete?: (() => unknown) | null,
290
+ ): Unsubscribe;
291
+ on(
292
+ event: TaskEventType,
293
+ nextOrObserver?: StorageObserver<TaskSnapshot> | null | ((snapshot: TaskSnapshot) => unknown),
294
+ error?: ((error: ReactNativeFirebase.NativeFirebaseError) => unknown) | null,
295
+ complete?: (() => unknown) | null,
296
+ ): Unsubscribe | Subscribe<TaskSnapshot> {
297
+ if (event !== TaskEvent.STATE_CHANGED) {
298
+ throw new Error(
299
+ `firebase.storage.StorageTask.on event argument must be a string with a value of '${TaskEvent.STATE_CHANGED}'`,
300
+ );
301
+ }
302
+
303
+ if (!this._promise) {
304
+ this._promise = this._beginTask(this);
305
+ }
306
+
307
+ // if only event provided return the subscriber function
308
+ if (!nextOrObserver && !error && !complete) {
309
+ return ((...args: Parameters<Subscribe<TaskSnapshot>>) =>
310
+ subscribeToEvents(this, ...args)) as Subscribe<TaskSnapshot>;
311
+ }
312
+
313
+ return subscribeToEvents(this, nextOrObserver, error, complete);
314
+ }
315
+
316
+ /**
317
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#pause
318
+ */
319
+ pause(): Promise<boolean> {
320
+ return this._storage.native.setTaskStatus(this._id, 0);
321
+ }
322
+
323
+ /**
324
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#pause
325
+ */
326
+ resume(): Promise<boolean> {
327
+ return this._storage.native.setTaskStatus(this._id, 1);
328
+ }
329
+
330
+ /**
331
+ * @url https://firebase.google.com/docs/reference/js/firebase.storage.UploadTask#cancel
332
+ */
333
+ cancel(): Promise<boolean> {
334
+ return this._storage.native.setTaskStatus(this._id, 2);
335
+ }
336
+ }