@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
|
@@ -1,188 +0,0 @@
|
|
|
1
|
-
# Core Concepts
|
|
2
|
-
|
|
3
|
-
Understanding the architecture and design principles of the Teardown SDK.
|
|
4
|
-
|
|
5
|
-
## Architecture Overview
|
|
6
|
-
|
|
7
|
-
The Teardown SDK is built around a central `TeardownCore` instance that manages several specialized clients:
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
TeardownCore
|
|
11
|
-
├── IdentityClient - User and device identity
|
|
12
|
-
├── ForceUpdateClient - Version management
|
|
13
|
-
├── DeviceClient - Device information
|
|
14
|
-
├── StorageClient - Persistent storage
|
|
15
|
-
├── LoggingClient - Structured logging
|
|
16
|
-
└── ApiClient - API communication
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
## Core Principles
|
|
20
|
-
|
|
21
|
-
### 1. Single Source of Truth
|
|
22
|
-
|
|
23
|
-
The `TeardownCore` instance is your single entry point to all SDK functionality. It's initialized once and passed through your app via the `TeardownProvider`.
|
|
24
|
-
|
|
25
|
-
```typescript
|
|
26
|
-
const teardown = new TeardownCore({...});
|
|
27
|
-
|
|
28
|
-
// Use throughout your app
|
|
29
|
-
<TeardownProvider core={teardown}>
|
|
30
|
-
<App />
|
|
31
|
-
</TeardownProvider>
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### 2. Automatic Initialization
|
|
35
|
-
|
|
36
|
-
The SDK automatically initializes when the `TeardownProvider` mounts:
|
|
37
|
-
|
|
38
|
-
- Loads persisted session data
|
|
39
|
-
- Identifies the device
|
|
40
|
-
- Checks version status
|
|
41
|
-
- Subscribes to app lifecycle events
|
|
42
|
-
|
|
43
|
-
### 3. Reactive State Management
|
|
44
|
-
|
|
45
|
-
All clients use event emitters to notify of state changes. React hooks automatically subscribe to these events:
|
|
46
|
-
|
|
47
|
-
```typescript
|
|
48
|
-
// Hooks automatically subscribe and cleanup
|
|
49
|
-
const session = useSession();
|
|
50
|
-
const { versionStatus } = useForceUpdate();
|
|
51
|
-
```
|
|
52
|
-
|
|
53
|
-
### 4. Namespaced Storage
|
|
54
|
-
|
|
55
|
-
Each client gets its own namespaced storage to prevent key collisions:
|
|
56
|
-
|
|
57
|
-
```typescript
|
|
58
|
-
// Storage is automatically namespaced
|
|
59
|
-
teardown:v1:identity:IDENTIFY_STATE
|
|
60
|
-
teardown:v1:device:deviceId
|
|
61
|
-
teardown:v1:version:VERSION_STATUS
|
|
62
|
-
```
|
|
63
|
-
|
|
64
|
-
## Client Responsibilities
|
|
65
|
-
|
|
66
|
-
### IdentityClient
|
|
67
|
-
|
|
68
|
-
Manages device and user identity:
|
|
69
|
-
|
|
70
|
-
- Generates unique device IDs
|
|
71
|
-
- Tracks user sessions
|
|
72
|
-
- Persists authentication state
|
|
73
|
-
- Provides persona management (anonymous or identified users)
|
|
74
|
-
|
|
75
|
-
### ForceUpdateClient
|
|
76
|
-
|
|
77
|
-
Handles version management:
|
|
78
|
-
|
|
79
|
-
- Checks app version against backend
|
|
80
|
-
- Monitors app state changes
|
|
81
|
-
- Throttles version checks
|
|
82
|
-
- Emits update status changes
|
|
83
|
-
|
|
84
|
-
### DeviceClient
|
|
85
|
-
|
|
86
|
-
Collects device information:
|
|
87
|
-
|
|
88
|
-
- OS version and platform
|
|
89
|
-
- Device model and manufacturer
|
|
90
|
-
- App version and build number
|
|
91
|
-
- Uses platform adapters for consistency
|
|
92
|
-
|
|
93
|
-
### StorageClient
|
|
94
|
-
|
|
95
|
-
Provides persistent storage:
|
|
96
|
-
|
|
97
|
-
- Namespaced key-value storage
|
|
98
|
-
- Platform-agnostic interface
|
|
99
|
-
- Support for multiple adapters (MMKV, AsyncStorage, etc.)
|
|
100
|
-
- Automatic cleanup on shutdown
|
|
101
|
-
|
|
102
|
-
### LoggingClient
|
|
103
|
-
|
|
104
|
-
Structured logging system:
|
|
105
|
-
|
|
106
|
-
- Configurable log levels
|
|
107
|
-
- Named loggers for each client
|
|
108
|
-
- Console binding preservation
|
|
109
|
-
- Debug mode support
|
|
110
|
-
|
|
111
|
-
### ApiClient
|
|
112
|
-
|
|
113
|
-
Handles API communication:
|
|
114
|
-
|
|
115
|
-
- Type-safe API client
|
|
116
|
-
- Automatic header injection
|
|
117
|
-
- Request/response logging
|
|
118
|
-
- Error handling
|
|
119
|
-
|
|
120
|
-
## Lifecycle Management
|
|
121
|
-
|
|
122
|
-
### Initialization
|
|
123
|
-
|
|
124
|
-
```typescript
|
|
125
|
-
const teardown = new TeardownCore({...});
|
|
126
|
-
// Automatically initializes identity client
|
|
127
|
-
```
|
|
128
|
-
|
|
129
|
-
### Runtime
|
|
130
|
-
|
|
131
|
-
The SDK operates automatically:
|
|
132
|
-
- Listens for app state changes
|
|
133
|
-
- Checks version on foreground
|
|
134
|
-
- Persists state changes
|
|
135
|
-
|
|
136
|
-
### Cleanup
|
|
137
|
-
|
|
138
|
-
```typescript
|
|
139
|
-
// Automatic cleanup when provider unmounts
|
|
140
|
-
useEffect(() => {
|
|
141
|
-
return () => {
|
|
142
|
-
core.shutdown();
|
|
143
|
-
};
|
|
144
|
-
}, [core]);
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
## State Persistence
|
|
148
|
-
|
|
149
|
-
All critical state is automatically persisted:
|
|
150
|
-
|
|
151
|
-
```typescript
|
|
152
|
-
// Identity state
|
|
153
|
-
{ type: "identified", session: {...}, version_info: {...} }
|
|
154
|
-
|
|
155
|
-
// Version status
|
|
156
|
-
{ type: "up_to_date" | "update_available" | "update_required" | ... }
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
State is restored on app restart for seamless user experience.
|
|
160
|
-
|
|
161
|
-
## Error Handling
|
|
162
|
-
|
|
163
|
-
The SDK uses `AsyncResult` pattern for predictable error handling:
|
|
164
|
-
|
|
165
|
-
```typescript
|
|
166
|
-
const result = await core.identity.identify({...});
|
|
167
|
-
|
|
168
|
-
if (result.success) {
|
|
169
|
-
// Handle success
|
|
170
|
-
console.log(result.data);
|
|
171
|
-
} else {
|
|
172
|
-
// Handle error
|
|
173
|
-
console.error(result.error);
|
|
174
|
-
}
|
|
175
|
-
```
|
|
176
|
-
|
|
177
|
-
## Type Safety
|
|
178
|
-
|
|
179
|
-
Full TypeScript support with:
|
|
180
|
-
- Runtime validation using Zod schemas
|
|
181
|
-
- Discriminated unions for state types
|
|
182
|
-
- Exported types for all public APIs
|
|
183
|
-
|
|
184
|
-
## Next Steps
|
|
185
|
-
|
|
186
|
-
- [Identity & Authentication](./03-identity.mdx)
|
|
187
|
-
- [Force Updates](./04-force-updates.mdx)
|
|
188
|
-
- [API Reference](./07-api-reference.mdx)
|
package/docs/03-identity.mdx
DELETED
|
@@ -1,301 +0,0 @@
|
|
|
1
|
-
# Identity & Authentication
|
|
2
|
-
|
|
3
|
-
Manage user sessions and device identity with the IdentityClient.
|
|
4
|
-
|
|
5
|
-
## Overview
|
|
6
|
-
|
|
7
|
-
The IdentityClient handles:
|
|
8
|
-
- Device fingerprinting
|
|
9
|
-
- User identification and session management
|
|
10
|
-
- Anonymous and identified user states
|
|
11
|
-
- Automatic session persistence
|
|
12
|
-
|
|
13
|
-
## Identity States
|
|
14
|
-
|
|
15
|
-
The SDK uses a discriminated union to represent identity states:
|
|
16
|
-
|
|
17
|
-
```typescript
|
|
18
|
-
type IdentifyState =
|
|
19
|
-
| { type: "unidentified" }
|
|
20
|
-
| { type: "identifying" }
|
|
21
|
-
| { type: "identified", session: Session, version_info: {...} }
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
### State Transitions
|
|
25
|
-
|
|
26
|
-
```
|
|
27
|
-
unidentified → identifying → identified
|
|
28
|
-
↑ ↓
|
|
29
|
-
└───────── reset() ─────────┘
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Using the Identity Client
|
|
33
|
-
|
|
34
|
-
### Access via Hook
|
|
35
|
-
|
|
36
|
-
```typescript
|
|
37
|
-
import { useSession } from '@teardown/react-native';
|
|
38
|
-
|
|
39
|
-
function MyComponent() {
|
|
40
|
-
const session = useSession();
|
|
41
|
-
|
|
42
|
-
if (!session) {
|
|
43
|
-
return <LoginScreen />;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
return <div>Welcome, {session.persona_id}</div>;
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
### Access via Core
|
|
51
|
-
|
|
52
|
-
```typescript
|
|
53
|
-
import { useTeardown } from '@teardown/react-native';
|
|
54
|
-
|
|
55
|
-
function MyComponent() {
|
|
56
|
-
const { core } = useTeardown();
|
|
57
|
-
|
|
58
|
-
const handleLogin = async () => {
|
|
59
|
-
const result = await core.identity.identify({
|
|
60
|
-
user_id: 'user-123',
|
|
61
|
-
email: 'user@example.com',
|
|
62
|
-
name: 'John Doe',
|
|
63
|
-
});
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Identifying Users
|
|
69
|
-
|
|
70
|
-
### Anonymous Identification
|
|
71
|
-
|
|
72
|
-
Automatically happens on SDK initialization:
|
|
73
|
-
|
|
74
|
-
```typescript
|
|
75
|
-
// Happens automatically when TeardownProvider mounts
|
|
76
|
-
await core.identity.identify();
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
This creates an anonymous session with:
|
|
80
|
-
- Unique device ID
|
|
81
|
-
- Session ID
|
|
82
|
-
- Device information
|
|
83
|
-
- Version status
|
|
84
|
-
|
|
85
|
-
### Identified Users
|
|
86
|
-
|
|
87
|
-
Identify users with their information:
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
const result = await core.identity.identify({
|
|
91
|
-
user_id: 'user-123',
|
|
92
|
-
email: 'user@example.com',
|
|
93
|
-
name: 'John Doe',
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
if (result.success) {
|
|
97
|
-
console.log('Session:', result.data.session_id);
|
|
98
|
-
console.log('Device:', result.data.device_id);
|
|
99
|
-
console.log('Persona:', result.data.persona_id);
|
|
100
|
-
console.log('Token:', result.data.token);
|
|
101
|
-
}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
### Persona Object
|
|
105
|
-
|
|
106
|
-
```typescript
|
|
107
|
-
type Persona = {
|
|
108
|
-
user_id?: string;
|
|
109
|
-
email?: string;
|
|
110
|
-
name?: string;
|
|
111
|
-
}
|
|
112
|
-
```
|
|
113
|
-
|
|
114
|
-
All fields are optional. You can identify with just an email, just a user_id, or any combination.
|
|
115
|
-
|
|
116
|
-
## Session Management
|
|
117
|
-
|
|
118
|
-
### Getting Current Session
|
|
119
|
-
|
|
120
|
-
```typescript
|
|
121
|
-
// Via hook (reactive)
|
|
122
|
-
const session = useSession();
|
|
123
|
-
|
|
124
|
-
// Via client (direct)
|
|
125
|
-
const session = core.identity.getSessionState();
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### Session Object
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
type Session = {
|
|
132
|
-
session_id: string; // Unique session identifier
|
|
133
|
-
device_id: string; // Unique device identifier
|
|
134
|
-
persona_id: string; // User/persona identifier
|
|
135
|
-
token: string; // Authentication token
|
|
136
|
-
}
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
### Refreshing Session
|
|
140
|
-
|
|
141
|
-
Re-identify the current persona to refresh session data:
|
|
142
|
-
|
|
143
|
-
```typescript
|
|
144
|
-
const result = await core.identity.refresh();
|
|
145
|
-
|
|
146
|
-
if (result.success) {
|
|
147
|
-
console.log('Session refreshed');
|
|
148
|
-
}
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
Note: `refresh()` only works if already identified.
|
|
152
|
-
|
|
153
|
-
## Logging Out
|
|
154
|
-
|
|
155
|
-
Reset the identity state to anonymous:
|
|
156
|
-
|
|
157
|
-
```typescript
|
|
158
|
-
core.identity.reset();
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
This will:
|
|
162
|
-
- Clear persisted session data
|
|
163
|
-
- Set state to "unidentified"
|
|
164
|
-
- Emit state change event
|
|
165
|
-
- Trigger re-identification on next app open
|
|
166
|
-
|
|
167
|
-
## Listening to State Changes
|
|
168
|
-
|
|
169
|
-
### Via Hook
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
const session = useSession();
|
|
173
|
-
|
|
174
|
-
// Automatically re-renders on state changes
|
|
175
|
-
useEffect(() => {
|
|
176
|
-
console.log('Session changed:', session);
|
|
177
|
-
}, [session]);
|
|
178
|
-
```
|
|
179
|
-
|
|
180
|
-
### Via Event Listener
|
|
181
|
-
|
|
182
|
-
```typescript
|
|
183
|
-
useEffect(() => {
|
|
184
|
-
const unsubscribe = core.identity.onIdentifyStateChange((state) => {
|
|
185
|
-
console.log('State changed:', state.type);
|
|
186
|
-
|
|
187
|
-
if (state.type === 'identified') {
|
|
188
|
-
console.log('User session:', state.session);
|
|
189
|
-
}
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
return unsubscribe;
|
|
193
|
-
}, []);
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
## Identity State
|
|
197
|
-
|
|
198
|
-
Get the full identity state (not just session):
|
|
199
|
-
|
|
200
|
-
```typescript
|
|
201
|
-
const state = core.identity.getIdentifyState();
|
|
202
|
-
|
|
203
|
-
switch (state.type) {
|
|
204
|
-
case 'unidentified':
|
|
205
|
-
// No session yet
|
|
206
|
-
break;
|
|
207
|
-
case 'identifying':
|
|
208
|
-
// Identifying in progress
|
|
209
|
-
break;
|
|
210
|
-
case 'identified':
|
|
211
|
-
// Has session and version info
|
|
212
|
-
console.log(state.session);
|
|
213
|
-
console.log(state.version_info);
|
|
214
|
-
break;
|
|
215
|
-
}
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
## Error Handling
|
|
219
|
-
|
|
220
|
-
All identity operations return `AsyncResult`:
|
|
221
|
-
|
|
222
|
-
```typescript
|
|
223
|
-
const result = await core.identity.identify({
|
|
224
|
-
email: 'invalid-email',
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
if (!result.success) {
|
|
228
|
-
console.error('Identification failed:', result.error);
|
|
229
|
-
// Handle error (show message, retry, etc.)
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
Common errors:
|
|
234
|
-
- Network errors
|
|
235
|
-
- Invalid API credentials
|
|
236
|
-
- Validation errors (422)
|
|
237
|
-
- Server errors
|
|
238
|
-
|
|
239
|
-
## Best Practices
|
|
240
|
-
|
|
241
|
-
### 1. Let Auto-Initialization Happen
|
|
242
|
-
|
|
243
|
-
```typescript
|
|
244
|
-
// ✅ Good - automatic anonymous identification
|
|
245
|
-
<TeardownProvider core={teardown}>
|
|
246
|
-
<App />
|
|
247
|
-
</TeardownProvider>
|
|
248
|
-
|
|
249
|
-
// ❌ Bad - don't manually call identify on mount
|
|
250
|
-
useEffect(() => {
|
|
251
|
-
core.identity.identify();
|
|
252
|
-
}, []);
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
### 2. Identify on Login/Signup
|
|
256
|
-
|
|
257
|
-
```typescript
|
|
258
|
-
const handleLogin = async (email: string, password: string) => {
|
|
259
|
-
// Your auth logic
|
|
260
|
-
const user = await login(email, password);
|
|
261
|
-
|
|
262
|
-
// Identify with Teardown
|
|
263
|
-
await core.identity.identify({
|
|
264
|
-
user_id: user.id,
|
|
265
|
-
email: user.email,
|
|
266
|
-
name: user.name,
|
|
267
|
-
});
|
|
268
|
-
};
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
### 3. Reset on Logout
|
|
272
|
-
|
|
273
|
-
```typescript
|
|
274
|
-
const handleLogout = async () => {
|
|
275
|
-
// Your logout logic
|
|
276
|
-
await logout();
|
|
277
|
-
|
|
278
|
-
// Reset Teardown identity
|
|
279
|
-
core.identity.reset();
|
|
280
|
-
};
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### 4. Use the Hook for Reactive UI
|
|
284
|
-
|
|
285
|
-
```typescript
|
|
286
|
-
function UserProfile() {
|
|
287
|
-
const session = useSession();
|
|
288
|
-
|
|
289
|
-
if (!session) {
|
|
290
|
-
return <LoginPrompt />;
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
return <Profile personaId={session.persona_id} />;
|
|
294
|
-
}
|
|
295
|
-
```
|
|
296
|
-
|
|
297
|
-
## Next Steps
|
|
298
|
-
|
|
299
|
-
- [Force Updates](./04-force-updates.mdx)
|
|
300
|
-
- [Device Information](./05-device-info.mdx)
|
|
301
|
-
- [API Reference](./07-api-reference.mdx)
|