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
|
@@ -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,94 +72,21 @@ Object.defineProperty(exports, "useStorageSelector", {
|
|
|
72
72
|
return _storageHooks.useStorageSelector;
|
|
73
73
|
}
|
|
74
74
|
});
|
|
75
|
+
var _shared = require("./shared");
|
|
75
76
|
var _Storage = require("./Storage.types");
|
|
76
|
-
var _internal = require("./internal");
|
|
77
77
|
var _webStorageBackend = require("./web-storage-backend");
|
|
78
|
-
var
|
|
79
|
-
var _storageEvents = require("./storage-events");
|
|
78
|
+
var _storageCore = require("./storage-core");
|
|
80
79
|
var _migration = require("./migration");
|
|
80
|
+
var _storageRuntime = require("./storage-runtime");
|
|
81
81
|
var _storageHooks = require("./storage-hooks");
|
|
82
82
|
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
|
-
const memoryStore = new Map();
|
|
112
|
-
const memoryListeners = new Map();
|
|
113
|
-
const webScopeListeners = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
114
|
-
const scopedRawCache = new Map([[_Storage.StorageScope.Disk, new Map()], [_Storage.StorageScope.Secure, new Map()]]);
|
|
115
83
|
const webScopeKeyIndex = new Map([[_Storage.StorageScope.Disk, new Set()], [_Storage.StorageScope.Secure, new Set()]]);
|
|
116
84
|
const hydratedWebScopeKeyIndex = new Set();
|
|
117
|
-
const pendingDiskWrites = new Map();
|
|
118
|
-
let diskFlushScheduled = false;
|
|
119
|
-
let diskWritesAsync = false;
|
|
120
|
-
const pendingSecureWrites = new Map();
|
|
121
|
-
let secureFlushScheduled = false;
|
|
122
|
-
let secureDefaultAccessControl = _Storage.AccessControl.WhenUnlocked;
|
|
123
85
|
const SECURE_WEB_PREFIX = "__secure_";
|
|
124
86
|
const BIOMETRIC_WEB_PREFIX = "__bio_";
|
|
125
87
|
let hasWarnedAboutWebBiometricFallback = false;
|
|
126
88
|
let hasWindowStorageEventSubscription = false;
|
|
127
|
-
let
|
|
128
|
-
let eventObserver;
|
|
129
|
-
let eventObserverRedactSecureValues = true;
|
|
130
|
-
const metricsCounters = new Map();
|
|
131
|
-
const storageEvents = new _storageEvents.StorageEventRegistry();
|
|
132
|
-
function recordMetric(operation, scope, durationMs, keysCount = 1) {
|
|
133
|
-
const existing = metricsCounters.get(operation);
|
|
134
|
-
if (!existing) {
|
|
135
|
-
metricsCounters.set(operation, {
|
|
136
|
-
count: 1,
|
|
137
|
-
totalDurationMs: durationMs,
|
|
138
|
-
maxDurationMs: durationMs
|
|
139
|
-
});
|
|
140
|
-
} else {
|
|
141
|
-
existing.count += 1;
|
|
142
|
-
existing.totalDurationMs += durationMs;
|
|
143
|
-
existing.maxDurationMs = Math.max(existing.maxDurationMs, durationMs);
|
|
144
|
-
}
|
|
145
|
-
metricsObserver?.({
|
|
146
|
-
operation,
|
|
147
|
-
scope,
|
|
148
|
-
durationMs,
|
|
149
|
-
keysCount
|
|
150
|
-
});
|
|
151
|
-
}
|
|
152
|
-
function measureOperation(operation, scope, fn, keysCount = 1) {
|
|
153
|
-
if (!metricsObserver) {
|
|
154
|
-
return fn();
|
|
155
|
-
}
|
|
156
|
-
const start = now();
|
|
157
|
-
try {
|
|
158
|
-
return fn();
|
|
159
|
-
} finally {
|
|
160
|
-
recordMetric(operation, scope, now() - start, keysCount);
|
|
161
|
-
}
|
|
162
|
-
}
|
|
89
|
+
let internals;
|
|
163
90
|
function createDefaultDiskBackend() {
|
|
164
91
|
return (0, _webStorageBackend.createLocalStorageWebBackend)({
|
|
165
92
|
name: "localStorage:disk",
|
|
@@ -246,51 +173,51 @@ function ensureWebScopeKeyIndex(scope) {
|
|
|
246
173
|
}
|
|
247
174
|
function applyExternalChangeEvent(scope, key, newValue) {
|
|
248
175
|
if (key === null) {
|
|
249
|
-
clearScopeRawCache(scope);
|
|
176
|
+
internals.clearScopeRawCache(scope);
|
|
250
177
|
ensureWebScopeKeyIndex(scope).clear();
|
|
251
|
-
notifyAllListeners(getScopedListeners(scope));
|
|
178
|
+
(0, _shared.notifyAllListeners)(internals.getScopedListeners(scope));
|
|
252
179
|
return;
|
|
253
180
|
}
|
|
254
181
|
if (scope === _Storage.StorageScope.Secure && key.startsWith(SECURE_WEB_PREFIX)) {
|
|
255
182
|
const plainKey = fromSecureStorageKey(key);
|
|
256
|
-
const oldValue = readCachedRawValue(_Storage.StorageScope.Secure, plainKey);
|
|
183
|
+
const oldValue = internals.readCachedRawValue(_Storage.StorageScope.Secure, plainKey);
|
|
257
184
|
if (newValue === null) {
|
|
258
185
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).delete(plainKey);
|
|
259
|
-
cacheRawValue(_Storage.StorageScope.Secure, plainKey, undefined);
|
|
186
|
+
internals.cacheRawValue(_Storage.StorageScope.Secure, plainKey, undefined);
|
|
260
187
|
} else {
|
|
261
188
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).add(plainKey);
|
|
262
|
-
cacheRawValue(_Storage.StorageScope.Secure, plainKey, newValue);
|
|
189
|
+
internals.cacheRawValue(_Storage.StorageScope.Secure, plainKey, newValue);
|
|
263
190
|
}
|
|
264
|
-
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), plainKey);
|
|
265
|
-
emitKeyChange(_Storage.StorageScope.Secure, plainKey, oldValue, newValue ?? undefined, "external", "external");
|
|
191
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(_Storage.StorageScope.Secure), plainKey);
|
|
192
|
+
internals.emitKeyChange(_Storage.StorageScope.Secure, plainKey, oldValue, newValue ?? undefined, "external", "external");
|
|
266
193
|
return;
|
|
267
194
|
}
|
|
268
195
|
if (scope === _Storage.StorageScope.Secure && key.startsWith(BIOMETRIC_WEB_PREFIX)) {
|
|
269
196
|
const plainKey = fromBiometricStorageKey(key);
|
|
270
|
-
const oldValue = readCachedRawValue(_Storage.StorageScope.Secure, plainKey);
|
|
197
|
+
const oldValue = internals.readCachedRawValue(_Storage.StorageScope.Secure, plainKey);
|
|
271
198
|
if (newValue === null) {
|
|
272
199
|
if (withWebBackendOperation(_Storage.StorageScope.Secure, "external-sync:getItem", backend => backend.getItem(toSecureStorageKey(plainKey))) === null) {
|
|
273
200
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).delete(plainKey);
|
|
274
201
|
}
|
|
275
|
-
cacheRawValue(_Storage.StorageScope.Secure, plainKey, undefined);
|
|
202
|
+
internals.cacheRawValue(_Storage.StorageScope.Secure, plainKey, undefined);
|
|
276
203
|
} else {
|
|
277
204
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).add(plainKey);
|
|
278
|
-
cacheRawValue(_Storage.StorageScope.Secure, plainKey, newValue);
|
|
205
|
+
internals.cacheRawValue(_Storage.StorageScope.Secure, plainKey, newValue);
|
|
279
206
|
}
|
|
280
|
-
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), plainKey);
|
|
281
|
-
emitKeyChange(_Storage.StorageScope.Secure, plainKey, oldValue, newValue ?? undefined, "external", "external");
|
|
207
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(_Storage.StorageScope.Secure), plainKey);
|
|
208
|
+
internals.emitKeyChange(_Storage.StorageScope.Secure, plainKey, oldValue, newValue ?? undefined, "external", "external");
|
|
282
209
|
return;
|
|
283
210
|
}
|
|
284
|
-
const oldValue = readCachedRawValue(scope, key);
|
|
211
|
+
const oldValue = internals.readCachedRawValue(scope, key);
|
|
285
212
|
if (newValue === null) {
|
|
286
213
|
ensureWebScopeKeyIndex(scope).delete(key);
|
|
287
|
-
cacheRawValue(scope, key, undefined);
|
|
214
|
+
internals.cacheRawValue(scope, key, undefined);
|
|
288
215
|
} else {
|
|
289
216
|
ensureWebScopeKeyIndex(scope).add(key);
|
|
290
|
-
cacheRawValue(scope, key, newValue);
|
|
217
|
+
internals.cacheRawValue(scope, key, newValue);
|
|
291
218
|
}
|
|
292
|
-
notifyKeyListeners(getScopedListeners(scope), key);
|
|
293
|
-
emitKeyChange(scope, key, oldValue, newValue ?? undefined, "external", "external");
|
|
219
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(scope), key);
|
|
220
|
+
internals.emitKeyChange(scope, key, oldValue, newValue ?? undefined, "external", "external");
|
|
294
221
|
}
|
|
295
222
|
function handleWebStorageEvent(event) {
|
|
296
223
|
const key = event.key;
|
|
@@ -340,239 +267,6 @@ function ensureExternalSyncSubscriptions() {
|
|
|
340
267
|
subscribeToBackendChanges(_Storage.StorageScope.Disk);
|
|
341
268
|
subscribeToBackendChanges(_Storage.StorageScope.Secure);
|
|
342
269
|
}
|
|
343
|
-
function getScopedListeners(scope) {
|
|
344
|
-
return webScopeListeners.get(scope);
|
|
345
|
-
}
|
|
346
|
-
function getScopeRawCache(scope) {
|
|
347
|
-
return scopedRawCache.get(scope);
|
|
348
|
-
}
|
|
349
|
-
function cacheRawValue(scope, key, value) {
|
|
350
|
-
getScopeRawCache(scope).set(key, value);
|
|
351
|
-
}
|
|
352
|
-
function readCachedRawValue(scope, key) {
|
|
353
|
-
return getScopeRawCache(scope).get(key);
|
|
354
|
-
}
|
|
355
|
-
function hasCachedRawValue(scope, key) {
|
|
356
|
-
return getScopeRawCache(scope).has(key);
|
|
357
|
-
}
|
|
358
|
-
function clearScopeRawCache(scope) {
|
|
359
|
-
getScopeRawCache(scope).clear();
|
|
360
|
-
}
|
|
361
|
-
function notifyKeyListeners(registry, key) {
|
|
362
|
-
const listeners = registry.get(key);
|
|
363
|
-
if (listeners) {
|
|
364
|
-
for (const listener of listeners) {
|
|
365
|
-
listener();
|
|
366
|
-
}
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
function notifyAllListeners(registry) {
|
|
370
|
-
for (const listeners of registry.values()) {
|
|
371
|
-
for (const listener of listeners) {
|
|
372
|
-
listener();
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
}
|
|
376
|
-
function addKeyListener(registry, key, listener) {
|
|
377
|
-
let listeners = registry.get(key);
|
|
378
|
-
if (!listeners) {
|
|
379
|
-
listeners = new Set();
|
|
380
|
-
registry.set(key, listeners);
|
|
381
|
-
}
|
|
382
|
-
listeners.add(listener);
|
|
383
|
-
return () => {
|
|
384
|
-
const scopedListeners = registry.get(key);
|
|
385
|
-
if (!scopedListeners) {
|
|
386
|
-
return;
|
|
387
|
-
}
|
|
388
|
-
scopedListeners.delete(listener);
|
|
389
|
-
if (scopedListeners.size === 0) {
|
|
390
|
-
registry.delete(key);
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
|
-
function getEventRawValue(scope, key) {
|
|
395
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
396
|
-
const value = memoryStore.get(key);
|
|
397
|
-
return typeof value === "string" ? value : undefined;
|
|
398
|
-
}
|
|
399
|
-
return getRawValue(key, scope);
|
|
400
|
-
}
|
|
401
|
-
function createKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
402
|
-
return {
|
|
403
|
-
type: "key",
|
|
404
|
-
scope,
|
|
405
|
-
key,
|
|
406
|
-
oldValue,
|
|
407
|
-
newValue,
|
|
408
|
-
operation,
|
|
409
|
-
source
|
|
410
|
-
};
|
|
411
|
-
}
|
|
412
|
-
function hasStorageChangeObservers(scope) {
|
|
413
|
-
return storageEvents.hasListeners(scope) || eventObserver !== undefined;
|
|
414
|
-
}
|
|
415
|
-
function shouldReadPreviousEventValues(scope) {
|
|
416
|
-
if (storageEvents.hasListeners(scope)) {
|
|
417
|
-
return true;
|
|
418
|
-
}
|
|
419
|
-
if (!eventObserver) {
|
|
420
|
-
return false;
|
|
421
|
-
}
|
|
422
|
-
return scope !== _Storage.StorageScope.Secure || !eventObserverRedactSecureValues;
|
|
423
|
-
}
|
|
424
|
-
const SECURE_EVENT_REDACTED_VALUE = "[secure]";
|
|
425
|
-
function redactSecureKeyChange(event) {
|
|
426
|
-
if (event.scope !== _Storage.StorageScope.Secure) {
|
|
427
|
-
return event;
|
|
428
|
-
}
|
|
429
|
-
return {
|
|
430
|
-
...event,
|
|
431
|
-
oldValue: event.oldValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE,
|
|
432
|
-
newValue: event.newValue === undefined ? undefined : SECURE_EVENT_REDACTED_VALUE
|
|
433
|
-
};
|
|
434
|
-
}
|
|
435
|
-
function eventForGlobalObserver(event) {
|
|
436
|
-
if (!eventObserverRedactSecureValues || event.scope !== _Storage.StorageScope.Secure) {
|
|
437
|
-
return event;
|
|
438
|
-
}
|
|
439
|
-
if (event.type === "key") {
|
|
440
|
-
return redactSecureKeyChange(event);
|
|
441
|
-
}
|
|
442
|
-
return {
|
|
443
|
-
...event,
|
|
444
|
-
changes: event.changes.map(redactSecureKeyChange)
|
|
445
|
-
};
|
|
446
|
-
}
|
|
447
|
-
function emitKeyChange(scope, key, oldValue, newValue, operation, source) {
|
|
448
|
-
const event = createKeyChange(scope, key, oldValue, newValue, operation, source);
|
|
449
|
-
storageEvents.emitKey(event);
|
|
450
|
-
eventObserver?.(eventForGlobalObserver(event));
|
|
451
|
-
}
|
|
452
|
-
function emitBatchChange(scope, operation, source, changes) {
|
|
453
|
-
if (changes.length === 0) {
|
|
454
|
-
return;
|
|
455
|
-
}
|
|
456
|
-
const event = {
|
|
457
|
-
type: "batch",
|
|
458
|
-
scope,
|
|
459
|
-
operation,
|
|
460
|
-
source,
|
|
461
|
-
changes
|
|
462
|
-
};
|
|
463
|
-
storageEvents.emitBatch(event);
|
|
464
|
-
eventObserver?.(eventForGlobalObserver(event));
|
|
465
|
-
}
|
|
466
|
-
function readPendingSecureWrite(key) {
|
|
467
|
-
return pendingSecureWrites.get(key)?.value;
|
|
468
|
-
}
|
|
469
|
-
function readPendingDiskWrite(key) {
|
|
470
|
-
return pendingDiskWrites.get(key)?.value;
|
|
471
|
-
}
|
|
472
|
-
function hasPendingDiskWrite(key) {
|
|
473
|
-
return pendingDiskWrites.has(key);
|
|
474
|
-
}
|
|
475
|
-
function hasPendingSecureWrite(key) {
|
|
476
|
-
return pendingSecureWrites.has(key);
|
|
477
|
-
}
|
|
478
|
-
function clearPendingDiskWrite(key) {
|
|
479
|
-
pendingDiskWrites.delete(key);
|
|
480
|
-
}
|
|
481
|
-
function clearPendingSecureWrite(key) {
|
|
482
|
-
pendingSecureWrites.delete(key);
|
|
483
|
-
}
|
|
484
|
-
function flushDiskWrites() {
|
|
485
|
-
diskFlushScheduled = false;
|
|
486
|
-
if (pendingDiskWrites.size === 0) {
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
const writes = Array.from(pendingDiskWrites.values());
|
|
490
|
-
pendingDiskWrites.clear();
|
|
491
|
-
const keysToSet = [];
|
|
492
|
-
const valuesToSet = [];
|
|
493
|
-
const keysToRemove = [];
|
|
494
|
-
writes.forEach(({
|
|
495
|
-
key,
|
|
496
|
-
value
|
|
497
|
-
}) => {
|
|
498
|
-
if (value === undefined) {
|
|
499
|
-
keysToRemove.push(key);
|
|
500
|
-
return;
|
|
501
|
-
}
|
|
502
|
-
keysToSet.push(key);
|
|
503
|
-
valuesToSet.push(value);
|
|
504
|
-
});
|
|
505
|
-
if (keysToSet.length > 0) {
|
|
506
|
-
WebStorage.setBatch(keysToSet, valuesToSet, _Storage.StorageScope.Disk);
|
|
507
|
-
}
|
|
508
|
-
if (keysToRemove.length > 0) {
|
|
509
|
-
WebStorage.removeBatch(keysToRemove, _Storage.StorageScope.Disk);
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
function flushSecureWrites() {
|
|
513
|
-
secureFlushScheduled = false;
|
|
514
|
-
if (pendingSecureWrites.size === 0) {
|
|
515
|
-
return;
|
|
516
|
-
}
|
|
517
|
-
const writes = Array.from(pendingSecureWrites.values());
|
|
518
|
-
pendingSecureWrites.clear();
|
|
519
|
-
const groupedSetWrites = new Map();
|
|
520
|
-
const keysToRemove = [];
|
|
521
|
-
writes.forEach(({
|
|
522
|
-
key,
|
|
523
|
-
value,
|
|
524
|
-
accessControl
|
|
525
|
-
}) => {
|
|
526
|
-
if (value === undefined) {
|
|
527
|
-
keysToRemove.push(key);
|
|
528
|
-
} else {
|
|
529
|
-
const resolvedAccessControl = accessControl ?? secureDefaultAccessControl;
|
|
530
|
-
const existingGroup = groupedSetWrites.get(resolvedAccessControl);
|
|
531
|
-
const group = existingGroup ?? {
|
|
532
|
-
keys: [],
|
|
533
|
-
values: []
|
|
534
|
-
};
|
|
535
|
-
group.keys.push(key);
|
|
536
|
-
group.values.push(value);
|
|
537
|
-
if (!existingGroup) {
|
|
538
|
-
groupedSetWrites.set(resolvedAccessControl, group);
|
|
539
|
-
}
|
|
540
|
-
}
|
|
541
|
-
});
|
|
542
|
-
groupedSetWrites.forEach((group, accessControl) => {
|
|
543
|
-
WebStorage.setSecureAccessControl(accessControl);
|
|
544
|
-
WebStorage.setBatch(group.keys, group.values, _Storage.StorageScope.Secure);
|
|
545
|
-
});
|
|
546
|
-
if (keysToRemove.length > 0) {
|
|
547
|
-
WebStorage.removeBatch(keysToRemove, _Storage.StorageScope.Secure);
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
function scheduleDiskWrite(key, value) {
|
|
551
|
-
pendingDiskWrites.set(key, {
|
|
552
|
-
key,
|
|
553
|
-
value
|
|
554
|
-
});
|
|
555
|
-
if (diskFlushScheduled) {
|
|
556
|
-
return;
|
|
557
|
-
}
|
|
558
|
-
diskFlushScheduled = true;
|
|
559
|
-
runMicrotask(flushDiskWrites);
|
|
560
|
-
}
|
|
561
|
-
function scheduleSecureWrite(key, value, accessControl) {
|
|
562
|
-
const pendingWrite = {
|
|
563
|
-
key,
|
|
564
|
-
value
|
|
565
|
-
};
|
|
566
|
-
if (accessControl !== undefined) {
|
|
567
|
-
pendingWrite.accessControl = accessControl;
|
|
568
|
-
}
|
|
569
|
-
pendingSecureWrites.set(key, pendingWrite);
|
|
570
|
-
if (secureFlushScheduled) {
|
|
571
|
-
return;
|
|
572
|
-
}
|
|
573
|
-
secureFlushScheduled = true;
|
|
574
|
-
runMicrotask(flushSecureWrites);
|
|
575
|
-
}
|
|
576
270
|
const WebStorage = {
|
|
577
271
|
name: "Storage",
|
|
578
272
|
equals: other => other === WebStorage,
|
|
@@ -586,7 +280,7 @@ const WebStorage = {
|
|
|
586
280
|
backend.setItem(storageKey, value);
|
|
587
281
|
});
|
|
588
282
|
ensureWebScopeKeyIndex(scope).add(key);
|
|
589
|
-
notifyKeyListeners(getScopedListeners(scope), key);
|
|
283
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(scope), key);
|
|
590
284
|
},
|
|
591
285
|
get: (key, scope) => {
|
|
592
286
|
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
@@ -615,7 +309,7 @@ const WebStorage = {
|
|
|
615
309
|
});
|
|
616
310
|
}
|
|
617
311
|
ensureWebScopeKeyIndex(scope).delete(key);
|
|
618
|
-
notifyKeyListeners(getScopedListeners(scope), key);
|
|
312
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(scope), key);
|
|
619
313
|
},
|
|
620
314
|
clear: scope => {
|
|
621
315
|
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
@@ -625,7 +319,7 @@ const WebStorage = {
|
|
|
625
319
|
backend.clear();
|
|
626
320
|
});
|
|
627
321
|
ensureWebScopeKeyIndex(scope).clear();
|
|
628
|
-
notifyAllListeners(getScopedListeners(scope));
|
|
322
|
+
(0, _shared.notifyAllListeners)(internals.getScopedListeners(scope));
|
|
629
323
|
},
|
|
630
324
|
setBatch: (keys, values, scope) => {
|
|
631
325
|
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
@@ -653,8 +347,8 @@ const WebStorage = {
|
|
|
653
347
|
});
|
|
654
348
|
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
655
349
|
entries.forEach(([storageKey]) => keyIndex.add(scope === _Storage.StorageScope.Secure ? storageKey.slice(SECURE_WEB_PREFIX.length) : storageKey));
|
|
656
|
-
const listeners = getScopedListeners(scope);
|
|
657
|
-
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
350
|
+
const listeners = internals.getScopedListeners(scope);
|
|
351
|
+
keys.forEach(key => (0, _shared.notifyKeyListeners)(listeners, key));
|
|
658
352
|
},
|
|
659
353
|
getBatch: (keys, scope) => {
|
|
660
354
|
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
@@ -697,8 +391,8 @@ const WebStorage = {
|
|
|
697
391
|
}
|
|
698
392
|
const keyIndex = ensureWebScopeKeyIndex(scope);
|
|
699
393
|
keys.forEach(key => keyIndex.delete(key));
|
|
700
|
-
const listeners = getScopedListeners(scope);
|
|
701
|
-
keys.forEach(key => notifyKeyListeners(listeners, key));
|
|
394
|
+
const listeners = internals.getScopedListeners(scope);
|
|
395
|
+
keys.forEach(key => (0, _shared.notifyKeyListeners)(listeners, key));
|
|
702
396
|
},
|
|
703
397
|
removeByPrefix: (prefix, scope) => {
|
|
704
398
|
if (scope !== _Storage.StorageScope.Disk && scope !== _Storage.StorageScope.Secure) {
|
|
@@ -739,7 +433,7 @@ const WebStorage = {
|
|
|
739
433
|
return 0;
|
|
740
434
|
},
|
|
741
435
|
setSecureAccessControl: level => {
|
|
742
|
-
assertAccessControlLevel(level);
|
|
436
|
+
(0, _shared.assertAccessControlLevel)(level);
|
|
743
437
|
},
|
|
744
438
|
setSecureWritesAsync: _enabled => {},
|
|
745
439
|
setKeychainAccessGroup: () => {},
|
|
@@ -747,14 +441,14 @@ const WebStorage = {
|
|
|
747
441
|
WebStorage.setSecureBiometricWithLevel(key, value, _Storage.BiometricLevel.BiometryOnly);
|
|
748
442
|
},
|
|
749
443
|
setSecureBiometricWithLevel: (key, value, level) => {
|
|
750
|
-
assertBiometricLevel(level);
|
|
444
|
+
(0, _shared.assertBiometricLevel)(level);
|
|
751
445
|
if (level === _Storage.BiometricLevel.None) {
|
|
752
446
|
withWebBackendOperation(_Storage.StorageScope.Secure, "setSecure", backend => {
|
|
753
447
|
backend.removeItem(toBiometricStorageKey(key));
|
|
754
448
|
backend.setItem(toSecureStorageKey(key), value);
|
|
755
449
|
});
|
|
756
450
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).add(key);
|
|
757
|
-
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
451
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
758
452
|
return;
|
|
759
453
|
}
|
|
760
454
|
if (typeof __DEV__ !== "undefined" && __DEV__ && !hasWarnedAboutWebBiometricFallback) {
|
|
@@ -763,7 +457,7 @@ const WebStorage = {
|
|
|
763
457
|
}
|
|
764
458
|
withWebBackendOperation(_Storage.StorageScope.Secure, "setSecureBiometric", backend => backend.setItem(toBiometricStorageKey(key), value));
|
|
765
459
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).add(key);
|
|
766
|
-
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
460
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
767
461
|
},
|
|
768
462
|
getSecureBiometric: key => {
|
|
769
463
|
const value = withWebBackendOperation(_Storage.StorageScope.Secure, "getSecureBiometric", backend => backend.getItem(toBiometricStorageKey(key)));
|
|
@@ -774,7 +468,7 @@ const WebStorage = {
|
|
|
774
468
|
if (withWebBackendOperation(_Storage.StorageScope.Secure, "deleteSecureBiometric:getItem", backend => backend.getItem(toSecureStorageKey(key))) === null) {
|
|
775
469
|
ensureWebScopeKeyIndex(_Storage.StorageScope.Secure).delete(key);
|
|
776
470
|
}
|
|
777
|
-
notifyKeyListeners(getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
471
|
+
(0, _shared.notifyKeyListeners)(internals.getScopedListeners(_Storage.StorageScope.Secure), key);
|
|
778
472
|
},
|
|
779
473
|
hasSecureBiometric: key => {
|
|
780
474
|
return withWebBackendOperation(_Storage.StorageScope.Secure, "hasSecureBiometric", backend => backend.getItem(toBiometricStorageKey(key))) !== null;
|
|
@@ -801,364 +495,42 @@ const WebStorage = {
|
|
|
801
495
|
keyIndex.delete(key);
|
|
802
496
|
}
|
|
803
497
|
});
|
|
804
|
-
const listeners = getScopedListeners(_Storage.StorageScope.Secure);
|
|
805
|
-
keysToNotify.forEach(key => notifyKeyListeners(listeners, key));
|
|
498
|
+
const listeners = internals.getScopedListeners(_Storage.StorageScope.Secure);
|
|
499
|
+
keysToNotify.forEach(key => (0, _shared.notifyKeyListeners)(listeners, key));
|
|
806
500
|
}
|
|
807
501
|
};
|
|
808
|
-
function
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
memoryStore.set(key, value);
|
|
827
|
-
notifyKeyListeners(memoryListeners, key);
|
|
828
|
-
emitKeyChange(scope, key, oldValue, value, "set", "memory");
|
|
829
|
-
return;
|
|
830
|
-
}
|
|
831
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
832
|
-
cacheRawValue(scope, key, value);
|
|
833
|
-
if (diskWritesAsync) {
|
|
834
|
-
scheduleDiskWrite(key, value);
|
|
835
|
-
emitKeyChange(scope, key, oldValue, value, "set", "web");
|
|
836
|
-
return;
|
|
837
|
-
}
|
|
838
|
-
flushDiskWrites();
|
|
839
|
-
clearPendingDiskWrite(key);
|
|
840
|
-
}
|
|
841
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
842
|
-
flushSecureWrites();
|
|
843
|
-
clearPendingSecureWrite(key);
|
|
844
|
-
}
|
|
845
|
-
WebStorage.set(key, value, scope);
|
|
846
|
-
cacheRawValue(scope, key, value);
|
|
847
|
-
emitKeyChange(scope, key, oldValue, value, "set", "web");
|
|
848
|
-
}
|
|
849
|
-
function removeRawValue(key, scope) {
|
|
850
|
-
(0, _internal.assertValidScope)(scope);
|
|
851
|
-
const oldValue = getEventRawValue(scope, key);
|
|
852
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
853
|
-
memoryStore.delete(key);
|
|
854
|
-
notifyKeyListeners(memoryListeners, key);
|
|
855
|
-
emitKeyChange(scope, key, oldValue, undefined, "remove", "memory");
|
|
856
|
-
return;
|
|
857
|
-
}
|
|
858
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
859
|
-
cacheRawValue(scope, key, undefined);
|
|
860
|
-
if (diskWritesAsync) {
|
|
861
|
-
scheduleDiskWrite(key, undefined);
|
|
862
|
-
emitKeyChange(scope, key, oldValue, undefined, "remove", "web");
|
|
863
|
-
return;
|
|
864
|
-
}
|
|
865
|
-
flushDiskWrites();
|
|
866
|
-
clearPendingDiskWrite(key);
|
|
867
|
-
}
|
|
868
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
869
|
-
flushSecureWrites();
|
|
870
|
-
clearPendingSecureWrite(key);
|
|
871
|
-
}
|
|
872
|
-
WebStorage.remove(key, scope);
|
|
873
|
-
cacheRawValue(scope, key, undefined);
|
|
874
|
-
emitKeyChange(scope, key, oldValue, undefined, "remove", "web");
|
|
875
|
-
}
|
|
876
|
-
function readMigrationVersion(scope) {
|
|
877
|
-
const raw = getRawValue(_internal.MIGRATION_VERSION_KEY, scope);
|
|
878
|
-
if (raw === undefined) {
|
|
879
|
-
return 0;
|
|
880
|
-
}
|
|
881
|
-
const parsed = Number.parseInt(raw, 10);
|
|
882
|
-
return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
|
|
883
|
-
}
|
|
884
|
-
function writeMigrationVersion(scope, version) {
|
|
885
|
-
setRawValue(_internal.MIGRATION_VERSION_KEY, String(version), scope);
|
|
502
|
+
function buildWebAdapter(coreInternals) {
|
|
503
|
+
internals = coreInternals;
|
|
504
|
+
return {
|
|
505
|
+
backend: WebStorage,
|
|
506
|
+
changeSource: "web",
|
|
507
|
+
applyAccessControlOnSecureRawWrite: false,
|
|
508
|
+
flushDiskWritesOnImport: true,
|
|
509
|
+
ensureScopeSubscription: () => {
|
|
510
|
+
ensureExternalSyncSubscriptions();
|
|
511
|
+
},
|
|
512
|
+
maybeCleanupScopeSubscription: () => {},
|
|
513
|
+
onWillEmitChanges: () => {},
|
|
514
|
+
getSecureMetadataProfile: () => ({
|
|
515
|
+
backend: getBackendName(_Storage.StorageScope.Secure, webSecureStorageBackend),
|
|
516
|
+
encrypted: getWebSecureEncryptionStatus(webSecureStorageBackend),
|
|
517
|
+
hardwareBacked: "unavailable"
|
|
518
|
+
})
|
|
519
|
+
};
|
|
886
520
|
}
|
|
521
|
+
const core = (0, _storageCore.createStorageCore)(buildWebAdapter);
|
|
887
522
|
const storage = exports.storage = {
|
|
888
|
-
|
|
889
|
-
(0, _internal.assertValidScope)(scope);
|
|
890
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
891
|
-
ensureExternalSyncSubscriptions();
|
|
892
|
-
}
|
|
893
|
-
return storageEvents.subscribe(scope, listener);
|
|
894
|
-
},
|
|
895
|
-
subscribeKey: (scope, key, listener) => {
|
|
896
|
-
(0, _internal.assertValidScope)(scope);
|
|
897
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
898
|
-
ensureExternalSyncSubscriptions();
|
|
899
|
-
}
|
|
900
|
-
return storageEvents.subscribeKey(scope, key, listener);
|
|
901
|
-
},
|
|
902
|
-
subscribePrefix: (scope, prefix, listener) => {
|
|
903
|
-
(0, _internal.assertValidScope)(scope);
|
|
904
|
-
if (scope !== _Storage.StorageScope.Memory) {
|
|
905
|
-
ensureExternalSyncSubscriptions();
|
|
906
|
-
}
|
|
907
|
-
return storageEvents.subscribePrefix(scope, prefix, listener);
|
|
908
|
-
},
|
|
909
|
-
subscribeNamespace: (namespace, scope, listener) => {
|
|
910
|
-
return storage.subscribePrefix(scope, (0, _internal.prefixKey)(namespace, ""), listener);
|
|
911
|
-
},
|
|
912
|
-
setEventObserver: (observer, options = {}) => {
|
|
913
|
-
eventObserver = observer;
|
|
914
|
-
eventObserverRedactSecureValues = options.redactSecureValues !== false;
|
|
915
|
-
if (observer) {
|
|
916
|
-
ensureExternalSyncSubscriptions();
|
|
917
|
-
}
|
|
918
|
-
},
|
|
919
|
-
clear: scope => {
|
|
920
|
-
measureOperation("storage:clear", scope, () => {
|
|
921
|
-
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getAll(scope) : {};
|
|
922
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
923
|
-
memoryStore.clear();
|
|
924
|
-
notifyAllListeners(memoryListeners);
|
|
925
|
-
emitBatchChange(scope, "clear", "memory", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clear", "memory")));
|
|
926
|
-
return;
|
|
927
|
-
}
|
|
928
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
929
|
-
flushDiskWrites();
|
|
930
|
-
pendingDiskWrites.clear();
|
|
931
|
-
}
|
|
932
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
933
|
-
flushSecureWrites();
|
|
934
|
-
pendingSecureWrites.clear();
|
|
935
|
-
}
|
|
936
|
-
clearScopeRawCache(scope);
|
|
937
|
-
WebStorage.clear(scope);
|
|
938
|
-
emitBatchChange(scope, "clear", "web", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clear", "web")));
|
|
939
|
-
});
|
|
940
|
-
},
|
|
941
|
-
clearAll: () => {
|
|
942
|
-
measureOperation("storage:clearAll", _Storage.StorageScope.Memory, () => {
|
|
943
|
-
storage.clear(_Storage.StorageScope.Memory);
|
|
944
|
-
storage.clear(_Storage.StorageScope.Disk);
|
|
945
|
-
storage.clear(_Storage.StorageScope.Secure);
|
|
946
|
-
}, 3);
|
|
947
|
-
},
|
|
948
|
-
clearNamespace: (namespace, scope) => {
|
|
949
|
-
measureOperation("storage:clearNamespace", scope, () => {
|
|
950
|
-
(0, _internal.assertValidScope)(scope);
|
|
951
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
952
|
-
const affectedKeys = Array.from(memoryStore.keys()).filter(key => (0, _internal.isNamespaced)(key, namespace));
|
|
953
|
-
const previousValues = affectedKeys.map(key => ({
|
|
954
|
-
key,
|
|
955
|
-
value: getEventRawValue(scope, key)
|
|
956
|
-
}));
|
|
957
|
-
if (affectedKeys.length === 0) {
|
|
958
|
-
return;
|
|
959
|
-
}
|
|
960
|
-
affectedKeys.forEach(key => {
|
|
961
|
-
memoryStore.delete(key);
|
|
962
|
-
});
|
|
963
|
-
affectedKeys.forEach(key => notifyKeyListeners(memoryListeners, key));
|
|
964
|
-
emitBatchChange(scope, "clearNamespace", "memory", previousValues.map(({
|
|
965
|
-
key,
|
|
966
|
-
value
|
|
967
|
-
}) => createKeyChange(scope, key, value, undefined, "clearNamespace", "memory")));
|
|
968
|
-
return;
|
|
969
|
-
}
|
|
970
|
-
const keyPrefix = (0, _internal.prefixKey)(namespace, "");
|
|
971
|
-
const previousValues = shouldReadPreviousEventValues(scope) ? storage.getByPrefix(keyPrefix, scope) : {};
|
|
972
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
973
|
-
flushDiskWrites();
|
|
974
|
-
}
|
|
975
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
976
|
-
flushSecureWrites();
|
|
977
|
-
}
|
|
978
|
-
const scopeCache = getScopeRawCache(scope);
|
|
979
|
-
for (const key of scopeCache.keys()) {
|
|
980
|
-
if ((0, _internal.isNamespaced)(key, namespace)) {
|
|
981
|
-
scopeCache.delete(key);
|
|
982
|
-
}
|
|
983
|
-
}
|
|
984
|
-
WebStorage.removeByPrefix(keyPrefix, scope);
|
|
985
|
-
emitBatchChange(scope, "clearNamespace", "web", Object.keys(previousValues).map(key => createKeyChange(scope, key, previousValues[key], undefined, "clearNamespace", "web")));
|
|
986
|
-
});
|
|
987
|
-
},
|
|
988
|
-
clearBiometric: () => {
|
|
989
|
-
measureOperation("storage:clearBiometric", _Storage.StorageScope.Secure, () => {
|
|
990
|
-
WebStorage.clearSecureBiometric();
|
|
991
|
-
});
|
|
992
|
-
},
|
|
993
|
-
has: (key, scope) => {
|
|
994
|
-
return measureOperation("storage:has", scope, () => {
|
|
995
|
-
(0, _internal.assertValidScope)(scope);
|
|
996
|
-
if (scope === _Storage.StorageScope.Memory) return memoryStore.has(key);
|
|
997
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
998
|
-
flushDiskWrites();
|
|
999
|
-
}
|
|
1000
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1001
|
-
flushSecureWrites();
|
|
1002
|
-
}
|
|
1003
|
-
return WebStorage.has(key, scope);
|
|
1004
|
-
});
|
|
1005
|
-
},
|
|
1006
|
-
getAllKeys: scope => {
|
|
1007
|
-
return measureOperation("storage:getAllKeys", scope, () => {
|
|
1008
|
-
(0, _internal.assertValidScope)(scope);
|
|
1009
|
-
if (scope === _Storage.StorageScope.Memory) return Array.from(memoryStore.keys());
|
|
1010
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1011
|
-
flushDiskWrites();
|
|
1012
|
-
}
|
|
1013
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1014
|
-
flushSecureWrites();
|
|
1015
|
-
}
|
|
1016
|
-
return WebStorage.getAllKeys(scope);
|
|
1017
|
-
});
|
|
1018
|
-
},
|
|
1019
|
-
getKeysByPrefix: (prefix, scope) => {
|
|
1020
|
-
return measureOperation("storage:getKeysByPrefix", scope, () => {
|
|
1021
|
-
(0, _internal.assertValidScope)(scope);
|
|
1022
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1023
|
-
return Array.from(memoryStore.keys()).filter(key => key.startsWith(prefix));
|
|
1024
|
-
}
|
|
1025
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1026
|
-
flushDiskWrites();
|
|
1027
|
-
}
|
|
1028
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1029
|
-
flushSecureWrites();
|
|
1030
|
-
}
|
|
1031
|
-
return WebStorage.getKeysByPrefix(prefix, scope);
|
|
1032
|
-
});
|
|
1033
|
-
},
|
|
1034
|
-
getByPrefix: (prefix, scope) => {
|
|
1035
|
-
return measureOperation("storage:getByPrefix", scope, () => {
|
|
1036
|
-
const result = {};
|
|
1037
|
-
const keys = storage.getKeysByPrefix(prefix, scope);
|
|
1038
|
-
if (keys.length === 0) {
|
|
1039
|
-
return result;
|
|
1040
|
-
}
|
|
1041
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1042
|
-
keys.forEach(key => {
|
|
1043
|
-
const value = memoryStore.get(key);
|
|
1044
|
-
if (typeof value === "string") {
|
|
1045
|
-
result[key] = value;
|
|
1046
|
-
}
|
|
1047
|
-
});
|
|
1048
|
-
return result;
|
|
1049
|
-
}
|
|
1050
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1051
|
-
flushDiskWrites();
|
|
1052
|
-
}
|
|
1053
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1054
|
-
flushSecureWrites();
|
|
1055
|
-
}
|
|
1056
|
-
const values = WebStorage.getBatch(keys, scope);
|
|
1057
|
-
keys.forEach((key, index) => {
|
|
1058
|
-
const value = values[index];
|
|
1059
|
-
if (value !== undefined) {
|
|
1060
|
-
result[key] = value;
|
|
1061
|
-
}
|
|
1062
|
-
});
|
|
1063
|
-
return result;
|
|
1064
|
-
});
|
|
1065
|
-
},
|
|
1066
|
-
getAll: scope => {
|
|
1067
|
-
return measureOperation("storage:getAll", scope, () => {
|
|
1068
|
-
(0, _internal.assertValidScope)(scope);
|
|
1069
|
-
const result = {};
|
|
1070
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1071
|
-
memoryStore.forEach((value, key) => {
|
|
1072
|
-
if (typeof value === "string") result[key] = value;
|
|
1073
|
-
});
|
|
1074
|
-
return result;
|
|
1075
|
-
}
|
|
1076
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1077
|
-
flushDiskWrites();
|
|
1078
|
-
}
|
|
1079
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1080
|
-
flushSecureWrites();
|
|
1081
|
-
}
|
|
1082
|
-
const keys = WebStorage.getAllKeys(scope);
|
|
1083
|
-
if (keys.length === 0) return {};
|
|
1084
|
-
const values = WebStorage.getBatch(keys, scope);
|
|
1085
|
-
keys.forEach((key, index) => {
|
|
1086
|
-
const val = values[index];
|
|
1087
|
-
if (val !== undefined && val !== null) {
|
|
1088
|
-
result[key] = val;
|
|
1089
|
-
}
|
|
1090
|
-
});
|
|
1091
|
-
return result;
|
|
1092
|
-
});
|
|
1093
|
-
},
|
|
1094
|
-
export: (scope, options = {}) => {
|
|
1095
|
-
if (scope === _Storage.StorageScope.Secure && options.includeSecureValues !== true) {
|
|
1096
|
-
throw new Error("NitroStorage: exporting Secure scope exposes raw secret values. Pass { includeSecureValues: true } or use exportSecureUnsafe().");
|
|
1097
|
-
}
|
|
1098
|
-
return measureOperation("storage:export", scope, () => storage.getAll(scope));
|
|
1099
|
-
},
|
|
1100
|
-
exportSecureUnsafe: () => {
|
|
1101
|
-
return measureOperation("storage:exportSecureUnsafe", _Storage.StorageScope.Secure, () => storage.getAll(_Storage.StorageScope.Secure));
|
|
1102
|
-
},
|
|
1103
|
-
size: scope => {
|
|
1104
|
-
return measureOperation("storage:size", scope, () => {
|
|
1105
|
-
(0, _internal.assertValidScope)(scope);
|
|
1106
|
-
if (scope === _Storage.StorageScope.Memory) return memoryStore.size;
|
|
1107
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1108
|
-
flushDiskWrites();
|
|
1109
|
-
}
|
|
1110
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1111
|
-
flushSecureWrites();
|
|
1112
|
-
}
|
|
1113
|
-
return WebStorage.size(scope);
|
|
1114
|
-
});
|
|
1115
|
-
},
|
|
523
|
+
...core.storage,
|
|
1116
524
|
setAccessControl: level => {
|
|
1117
|
-
assertAccessControlLevel(level);
|
|
1118
|
-
|
|
1119
|
-
recordMetric("storage:setAccessControl", _Storage.StorageScope.Secure, 0);
|
|
525
|
+
(0, _shared.assertAccessControlLevel)(level);
|
|
526
|
+
internals.setSecureDefaultAccessControl(level);
|
|
527
|
+
internals.recordMetric("storage:setAccessControl", _Storage.StorageScope.Secure, 0);
|
|
1120
528
|
},
|
|
1121
529
|
setSecureWritesAsync: _enabled => {
|
|
1122
|
-
recordMetric("storage:setSecureWritesAsync", _Storage.StorageScope.Secure, 0);
|
|
1123
|
-
},
|
|
1124
|
-
setDiskWritesAsync: enabled => {
|
|
1125
|
-
measureOperation("storage:setDiskWritesAsync", _Storage.StorageScope.Disk, () => {
|
|
1126
|
-
diskWritesAsync = enabled;
|
|
1127
|
-
if (!enabled) {
|
|
1128
|
-
flushDiskWrites();
|
|
1129
|
-
}
|
|
1130
|
-
});
|
|
1131
|
-
},
|
|
1132
|
-
flushDiskWrites: () => {
|
|
1133
|
-
measureOperation("storage:flushDiskWrites", _Storage.StorageScope.Disk, () => {
|
|
1134
|
-
flushDiskWrites();
|
|
1135
|
-
});
|
|
1136
|
-
},
|
|
1137
|
-
flushSecureWrites: () => {
|
|
1138
|
-
measureOperation("storage:flushSecureWrites", _Storage.StorageScope.Secure, () => {
|
|
1139
|
-
flushSecureWrites();
|
|
1140
|
-
});
|
|
530
|
+
internals.recordMetric("storage:setSecureWritesAsync", _Storage.StorageScope.Secure, 0);
|
|
1141
531
|
},
|
|
1142
532
|
setKeychainAccessGroup: _group => {
|
|
1143
|
-
recordMetric("storage:setKeychainAccessGroup", _Storage.StorageScope.Secure, 0);
|
|
1144
|
-
},
|
|
1145
|
-
setMetricsObserver: observer => {
|
|
1146
|
-
metricsObserver = observer;
|
|
1147
|
-
},
|
|
1148
|
-
getMetricsSnapshot: () => {
|
|
1149
|
-
const snapshot = {};
|
|
1150
|
-
metricsCounters.forEach((value, key) => {
|
|
1151
|
-
snapshot[key] = {
|
|
1152
|
-
count: value.count,
|
|
1153
|
-
totalDurationMs: value.totalDurationMs,
|
|
1154
|
-
avgDurationMs: value.count === 0 ? 0 : value.totalDurationMs / value.count,
|
|
1155
|
-
maxDurationMs: value.maxDurationMs
|
|
1156
|
-
};
|
|
1157
|
-
});
|
|
1158
|
-
return snapshot;
|
|
1159
|
-
},
|
|
1160
|
-
resetMetrics: () => {
|
|
1161
|
-
metricsCounters.clear();
|
|
533
|
+
internals.recordMetric("storage:setKeychainAccessGroup", _Storage.StorageScope.Secure, 0);
|
|
1162
534
|
},
|
|
1163
535
|
getCapabilities: () => ({
|
|
1164
536
|
platform: "web",
|
|
@@ -1195,85 +567,24 @@ const storage = exports.storage = {
|
|
|
1195
567
|
persistsTimestamps: false
|
|
1196
568
|
}
|
|
1197
569
|
};
|
|
1198
|
-
},
|
|
1199
|
-
getSecureMetadata: key => {
|
|
1200
|
-
return measureOperation("storage:getSecureMetadata", _Storage.StorageScope.Secure, () => {
|
|
1201
|
-
flushSecureWrites();
|
|
1202
|
-
const biometricProtected = WebStorage.hasSecureBiometric(key);
|
|
1203
|
-
const exists = biometricProtected || WebStorage.has(key, _Storage.StorageScope.Secure);
|
|
1204
|
-
let kind = "missing";
|
|
1205
|
-
if (exists) {
|
|
1206
|
-
kind = biometricProtected ? "biometric" : "secure";
|
|
1207
|
-
}
|
|
1208
|
-
return {
|
|
1209
|
-
key,
|
|
1210
|
-
exists,
|
|
1211
|
-
kind,
|
|
1212
|
-
backend: getBackendName(_Storage.StorageScope.Secure, webSecureStorageBackend),
|
|
1213
|
-
encrypted: getWebSecureEncryptionStatus(webSecureStorageBackend),
|
|
1214
|
-
hardwareBacked: "unavailable",
|
|
1215
|
-
biometricProtected,
|
|
1216
|
-
valueExposed: false
|
|
1217
|
-
};
|
|
1218
|
-
});
|
|
1219
|
-
},
|
|
1220
|
-
getAllSecureMetadata: () => {
|
|
1221
|
-
return measureOperation("storage:getAllSecureMetadata", _Storage.StorageScope.Secure, () => {
|
|
1222
|
-
flushSecureWrites();
|
|
1223
|
-
return WebStorage.getAllKeys(_Storage.StorageScope.Secure).map(key => storage.getSecureMetadata(key));
|
|
1224
|
-
});
|
|
1225
|
-
},
|
|
1226
|
-
getString: (key, scope) => {
|
|
1227
|
-
return measureOperation("storage:getString", scope, () => {
|
|
1228
|
-
return getRawValue(key, scope);
|
|
1229
|
-
});
|
|
1230
|
-
},
|
|
1231
|
-
setString: (key, value, scope) => {
|
|
1232
|
-
measureOperation("storage:setString", scope, () => {
|
|
1233
|
-
setRawValue(key, value, scope);
|
|
1234
|
-
});
|
|
1235
|
-
},
|
|
1236
|
-
deleteString: (key, scope) => {
|
|
1237
|
-
measureOperation("storage:deleteString", scope, () => {
|
|
1238
|
-
removeRawValue(key, scope);
|
|
1239
|
-
});
|
|
1240
|
-
},
|
|
1241
|
-
import: (data, scope) => {
|
|
1242
|
-
const keys = Object.keys(data);
|
|
1243
|
-
measureOperation("storage:import", scope, () => {
|
|
1244
|
-
(0, _internal.assertValidScope)(scope);
|
|
1245
|
-
if (keys.length === 0) return;
|
|
1246
|
-
const values = keys.map(k => data[k]);
|
|
1247
|
-
const changes = keys.map((key, index) => createKeyChange(scope, key, getEventRawValue(scope, key), values[index], "import", scope === _Storage.StorageScope.Memory ? "memory" : "web"));
|
|
1248
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1249
|
-
keys.forEach((key, index) => {
|
|
1250
|
-
memoryStore.set(key, values[index]);
|
|
1251
|
-
});
|
|
1252
|
-
keys.forEach(key => notifyKeyListeners(memoryListeners, key));
|
|
1253
|
-
emitBatchChange(scope, "import", "memory", changes);
|
|
1254
|
-
return;
|
|
1255
|
-
}
|
|
1256
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1257
|
-
flushSecureWrites();
|
|
1258
|
-
WebStorage.setSecureAccessControl(secureDefaultAccessControl);
|
|
1259
|
-
}
|
|
1260
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1261
|
-
flushDiskWrites();
|
|
1262
|
-
}
|
|
1263
|
-
WebStorage.setBatch(keys, values, scope);
|
|
1264
|
-
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
1265
|
-
emitBatchChange(scope, "import", "web", changes);
|
|
1266
|
-
}, keys.length);
|
|
1267
570
|
}
|
|
1268
571
|
};
|
|
572
|
+
const createStorageItem = exports.createStorageItem = core.createStorageItem;
|
|
573
|
+
const getBatch = exports.getBatch = core.getBatch;
|
|
574
|
+
const setBatch = exports.setBatch = core.setBatch;
|
|
575
|
+
const removeBatch = exports.removeBatch = core.removeBatch;
|
|
576
|
+
const registerMigration = exports.registerMigration = core.registerMigration;
|
|
577
|
+
const migrateToLatest = exports.migrateToLatest = core.migrateToLatest;
|
|
578
|
+
const runTransaction = exports.runTransaction = core.runTransaction;
|
|
579
|
+
const createSecureAuthStorage = exports.createSecureAuthStorage = core.createSecureAuthStorage;
|
|
1269
580
|
function setWebSecureStorageBackend(backend) {
|
|
1270
581
|
const previousBackend = webSecureStorageBackend;
|
|
1271
582
|
const nextBackend = backend ?? createDefaultSecureBackend();
|
|
1272
|
-
|
|
583
|
+
internals.clearAllPendingSecureWrites();
|
|
1273
584
|
resetBackendChangeSubscription(_Storage.StorageScope.Secure);
|
|
1274
585
|
webSecureStorageBackend = nextBackend;
|
|
1275
586
|
hydratedWebScopeKeyIndex.delete(_Storage.StorageScope.Secure);
|
|
1276
|
-
clearScopeRawCache(_Storage.StorageScope.Secure);
|
|
587
|
+
internals.clearScopeRawCache(_Storage.StorageScope.Secure);
|
|
1277
588
|
ensureExternalSyncSubscriptions();
|
|
1278
589
|
if (previousBackend !== nextBackend) {
|
|
1279
590
|
closeWebBackend(_Storage.StorageScope.Secure, previousBackend);
|
|
@@ -1285,11 +596,11 @@ function getWebSecureStorageBackend() {
|
|
|
1285
596
|
function setWebDiskStorageBackend(backend) {
|
|
1286
597
|
const previousBackend = webDiskStorageBackend;
|
|
1287
598
|
const nextBackend = backend ?? createDefaultDiskBackend();
|
|
1288
|
-
|
|
599
|
+
internals.clearAllPendingDiskWrites();
|
|
1289
600
|
resetBackendChangeSubscription(_Storage.StorageScope.Disk);
|
|
1290
601
|
webDiskStorageBackend = nextBackend;
|
|
1291
602
|
hydratedWebScopeKeyIndex.delete(_Storage.StorageScope.Disk);
|
|
1292
|
-
clearScopeRawCache(_Storage.StorageScope.Disk);
|
|
603
|
+
internals.clearScopeRawCache(_Storage.StorageScope.Disk);
|
|
1293
604
|
ensureExternalSyncSubscriptions();
|
|
1294
605
|
if (previousBackend !== nextBackend) {
|
|
1295
606
|
closeWebBackend(_Storage.StorageScope.Disk, previousBackend);
|
|
@@ -1299,8 +610,8 @@ function getWebDiskStorageBackend() {
|
|
|
1299
610
|
return webDiskStorageBackend;
|
|
1300
611
|
}
|
|
1301
612
|
async function flushWebStorageBackends() {
|
|
1302
|
-
flushDiskWrites();
|
|
1303
|
-
flushSecureWrites();
|
|
613
|
+
internals.flushDiskWrites();
|
|
614
|
+
internals.flushSecureWrites();
|
|
1304
615
|
const flushes = [];
|
|
1305
616
|
const diskFlush = webDiskStorageBackend?.flush;
|
|
1306
617
|
const secureFlush = webSecureStorageBackend?.flush;
|
|
@@ -1312,782 +623,4 @@ async function flushWebStorageBackends() {
|
|
|
1312
623
|
}
|
|
1313
624
|
await Promise.all(flushes);
|
|
1314
625
|
}
|
|
1315
|
-
function canUseRawBatchPath(item) {
|
|
1316
|
-
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true && item._secureAccessControl === undefined;
|
|
1317
|
-
}
|
|
1318
|
-
function canUseSecureRawBatchPath(item) {
|
|
1319
|
-
return item._hasExpiration === false && item._hasValidation === false && item._isBiometric !== true;
|
|
1320
|
-
}
|
|
1321
|
-
function defaultSerialize(value) {
|
|
1322
|
-
return (0, _internal.serializeWithPrimitiveFastPath)(value);
|
|
1323
|
-
}
|
|
1324
|
-
function defaultDeserialize(value) {
|
|
1325
|
-
return (0, _internal.deserializeWithPrimitiveFastPath)(value);
|
|
1326
|
-
}
|
|
1327
|
-
function createStorageItem(config) {
|
|
1328
|
-
const storageKey = (0, _internal.prefixKey)(config.namespace, config.key);
|
|
1329
|
-
const serialize = config.serialize ?? defaultSerialize;
|
|
1330
|
-
const deserialize = config.deserialize ?? defaultDeserialize;
|
|
1331
|
-
const isMemory = config.scope === _Storage.StorageScope.Memory;
|
|
1332
|
-
const resolvedBiometricLevel = config.scope === _Storage.StorageScope.Secure ? config.biometricLevel ?? (config.biometric === true ? _Storage.BiometricLevel.BiometryOnly : _Storage.BiometricLevel.None) : _Storage.BiometricLevel.None;
|
|
1333
|
-
const isBiometric = resolvedBiometricLevel !== _Storage.BiometricLevel.None;
|
|
1334
|
-
const secureAccessControl = config.accessControl;
|
|
1335
|
-
const validate = config.validate;
|
|
1336
|
-
const onValidationError = config.onValidationError;
|
|
1337
|
-
const expiration = config.expiration;
|
|
1338
|
-
const onExpired = config.onExpired;
|
|
1339
|
-
const expirationTtlMs = expiration?.ttlMs;
|
|
1340
|
-
const memoryExpiration = expiration && isMemory ? new Map() : null;
|
|
1341
|
-
const readCache = !isMemory && config.readCache === true;
|
|
1342
|
-
const coalesceDiskWrites = config.scope === _Storage.StorageScope.Disk && config.coalesceDiskWrites === true;
|
|
1343
|
-
const coalesceSecureWrites = config.scope === _Storage.StorageScope.Secure && config.coalesceSecureWrites === true && !isBiometric;
|
|
1344
|
-
const defaultValue = config.defaultValue;
|
|
1345
|
-
const nonMemoryScope = config.scope === _Storage.StorageScope.Disk ? _Storage.StorageScope.Disk : config.scope === _Storage.StorageScope.Secure ? _Storage.StorageScope.Secure : null;
|
|
1346
|
-
if (expiration && expiration.ttlMs <= 0) {
|
|
1347
|
-
throw new Error("expiration.ttlMs must be greater than 0.");
|
|
1348
|
-
}
|
|
1349
|
-
if (config.scope === _Storage.StorageScope.Secure) {
|
|
1350
|
-
assertBiometricLevel(resolvedBiometricLevel);
|
|
1351
|
-
if (secureAccessControl !== undefined) {
|
|
1352
|
-
assertAccessControlLevel(secureAccessControl);
|
|
1353
|
-
}
|
|
1354
|
-
}
|
|
1355
|
-
const listeners = new Set();
|
|
1356
|
-
let unsubscribe = null;
|
|
1357
|
-
let lastRaw = undefined;
|
|
1358
|
-
let lastValue;
|
|
1359
|
-
let hasLastValue = false;
|
|
1360
|
-
let lastExpiresAt = undefined;
|
|
1361
|
-
const invalidateParsedCache = () => {
|
|
1362
|
-
lastRaw = undefined;
|
|
1363
|
-
lastValue = undefined;
|
|
1364
|
-
hasLastValue = false;
|
|
1365
|
-
lastExpiresAt = undefined;
|
|
1366
|
-
};
|
|
1367
|
-
const ensureSubscription = () => {
|
|
1368
|
-
if (unsubscribe) {
|
|
1369
|
-
return;
|
|
1370
|
-
}
|
|
1371
|
-
const listener = () => {
|
|
1372
|
-
invalidateParsedCache();
|
|
1373
|
-
listeners.forEach(callback => callback());
|
|
1374
|
-
};
|
|
1375
|
-
if (isMemory) {
|
|
1376
|
-
unsubscribe = addKeyListener(memoryListeners, storageKey, listener);
|
|
1377
|
-
return;
|
|
1378
|
-
}
|
|
1379
|
-
ensureExternalSyncSubscriptions();
|
|
1380
|
-
unsubscribe = addKeyListener(getScopedListeners(nonMemoryScope), storageKey, listener);
|
|
1381
|
-
};
|
|
1382
|
-
const readStoredRaw = () => {
|
|
1383
|
-
if (isMemory) {
|
|
1384
|
-
if (memoryExpiration) {
|
|
1385
|
-
const expiresAt = memoryExpiration.get(storageKey);
|
|
1386
|
-
if (expiresAt !== undefined && expiresAt <= Date.now()) {
|
|
1387
|
-
memoryExpiration.delete(storageKey);
|
|
1388
|
-
memoryStore.delete(storageKey);
|
|
1389
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1390
|
-
onExpired?.(storageKey);
|
|
1391
|
-
return undefined;
|
|
1392
|
-
}
|
|
1393
|
-
}
|
|
1394
|
-
return memoryStore.get(storageKey);
|
|
1395
|
-
}
|
|
1396
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1397
|
-
const pending = pendingDiskWrites.get(storageKey);
|
|
1398
|
-
if (pending !== undefined) {
|
|
1399
|
-
return pending.value;
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1402
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure && !isBiometric) {
|
|
1403
|
-
const pending = pendingSecureWrites.get(storageKey);
|
|
1404
|
-
if (pending !== undefined) {
|
|
1405
|
-
return pending.value;
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
if (readCache) {
|
|
1409
|
-
const cache = getScopeRawCache(nonMemoryScope);
|
|
1410
|
-
const cached = cache.get(storageKey);
|
|
1411
|
-
if (cached !== undefined || cache.has(storageKey)) {
|
|
1412
|
-
return cached;
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
if (isBiometric) {
|
|
1416
|
-
return WebStorage.getSecureBiometric(storageKey);
|
|
1417
|
-
}
|
|
1418
|
-
const raw = WebStorage.get(storageKey, config.scope);
|
|
1419
|
-
cacheRawValue(nonMemoryScope, storageKey, raw);
|
|
1420
|
-
return raw;
|
|
1421
|
-
};
|
|
1422
|
-
const writeStoredRaw = rawValue => {
|
|
1423
|
-
const oldValue = config.scope === _Storage.StorageScope.Memory ? getEventRawValue(config.scope, storageKey) : undefined;
|
|
1424
|
-
if (isBiometric) {
|
|
1425
|
-
WebStorage.setSecureBiometricWithLevel(storageKey, rawValue, resolvedBiometricLevel);
|
|
1426
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "web");
|
|
1427
|
-
return;
|
|
1428
|
-
}
|
|
1429
|
-
cacheRawValue(nonMemoryScope, storageKey, rawValue);
|
|
1430
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1431
|
-
if (coalesceDiskWrites || diskWritesAsync) {
|
|
1432
|
-
scheduleDiskWrite(storageKey, rawValue);
|
|
1433
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "web");
|
|
1434
|
-
return;
|
|
1435
|
-
}
|
|
1436
|
-
clearPendingDiskWrite(storageKey);
|
|
1437
|
-
}
|
|
1438
|
-
if (coalesceSecureWrites) {
|
|
1439
|
-
scheduleSecureWrite(storageKey, rawValue, secureAccessControl ?? secureDefaultAccessControl);
|
|
1440
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "web");
|
|
1441
|
-
return;
|
|
1442
|
-
}
|
|
1443
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1444
|
-
clearPendingSecureWrite(storageKey);
|
|
1445
|
-
}
|
|
1446
|
-
WebStorage.set(storageKey, rawValue, config.scope);
|
|
1447
|
-
emitKeyChange(config.scope, storageKey, oldValue, rawValue, "set", "web");
|
|
1448
|
-
};
|
|
1449
|
-
const removeStoredRaw = () => {
|
|
1450
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1451
|
-
if (isBiometric) {
|
|
1452
|
-
WebStorage.deleteSecureBiometric(storageKey);
|
|
1453
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "web");
|
|
1454
|
-
return;
|
|
1455
|
-
}
|
|
1456
|
-
cacheRawValue(nonMemoryScope, storageKey, undefined);
|
|
1457
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1458
|
-
if (coalesceDiskWrites || diskWritesAsync) {
|
|
1459
|
-
scheduleDiskWrite(storageKey, undefined);
|
|
1460
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "web");
|
|
1461
|
-
return;
|
|
1462
|
-
}
|
|
1463
|
-
clearPendingDiskWrite(storageKey);
|
|
1464
|
-
}
|
|
1465
|
-
if (coalesceSecureWrites) {
|
|
1466
|
-
scheduleSecureWrite(storageKey, undefined, secureAccessControl ?? secureDefaultAccessControl);
|
|
1467
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "web");
|
|
1468
|
-
return;
|
|
1469
|
-
}
|
|
1470
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1471
|
-
clearPendingSecureWrite(storageKey);
|
|
1472
|
-
}
|
|
1473
|
-
WebStorage.remove(storageKey, config.scope);
|
|
1474
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "web");
|
|
1475
|
-
};
|
|
1476
|
-
const writeValueWithoutValidation = value => {
|
|
1477
|
-
if (isMemory) {
|
|
1478
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1479
|
-
if (memoryExpiration) {
|
|
1480
|
-
memoryExpiration.set(storageKey, Date.now() + (expirationTtlMs ?? 0));
|
|
1481
|
-
}
|
|
1482
|
-
memoryStore.set(storageKey, value);
|
|
1483
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1484
|
-
emitKeyChange(config.scope, storageKey, oldValue, typeof value === "string" ? value : undefined, "set", "memory");
|
|
1485
|
-
return;
|
|
1486
|
-
}
|
|
1487
|
-
const serialized = serialize(value);
|
|
1488
|
-
if (expiration) {
|
|
1489
|
-
const envelope = {
|
|
1490
|
-
__nitroStorageEnvelope: true,
|
|
1491
|
-
expiresAt: Date.now() + expiration.ttlMs,
|
|
1492
|
-
payload: serialized
|
|
1493
|
-
};
|
|
1494
|
-
writeStoredRaw(JSON.stringify(envelope));
|
|
1495
|
-
return;
|
|
1496
|
-
}
|
|
1497
|
-
writeStoredRaw(serialized);
|
|
1498
|
-
};
|
|
1499
|
-
const resolveInvalidValue = invalidValue => {
|
|
1500
|
-
if (onValidationError) {
|
|
1501
|
-
return onValidationError(invalidValue);
|
|
1502
|
-
}
|
|
1503
|
-
return defaultValue;
|
|
1504
|
-
};
|
|
1505
|
-
const ensureValidatedValue = (candidate, hadStoredValue) => {
|
|
1506
|
-
if (!validate || validate(candidate)) {
|
|
1507
|
-
return candidate;
|
|
1508
|
-
}
|
|
1509
|
-
const resolved = resolveInvalidValue(candidate);
|
|
1510
|
-
if (validate && !validate(resolved)) {
|
|
1511
|
-
return defaultValue;
|
|
1512
|
-
}
|
|
1513
|
-
if (hadStoredValue) {
|
|
1514
|
-
writeValueWithoutValidation(resolved);
|
|
1515
|
-
}
|
|
1516
|
-
return resolved;
|
|
1517
|
-
};
|
|
1518
|
-
const getInternal = () => {
|
|
1519
|
-
const raw = readStoredRaw();
|
|
1520
|
-
if (!memoryExpiration && raw === lastRaw && hasLastValue) {
|
|
1521
|
-
if (!expiration || lastExpiresAt === null) {
|
|
1522
|
-
return lastValue;
|
|
1523
|
-
}
|
|
1524
|
-
if (typeof lastExpiresAt === "number") {
|
|
1525
|
-
if (lastExpiresAt > Date.now()) {
|
|
1526
|
-
return lastValue;
|
|
1527
|
-
}
|
|
1528
|
-
removeStoredRaw();
|
|
1529
|
-
invalidateParsedCache();
|
|
1530
|
-
onExpired?.(storageKey);
|
|
1531
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1532
|
-
hasLastValue = true;
|
|
1533
|
-
listeners.forEach(cb => cb());
|
|
1534
|
-
return lastValue;
|
|
1535
|
-
}
|
|
1536
|
-
}
|
|
1537
|
-
lastRaw = raw;
|
|
1538
|
-
if (raw === undefined) {
|
|
1539
|
-
lastExpiresAt = undefined;
|
|
1540
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1541
|
-
hasLastValue = true;
|
|
1542
|
-
return lastValue;
|
|
1543
|
-
}
|
|
1544
|
-
if (isMemory) {
|
|
1545
|
-
lastExpiresAt = undefined;
|
|
1546
|
-
lastValue = ensureValidatedValue(raw, true);
|
|
1547
|
-
hasLastValue = true;
|
|
1548
|
-
return lastValue;
|
|
1549
|
-
}
|
|
1550
|
-
if (typeof raw !== "string") {
|
|
1551
|
-
lastExpiresAt = undefined;
|
|
1552
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1553
|
-
hasLastValue = true;
|
|
1554
|
-
return lastValue;
|
|
1555
|
-
}
|
|
1556
|
-
let deserializableRaw = raw;
|
|
1557
|
-
if (expiration) {
|
|
1558
|
-
let envelopeExpiresAt = null;
|
|
1559
|
-
try {
|
|
1560
|
-
const parsed = JSON.parse(raw);
|
|
1561
|
-
if ((0, _internal.isStoredEnvelope)(parsed)) {
|
|
1562
|
-
envelopeExpiresAt = parsed.expiresAt;
|
|
1563
|
-
if (parsed.expiresAt <= Date.now()) {
|
|
1564
|
-
removeStoredRaw();
|
|
1565
|
-
invalidateParsedCache();
|
|
1566
|
-
onExpired?.(storageKey);
|
|
1567
|
-
lastValue = ensureValidatedValue(defaultValue, false);
|
|
1568
|
-
hasLastValue = true;
|
|
1569
|
-
listeners.forEach(cb => cb());
|
|
1570
|
-
return lastValue;
|
|
1571
|
-
}
|
|
1572
|
-
deserializableRaw = parsed.payload;
|
|
1573
|
-
}
|
|
1574
|
-
} catch {
|
|
1575
|
-
// Keep backward compatibility with legacy raw values.
|
|
1576
|
-
}
|
|
1577
|
-
lastExpiresAt = envelopeExpiresAt;
|
|
1578
|
-
} else {
|
|
1579
|
-
lastExpiresAt = undefined;
|
|
1580
|
-
}
|
|
1581
|
-
lastValue = ensureValidatedValue(deserialize(deserializableRaw), true);
|
|
1582
|
-
hasLastValue = true;
|
|
1583
|
-
return lastValue;
|
|
1584
|
-
};
|
|
1585
|
-
const getCurrentVersion = () => {
|
|
1586
|
-
const raw = readStoredRaw();
|
|
1587
|
-
return (0, _internal.toVersionToken)(raw);
|
|
1588
|
-
};
|
|
1589
|
-
const get = () => measureOperation("item:get", config.scope, () => getInternal());
|
|
1590
|
-
const getWithVersion = () => measureOperation("item:getWithVersion", config.scope, () => ({
|
|
1591
|
-
value: getInternal(),
|
|
1592
|
-
version: getCurrentVersion()
|
|
1593
|
-
}));
|
|
1594
|
-
const set = valueOrFn => {
|
|
1595
|
-
measureOperation("item:set", config.scope, () => {
|
|
1596
|
-
const newValue = isUpdater(valueOrFn) ? valueOrFn(getInternal()) : valueOrFn;
|
|
1597
|
-
if (validate && !validate(newValue)) {
|
|
1598
|
-
throw new Error(`Validation failed for key "${storageKey}" in scope "${_Storage.StorageScope[config.scope]}".`);
|
|
1599
|
-
}
|
|
1600
|
-
invalidateParsedCache();
|
|
1601
|
-
writeValueWithoutValidation(newValue);
|
|
1602
|
-
});
|
|
1603
|
-
};
|
|
1604
|
-
const setIfVersion = (version, valueOrFn) => measureOperation("item:setIfVersion", config.scope, () => {
|
|
1605
|
-
const currentVersion = getCurrentVersion();
|
|
1606
|
-
if (currentVersion !== version) {
|
|
1607
|
-
return false;
|
|
1608
|
-
}
|
|
1609
|
-
set(valueOrFn);
|
|
1610
|
-
return true;
|
|
1611
|
-
});
|
|
1612
|
-
const deleteItem = () => {
|
|
1613
|
-
measureOperation("item:delete", config.scope, () => {
|
|
1614
|
-
invalidateParsedCache();
|
|
1615
|
-
if (isMemory) {
|
|
1616
|
-
const oldValue = getEventRawValue(config.scope, storageKey);
|
|
1617
|
-
if (memoryExpiration) {
|
|
1618
|
-
memoryExpiration.delete(storageKey);
|
|
1619
|
-
}
|
|
1620
|
-
memoryStore.delete(storageKey);
|
|
1621
|
-
notifyKeyListeners(memoryListeners, storageKey);
|
|
1622
|
-
emitKeyChange(config.scope, storageKey, oldValue, undefined, "remove", "memory");
|
|
1623
|
-
return;
|
|
1624
|
-
}
|
|
1625
|
-
removeStoredRaw();
|
|
1626
|
-
});
|
|
1627
|
-
};
|
|
1628
|
-
const hasItem = () => measureOperation("item:has", config.scope, () => {
|
|
1629
|
-
if (isMemory) return memoryStore.has(storageKey);
|
|
1630
|
-
if (isBiometric) return WebStorage.hasSecureBiometric(storageKey);
|
|
1631
|
-
if (nonMemoryScope === _Storage.StorageScope.Disk) {
|
|
1632
|
-
const pending = pendingDiskWrites.get(storageKey);
|
|
1633
|
-
if (pending !== undefined) {
|
|
1634
|
-
return pending.value !== undefined;
|
|
1635
|
-
}
|
|
1636
|
-
}
|
|
1637
|
-
if (nonMemoryScope === _Storage.StorageScope.Secure) {
|
|
1638
|
-
const pending = pendingSecureWrites.get(storageKey);
|
|
1639
|
-
if (pending !== undefined) {
|
|
1640
|
-
return pending.value !== undefined;
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
return WebStorage.has(storageKey, config.scope);
|
|
1644
|
-
});
|
|
1645
|
-
const subscribe = callback => {
|
|
1646
|
-
ensureSubscription();
|
|
1647
|
-
listeners.add(callback);
|
|
1648
|
-
return () => {
|
|
1649
|
-
listeners.delete(callback);
|
|
1650
|
-
if (listeners.size === 0 && unsubscribe) {
|
|
1651
|
-
unsubscribe();
|
|
1652
|
-
unsubscribe = null;
|
|
1653
|
-
}
|
|
1654
|
-
};
|
|
1655
|
-
};
|
|
1656
|
-
const subscribeSelector = (selector, listener, options = {}) => {
|
|
1657
|
-
const isEqual = options.isEqual ?? Object.is;
|
|
1658
|
-
let currentValue = selector(getInternal());
|
|
1659
|
-
if (options.fireImmediately === true) {
|
|
1660
|
-
listener(currentValue, currentValue);
|
|
1661
|
-
}
|
|
1662
|
-
return subscribe(() => {
|
|
1663
|
-
const nextValue = selector(getInternal());
|
|
1664
|
-
if (isEqual(currentValue, nextValue)) {
|
|
1665
|
-
return;
|
|
1666
|
-
}
|
|
1667
|
-
const previousValue = currentValue;
|
|
1668
|
-
currentValue = nextValue;
|
|
1669
|
-
listener(nextValue, previousValue);
|
|
1670
|
-
});
|
|
1671
|
-
};
|
|
1672
|
-
const storageItem = {
|
|
1673
|
-
get,
|
|
1674
|
-
getWithVersion,
|
|
1675
|
-
set,
|
|
1676
|
-
setIfVersion,
|
|
1677
|
-
delete: deleteItem,
|
|
1678
|
-
has: hasItem,
|
|
1679
|
-
subscribe,
|
|
1680
|
-
subscribeSelector,
|
|
1681
|
-
serialize,
|
|
1682
|
-
deserialize,
|
|
1683
|
-
_triggerListeners: () => {
|
|
1684
|
-
invalidateParsedCache();
|
|
1685
|
-
listeners.forEach(listener => listener());
|
|
1686
|
-
},
|
|
1687
|
-
_invalidateParsedCacheOnly: () => {
|
|
1688
|
-
invalidateParsedCache();
|
|
1689
|
-
},
|
|
1690
|
-
_hasValidation: validate !== undefined,
|
|
1691
|
-
_hasExpiration: expiration !== undefined,
|
|
1692
|
-
_readCacheEnabled: readCache,
|
|
1693
|
-
_isBiometric: isBiometric,
|
|
1694
|
-
_biometricLevel: resolvedBiometricLevel,
|
|
1695
|
-
_defaultValue: defaultValue,
|
|
1696
|
-
...(secureAccessControl !== undefined ? {
|
|
1697
|
-
_secureAccessControl: secureAccessControl
|
|
1698
|
-
} : {}),
|
|
1699
|
-
scope: config.scope,
|
|
1700
|
-
key: storageKey
|
|
1701
|
-
};
|
|
1702
|
-
return storageItem;
|
|
1703
|
-
}
|
|
1704
|
-
function getBatch(items, scope) {
|
|
1705
|
-
return measureOperation("batch:get", scope, () => {
|
|
1706
|
-
(0, _internal.assertBatchScope)(items, scope);
|
|
1707
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1708
|
-
return items.map(item => item.get());
|
|
1709
|
-
}
|
|
1710
|
-
const useRawBatchPath = items.every(item => scope === _Storage.StorageScope.Secure ? canUseSecureRawBatchPath(item) : canUseRawBatchPath(item));
|
|
1711
|
-
if (!useRawBatchPath) {
|
|
1712
|
-
return items.map(item => item.get());
|
|
1713
|
-
}
|
|
1714
|
-
const rawValues = new Array(items.length);
|
|
1715
|
-
const keysToFetch = [];
|
|
1716
|
-
const keyIndexes = [];
|
|
1717
|
-
items.forEach((item, index) => {
|
|
1718
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1719
|
-
const pending = pendingDiskWrites.get(item.key);
|
|
1720
|
-
if (pending !== undefined) {
|
|
1721
|
-
rawValues[index] = pending.value;
|
|
1722
|
-
return;
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1726
|
-
const pending = pendingSecureWrites.get(item.key);
|
|
1727
|
-
if (pending !== undefined) {
|
|
1728
|
-
rawValues[index] = pending.value;
|
|
1729
|
-
return;
|
|
1730
|
-
}
|
|
1731
|
-
}
|
|
1732
|
-
if (item._readCacheEnabled === true) {
|
|
1733
|
-
const cache = getScopeRawCache(scope);
|
|
1734
|
-
const cached = cache.get(item.key);
|
|
1735
|
-
if (cached !== undefined || cache.has(item.key)) {
|
|
1736
|
-
rawValues[index] = cached;
|
|
1737
|
-
return;
|
|
1738
|
-
}
|
|
1739
|
-
}
|
|
1740
|
-
keysToFetch.push(item.key);
|
|
1741
|
-
keyIndexes.push(index);
|
|
1742
|
-
});
|
|
1743
|
-
if (keysToFetch.length > 0) {
|
|
1744
|
-
const fetchedValues = WebStorage.getBatch(keysToFetch, scope);
|
|
1745
|
-
fetchedValues.forEach((value, index) => {
|
|
1746
|
-
const key = keysToFetch[index];
|
|
1747
|
-
const targetIndex = keyIndexes[index];
|
|
1748
|
-
if (key === undefined || targetIndex === undefined) {
|
|
1749
|
-
return;
|
|
1750
|
-
}
|
|
1751
|
-
rawValues[targetIndex] = value;
|
|
1752
|
-
cacheRawValue(scope, key, value);
|
|
1753
|
-
});
|
|
1754
|
-
}
|
|
1755
|
-
return items.map((item, index) => {
|
|
1756
|
-
const raw = rawValues[index];
|
|
1757
|
-
if (raw === undefined) {
|
|
1758
|
-
return asInternal(item)._defaultValue;
|
|
1759
|
-
}
|
|
1760
|
-
return item.deserialize(raw);
|
|
1761
|
-
});
|
|
1762
|
-
}, items.length);
|
|
1763
|
-
}
|
|
1764
|
-
function setBatch(items, scope) {
|
|
1765
|
-
measureOperation("batch:set", scope, () => {
|
|
1766
|
-
(0, _internal.assertBatchScope)(items.map(batchEntry => batchEntry.item), scope);
|
|
1767
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1768
|
-
// Determine if any item needs per-item handling (validation or TTL)
|
|
1769
|
-
const needsIndividualSets = items.some(({
|
|
1770
|
-
item
|
|
1771
|
-
}) => {
|
|
1772
|
-
const internal = asInternal(item);
|
|
1773
|
-
return internal._hasValidation || internal._hasExpiration;
|
|
1774
|
-
});
|
|
1775
|
-
if (needsIndividualSets) {
|
|
1776
|
-
items.forEach(({
|
|
1777
|
-
item,
|
|
1778
|
-
value
|
|
1779
|
-
}) => item.set(value));
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
|
-
const changes = items.map(({
|
|
1783
|
-
item,
|
|
1784
|
-
value
|
|
1785
|
-
}) => createKeyChange(scope, item.key, getEventRawValue(scope, item.key), typeof value === "string" ? value : undefined, "setBatch", "memory"));
|
|
1786
|
-
|
|
1787
|
-
// Atomic write: update all values in memoryStore, invalidate caches, then batch-notify
|
|
1788
|
-
items.forEach(({
|
|
1789
|
-
item,
|
|
1790
|
-
value
|
|
1791
|
-
}) => {
|
|
1792
|
-
memoryStore.set(item.key, value);
|
|
1793
|
-
asInternal(item)._invalidateParsedCacheOnly();
|
|
1794
|
-
});
|
|
1795
|
-
items.forEach(({
|
|
1796
|
-
item
|
|
1797
|
-
}) => notifyKeyListeners(memoryListeners, item.key));
|
|
1798
|
-
emitBatchChange(scope, "setBatch", "memory", changes);
|
|
1799
|
-
return;
|
|
1800
|
-
}
|
|
1801
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1802
|
-
const secureEntries = items.map(({
|
|
1803
|
-
item,
|
|
1804
|
-
value
|
|
1805
|
-
}) => ({
|
|
1806
|
-
item,
|
|
1807
|
-
value,
|
|
1808
|
-
internal: asInternal(item)
|
|
1809
|
-
}));
|
|
1810
|
-
const canUseSecureBatchPath = secureEntries.every(({
|
|
1811
|
-
internal
|
|
1812
|
-
}) => canUseSecureRawBatchPath(internal));
|
|
1813
|
-
if (!canUseSecureBatchPath) {
|
|
1814
|
-
items.forEach(({
|
|
1815
|
-
item,
|
|
1816
|
-
value
|
|
1817
|
-
}) => item.set(value));
|
|
1818
|
-
return;
|
|
1819
|
-
}
|
|
1820
|
-
flushSecureWrites();
|
|
1821
|
-
const keys = secureEntries.map(({
|
|
1822
|
-
item
|
|
1823
|
-
}) => item.key);
|
|
1824
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1825
|
-
const groupedByAccessControl = new Map();
|
|
1826
|
-
secureEntries.forEach(({
|
|
1827
|
-
item,
|
|
1828
|
-
value,
|
|
1829
|
-
internal
|
|
1830
|
-
}) => {
|
|
1831
|
-
const accessControl = internal._secureAccessControl ?? secureDefaultAccessControl;
|
|
1832
|
-
const existingGroup = groupedByAccessControl.get(accessControl);
|
|
1833
|
-
const group = existingGroup ?? {
|
|
1834
|
-
keys: [],
|
|
1835
|
-
values: []
|
|
1836
|
-
};
|
|
1837
|
-
group.keys.push(item.key);
|
|
1838
|
-
group.values.push(item.serialize(value));
|
|
1839
|
-
if (!existingGroup) {
|
|
1840
|
-
groupedByAccessControl.set(accessControl, group);
|
|
1841
|
-
}
|
|
1842
|
-
});
|
|
1843
|
-
groupedByAccessControl.forEach((group, accessControl) => {
|
|
1844
|
-
WebStorage.setSecureAccessControl(accessControl);
|
|
1845
|
-
WebStorage.setBatch(group.keys, group.values, scope);
|
|
1846
|
-
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
1847
|
-
});
|
|
1848
|
-
emitBatchChange(scope, "setBatch", "web", secureEntries.map(({
|
|
1849
|
-
item,
|
|
1850
|
-
value
|
|
1851
|
-
}, index) => createKeyChange(scope, item.key, oldValues[index], item.serialize(value), "setBatch", "web")));
|
|
1852
|
-
return;
|
|
1853
|
-
}
|
|
1854
|
-
flushDiskWrites();
|
|
1855
|
-
const useRawBatchPath = items.every(({
|
|
1856
|
-
item
|
|
1857
|
-
}) => canUseRawBatchPath(asInternal(item)));
|
|
1858
|
-
if (!useRawBatchPath) {
|
|
1859
|
-
items.forEach(({
|
|
1860
|
-
item,
|
|
1861
|
-
value
|
|
1862
|
-
}) => item.set(value));
|
|
1863
|
-
return;
|
|
1864
|
-
}
|
|
1865
|
-
const keys = items.map(entry => entry.item.key);
|
|
1866
|
-
const values = items.map(entry => entry.item.serialize(entry.value));
|
|
1867
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1868
|
-
WebStorage.setBatch(keys, values, scope);
|
|
1869
|
-
keys.forEach((key, index) => cacheRawValue(scope, key, values[index]));
|
|
1870
|
-
emitBatchChange(scope, "setBatch", "web", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], values[index], "setBatch", "web")));
|
|
1871
|
-
}, items.length);
|
|
1872
|
-
}
|
|
1873
|
-
function removeBatch(items, scope) {
|
|
1874
|
-
measureOperation("batch:remove", scope, () => {
|
|
1875
|
-
(0, _internal.assertBatchScope)(items, scope);
|
|
1876
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1877
|
-
const changes = items.map(item => createKeyChange(scope, item.key, getEventRawValue(scope, item.key), undefined, "removeBatch", "memory"));
|
|
1878
|
-
items.forEach(item => item.delete());
|
|
1879
|
-
emitBatchChange(scope, "removeBatch", "memory", changes);
|
|
1880
|
-
return;
|
|
1881
|
-
}
|
|
1882
|
-
const keys = items.map(item => item.key);
|
|
1883
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1884
|
-
flushDiskWrites();
|
|
1885
|
-
}
|
|
1886
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1887
|
-
flushSecureWrites();
|
|
1888
|
-
}
|
|
1889
|
-
const oldValues = shouldReadPreviousEventValues(scope) ? WebStorage.getBatch(keys, scope) : [];
|
|
1890
|
-
WebStorage.removeBatch(keys, scope);
|
|
1891
|
-
keys.forEach(key => cacheRawValue(scope, key, undefined));
|
|
1892
|
-
emitBatchChange(scope, "removeBatch", "web", keys.map((key, index) => createKeyChange(scope, key, oldValues[index], undefined, "removeBatch", "web")));
|
|
1893
|
-
}, items.length);
|
|
1894
|
-
}
|
|
1895
|
-
function registerMigration(version, migration) {
|
|
1896
|
-
if (!Number.isInteger(version) || version <= 0) {
|
|
1897
|
-
throw new Error("Migration version must be a positive integer.");
|
|
1898
|
-
}
|
|
1899
|
-
if (registeredMigrations.has(version)) {
|
|
1900
|
-
throw new Error(`Migration version ${version} is already registered.`);
|
|
1901
|
-
}
|
|
1902
|
-
registeredMigrations.set(version, migration);
|
|
1903
|
-
}
|
|
1904
|
-
function migrateToLatest(scope = _Storage.StorageScope.Disk) {
|
|
1905
|
-
return measureOperation("migration:run", scope, () => {
|
|
1906
|
-
(0, _internal.assertValidScope)(scope);
|
|
1907
|
-
const currentVersion = readMigrationVersion(scope);
|
|
1908
|
-
const versions = Array.from(registeredMigrations.keys()).filter(version => version > currentVersion).sort((a, b) => a - b);
|
|
1909
|
-
let appliedVersion = currentVersion;
|
|
1910
|
-
const context = {
|
|
1911
|
-
scope,
|
|
1912
|
-
getRaw: key => getRawValue(key, scope),
|
|
1913
|
-
setRaw: (key, value) => setRawValue(key, value, scope),
|
|
1914
|
-
removeRaw: key => removeRawValue(key, scope)
|
|
1915
|
-
};
|
|
1916
|
-
versions.forEach(version => {
|
|
1917
|
-
const migration = registeredMigrations.get(version);
|
|
1918
|
-
if (!migration) {
|
|
1919
|
-
return;
|
|
1920
|
-
}
|
|
1921
|
-
migration(context);
|
|
1922
|
-
appliedVersion = version;
|
|
1923
|
-
});
|
|
1924
|
-
if (appliedVersion !== currentVersion) {
|
|
1925
|
-
writeMigrationVersion(scope, appliedVersion);
|
|
1926
|
-
}
|
|
1927
|
-
return appliedVersion;
|
|
1928
|
-
});
|
|
1929
|
-
}
|
|
1930
|
-
function runTransaction(scope, transaction) {
|
|
1931
|
-
return measureOperation("transaction:run", scope, () => {
|
|
1932
|
-
(0, _internal.assertValidScope)(scope);
|
|
1933
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
1934
|
-
flushDiskWrites();
|
|
1935
|
-
}
|
|
1936
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
1937
|
-
flushSecureWrites();
|
|
1938
|
-
}
|
|
1939
|
-
const NOT_SET = Symbol();
|
|
1940
|
-
const rollback = new Map();
|
|
1941
|
-
const rememberRollback = (key, item) => {
|
|
1942
|
-
if (rollback.has(key)) {
|
|
1943
|
-
return;
|
|
1944
|
-
}
|
|
1945
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
1946
|
-
rollback.set(key, {
|
|
1947
|
-
kind: "memory",
|
|
1948
|
-
value: memoryStore.has(key) ? memoryStore.get(key) : NOT_SET
|
|
1949
|
-
});
|
|
1950
|
-
} else {
|
|
1951
|
-
const internal = item ? item : undefined;
|
|
1952
|
-
if (scope === _Storage.StorageScope.Secure && internal?._isBiometric === true) {
|
|
1953
|
-
rollback.set(key, {
|
|
1954
|
-
kind: "biometric",
|
|
1955
|
-
value: WebStorage.getSecureBiometric(key),
|
|
1956
|
-
level: internal._biometricLevel
|
|
1957
|
-
});
|
|
1958
|
-
return;
|
|
1959
|
-
}
|
|
1960
|
-
rollback.set(key, {
|
|
1961
|
-
kind: "raw",
|
|
1962
|
-
value: getRawValue(key, scope),
|
|
1963
|
-
...(scope === _Storage.StorageScope.Secure && internal?._secureAccessControl !== undefined ? {
|
|
1964
|
-
accessControl: internal._secureAccessControl
|
|
1965
|
-
} : {})
|
|
1966
|
-
});
|
|
1967
|
-
}
|
|
1968
|
-
};
|
|
1969
|
-
const tx = {
|
|
1970
|
-
scope,
|
|
1971
|
-
getRaw: key => getRawValue(key, scope),
|
|
1972
|
-
setRaw: (key, value) => {
|
|
1973
|
-
rememberRollback(key);
|
|
1974
|
-
setRawValue(key, value, scope);
|
|
1975
|
-
},
|
|
1976
|
-
removeRaw: key => {
|
|
1977
|
-
rememberRollback(key);
|
|
1978
|
-
removeRawValue(key, scope);
|
|
1979
|
-
},
|
|
1980
|
-
getItem: item => {
|
|
1981
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1982
|
-
return item.get();
|
|
1983
|
-
},
|
|
1984
|
-
setItem: (item, value) => {
|
|
1985
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1986
|
-
rememberRollback(item.key, item);
|
|
1987
|
-
item.set(value);
|
|
1988
|
-
},
|
|
1989
|
-
removeItem: item => {
|
|
1990
|
-
(0, _internal.assertBatchScope)([item], scope);
|
|
1991
|
-
rememberRollback(item.key, item);
|
|
1992
|
-
item.delete();
|
|
1993
|
-
}
|
|
1994
|
-
};
|
|
1995
|
-
try {
|
|
1996
|
-
return transaction(tx);
|
|
1997
|
-
} catch (error) {
|
|
1998
|
-
const rollbackEntries = Array.from(rollback.entries()).reverse();
|
|
1999
|
-
if (scope === _Storage.StorageScope.Memory) {
|
|
2000
|
-
rollbackEntries.forEach(([key, record]) => {
|
|
2001
|
-
if (record.value === NOT_SET) {
|
|
2002
|
-
memoryStore.delete(key);
|
|
2003
|
-
} else {
|
|
2004
|
-
memoryStore.set(key, record.value);
|
|
2005
|
-
}
|
|
2006
|
-
notifyKeyListeners(memoryListeners, key);
|
|
2007
|
-
});
|
|
2008
|
-
} else {
|
|
2009
|
-
const groupedKeysToSet = new Map();
|
|
2010
|
-
const keysToRemove = [];
|
|
2011
|
-
rollbackEntries.forEach(([key, record]) => {
|
|
2012
|
-
if (record.kind === "biometric") {
|
|
2013
|
-
if (record.value === undefined) {
|
|
2014
|
-
WebStorage.deleteSecureBiometric(key);
|
|
2015
|
-
} else {
|
|
2016
|
-
WebStorage.setSecureBiometricWithLevel(key, record.value, record.level);
|
|
2017
|
-
}
|
|
2018
|
-
return;
|
|
2019
|
-
}
|
|
2020
|
-
if (record.kind !== "raw") {
|
|
2021
|
-
return;
|
|
2022
|
-
}
|
|
2023
|
-
if (record.value === undefined) {
|
|
2024
|
-
keysToRemove.push(key);
|
|
2025
|
-
} else {
|
|
2026
|
-
const accessControl = record.accessControl ?? secureDefaultAccessControl;
|
|
2027
|
-
const existingGroup = groupedKeysToSet.get(accessControl);
|
|
2028
|
-
const group = existingGroup ?? {
|
|
2029
|
-
keys: [],
|
|
2030
|
-
values: []
|
|
2031
|
-
};
|
|
2032
|
-
group.keys.push(key);
|
|
2033
|
-
group.values.push(record.value);
|
|
2034
|
-
if (!existingGroup) {
|
|
2035
|
-
groupedKeysToSet.set(accessControl, group);
|
|
2036
|
-
}
|
|
2037
|
-
}
|
|
2038
|
-
});
|
|
2039
|
-
if (scope === _Storage.StorageScope.Disk) {
|
|
2040
|
-
flushDiskWrites();
|
|
2041
|
-
}
|
|
2042
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
2043
|
-
flushSecureWrites();
|
|
2044
|
-
}
|
|
2045
|
-
groupedKeysToSet.forEach((group, accessControl) => {
|
|
2046
|
-
if (scope === _Storage.StorageScope.Secure) {
|
|
2047
|
-
WebStorage.setSecureAccessControl(accessControl);
|
|
2048
|
-
}
|
|
2049
|
-
WebStorage.setBatch(group.keys, group.values, scope);
|
|
2050
|
-
group.keys.forEach((key, index) => cacheRawValue(scope, key, group.values[index]));
|
|
2051
|
-
});
|
|
2052
|
-
if (keysToRemove.length > 0) {
|
|
2053
|
-
WebStorage.removeBatch(keysToRemove, scope);
|
|
2054
|
-
keysToRemove.forEach(key => cacheRawValue(scope, key, undefined));
|
|
2055
|
-
}
|
|
2056
|
-
}
|
|
2057
|
-
throw error;
|
|
2058
|
-
}
|
|
2059
|
-
});
|
|
2060
|
-
}
|
|
2061
|
-
function createSecureAuthStorage(config, options) {
|
|
2062
|
-
const ns = options?.namespace ?? "auth";
|
|
2063
|
-
const result = {};
|
|
2064
|
-
for (const key of typedKeys(config)) {
|
|
2065
|
-
const itemConfig = config[key];
|
|
2066
|
-
const expirationConfig = itemConfig.ttlMs !== undefined ? {
|
|
2067
|
-
ttlMs: itemConfig.ttlMs
|
|
2068
|
-
} : undefined;
|
|
2069
|
-
result[key] = createStorageItem({
|
|
2070
|
-
key,
|
|
2071
|
-
scope: _Storage.StorageScope.Secure,
|
|
2072
|
-
defaultValue: "",
|
|
2073
|
-
namespace: ns,
|
|
2074
|
-
...(itemConfig.biometric !== undefined ? {
|
|
2075
|
-
biometric: itemConfig.biometric
|
|
2076
|
-
} : {}),
|
|
2077
|
-
...(itemConfig.biometricLevel !== undefined ? {
|
|
2078
|
-
biometricLevel: itemConfig.biometricLevel
|
|
2079
|
-
} : {}),
|
|
2080
|
-
...(itemConfig.accessControl !== undefined ? {
|
|
2081
|
-
accessControl: itemConfig.accessControl
|
|
2082
|
-
} : {}),
|
|
2083
|
-
...(expirationConfig !== undefined ? {
|
|
2084
|
-
expiration: expirationConfig
|
|
2085
|
-
} : {})
|
|
2086
|
-
});
|
|
2087
|
-
}
|
|
2088
|
-
return result;
|
|
2089
|
-
}
|
|
2090
|
-
function isKeychainLockedError(err) {
|
|
2091
|
-
return (0, _storageRuntime.isLockedStorageErrorCode)((0, _storageRuntime.getStorageErrorCode)(err));
|
|
2092
|
-
}
|
|
2093
626
|
//# sourceMappingURL=index.web.js.map
|