insert-affiliate-js-sdk 1.0.2 → 1.1.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 +600 -30
- package/dist/index.d.ts +35 -4
- package/dist/index.js +347 -37
- package/package.json +1 -1
- package/src/sdk/InsertAffiliate.ts +459 -37
package/dist/index.d.ts
CHANGED
|
@@ -1,13 +1,44 @@
|
|
|
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
|
+
static getOfferCode(): Promise<string | null>;
|
|
41
|
+
private static fetchAndStoreOfferCode;
|
|
11
42
|
static trackEvent(eventName: string): Promise<void>;
|
|
12
43
|
static returnUserAccountTokenAndStoreExpectedTransaction(): Promise<string | null>;
|
|
13
44
|
static storeExpectedStoreTransaction(userAccountToken: string): Promise<void>;
|
|
@@ -19,4 +50,4 @@ declare class InsertAffiliate {
|
|
|
19
50
|
private static fetchShortLink;
|
|
20
51
|
}
|
|
21
52
|
|
|
22
|
-
export { InsertAffiliate };
|
|
53
|
+
export { type AffiliateDetails, InsertAffiliate, type InsertAffiliateIdentifierChangeCallback };
|
package/dist/index.js
CHANGED
|
@@ -75,78 +75,339 @@ 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;
|
|
106
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;
|
|
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
|
+
static async getOfferCode() {
|
|
299
|
+
this.verboseLog("Getting offer code...");
|
|
300
|
+
if (this.offerCode) {
|
|
301
|
+
this.verboseLog(`Returning cached offer code: ${this.offerCode}`);
|
|
302
|
+
return this.offerCode;
|
|
303
|
+
}
|
|
304
|
+
const storedOfferCode = await getValue("offerCode");
|
|
305
|
+
if (storedOfferCode) {
|
|
306
|
+
this.verboseLog(`Returning stored offer code: ${storedOfferCode}`);
|
|
307
|
+
this.offerCode = storedOfferCode;
|
|
308
|
+
return storedOfferCode;
|
|
309
|
+
}
|
|
310
|
+
this.verboseLog("No offer code found");
|
|
311
|
+
return null;
|
|
312
|
+
}
|
|
313
|
+
static async fetchAndStoreOfferCode(shortCode) {
|
|
314
|
+
this.verboseLog(`Fetching offer code for short code: ${shortCode}`);
|
|
315
|
+
try {
|
|
316
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
317
|
+
if (!companyCode) {
|
|
318
|
+
this.verboseLog("Cannot fetch offer code: no company code available");
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
const encoded = encodeURIComponent(shortCode);
|
|
322
|
+
const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}`;
|
|
323
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
324
|
+
const response = await fetch(url);
|
|
325
|
+
this.verboseLog(`API response status: ${response.status}`);
|
|
326
|
+
if (!response.ok) {
|
|
327
|
+
this.verboseLog(`Failed to fetch offer code, status: ${response.status}`);
|
|
328
|
+
return;
|
|
329
|
+
}
|
|
330
|
+
const offerCode = (await response.text()).replace(/[^a-zA-Z0-9]/g, "");
|
|
331
|
+
this.verboseLog(`Received offer code: ${offerCode}`);
|
|
332
|
+
const errorCodes = [
|
|
333
|
+
"errorofferCodeNotFound",
|
|
334
|
+
"errorAffiliateoffercodenotfoundinanycompany",
|
|
335
|
+
"errorAffiliateoffercodenotfoundinanycompanyAffiliatelinkwas",
|
|
336
|
+
"Routenotfound"
|
|
337
|
+
];
|
|
338
|
+
if (errorCodes.includes(offerCode)) {
|
|
339
|
+
this.verboseLog("Offer code not found or invalid");
|
|
340
|
+
return;
|
|
341
|
+
}
|
|
342
|
+
this.offerCode = offerCode;
|
|
343
|
+
await saveValue("offerCode", offerCode);
|
|
344
|
+
this.verboseLog(`Offer code stored successfully: ${offerCode}`);
|
|
345
|
+
} catch (error) {
|
|
346
|
+
this.verboseLog(`Error fetching offer code: ${error}`);
|
|
347
|
+
}
|
|
108
348
|
}
|
|
109
349
|
static async trackEvent(eventName) {
|
|
350
|
+
this.verboseLog(`Tracking event: ${eventName}`);
|
|
110
351
|
const id = await this.returnInsertAffiliateIdentifier();
|
|
111
352
|
if (!id) {
|
|
112
|
-
|
|
353
|
+
this.verboseLog("Cannot track event: no affiliate identifier available");
|
|
113
354
|
return;
|
|
114
355
|
}
|
|
115
356
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
116
|
-
|
|
357
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}`);
|
|
358
|
+
if (!companyCode) {
|
|
359
|
+
this.verboseLog("Cannot track event: no company code available");
|
|
360
|
+
return;
|
|
361
|
+
}
|
|
362
|
+
const payload = {
|
|
363
|
+
eventName,
|
|
364
|
+
deepLinkParam: id,
|
|
365
|
+
companyId: companyCode
|
|
366
|
+
};
|
|
367
|
+
this.verboseLog(`Track event payload: ${JSON.stringify(payload)}`);
|
|
368
|
+
this.verboseLog("Making API call to track event...");
|
|
117
369
|
try {
|
|
118
|
-
await fetch("https://api.insertaffiliate.com/v1/trackEvent", {
|
|
370
|
+
const response = await fetch("https://api.insertaffiliate.com/v1/trackEvent", {
|
|
119
371
|
method: "POST",
|
|
120
372
|
headers: { "Content-Type": "application/json" },
|
|
121
|
-
body: JSON.stringify(
|
|
122
|
-
{
|
|
123
|
-
eventName,
|
|
124
|
-
deepLinkParam: id,
|
|
125
|
-
companyId: companyCode
|
|
126
|
-
}
|
|
127
|
-
)
|
|
373
|
+
body: JSON.stringify(payload)
|
|
128
374
|
});
|
|
129
|
-
|
|
375
|
+
this.verboseLog(`Track event API response status: ${response.status}`);
|
|
376
|
+
if (response.ok) {
|
|
377
|
+
this.verboseLog(`Event tracked successfully: ${eventName}`);
|
|
378
|
+
} else {
|
|
379
|
+
this.verboseLog(`Failed to track event with status code: ${response.status}`);
|
|
380
|
+
}
|
|
130
381
|
} catch (err) {
|
|
131
|
-
|
|
382
|
+
this.verboseLog(`Network error tracking event: ${err}`);
|
|
132
383
|
}
|
|
133
384
|
}
|
|
134
385
|
static async returnUserAccountTokenAndStoreExpectedTransaction() {
|
|
386
|
+
this.verboseLog("Getting user account token and storing expected transaction...");
|
|
135
387
|
const shortCode = await this.returnInsertAffiliateIdentifier();
|
|
136
|
-
if (!shortCode)
|
|
388
|
+
if (!shortCode) {
|
|
389
|
+
this.verboseLog("No affiliate identifier found, not saving expected transaction");
|
|
390
|
+
return null;
|
|
391
|
+
}
|
|
137
392
|
let token = await getValue("userAccountToken");
|
|
393
|
+
this.verboseLog(`Existing token: ${token || "none"}`);
|
|
138
394
|
if (!token) {
|
|
395
|
+
this.verboseLog("Generating new user account token...");
|
|
139
396
|
token = generateUUID();
|
|
140
397
|
await saveValue("userAccountToken", token);
|
|
398
|
+
this.verboseLog(`Generated and saved new token: ${token}`);
|
|
141
399
|
}
|
|
400
|
+
this.verboseLog(`User account token: ${token}`);
|
|
142
401
|
await this.storeExpectedStoreTransaction(token);
|
|
143
402
|
return token;
|
|
144
403
|
}
|
|
145
404
|
static async storeExpectedStoreTransaction(userAccountToken) {
|
|
405
|
+
this.verboseLog(`Storing expected store transaction with token: ${userAccountToken}`);
|
|
146
406
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
147
407
|
const shortCode = await this.returnInsertAffiliateIdentifier();
|
|
408
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}, Short code: ${shortCode || "empty"}`);
|
|
148
409
|
if (!companyCode || !shortCode) {
|
|
149
|
-
|
|
410
|
+
this.verboseLog("Cannot store transaction: missing company code or identifier");
|
|
150
411
|
return;
|
|
151
412
|
}
|
|
152
413
|
const payload = {
|
|
@@ -155,36 +416,43 @@ var InsertAffiliate = class {
|
|
|
155
416
|
shortCode,
|
|
156
417
|
storedDate: (/* @__PURE__ */ new Date()).toISOString()
|
|
157
418
|
};
|
|
419
|
+
this.verboseLog(`Payload: ${JSON.stringify(payload)}`);
|
|
420
|
+
this.verboseLog("Making API call to store expected transaction...");
|
|
158
421
|
try {
|
|
159
422
|
const res = await fetch("https://api.insertaffiliate.com/v1/api/app-store-webhook/create-expected-transaction", {
|
|
160
423
|
method: "POST",
|
|
161
424
|
headers: { "Content-Type": "application/json" },
|
|
162
425
|
body: JSON.stringify(payload)
|
|
163
426
|
});
|
|
427
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
164
428
|
if (res.status === 200) {
|
|
165
|
-
|
|
429
|
+
this.verboseLog("Expected transaction stored successfully on server");
|
|
166
430
|
} else {
|
|
167
|
-
|
|
431
|
+
this.verboseLog(`Failed to store transaction with status: ${res.status}`);
|
|
168
432
|
}
|
|
169
433
|
} catch (error) {
|
|
170
|
-
|
|
434
|
+
this.verboseLog(`Network error storing transaction: ${error}`);
|
|
171
435
|
}
|
|
172
436
|
}
|
|
173
437
|
static async validatePurchaseWithIapticAPI(jsonIapPurchase, iapticAppId, iapticAppName, iapticPublicKey) {
|
|
174
438
|
try {
|
|
439
|
+
this.verboseLog("Starting Iaptic purchase validation...");
|
|
175
440
|
const isIOS = typeof window !== "undefined" && /iPad|iPhone|iPod/.test(navigator.userAgent);
|
|
441
|
+
this.verboseLog(`Platform detected: ${isIOS ? "iOS" : "Android"}`);
|
|
176
442
|
const baseRequest = {
|
|
177
443
|
id: iapticAppId,
|
|
178
444
|
type: "application"
|
|
179
445
|
};
|
|
180
446
|
let transaction;
|
|
181
447
|
if (isIOS) {
|
|
448
|
+
this.verboseLog("Creating iOS transaction payload");
|
|
182
449
|
transaction = {
|
|
183
450
|
id: iapticAppId,
|
|
184
451
|
type: "ios-appstore",
|
|
185
452
|
appStoreReceipt: jsonIapPurchase.transactionReceipt
|
|
186
453
|
};
|
|
187
454
|
} else {
|
|
455
|
+
this.verboseLog("Creating Android transaction payload");
|
|
188
456
|
const receiptJson = JSON.parse(atob(jsonIapPurchase.transactionReceipt));
|
|
189
457
|
transaction = {
|
|
190
458
|
id: receiptJson.orderId,
|
|
@@ -195,10 +463,12 @@ var InsertAffiliate = class {
|
|
|
195
463
|
};
|
|
196
464
|
}
|
|
197
465
|
const insertAffiliateIdentifier = await this.returnInsertAffiliateIdentifier();
|
|
466
|
+
this.verboseLog(`Affiliate identifier: ${insertAffiliateIdentifier || "none"}`);
|
|
198
467
|
const payload = __spreadProps(__spreadValues({}, baseRequest), {
|
|
199
468
|
transaction,
|
|
200
469
|
additionalData: insertAffiliateIdentifier ? { applicationUsername: insertAffiliateIdentifier } : void 0
|
|
201
470
|
});
|
|
471
|
+
this.verboseLog("Making API call to Iaptic validator...");
|
|
202
472
|
const response = await fetch("https://validator.iaptic.com/v1/validate", {
|
|
203
473
|
method: "POST",
|
|
204
474
|
headers: {
|
|
@@ -207,17 +477,36 @@ var InsertAffiliate = class {
|
|
|
207
477
|
},
|
|
208
478
|
body: JSON.stringify(payload)
|
|
209
479
|
});
|
|
210
|
-
|
|
480
|
+
this.verboseLog(`Iaptic validation response status: ${response.status}`);
|
|
481
|
+
if (response.status === 200) {
|
|
482
|
+
this.verboseLog("Purchase validated successfully");
|
|
483
|
+
return true;
|
|
484
|
+
} else {
|
|
485
|
+
this.verboseLog(`Validation failed with status: ${response.status}`);
|
|
486
|
+
return false;
|
|
487
|
+
}
|
|
211
488
|
} catch (error) {
|
|
212
|
-
|
|
489
|
+
this.verboseLog(`Error during purchase validation: ${error}`);
|
|
213
490
|
return false;
|
|
214
491
|
}
|
|
215
492
|
}
|
|
216
493
|
static async fetchAndConditionallyOpenUrl(affiliateLink, offerCodeUrlId) {
|
|
494
|
+
this.verboseLog("Fetching offer code and opening URL...");
|
|
217
495
|
const encoded = encodeURIComponent(affiliateLink);
|
|
496
|
+
this.verboseLog(`Encoded affiliate link: ${encoded}`);
|
|
218
497
|
try {
|
|
219
|
-
const
|
|
498
|
+
const companyCode = this.companyCode || await getValue("companyCode");
|
|
499
|
+
if (!companyCode) {
|
|
500
|
+
this.verboseLog("Cannot fetch offer code: no company code available");
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
this.verboseLog("Making API call to fetch offer code...");
|
|
504
|
+
const url = `https://api.insertaffiliate.com/v1/affiliateReturnOfferCode/${companyCode}/${encoded}`;
|
|
505
|
+
this.verboseLog(`API URL: ${url}`);
|
|
506
|
+
const res = await fetch(url);
|
|
507
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
220
508
|
const offerCode = (await res.text()).replace(/[^a-zA-Z0-9]/g, "");
|
|
509
|
+
this.verboseLog(`Received offer code: ${offerCode}`);
|
|
221
510
|
const errorCodes = [
|
|
222
511
|
"errorofferCodeNotFound",
|
|
223
512
|
"errorAffiliateoffercodenotfoundinanycompany",
|
|
@@ -225,39 +514,60 @@ var InsertAffiliate = class {
|
|
|
225
514
|
"Routenotfound"
|
|
226
515
|
];
|
|
227
516
|
if (errorCodes.includes(offerCode)) {
|
|
228
|
-
|
|
517
|
+
this.verboseLog("Offer code not found or invalid");
|
|
229
518
|
return;
|
|
230
519
|
}
|
|
231
520
|
const redeemUrl = `https://apps.apple.com/redeem?ctx=offercodes&id=${offerCodeUrlId}&code=${offerCode}`;
|
|
521
|
+
this.verboseLog(`Opening redeem URL: ${redeemUrl}`);
|
|
232
522
|
window.open(redeemUrl, "_blank");
|
|
523
|
+
this.verboseLog("Redeem URL opened successfully");
|
|
233
524
|
} catch (err) {
|
|
234
|
-
|
|
525
|
+
this.verboseLog(`Error fetching/opening offer code: ${err}`);
|
|
235
526
|
}
|
|
236
527
|
}
|
|
237
528
|
static async getOrCreateUserID() {
|
|
529
|
+
this.verboseLog("Getting or creating user ID...");
|
|
238
530
|
let id = await getValue("userId");
|
|
531
|
+
this.verboseLog(`Existing user ID: ${id || "none"}`);
|
|
239
532
|
if (!id) {
|
|
533
|
+
this.verboseLog("Generating new user ID...");
|
|
240
534
|
id = generateShortDeviceID();
|
|
241
535
|
await saveValue("userId", id);
|
|
536
|
+
this.verboseLog(`Generated and saved new user ID: ${id}`);
|
|
242
537
|
}
|
|
243
538
|
return id;
|
|
244
539
|
}
|
|
245
540
|
static async fetchShortLink(link) {
|
|
246
541
|
try {
|
|
542
|
+
this.verboseLog("Converting deep link to short link...");
|
|
247
543
|
const encoded = encodeURIComponent(link);
|
|
248
544
|
const companyCode = this.companyCode || await getValue("companyCode");
|
|
249
|
-
|
|
250
|
-
|
|
545
|
+
this.verboseLog(`Company code: ${companyCode || "empty"}`);
|
|
546
|
+
if (!companyCode) {
|
|
547
|
+
this.verboseLog("No company code available, cannot convert link");
|
|
548
|
+
return null;
|
|
549
|
+
}
|
|
550
|
+
const url = `https://api.insertaffiliate.com/V1/convert-deep-link-to-short-link?companyId=${companyCode}&deepLinkUrl=${encoded}`;
|
|
551
|
+
this.verboseLog(`Making API call to: ${url}`);
|
|
552
|
+
const res = await fetch(url);
|
|
553
|
+
this.verboseLog(`API response status: ${res.status}`);
|
|
251
554
|
const data = await res.json();
|
|
252
|
-
|
|
555
|
+
const shortLink = (data == null ? void 0 : data.shortLink) || null;
|
|
556
|
+
this.verboseLog(`Short link received: ${shortLink || "none"}`);
|
|
557
|
+
return shortLink;
|
|
253
558
|
} catch (err) {
|
|
254
|
-
|
|
559
|
+
this.verboseLog(`Error fetching short link: ${(err == null ? void 0 : err.message) || err}`);
|
|
255
560
|
return null;
|
|
256
561
|
}
|
|
257
562
|
}
|
|
258
563
|
};
|
|
259
564
|
InsertAffiliate.isInitialized = false;
|
|
260
565
|
InsertAffiliate.companyCode = null;
|
|
566
|
+
InsertAffiliate.verboseLogging = false;
|
|
567
|
+
InsertAffiliate.insertAffiliateIdentifierChangeCallback = null;
|
|
568
|
+
InsertAffiliate.affiliateAttributionActiveTime = null;
|
|
569
|
+
// in milliseconds
|
|
570
|
+
InsertAffiliate.offerCode = null;
|
|
261
571
|
// Annotate the CommonJS export names for ESM import in node:
|
|
262
572
|
0 && (module.exports = {
|
|
263
573
|
InsertAffiliate
|