insert-affiliate-react-native-sdk 1.7.0 → 1.9.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.
@@ -3,6 +3,11 @@ type T_DEEPLINK_IAP_PROVIDER = {
3
3
  children: React.ReactNode;
4
4
  };
5
5
  export type InsertAffiliateIdentifierChangeCallback = (identifier: string | null) => void;
6
+ export type AffiliateDetails = {
7
+ affiliateName: string;
8
+ affiliateShortCode: string;
9
+ deeplinkurl: string;
10
+ } | null;
6
11
  type CustomPurchase = {
7
12
  [key: string]: any;
8
13
  };
@@ -17,7 +22,8 @@ type T_DEEPLINK_IAP_CONTEXT = {
17
22
  returnUserAccountTokenAndStoreExpectedTransaction: () => Promise<string | null>;
18
23
  storeExpectedStoreTransaction: (purchaseToken: string) => Promise<void>;
19
24
  trackEvent: (eventName: string) => Promise<void>;
20
- setShortCode: (shortCode: string) => Promise<void>;
25
+ setShortCode: (shortCode: string) => Promise<boolean>;
26
+ getAffiliateDetails: (affiliateCode: string) => Promise<AffiliateDetails>;
21
27
  setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
22
28
  setInsertAffiliateIdentifierChangeCallback: (callback: InsertAffiliateIdentifierChangeCallback | null) => void;
23
29
  handleInsertLinks: (url: string) => Promise<boolean>;
@@ -44,6 +44,8 @@ const clipboard_1 = __importDefault(require("@react-native-clipboard/clipboard")
44
44
  const netinfo_1 = __importDefault(require("@react-native-community/netinfo"));
45
45
  const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
46
46
  const react_native_play_install_referrer_1 = require("react-native-play-install-referrer");
47
+ // Development environment check for React Native
48
+ const isDevelopmentEnvironment = typeof __DEV__ !== 'undefined' && __DEV__;
47
49
  const ASYNC_KEYS = {
48
50
  REFERRER_LINK: '@app_referrer_link',
49
51
  USER_PURCHASE: '@app_user_purchase',
@@ -65,7 +67,8 @@ exports.DeepLinkIapContext = (0, react_1.createContext)({
65
67
  returnUserAccountTokenAndStoreExpectedTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
66
68
  storeExpectedStoreTransaction: (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () { }),
67
69
  trackEvent: (eventName) => __awaiter(void 0, void 0, void 0, function* () { }),
68
- setShortCode: (shortCode) => __awaiter(void 0, void 0, void 0, function* () { }),
70
+ setShortCode: (shortCode) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
71
+ getAffiliateDetails: (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () { return null; }),
69
72
  setInsertAffiliateIdentifier: (referringLink) => __awaiter(void 0, void 0, void 0, function* () { }),
70
73
  setInsertAffiliateIdentifierChangeCallback: (callback) => { },
71
74
  handleInsertLinks: (url) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
@@ -1017,6 +1020,84 @@ const DeepLinkIapProvider = ({ children, }) => {
1017
1020
  const isValidCharacters = /^[a-zA-Z0-9_]+$/.test(referringLink);
1018
1021
  return isValidCharacters && referringLink.length >= 3 && referringLink.length <= 25;
1019
1022
  };
1023
+ const checkAffiliateExists = (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1024
+ try {
1025
+ const activeCompanyCode = yield getActiveCompanyCode();
1026
+ if (!activeCompanyCode) {
1027
+ verboseLog('Cannot check affiliate: no company code available');
1028
+ return false;
1029
+ }
1030
+ const url = 'https://api.insertaffiliate.com/V1/checkAffiliateExists';
1031
+ const payload = {
1032
+ companyId: activeCompanyCode,
1033
+ affiliateCode: affiliateCode
1034
+ };
1035
+ verboseLog(`Checking if affiliate exists: ${affiliateCode}`);
1036
+ const response = yield axios_1.default.post(url, payload, {
1037
+ headers: {
1038
+ 'Content-Type': 'application/json',
1039
+ },
1040
+ });
1041
+ verboseLog(`Affiliate check response: ${JSON.stringify(response.data)}`);
1042
+ if (response.status === 200 && response.data) {
1043
+ const exists = response.data.exists === true;
1044
+ if (exists) {
1045
+ verboseLog(`Affiliate ${affiliateCode} exists and is valid`);
1046
+ }
1047
+ else {
1048
+ verboseLog(`Affiliate ${affiliateCode} does not exist`);
1049
+ }
1050
+ return exists;
1051
+ }
1052
+ else {
1053
+ verboseLog(`Unexpected response checking affiliate: status ${response.status}`);
1054
+ return false;
1055
+ }
1056
+ }
1057
+ catch (error) {
1058
+ verboseLog(`Error checking affiliate exists: ${error}`);
1059
+ return false;
1060
+ }
1061
+ });
1062
+ const getAffiliateDetails = (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1063
+ try {
1064
+ const activeCompanyCode = yield getActiveCompanyCode();
1065
+ if (!activeCompanyCode) {
1066
+ verboseLog('Cannot get affiliate details: no company code available');
1067
+ return null;
1068
+ }
1069
+ const url = 'https://api.insertaffiliate.com/V1/checkAffiliateExists';
1070
+ const payload = {
1071
+ companyId: activeCompanyCode,
1072
+ affiliateCode: affiliateCode
1073
+ };
1074
+ verboseLog(`Getting affiliate details for: ${affiliateCode}`);
1075
+ const response = yield axios_1.default.post(url, payload, {
1076
+ headers: {
1077
+ 'Content-Type': 'application/json',
1078
+ },
1079
+ });
1080
+ verboseLog(`Affiliate details response: ${JSON.stringify(response.data)}`);
1081
+ if (response.status === 200 && response.data && response.data.exists === true) {
1082
+ const affiliate = response.data.affiliate;
1083
+ if (affiliate) {
1084
+ verboseLog(`Retrieved affiliate details: ${JSON.stringify(affiliate)}`);
1085
+ return {
1086
+ affiliateName: affiliate.affiliateName || '',
1087
+ affiliateShortCode: affiliate.affiliateShortCode || '',
1088
+ deeplinkurl: affiliate.deeplinkurl || ''
1089
+ };
1090
+ }
1091
+ }
1092
+ verboseLog(`Affiliate ${affiliateCode} not found or invalid response`);
1093
+ return null;
1094
+ }
1095
+ catch (error) {
1096
+ verboseLog(`Error getting affiliate details: ${error}`);
1097
+ console.error('[Insert Affiliate] Error getting affiliate details:', error);
1098
+ return null;
1099
+ }
1100
+ });
1020
1101
  function setShortCode(shortCode) {
1021
1102
  return __awaiter(this, void 0, void 0, function* () {
1022
1103
  console.log('[Insert Affiliate] Setting short code.');
@@ -1024,8 +1105,18 @@ const DeepLinkIapProvider = ({ children, }) => {
1024
1105
  // Validate it is a short code
1025
1106
  const capitalisedShortCode = shortCode.toUpperCase();
1026
1107
  isShortCode(capitalisedShortCode);
1027
- // If all checks pass, set the Insert Affiliate Identifier
1028
- yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
1108
+ // Check if the affiliate exists before storing
1109
+ const exists = yield checkAffiliateExists(capitalisedShortCode);
1110
+ if (exists) {
1111
+ // If affiliate exists, set the Insert Affiliate Identifier
1112
+ yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
1113
+ console.log(`[Insert Affiliate] Short code ${capitalisedShortCode} validated and stored successfully.`);
1114
+ return true;
1115
+ }
1116
+ else {
1117
+ console.warn(`[Insert Affiliate] Short code ${capitalisedShortCode} does not exist. Not storing.`);
1118
+ return false;
1119
+ }
1029
1120
  });
1030
1121
  }
1031
1122
  function getOrCreateUserAccountToken() {
@@ -1058,6 +1149,15 @@ const DeepLinkIapProvider = ({ children, }) => {
1058
1149
  }
1059
1150
  }
1060
1151
  catch (error) {
1152
+ // Handle E_IAP_NOT_AVAILABLE error gracefully
1153
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'E_IAP_NOT_AVAILABLE' ||
1154
+ (error instanceof Error && error.message.includes('E_IAP_NOT_AVAILABLE'))) {
1155
+ if (isDevelopmentEnvironment) {
1156
+ console.warn('[Insert Affiliate] IAP not available in development environment. Cannot store expected transaction.');
1157
+ verboseLog('E_IAP_NOT_AVAILABLE error in returnUserAccountTokenAndStoreExpectedTransaction - gracefully handling in development');
1158
+ }
1159
+ return null; // Return null but don't crash
1160
+ }
1061
1161
  console.error('[Insert Affiliate] Error in returnUserAccountTokenAndStoreExpectedTransaction:', error);
1062
1162
  return null;
1063
1163
  }
@@ -1258,7 +1358,21 @@ const DeepLinkIapProvider = ({ children, }) => {
1258
1358
  });
1259
1359
  }
1260
1360
  const validatePurchaseWithIapticAPI = (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
1361
+ var _a;
1261
1362
  try {
1363
+ // Check for E_IAP_NOT_AVAILABLE error in development environment
1364
+ if (((_a = jsonIapPurchase === null || jsonIapPurchase === void 0 ? void 0 : jsonIapPurchase.error) === null || _a === void 0 ? void 0 : _a.code) === 'E_IAP_NOT_AVAILABLE' ||
1365
+ (jsonIapPurchase === null || jsonIapPurchase === void 0 ? void 0 : jsonIapPurchase.code) === 'E_IAP_NOT_AVAILABLE' ||
1366
+ (typeof jsonIapPurchase === 'string' && jsonIapPurchase.includes('E_IAP_NOT_AVAILABLE'))) {
1367
+ if (isDevelopmentEnvironment) {
1368
+ console.warn('[Insert Affiliate] IAP not available in development environment. This is expected behavior.');
1369
+ verboseLog('E_IAP_NOT_AVAILABLE error detected in development - gracefully handling');
1370
+ }
1371
+ else {
1372
+ console.error('[Insert Affiliate] IAP not available in production environment. Please check your IAP configuration.');
1373
+ }
1374
+ return false; // Return false but don't crash
1375
+ }
1262
1376
  const baseRequestBody = {
1263
1377
  id: iapticAppId,
1264
1378
  type: 'application',
@@ -1308,6 +1422,18 @@ const DeepLinkIapProvider = ({ children, }) => {
1308
1422
  }
1309
1423
  }
1310
1424
  catch (error) {
1425
+ // Handle E_IAP_NOT_AVAILABLE error gracefully
1426
+ if ((error === null || error === void 0 ? void 0 : error.code) === 'E_IAP_NOT_AVAILABLE' ||
1427
+ (error instanceof Error && error.message.includes('E_IAP_NOT_AVAILABLE'))) {
1428
+ if (isDevelopmentEnvironment) {
1429
+ console.warn('[Insert Affiliate] IAP not available in development environment. SDK will continue without purchase validation.');
1430
+ verboseLog('E_IAP_NOT_AVAILABLE error caught in validatePurchaseWithIapticAPI - gracefully handling in development');
1431
+ }
1432
+ else {
1433
+ console.error('[Insert Affiliate] IAP not available in production environment. Please check your IAP configuration.');
1434
+ }
1435
+ return false; // Return false but don't crash
1436
+ }
1311
1437
  if (error instanceof Error) {
1312
1438
  console.error(`validatePurchaseWithIapticAPI Error: ${error.message}`);
1313
1439
  }
@@ -1492,6 +1618,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1492
1618
  userId,
1493
1619
  OfferCode,
1494
1620
  setShortCode,
1621
+ getAffiliateDetails,
1495
1622
  returnInsertAffiliateIdentifier,
1496
1623
  isAffiliateAttributionValid,
1497
1624
  getAffiliateStoredDate,
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  import DeepLinkIapProvider from "./DeepLinkIapProvider";
2
2
  import useDeepLinkIapProvider from "./useDeepLinkIapProvider";
3
3
  export { DeepLinkIapProvider, useDeepLinkIapProvider };
4
- export type { InsertAffiliateIdentifierChangeCallback } from "./DeepLinkIapProvider";
4
+ export type { InsertAffiliateIdentifierChangeCallback, AffiliateDetails } from "./DeepLinkIapProvider";
@@ -10,7 +10,8 @@ declare const useDeepLinkIapProvider: () => {
10
10
  isAffiliateAttributionValid: () => Promise<boolean>;
11
11
  getAffiliateStoredDate: () => Promise<Date | null>;
12
12
  trackEvent: (eventName: string) => Promise<void>;
13
- setShortCode: (shortCode: string) => Promise<void>;
13
+ setShortCode: (shortCode: string) => Promise<boolean>;
14
+ getAffiliateDetails: (affiliateCode: string) => Promise<import("./DeepLinkIapProvider").AffiliateDetails>;
14
15
  setInsertAffiliateIdentifier: (referringLink: string) => Promise<void | string>;
15
16
  setInsertAffiliateIdentifierChangeCallback: (callback: import("./DeepLinkIapProvider").InsertAffiliateIdentifierChangeCallback | null) => void;
16
17
  handleInsertLinks: (url: string) => Promise<boolean>;
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const react_1 = require("react");
4
4
  const DeepLinkIapProvider_1 = require("./DeepLinkIapProvider");
5
5
  const useDeepLinkIapProvider = () => {
6
- const { referrerLink, userId, validatePurchaseWithIapticAPI, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, isAffiliateAttributionValid, getAffiliateStoredDate, trackEvent, setShortCode, setInsertAffiliateIdentifier, setInsertAffiliateIdentifierChangeCallback, handleInsertLinks, initialize, isInitialized, OfferCode, } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
6
+ const { referrerLink, userId, validatePurchaseWithIapticAPI, storeExpectedStoreTransaction, returnUserAccountTokenAndStoreExpectedTransaction, returnInsertAffiliateIdentifier, isAffiliateAttributionValid, getAffiliateStoredDate, trackEvent, setShortCode, getAffiliateDetails, setInsertAffiliateIdentifier, setInsertAffiliateIdentifierChangeCallback, handleInsertLinks, initialize, isInitialized, OfferCode, } = (0, react_1.useContext)(DeepLinkIapProvider_1.DeepLinkIapContext);
7
7
  return {
8
8
  referrerLink,
9
9
  userId,
@@ -15,6 +15,7 @@ const useDeepLinkIapProvider = () => {
15
15
  getAffiliateStoredDate,
16
16
  trackEvent,
17
17
  setShortCode,
18
+ getAffiliateDetails,
18
19
  setInsertAffiliateIdentifier,
19
20
  setInsertAffiliateIdentifierChangeCallback,
20
21
  handleInsertLinks,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "insert-affiliate-react-native-sdk",
3
- "version": "1.7.0",
3
+ "version": "1.9.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
@@ -763,6 +763,7 @@ const DeepLinkHandler = () => {
763
763
  // Listen for both deep link types
764
764
  appsFlyer.onDeepLink(handleDeepLink);
765
765
  appsFlyer.onAppOpenAttribution(handleDeepLink);
766
+ appsFlyer.onInstallConversionData(handleDeepLink);
766
767
 
767
768
  initAppsFlyer();
768
769
  }, [setInsertAffiliateIdentifier, isInitialized]);
@@ -828,6 +829,7 @@ const DeepLinkHandler = () => {
828
829
  // Listen for both deep link types
829
830
  appsFlyer.onDeepLink(handleDeepLink);
830
831
  appsFlyer.onAppOpenAttribution(handleDeepLink);
832
+ appsFlyer.onInstallConversionData(handleDeepLink);
831
833
 
832
834
  initAppsFlyer();
833
835
  }, [setInsertAffiliateIdentifier, isInitialized]);
@@ -1214,6 +1216,12 @@ Short codes must meet the following criteria:
1214
1216
  - Contain only **letters, numbers, and underscores** (alphanumeric characters and underscores).
1215
1217
  - Replace {{ user_entered_short_code }} with the short code the user enters through your chosen input method, i.e. an input field / pop up element
1216
1218
 
1219
+ **Return Value**: `setShortCode` returns a `Promise<boolean>`:
1220
+ - Returns `true` if the short code exists and was successfully validated and stored
1221
+ - Returns `false` if the short code does not exist or validation failed
1222
+
1223
+ This allows you to provide immediate feedback to users about whether their entered code is valid.
1224
+
1217
1225
  ```javascript
1218
1226
  import {
1219
1227
  DeepLinkIapProvider,
@@ -1223,12 +1231,30 @@ Short codes must meet the following criteria:
1223
1231
  setShortCode,
1224
1232
  } = useDeepLinkIapProvider();
1225
1233
 
1234
+ // Basic usage (without validation feedback)
1226
1235
  <Button
1227
1236
  title={'Set Short Code'}
1228
1237
  onPress={() => setShortCode('JOIN_123')}
1229
1238
  />
1239
+
1240
+ // Recommended usage with validation feedback
1241
+ <Button
1242
+ title={'Set Short Code'}
1243
+ onPress={async () => {
1244
+ const isValid = await setShortCode('JOIN_123');
1245
+ if (isValid) {
1246
+ // Show success message to user
1247
+ Alert.alert('Success', 'Affiliate code applied successfully!');
1248
+ } else {
1249
+ // Show error message to user
1250
+ Alert.alert('Error', 'Invalid affiliate code. Please check and try again.');
1251
+ }
1252
+ }}
1253
+ />
1230
1254
  ```
1231
1255
 
1256
+ **Important**: The SDK will automatically validate the short code with the Insert Affiliate backend before storing it. Only valid short codes that exist in your company's affiliate list will be stored. Invalid codes will be rejected and not associated with the user.
1257
+
1232
1258
  ### Attribution Timeout
1233
1259
 
1234
1260
  You can configure how long an affiliate link attribution remains active after being clicked. This allows you to control the attribution window for commissions.
@@ -1308,4 +1334,77 @@ const storedDate = await getAffiliateStoredDate();
1308
1334
  3. **Expired Attribution**: If the attribution has expired, the method returns `null` instead of the affiliate identifier
1309
1335
  4. **Bypass Option**: You can bypass the timeout check by passing `true` to `returnInsertAffiliateIdentifier(true)`
1310
1336
 
1311
- This ensures that affiliates are only credited for purchases made within the specified attribution window, providing fair and accurate commission tracking.
1337
+ This ensures that affiliates are only credited for purchases made within the specified attribution window, providing fair and accurate commission tracking.
1338
+
1339
+ ### Getting Affiliate Details
1340
+
1341
+ You can retrieve detailed information about an affiliate by their short code or deep link using the `getAffiliateDetails` method. This is useful for displaying affiliate information to users or showing personalized content based on the referrer.
1342
+
1343
+ #### Method Signature
1344
+
1345
+ ```typescript
1346
+ getAffiliateDetails(affiliateCode: string): Promise<AffiliateDetails>
1347
+
1348
+ type AffiliateDetails = {
1349
+ affiliateName: string;
1350
+ affiliateShortCode: string;
1351
+ deeplinkurl: string;
1352
+ } | null;
1353
+ ```
1354
+
1355
+ #### Usage Example
1356
+
1357
+ ```javascript
1358
+ import { useDeepLinkIapProvider } from 'insert-affiliate-react-native-sdk';
1359
+ import type { AffiliateDetails } from 'insert-affiliate-react-native-sdk';
1360
+
1361
+ const MyComponent = () => {
1362
+ const { getAffiliateDetails } = useDeepLinkIapProvider();
1363
+
1364
+ const handleGetAffiliateInfo = async (code: string) => {
1365
+ const details = await getAffiliateDetails(code);
1366
+
1367
+ if (details) {
1368
+ console.log('Affiliate Name:', details.affiliateName);
1369
+ console.log('Short Code:', details.affiliateShortCode);
1370
+ console.log('Deep Link:', details.deeplinkurl);
1371
+
1372
+ // Example: Show affiliate name in UI
1373
+ Alert.alert(
1374
+ 'Affiliate Found',
1375
+ `This code belongs to ${details.affiliateName}`
1376
+ );
1377
+ } else {
1378
+ console.log('Affiliate not found');
1379
+ Alert.alert('Error', 'Invalid affiliate code');
1380
+ }
1381
+ };
1382
+
1383
+ return (
1384
+ <View>
1385
+ <Button
1386
+ title="Get Affiliate Info"
1387
+ onPress={() => handleGetAffiliateInfo('JOIN_123')}
1388
+ />
1389
+ </View>
1390
+ );
1391
+ };
1392
+ ```
1393
+
1394
+ #### Return Value
1395
+
1396
+ - Returns an object with affiliate details if the code exists:
1397
+ - `affiliateName`: The name of the affiliate
1398
+ - `affiliateShortCode`: The affiliate's short code
1399
+ - `deeplinkurl`: The affiliate's deep link URL
1400
+ - Returns `null` if:
1401
+ - The affiliate code doesn't exist
1402
+ - The company code is not initialized
1403
+ - There's a network error or API issue
1404
+
1405
+ #### Important Notes
1406
+
1407
+ - This method does **not** store or set the affiliate identifier - it only retrieves information
1408
+ - Use `setShortCode()` to actually associate an affiliate with a user
1409
+ - The method automatically strips UUIDs from codes (e.g., "ABC123-uuid" becomes "ABC123")
1410
+ - Works with both short codes and deep link URLs
@@ -7,6 +7,9 @@ import NetInfo from '@react-native-community/netinfo';
7
7
  import DeviceInfo from 'react-native-device-info';
8
8
  import { PlayInstallReferrer, PlayInstallReferrerInfo } from 'react-native-play-install-referrer';
9
9
 
10
+ // Development environment check for React Native
11
+ const isDevelopmentEnvironment = typeof __DEV__ !== 'undefined' && __DEV__;
12
+
10
13
  // TYPES USED IN THIS PROVIDER
11
14
  type T_DEEPLINK_IAP_PROVIDER = {
12
15
  children: React.ReactNode;
@@ -14,6 +17,12 @@ type T_DEEPLINK_IAP_PROVIDER = {
14
17
 
15
18
  export type InsertAffiliateIdentifierChangeCallback = (identifier: string | null) => void;
16
19
 
20
+ export type AffiliateDetails = {
21
+ affiliateName: string;
22
+ affiliateShortCode: string;
23
+ deeplinkurl: string;
24
+ } | null;
25
+
17
26
  type CustomPurchase = {
18
27
  [key: string]: any; // Accept any fields to allow it to work wtih multiple IAP libraries
19
28
  };
@@ -36,7 +45,8 @@ type T_DEEPLINK_IAP_CONTEXT = {
36
45
  purchaseToken: string
37
46
  ) => Promise<void>;
38
47
  trackEvent: (eventName: string) => Promise<void>;
39
- setShortCode: (shortCode: string) => Promise<void>;
48
+ setShortCode: (shortCode: string) => Promise<boolean>;
49
+ getAffiliateDetails: (affiliateCode: string) => Promise<AffiliateDetails>;
40
50
  setInsertAffiliateIdentifier: (
41
51
  referringLink: string
42
52
  ) => Promise<void | string>;
@@ -89,7 +99,8 @@ export const DeepLinkIapContext = createContext<T_DEEPLINK_IAP_CONTEXT>({
89
99
  returnUserAccountTokenAndStoreExpectedTransaction: async () => '',
90
100
  storeExpectedStoreTransaction: async (purchaseToken: string) => {},
91
101
  trackEvent: async (eventName: string) => {},
92
- setShortCode: async (shortCode: string) => {},
102
+ setShortCode: async (shortCode: string) => false,
103
+ getAffiliateDetails: async (affiliateCode: string) => null,
93
104
  setInsertAffiliateIdentifier: async (referringLink: string) => {},
94
105
  setInsertAffiliateIdentifierChangeCallback: (callback: InsertAffiliateIdentifierChangeCallback | null) => {},
95
106
  handleInsertLinks: async (url: string) => false,
@@ -1171,7 +1182,94 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1171
1182
  return isValidCharacters && referringLink.length >= 3 && referringLink.length <= 25;
1172
1183
  };
1173
1184
 
1174
- async function setShortCode(shortCode: string): Promise<void> {
1185
+ const checkAffiliateExists = async (affiliateCode: string): Promise<boolean> => {
1186
+ try {
1187
+ const activeCompanyCode = await getActiveCompanyCode();
1188
+ if (!activeCompanyCode) {
1189
+ verboseLog('Cannot check affiliate: no company code available');
1190
+ return false;
1191
+ }
1192
+
1193
+ const url = 'https://api.insertaffiliate.com/V1/checkAffiliateExists';
1194
+ const payload = {
1195
+ companyId: activeCompanyCode,
1196
+ affiliateCode: affiliateCode
1197
+ };
1198
+
1199
+ verboseLog(`Checking if affiliate exists: ${affiliateCode}`);
1200
+
1201
+ const response = await axios.post(url, payload, {
1202
+ headers: {
1203
+ 'Content-Type': 'application/json',
1204
+ },
1205
+ });
1206
+
1207
+ verboseLog(`Affiliate check response: ${JSON.stringify(response.data)}`);
1208
+
1209
+ if (response.status === 200 && response.data) {
1210
+ const exists = response.data.exists === true;
1211
+ if (exists) {
1212
+ verboseLog(`Affiliate ${affiliateCode} exists and is valid`);
1213
+ } else {
1214
+ verboseLog(`Affiliate ${affiliateCode} does not exist`);
1215
+ }
1216
+ return exists;
1217
+ } else {
1218
+ verboseLog(`Unexpected response checking affiliate: status ${response.status}`);
1219
+ return false;
1220
+ }
1221
+ } catch (error) {
1222
+ verboseLog(`Error checking affiliate exists: ${error}`);
1223
+ return false;
1224
+ }
1225
+ };
1226
+
1227
+ const getAffiliateDetails = async (affiliateCode: string): Promise<AffiliateDetails> => {
1228
+ try {
1229
+ const activeCompanyCode = await getActiveCompanyCode();
1230
+ if (!activeCompanyCode) {
1231
+ verboseLog('Cannot get affiliate details: no company code available');
1232
+ return null;
1233
+ }
1234
+
1235
+ const url = 'https://api.insertaffiliate.com/V1/checkAffiliateExists';
1236
+ const payload = {
1237
+ companyId: activeCompanyCode,
1238
+ affiliateCode: affiliateCode
1239
+ };
1240
+
1241
+ verboseLog(`Getting affiliate details for: ${affiliateCode}`);
1242
+
1243
+ const response = await axios.post(url, payload, {
1244
+ headers: {
1245
+ 'Content-Type': 'application/json',
1246
+ },
1247
+ });
1248
+
1249
+ verboseLog(`Affiliate details response: ${JSON.stringify(response.data)}`);
1250
+
1251
+ if (response.status === 200 && response.data && response.data.exists === true) {
1252
+ const affiliate = response.data.affiliate;
1253
+ if (affiliate) {
1254
+ verboseLog(`Retrieved affiliate details: ${JSON.stringify(affiliate)}`);
1255
+ return {
1256
+ affiliateName: affiliate.affiliateName || '',
1257
+ affiliateShortCode: affiliate.affiliateShortCode || '',
1258
+ deeplinkurl: affiliate.deeplinkurl || ''
1259
+ };
1260
+ }
1261
+ }
1262
+
1263
+ verboseLog(`Affiliate ${affiliateCode} not found or invalid response`);
1264
+ return null;
1265
+ } catch (error) {
1266
+ verboseLog(`Error getting affiliate details: ${error}`);
1267
+ console.error('[Insert Affiliate] Error getting affiliate details:', error);
1268
+ return null;
1269
+ }
1270
+ };
1271
+
1272
+ async function setShortCode(shortCode: string): Promise<boolean> {
1175
1273
  console.log('[Insert Affiliate] Setting short code.');
1176
1274
  await generateThenSetUserID();
1177
1275
 
@@ -1179,8 +1277,18 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1179
1277
  const capitalisedShortCode = shortCode.toUpperCase();
1180
1278
  isShortCode(capitalisedShortCode);
1181
1279
 
1182
- // If all checks pass, set the Insert Affiliate Identifier
1183
- await storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
1280
+ // Check if the affiliate exists before storing
1281
+ const exists = await checkAffiliateExists(capitalisedShortCode);
1282
+
1283
+ if (exists) {
1284
+ // If affiliate exists, set the Insert Affiliate Identifier
1285
+ await storeInsertAffiliateIdentifier({ link: capitalisedShortCode });
1286
+ console.log(`[Insert Affiliate] Short code ${capitalisedShortCode} validated and stored successfully.`);
1287
+ return true;
1288
+ } else {
1289
+ console.warn(`[Insert Affiliate] Short code ${capitalisedShortCode} does not exist. Not storing.`);
1290
+ return false;
1291
+ }
1184
1292
  }
1185
1293
 
1186
1294
  async function getOrCreateUserAccountToken(): Promise<string> {
@@ -1213,6 +1321,17 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1213
1321
  return userAccountToken;
1214
1322
  }
1215
1323
  } catch (error) {
1324
+ // Handle E_IAP_NOT_AVAILABLE error gracefully
1325
+ if ((error as any)?.code === 'E_IAP_NOT_AVAILABLE' ||
1326
+ (error instanceof Error && error.message.includes('E_IAP_NOT_AVAILABLE'))) {
1327
+
1328
+ if (isDevelopmentEnvironment) {
1329
+ console.warn('[Insert Affiliate] IAP not available in development environment. Cannot store expected transaction.');
1330
+ verboseLog('E_IAP_NOT_AVAILABLE error in returnUserAccountTokenAndStoreExpectedTransaction - gracefully handling in development');
1331
+ }
1332
+ return null; // Return null but don't crash
1333
+ }
1334
+
1216
1335
  console.error('[Insert Affiliate] Error in returnUserAccountTokenAndStoreExpectedTransaction:', error);
1217
1336
  return null;
1218
1337
  };
@@ -1455,6 +1574,20 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1455
1574
  iapticPublicKey: string
1456
1575
  ): Promise<boolean> => {
1457
1576
  try {
1577
+ // Check for E_IAP_NOT_AVAILABLE error in development environment
1578
+ if ((jsonIapPurchase as any)?.error?.code === 'E_IAP_NOT_AVAILABLE' ||
1579
+ (jsonIapPurchase as any)?.code === 'E_IAP_NOT_AVAILABLE' ||
1580
+ (typeof jsonIapPurchase === 'string' && (jsonIapPurchase as string).includes('E_IAP_NOT_AVAILABLE'))) {
1581
+
1582
+ if (isDevelopmentEnvironment) {
1583
+ console.warn('[Insert Affiliate] IAP not available in development environment. This is expected behavior.');
1584
+ verboseLog('E_IAP_NOT_AVAILABLE error detected in development - gracefully handling');
1585
+ } else {
1586
+ console.error('[Insert Affiliate] IAP not available in production environment. Please check your IAP configuration.');
1587
+ }
1588
+ return false; // Return false but don't crash
1589
+ }
1590
+
1458
1591
  const baseRequestBody: RequestBody = {
1459
1592
  id: iapticAppId,
1460
1593
  type: 'application',
@@ -1513,6 +1646,19 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1513
1646
  return false;
1514
1647
  }
1515
1648
  } catch (error) {
1649
+ // Handle E_IAP_NOT_AVAILABLE error gracefully
1650
+ if ((error as any)?.code === 'E_IAP_NOT_AVAILABLE' ||
1651
+ (error instanceof Error && error.message.includes('E_IAP_NOT_AVAILABLE'))) {
1652
+
1653
+ if (isDevelopmentEnvironment) {
1654
+ console.warn('[Insert Affiliate] IAP not available in development environment. SDK will continue without purchase validation.');
1655
+ verboseLog('E_IAP_NOT_AVAILABLE error caught in validatePurchaseWithIapticAPI - gracefully handling in development');
1656
+ } else {
1657
+ console.error('[Insert Affiliate] IAP not available in production environment. Please check your IAP configuration.');
1658
+ }
1659
+ return false; // Return false but don't crash
1660
+ }
1661
+
1516
1662
  if (error instanceof Error) {
1517
1663
  console.error(`validatePurchaseWithIapticAPI Error: ${error.message}`);
1518
1664
  } else {
@@ -1738,6 +1884,7 @@ const DeepLinkIapProvider: React.FC<T_DEEPLINK_IAP_PROVIDER> = ({
1738
1884
  userId,
1739
1885
  OfferCode,
1740
1886
  setShortCode,
1887
+ getAffiliateDetails,
1741
1888
  returnInsertAffiliateIdentifier,
1742
1889
  isAffiliateAttributionValid,
1743
1890
  getAffiliateStoredDate,
package/src/index.ts CHANGED
@@ -4,4 +4,4 @@ import useDeepLinkIapProvider from "./useDeepLinkIapProvider";
4
4
  export { DeepLinkIapProvider, useDeepLinkIapProvider };
5
5
 
6
6
  // Export types
7
- export type { InsertAffiliateIdentifierChangeCallback } from "./DeepLinkIapProvider";
7
+ export type { InsertAffiliateIdentifierChangeCallback, AffiliateDetails } from "./DeepLinkIapProvider";
@@ -13,6 +13,7 @@ const useDeepLinkIapProvider = () => {
13
13
  getAffiliateStoredDate,
14
14
  trackEvent,
15
15
  setShortCode,
16
+ getAffiliateDetails,
16
17
  setInsertAffiliateIdentifier,
17
18
  setInsertAffiliateIdentifierChangeCallback,
18
19
  handleInsertLinks,
@@ -32,6 +33,7 @@ const useDeepLinkIapProvider = () => {
32
33
  getAffiliateStoredDate,
33
34
  trackEvent,
34
35
  setShortCode,
36
+ getAffiliateDetails,
35
37
  setInsertAffiliateIdentifier,
36
38
  setInsertAffiliateIdentifierChangeCallback,
37
39
  handleInsertLinks,