@vibecoding-official/purchases
v1.0.0
Published
VibeCoding Purchases SDK for React Native and Expo apps
Maintainers
Readme
@vibecoding/purchases
A React Native and Expo SDK for VibeCoding's in-app purchase and subscription management system.
Features
- ✅ Cross-platform support (iOS, Android, Web)
- ✅ React Native and Expo compatibility (including Expo Go detection)
- ✅ TypeScript support with full type definitions
- ✅ React hooks for easy integration
- ✅ Automatic receipt validation
- ✅ Subscription management
- ✅ Customer info synchronization
- ✅ Error handling and retry logic
- ✅ Platform-aware purchase handling
- ✅ Expo IAP integration for development builds
- ✅ Provider pattern for React applications
Installation
npm
npm install @vibecoding/purchasesyarn
yarn add @vibecoding/purchasespnpm
pnpm add @vibecoding/purchasesAdditional Dependencies
For React Native projects, you'll also need:
npm install react-native-iapFor Expo projects, you'll also need:
expo install expo-iap expo-constantsQuick Start
1. Using React Provider (Recommended)
import { VibeCodingPurchasesProvider, useVibeCodingPurchases } from '@vibecoding/purchases';
// Wrap your app with the provider
function App() {
const config = {
apiKey: "your-api-key",
projectId: "your-project-id",
environment: "production", // or 'development'
baseUrl: "https://your-api-url.com" // optional
};
return (
<VibeCodingPurchasesProvider
config={config}
appUserId="user-123" // optional, for automatic login
>
<YourAppContent />
</VibeCodingPurchasesProvider>
);
}
// Use the hook in your components
function SubscriptionScreen() {
const {
customerInfo,
offerings,
isLoading,
error,
purchasePackage,
purchase, // simplified purchase by package ID
hasEntitlement,
login,
logOut,
canMakePurchases,
isExpoGo
} = useVibeCodingPurchases();
const handlePurchase = async (packageToPurchase) => {
try {
const result = await purchasePackage(packageToPurchase);
console.log('Purchase successful:', result);
} catch (error) {
console.error('Purchase failed:', error);
}
};
const handleSimplePurchase = async (packageId) => {
try {
await purchase(packageId); // Purchase by package ID
console.log('Purchase successful');
} catch (error) {
console.error('Purchase failed:', error);
}
};
if (isLoading) {
return <Text>Loading...</Text>;
}
if (isExpoGo) {
return <Text>Purchases not supported in Expo Go. Use a development build.</Text>;
}
return (
<View>
<Text>Premium Active: {hasEntitlement('premium') ? 'Yes' : 'No'}</Text>
<Text>Can Make Purchases: {canMakePurchases ? 'Yes' : 'No'}</Text>
{offerings?.offerings.current && Object.values(offerings.offerings.current).map((offering) => (
offering.availablePackages.map((pkg) => (
<Button
key={pkg.identifier}
title={`Buy ${pkg.identifier} - ${pkg.product.price} ${pkg.product.currency}`}
onPress={() => handlePurchase(pkg)}
/>
))
))}
</View>
);
}2. Direct SDK Usage
import { VibeCodingPurchases } from "@vibecoding/purchases";
// Configure the SDK
const purchases = VibeCodingPurchases.configure({
apiKey: "your-api-key",
projectId: "your-project-id",
environment: "production",
});
// Login a user
const { customerInfo, created } = await purchases.logIn("user-123");
// Get available offerings
const offerings = await purchases.getOfferings();
// Get customer info
const customerInfo = await purchases.getCustomerInfo();
// Make a purchase using static method
const result = await VibeCodingPurchases.purchase("monthly_premium");
// Check if user is anonymous
const isAnonymous = VibeCodingPurchases.isAnonymous();
// Get current user ID
const userId = VibeCodingPurchases.getUserId();
// Log out
await VibeCodingPurchases.logOut();3. Initialize Method (Alternative)
import { VibeCodingPurchases } from "@vibecoding/purchases";
// Initialize with configuration and optional user
const purchases = await VibeCodingPurchases.initialize({
apiKey: "your-api-key",
projectId: "your-project-id",
environment: "production",
appUserId: "user-123", // optional
});API Reference
Configuration
interface VibeCodingPurchasesConfiguration {
apiKey: string;
projectId: string;
baseUrl?: string;
environment?: "production" | "development";
}Main Methods
Static Methods
VibeCodingPurchases.configure(config)
Configure the SDK with your API credentials. Returns a VibeCodingPurchases instance.
VibeCodingPurchases.initialize(config & { appUserId?: string })
Initialize the SDK with configuration and optional user login.
VibeCodingPurchases.isAnonymous()
Check if the current user is anonymous.
VibeCodingPurchases.getUserId()
Get the current app user ID.
VibeCodingPurchases.purchase(packageId)
Purchase a product by package ID (static convenience method).
VibeCodingPurchases.logOut()
Log out the current user (static method).
Instance Methods
purchases.logIn(appUserId)
Log in a specific user. Returns { customerInfo, created }.
purchases.getCustomerInfo()
Get current customer information and entitlements.
purchases.getOfferings(provider?)
Fetch available products and subscriptions. Optional provider parameter ("apple" | "google").
purchases.purchasePackage(package)
Purchase a product or subscription using a Package object.
purchases.restorePurchases()
Restore previous purchases (iOS primarily).
purchases.getCurrentAppUserId()
Get the current app user ID.
purchases.getCachedCustomerInfo()
Get cached customer information without making a network request.
purchases.isAnonymous()
Check if the current user is anonymous.
purchases.addCustomerInfoUpdateListener(listener)
Add a listener for customer info updates. Returns listener ID.
purchases.removeCustomerInfoUpdateListener(listenerId)
Remove a customer info update listener.
React Hooks
useVibeCodingPurchases()
Main hook providing access to purchases functionality.
const {
// State
customerInfo,
offerings,
isLoading,
error,
purchaseInProgress,
userId,
// Platform info
isExpoGo,
canMakePurchases,
// Methods
login,
logOut,
purchasePackage,
purchase, // simplified purchase by package ID
restorePurchases,
getOfferings,
refreshCustomerInfo,
// Utility methods
hasEntitlement,
isPurchasing,
isAnonymous,
} = useVibeCodingPurchases();useEntitlement(entitlementId)
Hook for checking a specific entitlement.
const {
isActive,
productIdentifier,
expirationDate,
purchaseDate,
identifier,
} = useEntitlement("premium");useSubscriptionStatus()
Hook for subscription status information.
const { hasActiveSubscription, activeSubscriptions, allEntitlements } =
useSubscriptionStatus();Types
The SDK exports comprehensive TypeScript types:
CustomerInfo- Customer subscription and entitlement informationOffering- Available products grouped by offeringOfferingsResponse- Complete offerings response structurePackage- Individual purchasable packageProduct- Product information (price, currency, identifier)Entitlement- Individual entitlement with status and datesLoginResponse- Response from login API callPurchaseResponse- Response from purchase API callVibeCodingPurchasesConfiguration- SDK configuration interfaceVibeCodingPurchasesError- Custom error classVibeCodingPurchasesErrorCode- Error code enumUseVibeCodingPurchasesResult- Hook return typeReactNativeIAPPurchase- React Native IAP purchase interface
Error Handling
The SDK includes comprehensive error handling:
import {
VibeCodingPurchasesError,
VibeCodingPurchasesErrorCode,
} from "@vibecoding/purchases";
try {
await VibeCodingPurchases.purchase("monthly_premium");
} catch (error) {
if (error instanceof VibeCodingPurchasesError) {
switch (error.code) {
case VibeCodingPurchasesErrorCode.PURCHASE_CANCELLED_ERROR:
console.log("User cancelled the purchase");
break;
case VibeCodingPurchasesErrorCode.NETWORK_ERROR:
console.log("Network error occurred");
break;
case VibeCodingPurchasesErrorCode.PLATFORM_NOT_SUPPORTED_ERROR:
console.log("Platform not supported for purchases");
break;
case VibeCodingPurchasesErrorCode.USER_NOT_LOGGED_IN_ERROR:
console.log("User needs to be logged in");
break;
case VibeCodingPurchasesErrorCode.CONFIGURATION_ERROR:
console.log("SDK configuration error");
break;
case VibeCodingPurchasesErrorCode.PURCHASE_IN_PROGRESS_ERROR:
console.log("Another purchase is already in progress");
break;
case VibeCodingPurchasesErrorCode.PRODUCT_NOT_AVAILABLE_ERROR:
console.log("Product not available");
break;
// Handle other error codes...
}
}
}Available Error Codes
UNKNOWN_ERROR- Unknown error occurredPURCHASE_CANCELLED_ERROR- User cancelled the purchaseSTORE_PROBLEM_ERROR- Store/platform errorNETWORK_ERROR- Network connectivity issueINVALID_CREDENTIALS_ERROR- Invalid API credentialsINVALID_APP_USER_ID_ERROR- Invalid user ID providedCONFIGURATION_ERROR- SDK configuration issueUSER_NOT_LOGGED_IN_ERROR- User needs to be logged inRECEIPT_VALIDATION_ERROR- Receipt validation failedPURCHASE_IN_PROGRESS_ERROR- Another purchase is in progressPRODUCT_NOT_AVAILABLE_ERROR- Product not found or unavailablePLATFORM_NOT_SUPPORTED_ERROR- Platform doesn't support purchases
Platform Support
- iOS: Full support via App Store (uses expo-iap in Expo development builds)
- Android: Full support via Google Play (uses expo-iap in Expo development builds)
- Web: Limited support - redirects to web-based checkout (Stripe)
- Expo Go: Not supported - displays helpful error messages and guidance
- React Native: Full support with react-native-iap integration
Platform Detection
The SDK automatically detects the platform and adjusts behavior accordingly:
import {
getPlatform,
isExpo,
isExpoGo,
isReactNative,
} from "@vibecoding/purchases";
const platform = getPlatform(); // "ios" | "android" | "web"
const isExpoEnvironment = isExpo(); // boolean
const isRunningInExpoGo = isExpoGo(); // boolean
const isReactNativeApp = isReactNative(); // booleanAdvanced Usage
Direct API Client Access
For advanced use cases, you can access the API client directly:
import { VibeCodingPurchases } from "@vibecoding/purchases";
const purchases = VibeCodingPurchases.getSharedInstance();
const apiClient = purchases.apiClient;
// Make direct API calls
const customerInfo = await apiClient.getCustomerInfo("user-123");
const offerings = await apiClient.getOfferings("apple");
const loginResult = await apiClient.login("user-123");
const purchaseResult = await apiClient.processPurchase(
"user-123",
"product-id",
"receipt-data",
"transaction-id" // optional, iOS only
);React Native Specific Exports
For React Native projects, there are additional convenience exports:
import {
initializeVibeCodingPurchases,
usePurchases, // alias for useVibeCodingPurchases
} from "@vibecoding/purchases/react-native";
// Initialize with React Native defaults
const purchases = await initializeVibeCodingPurchases(
{
apiKey: "your-key",
projectId: "your-project",
},
"user-123" // optional auto-login
);Convenience SDK Export
The SDK also exports a convenience object with static methods:
import { VibeCodingPurchasesSDK } from "@vibecoding/purchases";
// All static methods available
const purchases = VibeCodingPurchasesSDK.configure(config);
const instance = VibeCodingPurchasesSDK.getSharedInstance();
await VibeCodingPurchasesSDK.initialize(config);
const isAnon = VibeCodingPurchasesSDK.isAnonymous();
const userId = VibeCodingPurchasesSDK.getUserId();
await VibeCodingPurchasesSDK.purchase("package-id");
await VibeCodingPurchasesSDK.logOut();Development
Building the Package
# Install dependencies
npm install
# Build the package
npm run build
# Watch for changes during development
npm run devTesting
npm testLinting
npm run lint
npm run lint:fixContributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
License
This project is licensed under the MIT License - see the LICENSE file for details.
Support
For support, email [email protected] or create an issue in the GitHub repository.
