@react-native-firebase/app 20.0.0 → 20.2.0

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 (60) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/android/src/reactnative/java/io/invertase/firebase/app/ReactNativeFirebaseVersion.java +1 -1
  3. package/ios/RNFBApp/RNFBVersion.m +1 -1
  4. package/lib/common/index.js +2 -0
  5. package/lib/index.d.ts +1 -0
  6. package/lib/internal/RNFBNativeEventEmitter.js +31 -6
  7. package/lib/internal/nativeModule.android.js +2 -0
  8. package/lib/internal/nativeModule.ios.js +2 -0
  9. package/lib/internal/nativeModule.js +4 -0
  10. package/lib/internal/nativeModuleAndroidIos.js +45 -0
  11. package/lib/internal/nativeModuleWeb.js +48 -0
  12. package/lib/internal/registry/app.js +2 -1
  13. package/lib/internal/registry/nativeModule.js +11 -15
  14. package/lib/internal/web/RNFBAppModule.js +266 -0
  15. package/lib/internal/web/firebaseApp.js +3 -0
  16. package/lib/internal/web/firebaseAppCheck.js +6 -0
  17. package/lib/internal/web/firebaseAuth.js +4 -0
  18. package/lib/internal/web/firebaseDatabase.js +4 -0
  19. package/lib/internal/web/firebaseFirestore.js +4 -0
  20. package/lib/internal/web/firebaseFunctions.js +4 -0
  21. package/lib/internal/web/firebaseInstallations.js +6 -0
  22. package/lib/internal/web/firebaseRemoteConfig.js +6 -0
  23. package/lib/internal/web/firebaseStorage.js +4 -0
  24. package/lib/internal/web/memidb/FDBCursor.js +503 -0
  25. package/lib/internal/web/memidb/FDBCursorWithValue.js +11 -0
  26. package/lib/internal/web/memidb/FDBDatabase.js +172 -0
  27. package/lib/internal/web/memidb/FDBFactory.js +256 -0
  28. package/lib/internal/web/memidb/FDBIndex.js +187 -0
  29. package/lib/internal/web/memidb/FDBKeyRange.js +71 -0
  30. package/lib/internal/web/memidb/FDBObjectStore.js +411 -0
  31. package/lib/internal/web/memidb/FDBOpenDBRequest.js +9 -0
  32. package/lib/internal/web/memidb/FDBRequest.js +33 -0
  33. package/lib/internal/web/memidb/FDBTransaction.js +216 -0
  34. package/lib/internal/web/memidb/FDBVersionChangeEvent.js +12 -0
  35. package/lib/internal/web/memidb/LICENSE +208 -0
  36. package/lib/internal/web/memidb/index.js +39 -0
  37. package/lib/internal/web/memidb/lib/Database.js +32 -0
  38. package/lib/internal/web/memidb/lib/FakeDOMStringList.js +72 -0
  39. package/lib/internal/web/memidb/lib/FakeEvent.js +38 -0
  40. package/lib/internal/web/memidb/lib/FakeEventTarget.js +110 -0
  41. package/lib/internal/web/memidb/lib/Index.js +157 -0
  42. package/lib/internal/web/memidb/lib/KeyGenerator.js +22 -0
  43. package/lib/internal/web/memidb/lib/ObjectStore.js +172 -0
  44. package/lib/internal/web/memidb/lib/RecordStore.js +141 -0
  45. package/lib/internal/web/memidb/lib/binarySearch.js +78 -0
  46. package/lib/internal/web/memidb/lib/canInjectKey.js +25 -0
  47. package/lib/internal/web/memidb/lib/cmp.js +77 -0
  48. package/lib/internal/web/memidb/lib/enforceRange.js +13 -0
  49. package/lib/internal/web/memidb/lib/errors.js +69 -0
  50. package/lib/internal/web/memidb/lib/extractKey.js +39 -0
  51. package/lib/internal/web/memidb/lib/scheduling.js +30 -0
  52. package/lib/internal/web/memidb/lib/types.js +1 -0
  53. package/lib/internal/web/memidb/lib/validateKeyPath.js +54 -0
  54. package/lib/internal/web/memidb/lib/valueToKey.js +62 -0
  55. package/lib/internal/web/memidb/lib/valueToKeyRange.js +19 -0
  56. package/lib/internal/web/structuredClone/index.js +222 -0
  57. package/lib/internal/web/utils.js +35 -0
  58. package/lib/utils/UtilsStatics.js +3 -2
  59. package/lib/version.js +1 -1
  60. package/package.json +9 -8
@@ -0,0 +1,503 @@
1
+ import FDBKeyRange from './FDBKeyRange.js';
2
+ import FDBObjectStore from './FDBObjectStore.js';
3
+ import cmp from './lib/cmp.js';
4
+ import {
5
+ DataError,
6
+ InvalidAccessError,
7
+ InvalidStateError,
8
+ ReadOnlyError,
9
+ TransactionInactiveError,
10
+ } from './lib/errors.js';
11
+ import extractKey from './lib/extractKey.js';
12
+ import valueToKey from './lib/valueToKey.js';
13
+ const getEffectiveObjectStore = cursor => {
14
+ if (cursor.source instanceof FDBObjectStore) {
15
+ return cursor.source;
16
+ }
17
+ return cursor.source.objectStore;
18
+ };
19
+
20
+ // This takes a key range, a list of lower bounds, and a list of upper bounds and combines them all into a single key
21
+ // range. It does not handle gt/gte distinctions, because it doesn't really matter much anyway, since for next/prev
22
+ // cursor iteration it'd also have to look at values to be precise, which would be complicated. This should get us 99%
23
+ // of the way there.
24
+ const makeKeyRange = (range, lowers, uppers) => {
25
+ // Start with bounds from range
26
+ let lower = range !== undefined ? range.lower : undefined;
27
+ let upper = range !== undefined ? range.upper : undefined;
28
+
29
+ // Augment with values from lowers and uppers
30
+ for (const lowerTemp of lowers) {
31
+ if (lowerTemp === undefined) {
32
+ continue;
33
+ }
34
+ if (lower === undefined || cmp(lower, lowerTemp) === 1) {
35
+ lower = lowerTemp;
36
+ }
37
+ }
38
+ for (const upperTemp of uppers) {
39
+ if (upperTemp === undefined) {
40
+ continue;
41
+ }
42
+ if (upper === undefined || cmp(upper, upperTemp) === -1) {
43
+ upper = upperTemp;
44
+ }
45
+ }
46
+ if (lower !== undefined && upper !== undefined) {
47
+ return FDBKeyRange.bound(lower, upper);
48
+ }
49
+ if (lower !== undefined) {
50
+ return FDBKeyRange.lowerBound(lower);
51
+ }
52
+ if (upper !== undefined) {
53
+ return FDBKeyRange.upperBound(upper);
54
+ }
55
+ };
56
+
57
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#cursor
58
+ class FDBCursor {
59
+ _gotValue = false;
60
+ _position = undefined; // Key of previously returned record
61
+ _objectStorePosition = undefined;
62
+ _keyOnly = false;
63
+ _key = undefined;
64
+ _primaryKey = undefined;
65
+ constructor(source, range, direction = 'next', request, keyOnly = false) {
66
+ this._range = range;
67
+ this._source = source;
68
+ this._direction = direction;
69
+ this._request = request;
70
+ this._keyOnly = keyOnly;
71
+ }
72
+
73
+ // Read only properties
74
+ get source() {
75
+ return this._source;
76
+ }
77
+ set source(val) {
78
+ /* For babel */
79
+ }
80
+ get request() {
81
+ return this._request;
82
+ }
83
+ set request(val) {
84
+ /* For babel */
85
+ }
86
+ get direction() {
87
+ return this._direction;
88
+ }
89
+ set direction(val) {
90
+ /* For babel */
91
+ }
92
+ get key() {
93
+ return this._key;
94
+ }
95
+ set key(val) {
96
+ /* For babel */
97
+ }
98
+ get primaryKey() {
99
+ return this._primaryKey;
100
+ }
101
+ set primaryKey(val) {
102
+ /* For babel */
103
+ }
104
+
105
+ // https://w3c.github.io/IndexedDB/#iterate-a-cursor
106
+ _iterate(key, primaryKey) {
107
+ const sourceIsObjectStore = this.source instanceof FDBObjectStore;
108
+
109
+ // Can't use sourceIsObjectStore because TypeScript
110
+ const records =
111
+ this.source instanceof FDBObjectStore
112
+ ? this.source._rawObjectStore.records
113
+ : this.source._rawIndex.records;
114
+ let foundRecord;
115
+ if (this.direction === 'next') {
116
+ const range = makeKeyRange(this._range, [key, this._position], []);
117
+ for (const record of records.values(range)) {
118
+ const cmpResultKey = key !== undefined ? cmp(record.key, key) : undefined;
119
+ const cmpResultPosition =
120
+ this._position !== undefined ? cmp(record.key, this._position) : undefined;
121
+ if (key !== undefined) {
122
+ if (cmpResultKey === -1) {
123
+ continue;
124
+ }
125
+ }
126
+ if (primaryKey !== undefined) {
127
+ if (cmpResultKey === -1) {
128
+ continue;
129
+ }
130
+ const cmpResultPrimaryKey = cmp(record.value, primaryKey);
131
+ if (cmpResultKey === 0 && cmpResultPrimaryKey === -1) {
132
+ continue;
133
+ }
134
+ }
135
+ if (this._position !== undefined && sourceIsObjectStore) {
136
+ if (cmpResultPosition !== 1) {
137
+ continue;
138
+ }
139
+ }
140
+ if (this._position !== undefined && !sourceIsObjectStore) {
141
+ if (cmpResultPosition === -1) {
142
+ continue;
143
+ }
144
+ if (cmpResultPosition === 0 && cmp(record.value, this._objectStorePosition) !== 1) {
145
+ continue;
146
+ }
147
+ }
148
+ if (this._range !== undefined) {
149
+ if (!this._range.includes(record.key)) {
150
+ continue;
151
+ }
152
+ }
153
+ foundRecord = record;
154
+ break;
155
+ }
156
+ } else if (this.direction === 'nextunique') {
157
+ // This could be done without iterating, if the range was defined slightly better (to handle gt/gte cases).
158
+ // But the performance difference should be small, and that wouldn't work anyway for directions where the
159
+ // value needs to be used (like next and prev).
160
+ const range = makeKeyRange(this._range, [key, this._position], []);
161
+ for (const record of records.values(range)) {
162
+ if (key !== undefined) {
163
+ if (cmp(record.key, key) === -1) {
164
+ continue;
165
+ }
166
+ }
167
+ if (this._position !== undefined) {
168
+ if (cmp(record.key, this._position) !== 1) {
169
+ continue;
170
+ }
171
+ }
172
+ if (this._range !== undefined) {
173
+ if (!this._range.includes(record.key)) {
174
+ continue;
175
+ }
176
+ }
177
+ foundRecord = record;
178
+ break;
179
+ }
180
+ } else if (this.direction === 'prev') {
181
+ const range = makeKeyRange(this._range, [], [key, this._position]);
182
+ for (const record of records.values(range, 'prev')) {
183
+ const cmpResultKey = key !== undefined ? cmp(record.key, key) : undefined;
184
+ const cmpResultPosition =
185
+ this._position !== undefined ? cmp(record.key, this._position) : undefined;
186
+ if (key !== undefined) {
187
+ if (cmpResultKey === 1) {
188
+ continue;
189
+ }
190
+ }
191
+ if (primaryKey !== undefined) {
192
+ if (cmpResultKey === 1) {
193
+ continue;
194
+ }
195
+ const cmpResultPrimaryKey = cmp(record.value, primaryKey);
196
+ if (cmpResultKey === 0 && cmpResultPrimaryKey === 1) {
197
+ continue;
198
+ }
199
+ }
200
+ if (this._position !== undefined && sourceIsObjectStore) {
201
+ if (cmpResultPosition !== -1) {
202
+ continue;
203
+ }
204
+ }
205
+ if (this._position !== undefined && !sourceIsObjectStore) {
206
+ if (cmpResultPosition === 1) {
207
+ continue;
208
+ }
209
+ if (cmpResultPosition === 0 && cmp(record.value, this._objectStorePosition) !== -1) {
210
+ continue;
211
+ }
212
+ }
213
+ if (this._range !== undefined) {
214
+ if (!this._range.includes(record.key)) {
215
+ continue;
216
+ }
217
+ }
218
+ foundRecord = record;
219
+ break;
220
+ }
221
+ } else if (this.direction === 'prevunique') {
222
+ let tempRecord;
223
+ const range = makeKeyRange(this._range, [], [key, this._position]);
224
+ for (const record of records.values(range, 'prev')) {
225
+ if (key !== undefined) {
226
+ if (cmp(record.key, key) === 1) {
227
+ continue;
228
+ }
229
+ }
230
+ if (this._position !== undefined) {
231
+ if (cmp(record.key, this._position) !== -1) {
232
+ continue;
233
+ }
234
+ }
235
+ if (this._range !== undefined) {
236
+ if (!this._range.includes(record.key)) {
237
+ continue;
238
+ }
239
+ }
240
+ tempRecord = record;
241
+ break;
242
+ }
243
+ if (tempRecord) {
244
+ foundRecord = records.get(tempRecord.key);
245
+ }
246
+ }
247
+ let result;
248
+ if (!foundRecord) {
249
+ this._key = undefined;
250
+ if (!sourceIsObjectStore) {
251
+ this._objectStorePosition = undefined;
252
+ }
253
+
254
+ // "this instanceof FDBCursorWithValue" would be better and not require (this as any), but causes runtime
255
+ // error due to circular dependency.
256
+ if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
257
+ this.value = undefined;
258
+ }
259
+ result = null;
260
+ } else {
261
+ this._position = foundRecord.key;
262
+ if (!sourceIsObjectStore) {
263
+ this._objectStorePosition = foundRecord.value;
264
+ }
265
+ this._key = foundRecord.key;
266
+ if (sourceIsObjectStore) {
267
+ this._primaryKey = structuredClone(foundRecord.key);
268
+ if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
269
+ this.value = structuredClone(foundRecord.value);
270
+ }
271
+ } else {
272
+ this._primaryKey = structuredClone(foundRecord.value);
273
+ if (!this._keyOnly && this.toString() === '[object IDBCursorWithValue]') {
274
+ if (this.source instanceof FDBObjectStore) {
275
+ // Can't use sourceIsObjectStore because TypeScript
276
+ throw new Error('This should never happen');
277
+ }
278
+ const value = this.source.objectStore._rawObjectStore.getValue(foundRecord.value);
279
+ this.value = structuredClone(value);
280
+ }
281
+ }
282
+ this._gotValue = true;
283
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
284
+ result = this;
285
+ }
286
+ return result;
287
+ }
288
+
289
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-update-IDBRequest-any-value
290
+ update(value) {
291
+ if (value === undefined) {
292
+ throw new TypeError();
293
+ }
294
+ const effectiveObjectStore = getEffectiveObjectStore(this);
295
+ const effectiveKey = Object.hasOwn(this.source, '_rawIndex') ? this.primaryKey : this._position;
296
+ const transaction = effectiveObjectStore.transaction;
297
+ if (transaction._state !== 'active') {
298
+ throw new TransactionInactiveError();
299
+ }
300
+ if (transaction.mode === 'readonly') {
301
+ throw new ReadOnlyError();
302
+ }
303
+ if (effectiveObjectStore._rawObjectStore.deleted) {
304
+ throw new InvalidStateError();
305
+ }
306
+ if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
307
+ throw new InvalidStateError();
308
+ }
309
+ if (!this._gotValue || !Object.hasOwn(this, 'value')) {
310
+ throw new InvalidStateError();
311
+ }
312
+ const clone = structuredClone(value);
313
+ if (effectiveObjectStore.keyPath !== null) {
314
+ let tempKey;
315
+ try {
316
+ tempKey = extractKey(effectiveObjectStore.keyPath, clone);
317
+ } catch (err) {
318
+ /* Handled immediately below */
319
+ }
320
+ if (cmp(tempKey, effectiveKey) !== 0) {
321
+ throw new DataError();
322
+ }
323
+ }
324
+ const record = {
325
+ key: effectiveKey,
326
+ value: clone,
327
+ };
328
+ return transaction._execRequestAsync({
329
+ operation: effectiveObjectStore._rawObjectStore.storeRecord.bind(
330
+ effectiveObjectStore._rawObjectStore,
331
+ record,
332
+ false,
333
+ transaction._rollbackLog,
334
+ ),
335
+ source: this,
336
+ });
337
+ }
338
+
339
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-advance-void-unsigned-long-count
340
+ advance(count) {
341
+ if (!Number.isInteger(count) || count <= 0) {
342
+ throw new TypeError();
343
+ }
344
+ const effectiveObjectStore = getEffectiveObjectStore(this);
345
+ const transaction = effectiveObjectStore.transaction;
346
+ if (transaction._state !== 'active') {
347
+ throw new TransactionInactiveError();
348
+ }
349
+ if (effectiveObjectStore._rawObjectStore.deleted) {
350
+ throw new InvalidStateError();
351
+ }
352
+ if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
353
+ throw new InvalidStateError();
354
+ }
355
+ if (!this._gotValue) {
356
+ throw new InvalidStateError();
357
+ }
358
+ if (this._request) {
359
+ this._request.readyState = 'pending';
360
+ }
361
+ transaction._execRequestAsync({
362
+ operation: () => {
363
+ let result;
364
+ for (let i = 0; i < count; i++) {
365
+ result = this._iterate();
366
+
367
+ // Not sure why this is needed
368
+ if (!result) {
369
+ break;
370
+ }
371
+ }
372
+ return result;
373
+ },
374
+ request: this._request,
375
+ source: this.source,
376
+ });
377
+ this._gotValue = false;
378
+ }
379
+
380
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#widl-IDBCursor-continue-void-any-key
381
+ continue(key) {
382
+ const effectiveObjectStore = getEffectiveObjectStore(this);
383
+ const transaction = effectiveObjectStore.transaction;
384
+ if (transaction._state !== 'active') {
385
+ throw new TransactionInactiveError();
386
+ }
387
+ if (effectiveObjectStore._rawObjectStore.deleted) {
388
+ throw new InvalidStateError();
389
+ }
390
+ if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
391
+ throw new InvalidStateError();
392
+ }
393
+ if (!this._gotValue) {
394
+ throw new InvalidStateError();
395
+ }
396
+ if (key !== undefined) {
397
+ key = valueToKey(key);
398
+ const cmpResult = cmp(key, this._position);
399
+ if (
400
+ (cmpResult <= 0 && (this.direction === 'next' || this.direction === 'nextunique')) ||
401
+ (cmpResult >= 0 && (this.direction === 'prev' || this.direction === 'prevunique'))
402
+ ) {
403
+ throw new DataError();
404
+ }
405
+ }
406
+ if (this._request) {
407
+ this._request.readyState = 'pending';
408
+ }
409
+ transaction._execRequestAsync({
410
+ operation: this._iterate.bind(this, key),
411
+ request: this._request,
412
+ source: this.source,
413
+ });
414
+ this._gotValue = false;
415
+ }
416
+
417
+ // hthttps://w3c.github.io/IndexedDB/#dom-idbcursor-continueprimarykey
418
+ continuePrimaryKey(key, primaryKey) {
419
+ const effectiveObjectStore = getEffectiveObjectStore(this);
420
+ const transaction = effectiveObjectStore.transaction;
421
+ if (transaction._state !== 'active') {
422
+ throw new TransactionInactiveError();
423
+ }
424
+ if (effectiveObjectStore._rawObjectStore.deleted) {
425
+ throw new InvalidStateError();
426
+ }
427
+ if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
428
+ throw new InvalidStateError();
429
+ }
430
+ if (
431
+ this.source instanceof FDBObjectStore ||
432
+ (this.direction !== 'next' && this.direction !== 'prev')
433
+ ) {
434
+ throw new InvalidAccessError();
435
+ }
436
+ if (!this._gotValue) {
437
+ throw new InvalidStateError();
438
+ }
439
+
440
+ // Not sure about this
441
+ if (key === undefined || primaryKey === undefined) {
442
+ throw new DataError();
443
+ }
444
+ key = valueToKey(key);
445
+ const cmpResult = cmp(key, this._position);
446
+ if (
447
+ (cmpResult === -1 && this.direction === 'next') ||
448
+ (cmpResult === 1 && this.direction === 'prev')
449
+ ) {
450
+ throw new DataError();
451
+ }
452
+ const cmpResult2 = cmp(primaryKey, this._objectStorePosition);
453
+ if (cmpResult === 0) {
454
+ if (
455
+ (cmpResult2 <= 0 && this.direction === 'next') ||
456
+ (cmpResult2 >= 0 && this.direction === 'prev')
457
+ ) {
458
+ throw new DataError();
459
+ }
460
+ }
461
+ if (this._request) {
462
+ this._request.readyState = 'pending';
463
+ }
464
+ transaction._execRequestAsync({
465
+ operation: this._iterate.bind(this, key, primaryKey),
466
+ request: this._request,
467
+ source: this.source,
468
+ });
469
+ this._gotValue = false;
470
+ }
471
+ delete() {
472
+ const effectiveObjectStore = getEffectiveObjectStore(this);
473
+ const effectiveKey = Object.hasOwn(this.source, '_rawIndex') ? this.primaryKey : this._position;
474
+ const transaction = effectiveObjectStore.transaction;
475
+ if (transaction._state !== 'active') {
476
+ throw new TransactionInactiveError();
477
+ }
478
+ if (transaction.mode === 'readonly') {
479
+ throw new ReadOnlyError();
480
+ }
481
+ if (effectiveObjectStore._rawObjectStore.deleted) {
482
+ throw new InvalidStateError();
483
+ }
484
+ if (!(this.source instanceof FDBObjectStore) && this.source._rawIndex.deleted) {
485
+ throw new InvalidStateError();
486
+ }
487
+ if (!this._gotValue || !Object.hasOwn(this, 'value')) {
488
+ throw new InvalidStateError();
489
+ }
490
+ return transaction._execRequestAsync({
491
+ operation: effectiveObjectStore._rawObjectStore.deleteRecord.bind(
492
+ effectiveObjectStore._rawObjectStore,
493
+ effectiveKey,
494
+ transaction._rollbackLog,
495
+ ),
496
+ source: this,
497
+ });
498
+ }
499
+ toString() {
500
+ return '[object IDBCursor]';
501
+ }
502
+ }
503
+ export default FDBCursor;
@@ -0,0 +1,11 @@
1
+ import FDBCursor from './FDBCursor.js';
2
+ class FDBCursorWithValue extends FDBCursor {
3
+ value = undefined;
4
+ constructor(source, range, direction, request) {
5
+ super(source, range, direction, request);
6
+ }
7
+ toString() {
8
+ return '[object IDBCursorWithValue]';
9
+ }
10
+ }
11
+ export default FDBCursorWithValue;
@@ -0,0 +1,172 @@
1
+ import FDBTransaction from './FDBTransaction.js';
2
+ import {
3
+ ConstraintError,
4
+ InvalidAccessError,
5
+ InvalidStateError,
6
+ NotFoundError,
7
+ TransactionInactiveError,
8
+ } from './lib/errors.js';
9
+ import FakeDOMStringList from './lib/FakeDOMStringList.js';
10
+ import FakeEventTarget from './lib/FakeEventTarget.js';
11
+ import ObjectStore from './lib/ObjectStore.js';
12
+ import { queueTask } from './lib/scheduling.js';
13
+ import validateKeyPath from './lib/validateKeyPath.js';
14
+ const confirmActiveVersionchangeTransaction = database => {
15
+ if (!database._runningVersionchangeTransaction) {
16
+ throw new InvalidStateError();
17
+ }
18
+
19
+ // Find the latest versionchange transaction
20
+ const transactions = database._rawDatabase.transactions.filter(tx => {
21
+ return tx.mode === 'versionchange';
22
+ });
23
+ const transaction = transactions[transactions.length - 1];
24
+ if (!transaction || transaction._state === 'finished') {
25
+ throw new InvalidStateError();
26
+ }
27
+ if (transaction._state !== 'active') {
28
+ throw new TransactionInactiveError();
29
+ }
30
+ return transaction;
31
+ };
32
+
33
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-closing-steps
34
+ const closeConnection = connection => {
35
+ connection._closePending = true;
36
+ const transactionsComplete = connection._rawDatabase.transactions.every(transaction => {
37
+ return transaction._state === 'finished';
38
+ });
39
+ if (transactionsComplete) {
40
+ connection._closed = true;
41
+ connection._rawDatabase.connections = connection._rawDatabase.connections.filter(
42
+ otherConnection => {
43
+ return connection !== otherConnection;
44
+ },
45
+ );
46
+ } else {
47
+ queueTask(() => {
48
+ closeConnection(connection);
49
+ });
50
+ }
51
+ };
52
+
53
+ // http://www.w3.org/TR/2015/REC-IndexedDB-20150108/#database-interface
54
+ class FDBDatabase extends FakeEventTarget {
55
+ _closePending = false;
56
+ _closed = false;
57
+ _runningVersionchangeTransaction = false;
58
+ constructor(rawDatabase) {
59
+ super();
60
+ this._rawDatabase = rawDatabase;
61
+ this._rawDatabase.connections.push(this);
62
+ this.name = rawDatabase.name;
63
+ this.version = rawDatabase.version;
64
+ this.objectStoreNames = new FakeDOMStringList(
65
+ ...Array.from(rawDatabase.rawObjectStores.keys()).sort(),
66
+ );
67
+ }
68
+
69
+ // http://w3c.github.io/IndexedDB/#dom-idbdatabase-createobjectstore
70
+ createObjectStore(name, options = {}) {
71
+ if (name === undefined) {
72
+ throw new TypeError();
73
+ }
74
+ const transaction = confirmActiveVersionchangeTransaction(this);
75
+ const keyPath = options !== null && options.keyPath !== undefined ? options.keyPath : null;
76
+ const autoIncrement =
77
+ options !== null && options.autoIncrement !== undefined ? options.autoIncrement : false;
78
+ if (keyPath !== null) {
79
+ validateKeyPath(keyPath);
80
+ }
81
+ if (this._rawDatabase.rawObjectStores.has(name)) {
82
+ throw new ConstraintError();
83
+ }
84
+ if (autoIncrement && (keyPath === '' || Array.isArray(keyPath))) {
85
+ throw new InvalidAccessError();
86
+ }
87
+ const objectStoreNames = [...this.objectStoreNames];
88
+ transaction._rollbackLog.push(() => {
89
+ const objectStore = this._rawDatabase.rawObjectStores.get(name);
90
+ if (objectStore) {
91
+ objectStore.deleted = true;
92
+ }
93
+ this.objectStoreNames = new FakeDOMStringList(...objectStoreNames);
94
+ transaction._scope.delete(name);
95
+ this._rawDatabase.rawObjectStores.delete(name);
96
+ });
97
+ const rawObjectStore = new ObjectStore(this._rawDatabase, name, keyPath, autoIncrement);
98
+ this.objectStoreNames._push(name);
99
+ this.objectStoreNames._sort();
100
+ transaction._scope.add(name);
101
+ this._rawDatabase.rawObjectStores.set(name, rawObjectStore);
102
+ transaction.objectStoreNames = new FakeDOMStringList(...this.objectStoreNames);
103
+ return transaction.objectStore(name);
104
+ }
105
+ deleteObjectStore(name) {
106
+ if (name === undefined) {
107
+ throw new TypeError();
108
+ }
109
+ const transaction = confirmActiveVersionchangeTransaction(this);
110
+ const store = this._rawDatabase.rawObjectStores.get(name);
111
+ if (store === undefined) {
112
+ throw new NotFoundError();
113
+ }
114
+ this.objectStoreNames = new FakeDOMStringList(
115
+ ...Array.from(this.objectStoreNames).filter(objectStoreName => {
116
+ return objectStoreName !== name;
117
+ }),
118
+ );
119
+ transaction.objectStoreNames = new FakeDOMStringList(...this.objectStoreNames);
120
+ transaction._rollbackLog.push(() => {
121
+ store.deleted = false;
122
+ this._rawDatabase.rawObjectStores.set(name, store);
123
+ this.objectStoreNames._push(name);
124
+ this.objectStoreNames._sort();
125
+ });
126
+ store.deleted = true;
127
+ this._rawDatabase.rawObjectStores.delete(name);
128
+ transaction._objectStoresCache.delete(name);
129
+ }
130
+ transaction(storeNames, mode) {
131
+ mode = mode !== undefined ? mode : 'readonly';
132
+ if (mode !== 'readonly' && mode !== 'readwrite' && mode !== 'versionchange') {
133
+ throw new TypeError('Invalid mode: ' + mode);
134
+ }
135
+ const hasActiveVersionchange = this._rawDatabase.transactions.some(transaction => {
136
+ return (
137
+ transaction._state === 'active' &&
138
+ transaction.mode === 'versionchange' &&
139
+ transaction.db === this
140
+ );
141
+ });
142
+ if (hasActiveVersionchange) {
143
+ throw new InvalidStateError();
144
+ }
145
+ if (this._closePending) {
146
+ throw new InvalidStateError();
147
+ }
148
+ if (!Array.isArray(storeNames)) {
149
+ storeNames = [storeNames];
150
+ }
151
+ if (storeNames.length === 0 && mode !== 'versionchange') {
152
+ throw new InvalidAccessError();
153
+ }
154
+ for (const storeName of storeNames) {
155
+ if (!this.objectStoreNames.contains(storeName)) {
156
+ throw new NotFoundError('No objectStore named ' + storeName + ' in this database');
157
+ }
158
+ }
159
+ const tx = new FDBTransaction(storeNames, mode, this);
160
+ this._rawDatabase.transactions.push(tx);
161
+ this._rawDatabase.processTransactions(); // See if can start right away (async)
162
+
163
+ return tx;
164
+ }
165
+ close() {
166
+ closeConnection(this);
167
+ }
168
+ toString() {
169
+ return '[object IDBDatabase]';
170
+ }
171
+ }
172
+ export default FDBDatabase;