insert-affiliate-js-sdk 1.0.2 → 1.2.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.
- package/.claude/settings.local.json +10 -0
- package/CHANGELOG.md +60 -0
- package/README.md +414 -124
- package/dist/index.d.ts +53 -4
- package/dist/index.js +416 -37
- package/docs/deep-linking-web.md +199 -0
- package/docs/stripe-integration.md +237 -0
- package/package.json +1 -1
- package/src/sdk/InsertAffiliate.ts +543 -37
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,62 @@
|
|
|
1
1
|
interface IapticIOSReceipt {
|
|
2
2
|
transactionReceipt: string;
|
|
3
3
|
}
|
|
4
|
+
interface AffiliateDetails {
|
|
5
|
+
affiliateName: string;
|
|
6
|
+
affiliateShortCode: string;
|
|
7
|
+
deeplinkUrl: string;
|
|
8
|
+
}
|
|
9
|
+
type InsertAffiliateIdentifierChangeCallback = (identifier: string | null) => void;
|
|
4
10
|
declare class InsertAffiliate {
|
|
5
11
|
private static isInitialized;
|
|
6
12
|
private static companyCode;
|
|
7
|
-
static
|
|
8
|
-
static
|
|
13
|
+
private static verboseLogging;
|
|
14
|
+
private static insertAffiliateIdentifierChangeCallback;
|
|
15
|
+
private static affiliateAttributionActiveTime;
|
|
16
|
+
private static offerCode;
|
|
17
|
+
private static verboseLog;
|
|
18
|
+
static initialize(code: string | null, verboseLogging?: boolean, affiliateAttributionActiveTime?: number): Promise<void>;
|
|
19
|
+
private static checkForInsertAffiliateParam;
|
|
20
|
+
static returnInsertAffiliateIdentifier(ignoreTimeout?: boolean): Promise<string | null>;
|
|
9
21
|
static setInsertAffiliateIdentifier(referringLink: string): Promise<string | null>;
|
|
10
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Validates and sets a short code for affiliate tracking
|
|
24
|
+
* Validates the short code against the API before storing
|
|
25
|
+
* @param shortCode The short code to validate and set
|
|
26
|
+
* @returns true if the code exists and was successfully validated and stored, false otherwise
|
|
27
|
+
*/
|
|
28
|
+
static setShortCode(shortCode: string): Promise<boolean>;
|
|
29
|
+
static setInsertAffiliateIdentifierChangeCallback(callback: InsertAffiliateIdentifierChangeCallback | null): void;
|
|
30
|
+
static isAffiliateAttributionValid(): Promise<boolean>;
|
|
31
|
+
static getAffiliateStoredDate(): Promise<string | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Retrieve detailed information about an affiliate by their short code or deep link
|
|
34
|
+
* This method queries the API and does not store or set the affiliate identifier
|
|
35
|
+
* @param affiliateCode The short code or deep link to look up
|
|
36
|
+
* @returns AffiliateDetails if found, null otherwise
|
|
37
|
+
*/
|
|
38
|
+
static getAffiliateDetails(affiliateCode: string): Promise<AffiliateDetails | null>;
|
|
39
|
+
static returnCompanyId(): Promise<string | null>;
|
|
40
|
+
/**
|
|
41
|
+
* Get the offer code for the current affiliate
|
|
42
|
+
* @param platformType Optional platform type: 'stripe' (default for web), 'ios', or 'android'
|
|
43
|
+
* @returns The offer code for the specified platform, or null if not found
|
|
44
|
+
*/
|
|
45
|
+
static getOfferCode(platformType?: 'ios' | 'android' | 'stripe'): Promise<string | null>;
|
|
46
|
+
/**
|
|
47
|
+
* Get the Stripe coupon/promo code for the current affiliate
|
|
48
|
+
* Convenience method that calls getOfferCode with platformType='stripe'
|
|
49
|
+
* @returns The Stripe coupon/promo code, or null if not found
|
|
50
|
+
*/
|
|
51
|
+
static getStripeCouponCode(): Promise<string | null>;
|
|
52
|
+
/**
|
|
53
|
+
* Fetch offer code for a specific platform
|
|
54
|
+
* @param shortCode The affiliate short code
|
|
55
|
+
* @param platformType The platform type: 'ios', 'android', or 'stripe'
|
|
56
|
+
* @returns The offer code for the specified platform, or null if not found
|
|
57
|
+
*/
|
|
58
|
+
private static fetchOfferCodeForPlatform;
|
|
59
|
+
private static fetchAndStoreOfferCode;
|
|
11
60
|
static trackEvent(eventName: string): Promise<void>;
|
|
12
61
|
static returnUserAccountTokenAndStoreExpectedTransaction(): Promise<string | null>;
|
|
13
62
|
static storeExpectedStoreTransaction(userAccountToken: string): Promise<void>;
|
|
@@ -19,4 +68,4 @@ declare class InsertAffiliate {
|
|
|
19
68
|
private static fetchShortLink;
|
|
20
69
|
}
|
|
21
70
|
|
|
22
|
-
export { InsertAffiliate };
|
|
71
|
+
export { type AffiliateDetails, InsertAffiliate, type InsertAffiliateIdentifierChangeCallback };
|
package/dist/index.js
CHANGED
|
@@ -75,78 +75,408 @@ if (!String.prototype.hasOwnProperty("hashCode")) {
|
|
|
75
75
|
|
|
76
76
|
// src/sdk/InsertAffiliate.ts
|
|
77
77
|
var InsertAffiliate = class {
|
|
78
|
-
static
|
|
78
|
+
static verboseLog(message) {
|
|
79
|
+
if (this.verboseLogging) {
|
|
80
|
+
console.log(`[Insert Affiliate] [VERBOSE] ${message}`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
static async initialize(code, verboseLogging = false, affiliateAttributionActiveTime) {
|
|
84
|
+
this.verboseLogging = verboseLogging;
|
|
85
|
+
if (verboseLogging) {
|
|
86
|
+
this.verboseLog("Starting SDK initialization...");
|
|
87
|
+
this.verboseLog(`Company code provided: ${code ? "Yes" : "No"}`);
|
|
88
|
+
this.verboseLog("Verbose logging enabled");
|
|
89
|
+
}
|
|
79
90
|
if (this.isInitialized) {
|
|
80
|
-
|
|
91
|
+
this.verboseLog("SDK already initialized, skipping");
|
|
81
92
|
return;
|
|
82
93
|
}
|
|
83
94
|
this.companyCode = code;
|
|
84
95
|
await saveValue("companyCode", code || "");
|
|
96
|
+
if (affiliateAttributionActiveTime !== void 0) {
|
|
97
|
+
this.affiliateAttributionActiveTime = affiliateAttributionActiveTime;
|
|
98
|
+
await saveValue("affiliateAttributionActiveTime", affiliateAttributionActiveTime.toString());
|
|
99
|
+
this.verboseLog(`Attribution timeout set to: ${affiliateAttributionActiveTime}ms`);
|
|
100
|
+
}
|
|
85
101
|
this.isInitialized = true;
|
|
86
|
-
|
|
102
|
+
this.verboseLog(`SDK initialized ${code ? `with company code: ${code}` : "without a company code."}`);
|
|
103
|
+
this.verboseLog("Company code saved to storage");
|
|
104
|
+
this.verboseLog("SDK marked as initialized");
|
|
105
|
+
await this.checkForInsertAffiliateParam();
|
|
106
|
+
}
|
|
107
|
+
static async checkForInsertAffiliateParam() {
|
|
108
|
+
this.verboseLog("Checking for insertAffiliate URL parameter...");
|
|
109
|
+
try {
|
|
110
|
+
if (typeof window === "undefined" || !window.location) {
|
|
111
|
+
this.verboseLog("Not in browser environment, skipping URL parameter check");
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
this.verboseLog(`Current URL: ${window.location.href}`);
|
|
115
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
116
|
+
const insertAffiliateParam = urlParams.get("insertAffiliate");
|
|
117
|
+
if (insertAffiliateParam) {
|
|
118
|
+
this.verboseLog(`Found insertAffiliate URL parameter: ${insertAffiliateParam}`);
|
|
119
|
+
await this.setShortCode(insertAffiliateParam);
|
|
120
|
+
this.verboseLog("Successfully processed insertAffiliate URL parameter");
|
|
121
|
+
} else {
|
|
122
|
+
this.verboseLog("No insertAffiliate URL parameter found");
|
|
123
|
+
}
|
|
124
|
+
} catch (error) {
|
|
125
|
+
this.verboseLog(`Error checking for insertAffiliate URL parameter: ${error}`);
|
|
126
|
+
}
|
|
87
127
|
}
|
|
88
|
-
static async returnInsertAffiliateIdentifier() {
|
|
128
|
+
static async returnInsertAffiliateIdentifier(ignoreTimeout = false) {
|
|
129
|
+
this.verboseLog("Getting insert affiliate identifier...");
|
|
89
130
|
const userId = await this.getOrCreateUserID();
|
|
90
131
|
const referrerLink = await getValue("referrerLink");
|
|
91
|
-
|
|
92
|
-
|
|
132
|
+
this.verboseLog(`User ID: ${userId || "empty"}, Referrer link: ${referrerLink || "empty"}`);
|
|
133
|
+
if (!referrerLink) {
|
|
134
|
+
this.verboseLog("No referrer link found, returning null");
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
if (!ignoreTimeout) {
|
|
138
|
+
const isValid = await this.isAffiliateAttributionValid();
|
|
139
|
+
if (!isValid) {
|
|
140
|
+
this.verboseLog("Attribution has expired, returning null");
|
|
141
|
+
return null;
|
|
142
|
+
}
|
|
143
|
+
} else {
|
|
144
|
+
this.verboseLog("Ignoring attribution timeout");
|
|
145
|
+
}
|
|
146
|
+
const identifier = `${referrerLink}-${userId}`;
|
|
147
|
+
this.verboseLog(`Returning affiliate identifier: ${identifier}`);
|
|
148
|
+
return identifier;
|
|
93
149
|
}
|
|
94
150
|
static async setInsertAffiliateIdentifier(referringLink) {
|
|
151
|
+
this.verboseLog(`Setting affiliate identifier. Input referringLink: ${referringLink}`);
|
|
95
152
|
const userId = await this.getOrCreateUserID();
|
|
96
|
-
|
|
97
|
-
|
|
153
|
+
this.verboseLog(`User ID: ${userId}`);
|
|
154
|
+
const isShortCode = /^[a-zA-Z0-9]{3,25}$/.test(referringLink);
|
|
155
|
+
this.verboseLog(`Is short code: ${isShortCode}`);
|
|
156
|
+
const shortCode = isShortCode ? referringLink : await this.fetchShortLink(referringLink);
|
|
157
|
+
if (!shortCode) {
|
|
158
|
+
this.verboseLog("No short code found or generated, returning null");
|
|
159
|
+
return null;
|
|
160
|
+
}
|
|
161
|
+
const existingShortCode = await getValue("referrerLink");
|
|
162
|
+
if (existingShortCode === shortCode) {
|
|
163
|
+
this.verboseLog(`Short code ${shortCode} is already set, not updating attribution date`);
|
|
164
|
+
const identifier2 = `${shortCode}-${userId}`;
|
|
165
|
+
this.verboseLog(`Returning existing identifier: ${identifier2}`);
|
|
166
|
+
return identifier2;
|
|
167
|
+
}
|
|
168
|
+
this.verboseLog(`Saving short code to storage: ${shortCode}`);
|
|
98
169
|
await saveValue("referrerLink", shortCode);
|
|
99
|
-
|
|
170
|
+
const storedDate = (/* @__PURE__ */ new Date()).toISOString();
|
|
171
|
+
await saveValue("affiliateStoredDate", storedDate);
|
|
172
|
+
this.verboseLog(`Short code saved successfully with stored date: ${storedDate}`);
|
|
173
|
+
const identifier = `${shortCode}-${userId}`;
|
|
174
|
+
this.verboseLog(`Returning identifier: ${identifier}`);
|
|
175
|
+
await this.fetchAndStoreOfferCode(shortCode);
|
|
176
|
+
if (this.insertAffiliateIdentifierChangeCallback) {
|
|
177
|
+
this.verboseLog(`Triggering callback with identifier: ${identifier}`);
|
|
178
|
+
this.insertAffiliateIdentifierChangeCallback(identifier);
|
|
179
|
+
}
|
|
180
|
+
return identifier;
|
|
100
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Validates and sets a short code for affiliate tracking
|
|
184
|
+
* Validates the short code against the API before storing
|
|
185
|
+
* @param shortCode The short code to validate and set
|
|
186
|
+
* @returns true if the code exists and was successfully validated and stored, false otherwise
|
|
187
|
+
*/
|
|
101
188
|
static async setShortCode(shortCode) {
|
|
189
|
+
this.verboseLog(`Setting short code. Input: ${shortCode}`);
|
|
102
190
|
const valid = /^[a-zA-Z0-9]{3,25}$/.test(shortCode);
|
|
191
|
+
this.verboseLog(`Short code validation: ${valid ? "Valid" : "Invalid"}`);
|
|
103
192
|
if (!valid) {
|
|
104
|
-
|
|
105
|
-
return;
|
|
193
|
+
this.verboseLog("Invalid short code format, aborting");
|
|
194
|
+
return false;
|
|
195
|
+
}
|
|
196
|
+
const affiliateDetails = await this.getAffiliateDetails(shortCode);
|
|
197
|
+
if (!affiliateDetails) {
|
|
198
|
+
this.verboseLog(`Short code '${shortCode}' does not exist or validation failed`);
|
|
199
|
+
console.error(`[Insert Affiliate] Error: Short code '${shortCode}' does not exist or validation failed.`);
|
|
200
|
+
return false;
|
|
106
201
|
}
|
|
202
|
+
this.verboseLog(`Short code validated successfully for affiliate: ${affiliateDetails.affiliateName}`);
|
|
203
|
+
console.log(`[Insert Affiliate] Short code validated successfully for affiliate: ${affiliateDetails.affiliateName}`);
|
|
204
|
+
this.verboseLog("Calling setInsertAffiliateIdentifier with short code");
|
|
107
205
|
await this.setInsertAffiliateIdentifier(shortCode);
|
|
206
|
+
return true;
|
|
207
|
+
}
|
|
208
|
+
static setInsertAffiliateIdentifierChangeCallback(callback) {
|
|
209
|
+
this.verboseLog(`Setting affiliate identifier change callback: ${callback ? "callback provided" : "callback cleared"}`);
|
|
210
|
+
this.insertAffiliateIdentifierChangeCallback = callback;
|
|
211
|
+
}
|
|
212
|
+
static async isAffiliateAttributionValid() {
|
|
213
|
+
this.verboseLog("Checking if affiliate attribution is valid...");
|
|
214
|
+
const storedDateStr = await getValue("affiliateStoredDate");
|
|
215
|
+
if (!storedDateStr) {
|
|
216
|
+
this.verboseLog("No stored date found, attribution invalid");
|
|
217
|
+
return false;
|
|
218
|
+
}
|
|
219
|
+
let timeoutMs = this.affiliateAttributionActiveTime;
|
|
220
|
+
if (timeoutMs === null) {
|
|
221
|
+
const storedTimeout = await getValue("affiliateAttributionActiveTime");
|
|
222
|
+
timeoutMs = storedTimeout ? parseInt(storedTimeout, 10) : null;
|
|
223
|
+
}
|
|
224
|
+
if (timeoutMs === null) {
|
|
225
|
+
this.verboseLog("No attribution timeout configured, attribution is valid");
|
|
226
|
+
return true;
|
|
227
|
+
}
|
|
228
|
+
const storedDate = new Date(storedDateStr);
|
|
229
|
+
const currentDate = /* @__PURE__ */ new Date();
|
|
230
|
+
const elapsedMs = currentDate.getTime() - storedDate.getTime();
|
|
231
|
+
const isValid = elapsedMs <= timeoutMs;
|
|
232
|
+
this.verboseLog(`Attribution stored: ${storedDateStr}, elapsed: ${elapsedMs}ms, timeout: ${timeoutMs}ms, valid: ${isValid}`);
|
|
233
|
+
return isValid;
|
|
234
|
+
}
|
|
235
|
+
static async getAffiliateStoredDate() {
|
|
236
|
+
this.verboseLog("Getting affiliate stored date...");
|
|
237
|
+
const storedDate = await getValue("affiliateStoredDate");
|
|
238
|
+
this.verboseLog(`Stored date: ${storedDate || "none"}`);
|
|
239
|
+
return storedDate;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* Retrieve detailed information about an affiliate by their short code or deep link
|
|
243
|
+
* This method queries the API and does not store or set the affiliate identifier
|
|
244
|
+
* @param affiliateCode The short code or deep link to look up
|
|
245
|
+
* @returns AffiliateDetails if found, null otherwise
|
|
246
|
+
*/
|
|
247
|
+
static async getAffiliateDetails(affiliateCode) {
|
|
248
|
+
this.verboseLog(`Getting affiliate details for: ${affiliateCode}`);
|
|
249
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
250
|
+
if (!companyCode) {
|
|
251
|
+
this.verboseLog("Cannot get affiliate details: no company code available");
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
const cleanCode = affiliateCode.includes("-") ? affiliateCode.split("-")[0] : affiliateCode;
|
|
255
|
+
this.verboseLog(`Clean code: ${cleanCode}`);
|
|
256
|
+
try {
|
|
257
|
+
const url = "https://api.insertaffiliate.com/V1/checkAffiliateExists";
|
|
258
|
+
const payload = {
|
|
259
|
+
companyId: companyCode,
|
|
260
|
+
affiliateCode: cleanCode
|
|
261
|
+
};
|
|
262
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
263
|
+
this.verboseLog(`Payload: ${JSON.stringify(payload)}`);
|
|
264
|
+
const response = await fetch(url, {
|
|
265
|
+
method: "POST",
|
|
266
|
+
headers: { "Content-Type": "application/json" },
|
|
267
|
+
body: JSON.stringify(payload)
|
|
268
|
+
});
|
|
269
|
+
this.verboseLog(`API response status: ${response.status}`);
|
|
270
|
+
if (!response.ok) {
|
|
271
|
+
this.verboseLog(`Failed to get affiliate details, status: ${response.status}`);
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
274
|
+
const data = await response.json();
|
|
275
|
+
this.verboseLog(`API response data: ${JSON.stringify(data)}`);
|
|
276
|
+
if (data.exists && data.affiliate) {
|
|
277
|
+
const details = {
|
|
278
|
+
affiliateName: data.affiliate.affiliateName,
|
|
279
|
+
affiliateShortCode: data.affiliate.affiliateShortCode,
|
|
280
|
+
deeplinkUrl: data.affiliate.deeplinkurl
|
|
281
|
+
};
|
|
282
|
+
this.verboseLog(`Successfully retrieved affiliate details for: ${details.affiliateName}`);
|
|
283
|
+
return details;
|
|
284
|
+
}
|
|
285
|
+
this.verboseLog("Affiliate does not exist");
|
|
286
|
+
return null;
|
|
287
|
+
} catch (error) {
|
|
288
|
+
this.verboseLog(`Error fetching affiliate details: ${error}`);
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
static async returnCompanyId() {
|
|
293
|
+
this.verboseLog("Getting company ID...");
|
|
294
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
295
|
+
this.verboseLog(`Company ID: ${companyCode || "none"}`);
|
|
296
|
+
return companyCode;
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Get the offer code for the current affiliate
|
|
300
|
+
* @param platformType Optional platform type: 'stripe' (default for web), 'ios', or 'android'
|
|
301
|
+
* @returns The offer code for the specified platform, or null if not found
|
|
302
|
+
*/
|
|
303
|
+
static async getOfferCode(platformType = "stripe") {
|
|
304
|
+
this.verboseLog(`Getting offer code for platform: ${platformType}...`);
|
|
305
|
+
const storageKey = platformType === "stripe" ? "offerCode" : `offerCode_${platformType}`;
|
|
306
|
+
if (platformType === "stripe" && this.offerCode) {
|
|
307
|
+
this.verboseLog(`Returning cached offer code: ${this.offerCode}`);
|
|
308
|
+
return this.offerCode;
|
|
309
|
+
}
|
|
310
|
+
const storedOfferCode = await getValue(storageKey);
|
|
311
|
+
if (storedOfferCode) {
|
|
312
|
+
this.verboseLog(`Returning stored offer code: ${storedOfferCode}`);
|
|
313
|
+
if (platformType === "stripe") {
|
|
314
|
+
this.offerCode = storedOfferCode;
|
|
315
|
+
}
|
|
316
|
+
return storedOfferCode;
|
|
317
|
+
}
|
|
318
|
+
const shortCode = await getValue("referrerLink");
|
|
319
|
+
if (shortCode) {
|
|
320
|
+
this.verboseLog(`No stored offer code, fetching for short code: ${shortCode}`);
|
|
321
|
+
const fetchedCode = await this.fetchOfferCodeForPlatform(shortCode, platformType);
|
|
322
|
+
return fetchedCode;
|
|
323
|
+
}
|
|
324
|
+
this.verboseLog("No offer code found");
|
|
325
|
+
return null;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Get the Stripe coupon/promo code for the current affiliate
|
|
329
|
+
* Convenience method that calls getOfferCode with platformType='stripe'
|
|
330
|
+
* @returns The Stripe coupon/promo code, or null if not found
|
|
331
|
+
*/
|
|
332
|
+
static async getStripeCouponCode() {
|
|
333
|
+
return this.getOfferCode("stripe");
|
|
334
|
+
}
|
|
335
|
+
/**
|
|
336
|
+
* Fetch offer code for a specific platform
|
|
337
|
+
* @param shortCode The affiliate short code
|
|
338
|
+
* @param platformType The platform type: 'ios', 'android', or 'stripe'
|
|
339
|
+
* @returns The offer code for the specified platform, or null if not found
|
|
340
|
+
*/
|
|
341
|
+
static async fetchOfferCodeForPlatform(shortCode, platformType) {
|
|
342
|
+
this.verboseLog(`Fetching offer code for platform: ${platformType}, short code: ${shortCode}`);
|
|
343
|
+
try {
|
|
344
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
345
|
+
if (!companyCode) {
|
|
346
|
+
this.verboseLog("Cannot fetch offer code: no company code available");
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
const encoded = encodeURIComponent(shortCode);
|
|
350
|
+
const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}?platformType=${platformType}`;
|
|
351
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
352
|
+
const response = await fetch(url);
|
|
353
|
+
this.verboseLog(`API response status: ${response.status}`);
|
|
354
|
+
if (!response.ok) {
|
|
355
|
+
this.verboseLog(`Failed to fetch offer code, status: ${response.status}`);
|
|
356
|
+
return null;
|
|
357
|
+
}
|
|
358
|
+
const offerCode = (await response.text()).replace(/[^a-zA-Z0-9]/g, "");
|
|
359
|
+
this.verboseLog(`Received offer code: ${offerCode}`);
|
|
360
|
+
const errorCodes = [
|
|
361
|
+
"errorofferCodeNotFound",
|
|
362
|
+
"errorAffiliateoffercodenotfoundinanycompany",
|
|
363
|
+
"errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas",
|
|
364
|
+
"Routenotfound"
|
|
365
|
+
];
|
|
366
|
+
if (errorCodes.includes(offerCode)) {
|
|
367
|
+
this.verboseLog("Offer code not found or invalid");
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
const storageKey = platformType === "stripe" ? "offerCode" : `offerCode_${platformType}`;
|
|
371
|
+
await saveValue(storageKey, offerCode);
|
|
372
|
+
if (platformType === "stripe") {
|
|
373
|
+
this.offerCode = offerCode;
|
|
374
|
+
}
|
|
375
|
+
this.verboseLog(`Offer code stored successfully with key ${storageKey}: ${offerCode}`);
|
|
376
|
+
return offerCode;
|
|
377
|
+
} catch (error) {
|
|
378
|
+
this.verboseLog(`Error fetching offer code: ${error}`);
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
static async fetchAndStoreOfferCode(shortCode) {
|
|
383
|
+
this.verboseLog(`Fetching offer code for short code: ${shortCode}`);
|
|
384
|
+
try {
|
|
385
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
386
|
+
if (!companyCode) {
|
|
387
|
+
this.verboseLog("Cannot fetch offer code: no company code available");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
const encoded = encodeURIComponent(shortCode);
|
|
391
|
+
const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}`;
|
|
392
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
393
|
+
const response = await fetch(url);
|
|
394
|
+
this.verboseLog(`API response status: ${response.status}`);
|
|
395
|
+
if (!response.ok) {
|
|
396
|
+
this.verboseLog(`Failed to fetch offer code, status: ${response.status}`);
|
|
397
|
+
return;
|
|
398
|
+
}
|
|
399
|
+
const offerCode = (await response.text()).replace(/[^a-zA-Z0-9]/g, "");
|
|
400
|
+
this.verboseLog(`Received offer code: ${offerCode}`);
|
|
401
|
+
const errorCodes = [
|
|
402
|
+
"errorofferCodeNotFound",
|
|
403
|
+
"errorAffiliateoffercodenotfoundinanycompany",
|
|
404
|
+
"errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas",
|
|
405
|
+
"Routenotfound"
|
|
406
|
+
];
|
|
407
|
+
if (errorCodes.includes(offerCode)) {
|
|
408
|
+
this.verboseLog("Offer code not found or invalid");
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
this.offerCode = offerCode;
|
|
412
|
+
await saveValue("offerCode", offerCode);
|
|
413
|
+
this.verboseLog(`Offer code stored successfully: ${offerCode}`);
|
|
414
|
+
} catch (error) {
|
|
415
|
+
this.verboseLog(`Error fetching offer code: ${error}`);
|
|
416
|
+
}
|
|
108
417
|
}
|
|
109
418
|
static async trackEvent(eventName) {
|
|
419
|
+
this.verboseLog(`Tracking event: ${eventName}`);
|
|
110
420
|
const id = await this.returnInsertAffiliateIdentifier();
|
|
111
421
|
if (!id) {
|
|
112
|
-
|
|
422
|
+
this.verboseLog("Cannot track event: no affiliate identifier available");
|
|
113
423
|
return;
|
|
114
424
|
}
|
|
115
425
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
116
|
-
|
|
426
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}`);
|
|
427
|
+
if (!companyCode) {
|
|
428
|
+
this.verboseLog("Cannot track event: no company code available");
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const payload = {
|
|
432
|
+
eventName,
|
|
433
|
+
deepLinkParam: id,
|
|
434
|
+
companyId: companyCode
|
|
435
|
+
};
|
|
436
|
+
this.verboseLog(`Track event payload: ${JSON.stringify(payload)}`);
|
|
437
|
+
this.verboseLog("Making API call to track event...");
|
|
117
438
|
try {
|
|
118
|
-
await fetch("https://api.insertaffiliate.com/v1/trackEvent", {
|
|
439
|
+
const response = await fetch("https://api.insertaffiliate.com/v1/trackEvent", {
|
|
119
440
|
method: "POST",
|
|
120
441
|
headers: { "Content-Type": "application/json" },
|
|
121
|
-
body: JSON.stringify(
|
|
122
|
-
{
|
|
123
|
-
eventName,
|
|
124
|
-
deepLinkParam: id,
|
|
125
|
-
companyId: companyCode
|
|
126
|
-
}
|
|
127
|
-
)
|
|
442
|
+
body: JSON.stringify(payload)
|
|
128
443
|
});
|
|
129
|
-
|
|
444
|
+
this.verboseLog(`Track event API response status: ${response.status}`);
|
|
445
|
+
if (response.ok) {
|
|
446
|
+
this.verboseLog(`Event tracked successfully: ${eventName}`);
|
|
447
|
+
} else {
|
|
448
|
+
this.verboseLog(`Failed to track event with status code: ${response.status}`);
|
|
449
|
+
}
|
|
130
450
|
} catch (err) {
|
|
131
|
-
|
|
451
|
+
this.verboseLog(`Network error tracking event: ${err}`);
|
|
132
452
|
}
|
|
133
453
|
}
|
|
134
454
|
static async returnUserAccountTokenAndStoreExpectedTransaction() {
|
|
455
|
+
this.verboseLog("Getting user account token and storing expected transaction...");
|
|
135
456
|
const shortCode = await this.returnInsertAffiliateIdentifier();
|
|
136
|
-
if (!shortCode)
|
|
457
|
+
if (!shortCode) {
|
|
458
|
+
this.verboseLog("No affiliate identifier found, not saving expected transaction");
|
|
459
|
+
return null;
|
|
460
|
+
}
|
|
137
461
|
let token = await getValue("userAccountToken");
|
|
462
|
+
this.verboseLog(`Existing token: ${token || "none"}`);
|
|
138
463
|
if (!token) {
|
|
464
|
+
this.verboseLog("Generating new user account token...");
|
|
139
465
|
token = generateUUID();
|
|
140
466
|
await saveValue("userAccountToken", token);
|
|
467
|
+
this.verboseLog(`Generated and saved new token: ${token}`);
|
|
141
468
|
}
|
|
469
|
+
this.verboseLog(`User account token: ${token}`);
|
|
142
470
|
await this.storeExpectedStoreTransaction(token);
|
|
143
471
|
return token;
|
|
144
472
|
}
|
|
145
473
|
static async storeExpectedStoreTransaction(userAccountToken) {
|
|
474
|
+
this.verboseLog(`Storing expected store transaction with token: ${userAccountToken}`);
|
|
146
475
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
147
476
|
const shortCode = await this.returnInsertAffiliateIdentifier();
|
|
477
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}, Short code: ${shortCode || "empty"}`);
|
|
148
478
|
if (!companyCode || !shortCode) {
|
|
149
|
-
|
|
479
|
+
this.verboseLog("Cannot store transaction: missing company code or identifier");
|
|
150
480
|
return;
|
|
151
481
|
}
|
|
152
482
|
const payload = {
|
|
@@ -155,36 +485,43 @@ var InsertAffiliate = class {
|
|
|
155
485
|
shortCode,
|
|
156
486
|
storedDate: (/* @__PURE__ */ new Date()).toISOString()
|
|
157
487
|
};
|
|
488
|
+
this.verboseLog(`Payload: ${JSON.stringify(payload)}`);
|
|
489
|
+
this.verboseLog("Making API call to store expected transaction...");
|
|
158
490
|
try {
|
|
159
491
|
const res = await fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
160
492
|
method: "POST",
|
|
161
493
|
headers: { "Content-Type": "application/json" },
|
|
162
494
|
body: JSON.stringify(payload)
|
|
163
495
|
});
|
|
496
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
164
497
|
if (res.status === 200) {
|
|
165
|
-
|
|
498
|
+
this.verboseLog("Expected transaction stored successfully on server");
|
|
166
499
|
} else {
|
|
167
|
-
|
|
500
|
+
this.verboseLog(`Failed to store transaction with status: ${res.status}`);
|
|
168
501
|
}
|
|
169
502
|
} catch (error) {
|
|
170
|
-
|
|
503
|
+
this.verboseLog(`Network error storing transaction: ${error}`);
|
|
171
504
|
}
|
|
172
505
|
}
|
|
173
506
|
static async validatePurchaseWithIapticAPI(jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) {
|
|
174
507
|
try {
|
|
508
|
+
this.verboseLog("Starting Iaptic purchase validation...");
|
|
175
509
|
const isIOS = typeof window !== "undefined" && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
510
|
+
this.verboseLog(`Platform detected: ${isIOS ? "iOS" : "Android"}`);
|
|
176
511
|
const baseRequest = {
|
|
177
512
|
id: iapticAppId,
|
|
178
513
|
type: "application"
|
|
179
514
|
};
|
|
180
515
|
let transaction;
|
|
181
516
|
if (isIOS) {
|
|
517
|
+
this.verboseLog("Creating iOS transaction payload");
|
|
182
518
|
transaction = {
|
|
183
519
|
id: iapticAppId,
|
|
184
520
|
type: "ios-appstore",
|
|
185
521
|
appStoreReceipt: jsonIapPurchase.transactionReceipt
|
|
186
522
|
};
|
|
187
523
|
} else {
|
|
524
|
+
this.verboseLog("Creating Android transaction payload");
|
|
188
525
|
const receiptJson = JSON.parse(atob(jsonIapPurchase.transactionReceipt));
|
|
189
526
|
transaction = {
|
|
190
527
|
id: receiptJson.orderId,
|
|
@@ -195,10 +532,12 @@ var InsertAffiliate = class {
|
|
|
195
532
|
};
|
|
196
533
|
}
|
|
197
534
|
const insertAffiliateIdentifier = await this.returnInsertAffiliateIdentifier();
|
|
535
|
+
this.verboseLog(`Affiliate identifier: ${insertAffiliateIdentifier || "none"}`);
|
|
198
536
|
const payload = __spreadProps(__spreadValues({}, baseRequest), {
|
|
199
537
|
transaction,
|
|
200
538
|
additionalData: insertAffiliateIdentifier ? { applicationUsername: insertAffiliateIdentifier } : void 0
|
|
201
539
|
});
|
|
540
|
+
this.verboseLog("Making API call to Iaptic validator...");
|
|
202
541
|
const response = await fetch("https://validator.iaptic.com/v1/validate", {
|
|
203
542
|
method: "POST",
|
|
204
543
|
headers: {
|
|
@@ -207,17 +546,36 @@ var InsertAffiliate = class {
|
|
|
207
546
|
},
|
|
208
547
|
body: JSON.stringify(payload)
|
|
209
548
|
});
|
|
210
|
-
|
|
549
|
+
this.verboseLog(`Iaptic validation response status: ${response.status}`);
|
|
550
|
+
if (response.status === 200) {
|
|
551
|
+
this.verboseLog("Purchase validated successfully");
|
|
552
|
+
return true;
|
|
553
|
+
} else {
|
|
554
|
+
this.verboseLog(`Validation failed with status: ${response.status}`);
|
|
555
|
+
return false;
|
|
556
|
+
}
|
|
211
557
|
} catch (error) {
|
|
212
|
-
|
|
558
|
+
this.verboseLog(`Error during purchase validation: ${error}`);
|
|
213
559
|
return false;
|
|
214
560
|
}
|
|
215
561
|
}
|
|
216
562
|
static async fetchAndConditionallyOpenUrl(affiliateLink, offerCodeUrlId) {
|
|
563
|
+
this.verboseLog("Fetching offer code and opening URL...");
|
|
217
564
|
const encoded = encodeURIComponent(affiliateLink);
|
|
565
|
+
this.verboseLog(`Encoded affiliate link: ${encoded}`);
|
|
218
566
|
try {
|
|
219
|
-
const
|
|
567
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
568
|
+
if (!companyCode) {
|
|
569
|
+
this.verboseLog("Cannot fetch offer code: no company code available");
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
this.verboseLog("Making API call to fetch offer code...");
|
|
573
|
+
const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}`;
|
|
574
|
+
this.verboseLog(`API URL: ${url}`);
|
|
575
|
+
const res = await fetch(url);
|
|
576
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
220
577
|
const offerCode = (await res.text()).replace(/[^a-zA-Z0-9]/g, "");
|
|
578
|
+
this.verboseLog(`Received offer code: ${offerCode}`);
|
|
221
579
|
const errorCodes = [
|
|
222
580
|
"errorofferCodeNotFound",
|
|
223
581
|
"errorAffiliateoffercodenotfoundinanycompany",
|
|
@@ -225,39 +583,60 @@ var InsertAffiliate = class {
|
|
|
225
583
|
"Routenotfound"
|
|
226
584
|
];
|
|
227
585
|
if (errorCodes.includes(offerCode)) {
|
|
228
|
-
|
|
586
|
+
this.verboseLog("Offer code not found or invalid");
|
|
229
587
|
return;
|
|
230
588
|
}
|
|
231
589
|
const redeemUrl = `https://apps.apple.com/redeem?ctx=offercodes&id=${offerCodeUrlId}&code=${offerCode}`;
|
|
590
|
+
this.verboseLog(`Opening redeem URL: ${redeemUrl}`);
|
|
232
591
|
window.open(redeemUrl, "_blank");
|
|
592
|
+
this.verboseLog("Redeem URL opened successfully");
|
|
233
593
|
} catch (err) {
|
|
234
|
-
|
|
594
|
+
this.verboseLog(`Error fetching/opening offer code: ${err}`);
|
|
235
595
|
}
|
|
236
596
|
}
|
|
237
597
|
static async getOrCreateUserID() {
|
|
598
|
+
this.verboseLog("Getting or creating user ID...");
|
|
238
599
|
let id = await getValue("userId");
|
|
600
|
+
this.verboseLog(`Existing user ID: ${id || "none"}`);
|
|
239
601
|
if (!id) {
|
|
602
|
+
this.verboseLog("Generating new user ID...");
|
|
240
603
|
id = generateShortDeviceID();
|
|
241
604
|
await saveValue("userId", id);
|
|
605
|
+
this.verboseLog(`Generated and saved new user ID: ${id}`);
|
|
242
606
|
}
|
|
243
607
|
return id;
|
|
244
608
|
}
|
|
245
609
|
static async fetchShortLink(link) {
|
|
246
610
|
try {
|
|
611
|
+
this.verboseLog("Converting deep link to short link...");
|
|
247
612
|
const encoded = encodeURIComponent(link);
|
|
248
613
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
249
|
-
|
|
250
|
-
|
|
614
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}`);
|
|
615
|
+
if (!companyCode) {
|
|
616
|
+
this.verboseLog("No company code available, cannot convert link");
|
|
617
|
+
return null;
|
|
618
|
+
}
|
|
619
|
+
const url = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${companyCode}&deepLinkUrl=${encoded}`;
|
|
620
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
621
|
+
const res = await fetch(url);
|
|
622
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
251
623
|
const data = await res.json();
|
|
252
|
-
|
|
624
|
+
const shortLink = (data == null ? void 0 : data.shortLink) || null;
|
|
625
|
+
this.verboseLog(`Short link received: ${shortLink || "none"}`);
|
|
626
|
+
return shortLink;
|
|
253
627
|
} catch (err) {
|
|
254
|
-
|
|
628
|
+
this.verboseLog(`Error fetching short link: ${(err == null ? void 0 : err.message) || err}`);
|
|
255
629
|
return null;
|
|
256
630
|
}
|
|
257
631
|
}
|
|
258
632
|
};
|
|
259
633
|
InsertAffiliate.isInitialized = false;
|
|
260
634
|
InsertAffiliate.companyCode = null;
|
|
635
|
+
InsertAffiliate.verboseLogging = false;
|
|
636
|
+
InsertAffiliate.insertAffiliateIdentifierChangeCallback = null;
|
|
637
|
+
InsertAffiliate.affiliateAttributionActiveTime = null;
|
|
638
|
+
// in milliseconds
|
|
639
|
+
InsertAffiliate.offerCode = null;
|
|
261
640
|
// Annotate the CommonJS export names for ESM import in node:
|
|
262
641
|
0 && (module.exports = {
|
|
263
642
|
InsertAffiliate
|