@teardown/react-native 2.0.24 → 2.0.28

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 (59) hide show
  1. package/docs/adapters/device/basic.mdx +59 -0
  2. package/docs/adapters/device/device-info.mdx +76 -0
  3. package/docs/adapters/device/expo.mdx +61 -0
  4. package/docs/adapters/device/index.mdx +102 -0
  5. package/docs/adapters/device/meta.json +4 -0
  6. package/docs/adapters/index.mdx +96 -0
  7. package/docs/adapters/meta.json +4 -0
  8. package/docs/adapters/notifications/expo.mdx +127 -0
  9. package/docs/adapters/notifications/firebase.mdx +142 -0
  10. package/docs/adapters/notifications/index.mdx +100 -0
  11. package/docs/adapters/notifications/meta.json +4 -0
  12. package/docs/adapters/notifications/wix.mdx +140 -0
  13. package/docs/adapters/storage/async-storage.mdx +95 -0
  14. package/docs/adapters/storage/index.mdx +93 -0
  15. package/docs/adapters/storage/meta.json +4 -0
  16. package/docs/adapters/storage/mmkv.mdx +86 -0
  17. package/docs/advanced.mdx +280 -0
  18. package/docs/api-reference.mdx +241 -0
  19. package/docs/core-concepts.mdx +158 -0
  20. package/docs/force-updates.mdx +185 -0
  21. package/docs/getting-started.mdx +156 -0
  22. package/docs/hooks-reference.mdx +232 -0
  23. package/docs/identity.mdx +171 -0
  24. package/docs/index.mdx +61 -0
  25. package/docs/logging.mdx +144 -0
  26. package/docs/meta.json +14 -0
  27. package/package.json +49 -31
  28. package/src/clients/api/index.ts +1 -1
  29. package/src/clients/device/adapters/basic.adapter.ts +57 -66
  30. package/src/clients/device/adapters/device-info.adapter.ts +21 -28
  31. package/src/clients/device/adapters/device.adpater-interface.ts +1 -8
  32. package/src/clients/device/adapters/expo.adapter.ts +33 -40
  33. package/src/clients/device/device.client.test.ts +20 -35
  34. package/src/clients/device/device.client.ts +0 -3
  35. package/src/clients/identity/identity.client.test.ts +8 -8
  36. package/src/clients/identity/identity.client.ts +1 -1
  37. package/src/clients/identity/index.ts +1 -1
  38. package/src/clients/logging/index.ts +1 -1
  39. package/src/clients/notifications/adapters/expo-notifications.adapter.ts +105 -0
  40. package/src/clients/notifications/adapters/firebase-messaging.adapter.ts +87 -0
  41. package/src/clients/notifications/adapters/notifications.adapter-interface.ts +112 -0
  42. package/src/clients/notifications/adapters/wix-notifications.adapter.ts +183 -0
  43. package/src/clients/notifications/index.ts +2 -0
  44. package/src/clients/notifications/notifications.client.ts +214 -3
  45. package/src/clients/storage/adapters/async-storage.adapter.ts +2 -6
  46. package/src/clients/storage/adapters/storage-adapters.test.ts +2 -7
  47. package/src/clients/storage/adapters/storage.adpater-interface.ts +1 -5
  48. package/src/clients/utils/index.ts +1 -1
  49. package/src/clients/utils/utils.client.ts +1 -1
  50. package/src/exports/adapters/async-storage.ts +1 -1
  51. package/src/exports/adapters/expo.ts +1 -1
  52. package/src/exports/expo.ts +2 -0
  53. package/src/exports/firebase.ts +1 -0
  54. package/src/exports/index.ts +6 -9
  55. package/src/exports/wix.ts +1 -0
  56. package/src/hooks/use-force-update.ts +31 -34
  57. package/src/index.ts +1 -0
  58. package/src/teardown.core.ts +0 -2
  59. 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
+ ```