react-native-onyx 3.0.55 → 3.0.57
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.
|
@@ -34,25 +34,39 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
const IDB = __importStar(require("idb-keyval"));
|
|
37
|
-
const
|
|
37
|
+
const Logger = __importStar(require("../../../Logger"));
|
|
38
38
|
// This is a copy of the createStore function from idb-keyval, we need a custom implementation
|
|
39
39
|
// because we need to create the database manually in order to ensure that the store exists before we use it.
|
|
40
40
|
// If the store does not exist, idb-keyval will throw an error
|
|
41
41
|
// source: https://github.com/jakearchibald/idb-keyval/blob/9d19315b4a83897df1e0193dccdc29f78466a0f3/src/index.ts#L12
|
|
42
42
|
function createStore(dbName, storeName) {
|
|
43
43
|
let dbp;
|
|
44
|
+
const attachHandlers = (db) => {
|
|
45
|
+
// Browsers may close idle IDB connections at any time, especially Safari.
|
|
46
|
+
// We clear the cached promise so the next operation opens a fresh connection.
|
|
47
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/close_event
|
|
48
|
+
// eslint-disable-next-line no-param-reassign
|
|
49
|
+
db.onclose = () => {
|
|
50
|
+
Logger.logInfo('IDB connection closed by browser', { dbName, storeName });
|
|
51
|
+
dbp = undefined;
|
|
52
|
+
};
|
|
53
|
+
// When another tab triggers a DB version upgrade, we must close the connection
|
|
54
|
+
// to unblock the upgrade; otherwise the other tab's open request hangs indefinitely.
|
|
55
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/IDBDatabase/versionchange_event
|
|
56
|
+
// eslint-disable-next-line no-param-reassign
|
|
57
|
+
db.onversionchange = () => {
|
|
58
|
+
Logger.logInfo('IDB connection closing due to version change', { dbName, storeName });
|
|
59
|
+
db.close();
|
|
60
|
+
dbp = undefined;
|
|
61
|
+
};
|
|
62
|
+
};
|
|
44
63
|
const getDB = () => {
|
|
45
64
|
if (dbp)
|
|
46
65
|
return dbp;
|
|
47
66
|
const request = indexedDB.open(dbName);
|
|
48
67
|
request.onupgradeneeded = () => request.result.createObjectStore(storeName);
|
|
49
68
|
dbp = IDB.promisifyRequest(request);
|
|
50
|
-
dbp.then(
|
|
51
|
-
// It seems like Safari sometimes likes to just close the connection.
|
|
52
|
-
// It's supposed to fire this event when that happens. Let's hope it does!
|
|
53
|
-
// eslint-disable-next-line no-param-reassign
|
|
54
|
-
db.onclose = () => (dbp = undefined);
|
|
55
|
-
},
|
|
69
|
+
dbp.then(attachHandlers,
|
|
56
70
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
57
71
|
() => { });
|
|
58
72
|
return dbp;
|
|
@@ -63,7 +77,7 @@ function createStore(dbName, storeName) {
|
|
|
63
77
|
if (db.objectStoreNames.contains(storeName)) {
|
|
64
78
|
return db;
|
|
65
79
|
}
|
|
66
|
-
|
|
80
|
+
Logger.logInfo(`Store ${storeName} does not exist in database ${dbName}.`);
|
|
67
81
|
const nextVersion = db.version + 1;
|
|
68
82
|
db.close();
|
|
69
83
|
const request = indexedDB.open(dbName, nextVersion);
|
|
@@ -72,14 +86,34 @@ function createStore(dbName, storeName) {
|
|
|
72
86
|
if (updatedDatabase.objectStoreNames.contains(storeName)) {
|
|
73
87
|
return;
|
|
74
88
|
}
|
|
75
|
-
|
|
89
|
+
Logger.logInfo(`Creating store ${storeName} in database ${dbName}.`);
|
|
76
90
|
updatedDatabase.createObjectStore(storeName);
|
|
77
91
|
};
|
|
78
92
|
dbp = IDB.promisifyRequest(request);
|
|
93
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
94
|
+
dbp.then(attachHandlers, () => { });
|
|
79
95
|
return dbp;
|
|
80
96
|
};
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
97
|
+
function executeTransaction(txMode, callback) {
|
|
98
|
+
return getDB()
|
|
99
|
+
.then(verifyStoreExists)
|
|
100
|
+
.then((db) => callback(db.transaction(storeName, txMode).objectStore(storeName)));
|
|
101
|
+
}
|
|
102
|
+
// If the connection was closed between getDB() resolving and db.transaction() executing,
|
|
103
|
+
// the transaction throws InvalidStateError. We catch it and retry once with a fresh connection.
|
|
104
|
+
return (txMode, callback) => executeTransaction(txMode, callback).catch((error) => {
|
|
105
|
+
if (error instanceof DOMException && error.name === 'InvalidStateError') {
|
|
106
|
+
Logger.logAlert('IDB InvalidStateError, retrying with fresh connection', {
|
|
107
|
+
dbName,
|
|
108
|
+
storeName,
|
|
109
|
+
txMode,
|
|
110
|
+
errorMessage: error.message,
|
|
111
|
+
});
|
|
112
|
+
dbp = undefined;
|
|
113
|
+
// Retry only once — this call is not wrapped, so if it also fails the error propagates normally.
|
|
114
|
+
return executeTransaction(txMode, callback);
|
|
115
|
+
}
|
|
116
|
+
throw error;
|
|
117
|
+
});
|
|
84
118
|
}
|
|
85
119
|
exports.default = createStore;
|