insert-affiliate-react-native-sdk 1.10.0 → 1.11.2

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.
@@ -4,8 +4,14 @@
4
4
  "WebFetch(domain:github.com)",
5
5
  "Bash(npm run build:*)",
6
6
  "Bash(npm install:*)",
7
- "Bash(npm view:*)"
7
+ "Bash(npm view:*)",
8
+ "Bash(find:*)",
9
+ "Bash(adb logcat:*)",
10
+ "Bash(adb shell:*)",
11
+ "Bash(adb shell am start:*)",
12
+ "Bash(git checkout:*)",
13
+ "Bash(git pull:*)"
8
14
  ],
9
15
  "deny": []
10
16
  }
11
- }
17
+ }
@@ -88,43 +88,63 @@ const DeepLinkIapProvider = ({ children, }) => {
88
88
  const [OfferCode, setOfferCode] = (0, react_1.useState)(null);
89
89
  const [affiliateAttributionActiveTime, setAffiliateAttributionActiveTime] = (0, react_1.useState)(null);
90
90
  const insertAffiliateIdentifierChangeCallbackRef = (0, react_1.useRef)(null);
91
+ const isInitializingRef = (0, react_1.useRef)(false);
92
+ // Refs for values that need to be current inside callbacks (to avoid stale closures)
93
+ const companyCodeRef = (0, react_1.useRef)(null);
94
+ const verboseLoggingRef = (0, react_1.useRef)(false);
95
+ // Refs for implementation functions (ref callback pattern for stable + fresh)
96
+ const initializeImplRef = (0, react_1.useRef)(null);
97
+ const setShortCodeImplRef = (0, react_1.useRef)(null);
98
+ const getAffiliateDetailsImplRef = (0, react_1.useRef)(null);
99
+ const returnInsertAffiliateIdentifierImplRef = (0, react_1.useRef)(null);
100
+ const isAffiliateAttributionValidImplRef = (0, react_1.useRef)(null);
101
+ const getAffiliateStoredDateImplRef = (0, react_1.useRef)(null);
102
+ const storeExpectedStoreTransactionImplRef = (0, react_1.useRef)(null);
103
+ const returnUserAccountTokenAndStoreExpectedTransactionImplRef = (0, react_1.useRef)(null);
104
+ const validatePurchaseWithIapticAPIImplRef = (0, react_1.useRef)(null);
105
+ const trackEventImplRef = (0, react_1.useRef)(null);
106
+ const setInsertAffiliateIdentifierImplRef = (0, react_1.useRef)(null);
107
+ const handleInsertLinksImplRef = (0, react_1.useRef)(null);
91
108
  // MARK: Initialize the SDK
92
- const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false, insertLinksEnabled = false, insertLinksClipboardEnabled = false, affiliateAttributionActiveTime) {
93
- setVerboseLogging(verboseLogging);
94
- setInsertLinksEnabled(insertLinksEnabled);
95
- setInsertLinksClipboardEnabled(insertLinksClipboardEnabled);
96
- if (affiliateAttributionActiveTime !== undefined) {
97
- setAffiliateAttributionActiveTime(affiliateAttributionActiveTime);
109
+ const initializeImpl = (companyCodeParam_1, ...args_1) => __awaiter(void 0, [companyCodeParam_1, ...args_1], void 0, function* (companyCodeParam, verboseLoggingParam = false, insertLinksEnabledParam = false, insertLinksClipboardEnabledParam = false, affiliateAttributionActiveTimeParam) {
110
+ // Prevent multiple concurrent initialization attempts
111
+ if (isInitialized || isInitializingRef.current) {
112
+ return;
98
113
  }
99
- if (verboseLogging) {
114
+ isInitializingRef.current = true;
115
+ setVerboseLogging(verboseLoggingParam);
116
+ verboseLoggingRef.current = verboseLoggingParam;
117
+ setInsertLinksEnabled(insertLinksEnabledParam);
118
+ setInsertLinksClipboardEnabled(insertLinksClipboardEnabledParam);
119
+ if (affiliateAttributionActiveTimeParam !== undefined) {
120
+ setAffiliateAttributionActiveTime(affiliateAttributionActiveTimeParam);
121
+ }
122
+ if (verboseLoggingParam) {
100
123
  console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
101
- console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCode ? 'Yes' : 'No');
124
+ console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCodeParam ? 'Yes' : 'No');
102
125
  console.log('[Insert Affiliate] [VERBOSE] Verbose logging enabled');
103
126
  }
104
- if (isInitialized) {
105
- console.error('[Insert Affiliate] SDK is already initialized.');
106
- return;
107
- }
108
- if (companyCode && companyCode.trim() !== '') {
109
- setCompanyCode(companyCode);
110
- yield saveValueInAsync(ASYNC_KEYS.COMPANY_CODE, companyCode);
127
+ if (companyCodeParam && companyCodeParam.trim() !== '') {
128
+ setCompanyCode(companyCodeParam);
129
+ companyCodeRef.current = companyCodeParam;
130
+ yield saveValueInAsync(ASYNC_KEYS.COMPANY_CODE, companyCodeParam);
111
131
  setIsInitialized(true);
112
- console.log(`[Insert Affiliate] SDK initialized with company code: ${companyCode}`);
113
- if (verboseLogging) {
132
+ console.log(`[Insert Affiliate] SDK initialized with company code: ${companyCodeParam}`);
133
+ if (verboseLoggingParam) {
114
134
  console.log('[Insert Affiliate] [VERBOSE] Company code saved to AsyncStorage');
115
135
  console.log('[Insert Affiliate] [VERBOSE] SDK marked as initialized');
116
136
  }
117
137
  // Report SDK initialization for onboarding verification (fire and forget)
118
- reportSdkInitIfNeeded(companyCode, verboseLogging);
138
+ reportSdkInitIfNeeded(companyCodeParam, verboseLoggingParam);
119
139
  }
120
140
  else {
121
141
  console.warn('[Insert Affiliate] SDK initialized without a company code.');
122
142
  setIsInitialized(true);
123
- if (verboseLogging) {
143
+ if (verboseLoggingParam) {
124
144
  console.log('[Insert Affiliate] [VERBOSE] No company code provided, SDK initialized in limited mode');
125
145
  }
126
146
  }
127
- if (insertLinksEnabled && react_native_1.Platform.OS === 'ios') {
147
+ if (insertLinksEnabledParam && react_native_1.Platform.OS === 'ios') {
128
148
  try {
129
149
  const enhancedSystemInfo = yield getEnhancedSystemInfo();
130
150
  yield sendSystemInfoToBackend(enhancedSystemInfo);
@@ -155,6 +175,7 @@ const DeepLinkIapProvider = ({ children, }) => {
155
175
  }
156
176
  if (companyCodeFromStorage) {
157
177
  setCompanyCode(companyCodeFromStorage);
178
+ companyCodeRef.current = companyCodeFromStorage;
158
179
  verboseLog('Company code restored from storage');
159
180
  }
160
181
  if (storedOfferCode) {
@@ -288,12 +309,6 @@ const DeepLinkIapProvider = ({ children, }) => {
288
309
  setIsInitialized(false);
289
310
  console.log('[Insert Affiliate] SDK has been reset.');
290
311
  };
291
- // MARK: Callback Management
292
- // Sets a callback that will be triggered whenever storeInsertAffiliateIdentifier is called
293
- // The callback receives the current affiliate identifier (returnInsertAffiliateIdentifier result)
294
- const setInsertAffiliateIdentifierChangeCallbackHandler = (callback) => {
295
- insertAffiliateIdentifierChangeCallbackRef.current = callback;
296
- };
297
312
  // MARK: Deep Link Handling
298
313
  // Helper function to parse URLs in React Native compatible way
299
314
  const parseURL = (url) => {
@@ -479,7 +494,7 @@ const DeepLinkIapProvider = ({ children, }) => {
479
494
  }
480
495
  });
481
496
  // Handles Insert Links deep linking - equivalent to iOS handleInsertLinks
482
- const handleInsertLinks = (url) => __awaiter(void 0, void 0, void 0, function* () {
497
+ const handleInsertLinksImpl = (url) => __awaiter(void 0, void 0, void 0, function* () {
483
498
  try {
484
499
  console.log(`[Insert Affiliate] Attempting to handle URL: ${url}`);
485
500
  if (!url || typeof url !== 'string') {
@@ -582,14 +597,47 @@ const DeepLinkIapProvider = ({ children, }) => {
582
597
  return null;
583
598
  }
584
599
  };
600
+ // Parse shortcode from query parameter (new format: scheme://insert-affiliate?code=SHORTCODE)
601
+ const parseShortCodeFromQuery = (url) => {
602
+ try {
603
+ const queryIndex = url.indexOf('?');
604
+ if (queryIndex !== -1) {
605
+ const queryString = url.substring(queryIndex + 1);
606
+ const params = queryString.split('&');
607
+ for (const param of params) {
608
+ const [key, value] = param.split('=');
609
+ if (key === 'code' && value) {
610
+ return decodeURIComponent(value);
611
+ }
612
+ }
613
+ }
614
+ return null;
615
+ }
616
+ catch (error) {
617
+ verboseLog(`Error parsing short code from query: ${error}`);
618
+ return null;
619
+ }
620
+ };
585
621
  const parseShortCodeFromURLString = (url) => {
586
622
  try {
587
- // For custom schemes like ia-companycode://shortcode, everything after :// is the short code
623
+ // First try to extract from query parameter (new format: scheme://insert-affiliate?code=SHORTCODE)
624
+ const queryCode = parseShortCodeFromQuery(url);
625
+ if (queryCode) {
626
+ console.log(`[Insert Affiliate] Found short code in query parameter: ${queryCode}`);
627
+ return queryCode;
628
+ }
629
+ // Fall back to path format (legacy: scheme://SHORTCODE)
588
630
  const match = url.match(/^[^:]+:\/\/(.+)$/);
589
631
  if (match) {
590
- const shortCode = match[1];
632
+ let shortCode = match[1];
591
633
  // Remove leading slash if present
592
- return shortCode.startsWith('/') ? shortCode.substring(1) : shortCode;
634
+ shortCode = shortCode.startsWith('/') ? shortCode.substring(1) : shortCode;
635
+ // If the path is 'insert-affiliate' (from new format without code param), return null
636
+ if (shortCode === 'insert-affiliate' || shortCode.startsWith('insert-affiliate?')) {
637
+ return null;
638
+ }
639
+ console.log(`[Insert Affiliate] Found short code in URL path (legacy format): ${shortCode}`);
640
+ return shortCode;
593
641
  }
594
642
  return null;
595
643
  }
@@ -609,26 +657,27 @@ const DeepLinkIapProvider = ({ children, }) => {
609
657
  const clearAsyncStorage = () => __awaiter(void 0, void 0, void 0, function* () {
610
658
  yield async_storage_1.default.clear();
611
659
  });
612
- // Helper function to get company code from state or storage
660
+ // Helper function to get company code from ref or storage (uses ref to avoid stale closures)
613
661
  const getActiveCompanyCode = () => __awaiter(void 0, void 0, void 0, function* () {
614
662
  verboseLog('Getting active company code...');
615
- let activeCompanyCode = companyCode;
616
- verboseLog(`Company code in React state: ${activeCompanyCode || 'empty'}`);
663
+ let activeCompanyCode = companyCodeRef.current;
664
+ verboseLog(`Company code in ref: ${activeCompanyCode || 'empty'}`);
617
665
  if (!activeCompanyCode || (activeCompanyCode.trim() === '' && activeCompanyCode !== null)) {
618
- verboseLog('Company code not in state, checking AsyncStorage...');
666
+ verboseLog('Company code not in ref, checking AsyncStorage...');
619
667
  activeCompanyCode = yield getValueFromAsync(ASYNC_KEYS.COMPANY_CODE);
620
668
  verboseLog(`Company code in AsyncStorage: ${activeCompanyCode || 'empty'}`);
621
669
  if (activeCompanyCode) {
622
- // Update state for future use
670
+ // Update ref and state for future use
671
+ companyCodeRef.current = activeCompanyCode;
623
672
  setCompanyCode(activeCompanyCode);
624
- verboseLog('Updated React state with company code from storage');
673
+ verboseLog('Updated ref and React state with company code from storage');
625
674
  }
626
675
  }
627
676
  return activeCompanyCode;
628
677
  });
629
- // Helper function for verbose logging
678
+ // Helper function for verbose logging (uses ref to avoid stale closures)
630
679
  const verboseLog = (message) => {
631
- if (verboseLogging) {
680
+ if (verboseLoggingRef.current) {
632
681
  console.log(`[Insert Affiliate] [VERBOSE] ${message}`);
633
682
  }
634
683
  };
@@ -1156,7 +1205,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1156
1205
  return false;
1157
1206
  }
1158
1207
  });
1159
- const getAffiliateDetails = (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1208
+ const getAffiliateDetailsImpl = (affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1160
1209
  try {
1161
1210
  const activeCompanyCode = yield getActiveCompanyCode();
1162
1211
  if (!activeCompanyCode) {
@@ -1195,27 +1244,25 @@ const DeepLinkIapProvider = ({ children, }) => {
1195
1244
  return null;
1196
1245
  }
1197
1246
  });
1198
- function setShortCode(shortCode) {
1199
- return __awaiter(this, void 0, void 0, function* () {
1200
- console.log('[Insert Affiliate] Setting short code.');
1201
- yield generateThenSetUserID();
1202
- // Validate it is a short code
1203
- const capitalisedShortCode = shortCode.toUpperCase();
1204
- isShortCode(capitalisedShortCode);
1205
- // Check if the affiliate exists before storing
1206
- const exists = yield checkAffiliateExists(capitalisedShortCode);
1207
- if (exists) {
1208
- // If affiliate exists, set the Insert Affiliate Identifier
1209
- yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode, source: 'short_code_manual' });
1210
- console.log(`[Insert Affiliate] Short code ${capitalisedShortCode} validated and stored successfully.`);
1211
- return true;
1212
- }
1213
- else {
1214
- console.warn(`[Insert Affiliate] Short code ${capitalisedShortCode} does not exist. Not storing.`);
1215
- return false;
1216
- }
1217
- });
1218
- }
1247
+ const setShortCodeImpl = (shortCode) => __awaiter(void 0, void 0, void 0, function* () {
1248
+ console.log('[Insert Affiliate] Setting short code.');
1249
+ yield generateThenSetUserID();
1250
+ // Validate it is a short code
1251
+ const capitalisedShortCode = shortCode.toUpperCase();
1252
+ isShortCode(capitalisedShortCode);
1253
+ // Check if the affiliate exists before storing
1254
+ const exists = yield checkAffiliateExists(capitalisedShortCode);
1255
+ if (exists) {
1256
+ // If affiliate exists, set the Insert Affiliate Identifier
1257
+ yield storeInsertAffiliateIdentifier({ link: capitalisedShortCode, source: 'short_code_manual' });
1258
+ console.log(`[Insert Affiliate] Short code ${capitalisedShortCode} validated and stored successfully.`);
1259
+ return true;
1260
+ }
1261
+ else {
1262
+ console.warn(`[Insert Affiliate] Short code ${capitalisedShortCode} does not exist. Not storing.`);
1263
+ return false;
1264
+ }
1265
+ });
1219
1266
  function getOrCreateUserAccountToken() {
1220
1267
  return __awaiter(this, void 0, void 0, function* () {
1221
1268
  let userAccountToken = yield getValueFromAsync(ASYNC_KEYS.USER_ACCOUNT_TOKEN);
@@ -1227,9 +1274,9 @@ const DeepLinkIapProvider = ({ children, }) => {
1227
1274
  });
1228
1275
  }
1229
1276
  ;
1230
- const returnUserAccountTokenAndStoreExpectedTransaction = () => __awaiter(void 0, void 0, void 0, function* () {
1277
+ const returnUserAccountTokenAndStoreExpectedTransactionImpl = () => __awaiter(void 0, void 0, void 0, function* () {
1231
1278
  try {
1232
- const shortCode = yield returnInsertAffiliateIdentifier();
1279
+ const shortCode = yield returnInsertAffiliateIdentifierImpl();
1233
1280
  if (!shortCode) {
1234
1281
  console.log('[Insert Affiliate] No affiliate stored - not saving expected transaction.');
1235
1282
  return null;
@@ -1241,7 +1288,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1241
1288
  return null;
1242
1289
  }
1243
1290
  else {
1244
- yield storeExpectedStoreTransaction(userAccountToken);
1291
+ yield storeExpectedStoreTransactionImpl(userAccountToken);
1245
1292
  return userAccountToken;
1246
1293
  }
1247
1294
  }
@@ -1261,12 +1308,12 @@ const DeepLinkIapProvider = ({ children, }) => {
1261
1308
  ;
1262
1309
  });
1263
1310
  // MARK: Return Insert Affiliate Identifier
1264
- const returnInsertAffiliateIdentifier = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (ignoreTimeout = false) {
1311
+ const returnInsertAffiliateIdentifierImpl = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (ignoreTimeout = false) {
1265
1312
  try {
1266
1313
  verboseLog(`Getting insert affiliate identifier (ignoreTimeout: ${ignoreTimeout})...`);
1267
1314
  // If timeout is enabled and we're not ignoring it, check validity first
1268
1315
  if (!ignoreTimeout && affiliateAttributionActiveTime) {
1269
- const isValid = yield isAffiliateAttributionValid();
1316
+ const isValid = yield isAffiliateAttributionValidImpl();
1270
1317
  if (!isValid) {
1271
1318
  verboseLog('Attribution has expired, returning null');
1272
1319
  return null;
@@ -1306,14 +1353,14 @@ const DeepLinkIapProvider = ({ children, }) => {
1306
1353
  });
1307
1354
  // MARK: Attribution Timeout Functions
1308
1355
  // Check if the current affiliate attribution is still valid based on timeout
1309
- const isAffiliateAttributionValid = () => __awaiter(void 0, void 0, void 0, function* () {
1356
+ const isAffiliateAttributionValidImpl = () => __awaiter(void 0, void 0, void 0, function* () {
1310
1357
  try {
1311
1358
  // If no timeout is set, attribution is always valid
1312
1359
  if (!affiliateAttributionActiveTime) {
1313
1360
  verboseLog('No attribution timeout set, attribution is valid');
1314
1361
  return true;
1315
1362
  }
1316
- const storedDate = yield getAffiliateStoredDate();
1363
+ const storedDate = yield getAffiliateStoredDateImpl();
1317
1364
  if (!storedDate) {
1318
1365
  verboseLog('No stored date found, attribution is invalid');
1319
1366
  return false;
@@ -1330,7 +1377,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1330
1377
  }
1331
1378
  });
1332
1379
  // Get the date when the affiliate identifier was stored
1333
- const getAffiliateStoredDate = () => __awaiter(void 0, void 0, void 0, function* () {
1380
+ const getAffiliateStoredDateImpl = () => __awaiter(void 0, void 0, void 0, function* () {
1334
1381
  try {
1335
1382
  const storedDateString = yield getValueFromAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE);
1336
1383
  if (!storedDateString) {
@@ -1347,84 +1394,81 @@ const DeepLinkIapProvider = ({ children, }) => {
1347
1394
  }
1348
1395
  });
1349
1396
  // MARK: Insert Affiliate Identifier
1350
- function setInsertAffiliateIdentifier(referringLink) {
1351
- return __awaiter(this, void 0, void 0, function* () {
1352
- console.log('[Insert Affiliate] Setting affiliate identifier.');
1353
- verboseLog(`Input referringLink: ${referringLink}`);
1354
- try {
1355
- verboseLog('Generating or retrieving user ID...');
1356
- const customerID = yield generateThenSetUserID();
1357
- console.log('[Insert Affiliate] Completed generateThenSetUserID within setInsertAffiliateIdentifier.');
1358
- verboseLog(`Customer ID: ${customerID}`);
1359
- if (!referringLink) {
1360
- console.warn('[Insert Affiliate] Referring link is invalid.');
1361
- verboseLog('Referring link is empty or invalid, storing as-is');
1362
- yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1363
- return `${referringLink}-${customerID}`;
1364
- }
1365
- // Get company code from state or storage
1366
- verboseLog('Getting company code...');
1367
- const activeCompanyCode = yield getActiveCompanyCode();
1368
- verboseLog(`Active company code: ${activeCompanyCode || 'Not found'}`);
1369
- if (!activeCompanyCode) {
1370
- console.error('[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.');
1371
- verboseLog('Company code missing, cannot proceed with API call');
1372
- return;
1373
- }
1374
- // Check if referring link is already a short code, if so save it and stop here.
1375
- verboseLog('Checking if referring link is already a short code...');
1376
- if (isShortCode(referringLink)) {
1377
- console.log('[Insert Affiliate] Referring link is already a short code.');
1378
- verboseLog('Link is already a short code, storing directly');
1379
- yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1380
- return `${referringLink}-${customerID}`;
1381
- }
1382
- verboseLog('Link is not a short code, will convert via API');
1383
- // If the code is not already a short code, encode it raedy to send to our endpoint to return the short code. Save it before making the call in case something goes wrong
1384
- // Encode the referring link
1385
- verboseLog('Encoding referring link for API call...');
1386
- const encodedAffiliateLink = encodeURIComponent(referringLink);
1387
- if (!encodedAffiliateLink) {
1388
- console.error('[Insert Affiliate] Failed to encode affiliate link.');
1389
- verboseLog('Failed to encode link, storing original');
1390
- yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1391
- return `${referringLink}-${customerID}`;
1392
- }
1393
- // Create the request URL
1394
- const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${activeCompanyCode}&deepLinkUrl=${encodedAffiliateLink}`;
1395
- console.log('[Insert Affiliate] urlString .', urlString);
1396
- verboseLog('Making API request to convert deep link to short code...');
1397
- const response = yield axios_1.default.get(urlString, {
1398
- headers: {
1399
- 'Content-Type': 'application/json',
1400
- },
1401
- });
1402
- verboseLog(`API response status: ${response.status}`);
1403
- // Call to the backend for the short code and save the resolse in valid
1404
- if (response.status === 200 && response.data.shortLink) {
1405
- const shortLink = response.data.shortLink;
1406
- console.log('[Insert Affiliate] Short link received:', shortLink);
1407
- verboseLog(`Successfully converted to short link: ${shortLink}`);
1408
- verboseLog('Storing short link to AsyncStorage...');
1409
- yield storeInsertAffiliateIdentifier({ link: shortLink, source: 'referring_link' });
1410
- verboseLog('Short link stored successfully');
1411
- return `${shortLink}-${customerID}`;
1412
- }
1413
- else {
1414
- console.warn('[Insert Affiliate] Unexpected response format.');
1415
- verboseLog(`Unexpected API response. Status: ${response.status}, Data: ${JSON.stringify(response.data)}`);
1416
- verboseLog('Storing original link as fallback');
1417
- yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1418
- return `${referringLink}-${customerID}`;
1419
- }
1397
+ const setInsertAffiliateIdentifierImpl = (referringLink) => __awaiter(void 0, void 0, void 0, function* () {
1398
+ console.log('[Insert Affiliate] Setting affiliate identifier.');
1399
+ verboseLog(`Input referringLink: ${referringLink}`);
1400
+ try {
1401
+ verboseLog('Generating or retrieving user ID...');
1402
+ const customerID = yield generateThenSetUserID();
1403
+ console.log('[Insert Affiliate] Completed generateThenSetUserID within setInsertAffiliateIdentifier.');
1404
+ verboseLog(`Customer ID: ${customerID}`);
1405
+ if (!referringLink) {
1406
+ console.warn('[Insert Affiliate] Referring link is invalid.');
1407
+ verboseLog('Referring link is empty or invalid, storing as-is');
1408
+ yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1409
+ return `${referringLink}-${customerID}`;
1410
+ }
1411
+ // Get company code from state or storage
1412
+ verboseLog('Getting company code...');
1413
+ const activeCompanyCode = yield getActiveCompanyCode();
1414
+ verboseLog(`Active company code: ${activeCompanyCode || 'Not found'}`);
1415
+ if (!activeCompanyCode) {
1416
+ console.error('[Insert Affiliate] Company code is not set. Please initialize the SDK with a valid company code.');
1417
+ verboseLog('Company code missing, cannot proceed with API call');
1418
+ return;
1420
1419
  }
1421
- catch (error) {
1422
- console.error('[Insert Affiliate] Error:', error);
1423
- verboseLog(`Error in setInsertAffiliateIdentifier: ${error}`);
1420
+ // Check if referring link is already a short code, if so save it and stop here.
1421
+ verboseLog('Checking if referring link is already a short code...');
1422
+ if (isShortCode(referringLink)) {
1423
+ console.log('[Insert Affiliate] Referring link is already a short code.');
1424
+ verboseLog('Link is already a short code, storing directly');
1425
+ yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1426
+ return `${referringLink}-${customerID}`;
1427
+ }
1428
+ verboseLog('Link is not a short code, will convert via API');
1429
+ // If the code is not already a short code, encode it raedy to send to our endpoint to return the short code. Save it before making the call in case something goes wrong
1430
+ // Encode the referring link
1431
+ verboseLog('Encoding referring link for API call...');
1432
+ const encodedAffiliateLink = encodeURIComponent(referringLink);
1433
+ if (!encodedAffiliateLink) {
1434
+ console.error('[Insert Affiliate] Failed to encode affiliate link.');
1435
+ verboseLog('Failed to encode link, storing original');
1436
+ yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1437
+ return `${referringLink}-${customerID}`;
1438
+ }
1439
+ // Create the request URL
1440
+ const urlString = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${activeCompanyCode}&deepLinkUrl=${encodedAffiliateLink}`;
1441
+ console.log('[Insert Affiliate] urlString .', urlString);
1442
+ verboseLog('Making API request to convert deep link to short code...');
1443
+ const response = yield axios_1.default.get(urlString, {
1444
+ headers: {
1445
+ 'Content-Type': 'application/json',
1446
+ },
1447
+ });
1448
+ verboseLog(`API response status: ${response.status}`);
1449
+ // Call to the backend for the short code and save the resolse in valid
1450
+ if (response.status === 200 && response.data.shortLink) {
1451
+ const shortLink = response.data.shortLink;
1452
+ console.log('[Insert Affiliate] Short link received:', shortLink);
1453
+ verboseLog(`Successfully converted to short link: ${shortLink}`);
1454
+ verboseLog('Storing short link to AsyncStorage...');
1455
+ yield storeInsertAffiliateIdentifier({ link: shortLink, source: 'referring_link' });
1456
+ verboseLog('Short link stored successfully');
1457
+ return `${shortLink}-${customerID}`;
1424
1458
  }
1425
- });
1426
- }
1427
- ;
1459
+ else {
1460
+ console.warn('[Insert Affiliate] Unexpected response format.');
1461
+ verboseLog(`Unexpected API response. Status: ${response.status}, Data: ${JSON.stringify(response.data)}`);
1462
+ verboseLog('Storing original link as fallback');
1463
+ yield storeInsertAffiliateIdentifier({ link: referringLink, source: 'referring_link' });
1464
+ return `${referringLink}-${customerID}`;
1465
+ }
1466
+ }
1467
+ catch (error) {
1468
+ console.error('[Insert Affiliate] Error:', error);
1469
+ verboseLog(`Error in setInsertAffiliateIdentifier: ${error}`);
1470
+ }
1471
+ });
1428
1472
  function storeInsertAffiliateIdentifier(_a) {
1429
1473
  return __awaiter(this, arguments, void 0, function* ({ link, source }) {
1430
1474
  console.log(`[Insert Affiliate] Storing affiliate identifier: ${link} (source: ${source})`);
@@ -1448,18 +1492,18 @@ const DeepLinkIapProvider = ({ children, }) => {
1448
1492
  yield retrieveAndStoreOfferCode(link);
1449
1493
  // Trigger callback with the current affiliate identifier
1450
1494
  if (insertAffiliateIdentifierChangeCallbackRef.current) {
1451
- const currentIdentifier = yield returnInsertAffiliateIdentifier();
1495
+ const currentIdentifier = yield returnInsertAffiliateIdentifierImpl();
1452
1496
  verboseLog(`Triggering callback with identifier: ${currentIdentifier}`);
1453
1497
  insertAffiliateIdentifierChangeCallbackRef.current(currentIdentifier);
1454
1498
  }
1455
1499
  // Report this new affiliate association to the backend (fire and forget)
1456
- const fullIdentifier = yield returnInsertAffiliateIdentifier();
1500
+ const fullIdentifier = yield returnInsertAffiliateIdentifierImpl();
1457
1501
  if (fullIdentifier) {
1458
1502
  reportAffiliateAssociationIfNeeded(fullIdentifier, source);
1459
1503
  }
1460
1504
  });
1461
1505
  }
1462
- const validatePurchaseWithIapticAPI = (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
1506
+ const validatePurchaseWithIapticAPIImpl = (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
1463
1507
  var _a;
1464
1508
  try {
1465
1509
  // Check for E_IAP_NOT_AVAILABLE error in development environment
@@ -1498,7 +1542,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1498
1542
  };
1499
1543
  }
1500
1544
  const requestBody = Object.assign(Object.assign({}, baseRequestBody), { transaction });
1501
- let insertAffiliateIdentifier = yield returnInsertAffiliateIdentifier();
1545
+ let insertAffiliateIdentifier = yield returnInsertAffiliateIdentifierImpl();
1502
1546
  if (insertAffiliateIdentifier) {
1503
1547
  requestBody.additionalData = {
1504
1548
  applicationUsername: `${insertAffiliateIdentifier}`,
@@ -1545,7 +1589,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1545
1589
  return false;
1546
1590
  }
1547
1591
  });
1548
- const storeExpectedStoreTransaction = (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () {
1592
+ const storeExpectedStoreTransactionImpl = (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () {
1549
1593
  verboseLog(`Storing expected store transaction with token: ${purchaseToken}`);
1550
1594
  const activeCompanyCode = yield getActiveCompanyCode();
1551
1595
  if (!activeCompanyCode) {
@@ -1553,7 +1597,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1553
1597
  verboseLog("Cannot store transaction: no company code available");
1554
1598
  return;
1555
1599
  }
1556
- const shortCode = yield returnInsertAffiliateIdentifier();
1600
+ const shortCode = yield returnInsertAffiliateIdentifierImpl();
1557
1601
  if (!shortCode) {
1558
1602
  console.error("[Insert Affiliate] No affiliate identifier found. Please set one before tracking events.");
1559
1603
  verboseLog("Cannot store transaction: no affiliate identifier available");
@@ -1594,7 +1638,7 @@ const DeepLinkIapProvider = ({ children, }) => {
1594
1638
  }
1595
1639
  });
1596
1640
  // MARK: Track Event
1597
- const trackEvent = (eventName) => __awaiter(void 0, void 0, void 0, function* () {
1641
+ const trackEventImpl = (eventName) => __awaiter(void 0, void 0, void 0, function* () {
1598
1642
  try {
1599
1643
  verboseLog(`Tracking event: ${eventName}`);
1600
1644
  const activeCompanyCode = yield getActiveCompanyCode();
@@ -1715,6 +1759,75 @@ const DeepLinkIapProvider = ({ children, }) => {
1715
1759
  // Remove special characters, keep only alphanumeric
1716
1760
  return removeSpecialCharacters(offerCode);
1717
1761
  };
1762
+ // ============================================================================
1763
+ // REF CALLBACK PATTERN: Update refs on every render for fresh closures
1764
+ // ============================================================================
1765
+ initializeImplRef.current = initializeImpl;
1766
+ setShortCodeImplRef.current = setShortCodeImpl;
1767
+ getAffiliateDetailsImplRef.current = getAffiliateDetailsImpl;
1768
+ returnInsertAffiliateIdentifierImplRef.current = returnInsertAffiliateIdentifierImpl;
1769
+ isAffiliateAttributionValidImplRef.current = isAffiliateAttributionValidImpl;
1770
+ getAffiliateStoredDateImplRef.current = getAffiliateStoredDateImpl;
1771
+ storeExpectedStoreTransactionImplRef.current = storeExpectedStoreTransactionImpl;
1772
+ returnUserAccountTokenAndStoreExpectedTransactionImplRef.current = returnUserAccountTokenAndStoreExpectedTransactionImpl;
1773
+ validatePurchaseWithIapticAPIImplRef.current = validatePurchaseWithIapticAPIImpl;
1774
+ trackEventImplRef.current = trackEventImpl;
1775
+ setInsertAffiliateIdentifierImplRef.current = setInsertAffiliateIdentifierImpl;
1776
+ handleInsertLinksImplRef.current = handleInsertLinksImpl;
1777
+ // ============================================================================
1778
+ // STABLE WRAPPERS: useCallback with [] deps that delegate to refs
1779
+ // These provide stable function references that always call current implementations
1780
+ // ============================================================================
1781
+ const initialize = (0, react_1.useCallback)((code, verboseLogging, insertLinksEnabled, insertLinksClipboardEnabled, affiliateAttributionActiveTime) => __awaiter(void 0, void 0, void 0, function* () {
1782
+ return initializeImplRef.current(code, verboseLogging, insertLinksEnabled, insertLinksClipboardEnabled, affiliateAttributionActiveTime);
1783
+ }), []);
1784
+ const setShortCode = (0, react_1.useCallback)((shortCode) => __awaiter(void 0, void 0, void 0, function* () {
1785
+ return setShortCodeImplRef.current(shortCode);
1786
+ }), []);
1787
+ const getAffiliateDetails = (0, react_1.useCallback)((affiliateCode) => __awaiter(void 0, void 0, void 0, function* () {
1788
+ return getAffiliateDetailsImplRef.current(affiliateCode);
1789
+ }), []);
1790
+ const returnInsertAffiliateIdentifier = (0, react_1.useCallback)((ignoreTimeout) => __awaiter(void 0, void 0, void 0, function* () {
1791
+ return returnInsertAffiliateIdentifierImplRef.current(ignoreTimeout);
1792
+ }), []);
1793
+ const isAffiliateAttributionValid = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
1794
+ return isAffiliateAttributionValidImplRef.current();
1795
+ }), []);
1796
+ const getAffiliateStoredDate = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
1797
+ return getAffiliateStoredDateImplRef.current();
1798
+ }), []);
1799
+ const storeExpectedStoreTransaction = (0, react_1.useCallback)((purchaseToken) => __awaiter(void 0, void 0, void 0, function* () {
1800
+ return storeExpectedStoreTransactionImplRef.current(purchaseToken);
1801
+ }), []);
1802
+ const returnUserAccountTokenAndStoreExpectedTransaction = (0, react_1.useCallback)(() => __awaiter(void 0, void 0, void 0, function* () {
1803
+ return returnUserAccountTokenAndStoreExpectedTransactionImplRef.current();
1804
+ }), []);
1805
+ const validatePurchaseWithIapticAPI = (0, react_1.useCallback)((jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
1806
+ return validatePurchaseWithIapticAPIImplRef.current(jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey);
1807
+ }), []);
1808
+ const trackEvent = (0, react_1.useCallback)((eventName) => __awaiter(void 0, void 0, void 0, function* () {
1809
+ return trackEventImplRef.current(eventName);
1810
+ }), []);
1811
+ const setInsertAffiliateIdentifier = (0, react_1.useCallback)((referringLink) => __awaiter(void 0, void 0, void 0, function* () {
1812
+ return setInsertAffiliateIdentifierImplRef.current(referringLink);
1813
+ }), []);
1814
+ const setInsertAffiliateIdentifierChangeCallbackHandler = (0, react_1.useCallback)((callback) => {
1815
+ insertAffiliateIdentifierChangeCallbackRef.current = callback;
1816
+ // If callback is being set, immediately call it with the current identifier value
1817
+ // This ensures callbacks registered after initialization still receive the current state (including null if expired/not set)
1818
+ if (callback) {
1819
+ returnInsertAffiliateIdentifierImpl().then(identifier => {
1820
+ // Verify callback is still the same (wasn't replaced during async operation)
1821
+ if (insertAffiliateIdentifierChangeCallbackRef.current === callback) {
1822
+ verboseLog(`Calling callback immediately with current identifier: ${identifier}`);
1823
+ callback(identifier);
1824
+ }
1825
+ });
1826
+ }
1827
+ }, []);
1828
+ const handleInsertLinks = (0, react_1.useCallback)((url) => __awaiter(void 0, void 0, void 0, function* () {
1829
+ return handleInsertLinksImplRef.current(url);
1830
+ }), []);
1718
1831
  return (react_1.default.createElement(exports.DeepLinkIapContext.Provider, { value: {
1719
1832
  referrerLink,
1720
1833
  userId,