Priority: MANDATORY Follow these architectural principles in all code.
openiap/
├── packages/
│ ├── docs/ # Documentation (React/Vite/Vercel)
│ ├── gql/ # GraphQL schema & type generation
│ ├── google/ # Android library (Kotlin)
│ └── apple/ # iOS/macOS library (Swift)
├── libraries/ # Framework SDK implementations
│ ├── react-native-iap/ # React Native (npm, Yarn 3, Nitro Modules)
│ ├── expo-iap/ # Expo (npm, Bun, Expo Modules)
│ ├── flutter_inapp_purchase/ # Flutter (pub.dev, Dart)
│ ├── godot-iap/ # Godot 4.x (GitHub Release, GDScript)
│ ├── kmp-iap/ # Kotlin Multiplatform (Maven Central)
│ └── maui-iap/ # .NET MAUI / C# (NuGet)
├── knowledge/ # Shared knowledge base (SSOT)
│ ├── internal/ # Project philosophy (HIGHEST PRIORITY)
│ ├── external/ # External API reference
│ └── _claude-context/ # Compiled context for Claude Code
├── scripts/
│ └── agent/ # RAG Agent scripts
└── .github/workflows/ # CI/CD workflows
Libraries reference local packages/apple and packages/google source directly (not published CocoaPods/Maven artifacts), enabling immediate development without waiting for native releases.
Purpose: Single source of truth for type definitions.
- Contains GraphQL schema defining all OpenIAP types
- Generates types for: TypeScript, Swift, Kotlin, Dart, GDScript, C#
- RULE:
Types.swift/Types.ktare AUTO-GENERATED. Never edit directly.
# Regenerate all types
cd packages/gql && bun run generateGenerated files:
- TypeScript:
src/generated/types.ts - Swift:
src/generated/Types.swift - Kotlin:
src/generated/Types.kt - Dart:
src/generated/types.dart - GDScript:
src/generated/types.gd - C#:
src/generated/Types.cs
Purpose: iOS/macOS StoreKit 2 implementation.
Directory structure:
Sources/
├── Models/ # Official OpenIAP types (matches openiap.dev/docs/types)
│ ├── Product.swift
│ ├── Purchase.swift
│ ├── ActiveSubscription.swift
│ └── Types.swift # AUTO-GENERATED - DO NOT EDIT
├── Helpers/ # Internal implementation (NOT public API)
│ ├── ProductManager.swift
│ └── IapStatus.swift
├── OpenIapModule.swift # Core implementation
├── OpenIapStore.swift # SwiftUI-friendly store
└── OpenIapProtocol.swift # API interface definitions
Purpose: Android Google Play Billing implementation.
Directory structure:
openiap/src/main/
├── java/dev/hyo/openiap/
│ ├── OpenIapModule.kt
│ ├── Models.kt
│ ├── Types.kt # AUTO-GENERATED - DO NOT EDIT
│ └── utils/ # Internal helpers
Purpose: Documentation site for openiap.dev.
- Built with React + Vite
- Deployed to Vercel
- Contains API reference and guides
┌─────────────┐
│ packages/ │
│ gql │ ──── Generates Types ────┐
└─────────────┘ │
▼
┌──────────────────────────┐
│ │
┌─────┴─────┐ ┌───────┴──────┐
│ packages/ │ │ packages/ │
│ apple │ │ google │
└───────────┘ └──────────────┘
// OpenIapModule.swift
public final class OpenIapModule: OpenIapProtocol {
public static let shared = OpenIapModule()
private init() {}
// All public methods here
public func fetchProducts(_ productIds: [String]) async throws -> [ProductIOS]
}// OpenIapModule.kt
class OpenIapModule private constructor(
private val context: Context
) {
companion object {
@Volatile
private var instance: OpenIapModule? = null
fun getInstance(context: Context): OpenIapModule {
return instance ?: synchronized(this) {
instance ?: OpenIapModule(context).also { instance = it }
}
}
}
}public enum OpenIapError: Error {
case notInitialized
case productNotFound(String)
case purchaseFailed(String)
case verificationFailed
}
// Usage
public func fetchProducts(_ ids: [String]) async throws -> [ProductIOS] {
guard isInitialized else {
throw OpenIapError.notInitialized
}
// ...
}sealed class OpenIapError : Exception() {
object NotInitialized : OpenIapError()
data class ProductNotFound(val productId: String) : OpenIapError()
data class PurchaseFailed(val message: String) : OpenIapError()
}// CORRECT - Use async/await
public func fetchProducts(_ ids: [String]) async throws -> [ProductIOS]
// INCORRECT - Don't use completion handlers
public func fetchProducts(_ ids: [String], completion: @escaping (Result<[ProductIOS], Error>) -> Void)// CORRECT - Use suspend functions
suspend fun fetchProducts(productIds: List<String>): List<ProductAndroid>
// INCORRECT - Don't use callbacks
fun fetchProducts(productIds: List<String>, callback: (List<ProductAndroid>) -> Unit)CRITICAL: All async/Promise-returning operations in the GraphQL schema MUST include # Future comment above the field definition.
The # Future comment tells the type generator to wrap the return type appropriately:
- TypeScript:
Promise<T> - Swift:
async - Kotlin:
suspend
"""
Check if a billing program is available for the current user
Returns availability result with isAvailable flag
"""
# Future
isBillingProgramAvailableAndroid(program: BillingProgramAndroid!): BillingProgramAvailabilityResultAndroid!Rule: If the operation makes network calls, accesses native APIs, or returns data asynchronously, it MUST have # Future comment.