@userflow-tech/react-native 0.4.1 → 0.4.3
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 +83 -80
- package/docs/anchoring.md +0 -1
- package/docs/deep-linking.md +0 -17
- package/docs/troubleshooting.md +14 -16
- package/lib/commonjs/version.js +1 -1
- package/lib/module/version.js +1 -1
- package/lib/typescript/commonjs/src/version.d.ts +1 -1
- package/lib/typescript/module/src/version.d.ts +1 -1
- package/package.json +1 -1
- package/src/version.ts +1 -1
- package/vendor/core/dist/constants.d.ts +0 -4
- package/vendor/core/dist/constants.d.ts.map +1 -1
- package/vendor/core/dist/constants.js +0 -4
- package/vendor/core/dist/constants.js.map +1 -1
- package/vendor/core/package.json +1 -1
- package/vendor/protocol/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Userflow React Native SDK
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
modals, and banners authored in the Userflow dashboard — without shipping a new
|
|
5
|
-
app release for every content change.
|
|
3
|
+
> ⚠️ This SDK is under active development and evolving quickly.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
Release notes are tracked in the [Userflow React Native SDK Guide](https://app.notion.com/p/Userflow-React-Native-SDK-Guide-3fba9809ce89800682c3ea9078b0f210?source=copy_link).
|
|
6
|
+
|
|
7
|
+
`@userflow-tech/react-native` is the official Userflow SDK for React Native and
|
|
8
|
+
Expo. Deliver guided flows, tooltips, modals, and banners authored in the
|
|
9
|
+
Userflow dashboard — without shipping a new app release for every content
|
|
10
|
+
change.
|
|
11
|
+
|
|
12
|
+
The SDK connects to the Userflow backend using the same protocol as
|
|
13
|
+
userflow.js, so flows built in the Userflow dashboard work across web and
|
|
14
|
+
mobile from a single place.
|
|
8
15
|
|
|
9
16
|
## Requirements
|
|
10
17
|
|
|
@@ -116,22 +123,10 @@ npx expo install react-native-safe-area-context @react-native-community/netinfo
|
|
|
116
123
|
|
|
117
124
|
### Install with an AI agent
|
|
118
125
|
|
|
119
|
-
Cursor, Claude Code, and other agents
|
|
120
|
-
|
|
126
|
+
An Agent Skill that installs this SDK in Cursor, Claude Code, and other agents
|
|
127
|
+
will be available soon. It will be `install-react-native-with-ai` in
|
|
121
128
|
[userflow/ai-skills-library](https://github.com/userflow/ai-skills-library).
|
|
122
|
-
Web apps use `install-with-ai` from that library
|
|
123
|
-
|
|
124
|
-
```bash
|
|
125
|
-
npx skills add userflow/ai-skills-library@install-react-native-with-ai
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
Claude Code loads it from the plugin:
|
|
129
|
-
|
|
130
|
-
```text
|
|
131
|
-
/plugin marketplace add userflow/ai-skills-library
|
|
132
|
-
/plugin install userflow@ai-skills-library
|
|
133
|
-
/userflow:install-react-native-with-ai
|
|
134
|
-
```
|
|
129
|
+
Web apps will use `install-with-ai` from that library.
|
|
135
130
|
|
|
136
131
|
## Quick start
|
|
137
132
|
|
|
@@ -140,8 +135,6 @@ import { Userflow, UserflowProvider } from '@userflow-tech/react-native';
|
|
|
140
135
|
|
|
141
136
|
await Userflow.init({
|
|
142
137
|
clientToken: 'ct_...', // from Settings → Environments in the Userflow dashboard. Never an esk_ secret key.
|
|
143
|
-
// serverEndpoint: 'https://e.userflow.com', // default (US). EU: 'https://e.eu.userflow.com'
|
|
144
|
-
// pairingEndpoint: 'https://e.userflow.com', // default; pairing stays on the US host
|
|
145
138
|
});
|
|
146
139
|
|
|
147
140
|
// Identified user — signature is computed by YOUR backend, never in the app.
|
|
@@ -160,32 +153,31 @@ the app to change those.
|
|
|
160
153
|
|
|
161
154
|
### `init` options
|
|
162
155
|
|
|
163
|
-
| Option
|
|
164
|
-
|
|
|
165
|
-
| `clientToken`
|
|
166
|
-
| `
|
|
167
|
-
| `
|
|
168
|
-
| `
|
|
169
|
-
| `appVersion` | Read from the native app | Override the host app version sent as `app_version`. |
|
|
170
|
-
| `appBuild` | Read from the native app | Build number sent as `app_build`, paired with `appVersion`. |
|
|
156
|
+
| Option | Default | Description |
|
|
157
|
+
| ------------- | ------------------------ | ------------------------------------------------------------------------------------------------------------ |
|
|
158
|
+
| `clientToken` | — | **Required.** The `ct_…` client token from Settings → Environments. |
|
|
159
|
+
| `onNavigate` | — | Handler for flow NAVIGATE actions. Wins over React Navigation, Expo Router, and Linking. See NAVIGATE below. |
|
|
160
|
+
| `appVersion` | Read from the native app | Override the host app version sent as `app_version`. |
|
|
161
|
+
| `appBuild` | Read from the native app | Build number sent as `app_build`, paired with `appVersion`. |
|
|
171
162
|
|
|
172
163
|
### Where to put `init`, `identify`, and `UserflowProvider`
|
|
173
164
|
|
|
174
165
|
Call `Userflow.init` once, as early as you can, from the root component
|
|
175
166
|
(`app/_layout.tsx` with Expo Router, `App.tsx` with bare React Native or React
|
|
176
167
|
Navigation). `UserflowProvider` can mount before that promise resolves. Put it
|
|
177
|
-
once, near the top of the tree, inside `SafeAreaProvider`.
|
|
168
|
+
once, near the top of the tree, inside `SafeAreaProvider`. Expo Router already
|
|
169
|
+
renders `SafeAreaProvider` above the root layout. React Navigation and bare
|
|
170
|
+
apps wrap the tree in `SafeAreaProvider` themselves. Call `identify` after
|
|
178
171
|
sign-in. `identifyAnonymous` identifies signed-out users and counts them toward
|
|
179
172
|
MAU, so use it only when you mean to. Call `Userflow.reset()` on logout.
|
|
180
173
|
|
|
181
|
-
Expo Router:
|
|
174
|
+
Expo Router already renders `SafeAreaProvider` above the root layout:
|
|
182
175
|
|
|
183
176
|
```tsx
|
|
184
177
|
import { useEffect } from 'react';
|
|
185
178
|
import { Userflow, UserflowProvider } from '@userflow-tech/react-native';
|
|
186
179
|
import { UserflowExpoRouterScreenTracker } from '@userflow-tech/react-native/expo-router';
|
|
187
180
|
import { Stack } from 'expo-router';
|
|
188
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
189
181
|
|
|
190
182
|
export default function RootLayout() {
|
|
191
183
|
useEffect(() => {
|
|
@@ -193,12 +185,10 @@ export default function RootLayout() {
|
|
|
193
185
|
}, []);
|
|
194
186
|
|
|
195
187
|
return (
|
|
196
|
-
<
|
|
197
|
-
<
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
</UserflowProvider>
|
|
201
|
-
</SafeAreaProvider>
|
|
188
|
+
<UserflowProvider>
|
|
189
|
+
<UserflowExpoRouterScreenTracker />
|
|
190
|
+
<Stack />
|
|
191
|
+
</UserflowProvider>
|
|
202
192
|
);
|
|
203
193
|
}
|
|
204
194
|
```
|
|
@@ -255,8 +245,7 @@ Other rules:
|
|
|
255
245
|
that init is in flight or has succeeded logs
|
|
256
246
|
`[Userflow] Userflow.init() already ran with different options. The new clientToken, serverEndpoint, and pairingEndpoint are ignored because init runs once per process. Userflow.reset() does not apply new credentials. Restart the app to change them.`
|
|
257
247
|
Restart the app to change them after a successful init. If `init` rejects
|
|
258
|
-
(wrong token,
|
|
259
|
-
options; that retry runs. `Userflow.reset()` clears the signed-in user;
|
|
248
|
+
(wrong token), call it again with the corrected options; that retry runs. `Userflow.reset()` clears the signed-in user;
|
|
260
249
|
it does not apply new credentials.
|
|
261
250
|
- `identify()` with a **different** user id resets the previous identity first.
|
|
262
251
|
Same-id re-identify merges attributes.
|
|
@@ -311,22 +300,20 @@ re-fires the current screen.
|
|
|
311
300
|
|
|
312
301
|
Mount `UserflowExpoRouterScreenTracker` from the `@userflow-tech/react-native/expo-router`
|
|
313
302
|
subpath under `UserflowProvider` (the tracker is a separate entry so apps without
|
|
314
|
-
`expo-router` are not forced to install that peer)
|
|
303
|
+
`expo-router` are not forced to install that peer). Expo Router already renders
|
|
304
|
+
`SafeAreaProvider` above the root layout:
|
|
315
305
|
|
|
316
306
|
```tsx
|
|
317
307
|
import { UserflowProvider } from '@userflow-tech/react-native';
|
|
318
308
|
import { UserflowExpoRouterScreenTracker } from '@userflow-tech/react-native/expo-router';
|
|
319
309
|
import { Stack } from 'expo-router';
|
|
320
|
-
import { SafeAreaProvider } from 'react-native-safe-area-context';
|
|
321
310
|
|
|
322
311
|
export default function RootLayout() {
|
|
323
312
|
return (
|
|
324
|
-
<
|
|
325
|
-
<
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
</UserflowProvider>
|
|
329
|
-
</SafeAreaProvider>
|
|
313
|
+
<UserflowProvider>
|
|
314
|
+
<UserflowExpoRouterScreenTracker />
|
|
315
|
+
<Stack />
|
|
316
|
+
</UserflowProvider>
|
|
330
317
|
);
|
|
331
318
|
}
|
|
332
319
|
```
|
|
@@ -404,8 +391,7 @@ To preview draft flows from the Userflow builder onto a device (QR / deep link):
|
|
|
404
391
|
`userflow-v7twv2fw2ja2jaco7kesvowmem` — **not** the env UUID) with the
|
|
405
392
|
`@userflow-tech/react-native` config plugin, then **rebuild native**
|
|
406
393
|
(`npx expo prebuild` / a new development client). Metro reload is not enough.
|
|
407
|
-
2. Call `Userflow.init`
|
|
408
|
-
for staging or local stacks) and wrap the tree in `UserflowProvider`.
|
|
394
|
+
2. Call `Userflow.init` and wrap the tree in `UserflowProvider`.
|
|
409
395
|
3. Open the builder Preview dialog → **Pair a device** → scan/open the QR. The
|
|
410
396
|
app should show a **Preview mode** top bar.
|
|
411
397
|
4. Hit **Preview** in the builder. The draft flow lands on that paired device.
|
|
@@ -420,14 +406,11 @@ To preview draft flows from the Userflow builder onto a device (QR / deep link):
|
|
|
420
406
|
}
|
|
421
407
|
```
|
|
422
408
|
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
// pairingEndpoint: 'http://localhost:40401',
|
|
429
|
-
});
|
|
430
|
-
```
|
|
409
|
+
`schemeId` is the env's `scheme_id` from the dashboard, copied exactly. It is
|
|
410
|
+
`userflow-` followed by an opaque id. Do not rely on its shape. Preview links
|
|
411
|
+
(`…://?token=…`) and pairing links (`…://?pairing_token=…`) both ride that one
|
|
412
|
+
scheme. Expo Router needs no extra host files for these root-form URLs, and
|
|
413
|
+
pairing works in every build, including release.
|
|
431
414
|
|
|
432
415
|
Deep-link / pairing helpers:
|
|
433
416
|
|
|
@@ -444,7 +427,20 @@ Full scheme registration, Linking ownership, and verify commands:
|
|
|
444
427
|
|
|
445
428
|
## Connection resilience
|
|
446
429
|
|
|
447
|
-
|
|
430
|
+
After `Userflow.init`, the SDK suspends the socket when the app leaves the
|
|
431
|
+
foreground (after a short grace window) and resumes on return:
|
|
432
|
+
|
|
433
|
+
| Away duration | Behavior |
|
|
434
|
+
| --------------------- | ---------------------------------------------------- |
|
|
435
|
+
| < 3 seconds | No suspend/resume (transient blur / quick switch) |
|
|
436
|
+
| 3 seconds – 5 minutes | Reconnect and **keep** the mid-flow session |
|
|
437
|
+
| ≥ 5 minutes | **Clear** the local mid-flow session, then reconnect |
|
|
438
|
+
|
|
439
|
+
Foreground idle for 5 minutes also suspends (skipped while any mid-flow session
|
|
440
|
+
is active).
|
|
441
|
+
|
|
442
|
+
Recovery from a dropped or silently-dead socket works out of the box, with no
|
|
443
|
+
extra dependencies or host setup:
|
|
448
444
|
|
|
449
445
|
1. Reconnect ladder on socket `close` / `error`
|
|
450
446
|
2. Adaptive heartbeat with a short reply deadline
|
|
@@ -533,15 +529,6 @@ and forwards URLs itself.
|
|
|
533
529
|
| `@userflow-tech/react-native/navigation` | `WithUserflowReactNavigation` |
|
|
534
530
|
| `@userflow-tech/react-native/expo-router` | `UserflowExpoRouterScreenTracker`, `useUserflowExpoRouter`, `redirectSystemPath` (for `+native-intent`) |
|
|
535
531
|
|
|
536
|
-
### Constants
|
|
537
|
-
|
|
538
|
-
| Export | Meaning |
|
|
539
|
-
| ----------------------------------- | ---------------------------------------------------------------- |
|
|
540
|
-
| `SDK_VERSION` | Package version string injected at build time. |
|
|
541
|
-
| `SUSPEND_GRACE_MS` | Grace window before background suspend (3s). |
|
|
542
|
-
| `SESSION_STALE_AFTER_BACKGROUND_MS` | Clear mid-flow session after this long away (5 min). |
|
|
543
|
-
| `INACTIVITY_TIMEOUT_MS` | Foreground idle suspend (5 min; skipped while a flow is active). |
|
|
544
|
-
|
|
545
532
|
## Guides in this package
|
|
546
533
|
|
|
547
534
|
These guides also ship in the package, under
|
|
@@ -555,16 +542,38 @@ These guides also ship in the package, under
|
|
|
555
542
|
| [docs/identity-verification.md](https://unpkg.com/@userflow-tech/react-native/docs/identity-verification.md) | HMAC signature on your backend |
|
|
556
543
|
| [docs/troubleshooting.md](https://unpkg.com/@userflow-tech/react-native/docs/troubleshooting.md) | Symptom → cause for common integration failures |
|
|
557
544
|
|
|
558
|
-
##
|
|
545
|
+
## Current status
|
|
546
|
+
|
|
547
|
+
### Shipped
|
|
548
|
+
|
|
549
|
+
- Flow rendering — tooltips and modals
|
|
550
|
+
- Manual element targeting (`userflowId` / `testID` / `nativeID`, or `useUserflowAnchor`)
|
|
551
|
+
- Screen tracking — Expo Router (`UserflowExpoRouterScreenTracker`) and React
|
|
552
|
+
Navigation (`WithUserflowReactNavigation`); must be mounted by the host
|
|
553
|
+
- User & group attributes (`identify`, `identifyAnonymous`, `group`) and custom events (`track`)
|
|
554
|
+
- Embed banners (overlay and inline `EmbedBannerPlaceholder`)
|
|
555
|
+
- Client conditions — `ELEMENT` PRESENT / NOT_PRESENT on manual anchors and
|
|
556
|
+
AUTO selectors (guarded: weak evidence stays unknown)
|
|
557
|
+
- Connection lifecycle — suspend/resume, reconnect, optional NetInfo
|
|
558
|
+
|
|
559
|
+
### Experimental
|
|
559
560
|
|
|
560
561
|
- AUTO / codeless element targeting (exact-id fast path + scored matcher;
|
|
561
562
|
scored path needs Babel full mode to populate the auto-anchor registry).
|
|
562
563
|
See [docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md).
|
|
563
|
-
- Build-time stamping with `@userflow-tech/react-native/babel-plugin
|
|
564
|
+
- Build-time stamping with `@userflow-tech/react-native/babel-plugin`
|
|
565
|
+
(`stampOnly: true` stamps `nativeID` only; full mode is the default). Jest
|
|
564
566
|
runs the plugin too, which changes snapshots. Read
|
|
565
567
|
[Babel plugin and snapshot tests](#babel-plugin-and-snapshot-tests) before
|
|
566
568
|
enabling it.
|
|
567
569
|
|
|
570
|
+
### Not available yet
|
|
571
|
+
|
|
572
|
+
- `INPUT_VALUE` / `FILLED_IN_INPUT` client conditions
|
|
573
|
+
|
|
574
|
+
Flows gated on unsupported client conditions stay unknown and **never start**.
|
|
575
|
+
See [docs/troubleshooting.md](https://unpkg.com/@userflow-tech/react-native/docs/troubleshooting.md).
|
|
576
|
+
|
|
568
577
|
## Install diagnostics
|
|
569
578
|
|
|
570
579
|
In development, the first `Userflow.init` checks native module registration and
|
|
@@ -597,10 +606,6 @@ Passing an environment secret key as `clientToken` throws:
|
|
|
597
606
|
clientToken is an environment secret key (esk_...). That key must never ship in the app. Pass the client token (ct_...) from Settings → Environments instead.
|
|
598
607
|
```
|
|
599
608
|
|
|
600
|
-
When the default US endpoint rejects the token with `invalid_client_token`, the
|
|
601
|
-
error also says: `For EU-hosted environments pass serverEndpoint: 'https://e.eu.userflow.com'.`
|
|
602
|
-
Pairing stays on `https://e.userflow.com`.
|
|
603
|
-
|
|
604
609
|
`expo prebuild` warns when the config plugin has no `schemeId`, when
|
|
605
610
|
`react-native-view-shot` is missing or older than 5, and (on Expo SDK 53 and
|
|
606
611
|
older) when AsyncStorage, WebView, or safe-area-context is not a direct
|
|
@@ -710,9 +715,7 @@ instead. Snapshots then gain only `nativeID` and `collapsable`, and stamped file
|
|
|
710
715
|
skip the SDK import. The plugin's `exclude` option does not help here: it skips
|
|
711
716
|
the files it lists, not the components a test renders.
|
|
712
717
|
|
|
713
|
-
##
|
|
714
|
-
|
|
715
|
-
- `INPUT_VALUE` / `FILLED_IN_INPUT` client conditions
|
|
718
|
+
## Related
|
|
716
719
|
|
|
717
|
-
|
|
718
|
-
|
|
720
|
+
- [Userflow](https://userflow.com)
|
|
721
|
+
- [userflow.js](https://github.com/userflow/userflow.js) — Web SDK
|
package/docs/anchoring.md
CHANGED
package/docs/deep-linking.md
CHANGED
|
@@ -147,9 +147,6 @@ Rebuild the native app after changing these files.
|
|
|
147
147
|
```ts
|
|
148
148
|
await Userflow.init({
|
|
149
149
|
clientToken: 'ct_...',
|
|
150
|
-
// Defaults to production. Override for staging / local stacks:
|
|
151
|
-
// serverEndpoint: 'http://localhost:40401',
|
|
152
|
-
// pairingEndpoint: 'http://localhost:40401',
|
|
153
150
|
});
|
|
154
151
|
await Userflow.identify(userId); // or identifyAnonymous()
|
|
155
152
|
```
|
|
@@ -293,19 +290,5 @@ conditions to match, so nothing appears until they do — the top bar reads
|
|
|
293
290
|
**Waiting for auto-start condition…** meanwhile. A flow that never
|
|
294
291
|
shows up in that mode points at the condition, not at pairing.
|
|
295
292
|
|
|
296
|
-
## Local / staging endpoints
|
|
297
|
-
|
|
298
|
-
Defaults target production (`https://e.userflow.com` for the end-user socket;
|
|
299
|
-
pairing defaults to the US-pinned production host). When pointing at a local or
|
|
300
|
-
staging stack, set both:
|
|
301
|
-
|
|
302
|
-
```ts
|
|
303
|
-
await Userflow.init({
|
|
304
|
-
clientToken: 'ct_...',
|
|
305
|
-
serverEndpoint: 'http://localhost:40401',
|
|
306
|
-
pairingEndpoint: 'http://localhost:40401',
|
|
307
|
-
});
|
|
308
|
-
```
|
|
309
|
-
|
|
310
293
|
See [troubleshooting.md](troubleshooting.md#builder-preview--pairing) for common
|
|
311
294
|
pairing failures.
|
package/docs/troubleshooting.md
CHANGED
|
@@ -29,7 +29,6 @@ Messages are quoted exactly so you can search logs for them.
|
|
|
29
29
|
| `[Userflow] UserflowProvider is not inside a <SafeAreaProvider>, so flow cards use the device's initial safe-area insets. Wrap your app in <SafeAreaProvider> from react-native-safe-area-context.` | `UserflowProvider` has no `SafeAreaProvider` ancestor. The app does not crash. Cards use `initialWindowMetrics`, or zero insets when those are unavailable. | Wrap the tree in `SafeAreaProvider`. |
|
|
30
30
|
| `Userflow.identifyAnonymous() needs @react-native-async-storage/async-storage, which is not linked in this native build. Add it to your app's package.json, run pod install, and rebuild.` | `identifyAnonymous()` ran without a linked AsyncStorage native module. | Install and rebuild, then call it again. |
|
|
31
31
|
| `clientToken is an environment secret key (esk_...). That key must never ship in the app. Pass the client token (ct_...) from Settings → Environments instead.` | `init` was given an `esk_` secret key. | Pass the `ct_…` client token. |
|
|
32
|
-
| `For EU-hosted environments pass serverEndpoint: 'https://e.eu.userflow.com'.` | The default US host rejected the token with `invalid_client_token`. This sentence is appended to that error. It is omitted when `serverEndpoint` was set explicitly. | For an EU environment, pass `serverEndpoint: 'https://e.eu.userflow.com'`. Pairing stays on `https://e.userflow.com`. |
|
|
33
32
|
| `[Userflow] Userflow.init() already ran with different options. The new clientToken, serverEndpoint, and pairingEndpoint are ignored because init runs once per process. Userflow.reset() does not apply new credentials. Restart the app to change them.` | A later `init` passed a different token or endpoint while a previous `init` is in flight or has succeeded. | Restart the app after a successful init. `reset()` clears the user and does not apply new credentials. If the previous `init` rejected, call `init` again with the corrected token or endpoint. |
|
|
34
33
|
|
|
35
34
|
## Init / identify / group
|
|
@@ -43,7 +42,7 @@ Messages are quoted exactly so you can search logs for them.
|
|
|
43
42
|
| `Call Userflow.identify() before updateUser()` | `updateUser` before any identify | Call `identify` or `identifyAnonymous` first |
|
|
44
43
|
| `Call Userflow.group() before updateGroup()` | `updateGroup` or a group-scoped button attribute before `group()` | Call `Userflow.group(...)` first |
|
|
45
44
|
| `Missing clientToken` | Empty / whitespace token | Pass the `ct_...` value from the dashboard |
|
|
46
|
-
| `… invalid_client_token: Invalid Userflow.js Token: …` | Wrong token
|
|
45
|
+
| `… invalid_client_token: Invalid Userflow.js Token: …` | Wrong token or deactivated env | Copy the token from the matching environment. |
|
|
47
46
|
| `… user_signature_required: …` | Env requires identity verification; no `signature` | Compute HMAC on your backend — [identity-verification.md](identity-verification.md) |
|
|
48
47
|
| `… incorrect_user_signature: …` | Signature does not match HMAC-SHA256(secret, userId) | Sign the **same** id string; use `esk_...`, not `ct_...` |
|
|
49
48
|
| `… group_signature_required` / `incorrect_group_signature` | Same rules for `group()` | Sign the group id with the env secret key |
|
|
@@ -104,7 +103,7 @@ Id matching: dashboard `#invite-teammates` ↔ `userflowId="invite-teammates"`,
|
|
|
104
103
|
|
|
105
104
|
| Symptom | Likely cause |
|
|
106
105
|
| --------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
107
|
-
| `WebSocket connection timed out` / `failed` |
|
|
106
|
+
| `WebSocket connection timed out` / `failed` | Network or VPN |
|
|
108
107
|
| `invalid_message` on channel join / `UpdateClientContext` | ClientContext missing required `pageUrl`, or sending `screenPath` / legacy `path`/`screen`. The SDK must send `pageUrl: ""` plus `screenName` only |
|
|
109
108
|
| Long recovery after Wi-Fi ↔ cellular while foregrounded | Install optional `@react-native-community/netinfo` for instant probe |
|
|
110
109
|
| Session cleared after returning from background | Away ≥ `SESSION_STALE_AFTER_BACKGROUND_MS` (5 minutes) — by design |
|
|
@@ -113,19 +112,18 @@ Id matching: dashboard `#invite-teammates` ↔ `userflowId="invite-teammates"`,
|
|
|
113
112
|
|
|
114
113
|
Full setup: [deep-linking.md](deep-linking.md). Pairing is available in all builds (including release).
|
|
115
114
|
|
|
116
|
-
| Symptom | Likely cause | Fix
|
|
117
|
-
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
118
|
-
| Deep link opens the app but nothing happens | Scheme added in config but **no native rebuild** | `npx expo prebuild` / new development client; Metro reload is not enough
|
|
119
|
-
| Deep link opens the app but nothing happens, and no **Preview mode** top bar appears | `Userflow.init()` rejected, so there is no session to preview into | Check the logs for `[Userflow] Builder pairing link received, but Userflow.init() failed` — fix that error (usually `clientToken`
|
|
120
|
-
| Killed app opens from a pairing link with no banner, or Preview returns on the wrong step | Pairing did not resume, or the install joined as a new device while the old presence was still on the topic | Install `expo-secure-store` so a relaunch can resume. A cold start should show **Connecting to Builder…** immediately, then **Preview mode**, with the flow at step 1. `exitPreview()` or an expired token ends resume
|
|
121
|
-
| Deep link opens the app and the router shows **Unmatched Route** / "page could not be found" | Deep link is not the root form from the QR; **or** the link was rebuilt with the app's own scheme instead of `scheme_id` | Open the QR unmodified (`userflow-<id>://?pairing_token=…`). If the log says `a scheme Userflow does not own`, do not substitute your app scheme
|
|
122
|
-
| "Can't select this element" right after pairing, or the app jumps to home when pairing | Expo Router navigated on the pairing link | Add `app/+native-intent.ts` exporting `redirectSystemPath` from `@userflow-tech/react-native/expo-router` (see [deep-linking.md](deep-linking.md#expo-router-hosts))
|
|
123
|
-
| Pairing deep link ignored (preview URL may still work) | Scheme is `userflow-*` but the id after it is empty or has stray hyphens | Use the env's `scheme_id` from the dashboard exactly (e.g. `userflow-v7twv2fw2ja2jaco7kesvowmem`), not the env UUID
|
|
124
|
-
| Builder says “A device was paired earlier…” and Preview closes immediately after a brief spinner | Stale pairing session still present; a ghost device acks | Pair again on the device you are watching, or clear the env's pairing session and re-QR
|
|
125
|
-
| Preview succeeds on the server but the phone stays idle | App is not the paired instance (no **Preview mode** top bar) | Confirm the top bar before hitting Preview; re-open the pairing QR on this install
|
|
126
|
-
|
|
|
127
|
-
|
|
|
128
|
-
| Builder selector has no screenshot after Confirm | Missing / unlinked `react-native-view-shot`, or Expo SDK 54 pinned 4.x | Install `react-native-view-shot@^5.0.0` and **rebuild native**. Look for `[Userflow] Required peer react-native-view-shot is not installed` |
|
|
115
|
+
| Symptom | Likely cause | Fix |
|
|
116
|
+
| ------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
117
|
+
| Deep link opens the app but nothing happens | Scheme added in config but **no native rebuild** | `npx expo prebuild` / new development client; Metro reload is not enough |
|
|
118
|
+
| Deep link opens the app but nothing happens, and no **Preview mode** top bar appears | `Userflow.init()` rejected, so there is no session to preview into | Check the logs for `[Userflow] Builder pairing link received, but Userflow.init() failed` — fix that error (usually `clientToken`) and re-open the link |
|
|
119
|
+
| Killed app opens from a pairing link with no banner, or Preview returns on the wrong step | Pairing did not resume, or the install joined as a new device while the old presence was still on the topic | Install `expo-secure-store` so a relaunch can resume. A cold start should show **Connecting to Builder…** immediately, then **Preview mode**, with the flow at step 1. `exitPreview()` or an expired token ends resume |
|
|
120
|
+
| Deep link opens the app and the router shows **Unmatched Route** / "page could not be found" | Deep link is not the root form from the QR; **or** the link was rebuilt with the app's own scheme instead of `scheme_id` | Open the QR unmodified (`userflow-<id>://?pairing_token=…`). If the log says `a scheme Userflow does not own`, do not substitute your app scheme |
|
|
121
|
+
| "Can't select this element" right after pairing, or the app jumps to home when pairing | Expo Router navigated on the pairing link | Add `app/+native-intent.ts` exporting `redirectSystemPath` from `@userflow-tech/react-native/expo-router` (see [deep-linking.md](deep-linking.md#expo-router-hosts)) |
|
|
122
|
+
| Pairing deep link ignored (preview URL may still work) | Scheme is `userflow-*` but the id after it is empty or has stray hyphens | Use the env's `scheme_id` from the dashboard exactly (e.g. `userflow-v7twv2fw2ja2jaco7kesvowmem`), not the env UUID |
|
|
123
|
+
| Builder says “A device was paired earlier…” and Preview closes immediately after a brief spinner | Stale pairing session still present; a ghost device acks | Pair again on the device you are watching, or clear the env's pairing session and re-QR |
|
|
124
|
+
| Preview succeeds on the server but the phone stays idle | App is not the paired instance (no **Preview mode** top bar) | Confirm the top bar before hitting Preview; re-open the pairing QR on this install |
|
|
125
|
+
| QR / `https://…/pair/<jwt>` does nothing in the app | SDK only parses the **scheme** form after the backend redirect | Open via the OS (scan QR) or forward `{schemeId}://?pairing_token=…` with `handlePairingUrl` |
|
|
126
|
+
| Builder selector has no screenshot after Confirm | Missing / unlinked `react-native-view-shot`, or Expo SDK 54 pinned 4.x | Install `react-native-view-shot@^5.0.0` and **rebuild native**. At init, look for `- react-native-view-shot is not linked, so Builder element selection gets no screenshot`. When confirming a pick, look for `[Userflow] Required peer react-native-view-shot is not installed; skipping picker screenshot.` |
|
|
129
127
|
|
|
130
128
|
## Expo
|
|
131
129
|
|
package/lib/commonjs/version.js
CHANGED
|
@@ -5,5 +5,5 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
5
5
|
});
|
|
6
6
|
exports.SDK_VERSION = void 0;
|
|
7
7
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
8
|
-
const SDK_VERSION = exports.SDK_VERSION = '0.4.
|
|
8
|
+
const SDK_VERSION = exports.SDK_VERSION = '0.4.3';
|
|
9
9
|
//# sourceMappingURL=version.js.map
|
package/lib/module/version.js
CHANGED
package/package.json
CHANGED
package/src/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** Generated by scripts/write-version.mjs — do not edit. */
|
|
2
|
-
export const SDK_VERSION = '0.4.
|
|
2
|
+
export const SDK_VERSION = '0.4.3';
|
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
*
|
|
5
5
|
* For local development against the Userflow dev stack, pass the local endpoint
|
|
6
6
|
* explicitly, e.g. `init({ ..., serverEndpoint: 'http://localhost:40401' })`.
|
|
7
|
-
*
|
|
8
|
-
* TODO(publish): production server-driven `Publish` delivery for mobile is not
|
|
9
|
-
* wired yet (only the Preview/dev-device path is validated). Revisit this
|
|
10
|
-
* default and the transport once Publish lands.
|
|
11
7
|
*/
|
|
12
8
|
export declare const DEFAULT_SERVER_ENDPOINT = "https://e.userflow.com";
|
|
13
9
|
/** End-user socket for EU-hosted environments. Pairing stays on the US host. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,eAAO,MAAM,uBAAuB,2BAA2B,CAAC;AAEhE,gFAAgF;AAChF,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAE9D;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,2BAA2B,CAAC"}
|
|
@@ -4,10 +4,6 @@
|
|
|
4
4
|
*
|
|
5
5
|
* For local development against the Userflow dev stack, pass the local endpoint
|
|
6
6
|
* explicitly, e.g. `init({ ..., serverEndpoint: 'http://localhost:40401' })`.
|
|
7
|
-
*
|
|
8
|
-
* TODO(publish): production server-driven `Publish` delivery for mobile is not
|
|
9
|
-
* wired yet (only the Preview/dev-device path is validated). Revisit this
|
|
10
|
-
* default and the transport once Publish lands.
|
|
11
7
|
*/
|
|
12
8
|
export const DEFAULT_SERVER_ENDPOINT = 'https://e.userflow.com';
|
|
13
9
|
/** End-user socket for EU-hosted environments. Pairing stays on the US host. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,uBAAuB,GAAG,wBAAwB,CAAC;AAEhE,gFAAgF;AAChF,MAAM,CAAC,MAAM,kBAAkB,GAAG,2BAA2B,CAAC;AAE9D;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,wBAAwB,GAAG,wBAAwB,CAAC"}
|
package/vendor/core/package.json
CHANGED