@teardown/react-native 2.0.2 → 2.0.9
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 +104 -34
- package/package.json +15 -6
- package/src/clients/device/adapters/basic.adapter.ts +1 -1
- package/src/clients/device/adapters/device-info.adapter.ts +36 -0
- package/src/clients/device/adapters/device.adpater-interface.ts +23 -15
- package/src/clients/device/adapters/expo.adapter.ts +2 -36
- package/src/clients/force-update/force-update.client.ts +30 -6
- package/src/clients/identity/identity.client.test.ts +2 -2
- package/src/exports/adapters/device-info.ts +1 -0
- package/docs/01-getting-started.mdx +0 -147
- package/docs/02-core-concepts.mdx +0 -188
- package/docs/03-identity.mdx +0 -301
- package/docs/04-force-updates.mdx +0 -339
- package/docs/05-device-info.mdx +0 -324
- package/docs/06-logging.mdx +0 -345
- package/docs/06-storage.mdx +0 -349
- package/docs/07-api-reference.mdx +0 -472
- package/docs/07-logging.mdx +0 -345
- package/docs/08-api-reference.mdx +0 -472
- package/docs/08-hooks-reference.mdx +0 -476
- package/docs/09-advanced.mdx +0 -563
- package/docs/09-hooks-reference.mdx +0 -476
- package/docs/10-advanced.mdx +0 -563
package/docs/06-logging.mdx
DELETED
|
@@ -1,345 +0,0 @@
|
|
|
1
|
-
# Logging
|
|
2
|
-
|
|
3
|
-
Structured logging system with configurable log levels.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The LoggingClient provides:
|
|
8
|
-
- Configurable log levels
|
|
9
|
-
- Named loggers for each client
|
|
10
|
-
- Console binding preservation
|
|
11
|
-
- Debug mode support
|
|
12
|
-
|
|
13
|
-
## Log Levels
|
|
14
|
-
|
|
15
|
-
```typescript
|
|
16
|
-
type LogLevel =
|
|
17
|
-
| "none" // No logging
|
|
18
|
-
| "error" // Only errors
|
|
19
|
-
| "warn" // Errors and warnings
|
|
20
|
-
| "info" // Errors, warnings, and info
|
|
21
|
-
| "verbose" // Everything including debug
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### Level Priority
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
none < error < warn < info < verbose
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
When you set a level, all lower-priority levels are also shown:
|
|
31
|
-
- `error`: Shows only errors
|
|
32
|
-
- `warn`: Shows errors + warnings
|
|
33
|
-
- `info`: Shows errors + warnings + info
|
|
34
|
-
- `verbose`: Shows everything (errors + warnings + info + debug)
|
|
35
|
-
|
|
36
|
-
## Setting Log Level
|
|
37
|
-
|
|
38
|
-
### On Initialization
|
|
39
|
-
|
|
40
|
-
```typescript
|
|
41
|
-
const teardown = new TeardownCore({
|
|
42
|
-
// ... other options
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
// Set log level after initialization
|
|
46
|
-
teardown.setLogLevel('verbose');
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### During Runtime
|
|
50
|
-
|
|
51
|
-
```typescript
|
|
52
|
-
import { useTeardown } from '@teardown/react-native';
|
|
53
|
-
|
|
54
|
-
function DebugPanel() {
|
|
55
|
-
const { core } = useTeardown();
|
|
56
|
-
|
|
57
|
-
const enableDebugMode = () => {
|
|
58
|
-
core.setLogLevel('verbose');
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
const disableLogging = () => {
|
|
62
|
-
core.setLogLevel('none');
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
return (
|
|
66
|
-
<View>
|
|
67
|
-
<Button title="Enable Debug" onPress={enableDebugMode} />
|
|
68
|
-
<Button title="Disable Logs" onPress={disableLogging} />
|
|
69
|
-
</View>
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
```
|
|
73
|
-
|
|
74
|
-
## Log Output Format
|
|
75
|
-
|
|
76
|
-
All logs are prefixed with the client name:
|
|
77
|
-
|
|
78
|
-
```
|
|
79
|
-
[Teardown:TeardownCore] Shutting down TeardownCore
|
|
80
|
-
[Teardown:IdentityClient] Identify state: unidentified -> identifying
|
|
81
|
-
[Teardown:IdentityClient] Identify state: identifying -> identified
|
|
82
|
-
[Teardown:ForceUpdateClient] Version status changing: initializing -> checking
|
|
83
|
-
[Teardown:ForceUpdateClient] Checking version status on foreground
|
|
84
|
-
[Teardown:DeviceClient] Getting device ID
|
|
85
|
-
[Teardown:StorageClient] Creating storage for teardown:v1:identity
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
## Logger Methods
|
|
89
|
-
|
|
90
|
-
Each client has a logger with these methods:
|
|
91
|
-
|
|
92
|
-
```typescript
|
|
93
|
-
logger.info(message, ...args) // Info level
|
|
94
|
-
logger.warn(message, ...args) // Warning level
|
|
95
|
-
logger.error(message, ...args) // Error level
|
|
96
|
-
logger.debug(message, ...args) // Debug level (verbose)
|
|
97
|
-
logger.trace(message, ...args) // Stack trace (verbose)
|
|
98
|
-
```
|
|
99
|
-
|
|
100
|
-
## Internal Logging
|
|
101
|
-
|
|
102
|
-
The SDK logs these events:
|
|
103
|
-
|
|
104
|
-
### TeardownCore
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
[Teardown:TeardownCore] Error initializing TeardownCore { error }
|
|
108
|
-
[Teardown:TeardownCore] Shutting down TeardownCore
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
### IdentityClient
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
[Teardown:IdentityClient] Identify state: unidentified -> identifying
|
|
115
|
-
[Teardown:IdentityClient] Identify state: identifying -> identified
|
|
116
|
-
[Teardown:IdentityClient] 422 Error identifying user { ... }
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### ForceUpdateClient
|
|
120
|
-
|
|
121
|
-
```typescript
|
|
122
|
-
[Teardown:ForceUpdateClient] Version status changing: initializing -> up_to_date
|
|
123
|
-
[Teardown:ForceUpdateClient] Checking version status on foreground
|
|
124
|
-
[Teardown:ForceUpdateClient] Skipping version check - not identified
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### DeviceClient
|
|
128
|
-
|
|
129
|
-
```typescript
|
|
130
|
-
[Teardown:DeviceClient] Getting device ID
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
### StorageClient
|
|
134
|
-
|
|
135
|
-
```typescript
|
|
136
|
-
[Teardown:StorageClient] Creating storage for teardown:v1:identity
|
|
137
|
-
[Teardown:StorageClient] Storage already exists for teardown:v1:identity
|
|
138
|
-
[Teardown:StorageClient] Returning existing storage for teardown:v1:identity
|
|
139
|
-
[Teardown:StorageClient] Clearing storage for teardown:v1:identity
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
## Console Binding
|
|
143
|
-
|
|
144
|
-
The logger preserves console call sites for better debugging:
|
|
145
|
-
|
|
146
|
-
```typescript
|
|
147
|
-
// Bound console methods preserve original call site
|
|
148
|
-
private boundConsole = {
|
|
149
|
-
log: console.log.bind(console),
|
|
150
|
-
error: console.error.bind(console),
|
|
151
|
-
debug: console.debug.bind(console),
|
|
152
|
-
warn: console.warn.bind(console),
|
|
153
|
-
trace: console.trace.bind(console),
|
|
154
|
-
};
|
|
155
|
-
```
|
|
156
|
-
|
|
157
|
-
This means clicking log messages in DevTools takes you to the original SDK code, not the logger wrapper.
|
|
158
|
-
|
|
159
|
-
## Creating Custom Loggers
|
|
160
|
-
|
|
161
|
-
While not typically needed, you can create custom loggers:
|
|
162
|
-
|
|
163
|
-
```typescript
|
|
164
|
-
import { LoggingClient } from '@teardown/react-native';
|
|
165
|
-
|
|
166
|
-
const logging = new LoggingClient({ logLevel: 'info' });
|
|
167
|
-
const logger = logging.createLogger({ name: 'MyFeature' });
|
|
168
|
-
|
|
169
|
-
logger.info('Feature initialized');
|
|
170
|
-
logger.error('Something went wrong');
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## Conditional Logging
|
|
174
|
-
|
|
175
|
-
The SDK checks log level before logging:
|
|
176
|
-
|
|
177
|
-
```typescript
|
|
178
|
-
// Only logs if current level >= info
|
|
179
|
-
if (this.loggingClient.shouldLog('info')) {
|
|
180
|
-
logger.info('Message');
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
This prevents unnecessary string concatenation and formatting in production.
|
|
185
|
-
|
|
186
|
-
## Best Practices
|
|
187
|
-
|
|
188
|
-
### 1. Use 'none' in Production
|
|
189
|
-
|
|
190
|
-
```typescript
|
|
191
|
-
// ✅ Good - no logs in production
|
|
192
|
-
const logLevel = __DEV__ ? 'verbose' : 'none';
|
|
193
|
-
teardown.setLogLevel(logLevel);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### 2. Use 'verbose' for Debugging
|
|
197
|
-
|
|
198
|
-
```typescript
|
|
199
|
-
// ✅ Good - detailed logs during development
|
|
200
|
-
if (__DEV__) {
|
|
201
|
-
teardown.setLogLevel('verbose');
|
|
202
|
-
}
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
### 3. Enable Logging for Support
|
|
206
|
-
|
|
207
|
-
```typescript
|
|
208
|
-
// ✅ Good - user can enable logs for support
|
|
209
|
-
function Settings() {
|
|
210
|
-
const { core } = useTeardown();
|
|
211
|
-
const [debugMode, setDebugMode] = useState(false);
|
|
212
|
-
|
|
213
|
-
const toggleDebug = () => {
|
|
214
|
-
const newMode = !debugMode;
|
|
215
|
-
setDebugMode(newMode);
|
|
216
|
-
core.setLogLevel(newMode ? 'verbose' : 'none');
|
|
217
|
-
};
|
|
218
|
-
|
|
219
|
-
return <Switch value={debugMode} onValueChange={toggleDebug} />;
|
|
220
|
-
}
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
### 4. Don't Rely on Logs for Logic
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
226
|
-
// ❌ Bad - logs may be disabled
|
|
227
|
-
logger.info('User identified');
|
|
228
|
-
// ... rely on this log
|
|
229
|
-
|
|
230
|
-
// ✅ Good - use state/events
|
|
231
|
-
const result = await identify();
|
|
232
|
-
if (result.success) {
|
|
233
|
-
// ... use result, not logs
|
|
234
|
-
}
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
## Log Level Examples
|
|
238
|
-
|
|
239
|
-
### Development
|
|
240
|
-
|
|
241
|
-
```typescript
|
|
242
|
-
// See everything
|
|
243
|
-
teardown.setLogLevel('verbose');
|
|
244
|
-
|
|
245
|
-
// Output:
|
|
246
|
-
// [Teardown:IdentityClient] Getting device ID
|
|
247
|
-
// [Teardown:IdentityClient] Identify state: unidentified -> identifying
|
|
248
|
-
// [Teardown:StorageClient] Creating storage for teardown:v1:identity
|
|
249
|
-
// etc.
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
### Debugging Issues
|
|
253
|
-
|
|
254
|
-
```typescript
|
|
255
|
-
// See important events
|
|
256
|
-
teardown.setLogLevel('info');
|
|
257
|
-
|
|
258
|
-
// Output:
|
|
259
|
-
// [Teardown:IdentityClient] Identify state: unidentified -> identifying
|
|
260
|
-
// [Teardown:ForceUpdateClient] Version status changing: initializing -> up_to_date
|
|
261
|
-
```
|
|
262
|
-
|
|
263
|
-
### Production
|
|
264
|
-
|
|
265
|
-
```typescript
|
|
266
|
-
// See only errors
|
|
267
|
-
teardown.setLogLevel('error');
|
|
268
|
-
|
|
269
|
-
// Output:
|
|
270
|
-
// [Teardown:TeardownCore] Error initializing TeardownCore { error }
|
|
271
|
-
// [Teardown:IdentityClient] 422 Error identifying user { ... }
|
|
272
|
-
```
|
|
273
|
-
|
|
274
|
-
### Disabled
|
|
275
|
-
|
|
276
|
-
```typescript
|
|
277
|
-
// No logs
|
|
278
|
-
teardown.setLogLevel('none');
|
|
279
|
-
|
|
280
|
-
// Output:
|
|
281
|
-
// (nothing)
|
|
282
|
-
```
|
|
283
|
-
|
|
284
|
-
## Environment-Based Configuration
|
|
285
|
-
|
|
286
|
-
```typescript
|
|
287
|
-
const LOG_LEVEL: LogLevel =
|
|
288
|
-
process.env.NODE_ENV === 'development' ? 'verbose' :
|
|
289
|
-
process.env.NODE_ENV === 'staging' ? 'info' :
|
|
290
|
-
'error';
|
|
291
|
-
|
|
292
|
-
teardown.setLogLevel(LOG_LEVEL);
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
## Debugging Tips
|
|
296
|
-
|
|
297
|
-
### 1. Enable Verbose Logging
|
|
298
|
-
|
|
299
|
-
```typescript
|
|
300
|
-
teardown.setLogLevel('verbose');
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
### 2. Filter by Client
|
|
304
|
-
|
|
305
|
-
Search DevTools console for specific client:
|
|
306
|
-
```
|
|
307
|
-
[Teardown:IdentityClient]
|
|
308
|
-
```
|
|
309
|
-
|
|
310
|
-
### 3. Track State Transitions
|
|
311
|
-
|
|
312
|
-
Look for state change logs:
|
|
313
|
-
```
|
|
314
|
-
Identify state: unidentified -> identifying
|
|
315
|
-
Version status changing: checking -> up_to_date
|
|
316
|
-
```
|
|
317
|
-
|
|
318
|
-
### 4. Check Error Details
|
|
319
|
-
|
|
320
|
-
Errors include full context:
|
|
321
|
-
```typescript
|
|
322
|
-
logger.error('Error initializing', { error, context });
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
## Performance
|
|
326
|
-
|
|
327
|
-
Logging is optimized for production:
|
|
328
|
-
|
|
329
|
-
```typescript
|
|
330
|
-
// ✅ Good - check happens before string operations
|
|
331
|
-
if (this.shouldLog('verbose')) {
|
|
332
|
-
logger.debug(`Expensive operation: ${JSON.stringify(bigObject)}`);
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
// ❌ Bad - string created even if logging disabled
|
|
336
|
-
logger.debug(`Expensive operation: ${JSON.stringify(bigObject)}`);
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
The SDK uses the first pattern internally.
|
|
340
|
-
|
|
341
|
-
## Next Steps
|
|
342
|
-
|
|
343
|
-
- [API Reference](./07-api-reference.mdx)
|
|
344
|
-
- [Hooks Reference](./08-hooks-reference.mdx)
|
|
345
|
-
- [Advanced Usage](./09-advanced.mdx)
|
package/docs/06-storage.mdx
DELETED
|
@@ -1,349 +0,0 @@
|
|
|
1
|
-
# Storage
|
|
2
|
-
|
|
3
|
-
Persistent, namespaced storage with platform adapters.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The StorageClient provides:
|
|
8
|
-
- Namespaced key-value storage
|
|
9
|
-
- Platform-agnostic interface
|
|
10
|
-
- Multiple storage adapters
|
|
11
|
-
- Automatic cleanup
|
|
12
|
-
|
|
13
|
-
## Storage Adapters
|
|
14
|
-
|
|
15
|
-
### MMKV Adapter (Recommended)
|
|
16
|
-
|
|
17
|
-
Fast, encrypted storage using react-native-mmkv:
|
|
18
|
-
|
|
19
|
-
```typescript
|
|
20
|
-
import { TeardownCore } from '@teardown/react-native';
|
|
21
|
-
import { createMMKVStorageFactory } from '@teardown/react-native/mmkv';
|
|
22
|
-
|
|
23
|
-
const teardown = new TeardownCore({
|
|
24
|
-
// ... other options
|
|
25
|
-
storageFactory: createMMKVStorageFactory(),
|
|
26
|
-
});
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
Install dependency:
|
|
30
|
-
```bash
|
|
31
|
-
bun add react-native-mmkv
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
Benefits:
|
|
35
|
-
- ⚡ Extremely fast (synchronous)
|
|
36
|
-
- 🔒 Encrypted by default
|
|
37
|
-
- 📦 Small bundle size
|
|
38
|
-
- 💾 Persistent across app restarts
|
|
39
|
-
|
|
40
|
-
### Custom Storage Adapter
|
|
41
|
-
|
|
42
|
-
Create your own storage adapter:
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import type { SupportedStorage } from '@teardown/react-native';
|
|
46
|
-
|
|
47
|
-
function createCustomStorageFactory() {
|
|
48
|
-
return (storageKey: string): SupportedStorage => {
|
|
49
|
-
// Your storage implementation
|
|
50
|
-
return {
|
|
51
|
-
preload: () => {
|
|
52
|
-
// Load data into memory if needed
|
|
53
|
-
},
|
|
54
|
-
getItem: (key: string) => {
|
|
55
|
-
// Return value or null
|
|
56
|
-
return localStorage.getItem(`${storageKey}:${key}`);
|
|
57
|
-
},
|
|
58
|
-
setItem: (key: string, value: string) => {
|
|
59
|
-
// Store value
|
|
60
|
-
localStorage.setItem(`${storageKey}:${key}`, value);
|
|
61
|
-
},
|
|
62
|
-
removeItem: (key: string) => {
|
|
63
|
-
// Remove value
|
|
64
|
-
localStorage.removeItem(`${storageKey}:${key}`);
|
|
65
|
-
},
|
|
66
|
-
clear: () => {
|
|
67
|
-
// Clear all keys for this namespace
|
|
68
|
-
},
|
|
69
|
-
keys: () => {
|
|
70
|
-
// Return all keys
|
|
71
|
-
return Object.keys(localStorage);
|
|
72
|
-
},
|
|
73
|
-
};
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
## Storage Interface
|
|
79
|
-
|
|
80
|
-
```typescript
|
|
81
|
-
type SupportedStorage = {
|
|
82
|
-
preload: () => void;
|
|
83
|
-
getItem: (key: string) => string | null;
|
|
84
|
-
setItem: (key: string, value: string) => void;
|
|
85
|
-
removeItem: (key: string) => void;
|
|
86
|
-
clear: () => void;
|
|
87
|
-
keys: () => string[];
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
## Namespacing
|
|
92
|
-
|
|
93
|
-
Storage is automatically namespaced to prevent key collisions:
|
|
94
|
-
|
|
95
|
-
```typescript
|
|
96
|
-
// Internal storage keys are prefixed
|
|
97
|
-
teardown:v1:identity:IDENTIFY_STATE
|
|
98
|
-
teardown:v1:device:deviceId
|
|
99
|
-
teardown:v1:version:VERSION_STATUS
|
|
100
|
-
```
|
|
101
|
-
|
|
102
|
-
This prevents conflicts with:
|
|
103
|
-
- Your app's storage
|
|
104
|
-
- Other libraries
|
|
105
|
-
- Multiple Teardown instances
|
|
106
|
-
|
|
107
|
-
## How It Works
|
|
108
|
-
|
|
109
|
-
### 1. Storage Factory
|
|
110
|
-
|
|
111
|
-
The storage factory creates namespaced storage instances:
|
|
112
|
-
|
|
113
|
-
```typescript
|
|
114
|
-
// You provide the factory
|
|
115
|
-
storageFactory: createMMKVStorageFactory()
|
|
116
|
-
|
|
117
|
-
// SDK calls it for each client
|
|
118
|
-
const identityStorage = storage.createStorage('identity');
|
|
119
|
-
const deviceStorage = storage.createStorage('device');
|
|
120
|
-
```
|
|
121
|
-
|
|
122
|
-
### 2. Client Storage
|
|
123
|
-
|
|
124
|
-
Each client gets its own namespaced storage:
|
|
125
|
-
|
|
126
|
-
```typescript
|
|
127
|
-
class IdentityClient {
|
|
128
|
-
constructor(storage: StorageClient) {
|
|
129
|
-
// Creates "teardown:v1:identity" namespace
|
|
130
|
-
this.storage = storage.createStorage('identity');
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
saveSession(session: Session) {
|
|
134
|
-
// Actually saves to "teardown:v1:identity:IDENTIFY_STATE"
|
|
135
|
-
this.storage.setItem('IDENTIFY_STATE', JSON.stringify(session));
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
### 3. Automatic Persistence
|
|
141
|
-
|
|
142
|
-
The SDK automatically persists critical state:
|
|
143
|
-
|
|
144
|
-
- Identity state (session data)
|
|
145
|
-
- Version status
|
|
146
|
-
- Device ID
|
|
147
|
-
|
|
148
|
-
## Internal Storage Keys
|
|
149
|
-
|
|
150
|
-
The SDK uses these storage keys internally:
|
|
151
|
-
|
|
152
|
-
| Client | Key | Data |
|
|
153
|
-
|--------|-----|------|
|
|
154
|
-
| Identity | `IDENTIFY_STATE` | User session and identity state |
|
|
155
|
-
| Device | `deviceId` | Generated device UUID |
|
|
156
|
-
| ForceUpdate | `VERSION_STATUS` | Current version status |
|
|
157
|
-
|
|
158
|
-
## Creating Storage Instances
|
|
159
|
-
|
|
160
|
-
You typically don't create storage instances directly - clients do it internally:
|
|
161
|
-
|
|
162
|
-
```typescript
|
|
163
|
-
// Internal SDK code
|
|
164
|
-
class MyClient {
|
|
165
|
-
constructor(storage: StorageClient) {
|
|
166
|
-
this.storage = storage.createStorage('my-namespace');
|
|
167
|
-
}
|
|
168
|
-
}
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
If you need custom storage:
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
import { useTeardown } from '@teardown/react-native';
|
|
175
|
-
|
|
176
|
-
function MyComponent() {
|
|
177
|
-
const { core } = useTeardown();
|
|
178
|
-
|
|
179
|
-
// Access internal storage (not recommended)
|
|
180
|
-
// Better to use your own storage solution for app data
|
|
181
|
-
}
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
## Data Format
|
|
185
|
-
|
|
186
|
-
All data is stored as JSON strings:
|
|
187
|
-
|
|
188
|
-
```typescript
|
|
189
|
-
// Stored
|
|
190
|
-
storage.setItem('key', JSON.stringify({ foo: 'bar' }));
|
|
191
|
-
|
|
192
|
-
// Retrieved
|
|
193
|
-
const data = JSON.parse(storage.getItem('key'));
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Cleanup
|
|
197
|
-
|
|
198
|
-
Storage is automatically cleaned up on SDK shutdown:
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
// Happens automatically when TeardownProvider unmounts
|
|
202
|
-
core.shutdown();
|
|
203
|
-
```
|
|
204
|
-
|
|
205
|
-
This clears all namespaced storage instances.
|
|
206
|
-
|
|
207
|
-
## Best Practices
|
|
208
|
-
|
|
209
|
-
### 1. Use MMKV for Production
|
|
210
|
-
|
|
211
|
-
```typescript
|
|
212
|
-
// ✅ Recommended - fast and encrypted
|
|
213
|
-
storageFactory: createMMKVStorageFactory()
|
|
214
|
-
|
|
215
|
-
// ⚠️ Avoid in production - slow and unencrypted
|
|
216
|
-
storageFactory: createAsyncStorageFactory()
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
### 2. Don't Access Internal Storage Directly
|
|
220
|
-
|
|
221
|
-
```typescript
|
|
222
|
-
// ❌ Bad - bypasses SDK abstractions
|
|
223
|
-
MMKV.set('teardown:v1:identity:IDENTIFY_STATE', '...');
|
|
224
|
-
|
|
225
|
-
// ✅ Good - use SDK methods
|
|
226
|
-
await core.identity.identify({...});
|
|
227
|
-
```
|
|
228
|
-
|
|
229
|
-
### 3. Use Your Own Storage for App Data
|
|
230
|
-
|
|
231
|
-
```typescript
|
|
232
|
-
// ❌ Bad - mixing SDK and app data
|
|
233
|
-
core.storage.setItem('user-preferences', '...');
|
|
234
|
-
|
|
235
|
-
// ✅ Good - separate storage for app
|
|
236
|
-
import { MMKV } from 'react-native-mmkv';
|
|
237
|
-
const appStorage = new MMKV({ id: 'app-storage' });
|
|
238
|
-
appStorage.set('user-preferences', '...');
|
|
239
|
-
```
|
|
240
|
-
|
|
241
|
-
### 4. Handle Storage Errors
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// Storage operations can throw
|
|
245
|
-
try {
|
|
246
|
-
const value = storage.getItem('key');
|
|
247
|
-
} catch (error) {
|
|
248
|
-
console.error('Storage error:', error);
|
|
249
|
-
// Handle error (fallback, retry, etc.)
|
|
250
|
-
}
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Migrations
|
|
254
|
-
|
|
255
|
-
If you need to migrate storage data:
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
function migrateStorage() {
|
|
259
|
-
const oldKey = 'old-app:session';
|
|
260
|
-
const newKey = 'teardown:v1:identity:IDENTIFY_STATE';
|
|
261
|
-
|
|
262
|
-
const oldData = localStorage.getItem(oldKey);
|
|
263
|
-
if (oldData) {
|
|
264
|
-
// Transform data if needed
|
|
265
|
-
const newData = transformData(oldData);
|
|
266
|
-
localStorage.setItem(newKey, newData);
|
|
267
|
-
localStorage.removeItem(oldKey);
|
|
268
|
-
}
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
// Run before initializing Teardown
|
|
272
|
-
migrateStorage();
|
|
273
|
-
const teardown = new TeardownCore({...});
|
|
274
|
-
```
|
|
275
|
-
|
|
276
|
-
## Storage Size
|
|
277
|
-
|
|
278
|
-
The SDK stores minimal data:
|
|
279
|
-
|
|
280
|
-
- Identity state: ~500 bytes
|
|
281
|
-
- Device ID: ~36 bytes (UUID)
|
|
282
|
-
- Version status: ~50 bytes
|
|
283
|
-
|
|
284
|
-
Total: Less than 1KB for all SDK data.
|
|
285
|
-
|
|
286
|
-
## Encryption
|
|
287
|
-
|
|
288
|
-
### MMKV
|
|
289
|
-
|
|
290
|
-
MMKV encrypts data by default:
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
// Already encrypted
|
|
294
|
-
storageFactory: createMMKVStorageFactory()
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
### Custom Encryption
|
|
298
|
-
|
|
299
|
-
For custom adapters, implement encryption:
|
|
300
|
-
|
|
301
|
-
```typescript
|
|
302
|
-
import CryptoJS from 'crypto-js';
|
|
303
|
-
|
|
304
|
-
function createEncryptedStorage(encryptionKey: string) {
|
|
305
|
-
return (namespace: string) => ({
|
|
306
|
-
getItem: (key: string) => {
|
|
307
|
-
const encrypted = localStorage.getItem(`${namespace}:${key}`);
|
|
308
|
-
if (!encrypted) return null;
|
|
309
|
-
return CryptoJS.AES.decrypt(encrypted, encryptionKey).toString();
|
|
310
|
-
},
|
|
311
|
-
setItem: (key: string, value: string) => {
|
|
312
|
-
const encrypted = CryptoJS.AES.encrypt(value, encryptionKey).toString();
|
|
313
|
-
localStorage.setItem(`${namespace}:${key}`, encrypted);
|
|
314
|
-
},
|
|
315
|
-
// ... other methods
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
```
|
|
319
|
-
|
|
320
|
-
## Testing
|
|
321
|
-
|
|
322
|
-
Mock storage for testing:
|
|
323
|
-
|
|
324
|
-
```typescript
|
|
325
|
-
function createMockStorageFactory() {
|
|
326
|
-
const store = new Map<string, string>();
|
|
327
|
-
|
|
328
|
-
return (namespace: string) => ({
|
|
329
|
-
preload: () => {},
|
|
330
|
-
getItem: (key: string) => store.get(`${namespace}:${key}`) ?? null,
|
|
331
|
-
setItem: (key: string, value: string) => store.set(`${namespace}:${key}`, value),
|
|
332
|
-
removeItem: (key: string) => store.delete(`${namespace}:${key}`),
|
|
333
|
-
clear: () => store.clear(),
|
|
334
|
-
keys: () => Array.from(store.keys()),
|
|
335
|
-
});
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
// Use in tests
|
|
339
|
-
const teardown = new TeardownCore({
|
|
340
|
-
storageFactory: createMockStorageFactory(),
|
|
341
|
-
// ...
|
|
342
|
-
});
|
|
343
|
-
```
|
|
344
|
-
|
|
345
|
-
## Next Steps
|
|
346
|
-
|
|
347
|
-
- [Logging](./06-logging.mdx)
|
|
348
|
-
- [API Reference](./07-api-reference.mdx)
|
|
349
|
-
- [Advanced Usage](./09-advanced.mdx)
|