@treasuredata/web-sdk 1.0.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +807 -0
- package/dist/browser.d.ts +9 -0
- package/dist/checksums.txt +8 -0
- package/dist/core/config.d.ts +10 -0
- package/dist/core/config.template.d.ts +10 -0
- package/dist/core/configurator.d.ts +35 -0
- package/dist/core/sdk.d.ts +3 -0
- package/dist/index.d.ts +37 -0
- package/dist/init.d.ts +18 -0
- package/dist/loader.d.ts +59 -0
- package/dist/loader.js +1 -0
- package/dist/loader.min.js +1 -0
- package/dist/plugins/clicks.d.ts +21 -0
- package/dist/plugins/conversion-api.d.ts +23 -0
- package/dist/plugins/global-id.d.ts +17 -0
- package/dist/plugins/in-browser-message.d.ts +6 -0
- package/dist/plugins/page-personalize/bridge/constants.d.ts +9 -0
- package/dist/plugins/page-personalize/bridge/rpc.d.ts +15 -0
- package/dist/plugins/page-personalize/index.d.ts +34 -0
- package/dist/plugins/page-personalize/injection/inject.d.ts +17 -0
- package/dist/plugins/page-personalize/modes/preview.d.ts +3 -0
- package/dist/plugins/page-personalize/modes/spot-selection.d.ts +9 -0
- package/dist/plugins/page-personalize/offers.d.ts +72 -0
- package/dist/plugins/page-personalize/router.d.ts +17 -0
- package/dist/plugins/page-personalize/types.d.ts +27 -0
- package/dist/plugins/page-personalize/utils/selector-generator.d.ts +6 -0
- package/dist/plugins/personalization.d.ts +39 -0
- package/dist/plugins/record.d.ts +32 -0
- package/dist/plugins/server-cookie.d.ts +14 -0
- package/dist/plugins/session.d.ts +25 -0
- package/dist/plugins/track.d.ts +16 -0
- package/dist/plugins/utm.d.ts +16 -0
- package/dist/td-sdk.cjs +3263 -0
- package/dist/td-sdk.esm.js +3263 -0
- package/dist/td-sdk.esm.min.js +1 -0
- package/dist/td-sdk.js +3176 -0
- package/dist/td-sdk.min.cjs +1 -0
- package/dist/td-sdk.min.js +1 -0
- package/dist/treasure.d.ts +198 -0
- package/dist/types/index.d.ts +177 -0
- package/dist/utils/element.d.ts +20 -0
- package/dist/utils/lodash.d.ts +18 -0
- package/dist/utils/misc.d.ts +17 -0
- package/dist/utils/set-cookie.d.ts +14 -0
- package/dist/utils/uuid.d.ts +14 -0
- package/dist/utils/xhr.d.ts +58 -0
- package/dist/vendor/js-cookies.d.ts +19 -0
- package/package.json +90 -0
package/dist/td-sdk.js
ADDED
|
@@ -0,0 +1,3176 @@
|
|
|
1
|
+
var Treasure = function() {
|
|
2
|
+
"use strict";
|
|
3
|
+
function createSDK(config) {
|
|
4
|
+
if (!config || typeof config.writeKey !== "string" || !config.writeKey) {
|
|
5
|
+
throw new Error("TreasureSDK: writeKey is required");
|
|
6
|
+
}
|
|
7
|
+
if (!config.database) {
|
|
8
|
+
throw new Error("TreasureSDK: database is required");
|
|
9
|
+
}
|
|
10
|
+
const logger = {
|
|
11
|
+
debug: (...args) => {
|
|
12
|
+
if (config.development) console.debug("[TreasureSDK]", ...args);
|
|
13
|
+
},
|
|
14
|
+
warn: (...args) => console.warn("[TreasureSDK]", ...args),
|
|
15
|
+
error: (...args) => console.error("[TreasureSDK]", ...args)
|
|
16
|
+
};
|
|
17
|
+
const core = {
|
|
18
|
+
config: { ...config },
|
|
19
|
+
log: logger
|
|
20
|
+
};
|
|
21
|
+
const sdk = {
|
|
22
|
+
...core,
|
|
23
|
+
use(plugin) {
|
|
24
|
+
core.log.debug(`Loading plugin: ${plugin.name}`);
|
|
25
|
+
const methods = plugin.setup(core, sdk);
|
|
26
|
+
for (const key of Object.keys(methods)) {
|
|
27
|
+
if (key in sdk) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`TreasureSDK: plugin "${plugin.name}" conflicts on "${key}"`
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
Object.assign(sdk, methods);
|
|
34
|
+
return sdk;
|
|
35
|
+
},
|
|
36
|
+
getWriteKey() {
|
|
37
|
+
return core.config.writeKey;
|
|
38
|
+
},
|
|
39
|
+
setWriteKey(writeKey) {
|
|
40
|
+
if (!writeKey || typeof writeKey !== "string") {
|
|
41
|
+
throw new Error("TreasureSDK: writeKey must be a non-empty string");
|
|
42
|
+
}
|
|
43
|
+
core.config.writeKey = writeKey;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
return sdk;
|
|
47
|
+
}
|
|
48
|
+
function isObject$1(value) {
|
|
49
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50
|
+
}
|
|
51
|
+
function isString(value) {
|
|
52
|
+
return typeof value === "string";
|
|
53
|
+
}
|
|
54
|
+
function isArray(value) {
|
|
55
|
+
return Array.isArray(value);
|
|
56
|
+
}
|
|
57
|
+
function isEmpty(value) {
|
|
58
|
+
if (value == null) return true;
|
|
59
|
+
if (isArray(value) || isString(value)) return value.length === 0;
|
|
60
|
+
if (isObject$1(value)) return Object.keys(value).length === 0;
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function assign(target, ...sources) {
|
|
64
|
+
return Object.assign(target, ...sources);
|
|
65
|
+
}
|
|
66
|
+
function omit(obj, ...keysToOmit) {
|
|
67
|
+
const result = { ...obj };
|
|
68
|
+
keysToOmit.forEach((key) => delete result[key]);
|
|
69
|
+
return result;
|
|
70
|
+
}
|
|
71
|
+
function disposable(action) {
|
|
72
|
+
let disposed = false;
|
|
73
|
+
return function dispose() {
|
|
74
|
+
if (!disposed) {
|
|
75
|
+
disposed = true;
|
|
76
|
+
action();
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function invariant$1(condition, text) {
|
|
81
|
+
if (!condition) {
|
|
82
|
+
throw new Error(text);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
function isLocalStorageAccessible() {
|
|
86
|
+
const test = "__td__";
|
|
87
|
+
try {
|
|
88
|
+
localStorage.setItem(test, test);
|
|
89
|
+
localStorage.removeItem(test);
|
|
90
|
+
return true;
|
|
91
|
+
} catch {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const adlHeaders = {
|
|
96
|
+
"Content-Type": "application/vnd.treasuredata.v1+json",
|
|
97
|
+
Accept: "application/vnd.treasuredata.v1+json"
|
|
98
|
+
};
|
|
99
|
+
const globalIdAdlHeaders = {
|
|
100
|
+
"Content-Type": "application/vnd.treasuredata.v1.js+json",
|
|
101
|
+
Accept: "application/vnd.treasuredata.v1.js+json"
|
|
102
|
+
};
|
|
103
|
+
const CONFIG = {
|
|
104
|
+
VERSION: "1.0.0",
|
|
105
|
+
HOST: "us01.records.in.treasuredata.com",
|
|
106
|
+
DATABASE: "",
|
|
107
|
+
PATHNAME: "/"
|
|
108
|
+
};
|
|
109
|
+
function encode(val) {
|
|
110
|
+
try {
|
|
111
|
+
return encodeURIComponent(val);
|
|
112
|
+
} catch (e) {
|
|
113
|
+
console.error("error encode %o", e);
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
function decode(val) {
|
|
118
|
+
try {
|
|
119
|
+
return decodeURIComponent(val);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
console.error("error decode %o", err);
|
|
122
|
+
return null;
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
function handleSkey(sKey) {
|
|
126
|
+
const encoded = encode(sKey);
|
|
127
|
+
return encoded ? encoded.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&") : "";
|
|
128
|
+
}
|
|
129
|
+
const cookie = {
|
|
130
|
+
getItem(sKey) {
|
|
131
|
+
if (!sKey) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
const regex = new RegExp(
|
|
135
|
+
"(?:(?:^|.*;)\\s*" + handleSkey(sKey) + "\\s*\\=\\s*([^;]*).*$)|^.*$"
|
|
136
|
+
);
|
|
137
|
+
const match = document.cookie.replace(regex, "$1");
|
|
138
|
+
return decode(match) || null;
|
|
139
|
+
},
|
|
140
|
+
setItem(sKey, sValue, vEnd, sPath, sDomain, bSecure, sameSite) {
|
|
141
|
+
if (!sKey || /^(?:expires|max\-age|path|domain|secure)$/i.test(sKey)) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
let sExpires = "";
|
|
145
|
+
if (vEnd) {
|
|
146
|
+
if (typeof vEnd === "number") {
|
|
147
|
+
if (vEnd === Infinity) {
|
|
148
|
+
sExpires = "; expires=Fri, 31 Dec 9999 23:59:59 GMT";
|
|
149
|
+
} else {
|
|
150
|
+
sExpires = "; max-age=" + vEnd;
|
|
151
|
+
}
|
|
152
|
+
} else if (typeof vEnd === "string") {
|
|
153
|
+
sExpires = "; expires=" + vEnd;
|
|
154
|
+
} else if (vEnd instanceof Date) {
|
|
155
|
+
sExpires = "; expires=" + vEnd.toUTCString();
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
let secureAndSameSite = "";
|
|
159
|
+
if (sameSite && sameSite.toUpperCase() === "NONE") {
|
|
160
|
+
secureAndSameSite = "; Secure; SameSite=" + sameSite;
|
|
161
|
+
} else {
|
|
162
|
+
if (bSecure) {
|
|
163
|
+
secureAndSameSite += "; Secure";
|
|
164
|
+
}
|
|
165
|
+
if (sameSite) {
|
|
166
|
+
secureAndSameSite += "; SameSite=" + sameSite;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const encodedKey = encode(sKey);
|
|
170
|
+
const encodedValue = encode(sValue);
|
|
171
|
+
if (!encodedKey || !encodedValue) {
|
|
172
|
+
return false;
|
|
173
|
+
}
|
|
174
|
+
document.cookie = [
|
|
175
|
+
encodedKey,
|
|
176
|
+
"=",
|
|
177
|
+
encodedValue,
|
|
178
|
+
sExpires,
|
|
179
|
+
sDomain ? "; domain=" + sDomain : "",
|
|
180
|
+
sPath ? "; path=" + sPath : "",
|
|
181
|
+
secureAndSameSite
|
|
182
|
+
].join("");
|
|
183
|
+
return true;
|
|
184
|
+
},
|
|
185
|
+
removeItem(sKey, sPath, sDomain) {
|
|
186
|
+
if (!this.hasItem(sKey)) {
|
|
187
|
+
return false;
|
|
188
|
+
}
|
|
189
|
+
const encodedKey = encode(sKey);
|
|
190
|
+
if (!encodedKey) {
|
|
191
|
+
return false;
|
|
192
|
+
}
|
|
193
|
+
document.cookie = [
|
|
194
|
+
encodedKey,
|
|
195
|
+
"=; expires=Thu, 01 Jan 1970 00:00:00 GMT",
|
|
196
|
+
sDomain ? "; domain=" + sDomain : "",
|
|
197
|
+
sPath ? "; path=" + sPath : ""
|
|
198
|
+
].join("");
|
|
199
|
+
return true;
|
|
200
|
+
},
|
|
201
|
+
hasItem(sKey) {
|
|
202
|
+
if (!sKey) {
|
|
203
|
+
return false;
|
|
204
|
+
}
|
|
205
|
+
const encodedKey = encode(sKey);
|
|
206
|
+
if (!encodedKey) {
|
|
207
|
+
return false;
|
|
208
|
+
}
|
|
209
|
+
return new RegExp(
|
|
210
|
+
"(?:^|;\\s*)" + encodedKey.replace(/[\\^$.*+?()[\]{}|]/g, "\\$&") + "\\s*\\="
|
|
211
|
+
).test(document.cookie);
|
|
212
|
+
},
|
|
213
|
+
keys() {
|
|
214
|
+
const aKeys = document.cookie.replace(/((?:^|\s*;)[^=]+)(?=;|$)|^\s*|\s*(?:=[^;]*)?(?:\1|$)/g, "").split(/\s*(?:=[^;]*)?;\s*/);
|
|
215
|
+
return aKeys.map((key) => decode(key)).filter((key) => key !== null);
|
|
216
|
+
}
|
|
217
|
+
};
|
|
218
|
+
function validateOptions(options) {
|
|
219
|
+
invariant$1(
|
|
220
|
+
isObject$1(options),
|
|
221
|
+
"Check out our JavaScript SDK Usage Guide: https://github.com/treasure-data/td-js-sdk#api"
|
|
222
|
+
);
|
|
223
|
+
invariant$1(isString(options.writeKey), "Must provide a writeKey");
|
|
224
|
+
invariant$1(isString(options.database), "Must provide a database");
|
|
225
|
+
invariant$1(
|
|
226
|
+
options.database && /^[a-z0-9_]{3,255}$/.test(options.database),
|
|
227
|
+
"Database must be between 3 and 255 characters and must consist only of lower case letters, numbers, and _"
|
|
228
|
+
);
|
|
229
|
+
}
|
|
230
|
+
function defaultSSCCookieDomain() {
|
|
231
|
+
if (typeof document === "undefined") {
|
|
232
|
+
return "localhost";
|
|
233
|
+
}
|
|
234
|
+
const domainChunks = document.location.hostname.split(".");
|
|
235
|
+
for (let i = domainChunks.length - 2; i >= 1; i--) {
|
|
236
|
+
const domain = domainChunks.slice(i).join(".");
|
|
237
|
+
const name = "_td_domain_" + domain;
|
|
238
|
+
cookie.setItem(name, domain, 3600, "/", domain);
|
|
239
|
+
if (cookie.getItem(name) === domain) {
|
|
240
|
+
return domain;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return document.location.hostname;
|
|
244
|
+
}
|
|
245
|
+
const DEFAULT_CONFIG = {
|
|
246
|
+
database: CONFIG.DATABASE,
|
|
247
|
+
development: false,
|
|
248
|
+
globalIdCookie: "_td_global",
|
|
249
|
+
host: CONFIG.HOST,
|
|
250
|
+
logging: true,
|
|
251
|
+
pathname: CONFIG.PATHNAME,
|
|
252
|
+
requestType: "fetch",
|
|
253
|
+
jsonpTimeout: 1e4,
|
|
254
|
+
startInSignedMode: false,
|
|
255
|
+
useServerSideCookie: false,
|
|
256
|
+
sscDomain: defaultSSCCookieDomain,
|
|
257
|
+
sscServer: function(cookieDomain) {
|
|
258
|
+
return ["ssc", cookieDomain].join(".");
|
|
259
|
+
},
|
|
260
|
+
storeConsentByLocalStorage: false
|
|
261
|
+
};
|
|
262
|
+
function configure(options) {
|
|
263
|
+
const client = assign(
|
|
264
|
+
{},
|
|
265
|
+
{
|
|
266
|
+
globals: {}
|
|
267
|
+
},
|
|
268
|
+
DEFAULT_CONFIG,
|
|
269
|
+
options,
|
|
270
|
+
{
|
|
271
|
+
requestType: "fetch"
|
|
272
|
+
}
|
|
273
|
+
);
|
|
274
|
+
validateOptions(client);
|
|
275
|
+
if (!client.endpoint) {
|
|
276
|
+
client.endpoint = "https://" + client.host + client.pathname;
|
|
277
|
+
}
|
|
278
|
+
if (!client.storage) {
|
|
279
|
+
client.storage = {
|
|
280
|
+
name: "_td",
|
|
281
|
+
domain: typeof window !== "undefined" && typeof document !== "undefined" ? document.location.hostname : "localhost",
|
|
282
|
+
expires: 63072e3,
|
|
283
|
+
// 2 years in seconds
|
|
284
|
+
path: "/"
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
return client;
|
|
288
|
+
}
|
|
289
|
+
function findDomains(domain) {
|
|
290
|
+
const domainChunks = domain.split(".");
|
|
291
|
+
const domains = [];
|
|
292
|
+
for (let i = domainChunks.length - 1; i >= 0; i--) {
|
|
293
|
+
domains.push(domainChunks.slice(i).join("."));
|
|
294
|
+
}
|
|
295
|
+
return domains;
|
|
296
|
+
}
|
|
297
|
+
function setCookie(storage, name, value) {
|
|
298
|
+
const clone = { ...storage };
|
|
299
|
+
const is = {
|
|
300
|
+
ip: storage.domain.match(/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/),
|
|
301
|
+
local: storage.domain === "localhost",
|
|
302
|
+
custom: storage.customDomain
|
|
303
|
+
};
|
|
304
|
+
const expires = /* @__PURE__ */ new Date();
|
|
305
|
+
expires.setSeconds(expires.getSeconds() + clone.expires);
|
|
306
|
+
if (is.local) {
|
|
307
|
+
if (!value) {
|
|
308
|
+
cookie.removeItem(name, clone.path, clone.domain);
|
|
309
|
+
} else {
|
|
310
|
+
cookie.setItem(name, value, expires, clone.path);
|
|
311
|
+
}
|
|
312
|
+
} else if (is.ip || is.custom) {
|
|
313
|
+
if (!value) {
|
|
314
|
+
cookie.removeItem(name, clone.path, clone.domain);
|
|
315
|
+
} else {
|
|
316
|
+
cookie.setItem(
|
|
317
|
+
name,
|
|
318
|
+
value,
|
|
319
|
+
expires,
|
|
320
|
+
clone.path,
|
|
321
|
+
clone.domain,
|
|
322
|
+
true,
|
|
323
|
+
"None"
|
|
324
|
+
);
|
|
325
|
+
}
|
|
326
|
+
} else {
|
|
327
|
+
const domains = findDomains(storage.domain);
|
|
328
|
+
const ll = domains.length;
|
|
329
|
+
let i = 0;
|
|
330
|
+
if (!value) {
|
|
331
|
+
for (; i < ll; i++) {
|
|
332
|
+
cookie.removeItem(name, storage.path, domains[i]);
|
|
333
|
+
}
|
|
334
|
+
} else {
|
|
335
|
+
if (cookie.getItem(name) === value) return;
|
|
336
|
+
for (; i < ll; i++) {
|
|
337
|
+
clone.domain = domains[i];
|
|
338
|
+
cookie.setItem(
|
|
339
|
+
name,
|
|
340
|
+
value,
|
|
341
|
+
expires,
|
|
342
|
+
clone.path,
|
|
343
|
+
clone.domain,
|
|
344
|
+
true,
|
|
345
|
+
"None"
|
|
346
|
+
);
|
|
347
|
+
if (cookie.getItem(name) === value) {
|
|
348
|
+
storage.domain = clone.domain;
|
|
349
|
+
break;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
function generateUUID$1() {
|
|
356
|
+
if (typeof crypto !== "undefined" && crypto.randomUUID) {
|
|
357
|
+
return crypto.randomUUID();
|
|
358
|
+
}
|
|
359
|
+
if (typeof crypto !== "undefined" && crypto.getRandomValues) {
|
|
360
|
+
const bytes = new Uint8Array(16);
|
|
361
|
+
crypto.getRandomValues(bytes);
|
|
362
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
363
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
364
|
+
const hex = Array.from(bytes, (b) => b.toString(16).padStart(2, "0")).join("");
|
|
365
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
366
|
+
}
|
|
367
|
+
throw new Error(
|
|
368
|
+
"Secure random number generation is not available in this environment"
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
const FETCH_CREDENTIALS = {
|
|
372
|
+
"same-origin": "same-origin",
|
|
373
|
+
include: "include",
|
|
374
|
+
omit: "omit"
|
|
375
|
+
};
|
|
376
|
+
function toJSON(text) {
|
|
377
|
+
let result;
|
|
378
|
+
try {
|
|
379
|
+
result = JSON.parse(text);
|
|
380
|
+
} catch {
|
|
381
|
+
result = {};
|
|
382
|
+
}
|
|
383
|
+
return result;
|
|
384
|
+
}
|
|
385
|
+
function getCredentials(options = {}) {
|
|
386
|
+
return FETCH_CREDENTIALS[options.credentials || "include"] || "include";
|
|
387
|
+
}
|
|
388
|
+
function post(url, body, options = {}) {
|
|
389
|
+
const headers = options.headers || {};
|
|
390
|
+
const credentials = getCredentials(options);
|
|
391
|
+
const fetchOptions = {
|
|
392
|
+
method: "POST",
|
|
393
|
+
headers,
|
|
394
|
+
keepalive: true,
|
|
395
|
+
body: JSON.stringify(body)
|
|
396
|
+
};
|
|
397
|
+
{
|
|
398
|
+
fetchOptions.credentials = credentials;
|
|
399
|
+
}
|
|
400
|
+
if (options.signal) {
|
|
401
|
+
fetchOptions.signal = options.signal;
|
|
402
|
+
}
|
|
403
|
+
return fetch(url, fetchOptions).then(function(response) {
|
|
404
|
+
if (!response.ok) {
|
|
405
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
406
|
+
}
|
|
407
|
+
return response.text();
|
|
408
|
+
}).then(function(text) {
|
|
409
|
+
return toJSON(text);
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
function get(url, options = {}) {
|
|
413
|
+
const headers = options.headers || {};
|
|
414
|
+
const credentials = getCredentials(options);
|
|
415
|
+
const fetchOptions = {
|
|
416
|
+
method: "GET",
|
|
417
|
+
headers
|
|
418
|
+
};
|
|
419
|
+
{
|
|
420
|
+
fetchOptions.credentials = credentials;
|
|
421
|
+
}
|
|
422
|
+
if (options.signal) {
|
|
423
|
+
fetchOptions.signal = options.signal;
|
|
424
|
+
}
|
|
425
|
+
return fetch(url, fetchOptions).then(function(response) {
|
|
426
|
+
if (!response.ok) {
|
|
427
|
+
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
428
|
+
}
|
|
429
|
+
return response.text();
|
|
430
|
+
}).then(function(text) {
|
|
431
|
+
return toJSON(text);
|
|
432
|
+
});
|
|
433
|
+
}
|
|
434
|
+
function withTimeout(promiseFactory, milliseconds, timeoutMessage) {
|
|
435
|
+
const controller = new AbortController();
|
|
436
|
+
let timeoutId;
|
|
437
|
+
const timeoutPromise2 = new Promise((_, reject) => {
|
|
438
|
+
timeoutId = setTimeout(() => {
|
|
439
|
+
controller.abort();
|
|
440
|
+
reject(new Error(timeoutMessage || "Operation Timeout"));
|
|
441
|
+
}, milliseconds);
|
|
442
|
+
});
|
|
443
|
+
const promise = promiseFactory(controller.signal).finally(() => {
|
|
444
|
+
clearTimeout(timeoutId);
|
|
445
|
+
});
|
|
446
|
+
return Promise.race([promise, timeoutPromise2]).catch((error) => {
|
|
447
|
+
clearTimeout(timeoutId);
|
|
448
|
+
if (error.name === "AbortError") {
|
|
449
|
+
throw new Error(timeoutMessage || "Operation Timeout");
|
|
450
|
+
}
|
|
451
|
+
throw error;
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
function postWithTimeout(url, body, milliseconds, options = {}) {
|
|
455
|
+
return withTimeout(
|
|
456
|
+
(signal) => post(url, body, { ...options, signal }),
|
|
457
|
+
milliseconds,
|
|
458
|
+
"Request Timeout"
|
|
459
|
+
);
|
|
460
|
+
}
|
|
461
|
+
function getWithTimeout(url, milliseconds, options = {}) {
|
|
462
|
+
return withTimeout(
|
|
463
|
+
(signal) => get(url, { ...options, signal }),
|
|
464
|
+
milliseconds,
|
|
465
|
+
"Request Timeout"
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
function timeoutPromise(promiseFactory, milliseconds, timeoutMessage) {
|
|
469
|
+
return withTimeout((_signal) => promiseFactory(), milliseconds, timeoutMessage);
|
|
470
|
+
}
|
|
471
|
+
const api = {
|
|
472
|
+
post,
|
|
473
|
+
get,
|
|
474
|
+
postWithTimeout,
|
|
475
|
+
getWithTimeout,
|
|
476
|
+
withTimeout,
|
|
477
|
+
timeoutPromise
|
|
478
|
+
};
|
|
479
|
+
const SERVER_COOKIE_NAME = "_td_ssc_id";
|
|
480
|
+
const COOKIE_NAME = SERVER_COOKIE_NAME;
|
|
481
|
+
function serverCookie() {
|
|
482
|
+
return {
|
|
483
|
+
name: "serverCookie",
|
|
484
|
+
setup(core, sdk) {
|
|
485
|
+
const config = core.config;
|
|
486
|
+
let serverCookieDomain;
|
|
487
|
+
let serverCookieDomainHost;
|
|
488
|
+
const noop = () => {
|
|
489
|
+
};
|
|
490
|
+
function initializeServerCookieConfig() {
|
|
491
|
+
if (!serverCookieDomainHost) {
|
|
492
|
+
if (typeof config.sscDomain === "function") {
|
|
493
|
+
serverCookieDomain = config.sscDomain();
|
|
494
|
+
} else {
|
|
495
|
+
serverCookieDomain = config.sscDomain || (typeof window !== "undefined" ? window.location.hostname : "localhost");
|
|
496
|
+
}
|
|
497
|
+
if (typeof config.sscServer === "function") {
|
|
498
|
+
serverCookieDomainHost = config.sscServer(serverCookieDomain);
|
|
499
|
+
} else {
|
|
500
|
+
serverCookieDomainHost = config.sscServer || `ssc.${serverCookieDomain}`;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function fetchServerCookie(success, error, forceFetch = false) {
|
|
505
|
+
const successCallback = success || noop;
|
|
506
|
+
const errorCallback = error || noop;
|
|
507
|
+
if (typeof sdk.inSignedMode === "function" && !sdk.inSignedMode()) {
|
|
508
|
+
return errorCallback("not in signed in mode");
|
|
509
|
+
}
|
|
510
|
+
if (!config.useServerSideCookie) {
|
|
511
|
+
return errorCallback("server side cookie not enabled");
|
|
512
|
+
}
|
|
513
|
+
initializeServerCookieConfig();
|
|
514
|
+
if (!serverCookieDomain || !serverCookieDomainHost) {
|
|
515
|
+
return errorCallback(
|
|
516
|
+
"server cookie configuration not properly initialized"
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
const url = `https://${serverCookieDomainHost}/get_cookie_id?cookie_domain=${encodeURIComponent(serverCookieDomain)}&r=${Date.now()}`;
|
|
520
|
+
const cachedSSCId = cookie.getItem(COOKIE_NAME);
|
|
521
|
+
if (cachedSSCId && !forceFetch) {
|
|
522
|
+
setTimeout(() => {
|
|
523
|
+
successCallback(cachedSSCId);
|
|
524
|
+
}, 0);
|
|
525
|
+
return;
|
|
526
|
+
}
|
|
527
|
+
api.getWithTimeout(url, 1e4).then((response) => {
|
|
528
|
+
successCallback(response.td_ssc_id);
|
|
529
|
+
}).catch((err) => {
|
|
530
|
+
errorCallback(err);
|
|
531
|
+
});
|
|
532
|
+
}
|
|
533
|
+
return {
|
|
534
|
+
fetchServerCookie
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
const BLOCKEVENTSCOOKIE = "__td_blockEvents";
|
|
540
|
+
const SIGNEDMODECOOKIE = "__td_signed";
|
|
541
|
+
function configureStorage(storage) {
|
|
542
|
+
if (storage === "none") return null;
|
|
543
|
+
const s = typeof storage === "object" && storage !== null ? storage : {};
|
|
544
|
+
return {
|
|
545
|
+
name: s.name || "_td",
|
|
546
|
+
expires: s.expires ?? 63072e3,
|
|
547
|
+
domain: s.domain || document.location.hostname,
|
|
548
|
+
customDomain: !!s.domain,
|
|
549
|
+
path: s.path || "/"
|
|
550
|
+
};
|
|
551
|
+
}
|
|
552
|
+
function setStorageCookie(storage, name, value) {
|
|
553
|
+
try {
|
|
554
|
+
setCookie(storage, name, value || "");
|
|
555
|
+
} catch {
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
function session() {
|
|
559
|
+
return {
|
|
560
|
+
name: "session",
|
|
561
|
+
setup(core, sdk) {
|
|
562
|
+
const config = core.config;
|
|
563
|
+
const startInSignedMode = config.startInSignedMode ?? false;
|
|
564
|
+
const storeConsentByLocalStorage = config.storeConsentByLocalStorage ?? false;
|
|
565
|
+
const globals = {};
|
|
566
|
+
function set(table, property, value) {
|
|
567
|
+
let tableName;
|
|
568
|
+
let prop = property;
|
|
569
|
+
if (typeof table === "object" && table !== null) {
|
|
570
|
+
prop = table;
|
|
571
|
+
tableName = "$global";
|
|
572
|
+
} else {
|
|
573
|
+
tableName = table;
|
|
574
|
+
}
|
|
575
|
+
const bucket = globals[tableName] || {};
|
|
576
|
+
globals[tableName] = bucket;
|
|
577
|
+
if (typeof prop === "object" && prop !== null) {
|
|
578
|
+
Object.assign(bucket, prop);
|
|
579
|
+
} else if (typeof prop === "string" && value !== void 0) {
|
|
580
|
+
bucket[prop] = value;
|
|
581
|
+
}
|
|
582
|
+
}
|
|
583
|
+
function get2(table, key) {
|
|
584
|
+
const t = table || "$global";
|
|
585
|
+
globals[t] = globals[t] || {};
|
|
586
|
+
return key ? globals[t]?.[key] ?? null : globals[t];
|
|
587
|
+
}
|
|
588
|
+
const storage = configureStorage(config.storage);
|
|
589
|
+
let clientId;
|
|
590
|
+
if (config.clientId != null) {
|
|
591
|
+
clientId = typeof config.clientId === "number" ? config.clientId.toString() : config.clientId;
|
|
592
|
+
}
|
|
593
|
+
if (!clientId || typeof clientId !== "string") {
|
|
594
|
+
if (storage?.name && typeof document !== "undefined") {
|
|
595
|
+
clientId = cookie.getItem(storage.name) ?? void 0;
|
|
596
|
+
}
|
|
597
|
+
if (!clientId || clientId === "undefined") {
|
|
598
|
+
clientId = generateUUID$1();
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
let uuid = clientId.replace(/\0/g, "");
|
|
602
|
+
function getUUID() {
|
|
603
|
+
return uuid;
|
|
604
|
+
}
|
|
605
|
+
function persistUUID(storageOption, id) {
|
|
606
|
+
if (cookie.getItem(storageOption.name) === id) return;
|
|
607
|
+
try {
|
|
608
|
+
setCookie(storageOption, storageOption.name, id);
|
|
609
|
+
} catch {
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
function resetUUID(suggestedStorage, suggestedClientId) {
|
|
613
|
+
uuid = (suggestedClientId || generateUUID$1()).replace(/\0/g, "");
|
|
614
|
+
const storageToUse = suggestedStorage || config.storage;
|
|
615
|
+
if (storageToUse && typeof storageToUse === "object") {
|
|
616
|
+
const storageOption = configureStorage(storageToUse);
|
|
617
|
+
if (storageOption?.expires && inSignedMode()) {
|
|
618
|
+
persistUUID(storageOption, uuid);
|
|
619
|
+
}
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
if (storage?.expires && inSignedMode()) {
|
|
623
|
+
persistUUID(storage, uuid);
|
|
624
|
+
}
|
|
625
|
+
function inSignedMode() {
|
|
626
|
+
if (storeConsentByLocalStorage) {
|
|
627
|
+
if (!isLocalStorageAccessible()) return startInSignedMode;
|
|
628
|
+
const val2 = localStorage.getItem(SIGNEDMODECOOKIE);
|
|
629
|
+
return val2 !== "false" && (val2 === "true" || startInSignedMode);
|
|
630
|
+
}
|
|
631
|
+
if (typeof document === "undefined") return startInSignedMode;
|
|
632
|
+
const val = cookie.getItem(SIGNEDMODECOOKIE);
|
|
633
|
+
return val !== "false" && (val === "true" || startInSignedMode);
|
|
634
|
+
}
|
|
635
|
+
function setSignedMode() {
|
|
636
|
+
if (storeConsentByLocalStorage) {
|
|
637
|
+
if (isLocalStorageAccessible()) {
|
|
638
|
+
localStorage.setItem(SIGNEDMODECOOKIE, "true");
|
|
639
|
+
}
|
|
640
|
+
} else if (config.storage && typeof config.storage === "object") {
|
|
641
|
+
setStorageCookie(config.storage, SIGNEDMODECOOKIE, "true");
|
|
642
|
+
}
|
|
643
|
+
const currentUUID = getUUID();
|
|
644
|
+
resetUUID(config.storage, currentUUID);
|
|
645
|
+
}
|
|
646
|
+
function setAnonymousMode(keepIdentifier) {
|
|
647
|
+
if (storeConsentByLocalStorage) {
|
|
648
|
+
if (isLocalStorageAccessible()) {
|
|
649
|
+
localStorage.setItem(SIGNEDMODECOOKIE, "false");
|
|
650
|
+
}
|
|
651
|
+
} else if (config.storage && typeof config.storage === "object") {
|
|
652
|
+
setStorageCookie(config.storage, SIGNEDMODECOOKIE, "false");
|
|
653
|
+
}
|
|
654
|
+
if (!keepIdentifier) {
|
|
655
|
+
if (config.storage && typeof config.storage === "object") {
|
|
656
|
+
setStorageCookie(config.storage, config.storage.name);
|
|
657
|
+
}
|
|
658
|
+
removeCachedGlobalID();
|
|
659
|
+
sdk.removeServerCookie();
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
function areEventsBlocked() {
|
|
663
|
+
return cookie.getItem(BLOCKEVENTSCOOKIE) === "true";
|
|
664
|
+
}
|
|
665
|
+
function blockEvents() {
|
|
666
|
+
if (config.storage && typeof config.storage === "object") {
|
|
667
|
+
setStorageCookie(config.storage, BLOCKEVENTSCOOKIE, "true");
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
function unblockEvents() {
|
|
671
|
+
if (config.storage && typeof config.storage === "object") {
|
|
672
|
+
setStorageCookie(config.storage, BLOCKEVENTSCOOKIE, "false");
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
function removeCachedGlobalID() {
|
|
676
|
+
if (globals["$global"]) {
|
|
677
|
+
delete globals["$global"]["td_global_id"];
|
|
678
|
+
}
|
|
679
|
+
if (config.storage && typeof config.storage === "object") {
|
|
680
|
+
const globalIdCookie = config.globalIdCookie || "_td_global";
|
|
681
|
+
setStorageCookie(config.storage, globalIdCookie, "");
|
|
682
|
+
}
|
|
683
|
+
if (isLocalStorageAccessible()) {
|
|
684
|
+
const globalIdCookie = config.globalIdCookie || "_td_global";
|
|
685
|
+
try {
|
|
686
|
+
localStorage.removeItem(globalIdCookie);
|
|
687
|
+
} catch {
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function removeServerCookie() {
|
|
692
|
+
if (config.storage && typeof config.storage === "object") {
|
|
693
|
+
setStorageCookie(config.storage, SERVER_COOKIE_NAME, "");
|
|
694
|
+
const otherCookieNames = ["__td_ssc", "_td_ssc"];
|
|
695
|
+
otherCookieNames.forEach((cookieName) => {
|
|
696
|
+
setStorageCookie(config.storage, cookieName, "");
|
|
697
|
+
});
|
|
698
|
+
if (config.useServerSideCookie && config.globalIdCookie) {
|
|
699
|
+
setStorageCookie(config.storage, config.globalIdCookie, "");
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
if (isLocalStorageAccessible()) {
|
|
703
|
+
[SERVER_COOKIE_NAME, "__td_ssc", "_td_ssc"].forEach((key) => {
|
|
704
|
+
try {
|
|
705
|
+
localStorage.removeItem(key);
|
|
706
|
+
} catch {
|
|
707
|
+
}
|
|
708
|
+
});
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
function isGlobalIdEnabled() {
|
|
712
|
+
return get2(void 0, "td_global_id") === "td_global_id";
|
|
713
|
+
}
|
|
714
|
+
return {
|
|
715
|
+
inSignedMode,
|
|
716
|
+
setSignedMode,
|
|
717
|
+
setAnonymousMode,
|
|
718
|
+
blockEvents,
|
|
719
|
+
unblockEvents,
|
|
720
|
+
areEventsBlocked,
|
|
721
|
+
getUUID,
|
|
722
|
+
resetUUID,
|
|
723
|
+
set,
|
|
724
|
+
get: get2,
|
|
725
|
+
removeCachedGlobalID,
|
|
726
|
+
removeServerCookie,
|
|
727
|
+
isGlobalIdEnabled
|
|
728
|
+
};
|
|
729
|
+
}
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
const DEFAULT_HOST = "us01.records.in.treasuredata.com";
|
|
733
|
+
const DEFAULT_PATHNAME = "/";
|
|
734
|
+
function validateRecord(table, record2) {
|
|
735
|
+
invariant$1(isString(table), "Must provide a table");
|
|
736
|
+
invariant$1(
|
|
737
|
+
/^[a-z0-9_]{3,255}$/.test(table),
|
|
738
|
+
"Table must be between 3 and 255 characters and must consist only of lower case letters, numbers, and _"
|
|
739
|
+
);
|
|
740
|
+
invariant$1(isObject$1(record2), "Must provide a record");
|
|
741
|
+
}
|
|
742
|
+
function record() {
|
|
743
|
+
return {
|
|
744
|
+
name: "record",
|
|
745
|
+
setup(core, sdk) {
|
|
746
|
+
const config = core.config;
|
|
747
|
+
const host = config.host || DEFAULT_HOST;
|
|
748
|
+
const pathname = config.pathname || DEFAULT_PATHNAME;
|
|
749
|
+
const endpoint = config.endpoint || `https://${host}${pathname}`;
|
|
750
|
+
let windowBeingUnloaded = false;
|
|
751
|
+
if (typeof window !== "undefined" && window.addEventListener) {
|
|
752
|
+
const handleUnload = () => {
|
|
753
|
+
windowBeingUnloaded = true;
|
|
754
|
+
};
|
|
755
|
+
window.addEventListener("beforeunload", handleUnload);
|
|
756
|
+
window.addEventListener("unload", handleUnload);
|
|
757
|
+
core._unloadHandlers = [
|
|
758
|
+
() => window.removeEventListener("beforeunload", handleUnload),
|
|
759
|
+
() => window.removeEventListener("unload", handleUnload)
|
|
760
|
+
];
|
|
761
|
+
}
|
|
762
|
+
core._windowBeingUnloaded = () => windowBeingUnloaded;
|
|
763
|
+
function applyProperties(table, payload) {
|
|
764
|
+
return Object.assign(
|
|
765
|
+
{},
|
|
766
|
+
sdk.get("$global"),
|
|
767
|
+
sdk.get(table),
|
|
768
|
+
payload
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
const api2 = {
|
|
772
|
+
addRecord(table, record2, success, error, options) {
|
|
773
|
+
validateRecord(table, record2);
|
|
774
|
+
const propertiesRecord = applyProperties(table, record2);
|
|
775
|
+
const finalRecord = sdk.inSignedMode() ? propertiesRecord : omitKeys(propertiesRecord, [
|
|
776
|
+
"td_ip",
|
|
777
|
+
"td_client_id",
|
|
778
|
+
"td_global_id"
|
|
779
|
+
]);
|
|
780
|
+
const request = {
|
|
781
|
+
apikey: config.writeKey,
|
|
782
|
+
record: finalRecord,
|
|
783
|
+
time: null,
|
|
784
|
+
url: `${endpoint}${options?.database ?? config.database}/${table}`
|
|
785
|
+
};
|
|
786
|
+
if (request.record.time != null) {
|
|
787
|
+
request.time = request.record.time;
|
|
788
|
+
}
|
|
789
|
+
if (config.development) {
|
|
790
|
+
core.log.debug("addRecord", request);
|
|
791
|
+
success?.({
|
|
792
|
+
success: true,
|
|
793
|
+
message: "Development mode - record not sent"
|
|
794
|
+
});
|
|
795
|
+
} else if (!sdk.areEventsBlocked()) {
|
|
796
|
+
submitRecord(
|
|
797
|
+
{
|
|
798
|
+
...request,
|
|
799
|
+
inSignedMode: sdk.inSignedMode(),
|
|
800
|
+
isGlobalIdEnabled: sdk.isGlobalIdEnabled(),
|
|
801
|
+
windowBeingUnloaded: core._windowBeingUnloaded?.() ?? false,
|
|
802
|
+
timeoutMs: config.jsonpTimeout ?? 6e4
|
|
803
|
+
},
|
|
804
|
+
success,
|
|
805
|
+
error
|
|
806
|
+
);
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
};
|
|
810
|
+
return api2;
|
|
811
|
+
}
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
function omitKeys(obj, keys) {
|
|
815
|
+
const result = {};
|
|
816
|
+
for (const key of Object.keys(obj)) {
|
|
817
|
+
if (!keys.includes(key)) {
|
|
818
|
+
const value = obj[key];
|
|
819
|
+
if (value !== void 0) {
|
|
820
|
+
result[key] = value;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
return result;
|
|
825
|
+
}
|
|
826
|
+
async function submitRecord(request, success, error) {
|
|
827
|
+
const noop = () => {
|
|
828
|
+
};
|
|
829
|
+
const successCallback = success || noop;
|
|
830
|
+
const errorCallback = error || noop;
|
|
831
|
+
const params = ["modified=" + encodeURIComponent((/* @__PURE__ */ new Date()).getTime())];
|
|
832
|
+
if (request.time) {
|
|
833
|
+
params.push("time=" + encodeURIComponent(request.time));
|
|
834
|
+
}
|
|
835
|
+
const url = request.url + "?" + params.join("&");
|
|
836
|
+
const isClickedLink = request.record.tag === "a" && !!request.record.href;
|
|
837
|
+
const requestHeaders = {};
|
|
838
|
+
requestHeaders["Authorization"] = "TD1 " + request.apikey;
|
|
839
|
+
if (typeof navigator !== "undefined") {
|
|
840
|
+
requestHeaders["User-Agent"] = navigator.userAgent;
|
|
841
|
+
}
|
|
842
|
+
if (request.inSignedMode && request.isGlobalIdEnabled) {
|
|
843
|
+
Object.assign(requestHeaders, globalIdAdlHeaders);
|
|
844
|
+
} else {
|
|
845
|
+
Object.assign(requestHeaders, adlHeaders);
|
|
846
|
+
}
|
|
847
|
+
const payload = { events: [request.record] };
|
|
848
|
+
try {
|
|
849
|
+
if (typeof window !== "undefined" && (request.windowBeingUnloaded || isClickedLink)) {
|
|
850
|
+
const response = await api.postWithTimeout(
|
|
851
|
+
url,
|
|
852
|
+
payload,
|
|
853
|
+
request.timeoutMs,
|
|
854
|
+
{ headers: requestHeaders, credentials: "include" }
|
|
855
|
+
);
|
|
856
|
+
successCallback(response);
|
|
857
|
+
} else {
|
|
858
|
+
const response = await api.post(url, payload, {
|
|
859
|
+
headers: requestHeaders,
|
|
860
|
+
credentials: "include"
|
|
861
|
+
});
|
|
862
|
+
successCallback(response);
|
|
863
|
+
}
|
|
864
|
+
} catch (err) {
|
|
865
|
+
const tdError = err instanceof Error ? { ...err, name: err.name, message: err.message } : new Error("Unknown error occurred");
|
|
866
|
+
errorCallback(tdError);
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
const POPUP_CONTAINER_ID = "td-engage-popup-container";
|
|
870
|
+
let inlineObserver = null;
|
|
871
|
+
let navigationCleanupInstalled = false;
|
|
872
|
+
let accumulatedInline = [];
|
|
873
|
+
function parseAppearance(raw) {
|
|
874
|
+
if (typeof raw === "object" && raw !== null) return raw;
|
|
875
|
+
try {
|
|
876
|
+
return JSON.parse(raw);
|
|
877
|
+
} catch {
|
|
878
|
+
return {};
|
|
879
|
+
}
|
|
880
|
+
}
|
|
881
|
+
function parseMessages(tdApp) {
|
|
882
|
+
try {
|
|
883
|
+
const messagesRaw = tdApp["td_in_browser.messages"];
|
|
884
|
+
if (!messagesRaw) return [];
|
|
885
|
+
return JSON.parse(messagesRaw);
|
|
886
|
+
} catch {
|
|
887
|
+
return [];
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
function removeExistingPopup() {
|
|
891
|
+
document.getElementById(POPUP_CONTAINER_ID)?.remove();
|
|
892
|
+
}
|
|
893
|
+
function isPopupDisplayed() {
|
|
894
|
+
return document.getElementById(POPUP_CONTAINER_ID) !== null;
|
|
895
|
+
}
|
|
896
|
+
function resetForNavigation() {
|
|
897
|
+
removeExistingPopup();
|
|
898
|
+
if (inlineObserver) {
|
|
899
|
+
inlineObserver.disconnect();
|
|
900
|
+
inlineObserver = null;
|
|
901
|
+
}
|
|
902
|
+
accumulatedInline = [];
|
|
903
|
+
}
|
|
904
|
+
function ensureNavigationCleanup() {
|
|
905
|
+
if (navigationCleanupInstalled) return;
|
|
906
|
+
if (typeof window === "undefined" || !window.history) return;
|
|
907
|
+
window.addEventListener("popstate", resetForNavigation);
|
|
908
|
+
window.addEventListener("hashchange", resetForNavigation);
|
|
909
|
+
try {
|
|
910
|
+
const wrap2 = (method) => {
|
|
911
|
+
const original = window.history[method];
|
|
912
|
+
window.history[method] = function(...args) {
|
|
913
|
+
const result = original.apply(this, args);
|
|
914
|
+
resetForNavigation();
|
|
915
|
+
return result;
|
|
916
|
+
};
|
|
917
|
+
};
|
|
918
|
+
wrap2("pushState");
|
|
919
|
+
wrap2("replaceState");
|
|
920
|
+
} catch {
|
|
921
|
+
}
|
|
922
|
+
navigationCleanupInstalled = true;
|
|
923
|
+
}
|
|
924
|
+
function renderPopup(message) {
|
|
925
|
+
try {
|
|
926
|
+
const a = parseAppearance(message.appearance_setting);
|
|
927
|
+
const isDesktop = window.innerWidth > 620;
|
|
928
|
+
removeExistingPopup();
|
|
929
|
+
const placement = a.position?.placement ?? "center";
|
|
930
|
+
const isTop = placement.startsWith("top");
|
|
931
|
+
const isBottom = placement.startsWith("bottom");
|
|
932
|
+
const isLeft = placement.endsWith("left");
|
|
933
|
+
const isRight = placement.endsWith("right");
|
|
934
|
+
const inset = isDesktop ? a.inset?.desktop ?? 40 : a.inset?.mobile ?? 16;
|
|
935
|
+
const maxWidth = isDesktop ? a.width?.desktop_max_width ?? 600 : a.width?.mobile_max_width ?? 300;
|
|
936
|
+
const container = document.createElement("div");
|
|
937
|
+
container.id = POPUP_CONTAINER_ID;
|
|
938
|
+
const alignItems = isBottom ? "end" : isTop ? "start" : "center";
|
|
939
|
+
const justifyItems = isLeft ? "start" : isRight ? "end" : "center";
|
|
940
|
+
Object.assign(container.style, {
|
|
941
|
+
position: a.position?.fixed_on_scroll === false ? "absolute" : "fixed",
|
|
942
|
+
inset: "0",
|
|
943
|
+
display: "grid",
|
|
944
|
+
placeItems: `${alignItems} ${justifyItems}`,
|
|
945
|
+
padding: `${inset}px`,
|
|
946
|
+
pointerEvents: "none",
|
|
947
|
+
boxSizing: "border-box"
|
|
948
|
+
});
|
|
949
|
+
container.style.setProperty(
|
|
950
|
+
"z-index",
|
|
951
|
+
"var(--td-popup-z-index, 2147483647)"
|
|
952
|
+
);
|
|
953
|
+
const shadow = container.attachShadow({ mode: "open" });
|
|
954
|
+
const style = document.createElement("style");
|
|
955
|
+
style.textContent = `
|
|
956
|
+
:host { --td-popup-z-index: 2147483647; --td-popup-frame-z-index: 1; --td-close-btn-cursor: pointer; --td-close-btn-line-height: 1; }
|
|
957
|
+
.td-overlay { position: fixed; inset: 0; pointer-events: auto; }
|
|
958
|
+
.td-frame { position: relative; width: 100%; pointer-events: auto; box-sizing: border-box; z-index: var(--td-popup-frame-z-index); }
|
|
959
|
+
.td-close { position: absolute; background: transparent; border: none; cursor: var(--td-close-btn-cursor); line-height: var(--td-close-btn-line-height); padding: 0; display: flex; align-items: center; justify-content: center; z-index: 1; }
|
|
960
|
+
`;
|
|
961
|
+
shadow.appendChild(style);
|
|
962
|
+
if (a.overlay?.enabled) {
|
|
963
|
+
const overlayEl = document.createElement("div");
|
|
964
|
+
overlayEl.className = "td-overlay";
|
|
965
|
+
Object.assign(overlayEl.style, {
|
|
966
|
+
background: a.overlay.color ?? "#000000B3"
|
|
967
|
+
});
|
|
968
|
+
if (a.overlay.close_on_click_outside) {
|
|
969
|
+
overlayEl.setAttribute("data-engage-popup-close", "");
|
|
970
|
+
}
|
|
971
|
+
shadow.appendChild(overlayEl);
|
|
972
|
+
}
|
|
973
|
+
const frame = document.createElement("div");
|
|
974
|
+
frame.className = "td-frame";
|
|
975
|
+
const bgPadding = a.background?.padding ?? 0;
|
|
976
|
+
Object.assign(frame.style, {
|
|
977
|
+
maxWidth: `${maxWidth}px`,
|
|
978
|
+
background: a.background?.color ?? "#FFFFFF",
|
|
979
|
+
borderRadius: `${a.background?.border_radius ?? 8}px`,
|
|
980
|
+
padding: `${bgPadding}px`
|
|
981
|
+
});
|
|
982
|
+
if (a.close_button?.enabled !== false) {
|
|
983
|
+
const size = a.close_button?.size ?? 28;
|
|
984
|
+
const offsetTop = a.close_button?.offset_top ?? 2;
|
|
985
|
+
const offsetRight = a.close_button?.offset_right ?? 4;
|
|
986
|
+
const closeBtn = document.createElement("button");
|
|
987
|
+
closeBtn.type = "button";
|
|
988
|
+
closeBtn.className = "td-close";
|
|
989
|
+
closeBtn.setAttribute("aria-label", "Close");
|
|
990
|
+
closeBtn.setAttribute("data-engage-popup-close", "");
|
|
991
|
+
Object.assign(closeBtn.style, {
|
|
992
|
+
top: `${offsetTop}px`,
|
|
993
|
+
right: `${offsetRight}px`,
|
|
994
|
+
width: `${size}px`,
|
|
995
|
+
height: `${size}px`,
|
|
996
|
+
fontSize: `${size * 0.7}px`,
|
|
997
|
+
color: a.close_button?.color ?? "#FFFFFF"
|
|
998
|
+
});
|
|
999
|
+
closeBtn.textContent = "×";
|
|
1000
|
+
frame.appendChild(closeBtn);
|
|
1001
|
+
}
|
|
1002
|
+
const content = document.createElement("div");
|
|
1003
|
+
content.innerHTML = message.content_html;
|
|
1004
|
+
frame.appendChild(content);
|
|
1005
|
+
shadow.appendChild(frame);
|
|
1006
|
+
shadow.addEventListener("click", (e) => {
|
|
1007
|
+
const target = e.target;
|
|
1008
|
+
if (target.hasAttribute("data-engage-popup-close")) {
|
|
1009
|
+
container.remove();
|
|
1010
|
+
}
|
|
1011
|
+
});
|
|
1012
|
+
document.body.appendChild(container);
|
|
1013
|
+
} catch {
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
function renderInline(message) {
|
|
1017
|
+
if (!message.css_selector) return;
|
|
1018
|
+
try {
|
|
1019
|
+
const els = document.querySelectorAll(message.css_selector);
|
|
1020
|
+
for (const el of els) {
|
|
1021
|
+
el.innerHTML = message.content_html;
|
|
1022
|
+
}
|
|
1023
|
+
} catch {
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
function compareMessages(a, b) {
|
|
1027
|
+
const tsDiff = Number(b.created_at_millisecond ?? 0) - Number(a.created_at_millisecond ?? 0);
|
|
1028
|
+
if (tsDiff !== 0) return tsDiff;
|
|
1029
|
+
const sectionDiff = b._sectionName.localeCompare(a._sectionName);
|
|
1030
|
+
if (sectionDiff !== 0) return sectionDiff;
|
|
1031
|
+
return b._arrayIndex - a._arrayIndex;
|
|
1032
|
+
}
|
|
1033
|
+
function sortedInlineMessages(messages) {
|
|
1034
|
+
return messages.filter((m) => m.type === "inline" && m.css_selector).sort((a, b) => -compareMessages(a, b));
|
|
1035
|
+
}
|
|
1036
|
+
function pickPopup(messages) {
|
|
1037
|
+
const popups = messages.filter((m) => m.type === "popup").sort(compareMessages);
|
|
1038
|
+
return popups[0];
|
|
1039
|
+
}
|
|
1040
|
+
function applyAccumulatedInline() {
|
|
1041
|
+
for (const msg of accumulatedInline) {
|
|
1042
|
+
renderInline(msg);
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
function setupInlineObserver() {
|
|
1046
|
+
if (inlineObserver) {
|
|
1047
|
+
inlineObserver.disconnect();
|
|
1048
|
+
inlineObserver = null;
|
|
1049
|
+
}
|
|
1050
|
+
if (accumulatedInline.length === 0) return;
|
|
1051
|
+
inlineObserver = new MutationObserver(() => {
|
|
1052
|
+
inlineObserver.disconnect();
|
|
1053
|
+
applyAccumulatedInline();
|
|
1054
|
+
inlineObserver.observe(document.body, { childList: true, subtree: true });
|
|
1055
|
+
});
|
|
1056
|
+
inlineObserver.observe(document.body, { childList: true, subtree: true });
|
|
1057
|
+
}
|
|
1058
|
+
function extractMessages(response) {
|
|
1059
|
+
const offers = response.offers;
|
|
1060
|
+
if (!offers) return [];
|
|
1061
|
+
const allMessages = [];
|
|
1062
|
+
for (const [sectionName, section] of Object.entries(offers)) {
|
|
1063
|
+
const tdApp = section?.td_app;
|
|
1064
|
+
if (!tdApp) continue;
|
|
1065
|
+
const messages = parseMessages(tdApp);
|
|
1066
|
+
messages.forEach((m, i) => {
|
|
1067
|
+
allMessages.push({ ...m, _sectionName: sectionName, _arrayIndex: i });
|
|
1068
|
+
});
|
|
1069
|
+
}
|
|
1070
|
+
return allMessages;
|
|
1071
|
+
}
|
|
1072
|
+
function handlePersonalizationResponse(response) {
|
|
1073
|
+
try {
|
|
1074
|
+
const messages = extractMessages(response);
|
|
1075
|
+
if (messages.length === 0) return;
|
|
1076
|
+
ensureNavigationCleanup();
|
|
1077
|
+
if (!isPopupDisplayed()) {
|
|
1078
|
+
const popup = pickPopup(messages);
|
|
1079
|
+
if (popup) {
|
|
1080
|
+
renderPopup(popup);
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
const inline = sortedInlineMessages(messages);
|
|
1084
|
+
if (inline.length > 0) {
|
|
1085
|
+
accumulatedInline.push(...inline);
|
|
1086
|
+
applyAccumulatedInline();
|
|
1087
|
+
setupInlineObserver();
|
|
1088
|
+
}
|
|
1089
|
+
} catch {
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
function configureValues(getUUID, version) {
|
|
1093
|
+
return {
|
|
1094
|
+
td_version: () => version,
|
|
1095
|
+
td_client_id: getUUID,
|
|
1096
|
+
td_charset: () => (document.characterSet || document.charset || "-").toLowerCase(),
|
|
1097
|
+
td_language: () => {
|
|
1098
|
+
const nav = navigator;
|
|
1099
|
+
return (nav && (nav.language || nav.browserLanguage) || "-").toLowerCase();
|
|
1100
|
+
},
|
|
1101
|
+
td_color: () => screen ? screen.colorDepth + "-bit" : "-",
|
|
1102
|
+
td_screen: () => screen ? `${screen.width}x${screen.height}` : "-",
|
|
1103
|
+
td_viewport: () => {
|
|
1104
|
+
const clientHeight = document.documentElement && document.documentElement.clientHeight;
|
|
1105
|
+
const clientWidth = document.documentElement && document.documentElement.clientWidth;
|
|
1106
|
+
const innerHeight = window.innerHeight;
|
|
1107
|
+
const innerWidth = window.innerWidth;
|
|
1108
|
+
const height = (clientHeight || 0) < innerHeight ? innerHeight : clientHeight || 0;
|
|
1109
|
+
const width = (clientWidth || 0) < innerWidth ? innerWidth : clientWidth || 0;
|
|
1110
|
+
return `${width}x${height}`;
|
|
1111
|
+
},
|
|
1112
|
+
td_title: () => document.title,
|
|
1113
|
+
td_description: () => getMetaContent("description"),
|
|
1114
|
+
td_url: () => {
|
|
1115
|
+
return !document.location || !document.location.href ? "" : document.location.href.split("#")[0] || "";
|
|
1116
|
+
},
|
|
1117
|
+
td_user_agent: () => {
|
|
1118
|
+
const userAgent = navigator.userAgent;
|
|
1119
|
+
const sdkUserAgent = `WEBSDK/${version}`;
|
|
1120
|
+
return [userAgent, sdkUserAgent].join(";");
|
|
1121
|
+
},
|
|
1122
|
+
td_platform: () => {
|
|
1123
|
+
return navigator.platform || navigator.userAgentData?.platform || "-";
|
|
1124
|
+
},
|
|
1125
|
+
td_host: () => document.location.host,
|
|
1126
|
+
td_path: () => document.location.pathname,
|
|
1127
|
+
td_referrer: () => document.referrer
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
function getMetaContent(metaName) {
|
|
1131
|
+
const head = document.head || document.getElementsByTagName("head")[0];
|
|
1132
|
+
const metas = head.getElementsByTagName("meta");
|
|
1133
|
+
const metaLength = metas.length;
|
|
1134
|
+
for (let i = 0; i < metaLength; i++) {
|
|
1135
|
+
const meta = metas[i];
|
|
1136
|
+
if (meta && meta.getAttribute("name") === metaName) {
|
|
1137
|
+
return (meta.getAttribute("content") || "").substr(0, 8192);
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
return "";
|
|
1141
|
+
}
|
|
1142
|
+
function track() {
|
|
1143
|
+
return {
|
|
1144
|
+
name: "track",
|
|
1145
|
+
setup(core, sdk) {
|
|
1146
|
+
const trackValues = configureValues(() => sdk.getUUID(), CONFIG.VERSION);
|
|
1147
|
+
function getTrackValues() {
|
|
1148
|
+
const result = {};
|
|
1149
|
+
for (const [key, value] of Object.entries(trackValues)) {
|
|
1150
|
+
if (value) {
|
|
1151
|
+
result[key] = typeof value === "function" ? value() : value;
|
|
1152
|
+
}
|
|
1153
|
+
}
|
|
1154
|
+
return result;
|
|
1155
|
+
}
|
|
1156
|
+
function trackEvent(table, record2, success, failure) {
|
|
1157
|
+
const tableName = table || "events";
|
|
1158
|
+
const values = getTrackValues();
|
|
1159
|
+
const merged = Object.assign(values, record2);
|
|
1160
|
+
const personalization2 = core.config.personalization;
|
|
1161
|
+
if (personalization2) {
|
|
1162
|
+
const personalizationConfig = {
|
|
1163
|
+
endpoint: personalization2.endpoint,
|
|
1164
|
+
database: personalization2.database || core.config.database,
|
|
1165
|
+
table: tableName,
|
|
1166
|
+
token: personalization2.token
|
|
1167
|
+
};
|
|
1168
|
+
const payload = {
|
|
1169
|
+
...sdk.get("$global"),
|
|
1170
|
+
...sdk.get(tableName),
|
|
1171
|
+
...getTrackValues(),
|
|
1172
|
+
...record2
|
|
1173
|
+
};
|
|
1174
|
+
sdk.fetchPersonalization(
|
|
1175
|
+
personalizationConfig,
|
|
1176
|
+
payload,
|
|
1177
|
+
(response) => {
|
|
1178
|
+
handlePersonalizationResponse(response);
|
|
1179
|
+
if (typeof sdk.applyPersonalization === "function") {
|
|
1180
|
+
sdk.applyPersonalization(
|
|
1181
|
+
response
|
|
1182
|
+
);
|
|
1183
|
+
}
|
|
1184
|
+
},
|
|
1185
|
+
(error) => {
|
|
1186
|
+
core.log.error("Personalization failed:", error);
|
|
1187
|
+
}
|
|
1188
|
+
);
|
|
1189
|
+
return;
|
|
1190
|
+
}
|
|
1191
|
+
sdk.addRecord(tableName, merged, success, failure);
|
|
1192
|
+
}
|
|
1193
|
+
function trackPageview(table, success, failure, options) {
|
|
1194
|
+
const tableName = table || "pageviews";
|
|
1195
|
+
const eventRecord = options?.payload ?? {};
|
|
1196
|
+
trackEvent(tableName, eventRecord, success, failure);
|
|
1197
|
+
}
|
|
1198
|
+
function getPersonalizationConfig() {
|
|
1199
|
+
return core.config.personalization;
|
|
1200
|
+
}
|
|
1201
|
+
function setPersonalizationConfig(options) {
|
|
1202
|
+
core.config.personalization = options;
|
|
1203
|
+
}
|
|
1204
|
+
return {
|
|
1205
|
+
trackEvent,
|
|
1206
|
+
trackPageview,
|
|
1207
|
+
getTrackValues,
|
|
1208
|
+
getPersonalizationConfig,
|
|
1209
|
+
setPersonalizationConfig
|
|
1210
|
+
};
|
|
1211
|
+
}
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
function getEventTarget(event) {
|
|
1215
|
+
const target = event.target || event.srcElement || document;
|
|
1216
|
+
return target.nodeType === 3 ? target.parentNode : target;
|
|
1217
|
+
}
|
|
1218
|
+
function addEventListener(el, type, fn) {
|
|
1219
|
+
if ("addEventListener" in el) {
|
|
1220
|
+
el.addEventListener(type, handler, false);
|
|
1221
|
+
return disposable(() => {
|
|
1222
|
+
el.removeEventListener(type, handler, false);
|
|
1223
|
+
});
|
|
1224
|
+
} else if ("attachEvent" in el) {
|
|
1225
|
+
el.attachEvent("on" + type, handler);
|
|
1226
|
+
return disposable(() => {
|
|
1227
|
+
el.detachEvent("on" + type, handler);
|
|
1228
|
+
});
|
|
1229
|
+
} else {
|
|
1230
|
+
throw new Error("addEventListener not supported");
|
|
1231
|
+
}
|
|
1232
|
+
function handler(event) {
|
|
1233
|
+
fn.call(el, event || window.event);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
function htmlTreeAsString(elem) {
|
|
1237
|
+
const MAX_TRAVERSE_HEIGHT = 5;
|
|
1238
|
+
const MAX_OUTPUT_LEN = 80;
|
|
1239
|
+
const out = [];
|
|
1240
|
+
let height = 0;
|
|
1241
|
+
let len = 0;
|
|
1242
|
+
const separator = " > ";
|
|
1243
|
+
const sepLength = separator.length;
|
|
1244
|
+
let nextStr;
|
|
1245
|
+
let currentElem = elem;
|
|
1246
|
+
while (currentElem && height++ < MAX_TRAVERSE_HEIGHT) {
|
|
1247
|
+
nextStr = htmlElementAsString(currentElem);
|
|
1248
|
+
if (nextStr === "html" || height > 1 && len + out.length * sepLength + nextStr.length >= MAX_OUTPUT_LEN) {
|
|
1249
|
+
break;
|
|
1250
|
+
}
|
|
1251
|
+
out.push(nextStr);
|
|
1252
|
+
len += nextStr.length;
|
|
1253
|
+
currentElem = currentElem.parentNode;
|
|
1254
|
+
}
|
|
1255
|
+
const result = out.reverse().join(separator);
|
|
1256
|
+
if (result.length > MAX_OUTPUT_LEN) {
|
|
1257
|
+
return result.substring(0, MAX_OUTPUT_LEN - 3) + "...";
|
|
1258
|
+
}
|
|
1259
|
+
return result;
|
|
1260
|
+
}
|
|
1261
|
+
function htmlElementAsString(elem) {
|
|
1262
|
+
const out = [];
|
|
1263
|
+
let classes;
|
|
1264
|
+
let key;
|
|
1265
|
+
let attr;
|
|
1266
|
+
let i;
|
|
1267
|
+
if (!elem || !elem.tagName) {
|
|
1268
|
+
return "";
|
|
1269
|
+
}
|
|
1270
|
+
out.push(elem.tagName.toLowerCase());
|
|
1271
|
+
if (elem.id) {
|
|
1272
|
+
out.push("#" + elem.id);
|
|
1273
|
+
}
|
|
1274
|
+
const className = elem.className;
|
|
1275
|
+
if (className && isString(className)) {
|
|
1276
|
+
classes = className.split(" ");
|
|
1277
|
+
for (i = 0; i < classes.length; i++) {
|
|
1278
|
+
const cls = classes[i];
|
|
1279
|
+
if (cls && cls.trim()) {
|
|
1280
|
+
out.push("." + cls.trim());
|
|
1281
|
+
}
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
const attrWhitelist = ["type", "name", "title", "alt"];
|
|
1285
|
+
for (i = 0; i < attrWhitelist.length; i++) {
|
|
1286
|
+
key = attrWhitelist[i];
|
|
1287
|
+
attr = elem.getAttribute(key);
|
|
1288
|
+
if (attr) {
|
|
1289
|
+
out.push("[" + key + '="' + attr + '"]');
|
|
1290
|
+
}
|
|
1291
|
+
}
|
|
1292
|
+
return out.join("");
|
|
1293
|
+
}
|
|
1294
|
+
function hasAttribute(element, attrName) {
|
|
1295
|
+
if (typeof element.hasAttribute === "function") {
|
|
1296
|
+
return element.hasAttribute(attrName);
|
|
1297
|
+
}
|
|
1298
|
+
return element.getAttribute(attrName) !== null;
|
|
1299
|
+
}
|
|
1300
|
+
function findElement(el) {
|
|
1301
|
+
if (!el || !el.tagName) return null;
|
|
1302
|
+
let currentEl = el;
|
|
1303
|
+
let tag = currentEl.tagName.toLowerCase();
|
|
1304
|
+
while (tag && tag !== "body" && currentEl) {
|
|
1305
|
+
const type = currentEl.getAttribute("type");
|
|
1306
|
+
if (tag === "input" && type === "password") return null;
|
|
1307
|
+
const role = currentEl.getAttribute("role");
|
|
1308
|
+
if (role === "button" || role === "link" || tag === "a" || tag === "button" || tag === "input") {
|
|
1309
|
+
return currentEl;
|
|
1310
|
+
}
|
|
1311
|
+
currentEl = currentEl.parentNode;
|
|
1312
|
+
tag = currentEl && currentEl.tagName ? currentEl.tagName.toLowerCase() : "";
|
|
1313
|
+
}
|
|
1314
|
+
return null;
|
|
1315
|
+
}
|
|
1316
|
+
function createTreeHasIgnoreAttribute(ignoreAttribute) {
|
|
1317
|
+
const dataIgnoreAttribute = "data-" + ignoreAttribute;
|
|
1318
|
+
return function treeHasIgnoreAttribute(el) {
|
|
1319
|
+
if (!el || !el.tagName || el.tagName.toLowerCase() === "html") return false;
|
|
1320
|
+
if (hasAttribute(el, ignoreAttribute) || hasAttribute(el, dataIgnoreAttribute))
|
|
1321
|
+
return true;
|
|
1322
|
+
return treeHasIgnoreAttribute(el.parentNode);
|
|
1323
|
+
};
|
|
1324
|
+
}
|
|
1325
|
+
function getElementData(el) {
|
|
1326
|
+
const data = {
|
|
1327
|
+
tag: el.tagName.toLowerCase(),
|
|
1328
|
+
tree: htmlTreeAsString(el)
|
|
1329
|
+
};
|
|
1330
|
+
const attributesToCapture = [
|
|
1331
|
+
"alt",
|
|
1332
|
+
"class",
|
|
1333
|
+
"href",
|
|
1334
|
+
"id",
|
|
1335
|
+
"name",
|
|
1336
|
+
"role",
|
|
1337
|
+
"title",
|
|
1338
|
+
"type"
|
|
1339
|
+
];
|
|
1340
|
+
attributesToCapture.forEach((attrName) => {
|
|
1341
|
+
if (hasAttribute(el, attrName)) {
|
|
1342
|
+
const value = el.getAttribute(attrName);
|
|
1343
|
+
if (value) data[attrName] = value;
|
|
1344
|
+
}
|
|
1345
|
+
});
|
|
1346
|
+
return data;
|
|
1347
|
+
}
|
|
1348
|
+
function clicks() {
|
|
1349
|
+
return {
|
|
1350
|
+
name: "clicks",
|
|
1351
|
+
setup(_core, sdk) {
|
|
1352
|
+
let clickTrackingInstalled = false;
|
|
1353
|
+
return {
|
|
1354
|
+
trackClicks(options) {
|
|
1355
|
+
if (clickTrackingInstalled) return void 0;
|
|
1356
|
+
const opts = {
|
|
1357
|
+
element: options?.element ?? window.document,
|
|
1358
|
+
extendClickData: options?.extendClickData ?? ((_e, data) => data),
|
|
1359
|
+
ignoreAttribute: options?.ignoreAttribute ?? "td-ignore",
|
|
1360
|
+
tableName: options?.tableName ?? "clicks"
|
|
1361
|
+
};
|
|
1362
|
+
const treeHasIgnoreAttribute = createTreeHasIgnoreAttribute(
|
|
1363
|
+
opts.ignoreAttribute
|
|
1364
|
+
);
|
|
1365
|
+
const removeClickTracker = addEventListener(
|
|
1366
|
+
opts.element,
|
|
1367
|
+
"click",
|
|
1368
|
+
(e) => {
|
|
1369
|
+
const eventTarget = getEventTarget(e);
|
|
1370
|
+
const target = findElement(eventTarget);
|
|
1371
|
+
if (target && !treeHasIgnoreAttribute(target)) {
|
|
1372
|
+
const elementData = getElementData(target);
|
|
1373
|
+
const data = opts.extendClickData(
|
|
1374
|
+
e,
|
|
1375
|
+
elementData
|
|
1376
|
+
);
|
|
1377
|
+
if (data) {
|
|
1378
|
+
sdk.trackEvent(opts.tableName, data);
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
}
|
|
1382
|
+
);
|
|
1383
|
+
clickTrackingInstalled = true;
|
|
1384
|
+
return disposable(() => {
|
|
1385
|
+
removeClickTracker();
|
|
1386
|
+
clickTrackingInstalled = false;
|
|
1387
|
+
});
|
|
1388
|
+
}
|
|
1389
|
+
};
|
|
1390
|
+
}
|
|
1391
|
+
};
|
|
1392
|
+
}
|
|
1393
|
+
const DEFAULT_UTM_PARAMS = [
|
|
1394
|
+
"utm_id",
|
|
1395
|
+
"utm_medium",
|
|
1396
|
+
"utm_source_platform",
|
|
1397
|
+
"utm_source",
|
|
1398
|
+
"utm_campaign",
|
|
1399
|
+
"utm_marketing_tactic"
|
|
1400
|
+
];
|
|
1401
|
+
function collectUTMParametersFromURL(utmParams = DEFAULT_UTM_PARAMS) {
|
|
1402
|
+
if (typeof window === "undefined" || !window.location) {
|
|
1403
|
+
return {};
|
|
1404
|
+
}
|
|
1405
|
+
const searchString = window.location.search;
|
|
1406
|
+
const URLSearchParamsClass = window.URLSearchParams || URLSearchParams;
|
|
1407
|
+
const searchParams = new URLSearchParamsClass(searchString);
|
|
1408
|
+
const hasParams = utmParams.some((param) => searchParams.has(param));
|
|
1409
|
+
if (!hasParams) {
|
|
1410
|
+
return {};
|
|
1411
|
+
}
|
|
1412
|
+
return utmParams.reduce(
|
|
1413
|
+
(acc, paramName) => {
|
|
1414
|
+
const paramValue = searchParams.get(paramName);
|
|
1415
|
+
if (paramValue) {
|
|
1416
|
+
acc[paramName] = paramValue;
|
|
1417
|
+
}
|
|
1418
|
+
return acc;
|
|
1419
|
+
},
|
|
1420
|
+
{}
|
|
1421
|
+
);
|
|
1422
|
+
}
|
|
1423
|
+
function utm(options = {}) {
|
|
1424
|
+
return {
|
|
1425
|
+
name: "utm",
|
|
1426
|
+
setup(_core, sdk) {
|
|
1427
|
+
const opts = {
|
|
1428
|
+
customParameters: options.customParameters || DEFAULT_UTM_PARAMS,
|
|
1429
|
+
autoCollect: options.autoCollect ?? true,
|
|
1430
|
+
table: options.table || "$global"
|
|
1431
|
+
};
|
|
1432
|
+
let collectedParams = {};
|
|
1433
|
+
function collectUTMParameters() {
|
|
1434
|
+
const params = collectUTMParametersFromURL(opts.customParameters);
|
|
1435
|
+
if (isObject$1(params) && !isEmpty(params)) {
|
|
1436
|
+
if (opts.table === "$global") {
|
|
1437
|
+
sdk.set(params);
|
|
1438
|
+
} else {
|
|
1439
|
+
Object.keys(params).forEach((paramName) => {
|
|
1440
|
+
sdk.set(opts.table, paramName, params[paramName]);
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
collectedParams = { ...collectedParams, ...params };
|
|
1444
|
+
}
|
|
1445
|
+
return params;
|
|
1446
|
+
}
|
|
1447
|
+
function getUTMParameters() {
|
|
1448
|
+
return { ...collectedParams };
|
|
1449
|
+
}
|
|
1450
|
+
if (opts.autoCollect) {
|
|
1451
|
+
collectUTMParameters();
|
|
1452
|
+
}
|
|
1453
|
+
return {
|
|
1454
|
+
getUTMParameters,
|
|
1455
|
+
collectUTMParameters
|
|
1456
|
+
};
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1459
|
+
}
|
|
1460
|
+
const DEFAULT_CDP_HOST = "cdp.in.treasuredata.com";
|
|
1461
|
+
function invariant(condition, message) {
|
|
1462
|
+
if (!condition) {
|
|
1463
|
+
throw new Error(message);
|
|
1464
|
+
}
|
|
1465
|
+
}
|
|
1466
|
+
function personalization() {
|
|
1467
|
+
return {
|
|
1468
|
+
name: "personalization",
|
|
1469
|
+
setup(core, sdk) {
|
|
1470
|
+
const config = core.config;
|
|
1471
|
+
const cdpHost = config.cdpHost || DEFAULT_CDP_HOST;
|
|
1472
|
+
function fetchUserSegments(tokenOrOptions, successCallback, errorCallback) {
|
|
1473
|
+
const noop = () => {
|
|
1474
|
+
};
|
|
1475
|
+
const success = successCallback || noop;
|
|
1476
|
+
const error = errorCallback || noop;
|
|
1477
|
+
const isConfigObject = isObject$1(tokenOrOptions) && !isArray(tokenOrOptions);
|
|
1478
|
+
const audienceToken = isConfigObject ? tokenOrOptions.audienceToken : tokenOrOptions;
|
|
1479
|
+
const keys = isConfigObject && tokenOrOptions.keys || {};
|
|
1480
|
+
invariant(
|
|
1481
|
+
typeof audienceToken === "string" || isArray(audienceToken),
|
|
1482
|
+
`audienceToken must be a string or array; received "${String(audienceToken)}"`
|
|
1483
|
+
);
|
|
1484
|
+
invariant(
|
|
1485
|
+
isObject$1(keys),
|
|
1486
|
+
`keys must be an object; received "${String(keys)}"`
|
|
1487
|
+
);
|
|
1488
|
+
const token = isArray(audienceToken) ? audienceToken.join(",") : audienceToken;
|
|
1489
|
+
const keysArray = [];
|
|
1490
|
+
Object.keys(keys).forEach((key) => {
|
|
1491
|
+
keysArray.push(`key.${key}=${String(keys[key])}`);
|
|
1492
|
+
});
|
|
1493
|
+
const keyString = keysArray.join("&");
|
|
1494
|
+
const url = `https://${cdpHost}/cdp/lookup/collect/segments?version=2&token=${token}${keyString ? "&" + keyString : ""}`;
|
|
1495
|
+
api.getWithTimeout(url, 1e4, {
|
|
1496
|
+
headers: {
|
|
1497
|
+
"Content-Type": "application/json"
|
|
1498
|
+
}
|
|
1499
|
+
}).then(success).catch(error);
|
|
1500
|
+
}
|
|
1501
|
+
function fetchPersonalization(config2, data, successCallback, errorCallback) {
|
|
1502
|
+
const noop = () => {
|
|
1503
|
+
};
|
|
1504
|
+
const success = successCallback || noop;
|
|
1505
|
+
const error = errorCallback || noop;
|
|
1506
|
+
invariant(
|
|
1507
|
+
isObject$1(config2),
|
|
1508
|
+
`config must be an object, received "${String(config2)}"`
|
|
1509
|
+
);
|
|
1510
|
+
invariant(!!config2.endpoint, "endpoint is invalid");
|
|
1511
|
+
invariant(!!config2.database, "database is invalid");
|
|
1512
|
+
invariant(!!config2.table, "table is invalid");
|
|
1513
|
+
invariant(!!config2.token, "token is invalid");
|
|
1514
|
+
const eventsBlocked = typeof sdk.areEventsBlocked === "function" ? sdk.areEventsBlocked() : false;
|
|
1515
|
+
if (eventsBlocked) {
|
|
1516
|
+
return;
|
|
1517
|
+
}
|
|
1518
|
+
const url = `https://${config2.endpoint}/public/${config2.database}/${config2.table}`;
|
|
1519
|
+
let payload = data || {};
|
|
1520
|
+
const isSignedMode = typeof sdk.inSignedMode === "function" ? sdk.inSignedMode() : true;
|
|
1521
|
+
if (!isSignedMode) {
|
|
1522
|
+
payload = omit(
|
|
1523
|
+
payload,
|
|
1524
|
+
"td_ip",
|
|
1525
|
+
"td_client_id",
|
|
1526
|
+
"td_global_id"
|
|
1527
|
+
);
|
|
1528
|
+
}
|
|
1529
|
+
api.postWithTimeout(url, payload, 1e4, {
|
|
1530
|
+
headers: {
|
|
1531
|
+
"Content-Type": "application/vnd.treasuredata.v1+json",
|
|
1532
|
+
Authorization: `TD1 ${core.config.writeKey}`,
|
|
1533
|
+
"WP13n-Token": config2.token
|
|
1534
|
+
}
|
|
1535
|
+
}).then(success).catch(error);
|
|
1536
|
+
}
|
|
1537
|
+
return {
|
|
1538
|
+
fetchUserSegments,
|
|
1539
|
+
fetchPersonalization
|
|
1540
|
+
};
|
|
1541
|
+
}
|
|
1542
|
+
};
|
|
1543
|
+
}
|
|
1544
|
+
const VENDOR_FUNCTION_MAPPINGS = {
|
|
1545
|
+
google_ads: ["getGoogle_gclid_Param", "getGoogle_wbraid_Param"],
|
|
1546
|
+
google_ga: ["getGoogle_ga_Cookie"],
|
|
1547
|
+
google_mp: ["getGoogle_gcl_Cookies"],
|
|
1548
|
+
meta: [
|
|
1549
|
+
"getFacebook_fbp_Cookie",
|
|
1550
|
+
"getFacebook_fbc_Cookie",
|
|
1551
|
+
"getFacebook_fbclid_Param"
|
|
1552
|
+
],
|
|
1553
|
+
instagram: [
|
|
1554
|
+
"getInstagram_shbts_Cookie",
|
|
1555
|
+
"getInstagram_shbid_Cookie",
|
|
1556
|
+
"getInstagram_ds_user_id_Cookie",
|
|
1557
|
+
"getInstagram_ig_did_Cookie"
|
|
1558
|
+
],
|
|
1559
|
+
yahoojp_ads: [
|
|
1560
|
+
"getYahoo_ly_c_Param",
|
|
1561
|
+
"getYahoo_ly_c_Cookie",
|
|
1562
|
+
"getYahoo_ly_r_Cookie",
|
|
1563
|
+
"getYahoo_ly_su_Cookie",
|
|
1564
|
+
"getYahoo_yclid_Param",
|
|
1565
|
+
"getYahoo_yj_r_Param",
|
|
1566
|
+
"getYahoo_ycl_yjad_Cookie",
|
|
1567
|
+
"getYahoo_yjr_yjad_Cookie",
|
|
1568
|
+
"getYahoo_yjsu_yjad_Cookie"
|
|
1569
|
+
],
|
|
1570
|
+
line: [
|
|
1571
|
+
"getLine_lt_cid_Cookie",
|
|
1572
|
+
"getLine_lt_sid_Cookie",
|
|
1573
|
+
"getLine_ldtag_cl_Param"
|
|
1574
|
+
],
|
|
1575
|
+
x: ["getX_twclid_Param", "getX_twclid_Cookie"],
|
|
1576
|
+
pinterest: ["getPinterest_epik_Param", "getPinterest_epik_Cookie"],
|
|
1577
|
+
snapchat: ["getSnapchat_sccid_Param"],
|
|
1578
|
+
tiktok: ["getTiktok_ttp_Cookie"],
|
|
1579
|
+
marketo: ["getMarketo_mkto_trk_Cookie"],
|
|
1580
|
+
tealium: ["getTealium_utag_main_Cookie"]
|
|
1581
|
+
};
|
|
1582
|
+
function getCookie(key) {
|
|
1583
|
+
if (typeof document === "undefined") return null;
|
|
1584
|
+
return cookie.getItem(key);
|
|
1585
|
+
}
|
|
1586
|
+
function getCookieByNamePrefix(prefix) {
|
|
1587
|
+
if (typeof document === "undefined") return {};
|
|
1588
|
+
return cookie.keys().filter((key) => key.startsWith(prefix)).reduce(
|
|
1589
|
+
(acc, key) => {
|
|
1590
|
+
const value = cookie.getItem(key);
|
|
1591
|
+
if (value !== null) acc[key] = value;
|
|
1592
|
+
return acc;
|
|
1593
|
+
},
|
|
1594
|
+
{}
|
|
1595
|
+
);
|
|
1596
|
+
}
|
|
1597
|
+
function getParam(key) {
|
|
1598
|
+
if (typeof window === "undefined" || !window.location) return null;
|
|
1599
|
+
const queryString = window.location.search;
|
|
1600
|
+
const URLSearchParamsClass = window.URLSearchParams || URLSearchParams;
|
|
1601
|
+
const urlParams = new URLSearchParamsClass(queryString);
|
|
1602
|
+
return urlParams.get(key);
|
|
1603
|
+
}
|
|
1604
|
+
function conversionAPI() {
|
|
1605
|
+
return {
|
|
1606
|
+
name: "conversionAPI",
|
|
1607
|
+
setup(_core, sdk) {
|
|
1608
|
+
const tagCollectors = {
|
|
1609
|
+
// Google
|
|
1610
|
+
getGoogle_gclid_Param: () => ({ gclid: getParam("gclid") }),
|
|
1611
|
+
getGoogle_wbraid_Param: () => ({ wbraid: getParam("wbraid") }),
|
|
1612
|
+
getGoogle_ga_Cookie: () => ({ _ga: getCookie("_ga") }),
|
|
1613
|
+
getGoogle_gcl_Cookies: (options = {}) => {
|
|
1614
|
+
const prefix = options.gclPrefix || "_gcl";
|
|
1615
|
+
return getCookieByNamePrefix(prefix);
|
|
1616
|
+
},
|
|
1617
|
+
// Meta/Facebook
|
|
1618
|
+
getFacebook_fbp_Cookie: () => ({ _fbp: getCookie("_fbp") }),
|
|
1619
|
+
getFacebook_fbc_Cookie: () => ({ _fbc: getCookie("_fbc") }),
|
|
1620
|
+
getFacebook_fbclid_Param: () => ({ fbclid: getParam("fbclid") }),
|
|
1621
|
+
// Instagram
|
|
1622
|
+
getInstagram_shbts_Cookie: () => ({ shbts: getCookie("shbts") }),
|
|
1623
|
+
getInstagram_shbid_Cookie: () => ({ shbid: getCookie("shbid") }),
|
|
1624
|
+
getInstagram_ds_user_id_Cookie: () => ({
|
|
1625
|
+
ds_user_id: getCookie("ds_user_id")
|
|
1626
|
+
}),
|
|
1627
|
+
getInstagram_ig_did_Cookie: () => ({ ig_did: getCookie("ig_did") }),
|
|
1628
|
+
// Yahoo Japan
|
|
1629
|
+
getYahoo_yclid_Param: () => ({ yclid: getParam("yclid") }),
|
|
1630
|
+
getYahoo_yj_r_Param: () => ({ yj_r: getParam("yj_r") }),
|
|
1631
|
+
getYahoo_ycl_yjad_Cookie: () => ({ _ycl_yjad: getCookie("_ycl_yjad") }),
|
|
1632
|
+
getYahoo_yjr_yjad_Cookie: () => ({ _yjr_yjad: getCookie("_yjr_yjad") }),
|
|
1633
|
+
getYahoo_yjsu_yjad_Cookie: () => ({
|
|
1634
|
+
_yjsu_yjad: getCookie("_yjsu_yjad")
|
|
1635
|
+
}),
|
|
1636
|
+
getYahoo_ly_c_Param: () => ({ ly_c: getParam("_ly_c") }),
|
|
1637
|
+
getYahoo_ly_c_Cookie: () => ({ ly_c: getCookie("_ly_c") }),
|
|
1638
|
+
getYahoo_ly_r_Cookie: () => ({ ly_r: getCookie("_ly_r") }),
|
|
1639
|
+
getYahoo_ly_su_Cookie: () => ({ ly_su: getCookie("_ly_su") }),
|
|
1640
|
+
// Line
|
|
1641
|
+
getLine_lt_cid_Cookie: () => ({ __lt_cid: getCookie("__lt__cid") }),
|
|
1642
|
+
getLine_lt_sid_Cookie: () => ({ __lt_sid: getCookie("__lt__sid") }),
|
|
1643
|
+
getLine_ldtag_cl_Param: () => ({ ldtag_cl: getParam("ldtag_cl") }),
|
|
1644
|
+
// Twitter/X
|
|
1645
|
+
getX_twclid_Param: () => ({ twclid: getParam("twclid") }),
|
|
1646
|
+
getX_twclid_Cookie: () => ({ _twclid: getCookie("_twclid") }),
|
|
1647
|
+
// Pinterest
|
|
1648
|
+
getPinterest_epik_Param: () => ({ epik: getParam("epik") }),
|
|
1649
|
+
getPinterest_epik_Cookie: () => ({ _epik: getCookie("_epik") }),
|
|
1650
|
+
// Snapchat
|
|
1651
|
+
getSnapchat_sccid_Param: () => ({ ScCid: getParam("ScCid") }),
|
|
1652
|
+
// TikTok
|
|
1653
|
+
getTiktok_ttp_Cookie: () => ({ _ttp: getCookie("_ttp") }),
|
|
1654
|
+
// Marketo
|
|
1655
|
+
getMarketo_mkto_trk_Cookie: () => ({
|
|
1656
|
+
_mkto_trk: getCookie("_mkto_trk")
|
|
1657
|
+
}),
|
|
1658
|
+
// Tealium
|
|
1659
|
+
getTealium_utag_main_Cookie: () => ({
|
|
1660
|
+
utag_main: getCookie("utag_main")
|
|
1661
|
+
})
|
|
1662
|
+
};
|
|
1663
|
+
function collectTagsByVendors(vendors = [], options = {}) {
|
|
1664
|
+
return vendors.reduce(
|
|
1665
|
+
(acc, vendor) => {
|
|
1666
|
+
const fnNames = VENDOR_FUNCTION_MAPPINGS[vendor] || [];
|
|
1667
|
+
fnNames.forEach((fnName) => {
|
|
1668
|
+
const result = tagCollectors[fnName](options);
|
|
1669
|
+
Object.assign(acc, result);
|
|
1670
|
+
});
|
|
1671
|
+
return acc;
|
|
1672
|
+
},
|
|
1673
|
+
{}
|
|
1674
|
+
);
|
|
1675
|
+
}
|
|
1676
|
+
function collectTagsByCookieNames(cookieNames = []) {
|
|
1677
|
+
return cookieNames.reduce(
|
|
1678
|
+
(acc, cookieName) => {
|
|
1679
|
+
acc[cookieName] = getCookie(cookieName);
|
|
1680
|
+
return acc;
|
|
1681
|
+
},
|
|
1682
|
+
{}
|
|
1683
|
+
);
|
|
1684
|
+
}
|
|
1685
|
+
function collectTagsByParamNames(params = []) {
|
|
1686
|
+
return params.reduce(
|
|
1687
|
+
(acc, paramName) => {
|
|
1688
|
+
acc[paramName] = getParam(paramName);
|
|
1689
|
+
return acc;
|
|
1690
|
+
},
|
|
1691
|
+
{}
|
|
1692
|
+
);
|
|
1693
|
+
}
|
|
1694
|
+
function collectAllTags(options = {}) {
|
|
1695
|
+
const tags = {};
|
|
1696
|
+
const vendorKeys = Object.keys(VENDOR_FUNCTION_MAPPINGS);
|
|
1697
|
+
vendorKeys.forEach((vendor) => {
|
|
1698
|
+
const vendorFns = VENDOR_FUNCTION_MAPPINGS[vendor];
|
|
1699
|
+
if (vendorFns) {
|
|
1700
|
+
vendorFns.forEach((fnName) => {
|
|
1701
|
+
const result = tagCollectors[fnName](options);
|
|
1702
|
+
Object.assign(tags, result);
|
|
1703
|
+
});
|
|
1704
|
+
}
|
|
1705
|
+
});
|
|
1706
|
+
return Object.keys(tags).reduce(
|
|
1707
|
+
(acc, key) => {
|
|
1708
|
+
if (tags[key]) {
|
|
1709
|
+
acc[key] = tags[key];
|
|
1710
|
+
}
|
|
1711
|
+
return acc;
|
|
1712
|
+
},
|
|
1713
|
+
{}
|
|
1714
|
+
);
|
|
1715
|
+
}
|
|
1716
|
+
function collectTags(config = {}, options = {}) {
|
|
1717
|
+
const isEmptyConfigValues = isEmpty(config.vendors) && isEmpty(config.cookies) && isEmpty(config.params);
|
|
1718
|
+
let tags = {};
|
|
1719
|
+
if (isEmpty(config) || isEmptyConfigValues) {
|
|
1720
|
+
tags = collectAllTags(options);
|
|
1721
|
+
} else {
|
|
1722
|
+
if (!isEmpty(config.vendors)) {
|
|
1723
|
+
Object.assign(tags, collectTagsByVendors(config.vendors, options));
|
|
1724
|
+
}
|
|
1725
|
+
if (!isEmpty(config.cookies)) {
|
|
1726
|
+
Object.assign(tags, collectTagsByCookieNames(config.cookies));
|
|
1727
|
+
}
|
|
1728
|
+
if (!isEmpty(config.params)) {
|
|
1729
|
+
Object.assign(tags, collectTagsByParamNames(config.params));
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
Object.keys(tags).forEach((tagKey) => {
|
|
1733
|
+
const tagValue = tags[tagKey];
|
|
1734
|
+
if (tagValue) {
|
|
1735
|
+
sdk.set({ [tagKey]: tagValue });
|
|
1736
|
+
}
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
return {
|
|
1740
|
+
collectTags
|
|
1741
|
+
};
|
|
1742
|
+
}
|
|
1743
|
+
};
|
|
1744
|
+
}
|
|
1745
|
+
const MODE_QUERY_PARAM = "td-personalization-mode";
|
|
1746
|
+
const INIT_MESSAGE_TYPE = "td:p13n-studio:init";
|
|
1747
|
+
const READY_MESSAGE_TYPE = "td:p13n-studio:ready";
|
|
1748
|
+
const PROD_ORIGINS = [
|
|
1749
|
+
// us01
|
|
1750
|
+
"https://console-development-next.us01.treasuredata.com",
|
|
1751
|
+
"https://console-staging-next.us01.treasuredata.com",
|
|
1752
|
+
"https://console-next.us01.treasuredata.com",
|
|
1753
|
+
// tokyo
|
|
1754
|
+
"https://console-staging-next.treasuredata.co.jp",
|
|
1755
|
+
"https://console-next.treasuredata.co.jp",
|
|
1756
|
+
// eu01
|
|
1757
|
+
"https://console-development-next.eu01.treasuredata.com",
|
|
1758
|
+
"https://console-next.eu01.treasuredata.com",
|
|
1759
|
+
// ap02
|
|
1760
|
+
"https://console-next.ap02.treasuredata.com",
|
|
1761
|
+
// ap03
|
|
1762
|
+
"https://console-staging-next.ap03.treasuredata.com",
|
|
1763
|
+
"https://console-next.ap03.treasuredata.com"
|
|
1764
|
+
];
|
|
1765
|
+
const ALLOWED_PARENT_ORIGINS = Object.freeze(
|
|
1766
|
+
[...PROD_ORIGINS]
|
|
1767
|
+
);
|
|
1768
|
+
/**
|
|
1769
|
+
* @license
|
|
1770
|
+
* Copyright 2019 Google LLC
|
|
1771
|
+
* SPDX-License-Identifier: Apache-2.0
|
|
1772
|
+
*/
|
|
1773
|
+
const proxyMarker = Symbol("Comlink.proxy");
|
|
1774
|
+
const createEndpoint = Symbol("Comlink.endpoint");
|
|
1775
|
+
const releaseProxy = Symbol("Comlink.releaseProxy");
|
|
1776
|
+
const finalizer = Symbol("Comlink.finalizer");
|
|
1777
|
+
const throwMarker = Symbol("Comlink.thrown");
|
|
1778
|
+
const isObject = (val) => typeof val === "object" && val !== null || typeof val === "function";
|
|
1779
|
+
const proxyTransferHandler = {
|
|
1780
|
+
canHandle: (val) => isObject(val) && val[proxyMarker],
|
|
1781
|
+
serialize(obj) {
|
|
1782
|
+
const { port1, port2 } = new MessageChannel();
|
|
1783
|
+
expose(obj, port1);
|
|
1784
|
+
return [port2, [port2]];
|
|
1785
|
+
},
|
|
1786
|
+
deserialize(port) {
|
|
1787
|
+
port.start();
|
|
1788
|
+
return wrap(port);
|
|
1789
|
+
}
|
|
1790
|
+
};
|
|
1791
|
+
const throwTransferHandler = {
|
|
1792
|
+
canHandle: (value) => isObject(value) && throwMarker in value,
|
|
1793
|
+
serialize({ value }) {
|
|
1794
|
+
let serialized;
|
|
1795
|
+
if (value instanceof Error) {
|
|
1796
|
+
serialized = {
|
|
1797
|
+
isError: true,
|
|
1798
|
+
value: {
|
|
1799
|
+
message: value.message,
|
|
1800
|
+
name: value.name,
|
|
1801
|
+
stack: value.stack
|
|
1802
|
+
}
|
|
1803
|
+
};
|
|
1804
|
+
} else {
|
|
1805
|
+
serialized = { isError: false, value };
|
|
1806
|
+
}
|
|
1807
|
+
return [serialized, []];
|
|
1808
|
+
},
|
|
1809
|
+
deserialize(serialized) {
|
|
1810
|
+
if (serialized.isError) {
|
|
1811
|
+
throw Object.assign(new Error(serialized.value.message), serialized.value);
|
|
1812
|
+
}
|
|
1813
|
+
throw serialized.value;
|
|
1814
|
+
}
|
|
1815
|
+
};
|
|
1816
|
+
const transferHandlers = /* @__PURE__ */ new Map([
|
|
1817
|
+
["proxy", proxyTransferHandler],
|
|
1818
|
+
["throw", throwTransferHandler]
|
|
1819
|
+
]);
|
|
1820
|
+
function isAllowedOrigin(allowedOrigins, origin) {
|
|
1821
|
+
for (const allowedOrigin of allowedOrigins) {
|
|
1822
|
+
if (origin === allowedOrigin || allowedOrigin === "*") {
|
|
1823
|
+
return true;
|
|
1824
|
+
}
|
|
1825
|
+
if (allowedOrigin instanceof RegExp && allowedOrigin.test(origin)) {
|
|
1826
|
+
return true;
|
|
1827
|
+
}
|
|
1828
|
+
}
|
|
1829
|
+
return false;
|
|
1830
|
+
}
|
|
1831
|
+
function expose(obj, ep = globalThis, allowedOrigins = ["*"]) {
|
|
1832
|
+
ep.addEventListener("message", function callback(ev) {
|
|
1833
|
+
if (!ev || !ev.data) {
|
|
1834
|
+
return;
|
|
1835
|
+
}
|
|
1836
|
+
if (!isAllowedOrigin(allowedOrigins, ev.origin)) {
|
|
1837
|
+
console.warn(`Invalid origin '${ev.origin}' for comlink proxy`);
|
|
1838
|
+
return;
|
|
1839
|
+
}
|
|
1840
|
+
const { id, type, path } = Object.assign({ path: [] }, ev.data);
|
|
1841
|
+
const argumentList = (ev.data.argumentList || []).map(fromWireValue);
|
|
1842
|
+
let returnValue;
|
|
1843
|
+
try {
|
|
1844
|
+
const parent = path.slice(0, -1).reduce((obj2, prop) => obj2[prop], obj);
|
|
1845
|
+
const rawValue = path.reduce((obj2, prop) => obj2[prop], obj);
|
|
1846
|
+
switch (type) {
|
|
1847
|
+
case "GET":
|
|
1848
|
+
{
|
|
1849
|
+
returnValue = rawValue;
|
|
1850
|
+
}
|
|
1851
|
+
break;
|
|
1852
|
+
case "SET":
|
|
1853
|
+
{
|
|
1854
|
+
parent[path.slice(-1)[0]] = fromWireValue(ev.data.value);
|
|
1855
|
+
returnValue = true;
|
|
1856
|
+
}
|
|
1857
|
+
break;
|
|
1858
|
+
case "APPLY":
|
|
1859
|
+
{
|
|
1860
|
+
returnValue = rawValue.apply(parent, argumentList);
|
|
1861
|
+
}
|
|
1862
|
+
break;
|
|
1863
|
+
case "CONSTRUCT":
|
|
1864
|
+
{
|
|
1865
|
+
const value = new rawValue(...argumentList);
|
|
1866
|
+
returnValue = proxy(value);
|
|
1867
|
+
}
|
|
1868
|
+
break;
|
|
1869
|
+
case "ENDPOINT":
|
|
1870
|
+
{
|
|
1871
|
+
const { port1, port2 } = new MessageChannel();
|
|
1872
|
+
expose(obj, port2);
|
|
1873
|
+
returnValue = transfer(port1, [port1]);
|
|
1874
|
+
}
|
|
1875
|
+
break;
|
|
1876
|
+
case "RELEASE":
|
|
1877
|
+
{
|
|
1878
|
+
returnValue = void 0;
|
|
1879
|
+
}
|
|
1880
|
+
break;
|
|
1881
|
+
default:
|
|
1882
|
+
return;
|
|
1883
|
+
}
|
|
1884
|
+
} catch (value) {
|
|
1885
|
+
returnValue = { value, [throwMarker]: 0 };
|
|
1886
|
+
}
|
|
1887
|
+
Promise.resolve(returnValue).catch((value) => {
|
|
1888
|
+
return { value, [throwMarker]: 0 };
|
|
1889
|
+
}).then((returnValue2) => {
|
|
1890
|
+
const [wireValue, transferables] = toWireValue(returnValue2);
|
|
1891
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
1892
|
+
if (type === "RELEASE") {
|
|
1893
|
+
ep.removeEventListener("message", callback);
|
|
1894
|
+
closeEndPoint(ep);
|
|
1895
|
+
if (finalizer in obj && typeof obj[finalizer] === "function") {
|
|
1896
|
+
obj[finalizer]();
|
|
1897
|
+
}
|
|
1898
|
+
}
|
|
1899
|
+
}).catch((error) => {
|
|
1900
|
+
const [wireValue, transferables] = toWireValue({
|
|
1901
|
+
value: new TypeError("Unserializable return value"),
|
|
1902
|
+
[throwMarker]: 0
|
|
1903
|
+
});
|
|
1904
|
+
ep.postMessage(Object.assign(Object.assign({}, wireValue), { id }), transferables);
|
|
1905
|
+
});
|
|
1906
|
+
});
|
|
1907
|
+
if (ep.start) {
|
|
1908
|
+
ep.start();
|
|
1909
|
+
}
|
|
1910
|
+
}
|
|
1911
|
+
function isMessagePort(endpoint) {
|
|
1912
|
+
return endpoint.constructor.name === "MessagePort";
|
|
1913
|
+
}
|
|
1914
|
+
function closeEndPoint(endpoint) {
|
|
1915
|
+
if (isMessagePort(endpoint))
|
|
1916
|
+
endpoint.close();
|
|
1917
|
+
}
|
|
1918
|
+
function wrap(ep, target) {
|
|
1919
|
+
const pendingListeners = /* @__PURE__ */ new Map();
|
|
1920
|
+
ep.addEventListener("message", function handleMessage(ev) {
|
|
1921
|
+
const { data } = ev;
|
|
1922
|
+
if (!data || !data.id) {
|
|
1923
|
+
return;
|
|
1924
|
+
}
|
|
1925
|
+
const resolver = pendingListeners.get(data.id);
|
|
1926
|
+
if (!resolver) {
|
|
1927
|
+
return;
|
|
1928
|
+
}
|
|
1929
|
+
try {
|
|
1930
|
+
resolver(data);
|
|
1931
|
+
} finally {
|
|
1932
|
+
pendingListeners.delete(data.id);
|
|
1933
|
+
}
|
|
1934
|
+
});
|
|
1935
|
+
return createProxy(ep, pendingListeners, [], target);
|
|
1936
|
+
}
|
|
1937
|
+
function throwIfProxyReleased(isReleased) {
|
|
1938
|
+
if (isReleased) {
|
|
1939
|
+
throw new Error("Proxy has been released and is not useable");
|
|
1940
|
+
}
|
|
1941
|
+
}
|
|
1942
|
+
function releaseEndpoint(ep) {
|
|
1943
|
+
return requestResponseMessage(ep, /* @__PURE__ */ new Map(), {
|
|
1944
|
+
type: "RELEASE"
|
|
1945
|
+
}).then(() => {
|
|
1946
|
+
closeEndPoint(ep);
|
|
1947
|
+
});
|
|
1948
|
+
}
|
|
1949
|
+
const proxyCounter = /* @__PURE__ */ new WeakMap();
|
|
1950
|
+
const proxyFinalizers = "FinalizationRegistry" in globalThis && new FinalizationRegistry((ep) => {
|
|
1951
|
+
const newCount = (proxyCounter.get(ep) || 0) - 1;
|
|
1952
|
+
proxyCounter.set(ep, newCount);
|
|
1953
|
+
if (newCount === 0) {
|
|
1954
|
+
releaseEndpoint(ep);
|
|
1955
|
+
}
|
|
1956
|
+
});
|
|
1957
|
+
function registerProxy(proxy2, ep) {
|
|
1958
|
+
const newCount = (proxyCounter.get(ep) || 0) + 1;
|
|
1959
|
+
proxyCounter.set(ep, newCount);
|
|
1960
|
+
if (proxyFinalizers) {
|
|
1961
|
+
proxyFinalizers.register(proxy2, ep, proxy2);
|
|
1962
|
+
}
|
|
1963
|
+
}
|
|
1964
|
+
function unregisterProxy(proxy2) {
|
|
1965
|
+
if (proxyFinalizers) {
|
|
1966
|
+
proxyFinalizers.unregister(proxy2);
|
|
1967
|
+
}
|
|
1968
|
+
}
|
|
1969
|
+
function createProxy(ep, pendingListeners, path = [], target = function() {
|
|
1970
|
+
}) {
|
|
1971
|
+
let isProxyReleased = false;
|
|
1972
|
+
const proxy2 = new Proxy(target, {
|
|
1973
|
+
get(_target, prop) {
|
|
1974
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1975
|
+
if (prop === releaseProxy) {
|
|
1976
|
+
return () => {
|
|
1977
|
+
unregisterProxy(proxy2);
|
|
1978
|
+
releaseEndpoint(ep);
|
|
1979
|
+
pendingListeners.clear();
|
|
1980
|
+
isProxyReleased = true;
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
if (prop === "then") {
|
|
1984
|
+
if (path.length === 0) {
|
|
1985
|
+
return { then: () => proxy2 };
|
|
1986
|
+
}
|
|
1987
|
+
const r = requestResponseMessage(ep, pendingListeners, {
|
|
1988
|
+
type: "GET",
|
|
1989
|
+
path: path.map((p) => p.toString())
|
|
1990
|
+
}).then(fromWireValue);
|
|
1991
|
+
return r.then.bind(r);
|
|
1992
|
+
}
|
|
1993
|
+
return createProxy(ep, pendingListeners, [...path, prop]);
|
|
1994
|
+
},
|
|
1995
|
+
set(_target, prop, rawValue) {
|
|
1996
|
+
throwIfProxyReleased(isProxyReleased);
|
|
1997
|
+
const [value, transferables] = toWireValue(rawValue);
|
|
1998
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
1999
|
+
type: "SET",
|
|
2000
|
+
path: [...path, prop].map((p) => p.toString()),
|
|
2001
|
+
value
|
|
2002
|
+
}, transferables).then(fromWireValue);
|
|
2003
|
+
},
|
|
2004
|
+
apply(_target, _thisArg, rawArgumentList) {
|
|
2005
|
+
throwIfProxyReleased(isProxyReleased);
|
|
2006
|
+
const last = path[path.length - 1];
|
|
2007
|
+
if (last === createEndpoint) {
|
|
2008
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
2009
|
+
type: "ENDPOINT"
|
|
2010
|
+
}).then(fromWireValue);
|
|
2011
|
+
}
|
|
2012
|
+
if (last === "bind") {
|
|
2013
|
+
return createProxy(ep, pendingListeners, path.slice(0, -1));
|
|
2014
|
+
}
|
|
2015
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
2016
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
2017
|
+
type: "APPLY",
|
|
2018
|
+
path: path.map((p) => p.toString()),
|
|
2019
|
+
argumentList
|
|
2020
|
+
}, transferables).then(fromWireValue);
|
|
2021
|
+
},
|
|
2022
|
+
construct(_target, rawArgumentList) {
|
|
2023
|
+
throwIfProxyReleased(isProxyReleased);
|
|
2024
|
+
const [argumentList, transferables] = processArguments(rawArgumentList);
|
|
2025
|
+
return requestResponseMessage(ep, pendingListeners, {
|
|
2026
|
+
type: "CONSTRUCT",
|
|
2027
|
+
path: path.map((p) => p.toString()),
|
|
2028
|
+
argumentList
|
|
2029
|
+
}, transferables).then(fromWireValue);
|
|
2030
|
+
}
|
|
2031
|
+
});
|
|
2032
|
+
registerProxy(proxy2, ep);
|
|
2033
|
+
return proxy2;
|
|
2034
|
+
}
|
|
2035
|
+
function myFlat(arr) {
|
|
2036
|
+
return Array.prototype.concat.apply([], arr);
|
|
2037
|
+
}
|
|
2038
|
+
function processArguments(argumentList) {
|
|
2039
|
+
const processed = argumentList.map(toWireValue);
|
|
2040
|
+
return [processed.map((v) => v[0]), myFlat(processed.map((v) => v[1]))];
|
|
2041
|
+
}
|
|
2042
|
+
const transferCache = /* @__PURE__ */ new WeakMap();
|
|
2043
|
+
function transfer(obj, transfers) {
|
|
2044
|
+
transferCache.set(obj, transfers);
|
|
2045
|
+
return obj;
|
|
2046
|
+
}
|
|
2047
|
+
function proxy(obj) {
|
|
2048
|
+
return Object.assign(obj, { [proxyMarker]: true });
|
|
2049
|
+
}
|
|
2050
|
+
function toWireValue(value) {
|
|
2051
|
+
for (const [name, handler] of transferHandlers) {
|
|
2052
|
+
if (handler.canHandle(value)) {
|
|
2053
|
+
const [serializedValue, transferables] = handler.serialize(value);
|
|
2054
|
+
return [
|
|
2055
|
+
{
|
|
2056
|
+
type: "HANDLER",
|
|
2057
|
+
name,
|
|
2058
|
+
value: serializedValue
|
|
2059
|
+
},
|
|
2060
|
+
transferables
|
|
2061
|
+
];
|
|
2062
|
+
}
|
|
2063
|
+
}
|
|
2064
|
+
return [
|
|
2065
|
+
{
|
|
2066
|
+
type: "RAW",
|
|
2067
|
+
value
|
|
2068
|
+
},
|
|
2069
|
+
transferCache.get(value) || []
|
|
2070
|
+
];
|
|
2071
|
+
}
|
|
2072
|
+
function fromWireValue(value) {
|
|
2073
|
+
switch (value.type) {
|
|
2074
|
+
case "HANDLER":
|
|
2075
|
+
return transferHandlers.get(value.name).deserialize(value.value);
|
|
2076
|
+
case "RAW":
|
|
2077
|
+
return value.value;
|
|
2078
|
+
}
|
|
2079
|
+
}
|
|
2080
|
+
function requestResponseMessage(ep, pendingListeners, msg, transfers) {
|
|
2081
|
+
return new Promise((resolve) => {
|
|
2082
|
+
const id = generateUUID();
|
|
2083
|
+
pendingListeners.set(id, resolve);
|
|
2084
|
+
if (ep.start) {
|
|
2085
|
+
ep.start();
|
|
2086
|
+
}
|
|
2087
|
+
ep.postMessage(Object.assign({ id }, msg), transfers);
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
function generateUUID() {
|
|
2091
|
+
return new Array(4).fill(0).map(() => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString(16)).join("-");
|
|
2092
|
+
}
|
|
2093
|
+
function onParentPort(onPort) {
|
|
2094
|
+
let activePort = null;
|
|
2095
|
+
const onInit = (ev) => {
|
|
2096
|
+
if (!ALLOWED_PARENT_ORIGINS.includes(ev.origin)) return;
|
|
2097
|
+
if (ev.data !== INIT_MESSAGE_TYPE) return;
|
|
2098
|
+
const port = ev.ports[0];
|
|
2099
|
+
if (!port) return;
|
|
2100
|
+
window.removeEventListener("message", onInit);
|
|
2101
|
+
activePort = port;
|
|
2102
|
+
onPort(port);
|
|
2103
|
+
};
|
|
2104
|
+
window.addEventListener("message", onInit);
|
|
2105
|
+
try {
|
|
2106
|
+
window.parent.postMessage(READY_MESSAGE_TYPE, "*");
|
|
2107
|
+
} catch {
|
|
2108
|
+
}
|
|
2109
|
+
return {
|
|
2110
|
+
dispose() {
|
|
2111
|
+
window.removeEventListener("message", onInit);
|
|
2112
|
+
activePort?.close();
|
|
2113
|
+
activePort = null;
|
|
2114
|
+
}
|
|
2115
|
+
};
|
|
2116
|
+
}
|
|
2117
|
+
function exposeRpc(rpc) {
|
|
2118
|
+
return onParentPort((port) => {
|
|
2119
|
+
expose(rpc, port);
|
|
2120
|
+
});
|
|
2121
|
+
}
|
|
2122
|
+
function wrapParentRpc() {
|
|
2123
|
+
let api2 = null;
|
|
2124
|
+
const runtime = onParentPort((port) => {
|
|
2125
|
+
port.start();
|
|
2126
|
+
api2 = wrap(port);
|
|
2127
|
+
});
|
|
2128
|
+
return {
|
|
2129
|
+
getApi: () => api2,
|
|
2130
|
+
dispose() {
|
|
2131
|
+
runtime.dispose?.();
|
|
2132
|
+
api2 = null;
|
|
2133
|
+
}
|
|
2134
|
+
};
|
|
2135
|
+
}
|
|
2136
|
+
function querySpot(doc, selector) {
|
|
2137
|
+
try {
|
|
2138
|
+
const nodes = doc.querySelectorAll(selector);
|
|
2139
|
+
return { element: nodes[0] ?? null, matchCount: nodes.length };
|
|
2140
|
+
} catch {
|
|
2141
|
+
return null;
|
|
2142
|
+
}
|
|
2143
|
+
}
|
|
2144
|
+
function ensureShadowRoot(host) {
|
|
2145
|
+
if (host.shadowRoot) return { ok: true, shadow: host.shadowRoot };
|
|
2146
|
+
try {
|
|
2147
|
+
return { ok: true, shadow: host.attachShadow({ mode: "open" }) };
|
|
2148
|
+
} catch (err) {
|
|
2149
|
+
return { ok: false, name: err instanceof Error ? err.name : "" };
|
|
2150
|
+
}
|
|
2151
|
+
}
|
|
2152
|
+
function classifyShadowError(name) {
|
|
2153
|
+
switch (name) {
|
|
2154
|
+
case "NotSupportedError":
|
|
2155
|
+
return "unsupported_element";
|
|
2156
|
+
case "InvalidStateError":
|
|
2157
|
+
return "already_has_shadow";
|
|
2158
|
+
default:
|
|
2159
|
+
return "injection_error";
|
|
2160
|
+
}
|
|
2161
|
+
}
|
|
2162
|
+
function applySpot(doc, spot) {
|
|
2163
|
+
const query = querySpot(doc, spot.selector);
|
|
2164
|
+
if (!query) {
|
|
2165
|
+
return { selector: spot.selector, success: false, reason: "invalid_spot" };
|
|
2166
|
+
}
|
|
2167
|
+
if (!query.element) {
|
|
2168
|
+
return {
|
|
2169
|
+
selector: spot.selector,
|
|
2170
|
+
success: false,
|
|
2171
|
+
reason: "not_found",
|
|
2172
|
+
matchCount: 0
|
|
2173
|
+
};
|
|
2174
|
+
}
|
|
2175
|
+
const shadowResult = ensureShadowRoot(query.element);
|
|
2176
|
+
if (!shadowResult.ok) {
|
|
2177
|
+
return {
|
|
2178
|
+
selector: spot.selector,
|
|
2179
|
+
success: false,
|
|
2180
|
+
reason: classifyShadowError(shadowResult.name),
|
|
2181
|
+
matchCount: query.matchCount
|
|
2182
|
+
};
|
|
2183
|
+
}
|
|
2184
|
+
const shadow = shadowResult.shadow;
|
|
2185
|
+
try {
|
|
2186
|
+
shadow.replaceChildren();
|
|
2187
|
+
if (spot.css) {
|
|
2188
|
+
const style = doc.createElement("style");
|
|
2189
|
+
style.textContent = spot.css;
|
|
2190
|
+
shadow.appendChild(style);
|
|
2191
|
+
}
|
|
2192
|
+
if (spot.html) {
|
|
2193
|
+
const wrapper = doc.createElement("div");
|
|
2194
|
+
wrapper.innerHTML = spot.html;
|
|
2195
|
+
shadow.appendChild(wrapper);
|
|
2196
|
+
}
|
|
2197
|
+
return {
|
|
2198
|
+
selector: spot.selector,
|
|
2199
|
+
success: true,
|
|
2200
|
+
matchCount: query.matchCount
|
|
2201
|
+
};
|
|
2202
|
+
} catch {
|
|
2203
|
+
return {
|
|
2204
|
+
selector: spot.selector,
|
|
2205
|
+
success: false,
|
|
2206
|
+
reason: "injection_error",
|
|
2207
|
+
matchCount: query.matchCount
|
|
2208
|
+
};
|
|
2209
|
+
}
|
|
2210
|
+
}
|
|
2211
|
+
function removeSpot(doc, ref) {
|
|
2212
|
+
let host;
|
|
2213
|
+
try {
|
|
2214
|
+
host = doc.querySelector(ref.selector);
|
|
2215
|
+
} catch {
|
|
2216
|
+
return;
|
|
2217
|
+
}
|
|
2218
|
+
const shadow = host?.shadowRoot;
|
|
2219
|
+
if (!shadow) return;
|
|
2220
|
+
shadow.replaceChildren(doc.createElement("slot"));
|
|
2221
|
+
}
|
|
2222
|
+
function validateSpot(value) {
|
|
2223
|
+
if (!value || typeof value !== "object") {
|
|
2224
|
+
return { ok: false, reason: `not an object (${typeof value})` };
|
|
2225
|
+
}
|
|
2226
|
+
const v = value;
|
|
2227
|
+
if (typeof v["selector"] !== "string") {
|
|
2228
|
+
return {
|
|
2229
|
+
ok: false,
|
|
2230
|
+
reason: `selector not a string (${typeof v["selector"]})`
|
|
2231
|
+
};
|
|
2232
|
+
}
|
|
2233
|
+
if (v["selector"].length === 0) {
|
|
2234
|
+
return { ok: false, reason: "selector empty" };
|
|
2235
|
+
}
|
|
2236
|
+
if (v["html"] !== void 0 && typeof v["html"] !== "string") {
|
|
2237
|
+
return { ok: false, reason: `html not a string (${typeof v["html"]})` };
|
|
2238
|
+
}
|
|
2239
|
+
if (v["css"] !== void 0 && typeof v["css"] !== "string") {
|
|
2240
|
+
return { ok: false, reason: `css not a string (${typeof v["css"]})` };
|
|
2241
|
+
}
|
|
2242
|
+
return { ok: true, spot: value };
|
|
2243
|
+
}
|
|
2244
|
+
function isSpotRef(value) {
|
|
2245
|
+
if (!value || typeof value !== "object") return false;
|
|
2246
|
+
const sel = value.selector;
|
|
2247
|
+
return typeof sel === "string" && sel.length > 0;
|
|
2248
|
+
}
|
|
2249
|
+
function getSelector(value) {
|
|
2250
|
+
if (value && typeof value === "object" && "selector" in value) {
|
|
2251
|
+
return value.selector;
|
|
2252
|
+
}
|
|
2253
|
+
return null;
|
|
2254
|
+
}
|
|
2255
|
+
function buildRpc(log) {
|
|
2256
|
+
return {
|
|
2257
|
+
async applySpots(spots) {
|
|
2258
|
+
invariant$1(
|
|
2259
|
+
Array.isArray(spots),
|
|
2260
|
+
"pagePersonalize/preview: applySpots requires an array"
|
|
2261
|
+
);
|
|
2262
|
+
return spots.map((entry, i) => {
|
|
2263
|
+
const validated = validateSpot(entry);
|
|
2264
|
+
if (!validated.ok) {
|
|
2265
|
+
log.warn(
|
|
2266
|
+
`pagePersonalize/preview: applySpots[${i}] invalid_spot: ${validated.reason}`
|
|
2267
|
+
);
|
|
2268
|
+
return {
|
|
2269
|
+
selector: getSelector(entry),
|
|
2270
|
+
success: false,
|
|
2271
|
+
reason: "invalid_spot"
|
|
2272
|
+
};
|
|
2273
|
+
}
|
|
2274
|
+
const result = applySpot(document, validated.spot);
|
|
2275
|
+
if (!result.success) {
|
|
2276
|
+
log.warn(
|
|
2277
|
+
`pagePersonalize/preview: applySpot "${result.selector}" -> ${result.reason}` + (result.matchCount !== void 0 ? ` (matchCount=${result.matchCount})` : "")
|
|
2278
|
+
);
|
|
2279
|
+
}
|
|
2280
|
+
return result;
|
|
2281
|
+
});
|
|
2282
|
+
},
|
|
2283
|
+
async removeSpots(spots) {
|
|
2284
|
+
invariant$1(
|
|
2285
|
+
Array.isArray(spots),
|
|
2286
|
+
"pagePersonalize/preview: removeSpots requires an array"
|
|
2287
|
+
);
|
|
2288
|
+
for (let i = 0; i < spots.length; i++) {
|
|
2289
|
+
const entry = spots[i];
|
|
2290
|
+
if (!isSpotRef(entry)) {
|
|
2291
|
+
log.warn(
|
|
2292
|
+
`pagePersonalize/preview: removeSpots[${i}] skipped malformed ref`
|
|
2293
|
+
);
|
|
2294
|
+
continue;
|
|
2295
|
+
}
|
|
2296
|
+
removeSpot(document, entry);
|
|
2297
|
+
}
|
|
2298
|
+
}
|
|
2299
|
+
};
|
|
2300
|
+
}
|
|
2301
|
+
const previewHandler = {
|
|
2302
|
+
mode: "preview",
|
|
2303
|
+
activate(core) {
|
|
2304
|
+
return exposeRpc(buildRpc(core.log));
|
|
2305
|
+
}
|
|
2306
|
+
};
|
|
2307
|
+
const UNSTABLE_ID_PATTERNS = [
|
|
2308
|
+
/^[0-9]+$/,
|
|
2309
|
+
// numeric-only
|
|
2310
|
+
/^:r/,
|
|
2311
|
+
// React :r IDs
|
|
2312
|
+
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i
|
|
2313
|
+
// UUIDs
|
|
2314
|
+
];
|
|
2315
|
+
const UNSTABLE_DATA_VALUE_PATTERNS = [
|
|
2316
|
+
/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/i,
|
|
2317
|
+
// UUIDs
|
|
2318
|
+
/^[a-z0-9]{20,}$/i
|
|
2319
|
+
// long token-like strings
|
|
2320
|
+
];
|
|
2321
|
+
const UNSTABLE_CLASS_PATTERNS = [
|
|
2322
|
+
/^css-/,
|
|
2323
|
+
// CSS-in-JS (emotion, etc.)
|
|
2324
|
+
/^sc-/,
|
|
2325
|
+
// styled-components
|
|
2326
|
+
/^emotion-/,
|
|
2327
|
+
/^[a-zA-Z0-9]{5,}$/
|
|
2328
|
+
// random 5+ char alphanum (likely generated)
|
|
2329
|
+
];
|
|
2330
|
+
const SEMANTIC_TAGS = [
|
|
2331
|
+
"main",
|
|
2332
|
+
"nav",
|
|
2333
|
+
"header",
|
|
2334
|
+
"footer",
|
|
2335
|
+
"aside",
|
|
2336
|
+
"article",
|
|
2337
|
+
"section"
|
|
2338
|
+
];
|
|
2339
|
+
const ARIA_LANDMARK_ROLES = [
|
|
2340
|
+
"banner",
|
|
2341
|
+
"complementary",
|
|
2342
|
+
"contentinfo",
|
|
2343
|
+
"form",
|
|
2344
|
+
"main",
|
|
2345
|
+
"navigation",
|
|
2346
|
+
"region",
|
|
2347
|
+
"search"
|
|
2348
|
+
];
|
|
2349
|
+
function isStableId(id) {
|
|
2350
|
+
return !UNSTABLE_ID_PATTERNS.some((pattern) => pattern.test(id));
|
|
2351
|
+
}
|
|
2352
|
+
function isStableDataValue(value) {
|
|
2353
|
+
return !UNSTABLE_DATA_VALUE_PATTERNS.some((pattern) => pattern.test(value));
|
|
2354
|
+
}
|
|
2355
|
+
function isStableClass(className) {
|
|
2356
|
+
if (className.startsWith("p13n-sdk-")) return false;
|
|
2357
|
+
return !UNSTABLE_CLASS_PATTERNS.some((pattern) => pattern.test(className));
|
|
2358
|
+
}
|
|
2359
|
+
function isUnique(selector) {
|
|
2360
|
+
return document.querySelectorAll(selector).length === 1;
|
|
2361
|
+
}
|
|
2362
|
+
function validate(selector, element) {
|
|
2363
|
+
try {
|
|
2364
|
+
return document.querySelector(selector) === element;
|
|
2365
|
+
} catch {
|
|
2366
|
+
return false;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
function getTagName(element) {
|
|
2370
|
+
return element.localName;
|
|
2371
|
+
}
|
|
2372
|
+
function tryDirectAnchor(element) {
|
|
2373
|
+
if (element.id && isStableId(element.id)) {
|
|
2374
|
+
const selector = `#${CSS.escape(element.id)}`;
|
|
2375
|
+
if (validate(selector, element)) return selector;
|
|
2376
|
+
}
|
|
2377
|
+
for (const attr of element.attributes) {
|
|
2378
|
+
if (attr.name.startsWith("data-") && attr.value && isStableDataValue(attr.value)) {
|
|
2379
|
+
const selector = `[${CSS.escape(attr.name)}="${CSS.escape(attr.value)}"]`;
|
|
2380
|
+
if (isUnique(selector) && validate(selector, element)) return selector;
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
for (const cls of element.classList) {
|
|
2384
|
+
if (isStableClass(cls)) {
|
|
2385
|
+
const selector = `.${CSS.escape(cls)}`;
|
|
2386
|
+
if (isUnique(selector) && validate(selector, element)) return selector;
|
|
2387
|
+
}
|
|
2388
|
+
}
|
|
2389
|
+
const tag = getTagName(element);
|
|
2390
|
+
for (const cls of element.classList) {
|
|
2391
|
+
if (isStableClass(cls)) {
|
|
2392
|
+
const selector = `${tag}.${CSS.escape(cls)}`;
|
|
2393
|
+
if (isUnique(selector) && validate(selector, element)) return selector;
|
|
2394
|
+
}
|
|
2395
|
+
}
|
|
2396
|
+
const role = element.getAttribute("role");
|
|
2397
|
+
if (role && ARIA_LANDMARK_ROLES.includes(role)) {
|
|
2398
|
+
const selector = `[role="${role}"]`;
|
|
2399
|
+
if (isUnique(selector) && validate(selector, element)) return selector;
|
|
2400
|
+
}
|
|
2401
|
+
if (SEMANTIC_TAGS.includes(tag)) {
|
|
2402
|
+
if (isUnique(tag) && validate(tag, element)) return tag;
|
|
2403
|
+
}
|
|
2404
|
+
return null;
|
|
2405
|
+
}
|
|
2406
|
+
function getNthOfTypeIndex(element) {
|
|
2407
|
+
const tag = getTagName(element);
|
|
2408
|
+
let index = 1;
|
|
2409
|
+
let sibling = element.previousElementSibling;
|
|
2410
|
+
while (sibling) {
|
|
2411
|
+
if (sibling.localName === tag) index++;
|
|
2412
|
+
sibling = sibling.previousElementSibling;
|
|
2413
|
+
}
|
|
2414
|
+
return index;
|
|
2415
|
+
}
|
|
2416
|
+
function buildRelativePath(from, to) {
|
|
2417
|
+
const parts = [];
|
|
2418
|
+
let current = to;
|
|
2419
|
+
while (current && current !== from) {
|
|
2420
|
+
const tag = getTagName(current);
|
|
2421
|
+
const index = getNthOfTypeIndex(current);
|
|
2422
|
+
parts.unshift(`${tag}:nth-of-type(${index})`);
|
|
2423
|
+
current = current.parentElement;
|
|
2424
|
+
}
|
|
2425
|
+
return parts.join(" > ");
|
|
2426
|
+
}
|
|
2427
|
+
function tryAnchoredPath(element) {
|
|
2428
|
+
let ancestor = element.parentElement;
|
|
2429
|
+
while (ancestor && ancestor !== document.documentElement) {
|
|
2430
|
+
const anchorSelector = tryDirectAnchor(ancestor);
|
|
2431
|
+
if (anchorSelector) {
|
|
2432
|
+
const relativePath = buildRelativePath(ancestor, element);
|
|
2433
|
+
const selector = `${anchorSelector} > ${relativePath}`;
|
|
2434
|
+
if (validate(selector, element)) return selector;
|
|
2435
|
+
}
|
|
2436
|
+
ancestor = ancestor.parentElement;
|
|
2437
|
+
}
|
|
2438
|
+
return null;
|
|
2439
|
+
}
|
|
2440
|
+
function buildFullPath(element) {
|
|
2441
|
+
const parts = [];
|
|
2442
|
+
let current = element;
|
|
2443
|
+
while (current && current !== document.documentElement) {
|
|
2444
|
+
const tag = getTagName(current);
|
|
2445
|
+
const index = getNthOfTypeIndex(current);
|
|
2446
|
+
parts.unshift(`${tag}:nth-of-type(${index})`);
|
|
2447
|
+
current = current.parentElement;
|
|
2448
|
+
}
|
|
2449
|
+
const selector = `html > ${parts.join(" > ")}`;
|
|
2450
|
+
if (validate(selector, element)) return selector;
|
|
2451
|
+
return null;
|
|
2452
|
+
}
|
|
2453
|
+
function generateSelector(element) {
|
|
2454
|
+
if (!element || element === document.documentElement || element === document.body) {
|
|
2455
|
+
return element === document.body ? "body" : "html";
|
|
2456
|
+
}
|
|
2457
|
+
const direct = tryDirectAnchor(element);
|
|
2458
|
+
if (direct) return direct;
|
|
2459
|
+
const anchored = tryAnchoredPath(element);
|
|
2460
|
+
if (anchored) return anchored;
|
|
2461
|
+
return buildFullPath(element) ?? element.localName;
|
|
2462
|
+
}
|
|
2463
|
+
const SDK_ATTR = "data-p13n-sdk";
|
|
2464
|
+
const HIGHLIGHT_CLASS = "p13n-sdk-highlight";
|
|
2465
|
+
const SUPPRESSED_EVENTS = [
|
|
2466
|
+
"mousedown",
|
|
2467
|
+
"mouseup",
|
|
2468
|
+
"pointerdown",
|
|
2469
|
+
"pointerup",
|
|
2470
|
+
"keydown",
|
|
2471
|
+
"keyup",
|
|
2472
|
+
"focusin",
|
|
2473
|
+
"submit"
|
|
2474
|
+
];
|
|
2475
|
+
const INJECTED_CSS = `
|
|
2476
|
+
.${HIGHLIGHT_CLASS} {
|
|
2477
|
+
outline: 2px solid blue !important;
|
|
2478
|
+
outline-offset: -2px !important;
|
|
2479
|
+
cursor: crosshair !important;
|
|
2480
|
+
}
|
|
2481
|
+
.p13n-sdk-tooltip {
|
|
2482
|
+
position: fixed;
|
|
2483
|
+
z-index: 2147483647;
|
|
2484
|
+
background: rgba(0, 0, 0, 0.8);
|
|
2485
|
+
color: #fff;
|
|
2486
|
+
font-family: monospace;
|
|
2487
|
+
font-size: 12px;
|
|
2488
|
+
padding: 4px 8px;
|
|
2489
|
+
border-radius: 4px;
|
|
2490
|
+
pointer-events: none;
|
|
2491
|
+
white-space: nowrap;
|
|
2492
|
+
}
|
|
2493
|
+
`;
|
|
2494
|
+
function isSdkElement(target) {
|
|
2495
|
+
let current = target;
|
|
2496
|
+
while (current) {
|
|
2497
|
+
if (current.hasAttribute && current.hasAttribute(SDK_ATTR)) return true;
|
|
2498
|
+
current = current.parentElement;
|
|
2499
|
+
}
|
|
2500
|
+
return false;
|
|
2501
|
+
}
|
|
2502
|
+
function getElementDimensions(element) {
|
|
2503
|
+
if (element.offsetWidth !== 0) {
|
|
2504
|
+
return { width: element.offsetWidth, height: element.offsetHeight };
|
|
2505
|
+
}
|
|
2506
|
+
const rect = element.getBoundingClientRect();
|
|
2507
|
+
return { width: Math.round(rect.width), height: Math.round(rect.height) };
|
|
2508
|
+
}
|
|
2509
|
+
function createSelectionRuntime(onSelect) {
|
|
2510
|
+
let highlightedElement = null;
|
|
2511
|
+
const style = document.createElement("style");
|
|
2512
|
+
style.setAttribute(SDK_ATTR, "");
|
|
2513
|
+
style.textContent = INJECTED_CSS;
|
|
2514
|
+
document.head.appendChild(style);
|
|
2515
|
+
const tooltip = document.createElement("div");
|
|
2516
|
+
tooltip.className = "p13n-sdk-tooltip";
|
|
2517
|
+
tooltip.setAttribute(SDK_ATTR, "");
|
|
2518
|
+
tooltip.style.display = "none";
|
|
2519
|
+
document.body.appendChild(tooltip);
|
|
2520
|
+
function positionTooltip(event) {
|
|
2521
|
+
const offset = 15;
|
|
2522
|
+
let x = event.clientX + offset;
|
|
2523
|
+
let y = event.clientY + offset;
|
|
2524
|
+
const tooltipRect = tooltip.getBoundingClientRect();
|
|
2525
|
+
const tooltipWidth = tooltipRect.width || 150;
|
|
2526
|
+
const tooltipHeight = tooltipRect.height || 24;
|
|
2527
|
+
if (x + tooltipWidth > window.innerWidth) {
|
|
2528
|
+
x = event.clientX - offset - tooltipWidth;
|
|
2529
|
+
}
|
|
2530
|
+
if (y + tooltipHeight > window.innerHeight) {
|
|
2531
|
+
y = event.clientY - offset - tooltipHeight;
|
|
2532
|
+
}
|
|
2533
|
+
tooltip.style.left = `${x}px`;
|
|
2534
|
+
tooltip.style.top = `${y}px`;
|
|
2535
|
+
}
|
|
2536
|
+
function onMouseOver(event) {
|
|
2537
|
+
const target = event.target;
|
|
2538
|
+
if (!(target instanceof HTMLElement)) return;
|
|
2539
|
+
if (isSdkElement(target)) return;
|
|
2540
|
+
if (highlightedElement && highlightedElement !== target) {
|
|
2541
|
+
highlightedElement.classList.remove(HIGHLIGHT_CLASS);
|
|
2542
|
+
}
|
|
2543
|
+
highlightedElement = target;
|
|
2544
|
+
target.classList.add(HIGHLIGHT_CLASS);
|
|
2545
|
+
const tag = target.localName;
|
|
2546
|
+
const { width, height } = getElementDimensions(target);
|
|
2547
|
+
tooltip.textContent = `${tag} ${width}×${height}`;
|
|
2548
|
+
tooltip.style.display = "block";
|
|
2549
|
+
positionTooltip(event);
|
|
2550
|
+
}
|
|
2551
|
+
function onMouseMove(event) {
|
|
2552
|
+
if (tooltip.style.display === "block") {
|
|
2553
|
+
positionTooltip(event);
|
|
2554
|
+
}
|
|
2555
|
+
}
|
|
2556
|
+
function onMouseOut(event) {
|
|
2557
|
+
const target = event.target;
|
|
2558
|
+
if (!(target instanceof HTMLElement)) return;
|
|
2559
|
+
if (isSdkElement(target)) return;
|
|
2560
|
+
if (highlightedElement === target) {
|
|
2561
|
+
target.classList.remove(HIGHLIGHT_CLASS);
|
|
2562
|
+
highlightedElement = null;
|
|
2563
|
+
}
|
|
2564
|
+
tooltip.style.display = "none";
|
|
2565
|
+
}
|
|
2566
|
+
function suppressEvent(event) {
|
|
2567
|
+
if (isSdkElement(event.target)) return;
|
|
2568
|
+
event.preventDefault();
|
|
2569
|
+
event.stopPropagation();
|
|
2570
|
+
event.stopImmediatePropagation();
|
|
2571
|
+
}
|
|
2572
|
+
function onClick(event) {
|
|
2573
|
+
const target = event.target;
|
|
2574
|
+
if (!(target instanceof HTMLElement)) return;
|
|
2575
|
+
suppressEvent(event);
|
|
2576
|
+
const selector = generateSelector(target);
|
|
2577
|
+
onSelect(selector);
|
|
2578
|
+
}
|
|
2579
|
+
function attachListeners() {
|
|
2580
|
+
document.addEventListener("mouseover", onMouseOver, true);
|
|
2581
|
+
document.addEventListener("mousemove", onMouseMove, true);
|
|
2582
|
+
document.addEventListener("mouseout", onMouseOut, true);
|
|
2583
|
+
document.addEventListener("click", onClick, true);
|
|
2584
|
+
for (const eventType of SUPPRESSED_EVENTS) {
|
|
2585
|
+
document.addEventListener(eventType, suppressEvent, true);
|
|
2586
|
+
}
|
|
2587
|
+
}
|
|
2588
|
+
function detachListeners() {
|
|
2589
|
+
document.removeEventListener("mouseover", onMouseOver, true);
|
|
2590
|
+
document.removeEventListener("mousemove", onMouseMove, true);
|
|
2591
|
+
document.removeEventListener("mouseout", onMouseOut, true);
|
|
2592
|
+
document.removeEventListener("click", onClick, true);
|
|
2593
|
+
for (const eventType of SUPPRESSED_EVENTS) {
|
|
2594
|
+
document.removeEventListener(eventType, suppressEvent, true);
|
|
2595
|
+
}
|
|
2596
|
+
}
|
|
2597
|
+
function clearHighlightState() {
|
|
2598
|
+
if (highlightedElement) {
|
|
2599
|
+
highlightedElement.classList.remove(HIGHLIGHT_CLASS);
|
|
2600
|
+
highlightedElement = null;
|
|
2601
|
+
}
|
|
2602
|
+
tooltip.style.display = "none";
|
|
2603
|
+
}
|
|
2604
|
+
attachListeners();
|
|
2605
|
+
return {
|
|
2606
|
+
dispose() {
|
|
2607
|
+
detachListeners();
|
|
2608
|
+
clearHighlightState();
|
|
2609
|
+
tooltip.remove();
|
|
2610
|
+
style.remove();
|
|
2611
|
+
highlightedElement = null;
|
|
2612
|
+
}
|
|
2613
|
+
};
|
|
2614
|
+
}
|
|
2615
|
+
const spotSelectionHandler = {
|
|
2616
|
+
mode: "spot-selection",
|
|
2617
|
+
activate(core) {
|
|
2618
|
+
const bridge = wrapParentRpc();
|
|
2619
|
+
const runtime = createSelectionRuntime((selector) => {
|
|
2620
|
+
const api2 = bridge.getApi();
|
|
2621
|
+
if (api2) {
|
|
2622
|
+
api2.onSpotSelected(selector);
|
|
2623
|
+
} else {
|
|
2624
|
+
core.log.warn(
|
|
2625
|
+
"pagePersonalize/spot-selection: no parent RPC connection, cannot send selector"
|
|
2626
|
+
);
|
|
2627
|
+
}
|
|
2628
|
+
});
|
|
2629
|
+
return {
|
|
2630
|
+
dispose() {
|
|
2631
|
+
runtime.dispose?.();
|
|
2632
|
+
bridge.dispose?.();
|
|
2633
|
+
}
|
|
2634
|
+
};
|
|
2635
|
+
}
|
|
2636
|
+
};
|
|
2637
|
+
const MODE_HANDLERS = {
|
|
2638
|
+
preview: previewHandler,
|
|
2639
|
+
"spot-selection": spotSelectionHandler
|
|
2640
|
+
};
|
|
2641
|
+
function readMode() {
|
|
2642
|
+
if (typeof window === "undefined" || !window.location) return null;
|
|
2643
|
+
let raw_mode_param;
|
|
2644
|
+
try {
|
|
2645
|
+
raw_mode_param = new URLSearchParams(window.location.search).get(
|
|
2646
|
+
MODE_QUERY_PARAM
|
|
2647
|
+
);
|
|
2648
|
+
} catch {
|
|
2649
|
+
return null;
|
|
2650
|
+
}
|
|
2651
|
+
if (!raw_mode_param) return null;
|
|
2652
|
+
if (Object.hasOwn(MODE_HANDLERS, raw_mode_param))
|
|
2653
|
+
return raw_mode_param;
|
|
2654
|
+
return null;
|
|
2655
|
+
}
|
|
2656
|
+
function runRouter(core) {
|
|
2657
|
+
const mode = readMode();
|
|
2658
|
+
if (!mode) return null;
|
|
2659
|
+
let runtime;
|
|
2660
|
+
try {
|
|
2661
|
+
runtime = MODE_HANDLERS[mode].activate(core);
|
|
2662
|
+
} catch (err) {
|
|
2663
|
+
core.log.error(
|
|
2664
|
+
`pagePersonalize: activation failed for mode "${mode}":`,
|
|
2665
|
+
err
|
|
2666
|
+
);
|
|
2667
|
+
return null;
|
|
2668
|
+
}
|
|
2669
|
+
return runtime ? mode : null;
|
|
2670
|
+
}
|
|
2671
|
+
function numAttr(attrs, key) {
|
|
2672
|
+
const raw = attrs[key];
|
|
2673
|
+
if (typeof raw !== "string" || raw.length === 0) return null;
|
|
2674
|
+
const n = Number(raw);
|
|
2675
|
+
return Number.isFinite(n) ? n : null;
|
|
2676
|
+
}
|
|
2677
|
+
function strAttr(attrs, key) {
|
|
2678
|
+
const raw = attrs[key];
|
|
2679
|
+
return typeof raw === "string" && raw.length > 0 ? raw : null;
|
|
2680
|
+
}
|
|
2681
|
+
function isInWindow(attrs, now) {
|
|
2682
|
+
const start = numAttr(attrs, "td_personalization.campaigns_start_date");
|
|
2683
|
+
if (start !== null && now < start) return false;
|
|
2684
|
+
const end = numAttr(attrs, "td_personalization.campaigns_end_date");
|
|
2685
|
+
if (end !== null && now >= end) return false;
|
|
2686
|
+
return true;
|
|
2687
|
+
}
|
|
2688
|
+
function isLiveOffer(offer, now) {
|
|
2689
|
+
const attrs = offer.attributes;
|
|
2690
|
+
return !!attrs && typeof attrs === "object" && isInWindow(attrs, now);
|
|
2691
|
+
}
|
|
2692
|
+
function toScoredOffer(offer) {
|
|
2693
|
+
const attrs = offer.attributes;
|
|
2694
|
+
if (!attrs) return null;
|
|
2695
|
+
const rank = numAttr(attrs, "td_personalization.audience_rank");
|
|
2696
|
+
if (rank === null) return null;
|
|
2697
|
+
const updated = numAttr(attrs, "td_personalization.campaign_updated_at") ?? -Infinity;
|
|
2698
|
+
return { offer, updated, rank };
|
|
2699
|
+
}
|
|
2700
|
+
function maxBy(items, ranksAbove) {
|
|
2701
|
+
return items.reduce(
|
|
2702
|
+
(best, item) => best === null || ranksAbove(item, best) ? item : best,
|
|
2703
|
+
null
|
|
2704
|
+
);
|
|
2705
|
+
}
|
|
2706
|
+
function selectWinningOffer(payload, now = Date.now() / 1e3) {
|
|
2707
|
+
const offers = payload?.offers;
|
|
2708
|
+
if (!offers || typeof offers !== "object") return null;
|
|
2709
|
+
const candidates = Object.values(offers).filter((offer) => isLiveOffer(offer, now)).flatMap((offer) => toScoredOffer(offer) ?? []);
|
|
2710
|
+
const winner = maxBy(
|
|
2711
|
+
candidates,
|
|
2712
|
+
(a, b) => a.updated > b.updated || a.updated === b.updated && a.rank < b.rank
|
|
2713
|
+
);
|
|
2714
|
+
return winner?.offer ?? null;
|
|
2715
|
+
}
|
|
2716
|
+
function parseEntries(p13n) {
|
|
2717
|
+
if (typeof p13n !== "string") return null;
|
|
2718
|
+
try {
|
|
2719
|
+
const parsed = JSON.parse(p13n);
|
|
2720
|
+
return Array.isArray(parsed) ? parsed : null;
|
|
2721
|
+
} catch {
|
|
2722
|
+
return null;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
function toSpot(entry) {
|
|
2726
|
+
if (!entry || typeof entry !== "object") return null;
|
|
2727
|
+
const {
|
|
2728
|
+
css_selector: selector,
|
|
2729
|
+
html_value: html,
|
|
2730
|
+
css_value: css
|
|
2731
|
+
} = entry;
|
|
2732
|
+
if (typeof selector !== "string" || selector.length === 0) return null;
|
|
2733
|
+
if (typeof html !== "string") return null;
|
|
2734
|
+
if (typeof css !== "string") return null;
|
|
2735
|
+
return { selector, html, css };
|
|
2736
|
+
}
|
|
2737
|
+
function decodeEntry(entry, campaign) {
|
|
2738
|
+
const spot = toSpot(entry);
|
|
2739
|
+
if (!spot) return null;
|
|
2740
|
+
const id = entry.id;
|
|
2741
|
+
const creative = typeof id === "number" && Number.isFinite(id) ? String(id) : null;
|
|
2742
|
+
const impression = campaign && creative ? { campaign, creative } : null;
|
|
2743
|
+
return { spot, impression };
|
|
2744
|
+
}
|
|
2745
|
+
function decodeOffers(payload, now) {
|
|
2746
|
+
const offer = selectWinningOffer(payload, now);
|
|
2747
|
+
if (!offer) return [];
|
|
2748
|
+
const attrs = offer.attributes;
|
|
2749
|
+
const campaign = attrs ? strAttr(attrs, "td_personalization.campaign") : null;
|
|
2750
|
+
const entries = parseEntries(attrs?.["td_personalization.content"]);
|
|
2751
|
+
if (!entries) return [];
|
|
2752
|
+
return entries.flatMap((entry) => decodeEntry(entry, campaign) ?? []);
|
|
2753
|
+
}
|
|
2754
|
+
const PERSONALIZATION_DATABASE = "td_c360_personalization";
|
|
2755
|
+
const PERSONALIZATION_TABLE = "events";
|
|
2756
|
+
const CLICKABLE_SELECTOR = 'a, button, [role="button"], [role="link"]';
|
|
2757
|
+
const CAMPAIGN_ATTR = "data-td-personalization-campaign";
|
|
2758
|
+
const CREATIVE_ATTR = "data-td-personalization-creative";
|
|
2759
|
+
function pagePersonalize() {
|
|
2760
|
+
return {
|
|
2761
|
+
name: "pagePersonalize",
|
|
2762
|
+
setup(core, sdk) {
|
|
2763
|
+
const activeMode = runRouter(core);
|
|
2764
|
+
function reportEvent(event, ref) {
|
|
2765
|
+
const base = typeof sdk.getTrackValues === "function" ? sdk.getTrackValues() : {};
|
|
2766
|
+
sdk.addRecord(
|
|
2767
|
+
PERSONALIZATION_TABLE,
|
|
2768
|
+
{
|
|
2769
|
+
...base,
|
|
2770
|
+
td_event: event,
|
|
2771
|
+
td_personalization_campaign: ref.campaign,
|
|
2772
|
+
td_personalization_creative: ref.creative
|
|
2773
|
+
},
|
|
2774
|
+
void 0,
|
|
2775
|
+
void 0,
|
|
2776
|
+
{ database: PERSONALIZATION_DATABASE }
|
|
2777
|
+
);
|
|
2778
|
+
}
|
|
2779
|
+
function handleSpotClick(e) {
|
|
2780
|
+
const node = e.target;
|
|
2781
|
+
if (!(node instanceof Element) || !node.closest(CLICKABLE_SELECTOR)) {
|
|
2782
|
+
return;
|
|
2783
|
+
}
|
|
2784
|
+
const host = e.currentTarget.host;
|
|
2785
|
+
const campaign = host.getAttribute(CAMPAIGN_ATTR);
|
|
2786
|
+
const creative = host.getAttribute(CREATIVE_ATTR);
|
|
2787
|
+
if (campaign && creative) reportEvent("click", { campaign, creative });
|
|
2788
|
+
}
|
|
2789
|
+
function trackSpotClicks(selector, ref) {
|
|
2790
|
+
const host = document.querySelector(selector);
|
|
2791
|
+
if (!host?.shadowRoot) return;
|
|
2792
|
+
host.setAttribute(CAMPAIGN_ATTR, ref.campaign);
|
|
2793
|
+
host.setAttribute(CREATIVE_ATTR, ref.creative);
|
|
2794
|
+
host.shadowRoot.addEventListener("click", handleSpotClick);
|
|
2795
|
+
}
|
|
2796
|
+
function applyPersonalization(payload, options) {
|
|
2797
|
+
if (typeof document === "undefined") return;
|
|
2798
|
+
if (activeMode !== null && !options?.force) return;
|
|
2799
|
+
for (const { spot, impression } of decodeOffers(payload)) {
|
|
2800
|
+
const result = applySpot(document, spot);
|
|
2801
|
+
if (result.success && impression) {
|
|
2802
|
+
reportEvent("impression", impression);
|
|
2803
|
+
trackSpotClicks(spot.selector, impression);
|
|
2804
|
+
}
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
function personalizePage(config, data, successCallback, errorCallback) {
|
|
2808
|
+
if (activeMode !== null) {
|
|
2809
|
+
core.log.debug(
|
|
2810
|
+
`pagePersonalize: personalizePage suppressed in "${activeMode}" mode`
|
|
2811
|
+
);
|
|
2812
|
+
return;
|
|
2813
|
+
}
|
|
2814
|
+
const body = {};
|
|
2815
|
+
if (typeof document !== "undefined" && document.location) {
|
|
2816
|
+
body["td_url"] = document.location.href.split("#")[0];
|
|
2817
|
+
body["td_host"] = document.location.host;
|
|
2818
|
+
body["td_path"] = document.location.pathname;
|
|
2819
|
+
}
|
|
2820
|
+
Object.assign(body, data);
|
|
2821
|
+
sdk.fetchPersonalization(
|
|
2822
|
+
config,
|
|
2823
|
+
body,
|
|
2824
|
+
(response) => {
|
|
2825
|
+
const payload = response;
|
|
2826
|
+
applyPersonalization(payload);
|
|
2827
|
+
successCallback?.(payload);
|
|
2828
|
+
},
|
|
2829
|
+
errorCallback
|
|
2830
|
+
);
|
|
2831
|
+
}
|
|
2832
|
+
return { applyPersonalization, personalizePage };
|
|
2833
|
+
}
|
|
2834
|
+
};
|
|
2835
|
+
}
|
|
2836
|
+
function globalId() {
|
|
2837
|
+
return {
|
|
2838
|
+
name: "globalId",
|
|
2839
|
+
setup(core, sdk) {
|
|
2840
|
+
const config = core.config;
|
|
2841
|
+
const noop = () => {
|
|
2842
|
+
};
|
|
2843
|
+
function fetchGlobalID(success, error, forceFetch = false, options = {}) {
|
|
2844
|
+
const successCallback = success || noop;
|
|
2845
|
+
const errorCallback = error || noop;
|
|
2846
|
+
if (!sdk.inSignedMode()) {
|
|
2847
|
+
return errorCallback("not in signed in mode");
|
|
2848
|
+
}
|
|
2849
|
+
if (!sdk.isGlobalIdEnabled()) {
|
|
2850
|
+
return errorCallback("global id is not enabled");
|
|
2851
|
+
}
|
|
2852
|
+
const cookieName = config.globalIdCookie || "_td_global";
|
|
2853
|
+
const cachedGlobalId = cookie.getItem(cookieName);
|
|
2854
|
+
if (cachedGlobalId && !forceFetch) {
|
|
2855
|
+
setTimeout(() => successCallback(cachedGlobalId), 0);
|
|
2856
|
+
return;
|
|
2857
|
+
}
|
|
2858
|
+
const sameSite = options.sameSite || "None";
|
|
2859
|
+
const url = `https://${config.host}`;
|
|
2860
|
+
const headers = {
|
|
2861
|
+
Authorization: `TD1 ${config.writeKey}`,
|
|
2862
|
+
"Content-Type": globalIdAdlHeaders["Content-Type"],
|
|
2863
|
+
Accept: globalIdAdlHeaders["Accept"]
|
|
2864
|
+
};
|
|
2865
|
+
if (typeof navigator !== "undefined") {
|
|
2866
|
+
headers["User-Agent"] = navigator.userAgent;
|
|
2867
|
+
}
|
|
2868
|
+
api.get(url, { headers }).then((res) => {
|
|
2869
|
+
if (!res["global_id"]) {
|
|
2870
|
+
successCallback(null);
|
|
2871
|
+
return;
|
|
2872
|
+
}
|
|
2873
|
+
const globalIdValue = res["global_id"];
|
|
2874
|
+
const maxAge = options.maxAge ?? 6e3;
|
|
2875
|
+
cookie.setItem(
|
|
2876
|
+
cookieName,
|
|
2877
|
+
globalIdValue,
|
|
2878
|
+
maxAge,
|
|
2879
|
+
options.path,
|
|
2880
|
+
options.domain,
|
|
2881
|
+
options.secure,
|
|
2882
|
+
sameSite
|
|
2883
|
+
);
|
|
2884
|
+
successCallback(globalIdValue);
|
|
2885
|
+
}).catch((err) => {
|
|
2886
|
+
errorCallback(err);
|
|
2887
|
+
});
|
|
2888
|
+
}
|
|
2889
|
+
return { fetchGlobalID };
|
|
2890
|
+
}
|
|
2891
|
+
};
|
|
2892
|
+
}
|
|
2893
|
+
const LOADER_METHODS = [
|
|
2894
|
+
"set",
|
|
2895
|
+
"collectTags",
|
|
2896
|
+
"blockEvents",
|
|
2897
|
+
"unblockEvents",
|
|
2898
|
+
"setSignedMode",
|
|
2899
|
+
"setAnonymousMode",
|
|
2900
|
+
"fetchServerCookie",
|
|
2901
|
+
"fetchGlobalID",
|
|
2902
|
+
"fetchUserSegments",
|
|
2903
|
+
"fetchPersonalization",
|
|
2904
|
+
"resetUUID",
|
|
2905
|
+
"addRecord",
|
|
2906
|
+
"trackEvent",
|
|
2907
|
+
"trackPageview",
|
|
2908
|
+
"trackClicks",
|
|
2909
|
+
"ready"
|
|
2910
|
+
];
|
|
2911
|
+
function processQueuedCalls(loaderClient, actualClient) {
|
|
2912
|
+
if (loaderClient._init && loaderClient._init.length > 0) ;
|
|
2913
|
+
LOADER_METHODS.forEach((method) => {
|
|
2914
|
+
const queuedCalls = loaderClient["_" + method];
|
|
2915
|
+
if (queuedCalls && Array.isArray(queuedCalls) && queuedCalls.length > 0) {
|
|
2916
|
+
queuedCalls.forEach((args) => {
|
|
2917
|
+
if (typeof actualClient[method] === "function") {
|
|
2918
|
+
actualClient[method].apply(actualClient, args);
|
|
2919
|
+
}
|
|
2920
|
+
});
|
|
2921
|
+
}
|
|
2922
|
+
});
|
|
2923
|
+
}
|
|
2924
|
+
function replaceLoaderStub(globalName, sdkConstructor) {
|
|
2925
|
+
const global = typeof window !== "undefined" ? window : globalThis;
|
|
2926
|
+
if (global[globalName] && global[globalName].clients) {
|
|
2927
|
+
const clients = global[globalName].clients;
|
|
2928
|
+
global[globalName] = sdkConstructor;
|
|
2929
|
+
clients.forEach((loaderClient) => {
|
|
2930
|
+
let actualClient;
|
|
2931
|
+
if (loaderClient._init && loaderClient._init.length > 0) {
|
|
2932
|
+
const initArgs = loaderClient._init[0];
|
|
2933
|
+
actualClient = new sdkConstructor(...initArgs || []);
|
|
2934
|
+
} else {
|
|
2935
|
+
actualClient = new sdkConstructor();
|
|
2936
|
+
}
|
|
2937
|
+
processQueuedCalls(loaderClient, actualClient);
|
|
2938
|
+
Object.setPrototypeOf(loaderClient, actualClient);
|
|
2939
|
+
Object.assign(loaderClient, actualClient);
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
class Treasure2 {
|
|
2944
|
+
_sdk;
|
|
2945
|
+
constructor(config) {
|
|
2946
|
+
if (!(this instanceof Treasure2)) {
|
|
2947
|
+
return new Treasure2(config);
|
|
2948
|
+
}
|
|
2949
|
+
this._sdk = this.init(config);
|
|
2950
|
+
this.bindMethods();
|
|
2951
|
+
return this;
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* Initialize the SDK with all plugins
|
|
2955
|
+
*/
|
|
2956
|
+
init(config) {
|
|
2957
|
+
const processedConfig = configure(config);
|
|
2958
|
+
const sdk = createSDK(processedConfig).use(session()).use(record()).use(track()).use(clicks()).use(utm()).use(personalization()).use(conversionAPI()).use(serverCookie()).use(globalId()).use(pagePersonalize());
|
|
2959
|
+
return sdk;
|
|
2960
|
+
}
|
|
2961
|
+
/**
|
|
2962
|
+
* Bind all SDK methods to this instance for direct access
|
|
2963
|
+
*/
|
|
2964
|
+
bindMethods() {
|
|
2965
|
+
const methodNames = /* @__PURE__ */ new Set();
|
|
2966
|
+
let current = this._sdk;
|
|
2967
|
+
while (current && current !== Object.prototype) {
|
|
2968
|
+
Object.getOwnPropertyNames(current).forEach((name) => {
|
|
2969
|
+
if (typeof current[name] === "function" && name !== "constructor") {
|
|
2970
|
+
methodNames.add(name);
|
|
2971
|
+
}
|
|
2972
|
+
});
|
|
2973
|
+
current = Object.getPrototypeOf(current);
|
|
2974
|
+
}
|
|
2975
|
+
methodNames.forEach((methodName) => {
|
|
2976
|
+
if (!this.hasOwnProperty(methodName) && methodName !== "init" && methodName !== "bindMethods") {
|
|
2977
|
+
this[methodName] = this._sdk[methodName].bind(
|
|
2978
|
+
this._sdk
|
|
2979
|
+
);
|
|
2980
|
+
}
|
|
2981
|
+
});
|
|
2982
|
+
}
|
|
2983
|
+
/**
|
|
2984
|
+
* Get the underlying SDK instance
|
|
2985
|
+
*/
|
|
2986
|
+
get sdk() {
|
|
2987
|
+
return this._sdk;
|
|
2988
|
+
}
|
|
2989
|
+
/**
|
|
2990
|
+
* Get the configuration
|
|
2991
|
+
*/
|
|
2992
|
+
get config() {
|
|
2993
|
+
return this._sdk.config;
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Version information
|
|
2997
|
+
*/
|
|
2998
|
+
static version = "1.0.0";
|
|
2999
|
+
get version() {
|
|
3000
|
+
return Treasure2.version;
|
|
3001
|
+
}
|
|
3002
|
+
// Core methods
|
|
3003
|
+
/**
|
|
3004
|
+
* Add a record to a table
|
|
3005
|
+
*/
|
|
3006
|
+
addRecord = (table, record2, success, error, options) => {
|
|
3007
|
+
return this._sdk.addRecord(table, record2, success, error, options);
|
|
3008
|
+
};
|
|
3009
|
+
/**
|
|
3010
|
+
* Track a custom event
|
|
3011
|
+
*/
|
|
3012
|
+
trackEvent = (table, data, success, error) => {
|
|
3013
|
+
return this._sdk.trackEvent(table, data, success, error);
|
|
3014
|
+
};
|
|
3015
|
+
/**
|
|
3016
|
+
* Track a page view
|
|
3017
|
+
*/
|
|
3018
|
+
trackPageview = (table, success, error, options) => {
|
|
3019
|
+
return this._sdk.trackPageview(table, success, error, options);
|
|
3020
|
+
};
|
|
3021
|
+
/**
|
|
3022
|
+
* Start tracking clicks
|
|
3023
|
+
*/
|
|
3024
|
+
trackClicks = (options) => {
|
|
3025
|
+
return this._sdk.trackClicks(options);
|
|
3026
|
+
};
|
|
3027
|
+
fetchUserSegments(tokenOrOptions, successCallback, errorCallback) {
|
|
3028
|
+
return this._sdk.fetchUserSegments(
|
|
3029
|
+
tokenOrOptions,
|
|
3030
|
+
successCallback,
|
|
3031
|
+
errorCallback
|
|
3032
|
+
);
|
|
3033
|
+
}
|
|
3034
|
+
/**
|
|
3035
|
+
* Fetch personalization data
|
|
3036
|
+
*/
|
|
3037
|
+
fetchPersonalization = (config, data, successCallback, errorCallback) => {
|
|
3038
|
+
return this._sdk.fetchPersonalization(
|
|
3039
|
+
config,
|
|
3040
|
+
data,
|
|
3041
|
+
successCallback,
|
|
3042
|
+
errorCallback
|
|
3043
|
+
);
|
|
3044
|
+
};
|
|
3045
|
+
/**
|
|
3046
|
+
* Apply an already-fetched personalization payload to the current page
|
|
3047
|
+
*/
|
|
3048
|
+
applyPersonalization = (payload, options) => {
|
|
3049
|
+
this._sdk.applyPersonalization(payload, options);
|
|
3050
|
+
};
|
|
3051
|
+
/**
|
|
3052
|
+
* Fetch personalization offers and apply them to the current page
|
|
3053
|
+
*/
|
|
3054
|
+
personalizePage = (config, data, successCallback, errorCallback) => {
|
|
3055
|
+
this._sdk.personalizePage(config, data, successCallback, errorCallback);
|
|
3056
|
+
};
|
|
3057
|
+
/**
|
|
3058
|
+
* Collect UTM parameters
|
|
3059
|
+
*/
|
|
3060
|
+
collectUTMParameters = () => {
|
|
3061
|
+
return this._sdk.collectUTMParameters();
|
|
3062
|
+
};
|
|
3063
|
+
/**
|
|
3064
|
+
* Get UTM parameters
|
|
3065
|
+
*/
|
|
3066
|
+
getUTMParameters = () => {
|
|
3067
|
+
return this._sdk.getUTMParameters();
|
|
3068
|
+
};
|
|
3069
|
+
/**
|
|
3070
|
+
* Set global or table-specific values
|
|
3071
|
+
*/
|
|
3072
|
+
set = (table, property, value) => {
|
|
3073
|
+
return this._sdk.set(table, property, value);
|
|
3074
|
+
};
|
|
3075
|
+
/**
|
|
3076
|
+
* Get global or table-specific values
|
|
3077
|
+
*/
|
|
3078
|
+
get = (table, key) => {
|
|
3079
|
+
return this._sdk.get(table, key);
|
|
3080
|
+
};
|
|
3081
|
+
/**
|
|
3082
|
+
* Set signed mode
|
|
3083
|
+
*/
|
|
3084
|
+
setSignedMode = () => {
|
|
3085
|
+
return this._sdk.setSignedMode();
|
|
3086
|
+
};
|
|
3087
|
+
/**
|
|
3088
|
+
* Set anonymous mode
|
|
3089
|
+
*/
|
|
3090
|
+
setAnonymousMode = (keepIdentifier) => {
|
|
3091
|
+
return this._sdk.setAnonymousMode(keepIdentifier);
|
|
3092
|
+
};
|
|
3093
|
+
/**
|
|
3094
|
+
* Check if in signed mode
|
|
3095
|
+
*/
|
|
3096
|
+
inSignedMode = () => {
|
|
3097
|
+
return this._sdk.inSignedMode();
|
|
3098
|
+
};
|
|
3099
|
+
/**
|
|
3100
|
+
* Block events
|
|
3101
|
+
*/
|
|
3102
|
+
blockEvents = () => {
|
|
3103
|
+
return this._sdk.blockEvents();
|
|
3104
|
+
};
|
|
3105
|
+
/**
|
|
3106
|
+
* Unblock events
|
|
3107
|
+
*/
|
|
3108
|
+
unblockEvents = () => {
|
|
3109
|
+
return this._sdk.unblockEvents();
|
|
3110
|
+
};
|
|
3111
|
+
/**
|
|
3112
|
+
* Check if events are blocked
|
|
3113
|
+
*/
|
|
3114
|
+
areEventsBlocked = () => {
|
|
3115
|
+
return this._sdk.areEventsBlocked();
|
|
3116
|
+
};
|
|
3117
|
+
/**
|
|
3118
|
+
* Reset UUID
|
|
3119
|
+
*/
|
|
3120
|
+
resetUUID = () => {
|
|
3121
|
+
return this._sdk.resetUUID();
|
|
3122
|
+
};
|
|
3123
|
+
/**
|
|
3124
|
+
* Get track values
|
|
3125
|
+
*/
|
|
3126
|
+
getTrackValues = () => {
|
|
3127
|
+
return this._sdk.getTrackValues();
|
|
3128
|
+
};
|
|
3129
|
+
/**
|
|
3130
|
+
* Get the personalization config
|
|
3131
|
+
*/
|
|
3132
|
+
getPersonalizationConfig = () => {
|
|
3133
|
+
return this._sdk.getPersonalizationConfig();
|
|
3134
|
+
};
|
|
3135
|
+
/**
|
|
3136
|
+
* Set the personalization config (pass undefined to disable)
|
|
3137
|
+
*/
|
|
3138
|
+
setPersonalizationConfig = (options) => {
|
|
3139
|
+
return this._sdk.setPersonalizationConfig(options);
|
|
3140
|
+
};
|
|
3141
|
+
/**
|
|
3142
|
+
* Get the configured write key
|
|
3143
|
+
*/
|
|
3144
|
+
getWriteKey = () => {
|
|
3145
|
+
return this._sdk.getWriteKey();
|
|
3146
|
+
};
|
|
3147
|
+
/**
|
|
3148
|
+
* Set the write key
|
|
3149
|
+
*/
|
|
3150
|
+
setWriteKey = (writeKey) => {
|
|
3151
|
+
return this._sdk.setWriteKey(writeKey);
|
|
3152
|
+
};
|
|
3153
|
+
/**
|
|
3154
|
+
* Collect conversion tracking tags
|
|
3155
|
+
*/
|
|
3156
|
+
collectTags = (options) => {
|
|
3157
|
+
return this._sdk.collectTags(options);
|
|
3158
|
+
};
|
|
3159
|
+
/**
|
|
3160
|
+
* Fetch server-side cookie ID
|
|
3161
|
+
*/
|
|
3162
|
+
fetchServerCookie = (success, error, forceFetch) => {
|
|
3163
|
+
return this._sdk.fetchServerCookie(success, error, forceFetch);
|
|
3164
|
+
};
|
|
3165
|
+
/**
|
|
3166
|
+
* Fetch Global ID
|
|
3167
|
+
*/
|
|
3168
|
+
fetchGlobalID = (success, error, forceFetch, options) => {
|
|
3169
|
+
return this._sdk.fetchGlobalID(success, error, forceFetch, options);
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
if (typeof window !== "undefined") {
|
|
3173
|
+
replaceLoaderStub("Treasure", Treasure2);
|
|
3174
|
+
}
|
|
3175
|
+
return Treasure2;
|
|
3176
|
+
}();
|