react-native-nitro-storage 0.7.0 → 0.9.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.
Files changed (110) hide show
  1. package/CHANGELOG.md +54 -0
  2. package/README.md +89 -22
  3. package/SECURITY.md +2 -2
  4. package/cpp/bindings/HybridStorage.cpp +5 -12
  5. package/cpp/bindings/HybridStorage.hpp +1 -1
  6. package/docs/api-reference.md +11 -1
  7. package/docs/batch-transactions-migrations.md +8 -2
  8. package/docs/benchmarks.md +19 -15
  9. package/docs/web-backends.md +18 -1
  10. package/ios/IOSStorageAdapterCpp.mm +162 -17
  11. package/lib/commonjs/capabilities.js +26 -0
  12. package/lib/commonjs/capabilities.js.map +1 -0
  13. package/lib/commonjs/core/durability.js +137 -0
  14. package/lib/commonjs/core/durability.js.map +1 -0
  15. package/lib/commonjs/core/metrics.js +91 -0
  16. package/lib/commonjs/core/metrics.js.map +1 -0
  17. package/lib/commonjs/index.js +47 -22
  18. package/lib/commonjs/index.js.map +1 -1
  19. package/lib/commonjs/index.web.js +118 -66
  20. package/lib/commonjs/index.web.js.map +1 -1
  21. package/lib/commonjs/indexeddb-backend.js +73 -23
  22. package/lib/commonjs/indexeddb-backend.js.map +1 -1
  23. package/lib/commonjs/internal.js +27 -4
  24. package/lib/commonjs/internal.js.map +1 -1
  25. package/lib/commonjs/shared.js +2 -2
  26. package/lib/commonjs/shared.js.map +1 -1
  27. package/lib/commonjs/storage-core.js +224 -237
  28. package/lib/commonjs/storage-core.js.map +1 -1
  29. package/lib/commonjs/storage-events.js.map +1 -1
  30. package/lib/commonjs/storage-platform.js +6 -0
  31. package/lib/commonjs/storage-platform.js.map +1 -0
  32. package/lib/commonjs/storage-runtime.js +3 -21
  33. package/lib/commonjs/storage-runtime.js.map +1 -1
  34. package/lib/commonjs/testing.js +19 -4
  35. package/lib/commonjs/testing.js.map +1 -1
  36. package/lib/commonjs/web-backend-contract.js +27 -0
  37. package/lib/commonjs/web-backend-contract.js.map +1 -0
  38. package/lib/module/capabilities.js +21 -0
  39. package/lib/module/capabilities.js.map +1 -0
  40. package/lib/module/core/durability.js +133 -0
  41. package/lib/module/core/durability.js.map +1 -0
  42. package/lib/module/core/metrics.js +87 -0
  43. package/lib/module/core/metrics.js.map +1 -0
  44. package/lib/module/index.js +48 -23
  45. package/lib/module/index.js.map +1 -1
  46. package/lib/module/index.web.js +103 -64
  47. package/lib/module/index.web.js.map +1 -1
  48. package/lib/module/indexeddb-backend.js +73 -23
  49. package/lib/module/indexeddb-backend.js.map +1 -1
  50. package/lib/module/internal.js +24 -3
  51. package/lib/module/internal.js.map +1 -1
  52. package/lib/module/shared.js +2 -2
  53. package/lib/module/shared.js.map +1 -1
  54. package/lib/module/storage-core.js +225 -238
  55. package/lib/module/storage-core.js.map +1 -1
  56. package/lib/module/storage-events.js.map +1 -1
  57. package/lib/module/storage-platform.js +4 -0
  58. package/lib/module/storage-platform.js.map +1 -0
  59. package/lib/module/storage-runtime.js +3 -21
  60. package/lib/module/storage-runtime.js.map +1 -1
  61. package/lib/module/testing.js +5 -3
  62. package/lib/module/testing.js.map +1 -1
  63. package/lib/module/web-backend-contract.js +22 -0
  64. package/lib/module/web-backend-contract.js.map +1 -0
  65. package/lib/typescript/capabilities.d.ts +11 -0
  66. package/lib/typescript/capabilities.d.ts.map +1 -0
  67. package/lib/typescript/core/durability.d.ts +27 -0
  68. package/lib/typescript/core/durability.d.ts.map +1 -0
  69. package/lib/typescript/core/metrics.d.ts +12 -0
  70. package/lib/typescript/core/metrics.d.ts.map +1 -0
  71. package/lib/typescript/index.d.ts +5 -2
  72. package/lib/typescript/index.d.ts.map +1 -1
  73. package/lib/typescript/index.web.d.ts +8 -4
  74. package/lib/typescript/index.web.d.ts.map +1 -1
  75. package/lib/typescript/indexeddb-backend.d.ts.map +1 -1
  76. package/lib/typescript/internal.d.ts +3 -0
  77. package/lib/typescript/internal.d.ts.map +1 -1
  78. package/lib/typescript/shared.d.ts +2 -1
  79. package/lib/typescript/shared.d.ts.map +1 -1
  80. package/lib/typescript/storage-core.d.ts +6 -6
  81. package/lib/typescript/storage-core.d.ts.map +1 -1
  82. package/lib/typescript/storage-events.d.ts +2 -2
  83. package/lib/typescript/storage-events.d.ts.map +1 -1
  84. package/lib/typescript/storage-platform.d.ts +12 -0
  85. package/lib/typescript/storage-platform.d.ts.map +1 -0
  86. package/lib/typescript/storage-runtime.d.ts.map +1 -1
  87. package/lib/typescript/testing.d.ts +5 -1
  88. package/lib/typescript/testing.d.ts.map +1 -1
  89. package/lib/typescript/web-backend-contract.d.ts +10 -0
  90. package/lib/typescript/web-backend-contract.d.ts.map +1 -0
  91. package/lib/typescript/web-storage-backend.d.ts +1 -1
  92. package/lib/typescript/web-storage-backend.d.ts.map +1 -1
  93. package/nitrogen/generated/shared/c++/HybridStorageSpec.hpp +1 -1
  94. package/package.json +4 -3
  95. package/react-native-nitro-storage.podspec +3 -1
  96. package/src/capabilities.ts +36 -0
  97. package/src/core/durability.ts +170 -0
  98. package/src/core/metrics.ts +133 -0
  99. package/src/index.ts +66 -40
  100. package/src/index.web.ts +158 -86
  101. package/src/indexeddb-backend.ts +91 -20
  102. package/src/internal.ts +50 -4
  103. package/src/shared.ts +7 -6
  104. package/src/storage-core.ts +327 -292
  105. package/src/storage-events.ts +2 -1
  106. package/src/storage-platform.ts +16 -0
  107. package/src/storage-runtime.ts +13 -47
  108. package/src/testing.ts +14 -7
  109. package/src/web-backend-contract.ts +34 -0
  110. package/src/web-storage-backend.ts +1 -1
@@ -1,4 +1,4 @@
1
- import { StorageScope } from "./Storage.types";
1
+ import type { StorageScope } from "./Storage.types";
2
2
 
3
3
  export type StorageChangeOperation =
4
4
  | "set"
@@ -10,6 +10,7 @@ export type StorageChangeOperation =
10
10
  | "removeBatch"
11
11
  | "import"
12
12
  | "expire"
13
+ | "rollback"
13
14
  | "external";
14
15
 
15
16
  export type StorageChangeSource = "memory" | "native" | "web" | "external";
@@ -0,0 +1,16 @@
1
+ import type { StorageCore } from "./storage-core";
2
+ import type {
3
+ SecurityCapabilities,
4
+ StorageCapabilities,
5
+ } from "./storage-runtime";
6
+ import type { AccessControl, StorageScope } from "./Storage.types";
7
+
8
+ export type PlatformStorage = StorageCore["storage"] & {
9
+ setAccessControl(level: AccessControl): void;
10
+ setSecureWritesAsync(enabled: boolean): void;
11
+ setKeychainAccessGroup(group: string): void;
12
+ getCapabilities(): StorageCapabilities;
13
+ getSecurityCapabilities(): SecurityCapabilities;
14
+ };
15
+
16
+ export type PlatformScope = StorageScope;
@@ -56,6 +56,15 @@ export type SecureStorageMetadata = {
56
56
 
57
57
  const STORAGE_ERROR_TAG_PATTERN = /\[nitro-error:([a-z_]+)\]/;
58
58
 
59
+ const STORAGE_ERROR_CODES = new Set<StorageErrorCode>([
60
+ "keychain_locked",
61
+ "authentication_required",
62
+ "key_invalidated",
63
+ "storage_corruption",
64
+ "biometric_unavailable",
65
+ "unsupported",
66
+ ]);
67
+
59
68
  export function getStorageErrorCode(
60
69
  err: unknown,
61
70
  ): StorageErrorCode | undefined {
@@ -63,56 +72,13 @@ export function getStorageErrorCode(
63
72
  return undefined;
64
73
  }
65
74
 
66
- const message = err.message;
67
- const taggedCode = message.match(STORAGE_ERROR_TAG_PATTERN)?.[1];
68
-
69
- if (
70
- taggedCode === "keychain_locked" ||
71
- taggedCode === "authentication_required" ||
72
- taggedCode === "key_invalidated" ||
73
- taggedCode === "storage_corruption" ||
74
- taggedCode === "biometric_unavailable" ||
75
- taggedCode === "unsupported"
76
- ) {
77
- return taggedCode;
78
- }
79
-
80
- if (message.includes("errSecInteractionNotAllowed")) {
81
- return "keychain_locked";
82
- }
83
-
84
- if (
85
- message.includes("UserNotAuthenticatedException") ||
86
- message.includes("KeyStoreException") ||
87
- message.includes("android.security.keystore")
88
- ) {
89
- return "authentication_required";
90
- }
75
+ const taggedCode = err.message.match(STORAGE_ERROR_TAG_PATTERN)?.[1];
91
76
 
92
77
  if (
93
- message.includes("KeyPermanentlyInvalidatedException") ||
94
- message.includes("InvalidKeyException")
78
+ taggedCode !== undefined &&
79
+ STORAGE_ERROR_CODES.has(taggedCode as StorageErrorCode)
95
80
  ) {
96
- return "key_invalidated";
97
- }
98
-
99
- if (
100
- message.includes("AEADBadTagException") ||
101
- message.toLowerCase().includes("storage corruption") ||
102
- message.toLowerCase().includes("corrupted storage")
103
- ) {
104
- return "storage_corruption";
105
- }
106
-
107
- if (
108
- message.toLowerCase().includes("biometric storage unavailable") ||
109
- message.toLowerCase().includes("biometric storage is not available")
110
- ) {
111
- return "biometric_unavailable";
112
- }
113
-
114
- if (message.toLowerCase().includes("unsupported")) {
115
- return "unsupported";
81
+ return taggedCode as StorageErrorCode;
116
82
  }
117
83
 
118
84
  return undefined;
package/src/testing.ts CHANGED
@@ -1,22 +1,27 @@
1
- import { StorageScope, AccessControl } from "./Storage.types";
2
1
  import { assertAccessControlLevel } from "./shared";
3
2
  import type { NonMemoryScope } from "./shared";
4
- import type {
5
- SecurityCapabilities,
6
- StorageCapabilities,
7
- } from "./storage-runtime";
8
3
  import {
9
4
  createStorageCore,
10
5
  type StorageCoreAdapter,
11
6
  type StorageCoreBackend,
12
7
  type StorageCoreInternals,
13
8
  } from "./storage-core";
9
+ import type {
10
+ SecurityCapabilities,
11
+ StorageCapabilities,
12
+ } from "./storage-runtime";
13
+ import { StorageScope, AccessControl } from "./Storage.types";
14
14
 
15
15
  export { StorageScope, AccessControl, BiometricLevel } from "./Storage.types";
16
16
  export { isKeychainLockedError } from "./shared";
17
17
  export { migrateFromMMKV } from "./migration";
18
18
  export { getStorageErrorCode } from "./storage-runtime";
19
19
  export { createIndexedDBBackend } from "./indexeddb-backend";
20
+ export {
21
+ describeWebBackendCapabilities,
22
+ isIndexedDBWebBackend,
23
+ type WebBackendCapabilities,
24
+ } from "./web-backend-contract";
20
25
  export {
21
26
  useSetStorage,
22
27
  useStorage,
@@ -66,6 +71,7 @@ export type {
66
71
  StorageKeyRef,
67
72
  TransactionContext,
68
73
  } from "./storage-core";
74
+ export type { PlatformScope, PlatformStorage } from "./storage-platform";
69
75
 
70
76
  const TEST_SECURE_BACKEND = "in-memory-test";
71
77
 
@@ -144,7 +150,9 @@ function createInMemoryBackend(): InMemoryBackend {
144
150
  biometricStore.clear();
145
151
  },
146
152
  resetState: () => {
147
- stores.forEach((store) => store.clear());
153
+ stores.forEach((store) => {
154
+ store.clear();
155
+ });
148
156
  biometricStore.clear();
149
157
  },
150
158
  };
@@ -159,7 +167,6 @@ function buildTestingModule() {
159
167
  backend,
160
168
  changeSource: "native",
161
169
  applyAccessControlOnSecureRawWrite: true,
162
- flushDiskWritesOnImport: false,
163
170
  ensureScopeSubscription: (_scope: NonMemoryScope) => {},
164
171
  maybeCleanupScopeSubscription: (_scope: NonMemoryScope) => {},
165
172
  onWillEmitChanges: () => {},
@@ -0,0 +1,34 @@
1
+ import type { WebStorageBackend } from "./web-storage-backend";
2
+
3
+ export type WebBackendCapabilities = {
4
+ buffered: boolean;
5
+ flushable: boolean;
6
+ closable: boolean;
7
+ subscribable: boolean;
8
+ };
9
+
10
+ export function describeWebBackendCapabilities(
11
+ backend: WebStorageBackend | undefined,
12
+ ): WebBackendCapabilities {
13
+ if (!backend) {
14
+ return {
15
+ buffered: false,
16
+ flushable: false,
17
+ closable: false,
18
+ subscribable: false,
19
+ };
20
+ }
21
+
22
+ return {
23
+ buffered: backend.name?.startsWith("indexeddb:") ?? false,
24
+ flushable: typeof backend.flush === "function",
25
+ closable: typeof backend.close === "function",
26
+ subscribable: typeof backend.subscribe === "function",
27
+ };
28
+ }
29
+
30
+ export function isIndexedDBWebBackend(
31
+ backend: WebStorageBackend | undefined,
32
+ ): boolean {
33
+ return backend?.name?.startsWith("indexeddb:") ?? false;
34
+ }
@@ -1,4 +1,4 @@
1
- import { StorageScope } from "./Storage.types";
1
+ import type { StorageScope } from "./Storage.types";
2
2
 
3
3
  export type WebStorageChangeEvent = {
4
4
  key: string | null;