@teardown/react-native 2.0.0 → 2.0.2
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 +33 -19
- package/docs/01-getting-started.mdx +147 -0
- package/docs/02-core-concepts.mdx +188 -0
- package/docs/03-identity.mdx +301 -0
- package/docs/04-force-updates.mdx +339 -0
- package/docs/05-device-info.mdx +324 -0
- package/docs/06-logging.mdx +345 -0
- package/docs/06-storage.mdx +349 -0
- package/docs/07-api-reference.mdx +472 -0
- package/docs/07-logging.mdx +345 -0
- package/docs/08-api-reference.mdx +472 -0
- package/docs/08-hooks-reference.mdx +476 -0
- package/docs/09-advanced.mdx +563 -0
- package/docs/09-hooks-reference.mdx +476 -0
- package/docs/10-advanced.mdx +563 -0
- package/package.json +46 -18
- package/src/clients/api/api.client.ts +29 -4
- package/src/clients/device/{expo-adapter.ts → adapters/basic.adapter.ts} +2 -40
- package/src/clients/device/{device.adpater-interface.ts → adapters/device.adpater-interface.ts} +1 -1
- package/src/clients/device/adapters/expo.adapter.ts +90 -0
- package/src/clients/device/device.client.test.ts +1 -6
- package/src/clients/device/device.client.ts +5 -1
- package/src/clients/device/index.ts +1 -1
- package/src/clients/force-update/force-update.client.test.ts +244 -13
- package/src/clients/force-update/force-update.client.ts +71 -11
- package/src/clients/identity/identity.client.test.ts +888 -223
- package/src/clients/identity/identity.client.ts +59 -14
- package/src/clients/storage/adapters/async-storage.adapter.ts +81 -0
- package/src/clients/storage/{mmkv-adapter.ts → adapters/mmkv.adapter.ts} +7 -10
- package/src/clients/storage/adapters/storage.adpater-interface.ts +30 -0
- package/src/clients/storage/index.ts +2 -1
- package/src/clients/storage/storage.client.ts +9 -20
- package/src/clients/utils/utils.client.ts +1 -57
- package/src/exports/adapters/async-storage.ts +1 -0
- package/src/exports/adapters/expo.ts +1 -0
- package/src/exports/adapters/mmkv.ts +1 -0
- package/src/hooks/use-force-update.ts +12 -3
- package/src/hooks/use-session.ts +7 -4
- package/src/teardown.core.ts +16 -6
- package/src/exports/expo.ts +0 -1
- package/src/exports/mmkv.ts +0 -1
package/README.md
CHANGED
|
@@ -28,32 +28,46 @@ bun add react-native-device-info
|
|
|
28
28
|
|
|
29
29
|
## Quick Start
|
|
30
30
|
|
|
31
|
+
### 1. Initialize the SDK
|
|
32
|
+
|
|
31
33
|
```tsx
|
|
32
|
-
import { TeardownCore
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
34
|
+
import { TeardownCore } from '@teardown/react-native';
|
|
35
|
+
import { ExpoDeviceAdapter } from '@teardown/react-native/expo';
|
|
36
|
+
import { createMMKVStorageFactory } from '@teardown/react-native/mmkv';
|
|
37
|
+
|
|
38
|
+
export const teardown = new TeardownCore({
|
|
39
|
+
org_id: 'your-org-id',
|
|
40
|
+
project_id: 'your-project-id',
|
|
41
|
+
api_key: 'your-api-key',
|
|
42
|
+
storageFactory: createMMKVStorageFactory(),
|
|
43
|
+
deviceAdapter: new ExpoDeviceAdapter(),
|
|
44
|
+
forceUpdate: {
|
|
45
|
+
throttleMs: 30_000, // 30 seconds
|
|
46
|
+
checkCooldownMs: 10_000, // 10 seconds
|
|
41
47
|
},
|
|
42
|
-
storage: { /* ... */ },
|
|
43
|
-
device: { /* ... */ },
|
|
44
|
-
identity: { identifyOnLoad: true },
|
|
45
48
|
});
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Wrap your app with TeardownProvider
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
import { TeardownProvider } from '@teardown/react-native';
|
|
55
|
+
import { teardown } from './lib/teardown';
|
|
46
56
|
|
|
47
|
-
|
|
48
|
-
export default function App() {
|
|
57
|
+
export default function RootLayout() {
|
|
49
58
|
return (
|
|
50
59
|
<TeardownProvider core={teardown}>
|
|
51
60
|
<YourApp />
|
|
52
61
|
</TeardownProvider>
|
|
53
62
|
);
|
|
54
63
|
}
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
### 3. Use in components
|
|
67
|
+
|
|
68
|
+
```tsx
|
|
69
|
+
import { useTeardown } from '@teardown/react-native';
|
|
55
70
|
|
|
56
|
-
// Use in components
|
|
57
71
|
function YourComponent() {
|
|
58
72
|
const { core } = useTeardown();
|
|
59
73
|
|
|
@@ -78,10 +92,10 @@ Complete documentation is available in the [docs](./docs) folder:
|
|
|
78
92
|
- [Force Updates](./docs/04-force-updates.mdx) - Version management
|
|
79
93
|
- [Device Information](./docs/05-device-info.mdx) - Device data collection
|
|
80
94
|
- [Storage](./docs/06-storage.mdx) - Persistent storage
|
|
81
|
-
- [Logging](./docs/
|
|
82
|
-
- [API Reference](./docs/
|
|
83
|
-
- [Hooks Reference](./docs/
|
|
84
|
-
- [Advanced Usage](./docs/
|
|
95
|
+
- [Logging](./docs/07-logging.mdx) - Structured logging
|
|
96
|
+
- [API Reference](./docs/08-api-reference.mdx) - Complete API docs
|
|
97
|
+
- [Hooks Reference](./docs/09-hooks-reference.mdx) - React hooks
|
|
98
|
+
- [Advanced Usage](./docs/10-advanced.mdx) - Advanced patterns
|
|
85
99
|
|
|
86
100
|
## License
|
|
87
101
|
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
This guide will walk you through installing and setting up the Teardown SDK in your React Native or Expo application.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the core package:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
bun add @teardown/react-native
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
### Peer Dependencies
|
|
14
|
+
|
|
15
|
+
Install required peer dependencies:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
bun add react react-native zod
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### Platform Adapters
|
|
22
|
+
|
|
23
|
+
#### For Expo Projects
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
bun add expo-application expo-device expo-updates
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
#### For React Native CLI Projects
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
bun add react-native-device-info
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Storage Adapter
|
|
36
|
+
|
|
37
|
+
Install MMKV for fast, encrypted storage:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
bun add react-native-mmkv
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
## Initial Setup
|
|
44
|
+
|
|
45
|
+
### 1. Create SDK Configuration
|
|
46
|
+
|
|
47
|
+
Create a file to initialize the Teardown SDK (e.g., `lib/teardown.ts`):
|
|
48
|
+
|
|
49
|
+
```typescript
|
|
50
|
+
import { TeardownCore } from '@teardown/react-native';
|
|
51
|
+
import { ExpoDeviceAdapter } from '@teardown/react-native/expo';
|
|
52
|
+
import { createMMKVStorageFactory } from '@teardown/react-native/mmkv';
|
|
53
|
+
|
|
54
|
+
export const teardown = new TeardownCore({
|
|
55
|
+
org_id: 'your-org-id',
|
|
56
|
+
project_id: 'your-project-id',
|
|
57
|
+
api_key: 'your-api-key',
|
|
58
|
+
storageFactory: createMMKVStorageFactory(),
|
|
59
|
+
deviceAdapter: new ExpoDeviceAdapter(),
|
|
60
|
+
forceUpdate: {
|
|
61
|
+
throttleMs: 30_000, // Check every 30 seconds when app returns to foreground
|
|
62
|
+
checkCooldownMs: 300_000, // Wait 5 minutes between checks
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
### 2. Wrap Your App with TeardownProvider
|
|
68
|
+
|
|
69
|
+
In your root layout file (e.g., `app/_layout.tsx` for Expo Router):
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
import { TeardownProvider } from '@teardown/react-native';
|
|
73
|
+
import { teardown } from '../lib/teardown';
|
|
74
|
+
|
|
75
|
+
export default function RootLayout() {
|
|
76
|
+
return (
|
|
77
|
+
<TeardownProvider core={teardown}>
|
|
78
|
+
<YourApp />
|
|
79
|
+
</TeardownProvider>
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
For traditional React Native:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { TeardownProvider } from '@teardown/react-native';
|
|
88
|
+
import { teardown } from './lib/teardown';
|
|
89
|
+
|
|
90
|
+
export default function App() {
|
|
91
|
+
return (
|
|
92
|
+
<TeardownProvider core={teardown}>
|
|
93
|
+
<YourNavigationStack />
|
|
94
|
+
</TeardownProvider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 3. Use the SDK in Your Components
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { useTeardown } from '@teardown/react-native';
|
|
103
|
+
|
|
104
|
+
function MyComponent() {
|
|
105
|
+
const { core } = useTeardown();
|
|
106
|
+
|
|
107
|
+
const handleLogin = async () => {
|
|
108
|
+
const result = await core.identity.identify({
|
|
109
|
+
user_id: 'user-123',
|
|
110
|
+
email: 'user@example.com',
|
|
111
|
+
name: 'John Doe',
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
if (result.success) {
|
|
115
|
+
console.log('User identified:', result.data);
|
|
116
|
+
}
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
return <Button onPress={handleLogin} title="Login" />;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Configuration Options
|
|
124
|
+
|
|
125
|
+
### TeardownCore Options
|
|
126
|
+
|
|
127
|
+
| Option | Type | Required | Description |
|
|
128
|
+
|--------|------|----------|-------------|
|
|
129
|
+
| `org_id` | string | Yes | Your organization ID from Teardown dashboard |
|
|
130
|
+
| `project_id` | string | Yes | Your project ID from Teardown dashboard |
|
|
131
|
+
| `api_key` | string | Yes | Your API key from Teardown dashboard |
|
|
132
|
+
| `storageFactory` | function | Yes | Storage adapter factory (e.g., MMKV) |
|
|
133
|
+
| `deviceAdapter` | object | Yes | Device info adapter (Expo or RN) |
|
|
134
|
+
| `forceUpdate` | object | No | Force update configuration |
|
|
135
|
+
|
|
136
|
+
### Force Update Options
|
|
137
|
+
|
|
138
|
+
| Option | Type | Default | Description |
|
|
139
|
+
|--------|------|---------|-------------|
|
|
140
|
+
| `throttleMs` | number | 30000 | Minimum time between foreground checks (ms) |
|
|
141
|
+
| `checkCooldownMs` | number | 300000 | Minimum time since last successful check (ms) |
|
|
142
|
+
|
|
143
|
+
## Next Steps
|
|
144
|
+
|
|
145
|
+
- [Core Concepts](./02-core-concepts.mdx) - Understand the architecture
|
|
146
|
+
- [Identity & Authentication](./03-identity.mdx) - Manage user sessions
|
|
147
|
+
- [Force Updates](./04-force-updates.mdx) - Handle version management
|
|
@@ -0,0 +1,188 @@
|
|
|
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)
|
|
@@ -0,0 +1,301 @@
|
|
|
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)
|