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