react-native-nitro-storage 0.5.6 → 0.5.8
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.
- package/README.md +267 -362
- package/ios/IOSStorageAdapterCpp.mm +126 -80
- package/lib/commonjs/index.js +119 -1599
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +83 -1550
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/shared.js +102 -0
- package/lib/commonjs/shared.js.map +1 -0
- package/lib/commonjs/storage-core.js +1505 -0
- package/lib/commonjs/storage-core.js.map +1 -0
- package/lib/module/index.js +111 -1591
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +69 -1536
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/shared.js +82 -0
- package/lib/module/shared.js.map +1 -0
- package/lib/module/storage-core.js +1501 -0
- package/lib/module/storage-core.js.map +1 -0
- package/lib/typescript/index.d.ts +30 -133
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +31 -129
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/shared.d.ts +96 -0
- package/lib/typescript/shared.d.ts.map +1 -0
- package/lib/typescript/storage-core.d.ts +157 -0
- package/lib/typescript/storage-core.d.ts.map +1 -0
- package/package.json +7 -3
- package/react-native-nitro-storage.podspec +4 -0
- package/src/index.ts +260 -2519
- package/src/index.web.ts +133 -2326
- package/src/shared.ts +249 -0
- package/src/storage-core.ts +2349 -0
package/lib/commonjs/index.js
CHANGED
|
@@ -27,10 +27,9 @@ Object.defineProperty(exports, "createIndexedDBBackend", {
|
|
|
27
27
|
return _indexeddbBackend.createIndexedDBBackend;
|
|
28
28
|
}
|
|
29
29
|
});
|
|
30
|
-
exports.createSecureAuthStorage =
|
|
31
|
-
exports.createStorageItem = createStorageItem;
|
|
30
|
+
exports.createStorageItem = exports.createSecureAuthStorage = void 0;
|
|
32
31
|
exports.flushWebStorageBackends = flushWebStorageBackends;
|
|
33
|
-
exports.getBatch =
|
|
32
|
+
exports.getBatch = void 0;
|
|
34
33
|
Object.defineProperty(exports, "getStorageErrorCode", {
|
|
35
34
|
enumerable: true,
|
|
36
35
|
get: function () {
|
|
@@ -39,18 +38,19 @@ Object.defineProperty(exports, "getStorageErrorCode", {
|
|
|
39
38
|
});
|
|
40
39
|
exports.getWebDiskStorageBackend = getWebDiskStorageBackend;
|
|
41
40
|
exports.getWebSecureStorageBackend = getWebSecureStorageBackend;
|
|
42
|
-
exports
|
|
41
|
+
Object.defineProperty(exports, "isKeychainLockedError", {
|
|
42
|
+
enumerable: true,
|
|
43
|
+
get: function () {
|
|
44
|
+
return _shared.isKeychainLockedError;
|
|
45
|
+
}
|
|
46
|
+
});
|
|
43
47
|
Object.defineProperty(exports, "migrateFromMMKV", {
|
|
44
48
|
enumerable: true,
|
|
45
49
|
get: function () {
|
|
46
50
|
return _migration.migrateFromMMKV;
|
|
47
51
|
}
|
|
48
52
|
});
|
|
49
|
-
exports.migrateToLatest =
|
|
50
|
-
exports.registerMigration = registerMigration;
|
|
51
|
-
exports.removeBatch = removeBatch;
|
|
52
|
-
exports.runTransaction = runTransaction;
|
|
53
|
-
exports.setBatch = setBatch;
|
|
53
|
+
exports.setBatch = exports.runTransaction = exports.removeBatch = exports.registerMigration = exports.migrateToLatest = void 0;
|
|
54
54
|
exports.setWebDiskStorageBackend = setWebDiskStorageBackend;
|
|
55
55
|
exports.setWebSecureStorageBackend = setWebSecureStorageBackend;
|
|
56
56
|
exports.storage = void 0;
|
|
@@ -72,42 +72,15 @@ Object.defineProperty(exports, "useStorageSelector", {
|
|
|
72
72
|
return _storageHooks.useStorageSelector;
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
|
+
var _shared = require("./shared");
|
|
75
76
|
var _reactNativeNitroModules = require("react-native-nitro-modules");
|
|
76
77
|
var _Storage = require("./Storage.types");
|
|
77
78
|
var _internal = require("./internal");
|
|
78
|
-
var
|
|
79
|
-
var _storageEvents = require("./storage-events");
|
|
79
|
+
var _storageCore = require("./storage-core");
|
|
80
80
|
var _migration = require("./migration");
|
|
81
|
+
var _storageRuntime = require("./storage-runtime");
|
|
81
82
|
var _storageHooks = require("./storage-hooks");
|
|
82
83
|
var _indexeddbBackend = require("./indexeddb-backend");
|
|
83
|
-
function asInternal(item) {
|
|
84
|
-
return item;
|
|
85
|
-
}
|
|
86
|
-
function isUpdater(valueOrFn) {
|
|
87
|
-
return typeof valueOrFn === "function";
|
|
88
|
-
}
|
|
89
|
-
function typedKeys(record) {
|
|
90
|
-
return Object.keys(record);
|
|
91
|
-
}
|
|
92
|
-
function assertEnumInteger(value, min, max, label) {
|
|
93
|
-
if (!Number.isFinite(value) || value < min || value > max) {
|
|
94
|
-
throw new Error(`NitroStorage: Invalid ${label}`);
|
|
95
|
-
}
|
|
96
|
-
if (value !== Math.trunc(value)) {
|
|
97
|
-
throw new Error(`NitroStorage: Invalid ${label}`);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
function assertAccessControlLevel(level) {
|
|
101
|
-
assertEnumInteger(level, 0, 4, "access control level");
|
|
102
|
-
}
|
|
103
|
-
function assertBiometricLevel(level) {
|
|
104
|
-
assertEnumInteger(level, 0, 2, "biometric level");
|
|
105
|
-
}
|
|
106
|
-
const registeredMigrations = new Map();
|
|
107
|
-
const runMicrotask = typeof queueMicrotask === "function" ? queueMicrotask : task => {
|
|
108
|
-
Promise.resolve().then(task);
|
|
109
|
-
};
|
|
110
|
-
const now = typeof performance !== "undefined" && typeof performance.now === "function" ? () => performance.now() : () => Date.now();
|
|
111
84
|
let _storageModule = null;
|
|
112
85
|
function getStorageModule() {
|
|
113
86
|
if (!_storageModule) {
|
|
@@ -115,745 +88,135 @@ function getStorageModule() {
|
|
|
115
88
|
}
|
|
116
89
|
return _storageModule;
|
|
117
90
|
}
|
|
118
|
-
const memoryStore = new Map();
|
|
119
|
-
const memoryListeners = new Map();
|
|
120
|
-
const scopedListeners = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
121
|
-
const scopedUnsubscribers = new Map();
|
|
122
|
-
const scopedRawCache = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
123
|
-
const pendingDiskWrites = new Map();
|
|
124
|
-
let diskFlushScheduled = false;
|
|
125
|
-
let diskWritesAsync = false;
|
|
126
|
-
const pendingSecureWrites = new Map();
|
|
127
|
-
let secureFlushScheduled = false;
|
|
128
|
-
let secureDefaultAccessControl = _Storage.AccessControl.WhenUnlocked;
|
|
129
|
-
const suppressedNativeEvents = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
130
|
-
let metricsObserver;
|
|
131
|
-
let eventObserver;
|
|
132
|
-
let eventObserverRedactSecureValues = true;
|
|
133
|
-
const metricsCounters = new Map();
|
|
134
|
-
const storageEvents = new _storageEvents.StorageEventRegistry();
|
|
135
91
|
const nativeSecureBackend = "platform-secure-storage";
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
function
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
return scopedListeners.get(scope);
|
|
169
|
-
}
|
|
170
|
-
function getScopeRawCache(scope) {
|
|
171
|
-
return scopedRawCache.get(scope);
|
|
172
|
-
}
|
|
173
|
-
function cacheRawValue(scope, key, value) {
|
|
174
|
-
getScopeRawCache(scope).set(key, value);
|
|
175
|
-
}
|
|
176
|
-
function readCachedRawValue(scope, key) {
|
|
177
|
-
return getScopeRawCache(scope).get(key);
|
|
178
|
-
}
|
|
179
|
-
function hasCachedRawValue(scope, key) {
|
|
180
|
-
return getScopeRawCache(scope).has(key);
|
|
181
|
-
}
|
|
182
|
-
function clearScopeRawCache(scope) {
|
|
183
|
-
getScopeRawCache(scope).clear();
|
|
184
|
-
}
|
|
185
|
-
function suppressNativeEvent(scope, key) {
|
|
186
|
-
const suppressedEvents = suppressedNativeEvents.get(scope);
|
|
187
|
-
suppressedEvents.set(key, (suppressedEvents.get(key) ?? 0) + 1);
|
|
188
|
-
}
|
|
189
|
-
function consumeSuppressedNativeEvent(scope, key) {
|
|
190
|
-
const suppressedEvents = suppressedNativeEvents.get(scope);
|
|
191
|
-
const count = suppressedEvents.get(key);
|
|
192
|
-
if (count === undefined) {
|
|
193
|
-
return false;
|
|
194
|
-
}
|
|
195
|
-
if (count <= 1) {
|
|
196
|
-
suppressedEvents.delete(key);
|
|
197
|
-
} else {
|
|
198
|
-
suppressedEvents.set(key, count - 1);
|
|
199
|
-
}
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
|
-
function notifyKeyListeners(registry, key) {
|
|
203
|
-
const listeners = registry.get(key);
|
|
204
|
-
if (listeners) {
|
|
205
|
-
for (const listener of listeners) {
|
|
206
|
-
listener();
|
|
207
|
-
}
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
function notifyAllListeners(registry) {
|
|
211
|
-
for (const listeners of registry.values()) {
|
|
212
|
-
for (const listener of listeners) {
|
|
213
|
-
listener();
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
function addKeyListener(registry, key, listener) {
|
|
218
|
-
let listeners = registry.get(key);
|
|
219
|
-
if (!listeners) {
|
|
220
|
-
listeners = new Set();
|
|
221
|
-
registry.set(key, listeners);
|
|
222
|
-
}
|
|
223
|
-
listeners.add(listener);
|
|
224
|
-
return () => {
|
|
225
|
-
const scopedListeners = registry.get(key);
|
|
226
|
-
if (!scopedListeners) {
|
|
227
|
-
return;
|
|
92
|
+
const nativeBackend = {
|
|
93
|
+
get: (key, scope) => getStorageModule().get(key, scope),
|
|
94
|
+
set: (key, value, scope) => getStorageModule().set(key, value, scope),
|
|
95
|
+
remove: (key, scope) => getStorageModule().remove(key, scope),
|
|
96
|
+
clear: scope => getStorageModule().clear(scope),
|
|
97
|
+
has: (key, scope) => getStorageModule().has(key, scope),
|
|
98
|
+
getAllKeys: scope => getStorageModule().getAllKeys(scope) ?? [],
|
|
99
|
+
getKeysByPrefix: (prefix, scope) => getStorageModule().getKeysByPrefix(prefix, scope) ?? [],
|
|
100
|
+
size: scope => getStorageModule().size(scope),
|
|
101
|
+
setBatch: (keys, values, scope) => getStorageModule().setBatch(keys, values, scope),
|
|
102
|
+
getBatch: (keys, scope) => (getStorageModule().getBatch(keys, scope) ?? []).map(value => (0, _internal.decodeNativeBatchValue)(value)),
|
|
103
|
+
removeBatch: (keys, scope) => getStorageModule().removeBatch(keys, scope),
|
|
104
|
+
removeByPrefix: (prefix, scope) => getStorageModule().removeByPrefix(prefix, scope),
|
|
105
|
+
setSecureAccessControl: level => getStorageModule().setSecureAccessControl(level),
|
|
106
|
+
getSecureBiometric: key => getStorageModule().getSecureBiometric(key),
|
|
107
|
+
setSecureBiometricWithLevel: (key, value, level) => getStorageModule().setSecureBiometricWithLevel(key, value, level),
|
|
108
|
+
deleteSecureBiometric: key => getStorageModule().deleteSecureBiometric(key),
|
|
109
|
+
hasSecureBiometric: key => getStorageModule().hasSecureBiometric(key),
|
|
110
|
+
clearSecureBiometric: () => getStorageModule().clearSecureBiometric()
|
|
111
|
+
};
|
|
112
|
+
function buildNativeAdapter(internals) {
|
|
113
|
+
const scopedUnsubscribers = new Map();
|
|
114
|
+
const suppressedNativeEvents = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
115
|
+
function suppressNativeEvent(scope, key) {
|
|
116
|
+
const suppressedEvents = suppressedNativeEvents.get(scope);
|
|
117
|
+
suppressedEvents.set(key, (suppressedEvents.get(key) ?? 0) + 1);
|
|
118
|
+
}
|
|
119
|
+
function consumeSuppressedNativeEvent(scope, key) {
|
|
120
|
+
const suppressedEvents = suppressedNativeEvents.get(scope);
|
|
121
|
+
const count = suppressedEvents.get(key);
|
|
122
|
+
if (count === undefined) {
|
|
123
|
+
return false;
|
|
228
124
|
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
125
|
+
if (count <= 1) {
|
|
126
|
+
suppressedEvents.delete(key);
|
|
127
|
+
} else {
|
|
128
|
+
suppressedEvents.set(key, count - 1);
|
|
232
129
|
}
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
function getEventRawValue(scope, key) {
|
|
236
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
237
|
-
const value = memoryStore.get(key);
|
|
238
|
-
return typeof value === "string" ? value : undefined;
|
|
239
|
-
}
|
|
240
|
-
return getRawValue(key, scope);
|
|
241
|
-
}
|
|
242
|
-
function createKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
243
|
-
return {
|
|
244
|
-
type: "key",
|
|
245
|
-
scope,
|
|
246
|
-
key,
|
|
247
|
-
oldValue,
|
|
248
|
-
newValue,
|
|
249
|
-
operation,
|
|
250
|
-
source
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
function hasStorageChangeObservers(scope) {
|
|
254
|
-
return storageEvents.hasListeners(scope) || eventObserver !== undefined;
|
|
255
|
-
}
|
|
256
|
-
function shouldReadPreviousEventValues(scope) {
|
|
257
|
-
if (storageEvents.hasListeners(scope)) {
|
|
258
130
|
return true;
|
|
259
131
|
}
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
}
|
|
263
|
-
return scope !== _Storage.StorageScope.Secure || !eventObserverRedactSecureValues;
|
|
264
|
-
}
|
|
265
|
-
const SECURE_EVENT_REDACTED_VALUE = "[secure]";
|
|
266
|
-
function redactSecureKeyChange(event) {
|
|
267
|
-
if (event.scope !== _Storage.StorageScope.Secure) {
|
|
268
|
-
return event;
|
|
269
|
-
}
|
|
270
|
-
return {
|
|
271
|
-
...event,
|
|
272
|
-
oldValue: event.oldValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE,
|
|
273
|
-
newValue: event.newValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE
|
|
274
|
-
};
|
|
275
|
-
}
|
|
276
|
-
function eventForGlobalObserver(event) {
|
|
277
|
-
if (!eventObserverRedactSecureValues || event.scope !== _Storage.StorageScope.Secure) {
|
|
278
|
-
return event;
|
|
279
|
-
}
|
|
280
|
-
if (event.type === "key") {
|
|
281
|
-
return redactSecureKeyChange(event);
|
|
282
|
-
}
|
|
283
|
-
return {
|
|
284
|
-
...event,
|
|
285
|
-
changes: event.changes.map(redactSecureKeyChange)
|
|
286
|
-
};
|
|
287
|
-
}
|
|
288
|
-
function emitKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
289
|
-
if (source === "native" && operation !== "external" && scope !== _Storage.StorageScope.Memory && scopedUnsubscribers.has(scope)) {
|
|
290
|
-
suppressNativeEvent(scope, key);
|
|
291
|
-
}
|
|
292
|
-
const event = createKeyChange(scope, key, oldValue, newValue, operation, source);
|
|
293
|
-
storageEvents.emitKey(event);
|
|
294
|
-
eventObserver?.(eventForGlobalObserver(event));
|
|
295
|
-
}
|
|
296
|
-
function emitBatchChange(scope, operation, source, changes) {
|
|
297
|
-
if (changes.length === 0) {
|
|
298
|
-
return;
|
|
299
|
-
}
|
|
300
|
-
if (source === "native" && operation !== "external" && scope !== _Storage.StorageScope.Memory && scopedUnsubscribers.has(scope)) {
|
|
301
|
-
changes.forEach(change => suppressNativeEvent(scope, change.key));
|
|
302
|
-
}
|
|
303
|
-
const event = {
|
|
304
|
-
type: "batch",
|
|
305
|
-
scope,
|
|
306
|
-
operation,
|
|
307
|
-
source,
|
|
308
|
-
changes
|
|
309
|
-
};
|
|
310
|
-
storageEvents.emitBatch(event);
|
|
311
|
-
eventObserver?.(eventForGlobalObserver(event));
|
|
312
|
-
}
|
|
313
|
-
function readPendingSecureWrite(key) {
|
|
314
|
-
return pendingSecureWrites.get(key)?.value;
|
|
315
|
-
}
|
|
316
|
-
function readPendingDiskWrite(key) {
|
|
317
|
-
return pendingDiskWrites.get(key)?.value;
|
|
318
|
-
}
|
|
319
|
-
function hasPendingDiskWrite(key) {
|
|
320
|
-
return pendingDiskWrites.has(key);
|
|
321
|
-
}
|
|
322
|
-
function hasPendingSecureWrite(key) {
|
|
323
|
-
return pendingSecureWrites.has(key);
|
|
324
|
-
}
|
|
325
|
-
function clearPendingDiskWrite(key) {
|
|
326
|
-
pendingDiskWrites.delete(key);
|
|
327
|
-
}
|
|
328
|
-
function clearPendingSecureWrite(key) {
|
|
329
|
-
pendingSecureWrites.delete(key);
|
|
330
|
-
}
|
|
331
|
-
function flushDiskWrites() {
|
|
332
|
-
diskFlushScheduled = false;
|
|
333
|
-
if (pendingDiskWrites.size === 0) {
|
|
334
|
-
return;
|
|
335
|
-
}
|
|
336
|
-
const writes = Array.from(pendingDiskWrites.values());
|
|
337
|
-
pendingDiskWrites.clear();
|
|
338
|
-
const keysToSet = [];
|
|
339
|
-
const valuesToSet = [];
|
|
340
|
-
const keysToRemove = [];
|
|
341
|
-
writes.forEach(({
|
|
342
|
-
key,
|
|
343
|
-
value
|
|
344
|
-
}) => {
|
|
345
|
-
if (value === undefined) {
|
|
346
|
-
keysToRemove.push(key);
|
|
132
|
+
function ensureNativeScopeSubscription(scope) {
|
|
133
|
+
if (scopedUnsubscribers.has(scope)) {
|
|
347
134
|
return;
|
|
348
135
|
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
if (keysToRemove.length > 0) {
|
|
357
|
-
storageModule.removeBatch(keysToRemove, _Storage.StorageScope.Disk);
|
|
358
|
-
}
|
|
359
|
-
}
|
|
360
|
-
function flushSecureWrites() {
|
|
361
|
-
secureFlushScheduled = false;
|
|
362
|
-
if (pendingSecureWrites.size === 0) {
|
|
363
|
-
return;
|
|
364
|
-
}
|
|
365
|
-
const writes = Array.from(pendingSecureWrites.values());
|
|
366
|
-
pendingSecureWrites.clear();
|
|
367
|
-
const groupedSetWrites = new Map();
|
|
368
|
-
const keysToRemove = [];
|
|
369
|
-
writes.forEach(({
|
|
370
|
-
key,
|
|
371
|
-
value,
|
|
372
|
-
accessControl
|
|
373
|
-
}) => {
|
|
374
|
-
if (value === undefined) {
|
|
375
|
-
keysToRemove.push(key);
|
|
376
|
-
} else {
|
|
377
|
-
const resolvedAccessControl = accessControl ?? secureDefaultAccessControl;
|
|
378
|
-
const existingGroup = groupedSetWrites.get(resolvedAccessControl);
|
|
379
|
-
const group = existingGroup ?? {
|
|
380
|
-
keys: [],
|
|
381
|
-
values: []
|
|
382
|
-
};
|
|
383
|
-
group.keys.push(key);
|
|
384
|
-
group.values.push(value);
|
|
385
|
-
if (!existingGroup) {
|
|
386
|
-
groupedSetWrites.set(resolvedAccessControl, group);
|
|
136
|
+
const unsubscribe = getStorageModule().addOnChange(scope, (key, value) => {
|
|
137
|
+
if (scope === _Storage.StorageScope.Disk) {
|
|
138
|
+
if (key === "") {
|
|
139
|
+
internals.clearAllPendingDiskWrites();
|
|
140
|
+
} else {
|
|
141
|
+
internals.clearPendingDiskWrite(key);
|
|
142
|
+
}
|
|
387
143
|
}
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
});
|
|
395
|
-
if (keysToRemove.length > 0) {
|
|
396
|
-
storageModule.removeBatch(keysToRemove, _Storage.StorageScope.Secure);
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
function scheduleDiskWrite(key, value) {
|
|
400
|
-
pendingDiskWrites.set(key, {
|
|
401
|
-
key,
|
|
402
|
-
value
|
|
403
|
-
});
|
|
404
|
-
if (diskFlushScheduled) {
|
|
405
|
-
return;
|
|
406
|
-
}
|
|
407
|
-
diskFlushScheduled = true;
|
|
408
|
-
runMicrotask(flushDiskWrites);
|
|
409
|
-
}
|
|
410
|
-
function scheduleSecureWrite(key, value, accessControl) {
|
|
411
|
-
const pendingWrite = {
|
|
412
|
-
key,
|
|
413
|
-
value
|
|
414
|
-
};
|
|
415
|
-
if (accessControl !== undefined) {
|
|
416
|
-
pendingWrite.accessControl = accessControl;
|
|
417
|
-
}
|
|
418
|
-
pendingSecureWrites.set(key, pendingWrite);
|
|
419
|
-
if (secureFlushScheduled) {
|
|
420
|
-
return;
|
|
421
|
-
}
|
|
422
|
-
secureFlushScheduled = true;
|
|
423
|
-
runMicrotask(flushSecureWrites);
|
|
424
|
-
}
|
|
425
|
-
function ensureNativeScopeSubscription(scope) {
|
|
426
|
-
if (scopedUnsubscribers.has(scope)) {
|
|
427
|
-
return;
|
|
428
|
-
}
|
|
429
|
-
const unsubscribe = getStorageModule().addOnChange(scope, (key, value) => {
|
|
430
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
431
|
-
if (key === "") {
|
|
432
|
-
pendingDiskWrites.clear();
|
|
433
|
-
} else {
|
|
434
|
-
clearPendingDiskWrite(key);
|
|
144
|
+
if (scope === _Storage.StorageScope.Secure) {
|
|
145
|
+
if (key === "") {
|
|
146
|
+
internals.clearAllPendingSecureWrites();
|
|
147
|
+
} else {
|
|
148
|
+
internals.clearPendingSecureWrite(key);
|
|
149
|
+
}
|
|
435
150
|
}
|
|
436
|
-
}
|
|
437
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
438
151
|
if (key === "") {
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
152
|
+
internals.clearScopeRawCache(scope);
|
|
153
|
+
(0, _shared.notifyAllListeners)(internals.getScopedListeners(scope));
|
|
154
|
+
return;
|
|
442
155
|
}
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
if (consumeSuppressedNativeEvent(scope, key)) {
|
|
453
|
-
return;
|
|
454
|
-
}
|
|
455
|
-
emitKeyChange(scope, key, oldValue, value, "external", "native");
|
|
456
|
-
});
|
|
457
|
-
scopedUnsubscribers.set(scope, typeof unsubscribe === "function" ? unsubscribe : () => {});
|
|
458
|
-
}
|
|
459
|
-
function maybeCleanupNativeScopeSubscription(scope) {
|
|
460
|
-
const listeners = getScopedListeners(scope);
|
|
461
|
-
if (listeners.size > 0 || storageEvents.hasListeners(scope) || eventObserver !== undefined) {
|
|
462
|
-
return;
|
|
463
|
-
}
|
|
464
|
-
const unsubscribe = scopedUnsubscribers.get(scope);
|
|
465
|
-
if (!unsubscribe) {
|
|
466
|
-
return;
|
|
467
|
-
}
|
|
468
|
-
unsubscribe();
|
|
469
|
-
scopedUnsubscribers.delete(scope);
|
|
470
|
-
}
|
|
471
|
-
function getRawValue(key, scope) {
|
|
472
|
-
(0, _internal.assertValidScope)(scope);
|
|
473
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
474
|
-
const value = memoryStore.get(key);
|
|
475
|
-
return typeof value === "string" ? value : undefined;
|
|
476
|
-
}
|
|
477
|
-
if (scope === _Storage.StorageScope.Disk && hasPendingDiskWrite(key)) {
|
|
478
|
-
return readPendingDiskWrite(key);
|
|
479
|
-
}
|
|
480
|
-
if (scope === _Storage.StorageScope.Secure && hasPendingSecureWrite(key)) {
|
|
481
|
-
return readPendingSecureWrite(key);
|
|
482
|
-
}
|
|
483
|
-
return getStorageModule().get(key, scope);
|
|
484
|
-
}
|
|
485
|
-
function setRawValue(key, value, scope) {
|
|
486
|
-
(0, _internal.assertValidScope)(scope);
|
|
487
|
-
const oldValue = scope === _Storage.StorageScope.Memory ? getEventRawValue(scope, key) : undefined;
|
|
488
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
489
|
-
memoryStore.set(key, value);
|
|
490
|
-
notifyKeyListeners(memoryListeners, key);
|
|
491
|
-
emitKeyChange(scope, key, oldValue, value, "set", "memory");
|
|
492
|
-
return;
|
|
156
|
+
const oldValue = internals.readCachedRawValue(scope, key);
|
|
157
|
+
internals.cacheRawValue(scope, key, value);
|
|
158
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(scope), key);
|
|
159
|
+
if (consumeSuppressedNativeEvent(scope, key)) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
internals.emitKeyChange(scope, key, oldValue, value, "external", "native");
|
|
163
|
+
});
|
|
164
|
+
scopedUnsubscribers.set(scope, typeof unsubscribe === "function" ? unsubscribe : () => {});
|
|
493
165
|
}
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
if (
|
|
497
|
-
scheduleDiskWrite(key, value);
|
|
498
|
-
emitKeyChange(scope, key, oldValue, value, "set", "native");
|
|
166
|
+
function maybeCleanupNativeScopeSubscription(scope) {
|
|
167
|
+
const listeners = internals.getScopedListeners(scope);
|
|
168
|
+
if (listeners.size > 0 || internals.hasScopeEventListeners(scope) || internals.hasEventObserver()) {
|
|
499
169
|
return;
|
|
500
170
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
505
|
-
flushSecureWrites();
|
|
506
|
-
clearPendingSecureWrite(key);
|
|
507
|
-
getStorageModule().setSecureAccessControl(secureDefaultAccessControl);
|
|
508
|
-
}
|
|
509
|
-
getStorageModule().set(key, value, scope);
|
|
510
|
-
cacheRawValue(scope, key, value);
|
|
511
|
-
emitKeyChange(scope, key, oldValue, value, "set", "native");
|
|
512
|
-
}
|
|
513
|
-
function removeRawValue(key, scope) {
|
|
514
|
-
(0, _internal.assertValidScope)(scope);
|
|
515
|
-
const oldValue = getEventRawValue(scope, key);
|
|
516
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
517
|
-
memoryStore.delete(key);
|
|
518
|
-
notifyKeyListeners(memoryListeners, key);
|
|
519
|
-
emitKeyChange(scope, key, oldValue, undefined, "remove", "memory");
|
|
520
|
-
return;
|
|
521
|
-
}
|
|
522
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
523
|
-
cacheRawValue(scope, key, undefined);
|
|
524
|
-
if (diskWritesAsync) {
|
|
525
|
-
scheduleDiskWrite(key, undefined);
|
|
526
|
-
emitKeyChange(scope, key, oldValue, undefined, "remove", "native");
|
|
171
|
+
const unsubscribe = scopedUnsubscribers.get(scope);
|
|
172
|
+
if (!unsubscribe) {
|
|
527
173
|
return;
|
|
528
174
|
}
|
|
529
|
-
|
|
530
|
-
|
|
175
|
+
unsubscribe();
|
|
176
|
+
scopedUnsubscribers.delete(scope);
|
|
531
177
|
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
178
|
+
return {
|
|
179
|
+
backend: nativeBackend,
|
|
180
|
+
changeSource: "native",
|
|
181
|
+
applyAccessControlOnSecureRawWrite: true,
|
|
182
|
+
flushDiskWritesOnImport: false,
|
|
183
|
+
ensureScopeSubscription: ensureNativeScopeSubscription,
|
|
184
|
+
maybeCleanupScopeSubscription: maybeCleanupNativeScopeSubscription,
|
|
185
|
+
onWillEmitChanges: (scope, keys, operation, source) => {
|
|
186
|
+
if (source === "native" && operation !== "external" && scope !== _Storage.StorageScope.Memory && scopedUnsubscribers.has(scope)) {
|
|
187
|
+
keys.forEach(key => suppressNativeEvent(scope, key));
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
getSecureMetadataProfile: () => ({
|
|
191
|
+
backend: nativeSecureBackend,
|
|
192
|
+
encrypted: "available",
|
|
193
|
+
hardwareBacked: "unknown"
|
|
194
|
+
})
|
|
195
|
+
};
|
|
550
196
|
}
|
|
197
|
+
const core = (0, _storageCore.createStorageCore)(buildNativeAdapter);
|
|
198
|
+
const {
|
|
199
|
+
internals
|
|
200
|
+
} = core;
|
|
551
201
|
const storage = exports.storage = {
|
|
552
|
-
|
|
553
|
-
(0, _internal.assertValidScope)(scope);
|
|
554
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
555
|
-
ensureNativeScopeSubscription(scope);
|
|
556
|
-
const unsubscribe = storageEvents.subscribe(scope, listener);
|
|
557
|
-
return () => {
|
|
558
|
-
unsubscribe();
|
|
559
|
-
maybeCleanupNativeScopeSubscription(scope);
|
|
560
|
-
};
|
|
561
|
-
}
|
|
562
|
-
return storageEvents.subscribe(scope, listener);
|
|
563
|
-
},
|
|
564
|
-
subscribeKey: (scope, key, listener) => {
|
|
565
|
-
(0, _internal.assertValidScope)(scope);
|
|
566
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
567
|
-
ensureNativeScopeSubscription(scope);
|
|
568
|
-
const unsubscribe = storageEvents.subscribeKey(scope, key, listener);
|
|
569
|
-
return () => {
|
|
570
|
-
unsubscribe();
|
|
571
|
-
maybeCleanupNativeScopeSubscription(scope);
|
|
572
|
-
};
|
|
573
|
-
}
|
|
574
|
-
return storageEvents.subscribeKey(scope, key, listener);
|
|
575
|
-
},
|
|
576
|
-
subscribePrefix: (scope, prefix, listener) => {
|
|
577
|
-
(0, _internal.assertValidScope)(scope);
|
|
578
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
579
|
-
ensureNativeScopeSubscription(scope);
|
|
580
|
-
const unsubscribe = storageEvents.subscribePrefix(scope, prefix, listener);
|
|
581
|
-
return () => {
|
|
582
|
-
unsubscribe();
|
|
583
|
-
maybeCleanupNativeScopeSubscription(scope);
|
|
584
|
-
};
|
|
585
|
-
}
|
|
586
|
-
return storageEvents.subscribePrefix(scope, prefix, listener);
|
|
587
|
-
},
|
|
588
|
-
subscribeNamespace: (namespace, scope, listener) => {
|
|
589
|
-
return storage.subscribePrefix(scope, (0, _internal.prefixKey)(namespace, ""), listener);
|
|
590
|
-
},
|
|
591
|
-
setEventObserver: (observer, options = {}) => {
|
|
592
|
-
eventObserver = observer;
|
|
593
|
-
eventObserverRedactSecureValues = options.redactSecureValues !== false;
|
|
594
|
-
if (observer) {
|
|
595
|
-
ensureNativeScopeSubscription(_Storage.StorageScope.Disk);
|
|
596
|
-
ensureNativeScopeSubscription(_Storage.StorageScope.Secure);
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
maybeCleanupNativeScopeSubscription(_Storage.StorageScope.Disk);
|
|
600
|
-
maybeCleanupNativeScopeSubscription(_Storage.StorageScope.Secure);
|
|
601
|
-
},
|
|
602
|
-
clear: scope => {
|
|
603
|
-
measureOperation("storage:clear", scope, () => {
|
|
604
|
-
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getAll(scope) : {};
|
|
605
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
606
|
-
memoryStore.clear();
|
|
607
|
-
notifyAllListeners(memoryListeners);
|
|
608
|
-
emitBatchChange(scope, "clear", "memory", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clear", "memory")));
|
|
609
|
-
return;
|
|
610
|
-
}
|
|
611
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
612
|
-
flushDiskWrites();
|
|
613
|
-
pendingDiskWrites.clear();
|
|
614
|
-
}
|
|
615
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
616
|
-
flushSecureWrites();
|
|
617
|
-
pendingSecureWrites.clear();
|
|
618
|
-
}
|
|
619
|
-
clearScopeRawCache(scope);
|
|
620
|
-
getStorageModule().clear(scope);
|
|
621
|
-
emitBatchChange(scope, "clear", "native", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clear", "native")));
|
|
622
|
-
});
|
|
623
|
-
},
|
|
624
|
-
clearAll: () => {
|
|
625
|
-
measureOperation("storage:clearAll", _Storage.StorageScope.Memory, () => {
|
|
626
|
-
storage.clear(_Storage.StorageScope.Memory);
|
|
627
|
-
storage.clear(_Storage.StorageScope.Disk);
|
|
628
|
-
storage.clear(_Storage.StorageScope.Secure);
|
|
629
|
-
}, 3);
|
|
630
|
-
},
|
|
631
|
-
clearNamespace: (namespace, scope) => {
|
|
632
|
-
measureOperation("storage:clearNamespace", scope, () => {
|
|
633
|
-
(0, _internal.assertValidScope)(scope);
|
|
634
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
635
|
-
const affectedKeys = Array.from(memoryStore.keys()).filter(key => (0, _internal.isNamespaced)(key, namespace));
|
|
636
|
-
const previousValues = affectedKeys.map(key => ({
|
|
637
|
-
key,
|
|
638
|
-
value: getEventRawValue(scope, key)
|
|
639
|
-
}));
|
|
640
|
-
if (affectedKeys.length === 0) {
|
|
641
|
-
return;
|
|
642
|
-
}
|
|
643
|
-
affectedKeys.forEach(key => {
|
|
644
|
-
memoryStore.delete(key);
|
|
645
|
-
});
|
|
646
|
-
affectedKeys.forEach(key => notifyKeyListeners(memoryListeners, key));
|
|
647
|
-
emitBatchChange(scope, "clearNamespace", "memory", previousValues.map(({
|
|
648
|
-
key,
|
|
649
|
-
value
|
|
650
|
-
}) => createKeyChange(scope, key, value, undefined, "clearNamespace", "memory")));
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
const keyPrefix = (0, _internal.prefixKey)(namespace, "");
|
|
654
|
-
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getByPrefix(keyPrefix, scope) : {};
|
|
655
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
656
|
-
flushDiskWrites();
|
|
657
|
-
}
|
|
658
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
659
|
-
flushSecureWrites();
|
|
660
|
-
}
|
|
661
|
-
const scopeCache = getScopeRawCache(scope);
|
|
662
|
-
for (const key of scopeCache.keys()) {
|
|
663
|
-
if ((0, _internal.isNamespaced)(key, namespace)) {
|
|
664
|
-
scopeCache.delete(key);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
getStorageModule().removeByPrefix(keyPrefix, scope);
|
|
668
|
-
emitBatchChange(scope, "clearNamespace", "native", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clearNamespace", "native")));
|
|
669
|
-
});
|
|
670
|
-
},
|
|
671
|
-
clearBiometric: () => {
|
|
672
|
-
measureOperation("storage:clearBiometric", _Storage.StorageScope.Secure, () => {
|
|
673
|
-
getStorageModule().clearSecureBiometric();
|
|
674
|
-
});
|
|
675
|
-
},
|
|
676
|
-
has: (key, scope) => {
|
|
677
|
-
return measureOperation("storage:has", scope, () => {
|
|
678
|
-
(0, _internal.assertValidScope)(scope);
|
|
679
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
680
|
-
return memoryStore.has(key);
|
|
681
|
-
}
|
|
682
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
683
|
-
flushDiskWrites();
|
|
684
|
-
}
|
|
685
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
686
|
-
flushSecureWrites();
|
|
687
|
-
}
|
|
688
|
-
return getStorageModule().has(key, scope);
|
|
689
|
-
});
|
|
690
|
-
},
|
|
691
|
-
getAllKeys: scope => {
|
|
692
|
-
return measureOperation("storage:getAllKeys", scope, () => {
|
|
693
|
-
(0, _internal.assertValidScope)(scope);
|
|
694
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
695
|
-
return Array.from(memoryStore.keys());
|
|
696
|
-
}
|
|
697
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
698
|
-
flushDiskWrites();
|
|
699
|
-
}
|
|
700
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
701
|
-
flushSecureWrites();
|
|
702
|
-
}
|
|
703
|
-
return getStorageModule().getAllKeys(scope);
|
|
704
|
-
});
|
|
705
|
-
},
|
|
706
|
-
getKeysByPrefix: (prefix, scope) => {
|
|
707
|
-
return measureOperation("storage:getKeysByPrefix", scope, () => {
|
|
708
|
-
(0, _internal.assertValidScope)(scope);
|
|
709
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
710
|
-
return Array.from(memoryStore.keys()).filter(key => key.startsWith(prefix));
|
|
711
|
-
}
|
|
712
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
713
|
-
flushDiskWrites();
|
|
714
|
-
}
|
|
715
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
716
|
-
flushSecureWrites();
|
|
717
|
-
}
|
|
718
|
-
return getStorageModule().getKeysByPrefix(prefix, scope) ?? [];
|
|
719
|
-
});
|
|
720
|
-
},
|
|
721
|
-
getByPrefix: (prefix, scope) => {
|
|
722
|
-
return measureOperation("storage:getByPrefix", scope, () => {
|
|
723
|
-
const result = {};
|
|
724
|
-
const keys = storage.getKeysByPrefix(prefix, scope);
|
|
725
|
-
if (keys.length === 0) {
|
|
726
|
-
return result;
|
|
727
|
-
}
|
|
728
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
729
|
-
keys.forEach(key => {
|
|
730
|
-
const value = memoryStore.get(key);
|
|
731
|
-
if (typeof value === "string") {
|
|
732
|
-
result[key] = value;
|
|
733
|
-
}
|
|
734
|
-
});
|
|
735
|
-
return result;
|
|
736
|
-
}
|
|
737
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
738
|
-
flushDiskWrites();
|
|
739
|
-
}
|
|
740
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
741
|
-
flushSecureWrites();
|
|
742
|
-
}
|
|
743
|
-
const values = getStorageModule().getBatch(keys, scope) ?? [];
|
|
744
|
-
keys.forEach((key, idx) => {
|
|
745
|
-
const value = (0, _internal.decodeNativeBatchValue)(values[idx]);
|
|
746
|
-
if (value !== undefined) {
|
|
747
|
-
result[key] = value;
|
|
748
|
-
}
|
|
749
|
-
});
|
|
750
|
-
return result;
|
|
751
|
-
});
|
|
752
|
-
},
|
|
753
|
-
getAll: scope => {
|
|
754
|
-
return measureOperation("storage:getAll", scope, () => {
|
|
755
|
-
(0, _internal.assertValidScope)(scope);
|
|
756
|
-
const result = {};
|
|
757
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
758
|
-
for (const key of memoryStore.keys()) {
|
|
759
|
-
const value = memoryStore.get(key);
|
|
760
|
-
if (typeof value === "string") result[key] = value;
|
|
761
|
-
}
|
|
762
|
-
return result;
|
|
763
|
-
}
|
|
764
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
765
|
-
flushDiskWrites();
|
|
766
|
-
}
|
|
767
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
768
|
-
flushSecureWrites();
|
|
769
|
-
}
|
|
770
|
-
const keys = getStorageModule().getAllKeys(scope) ?? [];
|
|
771
|
-
if (keys.length === 0) return result;
|
|
772
|
-
const values = getStorageModule().getBatch(keys, scope) ?? [];
|
|
773
|
-
keys.forEach((key, idx) => {
|
|
774
|
-
const val = (0, _internal.decodeNativeBatchValue)(values[idx]);
|
|
775
|
-
if (val !== undefined) result[key] = val;
|
|
776
|
-
});
|
|
777
|
-
return result;
|
|
778
|
-
});
|
|
779
|
-
},
|
|
780
|
-
export: (scope, options = {}) => {
|
|
781
|
-
if (scope === _Storage.StorageScope.Secure && options.includeSecureValues !== true) {
|
|
782
|
-
throw new Error("NitroStorage: exporting Secure scope exposes raw secret values. Pass { includeSecureValues: true } or use exportSecureUnsafe().");
|
|
783
|
-
}
|
|
784
|
-
return measureOperation("storage:export", scope, () => storage.getAll(scope));
|
|
785
|
-
},
|
|
786
|
-
exportSecureUnsafe: () => {
|
|
787
|
-
return measureOperation("storage:exportSecureUnsafe", _Storage.StorageScope.Secure, () => storage.getAll(_Storage.StorageScope.Secure));
|
|
788
|
-
},
|
|
789
|
-
size: scope => {
|
|
790
|
-
return measureOperation("storage:size", scope, () => {
|
|
791
|
-
(0, _internal.assertValidScope)(scope);
|
|
792
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
793
|
-
return memoryStore.size;
|
|
794
|
-
}
|
|
795
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
796
|
-
flushDiskWrites();
|
|
797
|
-
}
|
|
798
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
799
|
-
flushSecureWrites();
|
|
800
|
-
}
|
|
801
|
-
return getStorageModule().size(scope);
|
|
802
|
-
});
|
|
803
|
-
},
|
|
202
|
+
...core.storage,
|
|
804
203
|
setAccessControl: level => {
|
|
805
|
-
measureOperation("storage:setAccessControl", _Storage.StorageScope.Secure, () => {
|
|
806
|
-
assertAccessControlLevel(level);
|
|
807
|
-
|
|
204
|
+
internals.measureOperation("storage:setAccessControl", _Storage.StorageScope.Secure, () => {
|
|
205
|
+
(0, _shared.assertAccessControlLevel)(level);
|
|
206
|
+
internals.setSecureDefaultAccessControl(level);
|
|
808
207
|
getStorageModule().setSecureAccessControl(level);
|
|
809
208
|
});
|
|
810
209
|
},
|
|
811
210
|
setSecureWritesAsync: enabled => {
|
|
812
|
-
measureOperation("storage:setSecureWritesAsync", _Storage.StorageScope.Secure, () => {
|
|
211
|
+
internals.measureOperation("storage:setSecureWritesAsync", _Storage.StorageScope.Secure, () => {
|
|
813
212
|
getStorageModule().setSecureWritesAsync(enabled);
|
|
814
213
|
});
|
|
815
214
|
},
|
|
816
|
-
setDiskWritesAsync: enabled => {
|
|
817
|
-
measureOperation("storage:setDiskWritesAsync", _Storage.StorageScope.Disk, () => {
|
|
818
|
-
diskWritesAsync = enabled;
|
|
819
|
-
if (!enabled) {
|
|
820
|
-
flushDiskWrites();
|
|
821
|
-
}
|
|
822
|
-
});
|
|
823
|
-
},
|
|
824
|
-
flushDiskWrites: () => {
|
|
825
|
-
measureOperation("storage:flushDiskWrites", _Storage.StorageScope.Disk, () => {
|
|
826
|
-
flushDiskWrites();
|
|
827
|
-
});
|
|
828
|
-
},
|
|
829
|
-
flushSecureWrites: () => {
|
|
830
|
-
measureOperation("storage:flushSecureWrites", _Storage.StorageScope.Secure, () => {
|
|
831
|
-
flushSecureWrites();
|
|
832
|
-
});
|
|
833
|
-
},
|
|
834
215
|
setKeychainAccessGroup: group => {
|
|
835
|
-
measureOperation("storage:setKeychainAccessGroup", _Storage.StorageScope.Secure, () => {
|
|
216
|
+
internals.measureOperation("storage:setKeychainAccessGroup", _Storage.StorageScope.Secure, () => {
|
|
836
217
|
getStorageModule().setKeychainAccessGroup(group);
|
|
837
218
|
});
|
|
838
219
|
},
|
|
839
|
-
setMetricsObserver: observer => {
|
|
840
|
-
metricsObserver = observer;
|
|
841
|
-
},
|
|
842
|
-
getMetricsSnapshot: () => {
|
|
843
|
-
const snapshot = {};
|
|
844
|
-
metricsCounters.forEach((value, key) => {
|
|
845
|
-
snapshot[key] = {
|
|
846
|
-
count: value.count,
|
|
847
|
-
totalDurationMs: value.totalDurationMs,
|
|
848
|
-
avgDurationMs: value.count === 0 ? 0 : value.totalDurationMs / value.count,
|
|
849
|
-
maxDurationMs: value.maxDurationMs
|
|
850
|
-
};
|
|
851
|
-
});
|
|
852
|
-
return snapshot;
|
|
853
|
-
},
|
|
854
|
-
resetMetrics: () => {
|
|
855
|
-
metricsCounters.clear();
|
|
856
|
-
},
|
|
857
220
|
getCapabilities: () => ({
|
|
858
221
|
platform: "native",
|
|
859
222
|
backend: {
|
|
@@ -886,75 +249,16 @@ const storage = exports.storage = {
|
|
|
886
249
|
listsWithoutValues: true,
|
|
887
250
|
persistsTimestamps: false
|
|
888
251
|
}
|
|
889
|
-
})
|
|
890
|
-
getSecureMetadata: key => {
|
|
891
|
-
return measureOperation("storage:getSecureMetadata", _Storage.StorageScope.Secure, () => {
|
|
892
|
-
flushSecureWrites();
|
|
893
|
-
const storageModule = getStorageModule();
|
|
894
|
-
const biometricProtected = storageModule.hasSecureBiometric(key);
|
|
895
|
-
const exists = biometricProtected || storageModule.has(key, _Storage.StorageScope.Secure);
|
|
896
|
-
let kind = "missing";
|
|
897
|
-
if (exists) {
|
|
898
|
-
kind = biometricProtected ? "biometric" : "secure";
|
|
899
|
-
}
|
|
900
|
-
return {
|
|
901
|
-
key,
|
|
902
|
-
exists,
|
|
903
|
-
kind,
|
|
904
|
-
backend: nativeSecureBackend,
|
|
905
|
-
encrypted: "available",
|
|
906
|
-
hardwareBacked: "unknown",
|
|
907
|
-
biometricProtected,
|
|
908
|
-
valueExposed: false
|
|
909
|
-
};
|
|
910
|
-
});
|
|
911
|
-
},
|
|
912
|
-
getAllSecureMetadata: () => {
|
|
913
|
-
return measureOperation("storage:getAllSecureMetadata", _Storage.StorageScope.Secure, () => {
|
|
914
|
-
flushSecureWrites();
|
|
915
|
-
return getStorageModule().getAllKeys(_Storage.StorageScope.Secure).map(key => storage.getSecureMetadata(key));
|
|
916
|
-
});
|
|
917
|
-
},
|
|
918
|
-
getString: (key, scope) => {
|
|
919
|
-
return measureOperation("storage:getString", scope, () => {
|
|
920
|
-
return getRawValue(key, scope);
|
|
921
|
-
});
|
|
922
|
-
},
|
|
923
|
-
setString: (key, value, scope) => {
|
|
924
|
-
measureOperation("storage:setString", scope, () => {
|
|
925
|
-
setRawValue(key, value, scope);
|
|
926
|
-
});
|
|
927
|
-
},
|
|
928
|
-
deleteString: (key, scope) => {
|
|
929
|
-
measureOperation("storage:deleteString", scope, () => {
|
|
930
|
-
removeRawValue(key, scope);
|
|
931
|
-
});
|
|
932
|
-
},
|
|
933
|
-
import: (data, scope) => {
|
|
934
|
-
const keys = Object.keys(data);
|
|
935
|
-
measureOperation("storage:import", scope, () => {
|
|
936
|
-
(0, _internal.assertValidScope)(scope);
|
|
937
|
-
if (keys.length === 0) return;
|
|
938
|
-
const values = keys.map(k => data[k]);
|
|
939
|
-
const changes = keys.map((key, index) => createKeyChange(scope, key, getEventRawValue(scope, key), values[index], "import", scope === _Storage.StorageScope.Memory ? "memory" : "native"));
|
|
940
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
941
|
-
keys.forEach((key, index) => {
|
|
942
|
-
memoryStore.set(key, values[index]);
|
|
943
|
-
});
|
|
944
|
-
keys.forEach(key => notifyKeyListeners(memoryListeners, key));
|
|
945
|
-
emitBatchChange(scope, "import", "memory", changes);
|
|
946
|
-
return;
|
|
947
|
-
}
|
|
948
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
949
|
-
flushSecureWrites();
|
|
950
|
-
getStorageModule().setSecureAccessControl(secureDefaultAccessControl);
|
|
951
|
-
}
|
|
952
|
-
getStorageModule().setBatch(keys, values, scope);
|
|
953
|
-
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
954
|
-
emitBatchChange(scope, "import", "native", changes);
|
|
955
|
-
}, keys.length);
|
|
956
|
-
}
|
|
252
|
+
})
|
|
957
253
|
};
|
|
254
|
+
const createStorageItem = exports.createStorageItem = core.createStorageItem;
|
|
255
|
+
const getBatch = exports.getBatch = core.getBatch;
|
|
256
|
+
const setBatch = exports.setBatch = core.setBatch;
|
|
257
|
+
const removeBatch = exports.removeBatch = core.removeBatch;
|
|
258
|
+
const registerMigration = exports.registerMigration = core.registerMigration;
|
|
259
|
+
const migrateToLatest = exports.migrateToLatest = core.migrateToLatest;
|
|
260
|
+
const runTransaction = exports.runTransaction = core.runTransaction;
|
|
261
|
+
const createSecureAuthStorage = exports.createSecureAuthStorage = core.createSecureAuthStorage;
|
|
958
262
|
function setWebSecureStorageBackend(_backend) {
|
|
959
263
|
// Native platforms do not use web secure backends.
|
|
960
264
|
}
|
|
@@ -970,788 +274,4 @@ function getWebDiskStorageBackend() {
|
|
|
970
274
|
async function flushWebStorageBackends() {
|
|
971
275
|
// Native platforms do not use web storage backends.
|
|
972
276
|
}
|
|
973
|
-
function canUseRawBatchPath(item) {
|
|
974
|
-
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true && item._secureAccessControl === undefined;
|
|
975
|
-
}
|
|
976
|
-
function canUseSecureRawBatchPath(item) {
|
|
977
|
-
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true;
|
|
978
|
-
}
|
|
979
|
-
function defaultSerialize(value) {
|
|
980
|
-
return (0, _internal.serializeWithPrimitiveFastPath)(value);
|
|
981
|
-
}
|
|
982
|
-
function defaultDeserialize(value) {
|
|
983
|
-
return (0, _internal.deserializeWithPrimitiveFastPath)(value);
|
|
984
|
-
}
|
|
985
|
-
function createStorageItem(config) {
|
|
986
|
-
const storageKey = (0, _internal.prefixKey)(config.namespace, config.key);
|
|
987
|
-
const serialize = config.serialize ?? defaultSerialize;
|
|
988
|
-
const deserialize = config.deserialize ?? defaultDeserialize;
|
|
989
|
-
const isMemory = config.scope === _Storage.StorageScope.Memory;
|
|
990
|
-
const resolvedBiometricLevel = config.scope === _Storage.StorageScope.Secure ? config.biometricLevel ?? (config.biometric === true ? _Storage.BiometricLevel.BiometryOnly : _Storage.BiometricLevel.None) : _Storage.BiometricLevel.None;
|
|
991
|
-
const isBiometric = resolvedBiometricLevel !== _Storage.BiometricLevel.None;
|
|
992
|
-
const secureAccessControl = config.accessControl;
|
|
993
|
-
const validate = config.validate;
|
|
994
|
-
const onValidationError = config.onValidationError;
|
|
995
|
-
const expiration = config.expiration;
|
|
996
|
-
const onExpired = config.onExpired;
|
|
997
|
-
const expirationTtlMs = expiration?.ttlMs;
|
|
998
|
-
const memoryExpiration = expiration && isMemory ? new Map() : null;
|
|
999
|
-
const readCache = !isMemory && config.readCache === true;
|
|
1000
|
-
const coalesceDiskWrites = config.scope === _Storage.StorageScope.Disk && config.coalesceDiskWrites === true;
|
|
1001
|
-
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true && !isBiometric;
|
|
1002
|
-
const defaultValue = config.defaultValue;
|
|
1003
|
-
const nonMemoryScope = config.scope === _Storage.StorageScope.Disk ? _Storage.StorageScope.Disk : config.scope === _Storage.StorageScope.Secure ? _Storage.StorageScope.Secure : null;
|
|
1004
|
-
if (expiration && expiration.ttlMs <= 0) {
|
|
1005
|
-
throw new Error("expiration.ttlMs must be greater than 0.");
|
|
1006
|
-
}
|
|
1007
|
-
if (config.scope === _Storage.StorageScope.Secure) {
|
|
1008
|
-
assertBiometricLevel(resolvedBiometricLevel);
|
|
1009
|
-
if (secureAccessControl !== undefined) {
|
|
1010
|
-
assertAccessControlLevel(secureAccessControl);
|
|
1011
|
-
}
|
|
1012
|
-
}
|
|
1013
|
-
const listeners = new Set();
|
|
1014
|
-
let unsubscribe = null;
|
|
1015
|
-
let lastRaw = undefined;
|
|
1016
|
-
let lastValue;
|
|
1017
|
-
let hasLastValue = false;
|
|
1018
|
-
let lastExpiresAt = undefined;
|
|
1019
|
-
const invalidateParsedCache = () => {
|
|
1020
|
-
lastRaw = undefined;
|
|
1021
|
-
lastValue = undefined;
|
|
1022
|
-
hasLastValue = false;
|
|
1023
|
-
lastExpiresAt = undefined;
|
|
1024
|
-
};
|
|
1025
|
-
const ensureSubscription = () => {
|
|
1026
|
-
if (unsubscribe) {
|
|
1027
|
-
return;
|
|
1028
|
-
}
|
|
1029
|
-
const listener = () => {
|
|
1030
|
-
invalidateParsedCache();
|
|
1031
|
-
listeners.forEach(callback => callback());
|
|
1032
|
-
};
|
|
1033
|
-
if (isMemory) {
|
|
1034
|
-
unsubscribe = addKeyListener(memoryListeners, storageKey, listener);
|
|
1035
|
-
return;
|
|
1036
|
-
}
|
|
1037
|
-
ensureNativeScopeSubscription(nonMemoryScope);
|
|
1038
|
-
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope), storageKey, listener);
|
|
1039
|
-
};
|
|
1040
|
-
const readStoredRaw = () => {
|
|
1041
|
-
if (isMemory) {
|
|
1042
|
-
if (memoryExpiration) {
|
|
1043
|
-
const expiresAt = memoryExpiration.get(storageKey);
|
|
1044
|
-
if (expiresAt !== undefined && expiresAt <= Date.now()) {
|
|
1045
|
-
memoryExpiration.delete(storageKey);
|
|
1046
|
-
memoryStore.delete(storageKey);
|
|
1047
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1048
|
-
onExpired?.(storageKey);
|
|
1049
|
-
return undefined;
|
|
1050
|
-
}
|
|
1051
|
-
}
|
|
1052
|
-
return memoryStore.get(storageKey);
|
|
1053
|
-
}
|
|
1054
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1055
|
-
const pending = pendingDiskWrites.get(storageKey);
|
|
1056
|
-
if (pending !== undefined) {
|
|
1057
|
-
return pending.value;
|
|
1058
|
-
}
|
|
1059
|
-
}
|
|
1060
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure && !isBiometric) {
|
|
1061
|
-
const pending = pendingSecureWrites.get(storageKey);
|
|
1062
|
-
if (pending !== undefined) {
|
|
1063
|
-
return pending.value;
|
|
1064
|
-
}
|
|
1065
|
-
}
|
|
1066
|
-
if (readCache) {
|
|
1067
|
-
const cache = getScopeRawCache(nonMemoryScope);
|
|
1068
|
-
const cached = cache.get(storageKey);
|
|
1069
|
-
if (cached !== undefined || cache.has(storageKey)) {
|
|
1070
|
-
return cached;
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
if (isBiometric) {
|
|
1074
|
-
return getStorageModule().getSecureBiometric(storageKey);
|
|
1075
|
-
}
|
|
1076
|
-
const raw = getStorageModule().get(storageKey, config.scope);
|
|
1077
|
-
cacheRawValue(nonMemoryScope, storageKey, raw);
|
|
1078
|
-
return raw;
|
|
1079
|
-
};
|
|
1080
|
-
const writeStoredRaw = rawValue => {
|
|
1081
|
-
const oldValue = undefined;
|
|
1082
|
-
if (isBiometric) {
|
|
1083
|
-
getStorageModule().setSecureBiometricWithLevel(storageKey, rawValue, resolvedBiometricLevel);
|
|
1084
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "native");
|
|
1085
|
-
return;
|
|
1086
|
-
}
|
|
1087
|
-
cacheRawValue(nonMemoryScope, storageKey, rawValue);
|
|
1088
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1089
|
-
if (coalesceDiskWrites || diskWritesAsync) {
|
|
1090
|
-
scheduleDiskWrite(storageKey, rawValue);
|
|
1091
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "native");
|
|
1092
|
-
return;
|
|
1093
|
-
}
|
|
1094
|
-
clearPendingDiskWrite(storageKey);
|
|
1095
|
-
}
|
|
1096
|
-
if (coalesceSecureWrites) {
|
|
1097
|
-
scheduleSecureWrite(storageKey, rawValue, secureAccessControl ?? secureDefaultAccessControl);
|
|
1098
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "native");
|
|
1099
|
-
return;
|
|
1100
|
-
}
|
|
1101
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1102
|
-
clearPendingSecureWrite(storageKey);
|
|
1103
|
-
getStorageModule().setSecureAccessControl(secureAccessControl ?? secureDefaultAccessControl);
|
|
1104
|
-
}
|
|
1105
|
-
getStorageModule().set(storageKey, rawValue, config.scope);
|
|
1106
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "native");
|
|
1107
|
-
};
|
|
1108
|
-
const removeStoredRaw = () => {
|
|
1109
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1110
|
-
if (isBiometric) {
|
|
1111
|
-
getStorageModule().deleteSecureBiometric(storageKey);
|
|
1112
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "native");
|
|
1113
|
-
return;
|
|
1114
|
-
}
|
|
1115
|
-
cacheRawValue(nonMemoryScope, storageKey, undefined);
|
|
1116
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1117
|
-
if (coalesceDiskWrites || diskWritesAsync) {
|
|
1118
|
-
scheduleDiskWrite(storageKey, undefined);
|
|
1119
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "native");
|
|
1120
|
-
return;
|
|
1121
|
-
}
|
|
1122
|
-
clearPendingDiskWrite(storageKey);
|
|
1123
|
-
}
|
|
1124
|
-
if (coalesceSecureWrites) {
|
|
1125
|
-
scheduleSecureWrite(storageKey, undefined, secureAccessControl ?? secureDefaultAccessControl);
|
|
1126
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "native");
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1130
|
-
clearPendingSecureWrite(storageKey);
|
|
1131
|
-
}
|
|
1132
|
-
getStorageModule().remove(storageKey, config.scope);
|
|
1133
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "native");
|
|
1134
|
-
};
|
|
1135
|
-
const writeValueWithoutValidation = value => {
|
|
1136
|
-
if (isMemory) {
|
|
1137
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1138
|
-
if (memoryExpiration) {
|
|
1139
|
-
memoryExpiration.set(storageKey, Date.now() + (expirationTtlMs ?? 0));
|
|
1140
|
-
}
|
|
1141
|
-
memoryStore.set(storageKey, value);
|
|
1142
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1143
|
-
emitKeyChange(config.scope, storageKey, oldValue, typeof value === "string" ? value : undefined, "set", "memory");
|
|
1144
|
-
return;
|
|
1145
|
-
}
|
|
1146
|
-
const serialized = serialize(value);
|
|
1147
|
-
if (expiration) {
|
|
1148
|
-
const envelope = {
|
|
1149
|
-
__nitroStorageEnvelope: true,
|
|
1150
|
-
expiresAt: Date.now() + expiration.ttlMs,
|
|
1151
|
-
payload: serialized
|
|
1152
|
-
};
|
|
1153
|
-
writeStoredRaw(JSON.stringify(envelope));
|
|
1154
|
-
return;
|
|
1155
|
-
}
|
|
1156
|
-
writeStoredRaw(serialized);
|
|
1157
|
-
};
|
|
1158
|
-
const resolveInvalidValue = invalidValue => {
|
|
1159
|
-
if (onValidationError) {
|
|
1160
|
-
return onValidationError(invalidValue);
|
|
1161
|
-
}
|
|
1162
|
-
return defaultValue;
|
|
1163
|
-
};
|
|
1164
|
-
const ensureValidatedValue = (candidate, hadStoredValue) => {
|
|
1165
|
-
if (!validate || validate(candidate)) {
|
|
1166
|
-
return candidate;
|
|
1167
|
-
}
|
|
1168
|
-
const resolved = resolveInvalidValue(candidate);
|
|
1169
|
-
if (validate && !validate(resolved)) {
|
|
1170
|
-
return defaultValue;
|
|
1171
|
-
}
|
|
1172
|
-
if (hadStoredValue) {
|
|
1173
|
-
writeValueWithoutValidation(resolved);
|
|
1174
|
-
}
|
|
1175
|
-
return resolved;
|
|
1176
|
-
};
|
|
1177
|
-
const getInternal = () => {
|
|
1178
|
-
const raw = readStoredRaw();
|
|
1179
|
-
if (!memoryExpiration && raw === lastRaw && hasLastValue) {
|
|
1180
|
-
if (!expiration || lastExpiresAt === null) {
|
|
1181
|
-
return lastValue;
|
|
1182
|
-
}
|
|
1183
|
-
if (typeof lastExpiresAt === "number") {
|
|
1184
|
-
if (lastExpiresAt > Date.now()) {
|
|
1185
|
-
return lastValue;
|
|
1186
|
-
}
|
|
1187
|
-
removeStoredRaw();
|
|
1188
|
-
invalidateParsedCache();
|
|
1189
|
-
onExpired?.(storageKey);
|
|
1190
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1191
|
-
hasLastValue = true;
|
|
1192
|
-
listeners.forEach(cb => cb());
|
|
1193
|
-
return lastValue;
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
lastRaw = raw;
|
|
1197
|
-
if (raw === undefined) {
|
|
1198
|
-
lastExpiresAt = undefined;
|
|
1199
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1200
|
-
hasLastValue = true;
|
|
1201
|
-
return lastValue;
|
|
1202
|
-
}
|
|
1203
|
-
if (isMemory) {
|
|
1204
|
-
lastExpiresAt = undefined;
|
|
1205
|
-
lastValue = ensureValidatedValue(raw, true);
|
|
1206
|
-
hasLastValue = true;
|
|
1207
|
-
return lastValue;
|
|
1208
|
-
}
|
|
1209
|
-
if (typeof raw !== "string") {
|
|
1210
|
-
lastExpiresAt = undefined;
|
|
1211
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1212
|
-
hasLastValue = true;
|
|
1213
|
-
return lastValue;
|
|
1214
|
-
}
|
|
1215
|
-
let deserializableRaw = raw;
|
|
1216
|
-
if (expiration) {
|
|
1217
|
-
let envelopeExpiresAt = null;
|
|
1218
|
-
try {
|
|
1219
|
-
const parsed = JSON.parse(raw);
|
|
1220
|
-
if ((0, _internal.isStoredEnvelope)(parsed)) {
|
|
1221
|
-
envelopeExpiresAt = parsed.expiresAt;
|
|
1222
|
-
if (parsed.expiresAt <= Date.now()) {
|
|
1223
|
-
removeStoredRaw();
|
|
1224
|
-
invalidateParsedCache();
|
|
1225
|
-
onExpired?.(storageKey);
|
|
1226
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1227
|
-
hasLastValue = true;
|
|
1228
|
-
listeners.forEach(cb => cb());
|
|
1229
|
-
return lastValue;
|
|
1230
|
-
}
|
|
1231
|
-
deserializableRaw = parsed.payload;
|
|
1232
|
-
}
|
|
1233
|
-
} catch {
|
|
1234
|
-
// Keep backward compatibility with legacy raw values.
|
|
1235
|
-
}
|
|
1236
|
-
lastExpiresAt = envelopeExpiresAt;
|
|
1237
|
-
} else {
|
|
1238
|
-
lastExpiresAt = undefined;
|
|
1239
|
-
}
|
|
1240
|
-
lastValue = ensureValidatedValue(deserialize(deserializableRaw), true);
|
|
1241
|
-
hasLastValue = true;
|
|
1242
|
-
return lastValue;
|
|
1243
|
-
};
|
|
1244
|
-
const getCurrentVersion = () => {
|
|
1245
|
-
const raw = readStoredRaw();
|
|
1246
|
-
return (0, _internal.toVersionToken)(raw);
|
|
1247
|
-
};
|
|
1248
|
-
const get = () => measureOperation("item:get", config.scope, () => getInternal());
|
|
1249
|
-
const getWithVersion = () => measureOperation("item:getWithVersion", config.scope, () => ({
|
|
1250
|
-
value: getInternal(),
|
|
1251
|
-
version: getCurrentVersion()
|
|
1252
|
-
}));
|
|
1253
|
-
const set = valueOrFn => {
|
|
1254
|
-
measureOperation("item:set", config.scope, () => {
|
|
1255
|
-
const newValue = isUpdater(valueOrFn) ? valueOrFn(getInternal()) : valueOrFn;
|
|
1256
|
-
if (validate && !validate(newValue)) {
|
|
1257
|
-
throw new Error(`Validation failed for key "${storageKey}" in scope "${_Storage.StorageScope[config.scope]}".`);
|
|
1258
|
-
}
|
|
1259
|
-
invalidateParsedCache();
|
|
1260
|
-
writeValueWithoutValidation(newValue);
|
|
1261
|
-
});
|
|
1262
|
-
};
|
|
1263
|
-
const setIfVersion = (version, valueOrFn) => measureOperation("item:setIfVersion", config.scope, () => {
|
|
1264
|
-
const currentVersion = getCurrentVersion();
|
|
1265
|
-
if (currentVersion !== version) {
|
|
1266
|
-
return false;
|
|
1267
|
-
}
|
|
1268
|
-
set(valueOrFn);
|
|
1269
|
-
return true;
|
|
1270
|
-
});
|
|
1271
|
-
const deleteItem = () => {
|
|
1272
|
-
measureOperation("item:delete", config.scope, () => {
|
|
1273
|
-
invalidateParsedCache();
|
|
1274
|
-
if (isMemory) {
|
|
1275
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1276
|
-
if (memoryExpiration) {
|
|
1277
|
-
memoryExpiration.delete(storageKey);
|
|
1278
|
-
}
|
|
1279
|
-
memoryStore.delete(storageKey);
|
|
1280
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1281
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "memory");
|
|
1282
|
-
return;
|
|
1283
|
-
}
|
|
1284
|
-
removeStoredRaw();
|
|
1285
|
-
});
|
|
1286
|
-
};
|
|
1287
|
-
const hasItem = () => measureOperation("item:has", config.scope, () => {
|
|
1288
|
-
if (isMemory) return memoryStore.has(storageKey);
|
|
1289
|
-
if (isBiometric) return getStorageModule().hasSecureBiometric(storageKey);
|
|
1290
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1291
|
-
const pending = pendingDiskWrites.get(storageKey);
|
|
1292
|
-
if (pending !== undefined) {
|
|
1293
|
-
return pending.value !== undefined;
|
|
1294
|
-
}
|
|
1295
|
-
}
|
|
1296
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1297
|
-
const pending = pendingSecureWrites.get(storageKey);
|
|
1298
|
-
if (pending !== undefined) {
|
|
1299
|
-
return pending.value !== undefined;
|
|
1300
|
-
}
|
|
1301
|
-
}
|
|
1302
|
-
return getStorageModule().has(storageKey, config.scope);
|
|
1303
|
-
});
|
|
1304
|
-
const subscribe = callback => {
|
|
1305
|
-
ensureSubscription();
|
|
1306
|
-
listeners.add(callback);
|
|
1307
|
-
return () => {
|
|
1308
|
-
listeners.delete(callback);
|
|
1309
|
-
if (listeners.size === 0 && unsubscribe) {
|
|
1310
|
-
unsubscribe();
|
|
1311
|
-
if (!isMemory) {
|
|
1312
|
-
maybeCleanupNativeScopeSubscription(nonMemoryScope);
|
|
1313
|
-
}
|
|
1314
|
-
unsubscribe = null;
|
|
1315
|
-
}
|
|
1316
|
-
};
|
|
1317
|
-
};
|
|
1318
|
-
const subscribeSelector = (selector, listener, options = {}) => {
|
|
1319
|
-
const isEqual = options.isEqual ?? Object.is;
|
|
1320
|
-
let currentValue = selector(getInternal());
|
|
1321
|
-
if (options.fireImmediately === true) {
|
|
1322
|
-
listener(currentValue, currentValue);
|
|
1323
|
-
}
|
|
1324
|
-
return subscribe(() => {
|
|
1325
|
-
const nextValue = selector(getInternal());
|
|
1326
|
-
if (isEqual(currentValue, nextValue)) {
|
|
1327
|
-
return;
|
|
1328
|
-
}
|
|
1329
|
-
const previousValue = currentValue;
|
|
1330
|
-
currentValue = nextValue;
|
|
1331
|
-
listener(nextValue, previousValue);
|
|
1332
|
-
});
|
|
1333
|
-
};
|
|
1334
|
-
const storageItem = {
|
|
1335
|
-
get,
|
|
1336
|
-
getWithVersion,
|
|
1337
|
-
set,
|
|
1338
|
-
setIfVersion,
|
|
1339
|
-
delete: deleteItem,
|
|
1340
|
-
has: hasItem,
|
|
1341
|
-
subscribe,
|
|
1342
|
-
subscribeSelector,
|
|
1343
|
-
serialize,
|
|
1344
|
-
deserialize,
|
|
1345
|
-
_triggerListeners: () => {
|
|
1346
|
-
invalidateParsedCache();
|
|
1347
|
-
listeners.forEach(listener => listener());
|
|
1348
|
-
},
|
|
1349
|
-
_invalidateParsedCacheOnly: () => {
|
|
1350
|
-
invalidateParsedCache();
|
|
1351
|
-
},
|
|
1352
|
-
_hasValidation: validate !== undefined,
|
|
1353
|
-
_hasExpiration: expiration !== undefined,
|
|
1354
|
-
_readCacheEnabled: readCache,
|
|
1355
|
-
_isBiometric: isBiometric,
|
|
1356
|
-
_biometricLevel: resolvedBiometricLevel,
|
|
1357
|
-
_defaultValue: defaultValue,
|
|
1358
|
-
...(secureAccessControl !== undefined ? {
|
|
1359
|
-
_secureAccessControl: secureAccessControl
|
|
1360
|
-
} : {}),
|
|
1361
|
-
scope: config.scope,
|
|
1362
|
-
key: storageKey
|
|
1363
|
-
};
|
|
1364
|
-
return storageItem;
|
|
1365
|
-
}
|
|
1366
|
-
function getBatch(items, scope) {
|
|
1367
|
-
return measureOperation("batch:get", scope, () => {
|
|
1368
|
-
(0, _internal.assertBatchScope)(items, scope);
|
|
1369
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1370
|
-
return items.map(item => item.get());
|
|
1371
|
-
}
|
|
1372
|
-
const useRawBatchPath = items.every(item => scope === _Storage.StorageScope.Secure ? canUseSecureRawBatchPath(item) : canUseRawBatchPath(item));
|
|
1373
|
-
if (!useRawBatchPath) {
|
|
1374
|
-
return items.map(item => item.get());
|
|
1375
|
-
}
|
|
1376
|
-
const rawValues = new Array(items.length);
|
|
1377
|
-
const keysToFetch = [];
|
|
1378
|
-
const keyIndexes = [];
|
|
1379
|
-
items.forEach((item, index) => {
|
|
1380
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1381
|
-
const pending = pendingDiskWrites.get(item.key);
|
|
1382
|
-
if (pending !== undefined) {
|
|
1383
|
-
rawValues[index] = pending.value;
|
|
1384
|
-
return;
|
|
1385
|
-
}
|
|
1386
|
-
}
|
|
1387
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1388
|
-
const pending = pendingSecureWrites.get(item.key);
|
|
1389
|
-
if (pending !== undefined) {
|
|
1390
|
-
rawValues[index] = pending.value;
|
|
1391
|
-
return;
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
if (item._readCacheEnabled === true) {
|
|
1395
|
-
const cache = getScopeRawCache(scope);
|
|
1396
|
-
const cached = cache.get(item.key);
|
|
1397
|
-
if (cached !== undefined || cache.has(item.key)) {
|
|
1398
|
-
rawValues[index] = cached;
|
|
1399
|
-
return;
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
keysToFetch.push(item.key);
|
|
1403
|
-
keyIndexes.push(index);
|
|
1404
|
-
});
|
|
1405
|
-
if (keysToFetch.length > 0) {
|
|
1406
|
-
const fetchedValues = getStorageModule().getBatch(keysToFetch, scope).map(value => (0, _internal.decodeNativeBatchValue)(value));
|
|
1407
|
-
fetchedValues.forEach((value, index) => {
|
|
1408
|
-
const key = keysToFetch[index];
|
|
1409
|
-
const targetIndex = keyIndexes[index];
|
|
1410
|
-
if (key === undefined || targetIndex === undefined) {
|
|
1411
|
-
return;
|
|
1412
|
-
}
|
|
1413
|
-
rawValues[targetIndex] = value;
|
|
1414
|
-
cacheRawValue(scope, key, value);
|
|
1415
|
-
});
|
|
1416
|
-
}
|
|
1417
|
-
return items.map((item, index) => {
|
|
1418
|
-
const raw = rawValues[index];
|
|
1419
|
-
if (raw === undefined) {
|
|
1420
|
-
return asInternal(item)._defaultValue;
|
|
1421
|
-
}
|
|
1422
|
-
return item.deserialize(raw);
|
|
1423
|
-
});
|
|
1424
|
-
}, items.length);
|
|
1425
|
-
}
|
|
1426
|
-
function setBatch(items, scope) {
|
|
1427
|
-
measureOperation("batch:set", scope, () => {
|
|
1428
|
-
(0, _internal.assertBatchScope)(items.map(batchEntry => batchEntry.item), scope);
|
|
1429
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1430
|
-
// Determine if any item needs per-item handling (validation or TTL)
|
|
1431
|
-
const needsIndividualSets = items.some(({
|
|
1432
|
-
item
|
|
1433
|
-
}) => {
|
|
1434
|
-
const internal = asInternal(item);
|
|
1435
|
-
return internal._hasValidation || internal._hasExpiration;
|
|
1436
|
-
});
|
|
1437
|
-
if (needsIndividualSets) {
|
|
1438
|
-
// Fall back to individual sets to preserve validation and TTL semantics
|
|
1439
|
-
items.forEach(({
|
|
1440
|
-
item,
|
|
1441
|
-
value
|
|
1442
|
-
}) => item.set(value));
|
|
1443
|
-
return;
|
|
1444
|
-
}
|
|
1445
|
-
const changes = items.map(({
|
|
1446
|
-
item,
|
|
1447
|
-
value
|
|
1448
|
-
}) => createKeyChange(scope, item.key, getEventRawValue(scope, item.key), typeof value === "string" ? value : undefined, "setBatch", "memory"));
|
|
1449
|
-
|
|
1450
|
-
// Atomic write: update all values in memoryStore, invalidate caches, then batch-notify
|
|
1451
|
-
items.forEach(({
|
|
1452
|
-
item,
|
|
1453
|
-
value
|
|
1454
|
-
}) => {
|
|
1455
|
-
memoryStore.set(item.key, value);
|
|
1456
|
-
asInternal(item)._invalidateParsedCacheOnly();
|
|
1457
|
-
});
|
|
1458
|
-
items.forEach(({
|
|
1459
|
-
item
|
|
1460
|
-
}) => notifyKeyListeners(memoryListeners, item.key));
|
|
1461
|
-
emitBatchChange(scope, "setBatch", "memory", changes);
|
|
1462
|
-
return;
|
|
1463
|
-
}
|
|
1464
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1465
|
-
const secureEntries = items.map(({
|
|
1466
|
-
item,
|
|
1467
|
-
value
|
|
1468
|
-
}) => ({
|
|
1469
|
-
item,
|
|
1470
|
-
value,
|
|
1471
|
-
internal: asInternal(item)
|
|
1472
|
-
}));
|
|
1473
|
-
const canUseSecureBatchPath = secureEntries.every(({
|
|
1474
|
-
internal
|
|
1475
|
-
}) => canUseSecureRawBatchPath(internal));
|
|
1476
|
-
if (!canUseSecureBatchPath) {
|
|
1477
|
-
items.forEach(({
|
|
1478
|
-
item,
|
|
1479
|
-
value
|
|
1480
|
-
}) => item.set(value));
|
|
1481
|
-
return;
|
|
1482
|
-
}
|
|
1483
|
-
flushSecureWrites();
|
|
1484
|
-
const storageModule = getStorageModule();
|
|
1485
|
-
const keys = secureEntries.map(({
|
|
1486
|
-
item
|
|
1487
|
-
}) => item.key);
|
|
1488
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? storageModule.getBatch(keys, scope) ?? [] : [];
|
|
1489
|
-
const groupedByAccessControl = new Map();
|
|
1490
|
-
secureEntries.forEach(({
|
|
1491
|
-
item,
|
|
1492
|
-
value,
|
|
1493
|
-
internal
|
|
1494
|
-
}) => {
|
|
1495
|
-
const accessControl = internal._secureAccessControl ?? secureDefaultAccessControl;
|
|
1496
|
-
const existingGroup = groupedByAccessControl.get(accessControl);
|
|
1497
|
-
const group = existingGroup ?? {
|
|
1498
|
-
keys: [],
|
|
1499
|
-
values: []
|
|
1500
|
-
};
|
|
1501
|
-
group.keys.push(item.key);
|
|
1502
|
-
group.values.push(item.serialize(value));
|
|
1503
|
-
if (!existingGroup) {
|
|
1504
|
-
groupedByAccessControl.set(accessControl, group);
|
|
1505
|
-
}
|
|
1506
|
-
});
|
|
1507
|
-
groupedByAccessControl.forEach((group, accessControl) => {
|
|
1508
|
-
storageModule.setSecureAccessControl(accessControl);
|
|
1509
|
-
storageModule.setBatch(group.keys, group.values, scope);
|
|
1510
|
-
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
1511
|
-
});
|
|
1512
|
-
emitBatchChange(scope, "setBatch", "native", secureEntries.map(({
|
|
1513
|
-
item,
|
|
1514
|
-
value
|
|
1515
|
-
}, index) => createKeyChange(scope, item.key, oldValues[index], item.serialize(value), "setBatch", "native")));
|
|
1516
|
-
return;
|
|
1517
|
-
}
|
|
1518
|
-
flushDiskWrites();
|
|
1519
|
-
const useRawBatchPath = items.every(({
|
|
1520
|
-
item
|
|
1521
|
-
}) => canUseRawBatchPath(asInternal(item)));
|
|
1522
|
-
if (!useRawBatchPath) {
|
|
1523
|
-
items.forEach(({
|
|
1524
|
-
item,
|
|
1525
|
-
value
|
|
1526
|
-
}) => item.set(value));
|
|
1527
|
-
return;
|
|
1528
|
-
}
|
|
1529
|
-
const keys = items.map(entry => entry.item.key);
|
|
1530
|
-
const values = items.map(entry => entry.item.serialize(entry.value));
|
|
1531
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? getStorageModule().getBatch(keys, scope) ?? [] : [];
|
|
1532
|
-
getStorageModule().setBatch(keys, values, scope);
|
|
1533
|
-
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
1534
|
-
emitBatchChange(scope, "setBatch", "native", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], values[index], "setBatch", "native")));
|
|
1535
|
-
}, items.length);
|
|
1536
|
-
}
|
|
1537
|
-
function removeBatch(items, scope) {
|
|
1538
|
-
measureOperation("batch:remove", scope, () => {
|
|
1539
|
-
(0, _internal.assertBatchScope)(items, scope);
|
|
1540
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1541
|
-
const changes = items.map(item => createKeyChange(scope, item.key, getEventRawValue(scope, item.key), undefined, "removeBatch", "memory"));
|
|
1542
|
-
items.forEach(item => item.delete());
|
|
1543
|
-
emitBatchChange(scope, "removeBatch", "memory", changes);
|
|
1544
|
-
return;
|
|
1545
|
-
}
|
|
1546
|
-
const keys = items.map(item => item.key);
|
|
1547
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1548
|
-
flushDiskWrites();
|
|
1549
|
-
}
|
|
1550
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1551
|
-
flushSecureWrites();
|
|
1552
|
-
}
|
|
1553
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? getStorageModule().getBatch(keys, scope) ?? [] : [];
|
|
1554
|
-
getStorageModule().removeBatch(keys, scope);
|
|
1555
|
-
keys.forEach(key => cacheRawValue(scope, key, undefined));
|
|
1556
|
-
emitBatchChange(scope, "removeBatch", "native", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], undefined, "removeBatch", "native")));
|
|
1557
|
-
}, items.length);
|
|
1558
|
-
}
|
|
1559
|
-
function registerMigration(version, migration) {
|
|
1560
|
-
if (!Number.isInteger(version) || version <= 0) {
|
|
1561
|
-
throw new Error("Migration version must be a positive integer.");
|
|
1562
|
-
}
|
|
1563
|
-
if (registeredMigrations.has(version)) {
|
|
1564
|
-
throw new Error(`Migration version ${version} is already registered.`);
|
|
1565
|
-
}
|
|
1566
|
-
registeredMigrations.set(version, migration);
|
|
1567
|
-
}
|
|
1568
|
-
function migrateToLatest(scope = _Storage.StorageScope.Disk) {
|
|
1569
|
-
return measureOperation("migration:run", scope, () => {
|
|
1570
|
-
(0, _internal.assertValidScope)(scope);
|
|
1571
|
-
const currentVersion = readMigrationVersion(scope);
|
|
1572
|
-
const versions = Array.from(registeredMigrations.keys()).filter(version => version > currentVersion).sort((a, b) => a - b);
|
|
1573
|
-
let appliedVersion = currentVersion;
|
|
1574
|
-
const context = {
|
|
1575
|
-
scope,
|
|
1576
|
-
getRaw: key => getRawValue(key, scope),
|
|
1577
|
-
setRaw: (key, value) => setRawValue(key, value, scope),
|
|
1578
|
-
removeRaw: key => removeRawValue(key, scope)
|
|
1579
|
-
};
|
|
1580
|
-
versions.forEach(version => {
|
|
1581
|
-
const migration = registeredMigrations.get(version);
|
|
1582
|
-
if (!migration) {
|
|
1583
|
-
return;
|
|
1584
|
-
}
|
|
1585
|
-
migration(context);
|
|
1586
|
-
appliedVersion = version;
|
|
1587
|
-
});
|
|
1588
|
-
if (appliedVersion !== currentVersion) {
|
|
1589
|
-
writeMigrationVersion(scope, appliedVersion);
|
|
1590
|
-
}
|
|
1591
|
-
return appliedVersion;
|
|
1592
|
-
});
|
|
1593
|
-
}
|
|
1594
|
-
function runTransaction(scope, transaction) {
|
|
1595
|
-
return measureOperation("transaction:run", scope, () => {
|
|
1596
|
-
(0, _internal.assertValidScope)(scope);
|
|
1597
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1598
|
-
flushDiskWrites();
|
|
1599
|
-
}
|
|
1600
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1601
|
-
flushSecureWrites();
|
|
1602
|
-
}
|
|
1603
|
-
const NOT_SET = Symbol();
|
|
1604
|
-
const rollback = new Map();
|
|
1605
|
-
const rememberRollback = (key, item) => {
|
|
1606
|
-
if (rollback.has(key)) {
|
|
1607
|
-
return;
|
|
1608
|
-
}
|
|
1609
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1610
|
-
rollback.set(key, {
|
|
1611
|
-
kind: "memory",
|
|
1612
|
-
value: memoryStore.has(key) ? memoryStore.get(key) : NOT_SET
|
|
1613
|
-
});
|
|
1614
|
-
} else {
|
|
1615
|
-
const internal = item ? item : undefined;
|
|
1616
|
-
if (scope === _Storage.StorageScope.Secure && internal?._isBiometric === true) {
|
|
1617
|
-
rollback.set(key, {
|
|
1618
|
-
kind: "biometric",
|
|
1619
|
-
value: getStorageModule().getSecureBiometric(key),
|
|
1620
|
-
level: internal._biometricLevel
|
|
1621
|
-
});
|
|
1622
|
-
return;
|
|
1623
|
-
}
|
|
1624
|
-
rollback.set(key, {
|
|
1625
|
-
kind: "raw",
|
|
1626
|
-
value: getRawValue(key, scope),
|
|
1627
|
-
...(scope === _Storage.StorageScope.Secure && internal?._secureAccessControl !== undefined ? {
|
|
1628
|
-
accessControl: internal._secureAccessControl
|
|
1629
|
-
} : {})
|
|
1630
|
-
});
|
|
1631
|
-
}
|
|
1632
|
-
};
|
|
1633
|
-
const tx = {
|
|
1634
|
-
scope,
|
|
1635
|
-
getRaw: key => getRawValue(key, scope),
|
|
1636
|
-
setRaw: (key, value) => {
|
|
1637
|
-
rememberRollback(key);
|
|
1638
|
-
setRawValue(key, value, scope);
|
|
1639
|
-
},
|
|
1640
|
-
removeRaw: key => {
|
|
1641
|
-
rememberRollback(key);
|
|
1642
|
-
removeRawValue(key, scope);
|
|
1643
|
-
},
|
|
1644
|
-
getItem: item => {
|
|
1645
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1646
|
-
return item.get();
|
|
1647
|
-
},
|
|
1648
|
-
setItem: (item, value) => {
|
|
1649
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1650
|
-
rememberRollback(item.key, item);
|
|
1651
|
-
item.set(value);
|
|
1652
|
-
},
|
|
1653
|
-
removeItem: item => {
|
|
1654
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1655
|
-
rememberRollback(item.key, item);
|
|
1656
|
-
item.delete();
|
|
1657
|
-
}
|
|
1658
|
-
};
|
|
1659
|
-
try {
|
|
1660
|
-
return transaction(tx);
|
|
1661
|
-
} catch (error) {
|
|
1662
|
-
const rollbackEntries = Array.from(rollback.entries()).reverse();
|
|
1663
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1664
|
-
rollbackEntries.forEach(([key, record]) => {
|
|
1665
|
-
if (record.value === NOT_SET) {
|
|
1666
|
-
memoryStore.delete(key);
|
|
1667
|
-
} else {
|
|
1668
|
-
memoryStore.set(key, record.value);
|
|
1669
|
-
}
|
|
1670
|
-
notifyKeyListeners(memoryListeners, key);
|
|
1671
|
-
});
|
|
1672
|
-
} else {
|
|
1673
|
-
const groupedKeysToSet = new Map();
|
|
1674
|
-
const keysToRemove = [];
|
|
1675
|
-
rollbackEntries.forEach(([key, record]) => {
|
|
1676
|
-
if (record.kind === "biometric") {
|
|
1677
|
-
if (record.value === undefined) {
|
|
1678
|
-
getStorageModule().deleteSecureBiometric(key);
|
|
1679
|
-
} else {
|
|
1680
|
-
getStorageModule().setSecureBiometricWithLevel(key, record.value, record.level);
|
|
1681
|
-
}
|
|
1682
|
-
return;
|
|
1683
|
-
}
|
|
1684
|
-
if (record.kind !== "raw") {
|
|
1685
|
-
return;
|
|
1686
|
-
}
|
|
1687
|
-
if (record.value === undefined) {
|
|
1688
|
-
keysToRemove.push(key);
|
|
1689
|
-
} else {
|
|
1690
|
-
const accessControl = record.accessControl ?? secureDefaultAccessControl;
|
|
1691
|
-
const existingGroup = groupedKeysToSet.get(accessControl);
|
|
1692
|
-
const group = existingGroup ?? {
|
|
1693
|
-
keys: [],
|
|
1694
|
-
values: []
|
|
1695
|
-
};
|
|
1696
|
-
group.keys.push(key);
|
|
1697
|
-
group.values.push(record.value);
|
|
1698
|
-
if (!existingGroup) {
|
|
1699
|
-
groupedKeysToSet.set(accessControl, group);
|
|
1700
|
-
}
|
|
1701
|
-
}
|
|
1702
|
-
});
|
|
1703
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1704
|
-
flushDiskWrites();
|
|
1705
|
-
}
|
|
1706
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1707
|
-
flushSecureWrites();
|
|
1708
|
-
}
|
|
1709
|
-
groupedKeysToSet.forEach((group, accessControl) => {
|
|
1710
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1711
|
-
getStorageModule().setSecureAccessControl(accessControl);
|
|
1712
|
-
}
|
|
1713
|
-
getStorageModule().setBatch(group.keys, group.values, scope);
|
|
1714
|
-
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
1715
|
-
});
|
|
1716
|
-
if (keysToRemove.length > 0) {
|
|
1717
|
-
getStorageModule().removeBatch(keysToRemove, scope);
|
|
1718
|
-
keysToRemove.forEach(key => cacheRawValue(scope, key, undefined));
|
|
1719
|
-
}
|
|
1720
|
-
}
|
|
1721
|
-
throw error;
|
|
1722
|
-
}
|
|
1723
|
-
});
|
|
1724
|
-
}
|
|
1725
|
-
function isKeychainLockedError(err) {
|
|
1726
|
-
return (0, _storageRuntime.isLockedStorageErrorCode)((0, _storageRuntime.getStorageErrorCode)(err));
|
|
1727
|
-
}
|
|
1728
|
-
function createSecureAuthStorage(config, options) {
|
|
1729
|
-
const ns = options?.namespace ?? "auth";
|
|
1730
|
-
const result = {};
|
|
1731
|
-
for (const key of typedKeys(config)) {
|
|
1732
|
-
const itemConfig = config[key];
|
|
1733
|
-
const expirationConfig = itemConfig.ttlMs !== undefined ? {
|
|
1734
|
-
ttlMs: itemConfig.ttlMs
|
|
1735
|
-
} : undefined;
|
|
1736
|
-
result[key] = createStorageItem({
|
|
1737
|
-
key,
|
|
1738
|
-
scope: _Storage.StorageScope.Secure,
|
|
1739
|
-
defaultValue: "",
|
|
1740
|
-
namespace: ns,
|
|
1741
|
-
...(itemConfig.biometric !== undefined ? {
|
|
1742
|
-
biometric: itemConfig.biometric
|
|
1743
|
-
} : {}),
|
|
1744
|
-
...(itemConfig.biometricLevel !== undefined ? {
|
|
1745
|
-
biometricLevel: itemConfig.biometricLevel
|
|
1746
|
-
} : {}),
|
|
1747
|
-
...(itemConfig.accessControl !== undefined ? {
|
|
1748
|
-
accessControl: itemConfig.accessControl
|
|
1749
|
-
} : {}),
|
|
1750
|
-
...(expirationConfig !== undefined ? {
|
|
1751
|
-
expiration: expirationConfig
|
|
1752
|
-
} : {})
|
|
1753
|
-
});
|
|
1754
|
-
}
|
|
1755
|
-
return result;
|
|
1756
|
-
}
|
|
1757
277
|
//# sourceMappingURL=index.js.map
|