choreograph-create-pixel 1.4.2 โ 1.4.4
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/README.md +2 -2
- package/dist/bundle.cjs +370 -0
- package/dist/bundle.esm.js +299 -373
- package/dist/bundle.iife.min.js +3 -2
- package/package.json +13 -21
- package/dist/bundle.cjs.js +0 -425
package/dist/bundle.esm.js
CHANGED
|
@@ -1,181 +1,320 @@
|
|
|
1
|
-
/*! choreograph-create-pixel v1.4.
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
1
|
+
/*! choreograph-create-pixel v1.4.4 2026/03/14 */
|
|
2
|
+
|
|
3
|
+
// src/helpers.js
|
|
4
|
+
function getUrl({ allowedQueryParameters = [], allowHash = false } = {}) {
|
|
5
|
+
let url = `${location.protocol}//${location.host}${location.pathname}`;
|
|
6
|
+
const parameters = new URLSearchParams(location.search);
|
|
7
|
+
allowedQueryParameters.reduce((paramAdded, parameter) => {
|
|
8
|
+
const separator = paramAdded ? "&" : "?";
|
|
9
|
+
const key = encodeURI(parameter);
|
|
10
|
+
const value = parameters.get(parameter);
|
|
11
|
+
if (value != null) {
|
|
12
|
+
url += `${separator}${key}${value === "" ? "" : `=${encodeURI(value)}`}`;
|
|
13
|
+
return true;
|
|
14
|
+
}
|
|
15
|
+
return paramAdded;
|
|
16
|
+
}, false);
|
|
17
|
+
if (allowHash) url += location.hash;
|
|
18
|
+
return url;
|
|
19
|
+
}
|
|
20
|
+
function getAllPathSegments() {
|
|
21
|
+
return location.pathname.split("/").filter((segment) => segment).map((segment) => decodeURI(segment));
|
|
22
|
+
}
|
|
23
|
+
function getPathSegment(index) {
|
|
24
|
+
return getAllPathSegments()[index];
|
|
25
|
+
}
|
|
26
|
+
function getAllQueryParameters() {
|
|
27
|
+
return location.search.replace(/^\?/, "").split("&").filter((parameter) => parameter).reduce(
|
|
28
|
+
(parameters, parameter) => ({
|
|
29
|
+
...parameters,
|
|
30
|
+
[decodeURI(parameter.split("=")[0])]: decodeURI(
|
|
31
|
+
parameter.split("=")[1] || ""
|
|
32
|
+
)
|
|
33
|
+
}),
|
|
34
|
+
{}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
function getQueryParameter(key) {
|
|
38
|
+
return getAllQueryParameters()[key];
|
|
39
|
+
}
|
|
23
40
|
|
|
24
|
-
|
|
25
|
-
|
|
41
|
+
// src/log.js
|
|
42
|
+
function log(level, message, data = null) {
|
|
43
|
+
if (!this.config.debug || this.logs.includes(message)) return;
|
|
44
|
+
const args = [
|
|
45
|
+
`%cCreative Optimizations%c ${this.config.icons[this.config.type]} ${this.config.type} %c${message}`,
|
|
46
|
+
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
47
|
+
"font-weight:bold",
|
|
48
|
+
`color:${this.config.colors[level]}`
|
|
49
|
+
];
|
|
50
|
+
if (data) args.push(data);
|
|
51
|
+
console.info(...args);
|
|
52
|
+
this.logs.push(message);
|
|
53
|
+
}
|
|
26
54
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
55
|
+
// src/validate.js
|
|
56
|
+
function validateConfig() {
|
|
57
|
+
if (typeof this.config.advertiser !== "number")
|
|
58
|
+
this.log("error", "Please use a number", {
|
|
59
|
+
advertiser: this.config.advertiser
|
|
60
|
+
});
|
|
61
|
+
else if (![
|
|
62
|
+
"scraper",
|
|
63
|
+
"viewed",
|
|
64
|
+
"basketed",
|
|
65
|
+
"purchased",
|
|
66
|
+
"attribution",
|
|
67
|
+
"conversion"
|
|
68
|
+
].includes(this.config.type))
|
|
69
|
+
this.log(
|
|
70
|
+
"error",
|
|
71
|
+
"Please use scraper, viewed, basketed, purchased, attribution or conversion",
|
|
72
|
+
{ type: this.config.type }
|
|
73
|
+
);
|
|
74
|
+
else if (["attribution", "conversion"].includes(this.config.type) && typeof this.config.label !== "string")
|
|
75
|
+
this.log("error", "Please use a string", {
|
|
76
|
+
label: this.config.label
|
|
77
|
+
});
|
|
78
|
+
else if (!(this.config.url instanceof RegExp))
|
|
79
|
+
this.log("error", "Please use a regular expression", {
|
|
80
|
+
url: this.config.url
|
|
81
|
+
});
|
|
82
|
+
else if (!["attribution", "conversion"].includes(this.config.type) && !this.config.scrape)
|
|
83
|
+
this.log("error", "Please provide something to scrape", {
|
|
84
|
+
scrape: this.config.scrape
|
|
85
|
+
});
|
|
86
|
+
else return true;
|
|
87
|
+
}
|
|
30
88
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
89
|
+
// src/attribute.js
|
|
90
|
+
function attribute() {
|
|
91
|
+
const ccpid = getQueryParameter("ccpid");
|
|
92
|
+
if (!ccpid) return this.log("warn", "ccpid query parameter not present");
|
|
93
|
+
if (!/^[0-9a-f]{20}$/.test(ccpid))
|
|
94
|
+
return this.log(
|
|
95
|
+
"error",
|
|
96
|
+
"ccpid query parameter is not formatted correctly"
|
|
97
|
+
);
|
|
98
|
+
const storageItemLabel = `choreograph-${this.config.label}`;
|
|
99
|
+
const storedCcpid = localStorage.getItem(storageItemLabel);
|
|
100
|
+
if (storedCcpid === "")
|
|
101
|
+
return this.log("warn", `"${this.config.label}" already converted`);
|
|
102
|
+
if (storedCcpid !== ccpid) localStorage.setItem(storageItemLabel, ccpid);
|
|
103
|
+
this.log("success", `Stored CCPID "${ccpid}" for "${this.config.label}"`);
|
|
104
|
+
}
|
|
35
105
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
106
|
+
// src/convert.js
|
|
107
|
+
function convert() {
|
|
108
|
+
const label = `choreograph-${this.config.label}`;
|
|
109
|
+
const ccpid = localStorage.getItem(label);
|
|
110
|
+
if (!ccpid)
|
|
111
|
+
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
112
|
+
this.send(ccpid);
|
|
113
|
+
localStorage.setItem(label, "");
|
|
114
|
+
}
|
|
40
115
|
|
|
41
|
-
|
|
116
|
+
// src/scrape.js
|
|
117
|
+
function scrape(element) {
|
|
118
|
+
let hasErrors = false;
|
|
119
|
+
let data;
|
|
120
|
+
const handleField = (field, fieldName) => {
|
|
121
|
+
let result = field;
|
|
122
|
+
if (typeof result === "function") {
|
|
123
|
+
try {
|
|
124
|
+
result = result(element);
|
|
125
|
+
} catch (error) {
|
|
126
|
+
if (this.config.optional.includes(fieldName)) return void 0;
|
|
127
|
+
this.log("error", error.message, {
|
|
128
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result
|
|
129
|
+
});
|
|
130
|
+
hasErrors = true;
|
|
42
131
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
return
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
132
|
+
}
|
|
133
|
+
if (typeof result === "string")
|
|
134
|
+
result = result.replace(/\s+/g, " ").trim();
|
|
135
|
+
if ((result == null || result === "") && !this.config.optional.includes(fieldName)) {
|
|
136
|
+
this.log("error", "Value is empty", {
|
|
137
|
+
[fieldName ? `scrape.${fieldName}` : "scrape"]: result
|
|
138
|
+
});
|
|
139
|
+
hasErrors = true;
|
|
140
|
+
}
|
|
141
|
+
return result;
|
|
142
|
+
};
|
|
143
|
+
if (this.config.type !== "scraper") {
|
|
144
|
+
data = handleField(this.config.scrape);
|
|
145
|
+
} else {
|
|
146
|
+
data = Object.keys(this.config.scrape).reduce(
|
|
147
|
+
(acc, fieldName) => ({
|
|
148
|
+
...acc,
|
|
149
|
+
[fieldName]: handleField(this.config.scrape[fieldName], fieldName)
|
|
150
|
+
}),
|
|
151
|
+
{}
|
|
152
|
+
);
|
|
60
153
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
.
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
);
|
|
154
|
+
const dataHash = JSON.stringify(data);
|
|
155
|
+
if (!hasErrors && this.previouslyScrapedHash !== dataHash) {
|
|
156
|
+
try {
|
|
157
|
+
this.config.before(data, (newData) => {
|
|
158
|
+
if (Array.isArray(newData)) newData.forEach((id) => this.send(id));
|
|
159
|
+
else this.send(newData);
|
|
160
|
+
});
|
|
161
|
+
} catch (error) {
|
|
162
|
+
this.log("error", error.message, {
|
|
163
|
+
before: this.config.before
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
this.previouslyScrapedHash = dataHash;
|
|
167
|
+
this.logs.length = 0;
|
|
76
168
|
}
|
|
169
|
+
}
|
|
77
170
|
|
|
78
|
-
|
|
79
|
-
|
|
171
|
+
// src/send.js
|
|
172
|
+
function send(data) {
|
|
173
|
+
let payload;
|
|
174
|
+
let url;
|
|
175
|
+
let method = "GET";
|
|
176
|
+
switch (this.config.type) {
|
|
177
|
+
case "scraper": {
|
|
178
|
+
const { sku } = data;
|
|
179
|
+
delete data.sku;
|
|
180
|
+
payload = {
|
|
181
|
+
"advertiser-id": this.config.advertiser,
|
|
182
|
+
sku,
|
|
183
|
+
fields: data
|
|
184
|
+
};
|
|
185
|
+
url = `https://d.lemonpi.io/scrapes${this.config.debug ? "?validate=true" : ""}`;
|
|
186
|
+
method = "POST";
|
|
187
|
+
break;
|
|
188
|
+
}
|
|
189
|
+
case "viewed":
|
|
190
|
+
case "basketed":
|
|
191
|
+
case "purchased":
|
|
192
|
+
payload = {
|
|
193
|
+
"event-type": `product-${this.config.type}`,
|
|
194
|
+
sku: data
|
|
195
|
+
};
|
|
196
|
+
url = `https://d.lemonpi.io/a/${this.config.advertiser}/product/event?e=${encodeURIComponent(JSON.stringify(payload))}`;
|
|
197
|
+
break;
|
|
198
|
+
case "conversion":
|
|
199
|
+
payload = {
|
|
200
|
+
version: 1,
|
|
201
|
+
type: "conversion",
|
|
202
|
+
name: this.config.label,
|
|
203
|
+
"conversion-attribution-id": data,
|
|
204
|
+
"advertiser-id": this.config.advertiser
|
|
205
|
+
};
|
|
206
|
+
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
207
|
+
JSON.stringify(payload)
|
|
208
|
+
)}`;
|
|
209
|
+
break;
|
|
80
210
|
}
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
const args = [
|
|
86
|
-
`%cโธฌ create%c ${this.config.icons[this.config.type]} ${
|
|
87
|
-
this.config.type
|
|
88
|
-
} %c${message}`,
|
|
89
|
-
"background:black;color:white;border-radius:3px;padding:3px 6px",
|
|
90
|
-
"font-weight:bold",
|
|
91
|
-
`color:${this.config.colors[level]}`,
|
|
92
|
-
];
|
|
93
|
-
|
|
94
|
-
if (data) args.push(data);
|
|
95
|
-
console.info(...args);
|
|
96
|
-
this.logs.push(message);
|
|
211
|
+
if (["viewed", "basketed", "purchased"].includes(this.config.type) && !this.config.debug) {
|
|
212
|
+
new Image().src = url;
|
|
213
|
+
return;
|
|
97
214
|
}
|
|
215
|
+
fetch(
|
|
216
|
+
url,
|
|
217
|
+
method === "POST" ? {
|
|
218
|
+
method: "POST",
|
|
219
|
+
headers: { "Content-Type": "application/json" },
|
|
220
|
+
body: JSON.stringify(payload)
|
|
221
|
+
} : null
|
|
222
|
+
).then(
|
|
223
|
+
(response) => response.json().then((result) => {
|
|
224
|
+
if (response.ok) {
|
|
225
|
+
this.log("warn", "Successful, with warnings. Details:", {
|
|
226
|
+
payload,
|
|
227
|
+
result
|
|
228
|
+
});
|
|
229
|
+
try {
|
|
230
|
+
this.config.after(data);
|
|
231
|
+
} catch (error) {
|
|
232
|
+
this.log("error", error.message, {
|
|
233
|
+
after: this.config.after
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
} else
|
|
237
|
+
this.log(
|
|
238
|
+
"error",
|
|
239
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
240
|
+
{ payload, result }
|
|
241
|
+
);
|
|
242
|
+
this.logs.length = 0;
|
|
243
|
+
}).catch(() => {
|
|
244
|
+
if (response.ok) {
|
|
245
|
+
this.log("success", "Successful!", { payload });
|
|
246
|
+
try {
|
|
247
|
+
this.config.after(data);
|
|
248
|
+
} catch (error) {
|
|
249
|
+
this.log("error", error.message, {
|
|
250
|
+
after: this.config.after
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
} else
|
|
254
|
+
this.log(
|
|
255
|
+
"error",
|
|
256
|
+
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
257
|
+
{ payload, response }
|
|
258
|
+
);
|
|
259
|
+
this.logs.length = 0;
|
|
260
|
+
})
|
|
261
|
+
).catch((error) => {
|
|
262
|
+
this.log("error", `Failed: ${error.message}`, { payload });
|
|
263
|
+
this.logs.length = 0;
|
|
264
|
+
});
|
|
265
|
+
}
|
|
98
266
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"
|
|
108
|
-
"
|
|
109
|
-
"
|
|
110
|
-
"
|
|
111
|
-
"
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
this.log("error", "Please use a string", {
|
|
124
|
-
label: this.config.label,
|
|
125
|
-
});
|
|
126
|
-
else if (!(this.config.url instanceof RegExp))
|
|
127
|
-
this.log("error", "Please use a regular expression", {
|
|
128
|
-
url: this.config.url,
|
|
129
|
-
});
|
|
130
|
-
else if (
|
|
131
|
-
!["attribution", "conversion"].includes(this.config.type) &&
|
|
132
|
-
!this.config.scrape
|
|
133
|
-
)
|
|
134
|
-
this.log("error", "Please provide something to scrape", {
|
|
135
|
-
scrape: this.config.scrape,
|
|
136
|
-
});
|
|
137
|
-
else return true;
|
|
267
|
+
// src/index.js
|
|
268
|
+
var ChoreographCreatePixel = class {
|
|
269
|
+
constructor(userConfig) {
|
|
270
|
+
this.previouslyScrapedHash = null;
|
|
271
|
+
this.logs = [];
|
|
272
|
+
this.config = {
|
|
273
|
+
colors: { error: "red", warn: "orange", success: "green" },
|
|
274
|
+
icons: {
|
|
275
|
+
scraper: "\u{1F4DA}",
|
|
276
|
+
viewed: "\u{1F440}",
|
|
277
|
+
basketed: "\u{1F6D2}",
|
|
278
|
+
purchased: "\u{1F9FE}",
|
|
279
|
+
attribution: "\u{1F516}",
|
|
280
|
+
conversion: "\u{1F4C8}"
|
|
281
|
+
},
|
|
282
|
+
debug: /(pixel|lemonpi)_debug/i.test(location.href),
|
|
283
|
+
before: (data, callback) => callback(data),
|
|
284
|
+
after: () => {
|
|
285
|
+
},
|
|
286
|
+
optional: [],
|
|
287
|
+
...userConfig
|
|
288
|
+
};
|
|
289
|
+
if (this.validateConfig()) this.cycle();
|
|
138
290
|
}
|
|
139
|
-
|
|
140
291
|
cycle() {
|
|
141
292
|
if (!this.config.url.test(location.href))
|
|
142
293
|
this.log("warn", `URL pattern does not match "${location.href}"`, {
|
|
143
|
-
url: this.config.url
|
|
294
|
+
url: this.config.url
|
|
144
295
|
});
|
|
145
|
-
else if (
|
|
146
|
-
this.config.type === "scraper" &&
|
|
147
|
-
document.querySelector('html[class*="translated-"]')
|
|
148
|
-
)
|
|
296
|
+
else if (this.config.type === "scraper" && document.querySelector('html[class*="translated-"]'))
|
|
149
297
|
this.log(
|
|
150
298
|
"warn",
|
|
151
299
|
"This page has been translated by the browser, and won't be scraped"
|
|
152
300
|
);
|
|
153
301
|
else if (this.config.trigger) {
|
|
154
|
-
// TO-DO: replace this.config.type with a unique pixel instance ID
|
|
155
302
|
const elementAttribute = `create-${this.config.type}-${this.config.trigger.event}`;
|
|
156
|
-
|
|
157
303
|
try {
|
|
158
|
-
let elements =
|
|
159
|
-
typeof this.config.trigger.elements === "string"
|
|
160
|
-
? document.querySelectorAll(this.config.trigger.elements)
|
|
161
|
-
: this.config.trigger.elements();
|
|
162
|
-
|
|
304
|
+
let elements = typeof this.config.trigger.elements === "string" ? document.querySelectorAll(this.config.trigger.elements) : this.config.trigger.elements();
|
|
163
305
|
if (!elements.forEach) elements = [elements];
|
|
164
|
-
|
|
165
306
|
elements.forEach((element) => {
|
|
166
307
|
if (!element.hasAttribute(elementAttribute)) {
|
|
167
|
-
element.addEventListener(
|
|
168
|
-
this.config.
|
|
169
|
-
|
|
170
|
-
: this.scrape(element)
|
|
308
|
+
element.addEventListener(
|
|
309
|
+
this.config.trigger.event,
|
|
310
|
+
() => this.config.type === "conversion" ? this.convert() : this.scrape(element)
|
|
171
311
|
);
|
|
172
|
-
|
|
173
312
|
element.setAttribute(elementAttribute, "");
|
|
174
313
|
}
|
|
175
314
|
});
|
|
176
315
|
} catch (error) {
|
|
177
316
|
this.log("error", error.message, {
|
|
178
|
-
"trigger.elements": this.config.trigger.elements
|
|
317
|
+
"trigger.elements": this.config.trigger.elements
|
|
179
318
|
});
|
|
180
319
|
}
|
|
181
320
|
} else {
|
|
@@ -183,241 +322,28 @@ class ChoreographCreatePixel {
|
|
|
183
322
|
case "attribution":
|
|
184
323
|
this.attribute();
|
|
185
324
|
break;
|
|
186
|
-
|
|
187
325
|
case "conversion":
|
|
188
326
|
this.convert();
|
|
189
327
|
break;
|
|
190
|
-
|
|
191
328
|
default:
|
|
192
329
|
this.scrape();
|
|
193
330
|
break;
|
|
194
331
|
}
|
|
195
332
|
}
|
|
196
|
-
|
|
197
|
-
// TO-DO: Move this to each method's end? Pageview conversions are currently recursive
|
|
198
333
|
setTimeout(() => this.cycle(), 750);
|
|
199
334
|
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
convert() {
|
|
218
|
-
const label = `choreograph-${this.config.label}`;
|
|
219
|
-
const ccpid = localStorage.getItem(label);
|
|
220
|
-
|
|
221
|
-
if (!ccpid)
|
|
222
|
-
return this.log("warn", `"${this.config.label}" attribution not present`);
|
|
223
|
-
|
|
224
|
-
this.send(ccpid);
|
|
225
|
-
localStorage.removeItem(label);
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
scrape(element) {
|
|
229
|
-
let hasErrors = false;
|
|
230
|
-
let data;
|
|
231
|
-
|
|
232
|
-
const handleField = (field, fieldName) => {
|
|
233
|
-
let result = field;
|
|
234
|
-
|
|
235
|
-
if (typeof result === "function") {
|
|
236
|
-
try {
|
|
237
|
-
result = result(element);
|
|
238
|
-
} catch (error) {
|
|
239
|
-
if (this.config.optional.includes(fieldName)) return undefined;
|
|
240
|
-
|
|
241
|
-
this.log("error", error.message, {
|
|
242
|
-
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
243
|
-
});
|
|
244
|
-
|
|
245
|
-
hasErrors = true;
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
if (typeof result === "string")
|
|
250
|
-
result = result.replace(/\s+/g, " ").trim();
|
|
251
|
-
|
|
252
|
-
if (
|
|
253
|
-
(result == null || result === "") &&
|
|
254
|
-
!this.config.optional.includes(fieldName)
|
|
255
|
-
) {
|
|
256
|
-
this.log("error", "Value is empty", {
|
|
257
|
-
[fieldName ? `scrape.${fieldName}` : "scrape"]: result,
|
|
258
|
-
});
|
|
259
|
-
|
|
260
|
-
hasErrors = true;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
return result;
|
|
264
|
-
};
|
|
265
|
-
|
|
266
|
-
if (this.config.type !== "scraper") {
|
|
267
|
-
data = handleField(this.config.scrape);
|
|
268
|
-
} else {
|
|
269
|
-
data = Object.keys(this.config.scrape).reduce(
|
|
270
|
-
(acc, fieldName) => ({
|
|
271
|
-
...acc,
|
|
272
|
-
[fieldName]: handleField(this.config.scrape[fieldName], fieldName),
|
|
273
|
-
}),
|
|
274
|
-
{}
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
const dataHash = JSON.stringify(data);
|
|
279
|
-
|
|
280
|
-
if (!hasErrors && this.previouslyScrapedHash !== dataHash) {
|
|
281
|
-
try {
|
|
282
|
-
this.config.before(data, (newData) => {
|
|
283
|
-
if (Array.isArray(newData)) newData.forEach((id) => this.send(id));
|
|
284
|
-
else this.send(newData);
|
|
285
|
-
});
|
|
286
|
-
} catch (error) {
|
|
287
|
-
this.log("error", error.message, {
|
|
288
|
-
before: this.config.before,
|
|
289
|
-
});
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
this.previouslyScrapedHash = dataHash;
|
|
293
|
-
this.logs.length = 0;
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
send(data) {
|
|
298
|
-
let payload;
|
|
299
|
-
let url;
|
|
300
|
-
let method = "GET";
|
|
301
|
-
|
|
302
|
-
switch (this.config.type) {
|
|
303
|
-
case "scraper": {
|
|
304
|
-
const { sku } = data;
|
|
305
|
-
delete data.sku;
|
|
306
|
-
|
|
307
|
-
payload = {
|
|
308
|
-
"advertiser-id": this.config.advertiser,
|
|
309
|
-
sku,
|
|
310
|
-
fields: data,
|
|
311
|
-
};
|
|
312
|
-
|
|
313
|
-
url = `https://d.lemonpi.io/scrapes${
|
|
314
|
-
this.config.debug ? "?validate=true" : ""
|
|
315
|
-
}`;
|
|
316
|
-
|
|
317
|
-
method = "POST";
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
case "viewed":
|
|
322
|
-
case "basketed":
|
|
323
|
-
case "purchased":
|
|
324
|
-
payload = {
|
|
325
|
-
"event-type": `product-${this.config.type}`,
|
|
326
|
-
sku: data,
|
|
327
|
-
};
|
|
328
|
-
|
|
329
|
-
url = `https://d.lemonpi.io/a/${
|
|
330
|
-
this.config.advertiser
|
|
331
|
-
}/product/event?e=${encodeURIComponent(JSON.stringify(payload))}`;
|
|
332
|
-
|
|
333
|
-
break;
|
|
334
|
-
|
|
335
|
-
case "conversion":
|
|
336
|
-
payload = {
|
|
337
|
-
version: 1,
|
|
338
|
-
type: "conversion",
|
|
339
|
-
name: this.config.label,
|
|
340
|
-
"conversion-attribution-id": data,
|
|
341
|
-
"advertiser-id": this.config.advertiser,
|
|
342
|
-
};
|
|
343
|
-
|
|
344
|
-
url = `https://content.lemonpi.io/track/event?e=${encodeURIComponent(
|
|
345
|
-
JSON.stringify(payload)
|
|
346
|
-
)}`;
|
|
347
|
-
|
|
348
|
-
break;
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (
|
|
352
|
-
["viewed", "basketed", "purchased"].includes(this.config.type) &&
|
|
353
|
-
!this.config.debug
|
|
354
|
-
) {
|
|
355
|
-
new Image().src = url;
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
fetch(
|
|
360
|
-
url,
|
|
361
|
-
method === "POST"
|
|
362
|
-
? {
|
|
363
|
-
method: "POST",
|
|
364
|
-
headers: { "Content-Type": "application/json" },
|
|
365
|
-
body: JSON.stringify(payload),
|
|
366
|
-
}
|
|
367
|
-
: null
|
|
368
|
-
)
|
|
369
|
-
.then((response) =>
|
|
370
|
-
response
|
|
371
|
-
.json()
|
|
372
|
-
.then((result) => {
|
|
373
|
-
if (response.ok) {
|
|
374
|
-
this.log("warn", "Successful, with warnings. Details:", {
|
|
375
|
-
payload,
|
|
376
|
-
result,
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
try {
|
|
380
|
-
this.config.after(data);
|
|
381
|
-
} catch (error) {
|
|
382
|
-
this.log("error", error.message, {
|
|
383
|
-
after: this.config.after,
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
} else
|
|
387
|
-
this.log(
|
|
388
|
-
"error",
|
|
389
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
390
|
-
{ payload, result }
|
|
391
|
-
);
|
|
392
|
-
|
|
393
|
-
this.logs.length = 0;
|
|
394
|
-
})
|
|
395
|
-
.catch(() => {
|
|
396
|
-
if (response.ok) {
|
|
397
|
-
this.log("success", "Successful!", { payload });
|
|
398
|
-
|
|
399
|
-
try {
|
|
400
|
-
this.config.after(data);
|
|
401
|
-
} catch (error) {
|
|
402
|
-
this.log("error", error.message, {
|
|
403
|
-
after: this.config.after,
|
|
404
|
-
});
|
|
405
|
-
}
|
|
406
|
-
} else
|
|
407
|
-
this.log(
|
|
408
|
-
"error",
|
|
409
|
-
`Failed: ${response.status} (${response.statusText}). Details:`,
|
|
410
|
-
{ payload, response }
|
|
411
|
-
);
|
|
412
|
-
|
|
413
|
-
this.logs.length = 0;
|
|
414
|
-
})
|
|
415
|
-
)
|
|
416
|
-
.catch((error) => {
|
|
417
|
-
this.log("error", `Failed: ${error.message}`, { payload });
|
|
418
|
-
this.logs.length = 0;
|
|
419
|
-
});
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
export { ChoreographCreatePixel as default };
|
|
335
|
+
};
|
|
336
|
+
ChoreographCreatePixel.getUrl = getUrl;
|
|
337
|
+
ChoreographCreatePixel.getAllPathSegments = getAllPathSegments;
|
|
338
|
+
ChoreographCreatePixel.getPathSegment = getPathSegment;
|
|
339
|
+
ChoreographCreatePixel.getAllQueryParameters = getAllQueryParameters;
|
|
340
|
+
ChoreographCreatePixel.getQueryParameter = getQueryParameter;
|
|
341
|
+
ChoreographCreatePixel.prototype.log = log;
|
|
342
|
+
ChoreographCreatePixel.prototype.validateConfig = validateConfig;
|
|
343
|
+
ChoreographCreatePixel.prototype.attribute = attribute;
|
|
344
|
+
ChoreographCreatePixel.prototype.convert = convert;
|
|
345
|
+
ChoreographCreatePixel.prototype.scrape = scrape;
|
|
346
|
+
ChoreographCreatePixel.prototype.send = send;
|
|
347
|
+
export {
|
|
348
|
+
ChoreographCreatePixel as default
|
|
349
|
+
};
|