@rocapine/rn-referral
v0.1.0
Published
Headless referral engine for React Native / Expo apps: referral codes, reward ladder, RevenueCat attribution — pure shared core, injected-seam client, Supabase backend templates.
Keywords
Readme
@rocapine/rn-referral
Headless referral engine for React Native / Expo apps: deterministic referral
codes, a configurable reward ladder, and RevenueCat-attributed conversions — the
package owns the domain logic and wire protocol, you own the UI, storage, and
analytics. Ships with Supabase backend templates so a new app can go from
npx rn-referral init to a working referral loop without hand-writing the
attribution math.
Install
npm install @rocapine/rn-referralThe only peer dependency is react. It's designed for React Native apps, but
react-native itself is not a peer dependency. The ./core subpath has no peer
dependencies and works outside React Native too (e.g. from the Supabase Edge
Function, via Deno's npm: specifier).
Quick start
import { createReferralClient, useReferral } from "@rocapine/rn-referral";
const referralClient = createReferralClient({
ladder: [{ id: "first", threshold: 1, type: "collectible" }],
linkBase: "https://<your-domain>",
transport: (action, payload) => myBackend.invoke("referral-engine", payload),
storage: myAsyncStorageSeam,
subscription: myRevenueCatSeam,
});function ReferralScreen() {
const { state, rewards, nextReward, refresh, acknowledge } =
useReferral(referralClient);
// render state.code, rewards[].isUnlocked, nextReward, ...
}See docs/integration.md for the full seam-by-seam wiring
example (Supabase transport, AsyncStorage storage, RevenueCat subscription), deep
link configuration, and the EAS/Detour gotchas.
Backend setup
npx rn-referral initCopies the Supabase Edge Function + SQL migration templates into your app repo.
Edit ladder.config.ts, supabase db push, deploy, and wire the RevenueCat
webhook — the full walkthrough is in
docs/integration.md.
Architecture
./core is pure, isomorphic TypeScript — no React, no RN, no I/O. It's imported by
both the RN client (.) and the Supabase Edge Function (via Deno's
npm:@rocapine/rn-referral/core), so the code format and attribution math can
never drift between client and server.
The main entry (.) is CJS-only, deliberately — an ESM build breaks Metro's
lazy require() calls at runtime (the same lesson learned shipping
@rocapine/rn-social-share). Don't add an ESM output without re-verifying that.
Events
onEvent receives typed events; the package never logs analytics itself — map
these to your own analytics names.
| Event | Payload | Fires when |
| --------------------- | ----------------------- | -------------------------------------------- |
| state_synced | { refereesConverted } | Server read-through succeeds in getState() |
| redeem_attempted | { code, ok } | redeemCode() resolves (valid or not) |
| reward_acknowledged | { rewardId } | acknowledgeReward() is called |
Link formats
The canonical format for new apps is query-style, one static landing page per
site: ${linkBase}/referral?code=${code} (the buildReferralLink default).
Override it with formatLink(base, code) in createReferralClient if you need a
different shape (e.g. an app with live links already in the wild using
/invite/${code}).
parseReferralCode(url) (from @rocapine/rn-referral/core) is the tolerant
counterpart — it accepts the canonical ?code= query and the legacy
/invite/{code} / /referral/{code} path segments, on full URLs or bare paths, so
old and new links all resolve.
