react-native-nitro-storage 0.6.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/README.md +36 -12
- package/SECURITY.md +2 -2
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +225 -76
- package/app.plugin.js +2 -0
- package/cpp/bindings/HybridStorage.cpp +4 -12
- package/docs/api-reference.md +11 -1
- package/docs/batch-transactions-migrations.md +8 -2
- package/docs/benchmarks.md +19 -15
- package/docs/secure-storage.md +4 -0
- package/docs/web-backends.md +18 -1
- package/ios/IOSStorageAdapterCpp.mm +162 -17
- package/lib/commonjs/capabilities.js +26 -0
- package/lib/commonjs/capabilities.js.map +1 -0
- package/lib/commonjs/core/durability.js +137 -0
- package/lib/commonjs/core/durability.js.map +1 -0
- package/lib/commonjs/core/metrics.js +91 -0
- package/lib/commonjs/core/metrics.js.map +1 -0
- package/lib/commonjs/index.js +47 -22
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +118 -66
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/indexeddb-backend.js +73 -23
- package/lib/commonjs/indexeddb-backend.js.map +1 -1
- package/lib/commonjs/internal.js +27 -4
- package/lib/commonjs/internal.js.map +1 -1
- package/lib/commonjs/shared.js +2 -2
- package/lib/commonjs/shared.js.map +1 -1
- package/lib/commonjs/storage-core.js +217 -233
- package/lib/commonjs/storage-core.js.map +1 -1
- package/lib/commonjs/storage-platform.js +6 -0
- package/lib/commonjs/storage-platform.js.map +1 -0
- package/lib/commonjs/storage-runtime.js +3 -21
- package/lib/commonjs/storage-runtime.js.map +1 -1
- package/lib/commonjs/testing.js +19 -4
- package/lib/commonjs/testing.js.map +1 -1
- package/lib/commonjs/web-backend-contract.js +27 -0
- package/lib/commonjs/web-backend-contract.js.map +1 -0
- package/lib/module/capabilities.js +21 -0
- package/lib/module/capabilities.js.map +1 -0
- package/lib/module/core/durability.js +133 -0
- package/lib/module/core/durability.js.map +1 -0
- package/lib/module/core/metrics.js +87 -0
- package/lib/module/core/metrics.js.map +1 -0
- package/lib/module/index.js +48 -23
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +103 -64
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/indexeddb-backend.js +73 -23
- package/lib/module/indexeddb-backend.js.map +1 -1
- package/lib/module/internal.js +24 -3
- package/lib/module/internal.js.map +1 -1
- package/lib/module/shared.js +2 -2
- package/lib/module/shared.js.map +1 -1
- package/lib/module/storage-core.js +218 -234
- package/lib/module/storage-core.js.map +1 -1
- package/lib/module/storage-platform.js +4 -0
- package/lib/module/storage-platform.js.map +1 -0
- package/lib/module/storage-runtime.js +3 -21
- package/lib/module/storage-runtime.js.map +1 -1
- package/lib/module/testing.js +5 -3
- package/lib/module/testing.js.map +1 -1
- package/lib/module/web-backend-contract.js +22 -0
- package/lib/module/web-backend-contract.js.map +1 -0
- package/lib/typescript/capabilities.d.ts +11 -0
- package/lib/typescript/capabilities.d.ts.map +1 -0
- package/lib/typescript/core/durability.d.ts +27 -0
- package/lib/typescript/core/durability.d.ts.map +1 -0
- package/lib/typescript/core/metrics.d.ts +12 -0
- package/lib/typescript/core/metrics.d.ts.map +1 -0
- package/lib/typescript/index.d.ts +11 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +14 -5
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/indexeddb-backend.d.ts.map +1 -1
- package/lib/typescript/internal.d.ts +3 -0
- package/lib/typescript/internal.d.ts.map +1 -1
- package/lib/typescript/shared.d.ts +2 -1
- package/lib/typescript/shared.d.ts.map +1 -1
- package/lib/typescript/storage-core.d.ts +14 -4
- package/lib/typescript/storage-core.d.ts.map +1 -1
- package/lib/typescript/storage-events.d.ts +2 -2
- package/lib/typescript/storage-events.d.ts.map +1 -1
- package/lib/typescript/storage-platform.d.ts +12 -0
- package/lib/typescript/storage-platform.d.ts.map +1 -0
- package/lib/typescript/storage-runtime.d.ts.map +1 -1
- package/lib/typescript/testing.d.ts +17 -3
- package/lib/typescript/testing.d.ts.map +1 -1
- package/lib/typescript/web-backend-contract.d.ts +10 -0
- package/lib/typescript/web-backend-contract.d.ts.map +1 -0
- package/lib/typescript/web-storage-backend.d.ts +1 -1
- package/lib/typescript/web-storage-backend.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/capabilities.ts +36 -0
- package/src/core/durability.ts +170 -0
- package/src/core/metrics.ts +133 -0
- package/src/index.ts +67 -42
- package/src/index.web.ts +159 -88
- package/src/indexeddb-backend.ts +92 -22
- package/src/internal.ts +51 -5
- package/src/shared.ts +7 -6
- package/src/storage-core.ts +336 -287
- package/src/storage-events.ts +3 -3
- package/src/storage-platform.ts +16 -0
- package/src/storage-runtime.ts +13 -47
- package/src/testing.ts +14 -7
- package/src/web-backend-contract.ts +34 -0
- package/src/web-storage-backend.ts +1 -1
package/src/indexeddb-backend.ts
CHANGED
|
@@ -19,7 +19,11 @@ export type IndexedDBBackendOptions = {
|
|
|
19
19
|
function openDB(dbName: string, storeName: string): Promise<IDBDatabase> {
|
|
20
20
|
return new Promise((resolve, reject) => {
|
|
21
21
|
if (typeof indexedDB === "undefined") {
|
|
22
|
-
reject(
|
|
22
|
+
reject(
|
|
23
|
+
new Error(
|
|
24
|
+
"[nitro-error:unsupported] IndexedDB is not available in this environment.",
|
|
25
|
+
),
|
|
26
|
+
);
|
|
23
27
|
return;
|
|
24
28
|
}
|
|
25
29
|
|
|
@@ -32,9 +36,12 @@ function openDB(dbName: string, storeName: string): Promise<IDBDatabase> {
|
|
|
32
36
|
}
|
|
33
37
|
};
|
|
34
38
|
|
|
35
|
-
request.onsuccess = () =>
|
|
36
|
-
|
|
39
|
+
request.onsuccess = () => {
|
|
40
|
+
resolve(request.result);
|
|
41
|
+
};
|
|
42
|
+
request.onerror = () => {
|
|
37
43
|
reject(request.error ?? new Error("Failed to open IndexedDB database."));
|
|
44
|
+
};
|
|
38
45
|
});
|
|
39
46
|
}
|
|
40
47
|
|
|
@@ -72,7 +79,7 @@ export async function createIndexedDBBackend(
|
|
|
72
79
|
const db = await openDB(dbName, storeName);
|
|
73
80
|
const cache = new Map<string, string>();
|
|
74
81
|
const pendingWrites = new Set<Promise<void>>();
|
|
75
|
-
const pendingErrors: Error[] = [];
|
|
82
|
+
const pendingErrors: { keys: string[] | null; error: Error }[] = [];
|
|
76
83
|
const subscribers = new Set<(event: WebStorageChangeEvent) => void>();
|
|
77
84
|
let closed = false;
|
|
78
85
|
const sourceId = `nitro-storage-${Math.random().toString(36).slice(2)}`;
|
|
@@ -95,23 +102,58 @@ export async function createIndexedDBBackend(
|
|
|
95
102
|
});
|
|
96
103
|
}
|
|
97
104
|
|
|
98
|
-
function handleAsyncError(error: unknown): void {
|
|
105
|
+
function handleAsyncError(keys: string[] | null, error: unknown): void {
|
|
99
106
|
const normalized =
|
|
100
107
|
error instanceof Error
|
|
101
108
|
? error
|
|
102
109
|
: new Error(String(error ?? "Unknown IndexedDB error"));
|
|
103
|
-
pendingErrors.push(normalized);
|
|
110
|
+
pendingErrors.push({ keys, error: normalized });
|
|
104
111
|
options.onError?.(normalized);
|
|
105
112
|
}
|
|
106
113
|
|
|
114
|
+
function handleLifecycleFlush(): void {
|
|
115
|
+
if (closed || pendingWrites.size === 0) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
void Promise.all(Array.from(pendingWrites)).catch(() => {
|
|
119
|
+
// Errors are surfaced through flush() and onError; the page may be
|
|
120
|
+
// hidden, so the flush result is intentionally not awaited here.
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function installLifecycleFlush(): () => void {
|
|
125
|
+
if (typeof globalThis === "undefined" || !globalThis.addEventListener) {
|
|
126
|
+
return () => {};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
const onPageHide = () => {
|
|
130
|
+
handleLifecycleFlush();
|
|
131
|
+
};
|
|
132
|
+
const onVisibilityChange = () => {
|
|
133
|
+
if (
|
|
134
|
+
typeof document !== "undefined" &&
|
|
135
|
+
document.visibilityState === "hidden"
|
|
136
|
+
) {
|
|
137
|
+
handleLifecycleFlush();
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
globalThis.addEventListener("pagehide", onPageHide);
|
|
141
|
+
globalThis.addEventListener("visibilitychange", onVisibilityChange);
|
|
142
|
+
return () => {
|
|
143
|
+
globalThis.removeEventListener("pagehide", onPageHide);
|
|
144
|
+
globalThis.removeEventListener("visibilitychange", onVisibilityChange);
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const removeLifecycleFlush = installLifecycleFlush();
|
|
149
|
+
|
|
107
150
|
channel?.addEventListener("message", (event: MessageEvent) => {
|
|
108
151
|
if (closed) {
|
|
109
152
|
return;
|
|
110
153
|
}
|
|
111
154
|
|
|
112
155
|
const data = event.data as
|
|
113
|
-
|
|
114
|
-
| undefined;
|
|
156
|
+
(WebStorageChangeEvent & { sourceId?: string }) | undefined;
|
|
115
157
|
if (!data || data.sourceId === sourceId) {
|
|
116
158
|
return;
|
|
117
159
|
}
|
|
@@ -154,22 +196,29 @@ export async function createIndexedDBBackend(
|
|
|
154
196
|
}
|
|
155
197
|
};
|
|
156
198
|
|
|
157
|
-
tx.oncomplete = () =>
|
|
158
|
-
|
|
199
|
+
tx.oncomplete = () => {
|
|
200
|
+
resolve();
|
|
201
|
+
};
|
|
202
|
+
tx.onerror = () => {
|
|
159
203
|
reject(tx.error ?? new Error("Failed to load IndexedDB entries."));
|
|
204
|
+
};
|
|
160
205
|
});
|
|
161
206
|
|
|
162
|
-
function trackWrite(tx: IDBTransaction): void {
|
|
207
|
+
function trackWrite(tx: IDBTransaction, keys: string[] | null): void {
|
|
163
208
|
const pending = new Promise<void>((resolve) => {
|
|
164
|
-
tx.oncomplete = () =>
|
|
209
|
+
tx.oncomplete = () => {
|
|
210
|
+
resolve();
|
|
211
|
+
};
|
|
165
212
|
tx.onerror = () => {
|
|
166
213
|
handleAsyncError(
|
|
214
|
+
keys,
|
|
167
215
|
tx.error ?? new Error("Failed to persist IndexedDB transaction."),
|
|
168
216
|
);
|
|
169
217
|
resolve();
|
|
170
218
|
};
|
|
171
219
|
tx.onabort = () => {
|
|
172
220
|
handleAsyncError(
|
|
221
|
+
keys,
|
|
173
222
|
tx.error ?? new Error("IndexedDB transaction was aborted."),
|
|
174
223
|
);
|
|
175
224
|
resolve();
|
|
@@ -187,9 +236,10 @@ export async function createIndexedDBBackend(
|
|
|
187
236
|
try {
|
|
188
237
|
const tx = db.transaction(storeName, "readwrite");
|
|
189
238
|
tx.objectStore(storeName).put(value, key);
|
|
190
|
-
trackWrite(tx);
|
|
239
|
+
trackWrite(tx, [key]);
|
|
191
240
|
} catch {
|
|
192
241
|
handleAsyncError(
|
|
242
|
+
[key],
|
|
193
243
|
new Error(`Failed to queue IndexedDB write for "${key}".`),
|
|
194
244
|
);
|
|
195
245
|
}
|
|
@@ -199,9 +249,10 @@ export async function createIndexedDBBackend(
|
|
|
199
249
|
try {
|
|
200
250
|
const tx = db.transaction(storeName, "readwrite");
|
|
201
251
|
tx.objectStore(storeName).delete(key);
|
|
202
|
-
trackWrite(tx);
|
|
252
|
+
trackWrite(tx, [key]);
|
|
203
253
|
} catch {
|
|
204
254
|
handleAsyncError(
|
|
255
|
+
[key],
|
|
205
256
|
new Error(`Failed to queue IndexedDB delete for "${key}".`),
|
|
206
257
|
);
|
|
207
258
|
}
|
|
@@ -211,9 +262,9 @@ export async function createIndexedDBBackend(
|
|
|
211
262
|
try {
|
|
212
263
|
const tx = db.transaction(storeName, "readwrite");
|
|
213
264
|
tx.objectStore(storeName).clear();
|
|
214
|
-
trackWrite(tx);
|
|
265
|
+
trackWrite(tx, null);
|
|
215
266
|
} catch {
|
|
216
|
-
handleAsyncError(new Error("Failed to queue IndexedDB clear."));
|
|
267
|
+
handleAsyncError(null, new Error("Failed to queue IndexedDB clear."));
|
|
217
268
|
}
|
|
218
269
|
}
|
|
219
270
|
|
|
@@ -255,8 +306,10 @@ export async function createIndexedDBBackend(
|
|
|
255
306
|
},
|
|
256
307
|
setMany(entries): void {
|
|
257
308
|
assertOpen();
|
|
309
|
+
const keys: string[] = [];
|
|
258
310
|
entries.forEach(([key, value]) => {
|
|
259
311
|
cache.set(key, value);
|
|
312
|
+
keys.push(key);
|
|
260
313
|
});
|
|
261
314
|
try {
|
|
262
315
|
const tx = db.transaction(storeName, "readwrite");
|
|
@@ -265,9 +318,12 @@ export async function createIndexedDBBackend(
|
|
|
265
318
|
store.put(value, key);
|
|
266
319
|
publish({ key, newValue: value });
|
|
267
320
|
});
|
|
268
|
-
trackWrite(tx);
|
|
321
|
+
trackWrite(tx, keys);
|
|
269
322
|
} catch {
|
|
270
|
-
handleAsyncError(
|
|
323
|
+
handleAsyncError(
|
|
324
|
+
null,
|
|
325
|
+
new Error("Failed to queue IndexedDB batch write."),
|
|
326
|
+
);
|
|
271
327
|
}
|
|
272
328
|
},
|
|
273
329
|
removeMany(keys: string[]): void {
|
|
@@ -282,9 +338,12 @@ export async function createIndexedDBBackend(
|
|
|
282
338
|
store.delete(key);
|
|
283
339
|
publish({ key, newValue: null });
|
|
284
340
|
});
|
|
285
|
-
trackWrite(tx);
|
|
341
|
+
trackWrite(tx, keys);
|
|
286
342
|
} catch {
|
|
287
|
-
handleAsyncError(
|
|
343
|
+
handleAsyncError(
|
|
344
|
+
null,
|
|
345
|
+
new Error("Failed to queue IndexedDB batch delete."),
|
|
346
|
+
);
|
|
288
347
|
}
|
|
289
348
|
},
|
|
290
349
|
size(): number {
|
|
@@ -304,14 +363,25 @@ export async function createIndexedDBBackend(
|
|
|
304
363
|
return;
|
|
305
364
|
}
|
|
306
365
|
|
|
307
|
-
const
|
|
308
|
-
|
|
366
|
+
const failures = pendingErrors.splice(0);
|
|
367
|
+
const failedKeys = failures
|
|
368
|
+
.flatMap(({ keys }) => keys ?? [])
|
|
369
|
+
.filter((key, index, all) => all.indexOf(key) === index);
|
|
370
|
+
const keyDetail =
|
|
371
|
+
failedKeys.length > 0
|
|
372
|
+
? ` Affected keys: ${failedKeys.join(", ")}.`
|
|
373
|
+
: "";
|
|
374
|
+
const [first] = failures;
|
|
375
|
+
throw new Error(
|
|
376
|
+
`NitroStorage: IndexedDB persistence failed for ${failures.length} write(s).${keyDetail} ${first?.error.message ?? ""}`,
|
|
377
|
+
);
|
|
309
378
|
},
|
|
310
379
|
close(): void {
|
|
311
380
|
if (closed) {
|
|
312
381
|
return;
|
|
313
382
|
}
|
|
314
383
|
closed = true;
|
|
384
|
+
removeLifecycleFlush();
|
|
315
385
|
subscribers.clear();
|
|
316
386
|
channel?.close();
|
|
317
387
|
db.close();
|
package/src/internal.ts
CHANGED
|
@@ -16,6 +16,36 @@ const PRIM_NAN = "__nitro_storage_primitive__:n:NaN";
|
|
|
16
16
|
const NAMESPACE_SEPARATOR = ":";
|
|
17
17
|
const VERSION_TOKEN_PREFIX = "__nitro_storage_version__:";
|
|
18
18
|
|
|
19
|
+
export const ESCAPE_PREFIX = "__nitro_storage_escaped__:";
|
|
20
|
+
|
|
21
|
+
const RESERVED_RAW_TOKENS = new Set<string>([
|
|
22
|
+
PRIM_NULL,
|
|
23
|
+
PRIM_UNDEFINED,
|
|
24
|
+
PRIM_TRUE,
|
|
25
|
+
PRIM_FALSE,
|
|
26
|
+
PRIM_INFINITY,
|
|
27
|
+
PRIM_NEG_INFINITY,
|
|
28
|
+
PRIM_NAN,
|
|
29
|
+
NATIVE_BATCH_MISSING_SENTINEL,
|
|
30
|
+
]);
|
|
31
|
+
|
|
32
|
+
export function escapeCollidingRawValue(value: string): string {
|
|
33
|
+
if (
|
|
34
|
+
RESERVED_RAW_TOKENS.has(value) ||
|
|
35
|
+
value.startsWith(PRIMITIVE_FAST_PATH_PREFIX) ||
|
|
36
|
+
value.startsWith(ESCAPE_PREFIX)
|
|
37
|
+
) {
|
|
38
|
+
return `${ESCAPE_PREFIX}${value}`;
|
|
39
|
+
}
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function unescapeCollidingRawValue(value: string): string {
|
|
44
|
+
return value.startsWith(ESCAPE_PREFIX)
|
|
45
|
+
? value.slice(ESCAPE_PREFIX.length)
|
|
46
|
+
: value;
|
|
47
|
+
}
|
|
48
|
+
|
|
19
49
|
export type StoredEnvelope = {
|
|
20
50
|
__nitroStorageEnvelope: true;
|
|
21
51
|
expiresAt: number;
|
|
@@ -71,7 +101,7 @@ export function assertBatchScope(
|
|
|
71
101
|
export function decodeNativeBatchValue(
|
|
72
102
|
value: string | undefined,
|
|
73
103
|
): string | undefined {
|
|
74
|
-
if (value === NATIVE_BATCH_MISSING_SENTINEL) {
|
|
104
|
+
if (value === undefined || value === NATIVE_BATCH_MISSING_SENTINEL) {
|
|
75
105
|
return undefined;
|
|
76
106
|
}
|
|
77
107
|
|
|
@@ -93,13 +123,22 @@ export function serializeWithPrimitiveFastPath<T>(value: T): string {
|
|
|
93
123
|
}
|
|
94
124
|
|
|
95
125
|
switch (typeof value) {
|
|
96
|
-
case "string":
|
|
97
|
-
|
|
126
|
+
case "string": {
|
|
127
|
+
const stringValue = value as string;
|
|
128
|
+
if (
|
|
129
|
+
stringValue === NATIVE_BATCH_MISSING_SENTINEL ||
|
|
130
|
+
stringValue.startsWith(PRIMITIVE_FAST_PATH_PREFIX) ||
|
|
131
|
+
stringValue.startsWith(ESCAPE_PREFIX)
|
|
132
|
+
) {
|
|
133
|
+
return `${PRIM_STRING_PREFIX}${ESCAPE_PREFIX}${stringValue}`;
|
|
134
|
+
}
|
|
135
|
+
return PRIM_STRING_PREFIX + stringValue;
|
|
136
|
+
}
|
|
98
137
|
case "number":
|
|
99
138
|
if (Number.isFinite(value)) {
|
|
100
139
|
return PRIM_NUMBER_PREFIX + String(value);
|
|
101
140
|
}
|
|
102
|
-
if (Number.isNaN(value
|
|
141
|
+
if (Number.isNaN(value)) {
|
|
103
142
|
return PRIM_NAN;
|
|
104
143
|
}
|
|
105
144
|
if (value === Infinity) {
|
|
@@ -134,6 +173,10 @@ const CHAR_B = 98; // 'b'
|
|
|
134
173
|
const CHAR_N = 110; // 'n'
|
|
135
174
|
|
|
136
175
|
export function deserializeWithPrimitiveFastPath<T>(value: string): T {
|
|
176
|
+
if (value.startsWith(ESCAPE_PREFIX)) {
|
|
177
|
+
return value.slice(ESCAPE_PREFIX.length) as T;
|
|
178
|
+
}
|
|
179
|
+
|
|
137
180
|
if (value.startsWith(PRIMITIVE_FAST_PATH_PREFIX)) {
|
|
138
181
|
const prefixLen = PRIMITIVE_FAST_PATH_PREFIX.length;
|
|
139
182
|
const tagChar = value.charCodeAt(prefixLen);
|
|
@@ -149,7 +192,10 @@ export function deserializeWithPrimitiveFastPath<T>(value: string): T {
|
|
|
149
192
|
const payload = value.slice(prefixLen + 2);
|
|
150
193
|
|
|
151
194
|
if (tagChar === CHAR_S) {
|
|
152
|
-
|
|
195
|
+
const unescapedPayload = payload.startsWith(ESCAPE_PREFIX)
|
|
196
|
+
? payload.slice(ESCAPE_PREFIX.length)
|
|
197
|
+
: payload;
|
|
198
|
+
return unescapedPayload as T;
|
|
153
199
|
}
|
|
154
200
|
if (tagChar === CHAR_B) {
|
|
155
201
|
return (payload === "1") as T;
|
package/src/shared.ts
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import { StorageScope, AccessControl, BiometricLevel } from "./Storage.types";
|
|
2
1
|
import {
|
|
3
2
|
serializeWithPrimitiveFastPath,
|
|
4
3
|
deserializeWithPrimitiveFastPath,
|
|
5
4
|
} from "./internal";
|
|
6
|
-
import {
|
|
7
|
-
getStorageErrorCode,
|
|
8
|
-
isLockedStorageErrorCode,
|
|
9
|
-
} from "./storage-runtime";
|
|
10
5
|
import type {
|
|
11
6
|
StorageChangeOperation,
|
|
12
7
|
StorageChangeSource,
|
|
13
8
|
StorageKeyChangeEvent,
|
|
14
9
|
} from "./storage-events";
|
|
10
|
+
import {
|
|
11
|
+
getStorageErrorCode,
|
|
12
|
+
isLockedStorageErrorCode,
|
|
13
|
+
} from "./storage-runtime";
|
|
14
|
+
import { StorageScope } from "./Storage.types";
|
|
15
|
+
import type { AccessControl, BiometricLevel } from "./Storage.types";
|
|
15
16
|
|
|
16
17
|
export type Validator<T> = (value: unknown) => value is T;
|
|
17
18
|
|
|
@@ -144,7 +145,7 @@ export const runMicrotask =
|
|
|
144
145
|
typeof queueMicrotask === "function"
|
|
145
146
|
? queueMicrotask
|
|
146
147
|
: (task: () => void) => {
|
|
147
|
-
Promise.resolve().then(task);
|
|
148
|
+
void Promise.resolve().then(task);
|
|
148
149
|
};
|
|
149
150
|
|
|
150
151
|
export const now =
|