@teardown/react-native 2.0.23 → 2.0.27
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/docs/adapters/device/basic.mdx +59 -0
- package/docs/adapters/device/device-info.mdx +76 -0
- package/docs/adapters/device/expo.mdx +61 -0
- package/docs/adapters/device/index.mdx +102 -0
- package/docs/adapters/device/meta.json +4 -0
- package/docs/adapters/index.mdx +96 -0
- package/docs/adapters/meta.json +4 -0
- package/docs/adapters/notifications/expo.mdx +127 -0
- package/docs/adapters/notifications/firebase.mdx +142 -0
- package/docs/adapters/notifications/index.mdx +100 -0
- package/docs/adapters/notifications/meta.json +4 -0
- package/docs/adapters/notifications/wix.mdx +140 -0
- package/docs/adapters/storage/async-storage.mdx +95 -0
- package/docs/adapters/storage/index.mdx +93 -0
- package/docs/adapters/storage/meta.json +4 -0
- package/docs/adapters/storage/mmkv.mdx +86 -0
- package/docs/advanced.mdx +280 -0
- package/docs/api-reference.mdx +241 -0
- package/docs/core-concepts.mdx +158 -0
- package/docs/force-updates.mdx +185 -0
- package/docs/getting-started.mdx +156 -0
- package/docs/hooks-reference.mdx +232 -0
- package/docs/identity.mdx +171 -0
- package/docs/index.mdx +61 -0
- package/docs/logging.mdx +144 -0
- package/docs/meta.json +14 -0
- package/package.json +49 -31
- package/src/clients/api/index.ts +1 -1
- package/src/clients/device/adapters/basic.adapter.ts +57 -66
- package/src/clients/device/adapters/device-info.adapter.ts +21 -28
- package/src/clients/device/adapters/device.adpater-interface.ts +1 -8
- package/src/clients/device/adapters/expo.adapter.ts +33 -40
- package/src/clients/device/device.client.test.ts +20 -35
- package/src/clients/device/device.client.ts +0 -3
- package/src/clients/force-update/force-update.client.test.ts +69 -23
- package/src/clients/force-update/force-update.client.ts +42 -59
- package/src/clients/identity/identity.client.test.ts +22 -14
- package/src/clients/identity/identity.client.ts +1 -1
- package/src/clients/identity/index.ts +1 -1
- package/src/clients/logging/index.ts +1 -1
- package/src/clients/notifications/adapters/expo-notifications.adapter.ts +105 -0
- package/src/clients/notifications/adapters/firebase-messaging.adapter.ts +87 -0
- package/src/clients/notifications/adapters/notifications.adapter-interface.ts +112 -0
- package/src/clients/notifications/adapters/wix-notifications.adapter.ts +183 -0
- package/src/clients/notifications/index.ts +2 -0
- package/src/clients/notifications/notifications.client.ts +214 -3
- package/src/clients/storage/adapters/async-storage.adapter.ts +2 -6
- package/src/clients/storage/adapters/storage-adapters.test.ts +2 -7
- package/src/clients/storage/adapters/storage.adpater-interface.ts +1 -5
- package/src/clients/utils/index.ts +1 -1
- package/src/clients/utils/utils.client.ts +1 -1
- package/src/exports/adapters/async-storage.ts +1 -1
- package/src/exports/adapters/expo.ts +1 -1
- package/src/exports/expo.ts +2 -0
- package/src/exports/firebase.ts +1 -0
- package/src/exports/index.ts +6 -9
- package/src/exports/wix.ts +1 -0
- package/src/hooks/use-force-update.ts +31 -34
- package/src/index.ts +1 -0
- package/src/teardown.core.ts +0 -2
- package/src/.DS_Store +0 -0
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Force Updates
|
|
3
|
+
description: Manage app version checking and force update flows.
|
|
4
|
+
icon: RefreshCw
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The Force Update client automatically checks your app version against your configured release policy and can require users to update.
|
|
8
|
+
|
|
9
|
+
## Overview
|
|
10
|
+
|
|
11
|
+
Force updates work by:
|
|
12
|
+
|
|
13
|
+
1. Checking app version on identify
|
|
14
|
+
2. Checking again when app returns to foreground
|
|
15
|
+
3. Emitting status changes your app can respond to
|
|
16
|
+
|
|
17
|
+
## Version Status
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
type VersionStatus =
|
|
21
|
+
| { type: 'initializing' } // SDK starting up
|
|
22
|
+
| { type: 'checking' } // Version check in progress
|
|
23
|
+
| { type: 'up_to_date' } // Current version is valid
|
|
24
|
+
| { type: 'update_available' } // Optional update exists
|
|
25
|
+
| { type: 'update_recommended' } // Recommended update exists
|
|
26
|
+
| { type: 'update_required' } // Must update to continue
|
|
27
|
+
| { type: 'disabled' } // Version/build has been disabled
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Basic Usage
|
|
31
|
+
|
|
32
|
+
### Using the Hook
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
import { useForceUpdate } from '@teardown/react-native';
|
|
36
|
+
|
|
37
|
+
function App() {
|
|
38
|
+
const { versionStatus, isUpdateRequired, isUpdateAvailable, isUpdateRecommended } = useForceUpdate();
|
|
39
|
+
|
|
40
|
+
if (isUpdateRequired) {
|
|
41
|
+
return <ForceUpdateModal />;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if (isUpdateRecommended) {
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
<UpdateBanner onDismiss={() => {}} />
|
|
48
|
+
<MainApp />
|
|
49
|
+
</>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return <MainApp />;
|
|
54
|
+
}
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Hook Return Values
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
interface UseForceUpdateResult {
|
|
61
|
+
versionStatus: VersionStatus; // Full status object
|
|
62
|
+
isUpdateAvailable: boolean; // Any update exists (available, recommended, or required)
|
|
63
|
+
isUpdateRecommended: boolean; // Update is recommended but not required
|
|
64
|
+
isUpdateRequired: boolean; // Update is mandatory
|
|
65
|
+
}
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
Configure force update behavior in `TeardownCore`:
|
|
71
|
+
|
|
72
|
+
```typescript
|
|
73
|
+
const teardown = new TeardownCore({
|
|
74
|
+
// ...other options
|
|
75
|
+
forceUpdate: {
|
|
76
|
+
checkIntervalMs: 300_000, // 5 minutes (default)
|
|
77
|
+
checkOnForeground: true, // Check when app foregrounds (default: true)
|
|
78
|
+
identifyAnonymousDevice: false, // Check even when not identified (default: false)
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Options
|
|
84
|
+
|
|
85
|
+
| Option | Type | Default | Description |
|
|
86
|
+
|--------|------|---------|-------------|
|
|
87
|
+
| `checkIntervalMs` | number | 300000 | Minimum time between version checks. Use `0` for every foreground, `-1` to disable. Values below 30s are clamped to 30s. |
|
|
88
|
+
| `checkOnForeground` | boolean | true | Check version when app returns to foreground |
|
|
89
|
+
| `identifyAnonymousDevice` | boolean | false | Check version even when user is not identified |
|
|
90
|
+
|
|
91
|
+
## Direct API Access
|
|
92
|
+
|
|
93
|
+
### Get Current Status
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
const status = core.forceUpdate.getVersionStatus();
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Subscribe to Changes
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
const unsubscribe = core.forceUpdate.onVersionStatusChange((status) => {
|
|
103
|
+
if (status.type === 'update_required') {
|
|
104
|
+
// Show force update modal
|
|
105
|
+
}
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
// Cleanup
|
|
109
|
+
unsubscribe();
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Implementation Patterns
|
|
113
|
+
|
|
114
|
+
### Force Update Modal
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
function ForceUpdateModal() {
|
|
118
|
+
const handleUpdate = () => {
|
|
119
|
+
// Open app store
|
|
120
|
+
Linking.openURL('https://apps.apple.com/app/your-app');
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
return (
|
|
124
|
+
<Modal visible>
|
|
125
|
+
<View style={styles.container}>
|
|
126
|
+
<Text>Update Required</Text>
|
|
127
|
+
<Text>Please update to continue using the app.</Text>
|
|
128
|
+
<Button onPress={handleUpdate} title="Update Now" />
|
|
129
|
+
</View>
|
|
130
|
+
</Modal>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Soft Update Banner
|
|
136
|
+
|
|
137
|
+
```tsx
|
|
138
|
+
function UpdateBanner({ onDismiss }: { onDismiss: () => void }) {
|
|
139
|
+
const { isUpdateRecommended } = useForceUpdate();
|
|
140
|
+
|
|
141
|
+
if (!isUpdateRecommended) return null;
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<View style={styles.banner}>
|
|
145
|
+
<Text>A new version is available</Text>
|
|
146
|
+
<Button onPress={onDismiss} title="Later" />
|
|
147
|
+
<Button onPress={() => Linking.openURL('...')} title="Update" />
|
|
148
|
+
</View>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Root Level Guard
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
function RootLayout() {
|
|
157
|
+
const { isUpdateRequired } = useForceUpdate();
|
|
158
|
+
|
|
159
|
+
if (isUpdateRequired) {
|
|
160
|
+
return <ForceUpdateScreen />;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return <Stack />;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## How It Works
|
|
168
|
+
|
|
169
|
+
1. **On Identify** - Version status is returned from the identify API
|
|
170
|
+
2. **On Foreground** - If `checkOnForeground` is true and interval has passed, re-identifies to check version
|
|
171
|
+
3. **State Persistence** - Last known status is cached for offline access
|
|
172
|
+
4. **Event Emission** - Status changes trigger subscribers and hook re-renders
|
|
173
|
+
|
|
174
|
+
## Dashboard Configuration
|
|
175
|
+
|
|
176
|
+
Configure version policies in the [Teardown Dashboard](https://dash.teardown.dev):
|
|
177
|
+
|
|
178
|
+
1. Go to your project settings
|
|
179
|
+
2. Navigate to "Releases" or "Version Management"
|
|
180
|
+
3. Set policies for each version/build:
|
|
181
|
+
- **Active** - Version is valid
|
|
182
|
+
- **Update Available** - Optional update exists
|
|
183
|
+
- **Update Recommended** - Soft nudge to update
|
|
184
|
+
- **Update Required** - Force update
|
|
185
|
+
- **Disabled** - Version blocked entirely
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Getting Started
|
|
3
|
+
description: Install and configure the Teardown SDK for React Native.
|
|
4
|
+
icon: Rocket
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
Install the core package:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun add @teardown/react-native
|
|
13
|
+
# or
|
|
14
|
+
npm install @teardown/react-native
|
|
15
|
+
# or
|
|
16
|
+
yarn add @teardown/react-native
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### Peer Dependencies
|
|
20
|
+
|
|
21
|
+
Choose adapters based on your project setup:
|
|
22
|
+
|
|
23
|
+
**Expo projects:**
|
|
24
|
+
```bash
|
|
25
|
+
npx expo install expo-device expo-application
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Bare React Native projects:**
|
|
29
|
+
```bash
|
|
30
|
+
npm install react-native-device-info
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
**Storage (choose one):**
|
|
34
|
+
```bash
|
|
35
|
+
# MMKV (recommended - faster, synchronous)
|
|
36
|
+
npm install react-native-mmkv
|
|
37
|
+
|
|
38
|
+
# or AsyncStorage (broader compatibility)
|
|
39
|
+
npm install @react-native-async-storage/async-storage
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Getting Your Credentials
|
|
43
|
+
|
|
44
|
+
1. Sign up or log in at [dash.teardown.dev](https://dash.teardown.dev)
|
|
45
|
+
2. Create or select a project
|
|
46
|
+
3. Copy your `org_id`, `project_id`, and `api_key` from project settings
|
|
47
|
+
|
|
48
|
+
## Setup
|
|
49
|
+
|
|
50
|
+
### 1. Create SDK Configuration
|
|
51
|
+
|
|
52
|
+
Create a file to initialize the Teardown SDK (e.g., `lib/teardown.ts`):
|
|
53
|
+
|
|
54
|
+
**Expo Setup:**
|
|
55
|
+
```typescript
|
|
56
|
+
import { TeardownCore } from '@teardown/react-native';
|
|
57
|
+
import { ExpoDeviceAdapter } from '@teardown/react-native/adapters/expo';
|
|
58
|
+
import { MMKVStorageAdapter } from '@teardown/react-native/adapters/mmkv';
|
|
59
|
+
|
|
60
|
+
export const teardown = new TeardownCore({
|
|
61
|
+
org_id: 'your-org-id',
|
|
62
|
+
project_id: 'your-project-id',
|
|
63
|
+
api_key: 'your-api-key',
|
|
64
|
+
storageAdapter: new MMKVStorageAdapter(),
|
|
65
|
+
deviceAdapter: new ExpoDeviceAdapter(),
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
**Bare React Native Setup:**
|
|
70
|
+
```typescript
|
|
71
|
+
import { TeardownCore } from '@teardown/react-native';
|
|
72
|
+
import { DeviceInfoAdapter } from '@teardown/react-native/adapters/device-info';
|
|
73
|
+
import { AsyncStorageAdapter } from '@teardown/react-native/adapters/async-storage';
|
|
74
|
+
|
|
75
|
+
export const teardown = new TeardownCore({
|
|
76
|
+
org_id: 'your-org-id',
|
|
77
|
+
project_id: 'your-project-id',
|
|
78
|
+
api_key: 'your-api-key',
|
|
79
|
+
storageAdapter: new AsyncStorageAdapter(),
|
|
80
|
+
deviceAdapter: new DeviceInfoAdapter(),
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### 2. Wrap Your App
|
|
85
|
+
|
|
86
|
+
In your root layout file (e.g., `app/_layout.tsx` for Expo Router):
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
import { TeardownProvider } from '@teardown/react-native';
|
|
90
|
+
import { teardown } from '../lib/teardown';
|
|
91
|
+
|
|
92
|
+
export default function RootLayout() {
|
|
93
|
+
return (
|
|
94
|
+
<TeardownProvider core={teardown}>
|
|
95
|
+
<YourApp />
|
|
96
|
+
</TeardownProvider>
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
### 3. Use in Components
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { useTeardown, useSession, useForceUpdate } from '@teardown/react-native';
|
|
105
|
+
|
|
106
|
+
function MyComponent() {
|
|
107
|
+
const { core } = useTeardown();
|
|
108
|
+
const session = useSession();
|
|
109
|
+
const { isUpdateRequired } = useForceUpdate();
|
|
110
|
+
|
|
111
|
+
const handleLogin = async () => {
|
|
112
|
+
const result = await core.identity.identify({
|
|
113
|
+
user_id: 'user-123',
|
|
114
|
+
email: 'user@example.com',
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
if (result.success) {
|
|
118
|
+
console.log('Session:', result.data.session_id);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
if (isUpdateRequired) {
|
|
123
|
+
return <UpdateRequiredScreen />;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return <Button onPress={handleLogin} title="Login" />;
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
## Configuration Options
|
|
131
|
+
|
|
132
|
+
### TeardownCore Options
|
|
133
|
+
|
|
134
|
+
| Option | Type | Required | Description |
|
|
135
|
+
|--------|------|----------|-------------|
|
|
136
|
+
| `org_id` | string | Yes | Organization ID from dashboard |
|
|
137
|
+
| `project_id` | string | Yes | Project ID from dashboard |
|
|
138
|
+
| `api_key` | string | Yes | API key from dashboard |
|
|
139
|
+
| `storageAdapter` | StorageAdapter | Yes | Storage adapter instance ([see storage](/docs/react-native/adapters/storage)) |
|
|
140
|
+
| `deviceAdapter` | DeviceInfoAdapter | Yes | Device info adapter ([see device](/docs/react-native/adapters/device)) |
|
|
141
|
+
| `forceUpdate` | object | No | Force update configuration ([see force-updates](/docs/react-native/force-updates)) |
|
|
142
|
+
|
|
143
|
+
## Available Adapters
|
|
144
|
+
|
|
145
|
+
| Adapter | Import Path | Use Case |
|
|
146
|
+
|---------|-------------|----------|
|
|
147
|
+
| `ExpoDeviceAdapter` | `@teardown/react-native/adapters/expo` | Expo projects |
|
|
148
|
+
| `DeviceInfoAdapter` | `@teardown/react-native/adapters/device-info` | Bare RN projects |
|
|
149
|
+
| `MMKVStorageAdapter` | `@teardown/react-native/adapters/mmkv` | Fast sync storage |
|
|
150
|
+
| `AsyncStorageAdapter` | `@teardown/react-native/adapters/async-storage` | Standard async storage |
|
|
151
|
+
|
|
152
|
+
## Next Steps
|
|
153
|
+
|
|
154
|
+
- [Core Concepts](/docs/react-native/core-concepts) - Understand the SDK architecture
|
|
155
|
+
- [Identity](/docs/react-native/identity) - Learn about user identification
|
|
156
|
+
- [Force Updates](/docs/react-native/force-updates) - Configure version management
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hooks Reference
|
|
3
|
+
description: React hooks for the Teardown SDK.
|
|
4
|
+
icon: Anchor
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
The SDK provides React hooks for reactive access to SDK state.
|
|
8
|
+
|
|
9
|
+
## TeardownProvider
|
|
10
|
+
|
|
11
|
+
Context provider that makes the SDK available to all child components.
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { TeardownProvider } from '@teardown/react-native';
|
|
15
|
+
import { teardown } from './lib/teardown';
|
|
16
|
+
|
|
17
|
+
function App() {
|
|
18
|
+
return (
|
|
19
|
+
<TeardownProvider core={teardown}>
|
|
20
|
+
<YourApp />
|
|
21
|
+
</TeardownProvider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
### Props
|
|
27
|
+
|
|
28
|
+
| Prop | Type | Required | Description |
|
|
29
|
+
|------|------|----------|-------------|
|
|
30
|
+
| `core` | `TeardownCore` | Yes | Initialized TeardownCore instance |
|
|
31
|
+
| `children` | `ReactNode` | Yes | Child components |
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## useTeardown
|
|
36
|
+
|
|
37
|
+
Access the TeardownCore instance from any component.
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
import { useTeardown } from '@teardown/react-native';
|
|
41
|
+
|
|
42
|
+
function MyComponent() {
|
|
43
|
+
const { core } = useTeardown();
|
|
44
|
+
|
|
45
|
+
// Access clients
|
|
46
|
+
await core.identity.identify({ user_id: '123' });
|
|
47
|
+
core.setLogLevel('verbose');
|
|
48
|
+
}
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Returns
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
interface UseTeardownResult {
|
|
55
|
+
core: TeardownCore;
|
|
56
|
+
}
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Throws
|
|
60
|
+
|
|
61
|
+
Throws an error if used outside of `TeardownProvider`.
|
|
62
|
+
|
|
63
|
+
---
|
|
64
|
+
|
|
65
|
+
## useSession
|
|
66
|
+
|
|
67
|
+
Get the current session with reactive updates.
|
|
68
|
+
|
|
69
|
+
```typescript
|
|
70
|
+
import { useSession } from '@teardown/react-native';
|
|
71
|
+
|
|
72
|
+
function ProfileScreen() {
|
|
73
|
+
const session = useSession();
|
|
74
|
+
|
|
75
|
+
if (!session) {
|
|
76
|
+
return <LoginScreen />;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return (
|
|
80
|
+
<View>
|
|
81
|
+
<Text>User ID: {session.user_id}</Text>
|
|
82
|
+
<Text>Device ID: {session.device_id}</Text>
|
|
83
|
+
<Text>Session ID: {session.session_id}</Text>
|
|
84
|
+
</View>
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Returns
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
type UseSessionResult = Session | null;
|
|
93
|
+
|
|
94
|
+
interface Session {
|
|
95
|
+
session_id: string;
|
|
96
|
+
device_id: string;
|
|
97
|
+
user_id: string;
|
|
98
|
+
token: string;
|
|
99
|
+
}
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
Returns `null` if not identified.
|
|
103
|
+
|
|
104
|
+
### Reactivity
|
|
105
|
+
|
|
106
|
+
The hook subscribes to `identity.onIdentifyStateChange()` and re-renders when:
|
|
107
|
+
- User identifies (session available)
|
|
108
|
+
- User resets (session becomes null)
|
|
109
|
+
- Session refreshes (new session data)
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## useForceUpdate
|
|
114
|
+
|
|
115
|
+
Get version status with reactive updates.
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
import { useForceUpdate } from '@teardown/react-native';
|
|
119
|
+
|
|
120
|
+
function App() {
|
|
121
|
+
const {
|
|
122
|
+
versionStatus,
|
|
123
|
+
isUpdateAvailable,
|
|
124
|
+
isUpdateRecommended,
|
|
125
|
+
isUpdateRequired
|
|
126
|
+
} = useForceUpdate();
|
|
127
|
+
|
|
128
|
+
if (isUpdateRequired) {
|
|
129
|
+
return <ForceUpdateModal />;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (isUpdateRecommended) {
|
|
133
|
+
return (
|
|
134
|
+
<>
|
|
135
|
+
<UpdateBanner />
|
|
136
|
+
<MainApp />
|
|
137
|
+
</>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return <MainApp />;
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Returns
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
interface UseForceUpdateResult {
|
|
149
|
+
/** Full version status object */
|
|
150
|
+
versionStatus: VersionStatus;
|
|
151
|
+
/** Any update exists (available, recommended, or required) */
|
|
152
|
+
isUpdateAvailable: boolean;
|
|
153
|
+
/** Update is recommended but not required */
|
|
154
|
+
isUpdateRecommended: boolean;
|
|
155
|
+
/** Update is mandatory */
|
|
156
|
+
isUpdateRequired: boolean;
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Convenience Booleans
|
|
161
|
+
|
|
162
|
+
| Property | True When |
|
|
163
|
+
|----------|-----------|
|
|
164
|
+
| `isUpdateRequired` | `versionStatus.type === 'update_required'` |
|
|
165
|
+
| `isUpdateRecommended` | `versionStatus.type === 'update_recommended'` |
|
|
166
|
+
| `isUpdateAvailable` | Any of: `update_available`, `update_recommended`, `update_required` |
|
|
167
|
+
|
|
168
|
+
### Reactivity
|
|
169
|
+
|
|
170
|
+
The hook subscribes to `forceUpdate.onVersionStatusChange()` and re-renders when:
|
|
171
|
+
- Version check completes
|
|
172
|
+
- Status changes (e.g., from up_to_date to update_required)
|
|
173
|
+
- App foregrounds (triggers new check)
|
|
174
|
+
|
|
175
|
+
---
|
|
176
|
+
|
|
177
|
+
## Usage Patterns
|
|
178
|
+
|
|
179
|
+
### Conditional Rendering
|
|
180
|
+
|
|
181
|
+
```tsx
|
|
182
|
+
function RootLayout() {
|
|
183
|
+
const session = useSession();
|
|
184
|
+
const { isUpdateRequired } = useForceUpdate();
|
|
185
|
+
|
|
186
|
+
if (isUpdateRequired) {
|
|
187
|
+
return <ForceUpdateScreen />;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (!session) {
|
|
191
|
+
return <AuthStack />;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return <MainStack />;
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Loading States
|
|
199
|
+
|
|
200
|
+
```tsx
|
|
201
|
+
function App() {
|
|
202
|
+
const session = useSession();
|
|
203
|
+
const { versionStatus } = useForceUpdate();
|
|
204
|
+
|
|
205
|
+
// SDK is initializing
|
|
206
|
+
if (versionStatus.type === 'initializing') {
|
|
207
|
+
return <SplashScreen />;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Checking version
|
|
211
|
+
if (versionStatus.type === 'checking') {
|
|
212
|
+
return <LoadingScreen message="Checking for updates..." />;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return <MainApp />;
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### Accessing Core Methods
|
|
220
|
+
|
|
221
|
+
```tsx
|
|
222
|
+
function LogoutButton() {
|
|
223
|
+
const { core } = useTeardown();
|
|
224
|
+
|
|
225
|
+
const handleLogout = () => {
|
|
226
|
+
core.identity.reset();
|
|
227
|
+
// Session will become null, useSession will re-render
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
return <Button onPress={handleLogout} title="Logout" />;
|
|
231
|
+
}
|
|
232
|
+
```
|