react-native-nitro-storage 0.9.0 → 0.10.1
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 +101 -29
- package/README.md +83 -26
- package/android/build.gradle +3 -1
- package/android/src/main/cpp/AndroidStorageAdapterCpp.cpp +5 -2
- package/android/src/main/java/com/nitrostorage/AndroidStorageAdapter.kt +240 -34
- package/cpp/bindings/HybridStorage.cpp +106 -283
- package/cpp/bindings/HybridStorage.hpp +16 -9
- package/docs/api-reference.md +75 -19
- package/docs/benchmarks.md +6 -1
- package/docs/keychain-lifecycle-testing.md +36 -0
- package/docs/recipes.md +1 -2
- package/docs/secure-storage.md +45 -9
- package/ios/IOSStorageAdapterCpp.mm +391 -175
- package/lib/commonjs/capabilities.js +3 -1
- package/lib/commonjs/capabilities.js.map +1 -1
- package/lib/commonjs/core/durability.js +111 -45
- package/lib/commonjs/core/durability.js.map +1 -1
- package/lib/commonjs/index.js +15 -5
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +219 -97
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/internal.js +3 -11
- package/lib/commonjs/internal.js.map +1 -1
- package/lib/commonjs/shared.js +62 -2
- package/lib/commonjs/shared.js.map +1 -1
- package/lib/commonjs/storage-core.js +883 -163
- package/lib/commonjs/storage-core.js.map +1 -1
- package/lib/commonjs/storage-runtime.js +5 -1
- package/lib/commonjs/storage-runtime.js.map +1 -1
- package/lib/commonjs/testing.js +13 -0
- package/lib/commonjs/testing.js.map +1 -1
- package/lib/module/capabilities.js +2 -1
- package/lib/module/capabilities.js.map +1 -1
- package/lib/module/core/durability.js +111 -45
- package/lib/module/core/durability.js.map +1 -1
- package/lib/module/index.js +12 -8
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +215 -99
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/internal.js +2 -9
- package/lib/module/internal.js.map +1 -1
- package/lib/module/shared.js +60 -2
- package/lib/module/shared.js.map +1 -1
- package/lib/module/storage-core.js +884 -164
- package/lib/module/storage-core.js.map +1 -1
- package/lib/module/storage-runtime.js +4 -1
- package/lib/module/storage-runtime.js.map +1 -1
- package/lib/module/testing.js +8 -1
- package/lib/module/testing.js.map +1 -1
- package/lib/typescript/capabilities.d.ts +2 -1
- package/lib/typescript/capabilities.d.ts.map +1 -1
- package/lib/typescript/core/durability.d.ts +8 -4
- package/lib/typescript/core/durability.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +2 -2
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +3 -29
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/internal.d.ts +0 -2
- package/lib/typescript/internal.d.ts.map +1 -1
- package/lib/typescript/shared.d.ts +19 -0
- package/lib/typescript/shared.d.ts.map +1 -1
- package/lib/typescript/storage-core.d.ts +15 -6
- package/lib/typescript/storage-core.d.ts.map +1 -1
- package/lib/typescript/storage-runtime.d.ts +2 -1
- package/lib/typescript/storage-runtime.d.ts.map +1 -1
- package/lib/typescript/testing.d.ts +1 -1
- package/lib/typescript/testing.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/capabilities.ts +3 -1
- package/src/core/durability.ts +140 -43
- package/src/index.ts +20 -10
- package/src/index.web.ts +328 -166
- package/src/internal.ts +0 -14
- package/src/shared.ts +85 -0
- package/src/storage-core.ts +1198 -232
- package/src/storage-runtime.ts +6 -0
- package/src/testing.ts +8 -1
package/src/internal.ts
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { StorageScope } from "./Storage.types";
|
|
2
2
|
|
|
3
3
|
export const MIGRATION_VERSION_KEY = "__nitro_storage_migration_version__";
|
|
4
|
-
export const NATIVE_BATCH_MISSING_SENTINEL =
|
|
5
|
-
"__nitro_storage_batch_missing__::v1";
|
|
6
4
|
const PRIMITIVE_FAST_PATH_PREFIX = "__nitro_storage_primitive__:";
|
|
7
5
|
const PRIM_NULL = "__nitro_storage_primitive__:l";
|
|
8
6
|
const PRIM_UNDEFINED = "__nitro_storage_primitive__:u";
|
|
@@ -26,7 +24,6 @@ const RESERVED_RAW_TOKENS = new Set<string>([
|
|
|
26
24
|
PRIM_INFINITY,
|
|
27
25
|
PRIM_NEG_INFINITY,
|
|
28
26
|
PRIM_NAN,
|
|
29
|
-
NATIVE_BATCH_MISSING_SENTINEL,
|
|
30
27
|
]);
|
|
31
28
|
|
|
32
29
|
export function escapeCollidingRawValue(value: string): string {
|
|
@@ -98,16 +95,6 @@ export function assertBatchScope(
|
|
|
98
95
|
);
|
|
99
96
|
}
|
|
100
97
|
|
|
101
|
-
export function decodeNativeBatchValue(
|
|
102
|
-
value: string | undefined,
|
|
103
|
-
): string | undefined {
|
|
104
|
-
if (value === undefined || value === NATIVE_BATCH_MISSING_SENTINEL) {
|
|
105
|
-
return undefined;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
return value;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
98
|
export function prefixKey(namespace: string | undefined, key: string): string {
|
|
112
99
|
if (!namespace) return key;
|
|
113
100
|
return `${namespace}${NAMESPACE_SEPARATOR}${key}`;
|
|
@@ -126,7 +113,6 @@ export function serializeWithPrimitiveFastPath<T>(value: T): string {
|
|
|
126
113
|
case "string": {
|
|
127
114
|
const stringValue = value as string;
|
|
128
115
|
if (
|
|
129
|
-
stringValue === NATIVE_BATCH_MISSING_SENTINEL ||
|
|
130
116
|
stringValue.startsWith(PRIMITIVE_FAST_PATH_PREFIX) ||
|
|
131
117
|
stringValue.startsWith(ESCAPE_PREFIX)
|
|
132
118
|
) {
|
package/src/shared.ts
CHANGED
|
@@ -75,6 +75,7 @@ export type KeyListenerRegistry = Map<string, Set<() => void>>;
|
|
|
75
75
|
export type RawBatchPathItem = {
|
|
76
76
|
_hasValidation?: boolean;
|
|
77
77
|
_hasExpiration?: boolean;
|
|
78
|
+
_hasRenameFrom?: boolean;
|
|
78
79
|
_isBiometric?: boolean;
|
|
79
80
|
_biometricLevel?: BiometricLevel;
|
|
80
81
|
_secureAccessControl?: AccessControl;
|
|
@@ -84,6 +85,7 @@ export type RollbackRecord =
|
|
|
84
85
|
| {
|
|
85
86
|
kind: "memory";
|
|
86
87
|
value: unknown;
|
|
88
|
+
expiresAt?: number;
|
|
87
89
|
}
|
|
88
90
|
| {
|
|
89
91
|
kind: "raw";
|
|
@@ -96,6 +98,81 @@ export type RollbackRecord =
|
|
|
96
98
|
level: BiometricLevel;
|
|
97
99
|
};
|
|
98
100
|
|
|
101
|
+
export type StorageCompositeError = Error & {
|
|
102
|
+
readonly cause: unknown;
|
|
103
|
+
readonly errors: readonly unknown[];
|
|
104
|
+
readonly code: "storage_compensation_failed";
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export type StorageCompensationError = StorageCompositeError;
|
|
108
|
+
|
|
109
|
+
export function createStorageCompositeError(
|
|
110
|
+
operation: string,
|
|
111
|
+
primary: unknown,
|
|
112
|
+
contexts: readonly { label: string; error: unknown }[],
|
|
113
|
+
): StorageCompositeError {
|
|
114
|
+
const primaryMessage =
|
|
115
|
+
primary instanceof Error ? primary.message : String(primary);
|
|
116
|
+
const contextMessage = contexts
|
|
117
|
+
.map(({ label, error }) => {
|
|
118
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
+
return `${label}: ${message}`;
|
|
120
|
+
})
|
|
121
|
+
.join("; ");
|
|
122
|
+
const composite = new Error(
|
|
123
|
+
`[nitro-error:storage_compensation_failed] NitroStorage: ${operation} failed; primary error: ${primaryMessage}${
|
|
124
|
+
contextMessage.length > 0 ? `; ${contextMessage}` : ""
|
|
125
|
+
}`,
|
|
126
|
+
) as StorageCompositeError;
|
|
127
|
+
Object.defineProperties(composite, {
|
|
128
|
+
cause: {
|
|
129
|
+
configurable: true,
|
|
130
|
+
enumerable: false,
|
|
131
|
+
value: primary,
|
|
132
|
+
writable: false,
|
|
133
|
+
},
|
|
134
|
+
errors: {
|
|
135
|
+
configurable: true,
|
|
136
|
+
enumerable: false,
|
|
137
|
+
value: Object.freeze([primary, ...contexts.map(({ error }) => error)]),
|
|
138
|
+
writable: false,
|
|
139
|
+
},
|
|
140
|
+
code: {
|
|
141
|
+
configurable: false,
|
|
142
|
+
enumerable: false,
|
|
143
|
+
value: "storage_compensation_failed",
|
|
144
|
+
writable: false,
|
|
145
|
+
},
|
|
146
|
+
});
|
|
147
|
+
return composite;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function normalizeStorageError(error: unknown): unknown {
|
|
151
|
+
if (!(error instanceof Error)) {
|
|
152
|
+
return error;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
const code = getStorageErrorCode(error);
|
|
156
|
+
if (
|
|
157
|
+
code !== "storage_compensation_failed" ||
|
|
158
|
+
("cause" in error && "errors" in error && "code" in error)
|
|
159
|
+
) {
|
|
160
|
+
return error;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
const operationMatch = error.message.match(
|
|
164
|
+
/NitroStorage: ([^;]+?) failed(?:;|$)/,
|
|
165
|
+
);
|
|
166
|
+
const countMatch = error.message.match(/rollback_error_count=(\d+)/);
|
|
167
|
+
const rollbackErrorCount = countMatch ? Number(countMatch[1]) : 0;
|
|
168
|
+
const operation = operationMatch?.[1] ?? "native storage compensation";
|
|
169
|
+
const contexts = Array.from({ length: rollbackErrorCount }, (_, index) => ({
|
|
170
|
+
label: `native rollback ${index + 1}`,
|
|
171
|
+
error: new Error("Native storage rollback failed"),
|
|
172
|
+
}));
|
|
173
|
+
return createStorageCompositeError(operation, error, contexts);
|
|
174
|
+
}
|
|
175
|
+
|
|
99
176
|
export function isUpdater<T>(
|
|
100
177
|
valueOrFn: T | ((prev: T) => T),
|
|
101
178
|
): valueOrFn is (prev: T) => T {
|
|
@@ -133,12 +210,14 @@ export type NonMemoryScope = StorageScope.Disk | StorageScope.Secure;
|
|
|
133
210
|
export type PendingDiskWrite = {
|
|
134
211
|
key: string;
|
|
135
212
|
value: string | undefined;
|
|
213
|
+
generation: number;
|
|
136
214
|
};
|
|
137
215
|
|
|
138
216
|
export type PendingSecureWrite = {
|
|
139
217
|
key: string;
|
|
140
218
|
value: string | undefined;
|
|
141
219
|
accessControl?: AccessControl;
|
|
220
|
+
generation: number;
|
|
142
221
|
};
|
|
143
222
|
|
|
144
223
|
export const runMicrotask =
|
|
@@ -214,6 +293,7 @@ export function canUseRawBatchPath(item: RawBatchPathItem): boolean {
|
|
|
214
293
|
return (
|
|
215
294
|
item._hasExpiration === false &&
|
|
216
295
|
item._hasValidation === false &&
|
|
296
|
+
item._hasRenameFrom !== true &&
|
|
217
297
|
item._isBiometric !== true &&
|
|
218
298
|
item._secureAccessControl === undefined
|
|
219
299
|
);
|
|
@@ -223,6 +303,7 @@ export function canUseSecureRawBatchPath(item: RawBatchPathItem): boolean {
|
|
|
223
303
|
return (
|
|
224
304
|
item._hasExpiration === false &&
|
|
225
305
|
item._hasValidation === false &&
|
|
306
|
+
item._hasRenameFrom !== true &&
|
|
226
307
|
item._isBiometric !== true
|
|
227
308
|
);
|
|
228
309
|
}
|
|
@@ -246,6 +327,10 @@ export type SecureAuthStorageConfig<K extends string = string> = Record<
|
|
|
246
327
|
}
|
|
247
328
|
>;
|
|
248
329
|
|
|
330
|
+
/**
|
|
331
|
+
* @deprecated Use isStorageError(error, code) to distinguish temporary lock,
|
|
332
|
+
* authentication, and invalidated-key recovery paths.
|
|
333
|
+
*/
|
|
249
334
|
export function isKeychainLockedError(err: unknown): boolean {
|
|
250
335
|
return isLockedStorageErrorCode(getStorageErrorCode(err));
|
|
251
336
|
}
|