react-native-nitro-storage 0.4.5 → 0.5.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.
Files changed (37) hide show
  1. package/README.md +254 -945
  2. package/SECURITY.md +26 -0
  3. package/docs/api-reference.md +281 -0
  4. package/docs/batch-transactions-migrations.md +200 -0
  5. package/docs/benchmarks.md +37 -0
  6. package/docs/mmkv-migration.md +80 -0
  7. package/docs/react-hooks.md +113 -0
  8. package/docs/recipes.md +302 -0
  9. package/docs/secure-storage.md +190 -0
  10. package/docs/web-backends.md +141 -0
  11. package/lib/commonjs/index.js +265 -14
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/index.web.js +220 -11
  14. package/lib/commonjs/index.web.js.map +1 -1
  15. package/lib/commonjs/storage-events.js +117 -0
  16. package/lib/commonjs/storage-events.js.map +1 -0
  17. package/lib/commonjs/storage-runtime.js.map +1 -1
  18. package/lib/module/index.js +265 -14
  19. package/lib/module/index.js.map +1 -1
  20. package/lib/module/index.web.js +220 -11
  21. package/lib/module/index.web.js.map +1 -1
  22. package/lib/module/storage-events.js +112 -0
  23. package/lib/module/storage-events.js.map +1 -0
  24. package/lib/module/storage-runtime.js.map +1 -1
  25. package/lib/typescript/index.d.ts +19 -2
  26. package/lib/typescript/index.d.ts.map +1 -1
  27. package/lib/typescript/index.web.d.ts +19 -2
  28. package/lib/typescript/index.web.d.ts.map +1 -1
  29. package/lib/typescript/storage-events.d.ts +37 -0
  30. package/lib/typescript/storage-events.d.ts.map +1 -0
  31. package/lib/typescript/storage-runtime.d.ts +32 -0
  32. package/lib/typescript/storage-runtime.d.ts.map +1 -1
  33. package/package.json +25 -11
  34. package/src/index.ts +601 -14
  35. package/src/index.web.ts +535 -22
  36. package/src/storage-events.ts +184 -0
  37. package/src/storage-runtime.ts +35 -0
@@ -0,0 +1,141 @@
1
+ # Web Backends
2
+
3
+ Nitro Storage runs on web through synchronous backend contracts. Disk and Secure scopes can use different backends.
4
+
5
+ The default web backend is localStorage-style. Configure custom backends when you need IndexedDB persistence, tests with isolated storage, cross-tab sync, or a platform-specific secret wrapper.
6
+
7
+ ## Backend Contract
8
+
9
+ ```ts
10
+ import type { WebStorageBackend } from "react-native-nitro-storage";
11
+
12
+ const backend: WebStorageBackend = {
13
+ name: "memory-test-backend",
14
+ getItem: (key) => map.get(key) ?? null,
15
+ setItem: (key, value) => {
16
+ map.set(key, value);
17
+ },
18
+ removeItem: (key) => {
19
+ map.delete(key);
20
+ },
21
+ clear: () => {
22
+ map.clear();
23
+ },
24
+ getAllKeys: () => Array.from(map.keys()),
25
+ };
26
+ ```
27
+
28
+ Optional methods improve performance and observability:
29
+
30
+ - `getMany(keys)`
31
+ - `setMany(entries)`
32
+ - `removeMany(keys)`
33
+ - `size()`
34
+ - `subscribe(listener)`
35
+ - `flush()`
36
+ - `name`
37
+
38
+ `subscribe(listener)` should report `{ key, newValue }` changes. Use `key: null` when the whole backend is cleared.
39
+
40
+ ## Disk Backend
41
+
42
+ ```ts
43
+ import {
44
+ setWebDiskStorageBackend,
45
+ storage,
46
+ StorageScope,
47
+ } from "react-native-nitro-storage";
48
+
49
+ setWebDiskStorageBackend(backend);
50
+ storage.setString("theme", "dark", StorageScope.Disk);
51
+ ```
52
+
53
+ ## Secure Backend
54
+
55
+ ```ts
56
+ import {
57
+ setWebSecureStorageBackend,
58
+ storage,
59
+ StorageScope,
60
+ } from "react-native-nitro-storage";
61
+
62
+ setWebSecureStorageBackend(backend);
63
+ storage.setString("auth:refreshToken", "opaque-token", StorageScope.Secure);
64
+ ```
65
+
66
+ Web Secure storage is only as strong as the configured backend. Browser storage does not provide iOS Keychain or Android Keystore guarantees.
67
+
68
+ ## Flush Pending Web Writes
69
+
70
+ Backends may persist asynchronously while serving reads synchronously from memory. Use `flushWebStorageBackends()` before assertions or page lifecycle boundaries.
71
+
72
+ ```ts
73
+ import { flushWebStorageBackends } from "react-native-nitro-storage";
74
+
75
+ await flushWebStorageBackends();
76
+ ```
77
+
78
+ ## IndexedDB Secure Backend
79
+
80
+ `createIndexedDBBackend()` returns a `WebSecureStorageBackend` with a synchronous in-memory cache and asynchronous IndexedDB persistence.
81
+
82
+ ```ts
83
+ import { setWebSecureStorageBackend } from "react-native-nitro-storage";
84
+ import { createIndexedDBBackend } from "react-native-nitro-storage/indexeddb-backend";
85
+
86
+ const backend = await createIndexedDBBackend("app-secure", "keyvalue", {
87
+ channelName: "app-secure-sync",
88
+ onError: (error) => {
89
+ console.error("IndexedDB secure storage failed", error);
90
+ },
91
+ });
92
+
93
+ setWebSecureStorageBackend(backend);
94
+ ```
95
+
96
+ Reads are synchronous because they are served from memory after initial load. Writes update memory first and persist to IndexedDB in the background.
97
+
98
+ ## Cross-tab Updates
99
+
100
+ The IndexedDB backend uses `BroadcastChannel` when available. Other tabs receive cache invalidation events and update their in-memory copy.
101
+
102
+ If you provide your own backend, implement `subscribe(listener)` to keep Nitro Storage caches aligned with external writes.
103
+
104
+ ## Testing Backend
105
+
106
+ ```ts
107
+ import type { WebStorageBackend } from "react-native-nitro-storage";
108
+
109
+ export function createMemoryBackend(): WebStorageBackend {
110
+ const values = new Map<string, string>();
111
+ const listeners = new Set<
112
+ (event: { key: string | null; newValue: string | null }) => void
113
+ >();
114
+
115
+ function emit(key: string | null, newValue: string | null) {
116
+ listeners.forEach((listener) => listener({ key, newValue }));
117
+ }
118
+
119
+ return {
120
+ name: "memory",
121
+ getItem: (key) => values.get(key) ?? null,
122
+ setItem: (key, value) => {
123
+ values.set(key, value);
124
+ emit(key, value);
125
+ },
126
+ removeItem: (key) => {
127
+ values.delete(key);
128
+ emit(key, null);
129
+ },
130
+ clear: () => {
131
+ values.clear();
132
+ emit(null, null);
133
+ },
134
+ getAllKeys: () => Array.from(values.keys()),
135
+ subscribe: (listener) => {
136
+ listeners.add(listener);
137
+ return () => listeners.delete(listener);
138
+ },
139
+ };
140
+ }
141
+ ```