@userflow-tech/react-native 0.4.3 → 0.4.5

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 (52) hide show
  1. package/README.md +137 -39
  2. package/docs/deep-linking.md +26 -0
  3. package/docs/troubleshooting.md +45 -42
  4. package/expo-plugin/hostDependencyWarnings.d.ts +6 -4
  5. package/expo-plugin/hostDependencyWarnings.d.ts.map +1 -1
  6. package/expo-plugin/hostDependencyWarnings.js +8 -6
  7. package/expo-plugin/hostDependencyWarnings.js.map +1 -1
  8. package/lib/commonjs/installCheck.js +2 -2
  9. package/lib/commonjs/installCheck.js.map +1 -1
  10. package/lib/commonjs/surfaces/bannerWebView/resolveCdnHost.js +10 -16
  11. package/lib/commonjs/surfaces/bannerWebView/resolveCdnHost.js.map +1 -1
  12. package/lib/commonjs/version.js +1 -1
  13. package/lib/module/installCheck.js +2 -2
  14. package/lib/module/installCheck.js.map +1 -1
  15. package/lib/module/surfaces/bannerWebView/resolveCdnHost.js +10 -16
  16. package/lib/module/surfaces/bannerWebView/resolveCdnHost.js.map +1 -1
  17. package/lib/module/version.js +1 -1
  18. package/lib/typescript/commonjs/src/installCheck.d.ts +1 -1
  19. package/lib/typescript/commonjs/src/installCheck.d.ts.map +1 -1
  20. package/lib/typescript/commonjs/src/surfaces/bannerWebView/resolveCdnHost.d.ts +4 -2
  21. package/lib/typescript/commonjs/src/surfaces/bannerWebView/resolveCdnHost.d.ts.map +1 -1
  22. package/lib/typescript/commonjs/src/version.d.ts +1 -1
  23. package/lib/typescript/module/src/installCheck.d.ts +1 -1
  24. package/lib/typescript/module/src/installCheck.d.ts.map +1 -1
  25. package/lib/typescript/module/src/surfaces/bannerWebView/resolveCdnHost.d.ts +4 -2
  26. package/lib/typescript/module/src/surfaces/bannerWebView/resolveCdnHost.d.ts.map +1 -1
  27. package/lib/typescript/module/src/version.d.ts +1 -1
  28. package/package.json +1 -1
  29. package/src/installCheck.ts +4 -4
  30. package/src/surfaces/bannerWebView/resolveCdnHost.ts +14 -16
  31. package/src/version.ts +1 -1
  32. package/vendor/core/dist/constants.d.ts +6 -3
  33. package/vendor/core/dist/constants.d.ts.map +1 -1
  34. package/vendor/core/dist/constants.js +6 -3
  35. package/vendor/core/dist/constants.js.map +1 -1
  36. package/vendor/core/dist/engine/UserflowCore.d.ts.map +1 -1
  37. package/vendor/core/dist/engine/UserflowCore.js +4 -18
  38. package/vendor/core/dist/engine/UserflowCore.js.map +1 -1
  39. package/vendor/core/dist/index.d.ts +1 -0
  40. package/vendor/core/dist/index.d.ts.map +1 -1
  41. package/vendor/core/dist/index.js +1 -0
  42. package/vendor/core/dist/index.js.map +1 -1
  43. package/vendor/core/dist/serverEndpoint.d.ts +7 -0
  44. package/vendor/core/dist/serverEndpoint.d.ts.map +1 -0
  45. package/vendor/core/dist/serverEndpoint.js +15 -0
  46. package/vendor/core/dist/serverEndpoint.js.map +1 -0
  47. package/vendor/core/dist/types.d.ts +3 -2
  48. package/vendor/core/dist/types.d.ts.map +1 -1
  49. package/vendor/core/dist/version.d.ts +1 -1
  50. package/vendor/core/dist/version.js +1 -1
  51. package/vendor/core/package.json +1 -1
  52. package/vendor/protocol/package.json +1 -1
package/README.md CHANGED
@@ -19,7 +19,9 @@ Declared minimums: React `>=18.2.0`, React Native `>=0.76.0`. React Native
19
19
  0.74 and 0.75 cannot install this SDK: `react-native-view-shot` 5.x, which
20
20
  Builder element selection needs, requires React Native 0.76 or later. The SDK
21
21
  is tested on React Native 0.81 / React 19.1 and on Expo SDK 57 / React Native
22
- 0.86. Expo Go is not supported.
22
+ 0.86. Expo SDK 58 is not supported yet: it bundles `react-native-webview` 14
23
+ and `react-native-view-shot` 6, which are outside the peer ranges below. Expo
24
+ Go is not supported.
23
25
 
24
26
  `@react-native-async-storage/async-storage` is the only native module this
25
27
  package depends on, so npm installs it. `react-native-webview` and
@@ -73,23 +75,43 @@ needed with any package manager.
73
75
  ### Packages
74
76
 
75
77
  ```bash
76
- # Expo (dev build)
78
+ # Expo SDK 56–57 (dev build)
79
+ npx expo install @userflow-tech/react-native @react-native-async-storage/async-storage react-native-webview react-native-view-shot
80
+
81
+ # Expo SDK 55 and older (dev build): pin view-shot, see below
77
82
  npx expo install @userflow-tech/react-native @react-native-async-storage/async-storage react-native-webview react-native-view-shot@^5.0.0
78
83
 
79
84
  # Bare React Native
80
- npm install @userflow-tech/react-native @react-native-async-storage/async-storage react-native-device-info react-native-webview react-native-view-shot@^5.0.0
85
+ npm install @userflow-tech/react-native '@react-native-async-storage/async-storage@^2' 'react-native-device-info@<16' 'react-native-webview@>=13.8.0 <14' 'react-native-view-shot@^5.0.0'
81
86
  cd ios && pod install
82
87
  ```
83
88
 
89
+ Keep the version ranges in the bare command. Unpinned, npm picks the latest
90
+ majors. `react-native-webview` 14 is outside the peer range, and npm only warns
91
+ `ERESOLVE overriding peer dependency` and installs it anyway. AsyncStorage 3
92
+ sits next to the SDK's own 2.x copy, which leaves two copies of one native
93
+ module. `npx expo install` picks Expo's bundled versions, which fit the ranges
94
+ on Expo SDK 53–57, except view-shot on Expo SDK 55 and older.
95
+
84
96
  `react-native-webview` and `react-native-view-shot` (`^5.0.0`) are **required
85
97
  peers**. npm 7+ and pnpm install them. Yarn 1 and
86
98
  `npm install --legacy-peer-deps` do not, so the commands above install them in
87
99
  the app. Both are native modules — rebuild after install (a Metro reload is not
88
- enough). On Expo SDK 54,
89
- unpinned `npx expo install react-native-view-shot` resolves **4.0.3**, which
90
- does not satisfy the peer. Pin `^5.0.0` as in the command above. If the app
91
- already depends on 4.0.3, that same command is what fixes it: installing the
92
- SDK alone fails with
100
+ enough).
101
+
102
+ On Expo SDK 56 and 57, leave view-shot unpinned. Expo's default there (5.1.0)
103
+ satisfies the peer. A `^5.0.0` pin installs the newest 5.x instead, which
104
+ `expo doctor` reports as a version mismatch. To fix an app that already has the
105
+ pin, remove `"react-native-view-shot"` from `expo.install.exclude` if it is
106
+ there, then run `npx expo install react-native-view-shot`. While the exclude is
107
+ set, Expo installs the latest view-shot instead of 5.1.0, and `expo doctor`
108
+ skips the check. Installed with the SDK, npm keeps view-shot on 5.x; installed
109
+ on its own, it can pull 6.x, outside the peer range.
110
+
111
+ On Expo SDK 55 and older, unpinned `npx expo install react-native-view-shot`
112
+ resolves **4.0.3**, which does not satisfy the peer. Pin `^5.0.0` as in the
113
+ command above. If the app already depends on 4.0.3, that same command is what
114
+ fixes it: installing the SDK alone fails with
93
115
 
94
116
  ```text
95
117
  npm error Found: react-native-view-shot@4.0.3
@@ -98,8 +120,9 @@ npm error peer react-native-view-shot@"^5.0.0" from @userflow-tech/react-native
98
120
 
99
121
  Do not retry with `--force` or `--legacy-peer-deps`. That installs the SDK and
100
122
  leaves 4.0.3 in place. If that already happened, `Userflow.init` warns in
101
- development and names the installed version. If `expo doctor`
102
- reports the `^5.0.0` pin, exclude it from Expo's version check:
123
+ development and names the installed version. On Expo SDK 55 and older, also
124
+ exclude view-shot from Expo's version check. Otherwise `expo doctor` reports
125
+ the pin, and `npx expo install --fix` puts 4.0.3 back:
103
126
 
104
127
  ```json
105
128
  {
@@ -111,6 +134,10 @@ reports the `^5.0.0` pin, exclude it from Expo's version check:
111
134
  }
112
135
  ```
113
136
 
137
+ With the exclude set, always install view-shot as
138
+ `react-native-view-shot@^5.0.0`. Unpinned, Expo skips its version, so npm can
139
+ keep 4.0.3 or pull 6.x.
140
+
114
141
  On a bare React Native app, `expo-secure-store` needs Expo modules installed
115
142
  first (`npx install-expo-modules@latest`), then `npx expo install expo-secure-store`.
116
143
 
@@ -119,14 +146,41 @@ Optional peers as needed:
119
146
  ```bash
120
147
  npx expo install react-native-safe-area-context @react-native-community/netinfo expo-secure-store
121
148
  # and either expo-router or @react-navigation/native, depending on your router
149
+
150
+ # Bare React Native
151
+ npm install 'react-native-safe-area-context@<6' '@react-native-community/netinfo@<13'
122
152
  ```
123
153
 
154
+ ### Babel plugin
155
+
156
+ Add `@userflow-tech/react-native/babel-plugin` to `babel.config.js`. It stamps
157
+ `View`, `Text`, `Pressable`, the Touchables, `TextInput`, and `Image` at build
158
+ time, so elements can be targeted without a `testID`. An Expo app without a
159
+ `babel.config.js` can create one with `npx expo customize babel.config.js`.
160
+
161
+ ```js
162
+ // babel.config.js
163
+ module.exports = function (api) {
164
+ api.cache(true);
165
+ return {
166
+ presets: ['babel-preset-expo'], // or the app's existing preset
167
+ plugins: ['@userflow-tech/react-native/babel-plugin'],
168
+ };
169
+ };
170
+ ```
171
+
172
+ Keep the app's own plugins. If it lists `react-native-reanimated/plugin` or
173
+ `react-native-worklets/plugin`, keep that one last. Start Metro once with a
174
+ cleared cache (`npx expo start -c`) so every file is stamped. Apps with Jest
175
+ should read [Babel plugin and snapshot tests](#babel-plugin-and-snapshot-tests).
176
+
124
177
  ### Install with an AI agent
125
178
 
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
128
- [userflow/ai-skills-library](https://github.com/userflow/ai-skills-library).
129
- Web apps will use `install-with-ai` from that library.
179
+ The `install-userflow-react-native-sdk-with-ai` Agent Skill installs this SDK
180
+ with Cursor, Claude Code, and other agents. It is in
181
+ [userflow/ai-skills-library](https://github.com/userflow/ai-skills-library),
182
+ whose README explains how to add it to your agent. Web apps use
183
+ `install-with-ai` from that library.
130
184
 
131
185
  ## Quick start
132
186
 
@@ -153,12 +207,13 @@ the app to change those.
153
207
 
154
208
  ### `init` options
155
209
 
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`. |
210
+ | Option | Default | Description |
211
+ | ---------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
212
+ | `clientToken` | — | **Required.** The `ct_…` client token from Settings → Environments. |
213
+ | `serverEndpoint` | Picked from the client token | Optional. The region is picked automatically from the client token; only set this for a proxy or a non-production stack. |
214
+ | `onNavigate` | — | Handler for flow NAVIGATE actions. Wins over React Navigation, Expo Router, and Linking. See NAVIGATE below. |
215
+ | `appVersion` | Read from the native app | Override the host app version sent as `app_version`. |
216
+ | `appBuild` | Read from the native app | Build number sent as `app_build`, paired with `appVersion`. |
162
217
 
163
218
  ### Where to put `init`, `identify`, and `UserflowProvider`
164
219
 
@@ -193,6 +248,9 @@ export default function RootLayout() {
193
248
  }
194
249
  ```
195
250
 
251
+ Expo Router apps also add `app/+native-intent.ts`, so Builder pairing links do
252
+ not navigate. See [Builder preview & pairing](#builder-preview--pairing).
253
+
196
254
  React Navigation:
197
255
 
198
256
  ```tsx
@@ -391,10 +449,12 @@ To preview draft flows from the Userflow builder onto a device (QR / deep link):
391
449
  `userflow-v7twv2fw2ja2jaco7kesvowmem` — **not** the env UUID) with the
392
450
  `@userflow-tech/react-native` config plugin, then **rebuild native**
393
451
  (`npx expo prebuild` / a new development client). Metro reload is not enough.
394
- 2. Call `Userflow.init` and wrap the tree in `UserflowProvider`.
395
- 3. Open the builder Preview dialog → **Pair a device** → scan/open the QR. The
452
+ 2. Expo Router only: add `app/+native-intent.ts` (below) so pairing and preview
453
+ links do not navigate.
454
+ 3. Call `Userflow.init` and wrap the tree in `UserflowProvider`.
455
+ 4. Open the builder Preview dialog → **Pair a device** → scan/open the QR. The
396
456
  app should show a **Preview mode** top bar.
397
- 4. Hit **Preview** in the builder. The draft flow lands on that paired device.
457
+ 5. Hit **Preview** in the builder. The draft flow lands on that paired device.
398
458
 
399
459
  ```json
400
460
  {
@@ -409,8 +469,20 @@ To preview draft flows from the Userflow builder onto a device (QR / deep link):
409
469
  `schemeId` is the env's `scheme_id` from the dashboard, copied exactly. It is
410
470
  `userflow-` followed by an opaque id. Do not rely on its shape. Preview links
411
471
  (`…://?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.
472
+ scheme. Pairing works in every build, including release.
473
+
474
+ Expo Router treats these root-form URLs as `/`, so without
475
+ `app/+native-intent.ts` it navigates when a link arrives: the app jumps to its
476
+ home route, or element selection fails with "Can't select this element".
477
+ Re-export the SDK's handler to keep the current screen:
478
+
479
+ ```ts
480
+ // app/+native-intent.ts
481
+ export { redirectSystemPath } from '@userflow-tech/react-native/expo-router';
482
+ ```
483
+
484
+ If the app already has a `+native-intent.ts`, wrap it instead. See
485
+ [docs/deep-linking.md](https://unpkg.com/@userflow-tech/react-native/docs/deep-linking.md).
414
486
 
415
487
  Deep-link / pairing helpers:
416
488
 
@@ -524,10 +596,10 @@ and forwards URLs itself.
524
596
 
525
597
  ### Subpath exports
526
598
 
527
- | Import | Provides |
528
- | ----------------------------------------- | ------------------------------------------------------------------------------------------------------- |
529
- | `@userflow-tech/react-native/navigation` | `WithUserflowReactNavigation` |
530
- | `@userflow-tech/react-native/expo-router` | `UserflowExpoRouterScreenTracker`, `useUserflowExpoRouter`, `redirectSystemPath` (for `+native-intent`) |
599
+ | Import | Provides |
600
+ | ----------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
601
+ | `@userflow-tech/react-native/navigation` | `WithUserflowReactNavigation` |
602
+ | `@userflow-tech/react-native/expo-router` | `UserflowExpoRouterScreenTracker`, `useUserflowExpoRouter`, `redirectSystemPath` and `createRedirectSystemPath` (for `+native-intent`), `isUserflowLinkPath`, type `RedirectSystemPathOptions` |
531
603
 
532
604
  ## Guides in this package
533
605
 
@@ -555,17 +627,16 @@ These guides also ship in the package, under
555
627
  - Client conditions — `ELEMENT` PRESENT / NOT_PRESENT on manual anchors and
556
628
  AUTO selectors (guarded: weak evidence stays unknown)
557
629
  - Connection lifecycle — suspend/resume, reconnect, optional NetInfo
630
+ - Build-time stamping with `@userflow-tech/react-native/babel-plugin`
631
+ (`stampOnly: true` stamps `nativeID` only; full mode is the default). Jest
632
+ runs the plugin too, which changes snapshots; see
633
+ [Babel plugin and snapshot tests](#babel-plugin-and-snapshot-tests).
558
634
 
559
635
  ### Experimental
560
636
 
561
637
  - AUTO / codeless element targeting (exact-id fast path + scored matcher;
562
638
  scored path needs Babel full mode to populate the auto-anchor registry).
563
639
  See [docs/anchoring.md](https://unpkg.com/@userflow-tech/react-native/docs/anchoring.md).
564
- - Build-time stamping with `@userflow-tech/react-native/babel-plugin`
565
- (`stampOnly: true` stamps `nativeID` only; full mode is the default). Jest
566
- runs the plugin too, which changes snapshots. Read
567
- [Babel plugin and snapshot tests](#babel-plugin-and-snapshot-tests) before
568
- enabling it.
569
640
 
570
641
  ### Not available yet
571
642
 
@@ -589,7 +660,7 @@ missing lines are included):
589
660
  ```text
590
661
  [Userflow] Native setup is incomplete. Flows may not run until you fix the following, then rebuild the app (a Metro reload is not enough):
591
662
  - @react-native-async-storage/async-storage is not linked. Anonymous users and Builder pairing will not persist. Add it to the app package.json (npx expo install @react-native-async-storage/async-storage), run pod install on iOS, and rebuild.
592
- - react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install react-native-view-shot@^5.0.0 and rebuild. On Expo SDK 54, pin ^5.0.0; an unpinned npx expo install resolves 4.0.3.
663
+ - react-native-view-shot is not linked, so Builder element selection gets no screenshot. Install it and rebuild. On Expo SDK 56 and 57, run npx expo install react-native-view-shot unpinned, with no expo.install.exclude entry for it. Otherwise install react-native-view-shot@^5.0.0; on Expo SDK 55 and older, an unpinned npx expo install resolves 4.0.3.
593
664
  - react-native-webview is not linked. Evaluate JavaScript and WebView banners will not run. Install it (npx expo install react-native-webview) and rebuild.
594
665
  - react-native-device-info is not linked, so app_version and app_build are not sent. npm install react-native-device-info, then rebuild.
595
666
  See node_modules/@userflow-tech/react-native/docs/troubleshooting.md.
@@ -653,6 +724,28 @@ jest.mock('@userflow-tech/react-native/navigation', () => ({
653
724
  In a JavaScript setup file, drop the `ReactNode` import and the type
654
725
  annotations.
655
726
 
727
+ If `app/+native-intent.ts` imports `redirectSystemPath` or
728
+ `createRedirectSystemPath`, replace the `@userflow-tech/react-native/expo-router`
729
+ mock above with the one below (in a JavaScript setup file, drop its type
730
+ annotations too). Two `jest.mock` calls for one path do not merge; the later
731
+ one wins. Expo Router loads `+native-intent.ts` when a test renders the
732
+ router, and the mock replaces the whole module, so an export it leaves out is
733
+ `undefined`. A `+native-intent.ts` that calls `createRedirectSystemPath()` then
734
+ fails the suite with `createRedirectSystemPath is not a function`. These stubs
735
+ pass every URL through, as the real handlers do for links that are not Userflow
736
+ links:
737
+
738
+ ```ts
739
+ jest.mock('@userflow-tech/react-native/expo-router', () => ({
740
+ UserflowExpoRouterScreenTracker: () => null,
741
+ redirectSystemPath: ({ path }: { path: string }) => path,
742
+ createRedirectSystemPath:
743
+ ({ next }: { next?: (event: { path: string }) => unknown } = {}) =>
744
+ (event: { path: string }) =>
745
+ next ? next(event) : event.path,
746
+ }));
747
+ ```
748
+
656
749
  A custom Metro config that does not extend `getDefaultConfig` from `expo/metro-config`
657
750
  or `@react-native/metro-config` leaves `allowOptionalDependencies` off. Optional
658
751
  peers that this package loads inside `try/catch` then fail the bundle with
@@ -660,8 +753,8 @@ peers that this package loads inside `try/catch` then fail the bundle with
660
753
 
661
754
  ### Babel plugin and snapshot tests
662
755
 
663
- If you add the optional `@userflow-tech/react-native/babel-plugin` to
664
- `babel.config.js`, Jest runs it too, because `babel-jest` reads the same config.
756
+ With `@userflow-tech/react-native/babel-plugin` in `babel.config.js`, Jest
757
+ runs it too, because `babel-jest` reads the same config.
665
758
  The plugin adds props to `View`, `Text`, `Pressable`, the Touchables,
666
759
  `TextInput`, and `Image`, and React Native's Jest mocks render them, so they
667
760
  appear in snapshots:
@@ -692,7 +785,8 @@ or moving or renaming a file changes them again. The plugin also imports this
692
785
  package into every stamped file, so any test that renders a stamped component
693
786
  loads the SDK. Keep the mock above in the Jest setup file.
694
787
 
695
- Skip the plugin under Jest:
788
+ Skip the plugin under Jest, and keep the app's own plugins in every
789
+ environment:
696
790
 
697
791
  ```js
698
792
  // babel.config.js
@@ -700,7 +794,11 @@ module.exports = function (api) {
700
794
  const isTest = api.env('test');
701
795
  return {
702
796
  presets: ['babel-preset-expo'],
703
- plugins: isTest ? [] : ['@userflow-tech/react-native/babel-plugin'],
797
+ plugins: [
798
+ // ...the app's own plugins
799
+ ...(isTest ? [] : ['@userflow-tech/react-native/babel-plugin']),
800
+ // react-native-reanimated/plugin or react-native-worklets/plugin, if listed, stays last
801
+ ],
704
802
  };
705
803
  };
706
804
  ```
@@ -78,6 +78,32 @@ export const redirectSystemPath = createRedirectSystemPath({
78
78
  });
79
79
  ```
80
80
 
81
+ `next` runs only for links that are not Userflow links. A pairing or preview
82
+ link returns `null` before `next` is called, so host code inside `next` (logging
83
+ incoming URLs, for example) never sees it. If the host must see every URL, run
84
+ its code first, then return the SDK handler's result:
85
+
86
+ ```ts
87
+ import {
88
+ createRedirectSystemPath,
89
+ type RedirectSystemPathOptions,
90
+ } from '@userflow-tech/react-native/expo-router';
91
+
92
+ const userflowRedirectSystemPath = createRedirectSystemPath({
93
+ next: (event) => event.path, // the host's handling of non-Userflow links
94
+ });
95
+
96
+ export function redirectSystemPath(event: RedirectSystemPathOptions) {
97
+ try {
98
+ // Runs for every URL, Userflow links included. Use the app's own logger here.
99
+ console.log('[app] incoming URL', event.path);
100
+ } catch {
101
+ // Expo warns that throwing here can crash the app.
102
+ }
103
+ return userflowRedirectSystemPath(event);
104
+ }
105
+ ```
106
+
81
107
  Bare React Native / React Navigation apps need nothing beyond scheme
82
108
  registration.
83
109