insert-affiliate-react-native-sdk 1.12.0 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -56,6 +56,7 @@ const ASYNC_KEYS = {
56
56
  AFFILIATE_STORED_DATE: '@app_affiliate_stored_date',
57
57
  SDK_INIT_REPORTED: '@app_sdk_init_reported',
58
58
  REPORTED_AFFILIATE_ASSOCIATIONS: '@app_reported_affiliate_associations',
59
+ SYSTEM_INFO_SENT: '@app_system_info_sent',
59
60
  };
60
61
  // STARTING CONTEXT IMPLEMENTATION
61
62
  exports.DeepLinkIapContext = (0, react_1.createContext)({
@@ -151,12 +152,20 @@ const DeepLinkIapProvider = ({ children, }) => {
151
152
  }
152
153
  }
153
154
  if (insertLinksEnabledParam && react_native_1.Platform.OS === 'ios') {
154
- try {
155
- const enhancedSystemInfo = yield getEnhancedSystemInfo();
156
- yield sendSystemInfoToBackend(enhancedSystemInfo);
157
- }
158
- catch (error) {
159
- verboseLog(`Error sending system info for clipboard check: ${error}`);
155
+ const systemInfoSent = yield getValueFromAsync(ASYNC_KEYS.SYSTEM_INFO_SENT);
156
+ verboseLog(`System info sent flag: ${systemInfoSent ? 'true (skipping)' : 'false (will send)'}`);
157
+ if (!systemInfoSent) {
158
+ // Set flag immediately to prevent concurrent init calls from sending twice
159
+ yield saveValueInAsync(ASYNC_KEYS.SYSTEM_INFO_SENT, 'pending');
160
+ try {
161
+ const enhancedSystemInfo = yield getEnhancedSystemInfo();
162
+ yield sendSystemInfoToBackend(enhancedSystemInfo);
163
+ }
164
+ catch (error) {
165
+ // Remove flag on failure so it retries next launch
166
+ yield async_storage_1.default.removeItem(ASYNC_KEYS.SYSTEM_INFO_SENT);
167
+ verboseLog(`Error sending system info for clipboard check: ${error}`);
168
+ }
160
169
  }
161
170
  }
162
171
  });
@@ -561,14 +570,7 @@ const DeepLinkIapProvider = ({ children, }) => {
561
570
  }
562
571
  // If URL scheme is used, we can straight away store the short code as the referring link
563
572
  yield storeInsertAffiliateIdentifier({ link: shortCode, source: 'deep_link_ios' });
564
- // Collect and send enhanced system info to backend
565
- try {
566
- const enhancedSystemInfo = yield getEnhancedSystemInfo();
567
- yield sendSystemInfoToBackend(enhancedSystemInfo);
568
- }
569
- catch (error) {
570
- verboseLog(`Error sending system info for deep link: ${error}`);
571
- }
573
+ // System info not needed here - affiliate code already received via URL scheme
572
574
  return true;
573
575
  }
574
576
  catch (error) {
@@ -1162,6 +1164,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1162
1164
  }
1163
1165
  // Check for a successful response
1164
1166
  if (response.status >= 200 && response.status <= 299) {
1167
+ yield saveValueInAsync(ASYNC_KEYS.SYSTEM_INFO_SENT, 'true');
1165
1168
  verboseLog('System info sent successfully');
1166
1169
  }
1167
1170
  else {
@@ -1182,7 +1185,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1182
1185
  const isValidCharacters = /^[a-zA-Z0-9_]+$/.test(referringLink);
1183
1186
  return isValidCharacters && referringLink.length >= 3 && referringLink.length <= 25;
1184
1187
  };
1185
- const checkAffiliateExists = (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1188
+ const checkAffiliateExists = (affiliateCode_1, ...args_1) => __awaiter(void 0, [affiliateCode_1, ...args_1], void 0, function* (affiliateCode, trackUsage = false) {
1186
1189
  try {
1187
1190
  const activeCompanyCode = yield getActiveCompanyCode();
1188
1191
  if (!activeCompanyCode) {
@@ -1194,6 +1197,9 @@ const DeepLinkIapProvider = ({ children, }) => {
1194
1197
  companyId: activeCompanyCode,
1195
1198
  affiliateCode: affiliateCode
1196
1199
  };
1200
+ if (trackUsage) {
1201
+ payload.trackUsage = true;
1202
+ }
1197
1203
  verboseLog(`Checking if affiliate exists: ${affiliateCode}`);
1198
1204
  const response = yield axios_1.default.post(url, payload, {
1199
1205
  headers: {
@@ -1267,7 +1273,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1267
1273
  const capitalisedShortCode = shortCode.toUpperCase();
1268
1274
  isShortCode(capitalisedShortCode);
1269
1275
  // Check if the affiliate exists before storing
1270
- const exists = yield checkAffiliateExists(capitalisedShortCode);
1276
+ const exists = yield checkAffiliateExists(capitalisedShortCode, true);
1271
1277
  if (exists) {
1272
1278
  // If affiliate exists, set the Insert Affiliate Identifier
1273
1279
  yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode, source: 'short_code_manual' });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insert-affiliate-react-native-sdk",
3
- "version": "1.12.0",
3
+ "version": "1.14.0",
4
4
  "description": "A package for connecting with the Insert Affiliate Platform to add app based affiliate marketing.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -1011,6 +1011,29 @@ const rawIdentifier = await returnInsertAffiliateIdentifier(true);
1011
1011
 
1012
1012
  </details>
1013
1013
 
1014
+ ### Prevent Affiliate Transfer
1015
+
1016
+ By default, clicking a new affiliate link will overwrite any existing attribution. Enable `preventAffiliateTransfer` to lock the first affiliate:
1017
+
1018
+ ```javascript
1019
+ initialize(
1020
+ "YOUR_COMPANY_CODE",
1021
+ false, // verboseLogging
1022
+ false, // insertLinksEnabled
1023
+ false, // insertLinksClipboardEnabled
1024
+ 604800, // affiliateAttributionActiveTime (7 days)
1025
+ true // preventAffiliateTransfer - locks first affiliate
1026
+ );
1027
+ ```
1028
+
1029
+ **How it works:**
1030
+ - When enabled, once a user is attributed to an affiliate, that attribution is locked
1031
+ - New affiliate links will not overwrite the existing attribution
1032
+ - The callback still fires with the existing affiliate data (not the new one)
1033
+ - Useful for preventing "affiliate stealing" where users click competitor links
1034
+
1035
+ Learn more: [Prevent Affiliate Transfer Documentation](https://docs.insertaffiliate.com/prevent-affiliate-transfer)
1036
+
1014
1037
  ---
1015
1038
 
1016
1039
  ## 🔍 Troubleshooting
@@ -83,6 +83,7 @@ const ASYNC_KEYS = {
83
83
  AFFILIATE_STORED_DATE: '@app_affiliate_stored_date',
84
84
  SDK_INIT_REPORTED: '@app_sdk_init_reported',
85
85
  REPORTED_AFFILIATE_ASSOCIATIONS: '@app_reported_affiliate_associations',
86
+ SYSTEM_INFO_SENT: '@app_system_info_sent',
86
87
  };
87
88
 
88
89
  // Source types for affiliate association tracking
@@ -207,11 +208,19 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
207
208
  }
208
209
 
209
210
  if (insertLinksEnabledParam && Platform.OS === 'ios') {
210
- try {
211
- const enhancedSystemInfo = await getEnhancedSystemInfo();
212
- await sendSystemInfoToBackend(enhancedSystemInfo);
213
- } catch (error) {
214
- verboseLog(`Error sending system info for clipboard check: ${error}`);
211
+ const systemInfoSent = await getValueFromAsync(ASYNC_KEYS.SYSTEM_INFO_SENT);
212
+ verboseLog(`System info sent flag: ${systemInfoSent ? 'true (skipping)' : 'false (will send)'}`);
213
+ if (!systemInfoSent) {
214
+ // Set flag immediately to prevent concurrent init calls from sending twice
215
+ await saveValueInAsync(ASYNC_KEYS.SYSTEM_INFO_SENT, 'pending');
216
+ try {
217
+ const enhancedSystemInfo = await getEnhancedSystemInfo();
218
+ await sendSystemInfoToBackend(enhancedSystemInfo);
219
+ } catch (error) {
220
+ // Remove flag on failure so it retries next launch
221
+ await AsyncStorage.removeItem(ASYNC_KEYS.SYSTEM_INFO_SENT);
222
+ verboseLog(`Error sending system info for clipboard check: ${error}`);
223
+ }
215
224
  }
216
225
  }
217
226
  };
@@ -664,13 +673,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
664
673
  // If URL scheme is used, we can straight away store the short code as the referring link
665
674
  await storeInsertAffiliateIdentifier({ link: shortCode, source: 'deep_link_ios' });
666
675
 
667
- // Collect and send enhanced system info to backend
668
- try {
669
- const enhancedSystemInfo = await getEnhancedSystemInfo();
670
- await sendSystemInfoToBackend(enhancedSystemInfo);
671
- } catch (error) {
672
- verboseLog(`Error sending system info for deep link: ${error}`);
673
- }
676
+ // System info not needed here - affiliate code already received via URL scheme
674
677
 
675
678
  return true;
676
679
  } catch (error) {
@@ -1347,6 +1350,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1347
1350
 
1348
1351
  // Check for a successful response
1349
1352
  if (response.status >= 200 && response.status <= 299) {
1353
+ await saveValueInAsync(ASYNC_KEYS.SYSTEM_INFO_SENT, 'true');
1350
1354
  verboseLog('System info sent successfully');
1351
1355
  } else {
1352
1356
  verboseLog(`Failed to send system info with status code: ${response.status}`);
@@ -1367,7 +1371,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1367
1371
  return isValidCharacters && referringLink.length >= 3 && referringLink.length <= 25;
1368
1372
  };
1369
1373
 
1370
- const checkAffiliateExists = async (affiliateCode: string): Promise<boolean> => {
1374
+ const checkAffiliateExists = async (affiliateCode: string, trackUsage: boolean = false): Promise<boolean> => {
1371
1375
  try {
1372
1376
  const activeCompanyCode = await getActiveCompanyCode();
1373
1377
  if (!activeCompanyCode) {
@@ -1376,11 +1380,15 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1376
1380
  }
1377
1381
 
1378
1382
  const url = 'https://api.insertaffiliate.com/V1/checkAffiliateExists';
1379
- const payload = {
1383
+ const payload: Record<string, any> = {
1380
1384
  companyId: activeCompanyCode,
1381
1385
  affiliateCode: affiliateCode
1382
1386
  };
1383
1387
 
1388
+ if (trackUsage) {
1389
+ payload.trackUsage = true;
1390
+ }
1391
+
1384
1392
  verboseLog(`Checking if affiliate exists: ${affiliateCode}`);
1385
1393
 
1386
1394
  const response = await axios.post(url, payload, {
@@ -1463,7 +1471,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1463
1471
  isShortCode(capitalisedShortCode);
1464
1472
 
1465
1473
  // Check if the affiliate exists before storing
1466
- const exists = await checkAffiliateExists(capitalisedShortCode);
1474
+ const exists = await checkAffiliateExists(capitalisedShortCode, true);
1467
1475
 
1468
1476
  if (exists) {
1469
1477
  // If affiliate exists, set the Insert Affiliate Identifier