UNPKG

@viss-develop/affiliate-sdk

Version:

React Native Affiliate SDK with AppsFlyer integration

421 lines (420 loc) 16.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.initAppsFlyer = exports.createCustomConversion = exports.createBuyConversion = exports.clearStoredAffiliateData = exports.getStoredInstallData = exports.getStoredCampaignId = exports.getStoredClickId = exports.getFromLocalStorage = void 0; // Dynamic imports to avoid React Native conflicts let appsFlyer = null; let AsyncStorage = null; // Import conversion service and types const conversionService_1 = __importDefault(require("./services/conversionService")); // Secure logging utility class SecureLogger { constructor() { this.isDebug = false; } setDebugMode(enabled) { this.isDebug = enabled; } maskSensitiveData(data) { if (!data) return data; const masked = Object.assign({}, data); // Mask sensitive keys const sensitiveKeys = ['devKey', 'apiToken', 'clickId', 'click_id', 'campaignId', 'campaign_id']; sensitiveKeys.forEach(key => { if (masked[key]) { masked[key] = typeof masked[key] === 'string' ? `${masked[key].substring(0, 4)}***${masked[key].substring(masked[key].length - 4)}` : '***'; } }); // Mask full response data if (masked.fullResponseData) { masked.fullResponseData = '[MASKED]'; } // Mask data object if (masked.data && typeof masked.data === 'object') { masked.data = '[MASKED_DATA]'; } return masked; } log(message, data) { if (data) { if (this.isDebug) { console.log(message, data); } else { console.log(message, this.maskSensitiveData(data)); } } else { console.log(message); } } error(message, error) { if (error) { if (this.isDebug) { console.error(message, error); } else { console.error(message, this.maskSensitiveData(error)); } } else { console.error(message); } } warn(message, data) { if (data) { if (this.isDebug) { console.warn(message, data); } else { console.warn(message, this.maskSensitiveData(data)); } } else { console.warn(message); } } } const logger = new SecureLogger(); // Initialize modules dynamically const initializeModules = async () => { if (!appsFlyer) { appsFlyer = require('react-native-appsflyer').default; } if (!AsyncStorage) { AsyncStorage = require('@react-native-async-storage/async-storage').default; } }; let conversionService = null; // Local storage keys const STORAGE_KEYS = { CLICK_ID: 'affiliate_click_id', CAMPAIGN_ID: 'affiliate_campaign_id', INSTALL_DATA: 'affiliate_install_data' }; // Helper function to save data to local storage const saveToLocalStorage = async (key, value) => { try { await AsyncStorage.setItem(key, String(value)); logger.log(`💾 Saved ${key} to local storage:`, value); } catch (error) { logger.error(`❌ Failed to save ${key} to local storage:`, error); } }; // Helper function to get data from local storage const getFromLocalStorage = async (key) => { try { const value = await AsyncStorage.getItem(key); logger.log(`📖 Retrieved ${key} from local storage:`, value); return value; } catch (error) { logger.error(`❌ Failed to get ${key} from local storage:`, error); return null; } }; exports.getFromLocalStorage = getFromLocalStorage; // Helper functions to get stored affiliate data const getStoredClickId = async () => { return await (0, exports.getFromLocalStorage)(STORAGE_KEYS.CLICK_ID); }; exports.getStoredClickId = getStoredClickId; const getStoredCampaignId = async () => { const value = await (0, exports.getFromLocalStorage)(STORAGE_KEYS.CAMPAIGN_ID); return value ? Number(value) : null; }; exports.getStoredCampaignId = getStoredCampaignId; const getStoredInstallData = async () => { try { const data = await (0, exports.getFromLocalStorage)(STORAGE_KEYS.INSTALL_DATA); return data ? JSON.parse(data) : null; } catch (error) { logger.error('❌ Failed to parse stored install data:', error); return null; } }; exports.getStoredInstallData = getStoredInstallData; // Helper function to clear stored affiliate data const clearStoredAffiliateData = async () => { try { await AsyncStorage.multiRemove([ STORAGE_KEYS.CLICK_ID, STORAGE_KEYS.CAMPAIGN_ID, STORAGE_KEYS.INSTALL_DATA ]); logger.log('🗑️ Cleared stored affiliate data'); } catch (error) { logger.error('❌ Failed to clear stored affiliate data:', error); } }; exports.clearStoredAffiliateData = clearStoredAffiliateData; // Updated Buy Conversion function that uses stored data with optional parameters const createBuyConversion = async (orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts) => { try { // Initialize modules first await initializeModules(); // Check if conversion service is initialized if (!conversionService) { const errorMsg = 'Conversion service not initialized. Please call initAppsFlyer first.'; console.error('❌ Buy Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } // Get clickId and campaignId from local storage const clickId = await (0, exports.getStoredClickId)(); const campaignId = await (0, exports.getStoredCampaignId)(); if (!clickId || !campaignId) { const errorMsg = 'No stored clickId or campaignId found. Please ensure AppsFlyer has been initialized and install data received.'; console.error('❌ Buy Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } logger.log('🛒 Creating Buy Conversion with stored data:', { clickId, campaignId, orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts }); // Create conversion request with stored data and optional parameters const conversionRequest = { clickId, campaignId: campaignId, action: 'buy', orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts }; const result = await conversionService.createConversion(conversionRequest); logger.log('✅ Buy Conversion created successfully:', result); return { success: true, error: null, data: result }; } catch (error) { const errorMsg = error instanceof Error ? error.message : 'Unknown error occurred'; logger.error('❌ Buy Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } }; exports.createBuyConversion = createBuyConversion; // Updated Custom Conversion function that gets clickId and campaignId from SDK if not provided const createCustomConversion = async (clickId, campaignId, action, orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts) => { try { // Initialize modules first await initializeModules(); // Check if conversion service is initialized if (!conversionService) { const errorMsg = 'Conversion service not initialized. Please call initAppsFlyer first.'; logger.error('❌ Custom Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } // Validate required parameters if (!clickId || !campaignId) { const errorMsg = 'clickId and campaignId are required. Either provide them as parameters or ensure AppsFlyer has been initialized and install data received.'; logger.error('❌ Custom Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } logger.log('🎯 Creating Custom Conversion:', { clickId: clickId, campaignId: campaignId, action, orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts, source: clickId ? 'parameter' : 'sdk' }); // Create conversion request with provided data and optional parameters const conversionRequest = { clickId: clickId, campaignId: campaignId, action, orderId, actionTime, totalDiscount, totalSaleAmount, totalCommission, clientIp, userAgent, conversionParts }; const result = await conversionService.createConversion(conversionRequest); logger.log('✅ Custom Conversion created successfully:', result); return { success: true, error: null, data: result }; } catch (error) { const errorMsg = error instanceof Error ? error.message : 'Unknown error occurred'; logger.error('❌ Custom Conversion failed:', errorMsg); return { success: false, error: errorMsg, data: null }; } }; exports.createCustomConversion = createCustomConversion; const initAppsFlyer = async (config) => { try { // Initialize modules first await initializeModules(); // Initialize conversion service with API token conversionService = new conversionService_1.default(undefined, config.apiToken); // Set debug mode for logger logger.setDebugMode(config.isDebug || false); logger.log('🚀 Initializing AppsFlyer with config:', { devKey: config.devKey, appId: config.appId, isDebug: config.isDebug }); appsFlyer.initSdk({ devKey: config.devKey, isDebug: config.isDebug || true, appId: config.appId, onInstallConversionDataListener: true, onDeepLinkListener: true, }, (result) => { logger.log('✅ AppsFlyer initialized successfully:', result); }, (error) => { logger.error('❌ AppsFlyer init failed:', error); }); // Set up install conversion data listener appsFlyer.onInstallConversionData((res) => { const msg = `onInstallConversionData: ${JSON.stringify(res)}`; logger.log(msg); if (res != null && typeof res === 'object') { const status = res.status; const data = res.data; logger.log('📊 Install Conversion Data Details:', { status, data, fullResponseData: res, keys: Object.keys(res) }); // Handle the correct structure where data is directly in res.data if (data && typeof data === 'object') { const afStatus = data.af_status; const isFirstLaunch = data.is_first_launch; const clickId = data.click_id; // Note: it's click_id, not clickId const campaignId = data.campaign_id ? Number(data.campaign_id) : null; // Convert to number logger.log('🔍 Parsed Data:', { status, afStatus, isFirstLaunch, clickId, campaignId, data }); // Call the callback if provided if (config.onInstallConversionData) { config.onInstallConversionData(Object.assign({ status, data: data }, res)); } let isOrganic = afStatus === 'Organic'; // Handle first launch if (isFirstLaunch && !isOrganic) { // Save clickId and campaignId to local storage if available logger.log('🚀 First launch detected!'); // Auto-create conversion if clickId and campaignId are available if (clickId && campaignId && conversionService) { logger.log('🔄 Auto-creating conversion for install...'); conversionService.createConversion({ clickId, campaignId, action: 'install' }).then((result) => { if (result.success) { logger.log('💾 Saving clickId and campaignId to local storage...'); saveToLocalStorage(STORAGE_KEYS.CLICK_ID, clickId); saveToLocalStorage(STORAGE_KEYS.CAMPAIGN_ID, campaignId); // Also save the full install data for reference saveToLocalStorage(STORAGE_KEYS.INSTALL_DATA, JSON.stringify(data)); logger.log('✅ Auto-conversion created successfully:', result); } else { logger.error('❌ Auto-conversion failed:', result.error); } }).catch((error) => { logger.error('❌ Auto-conversion error:', error); }); } else { logger.warn('⚠️ Missing required data for auto-conversion:'); logger.log('🔍 Available fields:', { click_id: clickId, campaign_id: campaignId, af_status: afStatus, is_first_launch: isFirstLaunch }); if (!clickId) logger.warn('❌ click_id is missing'); if (!campaignId) logger.warn('❌ campaign_id is missing or null'); } } else if (isOrganic) { logger.log('🌱 Organic install detected, skipping auto-conversion'); } else if (!isFirstLaunch) { logger.log('🔄 Not first launch, skipping auto-conversion'); logger.log('📊 Install details:', { click_id: clickId, campaign_id: campaignId, af_status: afStatus, is_first_launch: isFirstLaunch, media_source: data.media_source, campaign: data.campaign }); } } else { logger.warn('⚠️ Could not find conversion data in res.data'); logger.log('🔍 Available keys in response:', Object.keys(res)); logger.log('🔍 Full response structure:', JSON.stringify(res, null, 2)); } } else { logger.warn('⚠️ Received invalid install conversion data:', res); } }); } catch (error) { logger.error('❌ AppsFlyer initialization failed:', error); throw error; } }; exports.initAppsFlyer = initAppsFlyer;