@getrheo/rheo-skill 2.5.0 → 3.0.0
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 +17 -12
- package/package.json +7 -5
- package/rheo/SKILL.md +20 -11
- package/rheo/rheo-best-practices/SKILL.md +32 -19
- package/rheo/rheo-best-practices/examples/swiftui-install-snippet.md +3 -1
- package/rheo/rheo-best-practices/examples/web-install-snippet.md +26 -0
- package/rheo/rheo-best-practices/references/analytics.md +104 -0
- package/rheo/rheo-best-practices/references/engage.md +95 -0
- package/rheo/rheo-best-practices/references/implement-workflow.md +20 -15
- package/rheo/rheo-best-practices/references/integrations.md +38 -4
- package/rheo/rheo-best-practices/references/product-model.md +66 -0
- package/rheo/rheo-best-practices/references/react-native-bare.md +3 -1
- package/rheo/rheo-best-practices/references/react-native-expo.md +5 -4
- package/rheo/rheo-best-practices/references/react-web.md +78 -0
- package/rheo/rheo-best-practices/references/swiftui.md +20 -49
- package/rheo/rheo-best-practices/references/troubleshooting.md +15 -2
- package/rheo/rheo-flow-import/SKILL.md +4 -2
- package/rheo/rheo-flow-import/references/capabilities.md +10 -1
- package/rheo/rheo-flow-import/references/flow-spec.md +11 -1
- package/rheo/rheo-flow-import/references/import-workflow.md +1 -1
- package/rheo/rheo-flow-import/references/manifest-agent-profile-fallback.md +1 -1
- package/rheo/rheo-flow-import/references/manifest-rules.md +1 -1
- package/rheo/rheo-flow-import/references/publish-gates.md +2 -2
- package/rheo/rheo-flow-import/references/react-native-source-patterns.md +3 -1
- package/rheo/rheo-flow-import/references/swiftui-source-patterns.md +2 -0
- package/rheo/rheo-flow-import/scripts/lib/rheo-cli.mjs +3713 -259
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Product model
|
|
2
|
+
|
|
3
|
+
Rheo is one SDK and one Customer. Analytics, Convert, and Engage are products on that SDK. Install once. Wire only the products the user asked for.
|
|
4
|
+
|
|
5
|
+
| Product | Host implements | Dashboard owns |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| **Analytics** | `RheoProvider` (sessions, page or screen views, `logEvent`), web consent, `setUserId`, `setBillingIdentity` | Visitors, retention, revenue reports |
|
|
8
|
+
| **Convert** | `Flow` / `FlowView` on a **channel** public id, terminal callbacks, Integration Nodes and External Surface Nodes | Canvas, experiments, channels, publish |
|
|
9
|
+
| **Engage** | `identify` for email and marketing consent. `track` for automation triggers on web and React Native | Email provider, broadcasts, automations, preference center |
|
|
10
|
+
| **Customers** | A stable `userId`, plus `identify` when email or consent exists | Profiles, segments, consent |
|
|
11
|
+
|
|
12
|
+
Customers are the shared record. The same id filters Analytics and targets Engage. Segments are dashboard (or CLI) objects. Do not invent a second user id per product.
|
|
13
|
+
|
|
14
|
+
## One provider
|
|
15
|
+
|
|
16
|
+
Mount `RheoProvider` once, high enough that the screens you care about sit under it. Product analytics starts when the provider mounts, including when no flow is on screen. A Convert-only request still gets Analytics unless the user opts out with `analytics={{ enabled: false }}` (web and React Native) or `analyticsEnabled: false` (SwiftUI `RheoConfig`).
|
|
17
|
+
|
|
18
|
+
Do not add a second product-analytics SDK, a second onboarding SDK, or a Rheo-owned email sender.
|
|
19
|
+
|
|
20
|
+
## Three event pipes
|
|
21
|
+
|
|
22
|
+
These are different APIs. Sending a product event does not start an automation.
|
|
23
|
+
|
|
24
|
+
| Call | Where it goes | Starts Engage automations |
|
|
25
|
+
| --- | --- | --- |
|
|
26
|
+
| Flow funnel events (`flow_started`, `step_viewed`, …) | `POST /v1/sdk/events` | No |
|
|
27
|
+
| `logEvent`, `screen`, automatic `session_start` / `page_view` / `first_visit` / `first_open` | `POST /v1/sdk/analytics/events` | No |
|
|
28
|
+
| `track` (web and React Native) | `POST /v1/sdk/track` | Yes |
|
|
29
|
+
|
|
30
|
+
Use `logEvent` when the event should show up in Analytics. Use `track` only when that event should enroll an Engage automation or match a segment rule. Call both only when the user asked for a report and a journey from the same action.
|
|
31
|
+
|
|
32
|
+
`unknown` marketing consent does not send. Granted consent is required for live email and webhook delivery; email also needs an address. See [engage.md](engage.md).
|
|
33
|
+
|
|
34
|
+
## Identity
|
|
35
|
+
|
|
36
|
+
| Input | Sets | Does not set |
|
|
37
|
+
| --- | --- | --- |
|
|
38
|
+
| `userId` on provider config | `appUserId` for analytics, experiment bucketing, and identify | Email or consent |
|
|
39
|
+
| `setUserId` / `customUserId` | CRM id on later product events | `appUserId` |
|
|
40
|
+
| `identify` | Email, marketing consent, optional topic consents on the Customer | A product-analytics event |
|
|
41
|
+
| `setBillingIdentity('revenuecat' \| 'superwall', id)` | Billing id used to attach webhook revenue to this person | A purchase by itself |
|
|
42
|
+
|
|
43
|
+
Email typed into a flow, or stuffed into event properties, is not marketing consent. Call `identify` after the person actually opts in or opts out.
|
|
44
|
+
|
|
45
|
+
When email is sent, `marketingConsent` is required (`granted`, `denied`, or `unknown`). `granted` requires an email.
|
|
46
|
+
|
|
47
|
+
Web and React Native `identify` also accept `attributes` (shallow-merged onto the Customer) and an IANA `timezone` for Engage quiet hours. SwiftUI `RheoRuntime.identify` takes email, consent, topic consents, and `customUserId` only.
|
|
48
|
+
|
|
49
|
+
## Revenue
|
|
50
|
+
|
|
51
|
+
Dollars come from the provider webhook, not from the device. After the host calls RevenueCat `logIn` / `Purchases.configure` or Superwall `identify`, call `setBillingIdentity` with that same id. Stripe on the web SDK records the charge from `checkout.session.completed` on the app webhook. There is no `setBillingIdentity('stripe', …)`.
|
|
52
|
+
|
|
53
|
+
One revenue source per store. App Store and Play are RevenueCat or Superwall. Web can be Stripe.
|
|
54
|
+
|
|
55
|
+
## Platforms this skill installs
|
|
56
|
+
|
|
57
|
+
| Stack | Package | Analytics | Convert | `identify` | Engage `track` |
|
|
58
|
+
| --- | --- | --- | --- | --- | --- |
|
|
59
|
+
| React Native + Expo | `@getrheo/react-native-expo` | Yes | Yes | Yes | Yes |
|
|
60
|
+
| React Native bare | `@getrheo/react-native-bare` | Yes | Yes | Yes | Yes |
|
|
61
|
+
| React web | `@getrheo/react` | Yes, consent required | Yes | Yes | Yes |
|
|
62
|
+
| SwiftUI | `RheoSwiftUI` | Yes | Yes | Yes | No |
|
|
63
|
+
|
|
64
|
+
Install one React Native flavor, never both. The web package is separate and can sit beside a native app. It is not a second flavor of the same binary.
|
|
65
|
+
|
|
66
|
+
Flutter exposes product analytics and `identify` in `rheo_flutter`. This skill has no Flutter install guide. Engage push and outbound webhooks are not SDK surfaces yet. Engage email sends through the app's own SES, Resend, Postmark, or SendGrid account, configured in the dashboard.
|
|
@@ -15,7 +15,7 @@ pnpm add @getrheo/react-native-bare \
|
|
|
15
15
|
react-native-safe-area-context react-native-in-app-review react-native-video
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
**Integrations (host only):** `react-native-appsflyer`, `react-native-purchases`, `react-native-purchases-ui` when needed. External Surface Nodes use `Flow` `externalSurfaces` (no extra native peer).
|
|
18
|
+
**Integrations (host only):** `react-native-appsflyer`, `react-native-purchases`, `react-native-purchases-ui`, `@superwall/react-native-superwall` when needed. External Surface Nodes use `Flow` `externalSurfaces` (no extra native peer).
|
|
19
19
|
|
|
20
20
|
## Minimal Runtime
|
|
21
21
|
|
|
@@ -38,5 +38,7 @@ export const OnboardingHost = () => (
|
|
|
38
38
|
## Notes
|
|
39
39
|
|
|
40
40
|
- Do **not** install `@getrheo/react-native-expo` in the same app.
|
|
41
|
+
- `RheoProvider` starts Analytics even when `Flow` is omitted. Pass a channel public id only for Convert, never a flow id.
|
|
42
|
+
- `logEvent` / `screen` / `setUserId` / `setBillingIdentity` are Analytics. `identify` and `track` are Engage. Same exports as Expo. See [analytics.md](analytics.md) and [engage.md](engage.md).
|
|
41
43
|
- **Production:** default API is `https://api.getrheo.io`; omit `apiBaseUrl` unless self-hosting.
|
|
42
44
|
- Link native modules (permissions, video, reanimated babel plugin) per upstream docs.
|
|
@@ -12,10 +12,10 @@ pnpm add @getrheo/react-native-expo \
|
|
|
12
12
|
react-native-permissions react-native-gesture-handler react-native-reanimated \
|
|
13
13
|
react-native-linear-gradient react-native-svg lottie-react-native \
|
|
14
14
|
react-native-vector-icons @react-native-async-storage/async-storage \
|
|
15
|
-
react-native-safe-area-context expo-store-review expo-video
|
|
15
|
+
react-native-safe-area-context expo-store-review expo-video expo-notifications
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
**Integrations (host only, not SDK peers):** `react-native-appsflyer`, `react-native-purchases`, `react-native-purchases-ui` when the flow uses attribution or
|
|
18
|
+
**Integrations (host only, not SDK peers):** `react-native-appsflyer`, `react-native-purchases`, `react-native-purchases-ui`, `expo-superwall` / `@superwall/react-native-superwall` when the flow uses attribution, RevenueCat, or Superwall Integration Nodes. External Surface Nodes use `Flow` / `useFlow` `externalSurfaces` (no extra native peer).
|
|
19
19
|
|
|
20
20
|
## Minimal Runtime
|
|
21
21
|
|
|
@@ -43,7 +43,8 @@ export const OnboardingHost = () => (
|
|
|
43
43
|
## Notes
|
|
44
44
|
|
|
45
45
|
- Do **not** install `@getrheo/react-native-bare` in the same app.
|
|
46
|
-
- Pass channel public id,
|
|
46
|
+
- `RheoProvider` starts Analytics even when `Flow` is omitted. Pass a channel public id only for Convert, never a flow id.
|
|
47
|
+
- `logEvent` / `screen` / `setUserId` / `setBillingIdentity` are Analytics. `identify` and `track` are Engage. See [analytics.md](analytics.md) and [engage.md](engage.md).
|
|
47
48
|
- **Production:** default API is `https://api.getrheo.io`; omit `apiBaseUrl` unless self-hosting. Never use localhost with `ob_pk_live_*` keys.
|
|
48
49
|
- Built-in OS permissions need `react-native-permissions` native setup (Expo plugin + Info.plist).
|
|
49
|
-
- Expo Go cannot run native RevenueCat UI; use a dev client.
|
|
50
|
+
- Expo Go cannot run native RevenueCat or Superwall UI; use a dev client.
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# React web
|
|
2
|
+
|
|
3
|
+
## Detect
|
|
4
|
+
|
|
5
|
+
A browser app: `react` and `react-dom`, often Vite, Next.js, or Remix. No `react-native` dependency.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pnpm add @getrheo/react
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Peers: `react` and `react-dom` ≥ 18.
|
|
14
|
+
|
|
15
|
+
## Minimal runtime
|
|
16
|
+
|
|
17
|
+
Analytics-only (no flow). Consent stays pending until the site grants it. See [analytics.md](analytics.md).
|
|
18
|
+
|
|
19
|
+
```tsx
|
|
20
|
+
import { RheoProvider } from '@getrheo/react';
|
|
21
|
+
|
|
22
|
+
export const App = () => (
|
|
23
|
+
<RheoProvider
|
|
24
|
+
config={{
|
|
25
|
+
publishableKey: import.meta.env.VITE_RHEO_PUBLISHABLE_KEY,
|
|
26
|
+
analytics: { consent: 'pending' },
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
{children}
|
|
30
|
+
</RheoProvider>
|
|
31
|
+
);
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Convert: same provider, plus `Flow` and a channel public id. Add the site origin (scheme, host, and port) under **App settings → SDK**. A browser request from an origin the app did not list is rejected.
|
|
35
|
+
|
|
36
|
+
```tsx
|
|
37
|
+
import { Flow, RheoProvider } from '@getrheo/react';
|
|
38
|
+
|
|
39
|
+
export const App = () => (
|
|
40
|
+
<RheoProvider
|
|
41
|
+
config={{
|
|
42
|
+
publishableKey: import.meta.env.VITE_RHEO_PUBLISHABLE_KEY,
|
|
43
|
+
analytics: { consent: 'pending' },
|
|
44
|
+
}}
|
|
45
|
+
>
|
|
46
|
+
<Flow channelId="ch_…" />
|
|
47
|
+
</RheoProvider>
|
|
48
|
+
);
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
**Production:** omit `apiBaseUrl` unless self-hosting. Default API is `https://api.getrheo.io`. Never pair `ob_pk_live_*` with localhost.
|
|
52
|
+
|
|
53
|
+
The snippet uses Vite's `import.meta.env`. Next.js should read `NEXT_PUBLIC_…` (or the project's existing public env) instead.
|
|
54
|
+
|
|
55
|
+
## Payments
|
|
56
|
+
|
|
57
|
+
Stripe is the web paywall. Turn **Stripe** on under **App settings → Integrations**, add a Stripe Integration Node whose Payment Link is on `buy.stripe.com` or another `https://*.stripe.com` host, and paste Rheo's webhook URL and signing secret into Stripe. No Stripe adapter on `RheoProvider`. The return restores the session. The webhook writes the charge. The browser does not send a price.
|
|
58
|
+
|
|
59
|
+
## Engage
|
|
60
|
+
|
|
61
|
+
`identify` and `track` export from `@getrheo/react`. Call `identify` after a real marketing opt-in. Use `track` for automation or segment triggers. An email typed into a flow answer is not consent. See [engage.md](engage.md).
|
|
62
|
+
|
|
63
|
+
`registerPush()` registers Web Push after you save a VAPID key under **App settings → Engage settings**.
|
|
64
|
+
|
|
65
|
+
## Prefetch
|
|
66
|
+
|
|
67
|
+
Pass `prefetch="all"` or `prefetch={['ch_…']}` on `RheoProvider`, or call `prefetch` / `prefetchAll` / `useRheoPrefetch` to warm the resolve cache (`localStorage` + `If-None-Match`).
|
|
68
|
+
|
|
69
|
+
## What the web SDK does not do
|
|
70
|
+
|
|
71
|
+
| Feature | Web behavior |
|
|
72
|
+
| --- | --- |
|
|
73
|
+
| RevenueCat / Superwall / headless external surfaces | Surface fails and follows **Fallback** |
|
|
74
|
+
| `request_os_permission` other than notifications | Treated as denied |
|
|
75
|
+
| `request_app_review` | No-op (`not_shown`) |
|
|
76
|
+
| AppsFlyer | Not supported. First-party UTMs are on by default (`attribution.enabled` not `false`) |
|
|
77
|
+
|
|
78
|
+
First-touch UTMs stay in memory while consent is pending or denied. `setAnalyticsConsent('granted')` writes them.
|
|
@@ -1,53 +1,24 @@
|
|
|
1
1
|
# SwiftUI
|
|
2
2
|
|
|
3
|
+
## Status: SDK install coming soon
|
|
4
|
+
|
|
5
|
+
**Do not install** a SwiftUI SDK package for customers today. Public Swift extract / SwiftPM distribution is paused until the native SDK GA checklist is satisfied. Marketing and the Developer Guide treat SwiftUI as **coming soon**.
|
|
6
|
+
|
|
7
|
+
If the user asks to install Rheo in a SwiftUI app:
|
|
8
|
+
|
|
9
|
+
1. Say SwiftUI SDK install is **not customer-available** yet.
|
|
10
|
+
2. Offer supported install stacks instead: Expo, bare React Native, or React web (see those references).
|
|
11
|
+
3. If they have an existing SwiftUI onboarding/paywall to migrate into Convert, route to **rheo-flow-import** (SwiftUI **source → manifest** import is supported; it does not install the SDK).
|
|
12
|
+
|
|
3
13
|
## Detect
|
|
4
14
|
|
|
5
|
-
Look for `Package.swift`, `.xcodeproj`, `.xcworkspace`, SwiftUI `App`, `NavigationStack`, onboarding root views, and coordinators.
|
|
6
|
-
|
|
7
|
-
##
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
Optional products:
|
|
16
|
-
|
|
17
|
-
```swift
|
|
18
|
-
.product(name: "RheoSwiftUIRevenueCat", package: "RheoSwiftUI")
|
|
19
|
-
.product(name: "RheoSwiftUIAppsFlyer", package: "RheoSwiftUI")
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Minimal Runtime
|
|
23
|
-
|
|
24
|
-
```swift
|
|
25
|
-
import SwiftUI
|
|
26
|
-
import RheoSwiftUI
|
|
27
|
-
|
|
28
|
-
struct OnboardingHost: View {
|
|
29
|
-
var body: some View {
|
|
30
|
-
RheoProvider(
|
|
31
|
-
config: RheoConfig(
|
|
32
|
-
publishableKey: "ob_pk_test_xxx",
|
|
33
|
-
userId: "user_123",
|
|
34
|
-
sessionId: "sess_123"
|
|
35
|
-
)
|
|
36
|
-
) {
|
|
37
|
-
FlowView(channelId: "ch_test_xxx") { snapshot in
|
|
38
|
-
// Continue host navigation.
|
|
39
|
-
} onFlowAbandoned: { snapshot in
|
|
40
|
-
// Continue or restore host navigation.
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
## Notes
|
|
48
|
-
|
|
49
|
-
- Use `RheoSwiftUIRevenueCat` for RevenueCat Integration Node presenter helpers.
|
|
50
|
-
- External Surface Nodes: pass `externalSurfaces: [surfId: { ctx in AnyView(...) }]` on `FlowView` (`ctx.onComplete` / `onBack` / `onDismiss`).
|
|
51
|
-
- Use `RheoSwiftUIAppsFlyer` for AppsFlyer attribution providers.
|
|
52
|
-
- Host apps must include Info.plist usage strings for authored permission prompts.
|
|
53
|
-
- Host apps must register branding fonts if relying on downloaded font families.
|
|
15
|
+
Look for `Package.swift`, `.xcodeproj`, `.xcworkspace`, SwiftUI `App`, `NavigationStack`, onboarding root views, and coordinators — useful for **flow import**, not for SDK install.
|
|
16
|
+
|
|
17
|
+
## Historical snippet (not for install)
|
|
18
|
+
|
|
19
|
+
The file [examples/swiftui-install-snippet.md](../examples/swiftui-install-snippet.md) is retained for internal / future GA reference only. **Do not** add `RheoSwiftUI` SwiftPM products or edit the host app to mount `RheoProvider` / `FlowView` until GA docs flip from coming soon.
|
|
20
|
+
|
|
21
|
+
## Engage notes (when GA lands)
|
|
22
|
+
|
|
23
|
+
- SwiftUI will not export Engage `track` (same as web). Automation triggers must come from React Native or from events the app already sends that Engage can enroll on.
|
|
24
|
+
- Push registration and billing identity helpers are documented in [engage.md](engage.md) / [integrations.md](integrations.md) for when the package is customer-installable.
|
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Troubleshooting
|
|
2
2
|
|
|
3
|
+
## Analytics shows no product events
|
|
4
|
+
|
|
5
|
+
- Confirm `RheoProvider` is mounted. Sessions start there, not when `Flow` mounts.
|
|
6
|
+
- On web, omitted consent is `pending`. Call `setAnalyticsConsent('granted')` or pass `analytics.consent: 'granted'` when a grant already exists. `analytics.enabled: false` stays off after a grant.
|
|
7
|
+
- `logEvent` before the provider mounts is a no-op. `track` does not write product analytics.
|
|
8
|
+
|
|
9
|
+
## An Engage automation never enrolls
|
|
10
|
+
|
|
11
|
+
- `logEvent` and flow events do not start automations. React Native must call `track`.
|
|
12
|
+
- SwiftUI and web do not export Engage `track`.
|
|
13
|
+
- `identify` with `unknown` or missing email does not make the person sendable. Consent has to be `granted`.
|
|
14
|
+
- Provider credentials, suppressions, and topic grants are dashboard state. The SDK cannot repair them.
|
|
15
|
+
|
|
3
16
|
## Manifest Fails Validation
|
|
4
17
|
|
|
5
18
|
Run:
|
|
@@ -38,11 +51,11 @@ Fix workflow:
|
|
|
38
51
|
|
|
39
52
|
## Missing Fallback Edge
|
|
40
53
|
|
|
41
|
-
Every Integration / External Surface Node needs `fallback`. Outcomes that are not explicitly mapped (RevenueCat purchase outcomes or headless `completed` / `back` / `dismissed`) fall through to this target.
|
|
54
|
+
Every Integration / External Surface Node needs `fallback`. Outcomes that are not explicitly mapped (RevenueCat / Superwall purchase outcomes or headless `completed` / `back` / `dismissed`) fall through to this target.
|
|
42
55
|
|
|
43
56
|
## Integration Disabled
|
|
44
57
|
|
|
45
|
-
The manifest may validate locally but fail dashboard import if the target app has RevenueCat disabled or the workspace lacks integration entitlements.
|
|
58
|
+
The manifest may validate locally but fail dashboard import if the target app has RevenueCat / Superwall disabled or the workspace lacks integration entitlements.
|
|
46
59
|
|
|
47
60
|
## Wrong Environment
|
|
48
61
|
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: rheo-flow-import
|
|
3
|
-
description: Analyze an existing mobile
|
|
3
|
+
description: Analyze an existing mobile Convert flow (onboarding, paywall, post-purchase, setup) in a React Native, Expo, or SwiftUI codebase and export it as a compliant Rheo FlowManifest, then validate it against the dashboard publish gates. Use when a user asks to import, migrate, or convert an existing flow into Rheo, generate or scaffold a Rheo manifest, or validate/repair a Rheo manifest. Part of the `rheo` skill. Does not install the SDK or configure Analytics or Engage. Ships self-contained node scripts — no install step.
|
|
4
4
|
compatibility: Requires Node.js 20+. All scripts are self-contained (zod, @getrheo/contracts, and @getrheo/flow-runtime are bundled into scripts/lib/rheo-cli.mjs). Internet access fetches the latest Manifest Agent Profile; a bundled fallback works offline.
|
|
5
5
|
---
|
|
6
6
|
|
|
7
7
|
# Rheo — Flow Import
|
|
8
8
|
|
|
9
|
-
Convert an existing
|
|
9
|
+
This is the **Convert** path. It turns an existing onboarding, paywall, post-purchase, or setup flow into a Rheo `FlowManifest` that imports and publishes in the dashboard with zero blockers. It does not install the SDK, record product analytics, or configure Engage. When the user also wants the app wired, finish the manifest, then follow [rheo-best-practices](../rheo-best-practices/SKILL.md).
|
|
10
|
+
|
|
11
|
+
Prefer **source code as truth**; use screenshots/recordings only as supporting evidence unless the user says they are newer.
|
|
10
12
|
|
|
11
13
|
The recommended authoring path is **spec → scaffold → enrich → validate**: describe the flow as a compact [flow spec](references/flow-spec.md), run `scaffold-manifest.mjs` to get a schema-valid skeleton with correct ids/structure, then enrich styling and validate. Hand-authoring full manifest JSON is allowed but error-prone — the scaffold removes the mechanical mistakes (ids, `children` arrays, choice bindings, branching).
|
|
12
14
|
|
|
@@ -27,6 +27,12 @@ Every layer `kind` accepted by the manifest:
|
|
|
27
27
|
- `text_input`
|
|
28
28
|
- `scale_input`
|
|
29
29
|
- `wheel_picker`
|
|
30
|
+
- `date_time_input`
|
|
31
|
+
- `number_stepper`
|
|
32
|
+
- `number_stepper_button`
|
|
33
|
+
- `number_stepper_value`
|
|
34
|
+
- `phone_input`
|
|
35
|
+
- `address_input`
|
|
30
36
|
- `oauth_provider`
|
|
31
37
|
- `oauth_login`
|
|
32
38
|
- `email_password_auth`
|
|
@@ -68,6 +74,7 @@ Valid `action.kind` values on `button` layers:
|
|
|
68
74
|
- `play_media`
|
|
69
75
|
- `request_app_review`
|
|
70
76
|
- `advance_carousel`
|
|
77
|
+
- `dismiss_banner`
|
|
71
78
|
|
|
72
79
|
- `FlowGraphNodeJumpTarget` (`scr_*` | `dec_*` | `surf_*`): `go_to_step.screenId`, choice `branching.conditions[].goTo`, loader/lottie/video `onComplete` when mode is `screen`, and `request_os_permission` outcomes (except `continue`/`end`).
|
|
73
80
|
- `go_back_one_screen` and `back_button` accept optional `fallbackScreenId` (`scr_*` only).
|
|
@@ -113,8 +120,10 @@ Valid `permissionKey` values for `request_os_permission`:
|
|
|
113
120
|
|
|
114
121
|
## External surface outcomes
|
|
115
122
|
|
|
116
|
-
Builder add-menu kinds share `externalSurfaceNodes`: **Integration Node** (partner providers such as RevenueCat) and **External Surface Node** (`provider: "headless"`). Every node needs a `fallback` jump target.
|
|
123
|
+
Builder add-menu kinds share `externalSurfaceNodes`: **Integration Node** (partner providers such as RevenueCat / Superwall) and **External Surface Node** (`provider: "headless"`). Every node needs a `fallback` jump target.
|
|
117
124
|
|
|
118
125
|
**Integration Node / RevenueCat** (`provider: "revenuecat"`): `purchase_completed`, `purchase_cancelled`, `dismissed`, `failed`, `restore_completed`.
|
|
119
126
|
|
|
127
|
+
**Integration Node / Superwall** (`provider: "superwall"`): `purchase_completed`, `purchase_cancelled`, `dismissed`, `failed`, `restore_completed`.
|
|
128
|
+
|
|
120
129
|
**External Surface Node / Headless** (`provider: "headless"`): `completed`, `back`, `dismissed`, `failed`. Host apps register UI via `externalSurfaces[hostKey]` (`config.hostKey` or node id) with `onComplete` / `onBack` / `onDismiss`.
|
|
@@ -200,7 +200,7 @@ instead of a plain footer CTA ([carousel-import.md](carousel-import.md)).
|
|
|
200
200
|
|
|
201
201
|
`decisions` accepts full `@getrheo/contracts` `DecisionNode` objects (the scaffold
|
|
202
202
|
passes them through). External surfaces use `externalSurfaces` (builder:
|
|
203
|
-
**Integration Node** for `revenuecat`, **External Surface Node** for `headless`):
|
|
203
|
+
**Integration Node** for `revenuecat` / `superwall`, **External Surface Node** for `headless`):
|
|
204
204
|
|
|
205
205
|
```jsonc
|
|
206
206
|
{
|
|
@@ -213,6 +213,16 @@ passes them through). External surfaces use `externalSurfaces` (builder:
|
|
|
213
213
|
}
|
|
214
214
|
```
|
|
215
215
|
|
|
216
|
+
```jsonc
|
|
217
|
+
{
|
|
218
|
+
"id": "surf_sw_paywall",
|
|
219
|
+
"provider": "superwall",
|
|
220
|
+
"placementId": "campaign_trigger",
|
|
221
|
+
"outcomes": { "purchase_completed": "scr_done", "restore_completed": "scr_done", "dismissed": "scr_offer2" },
|
|
222
|
+
"fallback": "scr_offer2" // required — Integration Node; placementId optional (uses app defaultPlacementId)
|
|
223
|
+
}
|
|
224
|
+
```
|
|
225
|
+
|
|
216
226
|
```jsonc
|
|
217
227
|
{
|
|
218
228
|
"id": "surf_custom_step",
|
|
@@ -109,7 +109,7 @@ If the user has not named an entry point, stop after question 1 and wait for an
|
|
|
109
109
|
18. Generate `rheo-import.manifest.json`:
|
|
110
110
|
- Emit a complete graph with explicit `next.default` edges.
|
|
111
111
|
- Use decision nodes for clear branches.
|
|
112
|
-
- Use RevenueCat
|
|
112
|
+
- Use RevenueCat / Superwall **Integration Nodes** for detected partner paywalls (`provider: "revenuecat"` or `"superwall"`).
|
|
113
113
|
- Prefer fidelity when the user chose visual fidelity: carousels, gradients, shadows, and centered stacks.
|
|
114
114
|
- **Layer ids:** `scr_*` / `lyr_*` only on screens and layers; UUID placeholders **only** for `media.mediaAssetId` and font sidecars ([layer-schema-pitfalls.md](layer-schema-pitfalls.md#layer-ids-vs-media-placeholder-uuids)).
|
|
115
115
|
- **Container layers:** every `button`, `back_button`, `hyperlink`, `stack`, choice input, and auth layer must include its `children` (or `slides`) array ([manifest-rules.md](manifest-rules.md#container-layers-required-children)).
|
|
@@ -67,7 +67,7 @@ Use only: `stack`, `text`, `image`, `lottie`, `video`, `icon`, `button`, `back_b
|
|
|
67
67
|
- Black-and-white fallback is acceptable only when the audit finds no style/token evidence and the user confirms no theme source.
|
|
68
68
|
- Use at most one input layer kind per **active path** (`single_choice`, `multiple_choice`, `text_input`, `scale_input`, `wheel_picker`) — one per screen unless sibling `conditional` branches split the path.
|
|
69
69
|
- Non-reserved `sdk.*` decision keys must be listed in `sdkAttributeKeys`.
|
|
70
|
-
- RevenueCat **Integration Nodes** and headless **External Surface Nodes** both live in `externalSurfaceNodes` and always need `fallback`.
|
|
70
|
+
- RevenueCat / Superwall **Integration Nodes** and headless **External Surface Nodes** both live in `externalSurfaceNodes` and always need `fallback`.
|
|
71
71
|
- Emit complete graph edges for imported flows.
|
|
72
72
|
- Use placeholder UUID media ids and `rheo-import.assets.json`; never put file paths directly in `mediaAssetId`.
|
|
73
73
|
- Do not silently drop media layers. If a traced asset cannot be copied, report the missing file and do not call the import complete.
|
|
@@ -197,7 +197,7 @@ Use `conditional` when the source renders different content on **one** screen ba
|
|
|
197
197
|
|
|
198
198
|
In the builder UI these are two add-menu kinds sharing `externalSurfaceNodes`:
|
|
199
199
|
|
|
200
|
-
- **Integration Node** — RevenueCat paywalls become nodes with provider `revenuecat`.
|
|
200
|
+
- **Integration Node** — RevenueCat / Superwall paywalls become nodes with provider `revenuecat` or `superwall`.
|
|
201
201
|
- **External Surface Node** — Host-owned custom screens become nodes with provider `headless` (stable `surf_*` id; optional `config.hostKey` for the host `externalSurfaces` registry).
|
|
202
202
|
- Every node needs a `fallback`.
|
|
203
203
|
- Map paywall outcomes to `purchase_completed`, `restore_completed`, `dismissed`, and `failed`.
|
|
@@ -45,9 +45,9 @@ These mirror `apps/web/src/features/builder/validateFlow.ts` and API `preflightP
|
|
|
45
45
|
|
|
46
46
|
### Integrations (default: enabled)
|
|
47
47
|
|
|
48
|
-
- External surfaces need `config.provider` (not `unspecified`). Integration Nodes use partner providers such as `revenuecat`; External Surface Nodes use `headless`.
|
|
48
|
+
- External surfaces need `config.provider` (not `unspecified`). Integration Nodes use partner providers such as `revenuecat` or `superwall`; External Surface Nodes use `headless`.
|
|
49
49
|
- Every external surface needs `fallback`.
|
|
50
|
-
- RevenueCat surfaces require
|
|
50
|
+
- RevenueCat / Superwall surfaces require the matching integration enabled (import assumes enabled).
|
|
51
51
|
- External Surface Nodes (`provider: "headless"`) do not require an App settings toggle; the host must supply `externalSurfaces`.
|
|
52
52
|
|
|
53
53
|
### Canvas editor gates (default: all enabled)
|
|
@@ -84,10 +84,12 @@ Paging is swipe by default; map the pager's own next button to a `button` with
|
|
|
84
84
|
|
|
85
85
|
- `react-native-purchases` / `react-native-purchases-ui` / `Purchases.configure`
|
|
86
86
|
/ a `<Paywall>` → a RevenueCat **Integration Node** (`provider: "revenuecat"`,
|
|
87
|
+
required `fallback`). `expo-superwall` / `@superwall/react-native-superwall` /
|
|
88
|
+
`registerPlacement` → a Superwall **Integration Node** (`provider: "superwall"`,
|
|
87
89
|
required `fallback`). Host-owned custom screens → an **External Surface Node**
|
|
88
90
|
(`provider: "headless"`). See [integrations](../../rheo-best-practices/references/integrations.md).
|
|
89
91
|
- `react-native-appsflyer` → represent stable attribution branches via decision
|
|
90
|
-
nodes; add keys to `sdkAttributeKeys`. Never include AppsFlyer/RevenueCat secrets.
|
|
92
|
+
nodes; add keys to `sdkAttributeKeys`. Never include AppsFlyer/RevenueCat/Superwall secrets.
|
|
91
93
|
- OAuth / email-password screens → `oauth_login` / `email_password_auth` (host
|
|
92
94
|
owns the actual auth logic).
|
|
93
95
|
- `react-native-permissions` prompts → a `request_os_permission` button action.
|
|
@@ -81,6 +81,8 @@ page. Paging is swipe by default; an explicit Next button becomes a `button` wit
|
|
|
81
81
|
|
|
82
82
|
- RevenueCat (`Purchases.configure`, `RevenueCatUI` `PaywallView`, `.presentPaywall`)
|
|
83
83
|
→ a RevenueCat **Integration Node** (`provider: "revenuecat"`, required
|
|
84
|
+
`fallback`). Superwall (`Superwall.configure`, `register(placement:)`)
|
|
85
|
+
→ a Superwall **Integration Node** (`provider: "superwall"`, required
|
|
84
86
|
`fallback`). Host-owned custom screens → an **External Surface Node**
|
|
85
87
|
(`provider: "headless"`). See [integrations](../../rheo-best-practices/references/integrations.md).
|
|
86
88
|
- AppsFlyer (`AppsFlyerLib`) → represent stable attribution branches via decision
|