@viss-develop/affiliate-sdk
Version:
React Native Affiliate SDK with AppsFlyer integration
466 lines (383 loc) • 13.6 kB
Markdown
# React Native Affiliate SDK
A React Native SDK for tracking affiliate conversions with AppsFlyer integration and enterprise-grade security.
## Features
- ✅ **AppsFlyer Integration**: Automatic install conversion tracking
- ✅ **Buy Conversion**: Create buy conversions using stored clickId and campaignId
- ✅ **Custom Conversion**: Create custom conversions with explicit clickId and campaignId
- ✅ **Local Storage**: Automatic storage and retrieval of affiliate data
- ✅ **TypeScript Support**: Full type definitions included
- ✅ **Optional Parameters**: Support for detailed conversion data (orderId, amounts, conversion parts, etc.)
- ✅ **Enterprise Security**: Production-safe logging with automatic data masking
- ✅ **Debug Mode Control**: Separate logging behavior for development and production
## Installation
```bash
npm install @viss-develop/affiliate-sdk
```
## Quick Start
### 1. Initialize AppsFlyer
```javascript
import { initAppsFlyer } from '@viss-develop/affiliate-sdk';
// Development (with secure logging)
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: true, // Shows masked logs for debugging
onInstallConversionData: (data) => {
console.log('📱 Install Conversion Data received:', data);
if (data.status === 'success') {
console.log('✅ Install conversion data success');
const conversionData = data.data;
if (conversionData) {
if (conversionData.is_first_launch) {
console.log('🎉 First launch detected!');
}
// Check if auto-conversion was triggered
if (conversionData.click_id && conversionData.campaign_id) {
console.log('🔄 Auto-conversion triggered for install');
}
}
}
}
});
// Production (no sensitive data logged)
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: false, // No logs, maximum security
onInstallConversionData: (data) => {
// Handle conversion data
}
});
```
### 2. Create Buy Conversion
```javascript
import { createBuyConversion } from '@viss-develop/affiliate-sdk';
// Simple buy conversion using stored data
const handleSimpleBuyConversion = async () => {
try {
const result = await createBuyConversion();
if (result.success) {
console.log('✅ Buy conversion created:', result.data);
} else {
console.error('❌ Buy conversion failed:', result.error);
}
} catch (error) {
console.error('❌ Unexpected error:', error);
}
};
// Buy conversion with optional data
const handleBuyConversionWithData = async () => {
try {
const result = await createBuyConversion(
'ord.001', // orderId
Date.now(), // actionTime
{ amount: 10000, currency: 'VND' }, // totalDiscount
{ amount: 100000, currency: 'VND' }, // totalSaleAmount
{ amount: 5000, currency: 'VND' }, // totalCommission
'192.168.1.1', // clientIp
'React Native App', // userAgent
[ // conversionParts
{
sku: 'product_001',
url: 'https://example.com/product/001',
price: 100000,
discount: 10000,
saleAmount: 90000,
currency: 'VND',
name: 'Sample Product',
categoryName: 'Electronics',
categoryId: 'cat_001',
quantity: 1,
commission: {
amount: 5000,
currency: 'VND'
},
calculateBy: 'FIXED'
}
]
);
if (result.success) {
console.log('✅ Buy conversion with data created:', result.data);
} else {
console.error('❌ Buy conversion with data failed:', result.error);
}
} catch (error) {
console.error('❌ Unexpected error:', error);
}
};
```
### 3. Create Custom Conversion
```javascript
import { createCustomConversion, getStoredClickId, getStoredCampaignId } from '@viss-develop/affiliate-sdk';
// Custom conversion using stored data
const handleCustomConversionFromStored = async () => {
try {
// Get stored clickId and campaignId first
const storedClickId = await getStoredClickId();
const storedCampaignId = await getStoredCampaignId();
if (!storedClickId || !storedCampaignId) {
console.error('❌ No stored clickId or campaignId found');
return;
}
// Use stored data for custom conversion
const result = await createCustomConversion(
storedClickId, // use stored clickId
storedCampaignId, // use stored campaignId
'buy', // action
'stored_ord.001', // orderId
Date.now(), // actionTime
undefined, // totalDiscount
{ amount: 75000, currency: 'VND' }, // totalSaleAmount
{ amount: 3750, currency: 'VND' }, // totalCommission
undefined, // clientIp
undefined, // userAgent
[ // conversionParts
{
sku: 'registration_success',
url: 'https://example.com/register',
price: 0,
discount: 0,
saleAmount: 0,
currency: 'VND',
name: 'User Registration',
categoryName: 'Registration',
categoryId: 'reg_001',
quantity: 1,
commission: {
amount: 10000,
currency: 'VND'
},
calculateBy: 'FIXED'
}
]
);
if (result.success) {
console.log('✅ Custom conversion with stored data created:', result.data);
} else {
console.error('❌ Custom conversion with stored data failed:', result.error);
}
} catch (error) {
console.error('❌ Unexpected error:', error);
}
};
// Custom conversion with explicit values
const handleCustomConversionExplicit = async () => {
try {
const result = await createCustomConversion(
'GKbQfVgyCIFkTvVmZHyMPOTpKLHGkE', // clickId (required)
9, // campaignId (required)
'register', // action
'custom_ord.001', // orderId
Date.now(), // actionTime
undefined, // totalDiscount
{ amount: 0, currency: 'VND' }, // totalSaleAmount
{ amount: 10000, currency: 'VND' }, // totalCommission
undefined, // clientIp
undefined, // userAgent
undefined // conversionParts
);
if (result.success) {
console.log('✅ Custom conversion with explicit values created:', result.data);
} else {
console.error('❌ Custom conversion with explicit values failed:', result.error);
}
} catch (error) {
console.error('❌ Unexpected error:', error);
}
};
```
### 4. Get Stored Data
```javascript
import { getStoredClickId, getStoredCampaignId, getStoredInstallData } from '@viss-develop/affiliate-sdk';
const handleGetStoredData = async () => {
try {
const clickId = await getStoredClickId();
const campaignId = await getStoredCampaignId();
const installData = await getStoredInstallData();
console.log('📊 Stored Data:', {
clickId: clickId || 'Not found',
campaignId: campaignId || 'Not found',
installData: installData || 'Not found'
});
} catch (error) {
console.error('❌ Failed to get stored data:', error);
}
};
```
## Security Features
The SDK includes enterprise-grade security with automatic data masking and production-safe logging.
### Data Masking
Sensitive information is automatically masked in logs:
```javascript
// Before: "abc123def456"
// After: "abc1***def4"
// Masked keys:
- devKey → "abc1***def4"
- apiToken → "tok1***ken4"
- clickId → "cli1***id4"
- campaignId → "***"
```
### Debug Mode Control
```javascript
// Development (debug on) - Shows masked logs
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: true // ✅ Shows masked logs for debugging
});
// Production (debug off) - No sensitive data logged
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: false // ✅ No logs, maximum security
});
```
## API Reference
### `initAppsFlyer(config)`
Initialize AppsFlyer SDK and store affiliate data.
**Parameters:**
- `config` (AppsFlyerConfig): Configuration object
- `devKey` (string): AppsFlyer dev key
- `appId` (string): App ID (iOS) or package name (Android)
- `apiToken` (string): API token for conversion service
- `isDebug` (boolean): Enable/disable debug logging (default: false)
- `onInstallConversionData` (function): Callback for install conversion data
### `createBuyConversion(orderId?, actionTime?, totalDiscount?, totalSaleAmount?, totalCommission?, clientIp?, userAgent?, conversionParts?)`
Create buy conversion using stored clickId and campaignId.
**Parameters:**
- `orderId` (string, optional): Order ID
- `actionTime` (number, optional): Action timestamp
- `totalDiscount` (MonetaryAmount, optional): Total discount
- `totalSaleAmount` (MonetaryAmount, optional): Total sale amount
- `totalCommission` (MonetaryAmount, optional): Total commission
- `clientIp` (string, optional): Client IP address
- `userAgent` (string, optional): User agent string
- `conversionParts` (ConversionPart[], optional): Conversion parts array
**Returns:** Promise with result object
```javascript
{
success: boolean,
data?: any,
error?: string
}
```
### `createCustomConversion(clickId, campaignId, action?, orderId?, actionTime?, totalDiscount?, totalSaleAmount?, totalCommission?, clientIp?, userAgent?, conversionParts?)`
Create custom conversion with explicit clickId and campaignId.
**Parameters:**
- `clickId` (string, required): Click ID from affiliate link
- `campaignId` (number, required): Campaign ID
- `action` (string, optional): Action type (default: 'buy')
- `orderId` (string, optional): Order ID
- `actionTime` (number, optional): Action timestamp
- `totalDiscount` (MonetaryAmount, optional): Total discount
- `totalSaleAmount` (MonetaryAmount, optional): Total sale amount
- `totalCommission` (MonetaryAmount, optional): Total commission
- `clientIp` (string, optional): Client IP address
- `userAgent` (string, optional): User agent string
- `conversionParts` (ConversionPart[], optional): Conversion parts array
**Returns:** Promise with result object (same as createBuyConversion)
### `getStoredClickId()`
Get stored clickId from local storage.
**Returns:** Promise<string | null>
### `getStoredCampaignId()`
Get stored campaignId from local storage.
**Returns:** Promise<number | null>
### `getStoredInstallData()`
Get stored install data from local storage.
**Returns:** Promise<InstallConversionData | null>
### `clearStoredAffiliateData()`
Clear all stored affiliate data.
**Returns:** Promise<void>
## Types
### `MonetaryAmount`
```typescript
interface MonetaryAmount {
amount: number;
currency: string;
}
```
### `ConversionPart`
```typescript
interface ConversionPart {
sku?: string;
url?: string;
price?: number;
discount?: number;
saleAmount?: number;
currency?: string;
name?: string;
categoryName?: string;
categoryId?: string;
quantity?: number;
commission?: MonetaryAmount;
calculateBy?: string;
}
```
### `InstallConversionData`
```typescript
interface InstallConversionData {
af_status: string;
is_first_launch: boolean;
click_id?: string;
campaign_id?: number;
media_source?: string;
campaign?: string;
// ... other AppsFlyer data
}
```
## How it works
1. **Initialization**: AppsFlyer is initialized with dev key and app ID
2. **Data Storage**: When install conversion data is received, clickId and campaignId are stored locally
3. **Buy Conversion**: Uses stored data to create buy conversions
4. **Custom Conversion**: Uses explicit clickId and campaignId or retrieves from storage
5. **Security**: All sensitive data is automatically masked in logs
6. **Optional Data**: All functions support optional parameters like orderId, amounts, conversion parts, etc.
## Example App
A complete demo app is included in the `example/` directory with the following features:
- **Create Buy Conversion (Simple)**: Create buy conversion with stored data
- **Create Buy Conversion (With Data)**: Create buy conversion with optional parameters
- **Create Custom Conversion (From Stored)**: Create custom conversion using stored data
- **Get Stored Data**: View stored data in the SDK
### Run Example App
```bash
cd example
npm install
npx react-native run-ios
# or
npx react-native run-android
```
## Security
The SDK includes production-safe logging with automatic data masking. Sensitive information like `devKey`, `apiToken`, `clickId`, and `campaignId` are automatically masked in logs.
### Production Usage
```javascript
// For production - no sensitive data logged
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: false // ✅ No sensitive data exposure
});
```
### Development Usage
```javascript
// For development - sensitive data masked
await initAppsFlyer({
devKey: 'your-dev-key',
appId: 'your-app-id',
apiToken: 'your-api-token',
isDebug: true // ✅ Shows masked logs: "abc1***def4"
});
```
For detailed security information, see [SECURITY.md](./SECURITY.md).
## Example Usage
See `example-usage-with-optional-data.js` for complete usage examples with all optional parameters.
## Version History
- **v1.0.3**: Added enterprise security with automatic data masking
- **v1.0.2**: Flattened API parameters, improved TypeScript types
- **v1.0.1**: Initial release with basic functionality
## License
MIT License