# React Native SDK Architecture

The Nami React Native SDK (`react-native-nami-sdk`) is a TypeScript bridge layer that exposes native Android and iOS SDK functionality to React Native applications via TurboModules.

## Build System

- **Language:** TypeScript 5 (strict mode), Kotlin (Android bridge), Swift (iOS bridge)
- **Package Manager:** npm
- **TypeScript Output:** Declaration files only (`emitDeclarationOnly`)
- **Native Code Generation:** React Native Codegen (TurboModule specs)
- **Linting:** ESLint with @react-native config, Prettier

### Native Dependencies

| Platform | SDK |
|----------|-----|
| Android (Google Play) | `com.namiml:sdk-android` |
| Android (Amazon) | `com.namiml:sdk-amazon` |
| iOS/tvOS | `Nami` CocoaPod |

## Directory Structure

```
sdk/react-native/
├── src/                           # TypeScript bridge layer
│   ├── index.ts                   # Main exports
│   ├── types.ts                   # Type definitions
│   ├── transformers.ts            # Data transformation utilities
│   ├── version.ts                 # Auto-generated version constant
│   ├── Nami.ts                    # Core SDK initialization
│   ├── NamiPaywallManager.ts      # Paywall display/events
│   ├── NamiCampaignManager.ts     # Campaign management
│   ├── NamiCustomerManager.ts     # Customer identity
│   ├── NamiEntitlementManager.ts  # Entitlement access
│   ├── NamiPurchaseManager.ts     # Purchase operations
│   ├── NamiFlowManager.ts         # Flow management
│   └── NamiOverlayControl.tsx     # React component for overlay UI
├── specs/                         # TurboModule native interface specs
├── android/                       # Kotlin native bridge modules
│   └── src/main/java/com/namiml/reactnative/
├── ios/                           # Swift + Objective-C native bridge
├── dist/                          # Built .d.ts type declarations
├── examples/
│   ├── Basic/                     # Full-featured sample (with Detox e2e)
│   └── TestNamiTV/                # tvOS sample
├── build-utils/                   # Version management scripts
└── scripts/                       # Version generation
```

## Bridge Architecture

```
JavaScript (React Native)
    |
TurboModule TypeScript Specs (/specs)
    |
Native Bridge Modules (Kotlin + Swift)
    |
Native SDKs (com.namiml:sdk-android / Nami CocoaPod)
    |
Platform APIs (Google Play Billing / StoreKit)
```

The React Native SDK is a **thin bridge** - it does NOT reimplement networking, IAP handling, paywall rendering, entitlement validation, or purchase tracking. All business logic lives in the native SDKs.

## Manager Classes

Each TypeScript manager wraps a corresponding TurboModule:

| Manager | Key Methods |
|---------|-------------|
| `Nami` | `configure()`, `sdkConfigured()`, `sdkVersion()` |
| `NamiPaywallManager` | `buySkuComplete()`, handler registration (buy, close, sign-in, restore, deeplink) |
| `NamiCampaignManager` | `launch()`, `allCampaigns()`, `isCampaignAvailable()`, `isFlow()`, `refresh()`, `getProductGroups()` |
| `NamiCustomerManager` | `login()`, `logout()`, `journeyState()`, `setCustomerAttribute()`, `setAnonymousMode()`, `deviceId()` |
| `NamiEntitlementManager` | `active()`, `isEntitlementActive()`, `refresh()`, `clearProvisionalEntitlementGrants()` |
| `NamiPurchaseManager` | `allPurchases()`, `skuPurchased()`, `restorePurchases()`, `presentCodeRedemptionSheet()` |
| `NamiFlowManager` | `pause()`, `resume()`, `finish()`, `isFlowOpen()`, `registerStepHandoff()` |
| `NamiOverlayControl` | `presentOverlay()`, `finishOverlay()`, React `NamiOverlayHost` component |

## Native Bridge Modules

### Android (`android/` - Kotlin)

- **NamiBridgePackage.java** - TurboReactPackage registering all modules
- **NamiBridgeModule.kt** - `RNNami` core configuration
- **NamiCampaignManagerBridgeModule.kt** - Campaign bridge
- **NamiPaywallManagerBridgeModule.kt** - Paywall bridge
- **NamiPurchaseManagerBridge.kt** - Purchase bridge
- **NamiEntitlementManagerBridge.kt** - Entitlement bridge
- **NamiCustomerManagerBridge.kt** - Customer bridge
- **NamiFlowManagerBridge.kt** - Flow bridge
- **NamiOverlayControlBridge.kt** - Overlay + ReactOverlayActivity
- **NamiUtil.kt** - Data transformation (WritableMap/WritableArray)

Android supports two product flavors: `play` (Google Play) and `amazon` (Amazon Appstore).

### iOS (`ios/` - Swift)

Parallel Swift implementations for each bridge module, plus Objective-C `.m` files for Codegen/legacy architecture support.

## Type System (`src/types.ts`)

Key types exported to consumers:

- **NamiConfiguration** - SDK init params (appPlatformID, logLevel, language)
- **NamiSKU** - Product details with platform-specific pricing (Apple, Google, Amazon)
- **NamiPurchase** - Purchase record with timestamps, transaction IDs, source
- **NamiEntitlement** - Entitlement with active purchases and related SKUs
- **NamiCampaign** - Campaign metadata (name, rule type, form factors, segment)
- **CustomerJourneyState** - Subscription lifecycle flags
- **NamiPaywallEvent** - Comprehensive event (30+ actions)
- **NamiPaywallAction** - Enum: BUY_SKU, SELECT_SKU, RESTORE_PURCHASES, VIDEO_STARTED, etc.

## Testing

### Unit Tests

TypeScript unit tests using Jest + ts-jest, covering the pure data transformation layer in `src/transformers.ts`:

- **`parsePurchaseDates`** — converts native timestamp numbers to JS Date objects
- **`coerceSkuType`** — validates raw strings against `NamiSKUType` union, falls back to `'unknown'`
- **`mapToNamiPaywallAction`** — validates raw strings against the `NamiPaywallAction` enum (28 values), falls back to `UNKNOWN`
- **`parseEntitlements`** — transforms raw entitlement arrays, parsing nested purchase dates and defaulting missing SKU arrays

```bash
# From monorepo root
make test-react-native

# Or directly
cd sdk/react-native && npm test
```

Test files live in `src/__tests__/` and are excluded from TypeScript compilation output via `tsconfig.json`.

### E2E Tests

- Detox framework in `examples/Basic/e2e/` (iOS simulator + Android emulator)
- CI via GitHub Actions with artifact upload on failure

#### Local Native SDK Resolution

In the monorepo, native SDKs may not yet be published when e2e tests run against a PR. The workflow resolves this by building native SDKs locally before the Detox build:

**iOS** — The `NAMI_SDK_LOCAL_PATH` environment variable points to `sdk/apple/` in the monorepo. When set, each example app's Podfile overrides the published `Nami` CocoaPod with a local `:path` reference. CI builds the XCFramework first (`make build-apple`), then sets the env var so `pod install` picks up the local artifact.

**Android** — CI publishes the SDK to `mavenLocal` via `./gradlew sdk:publishPublicGooglePublicationToMavenLocal sdk:publishPublicAmazonPublicationToMavenLocal`. The example app's `build.gradle` already includes `mavenLocal()` in its repository list, so Gradle resolves the local artifact without any code changes.

Both approaches are temporary until dev release publishing is in place, at which point the pre-build steps and env var can be removed.

### Code Quality

- ESLint + TypeScript compilation checks in CI

## Peer Dependencies

- React >= 18
- React Native >= 0.73

## Architectural Patterns

- **Bridge/Adapter** - TypeScript wrappers over native TurboModules
- **Event Emitter** - NativeEventEmitter for real-time native-to-JS events
- **Thin Client** - All business logic delegated to native SDKs
- **Codegen** - TurboModule specs for typed native module generation (New Architecture)
- **Transformer** - Data conversion between native types and JS objects
