@datalyr/react-native 1.3.0 → 1.3.1
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.
- package/CHANGELOG.md +19 -0
- package/README.md +145 -9
- package/ios/DatalyrSKAdNetwork.m +351 -3
- package/ios/PrivacyInfo.xcprivacy +48 -0
- package/lib/datalyr-sdk.d.ts +6 -0
- package/lib/datalyr-sdk.js +84 -27
- package/lib/index.d.ts +3 -1
- package/lib/index.js +3 -1
- package/lib/integrations/play-install-referrer.d.ts +5 -1
- package/lib/integrations/play-install-referrer.js +14 -4
- package/lib/native/SKAdNetworkBridge.d.ts +121 -0
- package/lib/native/SKAdNetworkBridge.js +276 -2
- package/lib/network-status.d.ts +84 -0
- package/lib/network-status.js +281 -0
- package/lib/types.d.ts +51 -0
- package/lib/utils.d.ts +6 -1
- package/lib/utils.js +52 -2
- package/package.json +6 -2
- package/src/datalyr-sdk.ts +96 -32
- package/src/index.ts +5 -1
- package/src/integrations/play-install-referrer.ts +19 -4
- package/src/native/SKAdNetworkBridge.ts +400 -5
- package/src/network-status.ts +312 -0
- package/src/types.ts +74 -6
- package/src/utils.ts +62 -6
package/lib/datalyr-sdk.js
CHANGED
|
@@ -8,10 +8,12 @@ import { AutoEventsManager } from './auto-events';
|
|
|
8
8
|
import { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
9
9
|
import { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
10
10
|
import { metaIntegration, tiktokIntegration, appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
|
|
11
|
+
import { networkStatusManager } from './network-status';
|
|
11
12
|
export class DatalyrSDK {
|
|
12
13
|
constructor() {
|
|
13
14
|
this.autoEventsManager = null;
|
|
14
15
|
this.appStateSubscription = null;
|
|
16
|
+
this.networkStatusUnsubscribe = null;
|
|
15
17
|
// Initialize state with defaults
|
|
16
18
|
this.state = {
|
|
17
19
|
initialized: false,
|
|
@@ -73,18 +75,20 @@ export class DatalyrSDK {
|
|
|
73
75
|
flushInterval: this.state.config.flushInterval || 30000,
|
|
74
76
|
maxRetryCount: this.state.config.maxRetries || 3,
|
|
75
77
|
});
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
78
|
+
// PARALLEL INITIALIZATION: IDs and core managers
|
|
79
|
+
// Run ID creation and core manager initialization in parallel for faster startup
|
|
80
|
+
const [visitorId, anonymousId, sessionId] = await Promise.all([
|
|
81
|
+
getOrCreateVisitorId(),
|
|
82
|
+
getOrCreateAnonymousId(),
|
|
83
|
+
getOrCreateSessionId(),
|
|
84
|
+
// These run concurrently but don't return values we need to capture
|
|
85
|
+
this.loadPersistedUserData(),
|
|
86
|
+
this.state.config.enableAttribution ? attributionManager.initialize() : Promise.resolve(),
|
|
87
|
+
journeyManager.initialize(),
|
|
88
|
+
]);
|
|
89
|
+
this.state.visitorId = visitorId;
|
|
90
|
+
this.state.anonymousId = anonymousId;
|
|
91
|
+
this.state.sessionId = sessionId;
|
|
88
92
|
// Record initial attribution to journey if this is a new session with attribution
|
|
89
93
|
const initialAttribution = attributionManager.getAttributionData();
|
|
90
94
|
if (initialAttribution.utm_source || initialAttribution.fbclid || initialAttribution.gclid || initialAttribution.lyr) {
|
|
@@ -122,7 +126,7 @@ export class DatalyrSDK {
|
|
|
122
126
|
errorLog('Error setting up app state monitoring (non-blocking):', error);
|
|
123
127
|
}
|
|
124
128
|
}, 50);
|
|
125
|
-
// Initialize SKAdNetwork conversion encoder
|
|
129
|
+
// Initialize SKAdNetwork conversion encoder (synchronous, no await needed)
|
|
126
130
|
if (config.skadTemplate) {
|
|
127
131
|
const template = ConversionTemplates[config.skadTemplate];
|
|
128
132
|
if (template) {
|
|
@@ -134,25 +138,34 @@ export class DatalyrSDK {
|
|
|
134
138
|
}
|
|
135
139
|
}
|
|
136
140
|
}
|
|
137
|
-
//
|
|
141
|
+
// PARALLEL INITIALIZATION: Network monitoring and platform integrations
|
|
142
|
+
// These are independent and can run concurrently for faster startup
|
|
143
|
+
const platformInitPromises = [
|
|
144
|
+
// Network monitoring
|
|
145
|
+
this.initializeNetworkMonitoring(),
|
|
146
|
+
// Apple Search Ads (iOS only)
|
|
147
|
+
appleSearchAdsIntegration.initialize(config.debug),
|
|
148
|
+
// Google Play Install Referrer (Android only)
|
|
149
|
+
playInstallReferrerIntegration.initialize(),
|
|
150
|
+
];
|
|
151
|
+
// Add Meta initialization if configured
|
|
138
152
|
if ((_b = config.meta) === null || _b === void 0 ? void 0 : _b.appId) {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
153
|
+
platformInitPromises.push(metaIntegration.initialize(config.meta, config.debug).then(async () => {
|
|
154
|
+
// After Meta initializes, fetch deferred deep link
|
|
155
|
+
if (config.enableAttribution !== false) {
|
|
156
|
+
const deferredLink = await metaIntegration.fetchDeferredDeepLink();
|
|
157
|
+
if (deferredLink) {
|
|
158
|
+
await this.handleDeferredDeepLink(deferredLink);
|
|
159
|
+
}
|
|
145
160
|
}
|
|
146
|
-
}
|
|
161
|
+
}));
|
|
147
162
|
}
|
|
148
|
-
//
|
|
163
|
+
// Add TikTok initialization if configured
|
|
149
164
|
if (((_c = config.tiktok) === null || _c === void 0 ? void 0 : _c.appId) && ((_d = config.tiktok) === null || _d === void 0 ? void 0 : _d.tiktokAppId)) {
|
|
150
|
-
|
|
165
|
+
platformInitPromises.push(tiktokIntegration.initialize(config.tiktok, config.debug));
|
|
151
166
|
}
|
|
152
|
-
//
|
|
153
|
-
await
|
|
154
|
-
// Initialize Google Play Install Referrer (Android only)
|
|
155
|
-
await playInstallReferrerIntegration.initialize();
|
|
167
|
+
// Wait for all platform integrations to complete
|
|
168
|
+
await Promise.all(platformInitPromises);
|
|
156
169
|
debugLog('Platform integrations initialized', {
|
|
157
170
|
meta: metaIntegration.isAvailable(),
|
|
158
171
|
tiktok: tiktokIntegration.isAvailable(),
|
|
@@ -900,6 +913,41 @@ export class DatalyrSDK {
|
|
|
900
913
|
errorLog('Error persisting user data:', error);
|
|
901
914
|
}
|
|
902
915
|
}
|
|
916
|
+
/**
|
|
917
|
+
* Initialize network status monitoring
|
|
918
|
+
* Automatically updates event queue when network status changes
|
|
919
|
+
*/
|
|
920
|
+
async initializeNetworkMonitoring() {
|
|
921
|
+
try {
|
|
922
|
+
await networkStatusManager.initialize();
|
|
923
|
+
// Update event queue with current network status
|
|
924
|
+
this.state.isOnline = networkStatusManager.isOnline();
|
|
925
|
+
this.eventQueue.setOnlineStatus(this.state.isOnline);
|
|
926
|
+
// Subscribe to network changes
|
|
927
|
+
this.networkStatusUnsubscribe = networkStatusManager.subscribe((state) => {
|
|
928
|
+
const isOnline = state.isConnected && (state.isInternetReachable !== false);
|
|
929
|
+
this.state.isOnline = isOnline;
|
|
930
|
+
this.eventQueue.setOnlineStatus(isOnline);
|
|
931
|
+
// Track network status change event (only if SDK is fully initialized)
|
|
932
|
+
if (this.state.initialized) {
|
|
933
|
+
this.track('$network_status_change', {
|
|
934
|
+
is_online: isOnline,
|
|
935
|
+
network_type: state.type,
|
|
936
|
+
is_internet_reachable: state.isInternetReachable,
|
|
937
|
+
}).catch(() => {
|
|
938
|
+
// Ignore errors for network status events
|
|
939
|
+
});
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
debugLog(`Network monitoring initialized, online: ${this.state.isOnline}`);
|
|
943
|
+
}
|
|
944
|
+
catch (error) {
|
|
945
|
+
errorLog('Error initializing network monitoring (non-blocking):', error);
|
|
946
|
+
// Default to online if monitoring fails
|
|
947
|
+
this.state.isOnline = true;
|
|
948
|
+
this.eventQueue.setOnlineStatus(true);
|
|
949
|
+
}
|
|
950
|
+
}
|
|
903
951
|
/**
|
|
904
952
|
* Set up app state monitoring for lifecycle events (optimized)
|
|
905
953
|
*/
|
|
@@ -920,6 +968,8 @@ export class DatalyrSDK {
|
|
|
920
968
|
else if (nextAppState === 'active') {
|
|
921
969
|
// App became active, ensure we have fresh session if needed
|
|
922
970
|
this.refreshSession();
|
|
971
|
+
// Refresh network status when coming back from background
|
|
972
|
+
networkStatusManager.refresh();
|
|
923
973
|
// Notify auto-events manager for session handling
|
|
924
974
|
if (this.autoEventsManager) {
|
|
925
975
|
this.autoEventsManager.handleAppForeground();
|
|
@@ -957,6 +1007,13 @@ export class DatalyrSDK {
|
|
|
957
1007
|
this.appStateSubscription.remove();
|
|
958
1008
|
this.appStateSubscription = null;
|
|
959
1009
|
}
|
|
1010
|
+
// Remove network status listener
|
|
1011
|
+
if (this.networkStatusUnsubscribe) {
|
|
1012
|
+
this.networkStatusUnsubscribe();
|
|
1013
|
+
this.networkStatusUnsubscribe = null;
|
|
1014
|
+
}
|
|
1015
|
+
// Destroy network status manager
|
|
1016
|
+
networkStatusManager.destroy();
|
|
960
1017
|
// Destroy event queue
|
|
961
1018
|
this.eventQueue.destroy();
|
|
962
1019
|
// Reset state
|
package/lib/index.d.ts
CHANGED
|
@@ -12,6 +12,8 @@ export * from './event-queue';
|
|
|
12
12
|
export { DatalyrSDK };
|
|
13
13
|
export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
14
14
|
export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
15
|
-
export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
|
|
15
|
+
export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
|
|
16
|
+
export { networkStatusManager } from './network-status';
|
|
17
|
+
export type { NetworkState, NetworkStateListener } from './network-status';
|
|
16
18
|
export type { AppleSearchAdsAttribution } from './native/DatalyrNativeBridge';
|
|
17
19
|
export default DatalyrSDK;
|
package/lib/index.js
CHANGED
|
@@ -20,6 +20,8 @@ export { DatalyrSDK };
|
|
|
20
20
|
export { ConversionValueEncoder, ConversionTemplates } from './ConversionValueEncoder';
|
|
21
21
|
export { SKAdNetworkBridge } from './native/SKAdNetworkBridge';
|
|
22
22
|
// Export platform integrations
|
|
23
|
-
export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration } from './integrations';
|
|
23
|
+
export { metaIntegration, tiktokIntegration, appleSearchAdsIntegration, playInstallReferrerIntegration } from './integrations';
|
|
24
|
+
// Export network status manager
|
|
25
|
+
export { networkStatusManager } from './network-status';
|
|
24
26
|
// Default export for compatibility
|
|
25
27
|
export default DatalyrSDK;
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
* - referrer_url: Full referrer URL from Play Store
|
|
20
20
|
* - referrer_click_timestamp: When the referrer link was clicked
|
|
21
21
|
* - install_begin_timestamp: When the install began
|
|
22
|
-
* - gclid: Google Ads click ID (
|
|
22
|
+
* - gclid: Google Ads click ID (standard)
|
|
23
|
+
* - gbraid: Google Ads privacy-safe click ID (iOS App campaigns)
|
|
24
|
+
* - wbraid: Google Ads privacy-safe click ID (Web-to-App campaigns)
|
|
23
25
|
* - utm_source, utm_medium, utm_campaign, etc.
|
|
24
26
|
*/
|
|
25
27
|
export interface PlayInstallReferrer {
|
|
@@ -28,6 +30,8 @@ export interface PlayInstallReferrer {
|
|
|
28
30
|
installBeginTimestamp: number;
|
|
29
31
|
installCompleteTimestamp?: number;
|
|
30
32
|
gclid?: string;
|
|
33
|
+
gbraid?: string;
|
|
34
|
+
wbraid?: string;
|
|
31
35
|
utmSource?: string;
|
|
32
36
|
utmMedium?: string;
|
|
33
37
|
utmCampaign?: string;
|
|
@@ -19,7 +19,9 @@
|
|
|
19
19
|
* - referrer_url: Full referrer URL from Play Store
|
|
20
20
|
* - referrer_click_timestamp: When the referrer link was clicked
|
|
21
21
|
* - install_begin_timestamp: When the install began
|
|
22
|
-
* - gclid: Google Ads click ID (
|
|
22
|
+
* - gclid: Google Ads click ID (standard)
|
|
23
|
+
* - gbraid: Google Ads privacy-safe click ID (iOS App campaigns)
|
|
24
|
+
* - wbraid: Google Ads privacy-safe click ID (Web-to-App campaigns)
|
|
23
25
|
* - utm_source, utm_medium, utm_campaign, etc.
|
|
24
26
|
*/
|
|
25
27
|
import { Platform, NativeModules } from 'react-native';
|
|
@@ -61,6 +63,8 @@ class PlayInstallReferrerIntegration {
|
|
|
61
63
|
utmSource: this.referrerData.utmSource,
|
|
62
64
|
utmMedium: this.referrerData.utmMedium,
|
|
63
65
|
hasGclid: !!this.referrerData.gclid,
|
|
66
|
+
hasGbraid: !!this.referrerData.gbraid,
|
|
67
|
+
hasWbraid: !!this.referrerData.wbraid,
|
|
64
68
|
});
|
|
65
69
|
}
|
|
66
70
|
}
|
|
@@ -109,11 +113,14 @@ class PlayInstallReferrerIntegration {
|
|
|
109
113
|
params.utmCampaign = searchParams.get('utm_campaign') || undefined;
|
|
110
114
|
params.utmTerm = searchParams.get('utm_term') || undefined;
|
|
111
115
|
params.utmContent = searchParams.get('utm_content') || undefined;
|
|
112
|
-
// Extract click IDs
|
|
116
|
+
// Extract click IDs (gclid, gbraid, wbraid)
|
|
113
117
|
params.gclid = searchParams.get('gclid') || undefined;
|
|
118
|
+
params.gbraid = searchParams.get('gbraid') || undefined;
|
|
119
|
+
params.wbraid = searchParams.get('wbraid') || undefined;
|
|
114
120
|
// Store any additional parameters
|
|
121
|
+
const knownParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'gclid', 'gbraid', 'wbraid'];
|
|
115
122
|
searchParams.forEach((value, key) => {
|
|
116
|
-
if (!
|
|
123
|
+
if (!knownParams.includes(key) && !key.startsWith('utm_')) {
|
|
117
124
|
params[key] = value;
|
|
118
125
|
}
|
|
119
126
|
});
|
|
@@ -141,8 +148,11 @@ class PlayInstallReferrerIntegration {
|
|
|
141
148
|
install_referrer_url: this.referrerData.referrerUrl,
|
|
142
149
|
referrer_click_timestamp: this.referrerData.referrerClickTimestamp,
|
|
143
150
|
install_begin_timestamp: this.referrerData.installBeginTimestamp,
|
|
144
|
-
//
|
|
151
|
+
// Google Ads click IDs (gclid is standard, gbraid/wbraid are privacy-safe alternatives)
|
|
145
152
|
gclid: this.referrerData.gclid,
|
|
153
|
+
gbraid: this.referrerData.gbraid,
|
|
154
|
+
wbraid: this.referrerData.wbraid,
|
|
155
|
+
// UTM parameters
|
|
146
156
|
utm_source: this.referrerData.utmSource,
|
|
147
157
|
utm_medium: this.referrerData.utmMedium,
|
|
148
158
|
utm_campaign: this.referrerData.utmCampaign,
|
|
@@ -5,6 +5,46 @@ export interface SKANConversionResult {
|
|
|
5
5
|
lockWindow: boolean;
|
|
6
6
|
priority: number;
|
|
7
7
|
}
|
|
8
|
+
export interface PostbackUpdateResponse {
|
|
9
|
+
success: boolean;
|
|
10
|
+
framework: 'AdAttributionKit' | 'SKAdNetwork';
|
|
11
|
+
fineValue: number;
|
|
12
|
+
coarseValue: string;
|
|
13
|
+
lockWindow: boolean;
|
|
14
|
+
type?: 'reengagement';
|
|
15
|
+
}
|
|
16
|
+
export interface AttributionFrameworkInfo {
|
|
17
|
+
framework: 'AdAttributionKit' | 'SKAdNetwork' | 'none';
|
|
18
|
+
version: string;
|
|
19
|
+
reengagement_available: boolean;
|
|
20
|
+
overlapping_windows: boolean;
|
|
21
|
+
fine_value_range: {
|
|
22
|
+
min: number;
|
|
23
|
+
max: number;
|
|
24
|
+
};
|
|
25
|
+
coarse_values: string[];
|
|
26
|
+
}
|
|
27
|
+
export interface EnhancedAttributionInfo extends AttributionFrameworkInfo {
|
|
28
|
+
geo_postback_available: boolean;
|
|
29
|
+
development_postbacks: boolean;
|
|
30
|
+
features: string[];
|
|
31
|
+
}
|
|
32
|
+
export interface PostbackEnvironmentResponse {
|
|
33
|
+
environment: 'production' | 'sandbox';
|
|
34
|
+
isSandbox: boolean;
|
|
35
|
+
note: string;
|
|
36
|
+
}
|
|
37
|
+
export interface OverlappingWindowPostbackResponse {
|
|
38
|
+
success: boolean;
|
|
39
|
+
framework: string;
|
|
40
|
+
version: string;
|
|
41
|
+
fineValue: number;
|
|
42
|
+
coarseValue: string;
|
|
43
|
+
lockWindow: boolean;
|
|
44
|
+
windowIndex: number;
|
|
45
|
+
overlappingWindows: boolean;
|
|
46
|
+
note?: string;
|
|
47
|
+
}
|
|
8
48
|
export declare class SKAdNetworkBridge {
|
|
9
49
|
private static _isSKAN4Available;
|
|
10
50
|
/**
|
|
@@ -22,4 +62,85 @@ export declare class SKAdNetworkBridge {
|
|
|
22
62
|
*/
|
|
23
63
|
static isSKAN4Available(): Promise<boolean>;
|
|
24
64
|
static isAvailable(): boolean;
|
|
65
|
+
/**
|
|
66
|
+
* Check if AdAttributionKit is available (iOS 17.4+)
|
|
67
|
+
* AdAttributionKit is Apple's replacement for SKAdNetwork with enhanced features
|
|
68
|
+
*/
|
|
69
|
+
private static _isAdAttributionKitAvailable;
|
|
70
|
+
static isAdAttributionKitAvailable(): Promise<boolean>;
|
|
71
|
+
/**
|
|
72
|
+
* Register for ad network attribution
|
|
73
|
+
* Uses AdAttributionKit on iOS 17.4+, SKAdNetwork on earlier versions
|
|
74
|
+
*/
|
|
75
|
+
static registerForAttribution(): Promise<{
|
|
76
|
+
framework: string;
|
|
77
|
+
registered: boolean;
|
|
78
|
+
} | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Get attribution framework info
|
|
81
|
+
* Returns details about which framework is being used and its capabilities
|
|
82
|
+
*/
|
|
83
|
+
static getAttributionInfo(): Promise<AttributionFrameworkInfo | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Check if overlapping conversion windows are available (iOS 18.4+)
|
|
86
|
+
* Overlapping windows allow multiple conversion windows to be active simultaneously
|
|
87
|
+
*/
|
|
88
|
+
private static _isOverlappingWindowsAvailable;
|
|
89
|
+
static isOverlappingWindowsAvailable(): Promise<boolean>;
|
|
90
|
+
/**
|
|
91
|
+
* Update conversion value for re-engagement attribution (AdAttributionKit iOS 17.4+ only)
|
|
92
|
+
* Re-engagement tracks users who return to the app via an ad after initial install.
|
|
93
|
+
*
|
|
94
|
+
* @param result - Conversion result with fine value (0-63), coarse value, and lock window
|
|
95
|
+
* @returns Response with framework info, or null if not supported
|
|
96
|
+
*/
|
|
97
|
+
static updateReengagementConversionValue(result: SKANConversionResult): Promise<PostbackUpdateResponse | null>;
|
|
98
|
+
/**
|
|
99
|
+
* Get a summary of attribution capabilities for the current device
|
|
100
|
+
*/
|
|
101
|
+
static getCapabilitiesSummary(): Promise<{
|
|
102
|
+
skadnetwork3: boolean;
|
|
103
|
+
skadnetwork4: boolean;
|
|
104
|
+
adAttributionKit: boolean;
|
|
105
|
+
reengagement: boolean;
|
|
106
|
+
overlappingWindows: boolean;
|
|
107
|
+
geoPostback: boolean;
|
|
108
|
+
developmentPostbacks: boolean;
|
|
109
|
+
framework: string;
|
|
110
|
+
}>;
|
|
111
|
+
/**
|
|
112
|
+
* Check if geo-level postback data is available (iOS 18.4+)
|
|
113
|
+
* Geo postbacks include country code information for regional analytics
|
|
114
|
+
*/
|
|
115
|
+
private static _isGeoPostbackAvailable;
|
|
116
|
+
static isGeoPostbackAvailable(): Promise<boolean>;
|
|
117
|
+
/**
|
|
118
|
+
* Set postback environment for testing (iOS 18.4+)
|
|
119
|
+
* Note: Actual sandbox mode requires Developer Mode enabled in iOS Settings
|
|
120
|
+
*
|
|
121
|
+
* @param environment - 'production' or 'sandbox'
|
|
122
|
+
*/
|
|
123
|
+
static setPostbackEnvironment(environment: 'production' | 'sandbox'): Promise<PostbackEnvironmentResponse | null>;
|
|
124
|
+
/**
|
|
125
|
+
* Get enhanced attribution info including iOS 18.4+ features
|
|
126
|
+
* Returns details about geo postbacks, development mode, and all available features
|
|
127
|
+
*/
|
|
128
|
+
static getEnhancedAttributionInfo(): Promise<EnhancedAttributionInfo | null>;
|
|
129
|
+
/**
|
|
130
|
+
* Update postback with overlapping window support (iOS 18.4+)
|
|
131
|
+
* Allows tracking conversions across multiple time windows simultaneously
|
|
132
|
+
*
|
|
133
|
+
* @param result - Conversion result with fine value, coarse value, and lock window
|
|
134
|
+
* @param windowIndex - Window index: 0 (0-2 days), 1 (3-7 days), 2 (8-35 days)
|
|
135
|
+
*/
|
|
136
|
+
static updatePostbackWithWindow(result: SKANConversionResult, windowIndex: 0 | 1 | 2): Promise<OverlappingWindowPostbackResponse | null>;
|
|
137
|
+
/**
|
|
138
|
+
* Enable development/sandbox mode for testing attribution
|
|
139
|
+
* Convenience method that sets sandbox environment
|
|
140
|
+
*/
|
|
141
|
+
static enableDevelopmentMode(): Promise<boolean>;
|
|
142
|
+
/**
|
|
143
|
+
* Disable development mode (switch to production)
|
|
144
|
+
*/
|
|
145
|
+
static disableDevelopmentMode(): Promise<boolean>;
|
|
25
146
|
}
|