insert-affiliate-react-native-sdk 1.6.3 → 1.7.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.
@@ -40,6 +40,10 @@ const react_1 = __importStar(require("react"));
40
40
  const react_native_1 = require("react-native");
41
41
  const axios_1 = __importDefault(require("axios"));
42
42
  const async_storage_1 = __importDefault(require("@react-native-async-storage/async-storage"));
43
+ const clipboard_1 = __importDefault(require("@react-native-clipboard/clipboard"));
44
+ const netinfo_1 = __importDefault(require("@react-native-community/netinfo"));
45
+ const react_native_device_info_1 = __importDefault(require("react-native-device-info"));
46
+ const react_native_play_install_referrer_1 = require("react-native-play-install-referrer");
43
47
  const ASYNC_KEYS = {
44
48
  REFERRER_LINK: '@app_referrer_link',
45
49
  USER_PURCHASE: '@app_user_purchase',
@@ -47,20 +51,25 @@ const ASYNC_KEYS = {
47
51
  COMPANY_CODE: '@app_company_code',
48
52
  USER_ACCOUNT_TOKEN: '@app_user_account_token',
49
53
  IOS_OFFER_CODE: '@app_ios_offer_code',
54
+ AFFILIATE_STORED_DATE: '@app_affiliate_stored_date',
50
55
  };
51
56
  // STARTING CONTEXT IMPLEMENTATION
52
57
  exports.DeepLinkIapContext = (0, react_1.createContext)({
53
58
  referrerLink: '',
54
59
  userId: '',
55
60
  OfferCode: null,
56
- returnInsertAffiliateIdentifier: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
61
+ returnInsertAffiliateIdentifier: (ignoreTimeout) => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
62
+ isAffiliateAttributionValid: () => __awaiter(void 0, void 0, void 0, function* () { return false; }),
63
+ getAffiliateStoredDate: () => __awaiter(void 0, void 0, void 0, function* () { return null; }),
57
64
  validatePurchaseWithIapticAPI: (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
58
65
  returnUserAccountTokenAndStoreExpectedTransaction: () => __awaiter(void 0, void 0, void 0, function* () { return ''; }),
59
66
  storeExpectedStoreTransaction: (purchaseToken) => __awaiter(void 0, void 0, void 0, function* () { }),
60
67
  trackEvent: (eventName) => __awaiter(void 0, void 0, void 0, function* () { }),
61
68
  setShortCode: (shortCode) => __awaiter(void 0, void 0, void 0, function* () { }),
62
69
  setInsertAffiliateIdentifier: (referringLink) => __awaiter(void 0, void 0, void 0, function* () { }),
63
- initialize: (code, verboseLogging) => __awaiter(void 0, void 0, void 0, function* () { }),
70
+ setInsertAffiliateIdentifierChangeCallback: (callback) => { },
71
+ handleInsertLinks: (url) => __awaiter(void 0, void 0, void 0, function* () { return false; }),
72
+ initialize: (code, verboseLogging, insertLinksEnabled, insertLinksClipboardEnabled, affiliateAttributionActiveTime) => __awaiter(void 0, void 0, void 0, function* () { }),
64
73
  isInitialized: false,
65
74
  });
66
75
  const DeepLinkIapProvider = ({ children, }) => {
@@ -69,10 +78,19 @@ const DeepLinkIapProvider = ({ children, }) => {
69
78
  const [companyCode, setCompanyCode] = (0, react_1.useState)(null);
70
79
  const [isInitialized, setIsInitialized] = (0, react_1.useState)(false);
71
80
  const [verboseLogging, setVerboseLogging] = (0, react_1.useState)(false);
81
+ const [insertLinksEnabled, setInsertLinksEnabled] = (0, react_1.useState)(false);
82
+ const [insertLinksClipboardEnabled, setInsertLinksClipboardEnabled] = (0, react_1.useState)(false);
72
83
  const [OfferCode, setOfferCode] = (0, react_1.useState)(null);
84
+ const [affiliateAttributionActiveTime, setAffiliateAttributionActiveTime] = (0, react_1.useState)(null);
85
+ const insertAffiliateIdentifierChangeCallbackRef = (0, react_1.useRef)(null);
73
86
  // MARK: Initialize the SDK
74
- const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false) {
87
+ const initialize = (companyCode_1, ...args_1) => __awaiter(void 0, [companyCode_1, ...args_1], void 0, function* (companyCode, verboseLogging = false, insertLinksEnabled = false, insertLinksClipboardEnabled = false, affiliateAttributionActiveTime) {
75
88
  setVerboseLogging(verboseLogging);
89
+ setInsertLinksEnabled(insertLinksEnabled);
90
+ setInsertLinksClipboardEnabled(insertLinksClipboardEnabled);
91
+ if (affiliateAttributionActiveTime !== undefined) {
92
+ setAffiliateAttributionActiveTime(affiliateAttributionActiveTime);
93
+ }
76
94
  if (verboseLogging) {
77
95
  console.log('[Insert Affiliate] [VERBOSE] Starting SDK initialization...');
78
96
  console.log('[Insert Affiliate] [VERBOSE] Company code provided:', companyCode ? 'Yes' : 'No');
@@ -99,6 +117,15 @@ const DeepLinkIapProvider = ({ children, }) => {
99
117
  console.log('[Insert Affiliate] [VERBOSE] No company code provided, SDK initialized in limited mode');
100
118
  }
101
119
  }
120
+ if (insertLinksEnabled && react_native_1.Platform.OS === 'ios') {
121
+ try {
122
+ const enhancedSystemInfo = yield getEnhancedSystemInfo();
123
+ yield sendSystemInfoToBackend(enhancedSystemInfo);
124
+ }
125
+ catch (error) {
126
+ verboseLog(`Error sending system info for clipboard check: ${error}`);
127
+ }
128
+ }
102
129
  });
103
130
  // EFFECT TO FETCH USER ID AND REF LINK
104
131
  // IF ALREADY EXISTS IN ASYNC STORAGE
@@ -135,6 +162,93 @@ const DeepLinkIapProvider = ({ children, }) => {
135
162
  });
136
163
  fetchAsyncEssentials();
137
164
  }, []);
165
+ // Cleanup callback on unmount
166
+ (0, react_1.useEffect)(() => {
167
+ return () => {
168
+ insertAffiliateIdentifierChangeCallbackRef.current = null;
169
+ };
170
+ }, []);
171
+ // Deep link event listeners - equivalent to iOS AppDelegate methods
172
+ (0, react_1.useEffect)(() => {
173
+ if (!isInitialized)
174
+ return;
175
+ // Handle app launch with URL (equivalent to didFinishLaunchingWithOptions)
176
+ const handleInitialURL = () => __awaiter(void 0, void 0, void 0, function* () {
177
+ try {
178
+ const initialUrl = yield react_native_1.Linking.getInitialURL();
179
+ if (initialUrl) {
180
+ verboseLog(`App launched with URL: ${initialUrl}`);
181
+ const handled = yield handleDeepLink(initialUrl);
182
+ if (handled) {
183
+ verboseLog('URL was handled by Insert Affiliate SDK');
184
+ }
185
+ else {
186
+ verboseLog('URL was not handled by Insert Affiliate SDK');
187
+ }
188
+ }
189
+ }
190
+ catch (error) {
191
+ console.error('[Insert Affiliate] Error getting initial URL:', error);
192
+ }
193
+ });
194
+ // Handle URL opening while app is running (equivalent to open url)
195
+ const handleUrlChange = (event) => __awaiter(void 0, void 0, void 0, function* () {
196
+ try {
197
+ verboseLog(`URL opened while app running: ${event.url}`);
198
+ const handled = yield handleDeepLink(event.url);
199
+ if (handled) {
200
+ verboseLog('URL was handled by Insert Affiliate SDK');
201
+ }
202
+ else {
203
+ verboseLog('URL was not handled by Insert Affiliate SDK');
204
+ }
205
+ }
206
+ catch (error) {
207
+ console.error('[Insert Affiliate] Error handling URL change:', error);
208
+ }
209
+ });
210
+ // Platform-specific deep link handler
211
+ const handleDeepLink = (url) => __awaiter(void 0, void 0, void 0, function* () {
212
+ try {
213
+ verboseLog(`Platform detection: Platform.OS = ${react_native_1.Platform.OS}`);
214
+ if (react_native_1.Platform.OS === 'ios') {
215
+ verboseLog('Routing to iOS handler (handleInsertLinks)');
216
+ return yield handleInsertLinks(url);
217
+ }
218
+ else if (react_native_1.Platform.OS === 'android') {
219
+ verboseLog('Routing to Android handler (handleInsertLinkAndroid)');
220
+ return yield handleInsertLinkAndroid(url);
221
+ }
222
+ verboseLog(`Unrecognized platform: ${react_native_1.Platform.OS}`);
223
+ return false;
224
+ }
225
+ catch (error) {
226
+ verboseLog(`Error handling deep link: ${error}`);
227
+ return false;
228
+ }
229
+ });
230
+ // Set up listeners
231
+ const urlListener = react_native_1.Linking.addEventListener('url', handleUrlChange);
232
+ // Handle initial URL
233
+ handleInitialURL();
234
+ // Cleanup
235
+ return () => {
236
+ urlListener === null || urlListener === void 0 ? void 0 : urlListener.remove();
237
+ };
238
+ }, [isInitialized]);
239
+ // EFFECT TO HANDLE INSTALL REFERRER ON ANDROID
240
+ (0, react_1.useEffect)(() => {
241
+ if (react_native_1.Platform.OS === 'android' && isInitialized && insertLinksEnabled) {
242
+ verboseLog('Install referrer effect - Platform.OS is android, isInitialized is true, and insertLinksEnabled is true');
243
+ // Ensure user ID is generated before processing install referrer
244
+ const initializeAndCapture = () => __awaiter(void 0, void 0, void 0, function* () {
245
+ yield generateThenSetUserID();
246
+ verboseLog('Install referrer effect - Generating user ID and capturing install referrer');
247
+ captureInstallReferrer();
248
+ });
249
+ initializeAndCapture();
250
+ }
251
+ }, [isInitialized, insertLinksEnabled]);
138
252
  function generateThenSetUserID() {
139
253
  return __awaiter(this, void 0, void 0, function* () {
140
254
  verboseLog('Getting or generating user ID...');
@@ -167,6 +281,304 @@ const DeepLinkIapProvider = ({ children, }) => {
167
281
  setIsInitialized(false);
168
282
  console.log('[Insert Affiliate] SDK has been reset.');
169
283
  };
284
+ // MARK: Callback Management
285
+ // Sets a callback that will be triggered whenever storeInsertAffiliateIdentifier is called
286
+ // The callback receives the current affiliate identifier (returnInsertAffiliateIdentifier result)
287
+ const setInsertAffiliateIdentifierChangeCallbackHandler = (callback) => {
288
+ insertAffiliateIdentifierChangeCallbackRef.current = callback;
289
+ };
290
+ // MARK: Deep Link Handling
291
+ // Helper function to parse URLs in React Native compatible way
292
+ const parseURL = (url) => {
293
+ try {
294
+ // Extract protocol
295
+ const protocolMatch = url.match(/^([^:]+):/);
296
+ const protocol = protocolMatch ? protocolMatch[1] + ':' : '';
297
+ // Extract hostname for https URLs
298
+ let hostname = '';
299
+ if (protocol === 'https:' || protocol === 'http:') {
300
+ const hostnameMatch = url.match(/^https?:\/\/([^\/]+)/);
301
+ hostname = hostnameMatch ? hostnameMatch[1] : '';
302
+ }
303
+ return {
304
+ protocol,
305
+ hostname,
306
+ href: url
307
+ };
308
+ }
309
+ catch (error) {
310
+ return {
311
+ protocol: '',
312
+ hostname: '',
313
+ href: url
314
+ };
315
+ }
316
+ };
317
+ // Handles Android deep links with insertAffiliate parameter
318
+ const handleInsertLinkAndroid = (url) => __awaiter(void 0, void 0, void 0, function* () {
319
+ try {
320
+ // Check if deep links are enabled
321
+ if (!insertLinksEnabled) {
322
+ verboseLog('Deep links are disabled, not handling Android URL');
323
+ return false;
324
+ }
325
+ verboseLog(`Processing Android deep link: ${url}`);
326
+ if (!url || typeof url !== 'string') {
327
+ verboseLog('Invalid URL provided to handleInsertLinkAndroid');
328
+ return false;
329
+ }
330
+ // Parse the URL to extract query parameters
331
+ const urlObj = new URL(url);
332
+ const insertAffiliate = urlObj.searchParams.get('insertAffiliate');
333
+ if (insertAffiliate && insertAffiliate.length > 0) {
334
+ verboseLog(`Found insertAffiliate parameter: ${insertAffiliate}`);
335
+ yield storeInsertAffiliateIdentifier({ link: insertAffiliate });
336
+ return true;
337
+ }
338
+ else {
339
+ verboseLog('No insertAffiliate parameter found in Android deep link');
340
+ return false;
341
+ }
342
+ }
343
+ catch (error) {
344
+ verboseLog(`Error handling Android deep link: ${error}`);
345
+ return false;
346
+ }
347
+ });
348
+ // MARK: Play Install Referrer
349
+ /**
350
+ * Captures install referrer data from Google Play Store
351
+ * This method automatically extracts referral parameters and processes them
352
+ */
353
+ const captureInstallReferrer = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (retryCount = 0) {
354
+ try {
355
+ // Check if deep links are enabled
356
+ if (!insertLinksEnabled) {
357
+ verboseLog('Deep links are disabled, not processing install referrer');
358
+ return false;
359
+ }
360
+ // Check if we're on Android
361
+ if (react_native_1.Platform.OS !== 'android') {
362
+ verboseLog('Install referrer is only available on Android');
363
+ return false;
364
+ }
365
+ verboseLog(`Starting install referrer capture... (attempt ${retryCount + 1})`);
366
+ // Convert callback-based API to Promise with timeout
367
+ const referrerData = yield new Promise((resolve, reject) => {
368
+ const timeout = setTimeout(() => {
369
+ reject(new Error('Install referrer request timed out'));
370
+ }, 10000); // 10 second timeout
371
+ react_native_play_install_referrer_1.PlayInstallReferrer.getInstallReferrerInfo((info, error) => {
372
+ clearTimeout(timeout);
373
+ if (error) {
374
+ reject(error);
375
+ }
376
+ else {
377
+ resolve(info);
378
+ }
379
+ });
380
+ });
381
+ if (referrerData && referrerData.installReferrer) {
382
+ verboseLog(`Raw install referrer data: ${referrerData.installReferrer}`);
383
+ const success = yield processInstallReferrerData(referrerData.installReferrer);
384
+ if (success) {
385
+ verboseLog('Install referrer processed successfully');
386
+ return true;
387
+ }
388
+ else {
389
+ verboseLog('No insertAffiliate parameter found in install referrer');
390
+ return false;
391
+ }
392
+ }
393
+ else {
394
+ verboseLog('No install referrer data found');
395
+ return false;
396
+ }
397
+ }
398
+ catch (error) {
399
+ const errorMessage = error instanceof Error ? error.message : String(error);
400
+ verboseLog(`Error capturing install referrer (attempt ${retryCount + 1}): ${errorMessage}`);
401
+ // Check if this is a retryable error and we haven't exceeded max retries
402
+ const isRetryableError = errorMessage.includes('SERVICE_UNAVAILABLE') ||
403
+ errorMessage.includes('DEVELOPER_ERROR') ||
404
+ errorMessage.includes('timed out') ||
405
+ errorMessage.includes('SERVICE_DISCONNECTED');
406
+ const maxRetries = 3;
407
+ const retryDelay = Math.min(1000 * Math.pow(2, retryCount), 10000); // Exponential backoff, max 10s
408
+ if (isRetryableError && retryCount < maxRetries) {
409
+ verboseLog(`Retrying install referrer capture in ${retryDelay}ms...`);
410
+ // Schedule retry
411
+ setTimeout(() => {
412
+ captureInstallReferrer(retryCount + 1);
413
+ }, retryDelay);
414
+ return false;
415
+ }
416
+ else {
417
+ verboseLog(`Install referrer capture failed after ${retryCount + 1} attempts`);
418
+ return false;
419
+ }
420
+ }
421
+ });
422
+ /**
423
+ * Processes the raw install referrer data and extracts insertAffiliate parameter
424
+ * @param rawReferrer The raw referrer string from Play Store
425
+ */
426
+ const processInstallReferrerData = (rawReferrer) => __awaiter(void 0, void 0, void 0, function* () {
427
+ try {
428
+ verboseLog('Processing install referrer data...');
429
+ if (!rawReferrer || rawReferrer.length === 0) {
430
+ verboseLog('No referrer data provided');
431
+ return false;
432
+ }
433
+ verboseLog(`Raw referrer data: ${rawReferrer}`);
434
+ // Parse the referrer string directly for insertAffiliate parameter
435
+ let insertAffiliate = null;
436
+ if (rawReferrer.includes('insertAffiliate=')) {
437
+ const params = rawReferrer.split('&');
438
+ for (const param of params) {
439
+ if (param.startsWith('insertAffiliate=')) {
440
+ insertAffiliate = param.substring('insertAffiliate='.length);
441
+ break;
442
+ }
443
+ }
444
+ }
445
+ verboseLog(`Extracted insertAffiliate parameter: ${insertAffiliate}`);
446
+ // If we have insertAffiliate parameter, use it as the affiliate identifier
447
+ if (insertAffiliate && insertAffiliate.length > 0) {
448
+ verboseLog(`Found insertAffiliate parameter, setting as affiliate identifier: ${insertAffiliate}`);
449
+ yield storeInsertAffiliateIdentifier({ link: insertAffiliate });
450
+ return true;
451
+ }
452
+ else {
453
+ verboseLog('No insertAffiliate parameter found in referrer data');
454
+ return false;
455
+ }
456
+ }
457
+ catch (error) {
458
+ verboseLog(`Error processing install referrer data: ${error}`);
459
+ return false;
460
+ }
461
+ });
462
+ // Handles Insert Links deep linking - equivalent to iOS handleInsertLinks
463
+ const handleInsertLinks = (url) => __awaiter(void 0, void 0, void 0, function* () {
464
+ try {
465
+ console.log(`[Insert Affiliate] Attempting to handle URL: ${url}`);
466
+ if (!url || typeof url !== 'string') {
467
+ console.log('[Insert Affiliate] Invalid URL provided to handleInsertLinks');
468
+ return false;
469
+ }
470
+ // Check if deep links are enabled synchronously
471
+ if (!insertLinksEnabled) {
472
+ console.log('[Insert Affiliate] Deep links are disabled, not handling URL');
473
+ return false;
474
+ }
475
+ const urlObj = parseURL(url);
476
+ // Handle custom URL schemes (ia-companycode://shortcode)
477
+ if (urlObj.protocol && urlObj.protocol.startsWith('ia-')) {
478
+ return yield handleCustomURLScheme(url, urlObj.protocol);
479
+ }
480
+ // Handle universal links (https://insertaffiliate.link/V1/companycode/shortcode)
481
+ // if (urlObj.protocol === 'https:' && urlObj.hostname?.includes('insertaffiliate.link')) {
482
+ // return await handleUniversalLink(urlObj);
483
+ // }
484
+ return false;
485
+ }
486
+ catch (error) {
487
+ console.error('[Insert Affiliate] Error handling Insert Link:', error);
488
+ verboseLog(`Error in handleInsertLinks: ${error}`);
489
+ return false;
490
+ }
491
+ });
492
+ // Handle custom URL schemes like ia-companycode://shortcode
493
+ const handleCustomURLScheme = (url, protocol) => __awaiter(void 0, void 0, void 0, function* () {
494
+ try {
495
+ const scheme = protocol.replace(':', '');
496
+ if (!scheme.startsWith('ia-')) {
497
+ return false;
498
+ }
499
+ // Extract company code from scheme (remove "ia-" prefix)
500
+ const companyCode = scheme.substring(3);
501
+ const shortCode = parseShortCodeFromURLString(url);
502
+ if (!shortCode) {
503
+ console.log(`[Insert Affiliate] Failed to parse short code from deep link: ${url}`);
504
+ return false;
505
+ }
506
+ console.log(`[Insert Affiliate] Custom URL scheme detected - Company: ${companyCode}, Short code: ${shortCode}`);
507
+ // Validate company code matches initialized one
508
+ const activeCompanyCode = yield getActiveCompanyCode();
509
+ if (activeCompanyCode && companyCode.toLowerCase() !== activeCompanyCode.toLowerCase()) {
510
+ console.log(`[Insert Affiliate] Warning: URL company code (${companyCode}) doesn't match initialized company code (${activeCompanyCode})`);
511
+ }
512
+ // If URL scheme is used, we can straight away store the short code as the referring link
513
+ yield storeInsertAffiliateIdentifier({ link: shortCode });
514
+ // Collect and send enhanced system info to backend
515
+ try {
516
+ const enhancedSystemInfo = yield getEnhancedSystemInfo();
517
+ yield sendSystemInfoToBackend(enhancedSystemInfo);
518
+ }
519
+ catch (error) {
520
+ verboseLog(`Error sending system info for deep link: ${error}`);
521
+ }
522
+ return true;
523
+ }
524
+ catch (error) {
525
+ console.error('[Insert Affiliate] Error handling custom URL scheme:', error);
526
+ return false;
527
+ }
528
+ });
529
+ // Handle universal links like https://insertaffiliate.link/V1/companycode/shortcode
530
+ // const handleUniversalLink = async (url: URL): Promise<boolean> => {
531
+ // try {
532
+ // const pathComponents = url.pathname.split('/').filter(segment => segment.length > 0);
533
+ // // Expected format: /V1/companycode/shortcode
534
+ // if (pathComponents.length < 3 || pathComponents[0] !== 'V1') {
535
+ // console.log(`[Insert Affiliate] Invalid universal link format: ${url.href}`);
536
+ // return false;
537
+ // }
538
+ // const companyCode = pathComponents[1];
539
+ // const shortCode = pathComponents[2];
540
+ // console.log(`[Insert Affiliate] Universal link detected - Company: ${companyCode}, Short code: ${shortCode}`);
541
+ // // Validate company code matches initialized one
542
+ // const activeCompanyCode = await getActiveCompanyCode();
543
+ // if (activeCompanyCode && companyCode.toLowerCase() !== activeCompanyCode.toLowerCase()) {
544
+ // console.log(`[Insert Affiliate] Warning: URL company code (${companyCode}) doesn't match initialized company code (${activeCompanyCode})`);
545
+ // }
546
+ // // Process the affiliate attribution
547
+ // await storeInsertAffiliateIdentifier({ link: shortCode });
548
+ // return true;
549
+ // } catch (error) {
550
+ // console.error('[Insert Affiliate] Error handling universal link:', error);
551
+ // return false;
552
+ // }
553
+ // };
554
+ // Parse short code from URL
555
+ const parseShortCodeFromURL = (url) => {
556
+ try {
557
+ // For custom schemes like ia-companycode://shortcode, everything after :// is the short code
558
+ // Remove leading slash from pathname
559
+ return url.pathname.startsWith('/') ? url.pathname.substring(1) : url.pathname;
560
+ }
561
+ catch (error) {
562
+ verboseLog(`Error parsing short code from URL: ${error}`);
563
+ return null;
564
+ }
565
+ };
566
+ const parseShortCodeFromURLString = (url) => {
567
+ try {
568
+ // For custom schemes like ia-companycode://shortcode, everything after :// is the short code
569
+ const match = url.match(/^[^:]+:\/\/(.+)$/);
570
+ if (match) {
571
+ const shortCode = match[1];
572
+ // Remove leading slash if present
573
+ return shortCode.startsWith('/') ? shortCode.substring(1) : shortCode;
574
+ }
575
+ return null;
576
+ }
577
+ catch (error) {
578
+ verboseLog(`Error parsing short code from URL string: ${error}`);
579
+ return null;
580
+ }
581
+ };
170
582
  // Helper funciton Storage / Retrieval
171
583
  const saveValueInAsync = (key, value) => __awaiter(void 0, void 0, void 0, function* () {
172
584
  yield async_storage_1.default.setItem(key, value);
@@ -215,6 +627,390 @@ const DeepLinkIapProvider = ({ children, }) => {
215
627
  break;
216
628
  }
217
629
  };
630
+ // MARK: - Deep Linking Utilities
631
+ // Retrieves and validates clipboard content for UUID format
632
+ const getClipboardUUID = () => __awaiter(void 0, void 0, void 0, function* () {
633
+ // Check if clipboard access is enabled
634
+ if (!insertLinksClipboardEnabled) {
635
+ return null;
636
+ }
637
+ verboseLog('Getting clipboard UUID');
638
+ try {
639
+ const clipboardString = yield clipboard_1.default.getString();
640
+ if (!clipboardString) {
641
+ verboseLog('No clipboard string found or access denied');
642
+ return null;
643
+ }
644
+ const trimmedString = clipboardString.trim();
645
+ if (isValidUUID(trimmedString)) {
646
+ verboseLog(`Valid clipboard UUID found: ${trimmedString}`);
647
+ return trimmedString;
648
+ }
649
+ verboseLog(`Invalid clipboard UUID found: ${trimmedString}`);
650
+ return null;
651
+ }
652
+ catch (error) {
653
+ verboseLog(`Clipboard access error: ${error}`);
654
+ return null;
655
+ }
656
+ });
657
+ // Validates if a string is a properly formatted UUID (36 characters)
658
+ const isValidUUID = (string) => {
659
+ if (string.length !== 36)
660
+ return false;
661
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
662
+ return uuidRegex.test(string);
663
+ };
664
+ // MARK: - System Info Collection
665
+ // Gets network connection type and interface information
666
+ const getNetworkInfo = () => __awaiter(void 0, void 0, void 0, function* () {
667
+ try {
668
+ const connectionInfo = {
669
+ connectionType: 'unknown',
670
+ interfaceTypes: [],
671
+ isExpensive: false,
672
+ isConstrained: false,
673
+ status: 'disconnected',
674
+ availableInterfaces: []
675
+ };
676
+ try {
677
+ // Use NetInfo to get accurate network information
678
+ const netInfo = yield netinfo_1.default.fetch();
679
+ connectionInfo.status = netInfo.isConnected ? 'connected' : 'disconnected';
680
+ connectionInfo.connectionType = netInfo.type || 'unknown';
681
+ connectionInfo.isExpensive = netInfo.isInternetReachable === false ? true : false;
682
+ connectionInfo.isConstrained = false; // NetInfo doesn't provide this directly
683
+ // Map NetInfo types to our interface format
684
+ if (netInfo.type) {
685
+ connectionInfo.interfaceTypes = [netInfo.type];
686
+ connectionInfo.availableInterfaces = [netInfo.type];
687
+ }
688
+ // Additional details if available
689
+ if (netInfo.details && 'isConnectionExpensive' in netInfo.details) {
690
+ connectionInfo.isExpensive = netInfo.details.isConnectionExpensive || false;
691
+ }
692
+ }
693
+ catch (error) {
694
+ verboseLog(`Network info fetch failed: ${error}`);
695
+ // Fallback to basic connectivity test
696
+ try {
697
+ const response = yield fetch('https://www.google.com/favicon.ico', {
698
+ method: 'HEAD'
699
+ });
700
+ if (response.ok) {
701
+ connectionInfo.status = 'connected';
702
+ }
703
+ }
704
+ catch (fetchError) {
705
+ verboseLog(`Fallback connectivity test failed: ${fetchError}`);
706
+ }
707
+ }
708
+ return connectionInfo;
709
+ }
710
+ catch (error) {
711
+ verboseLog(`Error getting network info: ${error}`);
712
+ return {
713
+ connectionType: 'unknown',
714
+ interfaceTypes: [],
715
+ isExpensive: false,
716
+ isConstrained: false,
717
+ status: 'disconnected',
718
+ availableInterfaces: []
719
+ };
720
+ }
721
+ });
722
+ const getNetworkPathInfo = () => __awaiter(void 0, void 0, void 0, function* () {
723
+ try {
724
+ const netInfo = yield netinfo_1.default.fetch();
725
+ // Default values - only set to true when proven
726
+ let supportsIPv4 = false;
727
+ let supportsIPv6 = false;
728
+ let supportsDNS = false;
729
+ let hasUnsatisfiedGateway = false;
730
+ let gatewayCount = 0;
731
+ let gateways = [];
732
+ let interfaceDetails = [];
733
+ if (netInfo.details && netInfo.isConnected) {
734
+ supportsIPv4 = true;
735
+ // IPv6 support based on interface type (following Swift logic)
736
+ if (netInfo.type === 'wifi' || netInfo.type === 'cellular' || netInfo.type === 'ethernet') {
737
+ supportsIPv6 = true;
738
+ }
739
+ else {
740
+ supportsIPv6 = false;
741
+ }
742
+ supportsDNS = netInfo.isInternetReachable === true;
743
+ // Get interface details from NetInfo
744
+ if (netInfo.details && 'isConnectionExpensive' in netInfo.details) {
745
+ // This is a cellular connection
746
+ interfaceDetails.push({
747
+ name: 'cellular',
748
+ index: 0,
749
+ type: 'cellular'
750
+ });
751
+ }
752
+ else if (netInfo.type === 'wifi') {
753
+ interfaceDetails.push({
754
+ name: 'en0',
755
+ index: 0,
756
+ type: 'wifi'
757
+ });
758
+ }
759
+ else if (netInfo.type === 'ethernet') {
760
+ interfaceDetails.push({
761
+ name: 'en0',
762
+ index: 0,
763
+ type: 'wiredEthernet'
764
+ });
765
+ }
766
+ gatewayCount = interfaceDetails.length;
767
+ hasUnsatisfiedGateway = gatewayCount === 0;
768
+ // For React Native, we can't easily get actual gateway IPs
769
+ // but we can indicate if we have network connectivity
770
+ if (netInfo.isConnected) {
771
+ gateways = ['default']; // Placeholder since we can't get actual gateway IPs
772
+ }
773
+ }
774
+ // Fallback if NetInfo doesn't provide enough details
775
+ if (interfaceDetails.length === 0) {
776
+ interfaceDetails = [{
777
+ name: 'en0',
778
+ index: 0,
779
+ type: netInfo.type || 'unknown'
780
+ }];
781
+ gatewayCount = 1;
782
+ hasUnsatisfiedGateway = false;
783
+ gateways = ['default'];
784
+ }
785
+ return {
786
+ supportsIPv4,
787
+ supportsIPv6,
788
+ supportsDNS,
789
+ hasUnsatisfiedGateway,
790
+ gatewayCount,
791
+ gateways,
792
+ interfaceDetails
793
+ };
794
+ }
795
+ catch (error) {
796
+ verboseLog(`Error getting network path info: ${error}`);
797
+ // Fallback to basic defaults if NetInfo fails
798
+ return {
799
+ supportsIPv4: true,
800
+ supportsIPv6: false,
801
+ supportsDNS: true,
802
+ hasUnsatisfiedGateway: false,
803
+ gatewayCount: 1,
804
+ gateways: ['default'],
805
+ interfaceDetails: [{
806
+ name: 'en0',
807
+ index: 0,
808
+ type: 'unknown'
809
+ }]
810
+ };
811
+ }
812
+ });
813
+ // Collects basic system information for deep linking (non-identifying data only)
814
+ const getSystemInfo = () => __awaiter(void 0, void 0, void 0, function* () {
815
+ const systemInfo = {};
816
+ try {
817
+ systemInfo.systemName = yield react_native_device_info_1.default.getSystemName();
818
+ systemInfo.systemVersion = yield react_native_device_info_1.default.getSystemVersion();
819
+ systemInfo.model = yield react_native_device_info_1.default.getModel();
820
+ systemInfo.localizedModel = yield react_native_device_info_1.default.getModel();
821
+ systemInfo.isPhysicalDevice = !(yield react_native_device_info_1.default.isEmulator());
822
+ systemInfo.bundleId = yield react_native_device_info_1.default.getBundleId();
823
+ // Map device type to more readable format
824
+ const deviceType = yield react_native_device_info_1.default.getDeviceType();
825
+ systemInfo.deviceType = deviceType === 'Handset' ? 'mobile' : deviceType;
826
+ }
827
+ catch (error) {
828
+ verboseLog(`Error getting device info: ${error}`);
829
+ // Fallback to basic platform detection
830
+ systemInfo.systemName = 'iOS';
831
+ systemInfo.systemVersion = react_native_1.Platform.Version.toString();
832
+ systemInfo.model = 'iPhone';
833
+ systemInfo.localizedModel = systemInfo.model;
834
+ systemInfo.isPhysicalDevice = true; // Assume physical device if we can't detect
835
+ systemInfo.bundleId = 'null'; // Fallback if we can't get bundle ID
836
+ systemInfo.deviceType = 'unknown';
837
+ }
838
+ if (verboseLogging) {
839
+ console.log('[Insert Affiliate] system info:', systemInfo);
840
+ }
841
+ return systemInfo;
842
+ });
843
+ const getEnhancedSystemInfo = () => __awaiter(void 0, void 0, void 0, function* () {
844
+ verboseLog('Collecting enhanced system information...');
845
+ let systemInfo = yield getSystemInfo();
846
+ verboseLog(`System info: ${JSON.stringify(systemInfo)}`);
847
+ try {
848
+ // Add timestamp
849
+ const now = new Date();
850
+ systemInfo.requestTime = now.toISOString();
851
+ systemInfo.requestTimestamp = Math.floor(now.getTime());
852
+ // Add user agent style information
853
+ const systemName = systemInfo.systemName;
854
+ const systemVersion = systemInfo.systemVersion;
855
+ const model = systemInfo.model;
856
+ systemInfo.userAgent = `${model}; ${systemName} ${systemVersion}`;
857
+ // Add screen dimensions and device pixel ratio (matching exact field names)
858
+ const { width, height } = react_native_1.Dimensions.get('window');
859
+ const pixelRatio = react_native_1.PixelRatio.get();
860
+ systemInfo.screenWidth = Math.floor(width);
861
+ systemInfo.screenHeight = Math.floor(height);
862
+ systemInfo.screenAvailWidth = Math.floor(width);
863
+ systemInfo.screenAvailHeight = Math.floor(height);
864
+ systemInfo.devicePixelRatio = pixelRatio;
865
+ systemInfo.screenColorDepth = 24;
866
+ systemInfo.screenPixelDepth = 24;
867
+ try {
868
+ systemInfo.hardwareConcurrency = (yield react_native_device_info_1.default.getTotalMemory()) / (1024 * 1024 * 1024); // Convert to GB
869
+ }
870
+ catch (error) {
871
+ systemInfo.hardwareConcurrency = 4; // Fallback assumption
872
+ }
873
+ systemInfo.maxTouchPoints = 5; // Default for mobile devices
874
+ // Add screen dimensions (native mobile naming)
875
+ systemInfo.screenInnerWidth = Math.floor(width);
876
+ systemInfo.screenInnerHeight = Math.floor(height);
877
+ systemInfo.screenOuterWidth = Math.floor(width);
878
+ systemInfo.screenOuterHeight = Math.floor(height);
879
+ // Add clipboard UUID if available
880
+ const clipboardUUID = yield getClipboardUUID();
881
+ if (clipboardUUID) {
882
+ systemInfo.clipboardID = clipboardUUID;
883
+ verboseLog(`Found valid clipboard UUID: ${clipboardUUID}`);
884
+ }
885
+ else {
886
+ if (insertLinksClipboardEnabled) {
887
+ verboseLog('Clipboard UUID not available - it may require NSPasteboardGeneralUseDescription in Info.plist');
888
+ }
889
+ else {
890
+ verboseLog('Clipboard access is disabled - it may require NSPasteboardGeneralUseDescription in Info.plist');
891
+ }
892
+ }
893
+ // Add language information using Intl API
894
+ try {
895
+ // Get locale with region information
896
+ const locale = Intl.DateTimeFormat().resolvedOptions().locale;
897
+ const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
898
+ // Try to get more specific locale information
899
+ let bestLocale = locale;
900
+ // If the locale doesn't have region info, try to infer from timezone
901
+ if (!locale.includes('-') && timeZone) {
902
+ try {
903
+ // Create a locale-specific date formatter to get region
904
+ const regionLocale = new Intl.DateTimeFormat(undefined, {
905
+ timeZone: timeZone
906
+ }).resolvedOptions().locale;
907
+ if (regionLocale && regionLocale.includes('-')) {
908
+ bestLocale = regionLocale;
909
+ }
910
+ }
911
+ catch (e) {
912
+ // Fallback to original locale
913
+ }
914
+ }
915
+ // Try navigator.language as fallback for better region detection
916
+ if (!bestLocale.includes('-') && typeof navigator !== 'undefined' && navigator.language) {
917
+ bestLocale = navigator.language;
918
+ }
919
+ const parts = bestLocale.split('-');
920
+ systemInfo.language = parts[0] || 'en';
921
+ systemInfo.country = parts[1] || null; // Set to null instead of defaulting to 'US'
922
+ systemInfo.languages = [bestLocale, parts[0] || 'en'];
923
+ }
924
+ catch (error) {
925
+ verboseLog(`Error getting device locale: ${error}`);
926
+ // Fallback to defaults
927
+ systemInfo.language = 'en';
928
+ systemInfo.country = null; // Set to null instead of defaulting to 'US'
929
+ systemInfo.languages = ['en'];
930
+ }
931
+ // Add timezone info (matching exact field names)
932
+ const timezoneOffset = new Date().getTimezoneOffset();
933
+ systemInfo.timezoneOffset = -timezoneOffset;
934
+ systemInfo.timezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
935
+ // Add browser and platform info (matching exact field names)
936
+ systemInfo.browserVersion = systemInfo.systemVersion;
937
+ systemInfo.platform = systemInfo.systemName;
938
+ systemInfo.os = systemInfo.systemName;
939
+ systemInfo.osVersion = systemInfo.systemVersion;
940
+ // Add network connection info
941
+ verboseLog('Getting network info');
942
+ const networkInfo = yield getNetworkInfo();
943
+ const pathInfo = yield getNetworkPathInfo();
944
+ verboseLog(`Network info: ${JSON.stringify(networkInfo)}`);
945
+ verboseLog(`Network path info: ${JSON.stringify(pathInfo)}`);
946
+ systemInfo.networkInfo = networkInfo;
947
+ systemInfo.networkPath = pathInfo;
948
+ // Update connection info with real data
949
+ const connection = {};
950
+ connection.type = networkInfo.connectionType || 'unknown';
951
+ connection.isExpensive = networkInfo.isExpensive || false;
952
+ connection.isConstrained = networkInfo.isConstrained || false;
953
+ connection.status = networkInfo.status || 'unknown';
954
+ connection.interfaces = networkInfo.availableInterfaces || [];
955
+ connection.supportsIPv4 = pathInfo.supportsIPv4 || true;
956
+ connection.supportsIPv6 = pathInfo.supportsIPv6 || false;
957
+ connection.supportsDNS = pathInfo.supportsDNS || true;
958
+ // Keep legacy fields for compatibility
959
+ connection.downlink = networkInfo.connectionType === 'wifi' ? 100 : 10;
960
+ connection.effectiveType = networkInfo.connectionType === 'wifi' ? '4g' : '3g';
961
+ connection.rtt = networkInfo.connectionType === 'wifi' ? 20 : 100;
962
+ connection.saveData = networkInfo.isConstrained || false;
963
+ systemInfo.connection = connection;
964
+ verboseLog(`Enhanced system info collected: ${JSON.stringify(systemInfo)}`);
965
+ return systemInfo;
966
+ }
967
+ catch (error) {
968
+ verboseLog(`Error collecting enhanced system info: ${error}`);
969
+ return systemInfo;
970
+ }
971
+ });
972
+ // Sends enhanced system info to the backend API for deep link event tracking
973
+ const sendSystemInfoToBackend = (systemInfo) => __awaiter(void 0, void 0, void 0, function* () {
974
+ if (verboseLogging) {
975
+ console.log('[Insert Affiliate] Sending system info to backend...');
976
+ }
977
+ try {
978
+ const apiUrlString = 'https://insertaffiliate.link/V1/appDeepLinkEvents';
979
+ verboseLog(`Sending request to: ${apiUrlString}`);
980
+ const response = yield axios_1.default.post(apiUrlString, systemInfo, {
981
+ headers: {
982
+ 'Content-Type': 'application/json',
983
+ },
984
+ });
985
+ verboseLog(`System info response status: ${response.status}`);
986
+ if (response.data) {
987
+ verboseLog(`System info response: ${JSON.stringify(response.data)}`);
988
+ }
989
+ // Try to parse backend response and persist matched short code if present
990
+ if (response.data && typeof response.data === 'object') {
991
+ const matchFound = response.data.matchFound || false;
992
+ if (matchFound && response.data.matched_affiliate_shortCode && response.data.matched_affiliate_shortCode.length > 0) {
993
+ const matchedShortCode = response.data.matched_affiliate_shortCode;
994
+ verboseLog(`Storing Matched short code from backend: ${matchedShortCode}`);
995
+ yield storeInsertAffiliateIdentifier({ link: matchedShortCode });
996
+ }
997
+ }
998
+ // Check for a successful response
999
+ if (response.status >= 200 && response.status <= 299) {
1000
+ verboseLog('System info sent successfully');
1001
+ }
1002
+ else {
1003
+ verboseLog(`Failed to send system info with status code: ${response.status}`);
1004
+ if (response.data) {
1005
+ verboseLog(`Error response: ${JSON.stringify(response.data)}`);
1006
+ }
1007
+ }
1008
+ }
1009
+ catch (error) {
1010
+ verboseLog(`Error sending system info: ${error}`);
1011
+ verboseLog(`Network error sending system info: ${error}`);
1012
+ }
1013
+ });
218
1014
  // MARK: Short Codes
219
1015
  const isShortCode = (referringLink) => {
220
1016
  // Short codes are 3-25 characters and can include underscores
@@ -268,10 +1064,18 @@ const DeepLinkIapProvider = ({ children, }) => {
268
1064
  ;
269
1065
  });
270
1066
  // MARK: Return Insert Affiliate Identifier
271
- // Instead of just reading React state
272
- const returnInsertAffiliateIdentifier = () => __awaiter(void 0, void 0, void 0, function* () {
1067
+ const returnInsertAffiliateIdentifier = (...args_1) => __awaiter(void 0, [...args_1], void 0, function* (ignoreTimeout = false) {
273
1068
  try {
274
- verboseLog('Getting insert affiliate identifier...');
1069
+ verboseLog(`Getting insert affiliate identifier (ignoreTimeout: ${ignoreTimeout})...`);
1070
+ // If timeout is enabled and we're not ignoring it, check validity first
1071
+ if (!ignoreTimeout && affiliateAttributionActiveTime) {
1072
+ const isValid = yield isAffiliateAttributionValid();
1073
+ if (!isValid) {
1074
+ verboseLog('Attribution has expired, returning null');
1075
+ return null;
1076
+ }
1077
+ }
1078
+ // Now get the actual identifier
275
1079
  verboseLog(`React state - referrerLink: ${referrerLink || 'empty'}, userId: ${userId || 'empty'}`);
276
1080
  // Try React state first
277
1081
  if (referrerLink && userId) {
@@ -282,8 +1086,14 @@ const DeepLinkIapProvider = ({ children, }) => {
282
1086
  verboseLog('React state empty, checking AsyncStorage...');
283
1087
  // Fallback to async storage if React state is empty
284
1088
  const storedLink = yield getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
285
- const storedUserId = yield getValueFromAsync(ASYNC_KEYS.USER_ID);
1089
+ let storedUserId = yield getValueFromAsync(ASYNC_KEYS.USER_ID);
286
1090
  verboseLog(`AsyncStorage - storedLink: ${storedLink || 'empty'}, storedUserId: ${storedUserId || 'empty'}`);
1091
+ // If we have a stored link but no user ID, generate one now
1092
+ if (storedLink && !storedUserId) {
1093
+ verboseLog('Found stored link but no user ID, generating user ID now...');
1094
+ storedUserId = yield generateThenSetUserID();
1095
+ verboseLog(`Generated user ID: ${storedUserId}`);
1096
+ }
287
1097
  if (storedLink && storedUserId) {
288
1098
  const identifier = `${storedLink}-${storedUserId}`;
289
1099
  verboseLog(`Found identifier in AsyncStorage: ${identifier}`);
@@ -297,6 +1107,48 @@ const DeepLinkIapProvider = ({ children, }) => {
297
1107
  return null;
298
1108
  }
299
1109
  });
1110
+ // MARK: Attribution Timeout Functions
1111
+ // Check if the current affiliate attribution is still valid based on timeout
1112
+ const isAffiliateAttributionValid = () => __awaiter(void 0, void 0, void 0, function* () {
1113
+ try {
1114
+ // If no timeout is set, attribution is always valid
1115
+ if (!affiliateAttributionActiveTime) {
1116
+ verboseLog('No attribution timeout set, attribution is valid');
1117
+ return true;
1118
+ }
1119
+ const storedDate = yield getAffiliateStoredDate();
1120
+ if (!storedDate) {
1121
+ verboseLog('No stored date found, attribution is invalid');
1122
+ return false;
1123
+ }
1124
+ const now = new Date();
1125
+ const timeDifferenceSeconds = Math.floor((now.getTime() - storedDate.getTime()) / 1000);
1126
+ const isValid = timeDifferenceSeconds <= affiliateAttributionActiveTime;
1127
+ verboseLog(`Attribution timeout check: stored=${storedDate.toISOString()}, now=${now.toISOString()}, diff=${timeDifferenceSeconds}s, timeout=${affiliateAttributionActiveTime}s, valid=${isValid}`);
1128
+ return isValid;
1129
+ }
1130
+ catch (error) {
1131
+ verboseLog(`Error checking attribution validity: ${error}`);
1132
+ return false;
1133
+ }
1134
+ });
1135
+ // Get the date when the affiliate identifier was stored
1136
+ const getAffiliateStoredDate = () => __awaiter(void 0, void 0, void 0, function* () {
1137
+ try {
1138
+ const storedDateString = yield getValueFromAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE);
1139
+ if (!storedDateString) {
1140
+ verboseLog('No affiliate stored date found');
1141
+ return null;
1142
+ }
1143
+ const storedDate = new Date(storedDateString);
1144
+ verboseLog(`Retrieved affiliate stored date: ${storedDate.toISOString()}`);
1145
+ return storedDate;
1146
+ }
1147
+ catch (error) {
1148
+ verboseLog(`Error getting affiliate stored date: ${error}`);
1149
+ return null;
1150
+ }
1151
+ });
300
1152
  // MARK: Insert Affiliate Identifier
301
1153
  function setInsertAffiliateIdentifier(referringLink) {
302
1154
  return __awaiter(this, void 0, void 0, function* () {
@@ -379,14 +1231,30 @@ const DeepLinkIapProvider = ({ children, }) => {
379
1231
  function storeInsertAffiliateIdentifier(_a) {
380
1232
  return __awaiter(this, arguments, void 0, function* ({ link }) {
381
1233
  console.log(`[Insert Affiliate] Storing affiliate identifier: ${link}`);
1234
+ // Check if we're trying to store the same link (prevent duplicate storage)
1235
+ const existingLink = yield getValueFromAsync(ASYNC_KEYS.REFERRER_LINK);
1236
+ if (existingLink === link) {
1237
+ verboseLog(`Link ${link} is already stored, skipping duplicate storage`);
1238
+ return;
1239
+ }
382
1240
  verboseLog(`Updating React state with referrer link: ${link}`);
383
1241
  setReferrerLink(link);
384
1242
  verboseLog(`Saving referrer link to AsyncStorage...`);
385
1243
  yield saveValueInAsync(ASYNC_KEYS.REFERRER_LINK, link);
1244
+ // Store the current date/time when the affiliate identifier is stored
1245
+ const currentDate = new Date().toISOString();
1246
+ verboseLog(`Saving affiliate stored date: ${currentDate}`);
1247
+ yield saveValueInAsync(ASYNC_KEYS.AFFILIATE_STORED_DATE, currentDate);
386
1248
  verboseLog(`Referrer link saved to AsyncStorage successfully`);
387
1249
  // Automatically fetch and store offer code for any affiliate identifier
388
1250
  verboseLog('Attempting to fetch offer code for stored affiliate identifier...');
389
1251
  yield retrieveAndStoreOfferCode(link);
1252
+ // Trigger callback with the current affiliate identifier
1253
+ if (insertAffiliateIdentifierChangeCallbackRef.current) {
1254
+ const currentIdentifier = yield returnInsertAffiliateIdentifier();
1255
+ verboseLog(`Triggering callback with identifier: ${currentIdentifier}`);
1256
+ insertAffiliateIdentifierChangeCallbackRef.current(currentIdentifier);
1257
+ }
390
1258
  });
391
1259
  }
392
1260
  const validatePurchaseWithIapticAPI = (jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) => __awaiter(void 0, void 0, void 0, function* () {
@@ -625,11 +1493,15 @@ const DeepLinkIapProvider = ({ children, }) => {
625
1493
  OfferCode,
626
1494
  setShortCode,
627
1495
  returnInsertAffiliateIdentifier,
1496
+ isAffiliateAttributionValid,
1497
+ getAffiliateStoredDate,
628
1498
  storeExpectedStoreTransaction,
629
1499
  returnUserAccountTokenAndStoreExpectedTransaction,
630
1500
  validatePurchaseWithIapticAPI,
631
1501
  trackEvent,
632
1502
  setInsertAffiliateIdentifier,
1503
+ setInsertAffiliateIdentifierChangeCallback: setInsertAffiliateIdentifierChangeCallbackHandler,
1504
+ handleInsertLinks,
633
1505
  initialize,
634
1506
  isInitialized,
635
1507
  } }, children));