@jitsu/js 1.9.3 → 1.9.5
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/.turbo/turbo-build.log +67 -67
- package/.turbo/turbo-clean.log +5 -5
- package/.turbo/turbo-test.log +327 -231
- package/__tests__/playwright/cases/reset.html +31 -0
- package/__tests__/playwright/integration.test.ts +37 -2
- package/dist/analytics-plugin.d.ts +2 -5
- package/dist/jitsu.cjs.js +101 -24
- package/dist/jitsu.d.ts +1 -2
- package/dist/jitsu.es.js +101 -25
- package/dist/script-loader.d.ts +8 -1
- package/dist/web/p.js.txt +100 -24
- package/package.json +3 -3
- package/src/analytics-plugin.ts +53 -15
- package/src/destination-plugins/ga4.ts +2 -3
- package/src/destination-plugins/gtm.ts +2 -2
- package/src/destination-plugins/logrocket.ts +3 -1
- package/src/index.ts +30 -2
- package/src/jitsu.ts +1 -3
- package/src/script-loader.ts +28 -3
package/dist/web/p.js.txt
CHANGED
|
@@ -72,7 +72,23 @@
|
|
|
72
72
|
const scripts = Array.prototype.slice.call(window.document.querySelectorAll("script"));
|
|
73
73
|
return scripts.find(s => s.src === src);
|
|
74
74
|
}
|
|
75
|
-
function
|
|
75
|
+
function buildScriptSrc(src, options) {
|
|
76
|
+
let result = src;
|
|
77
|
+
if (!result.startsWith("http")) {
|
|
78
|
+
result = `https://${(options === null || options === void 0 ? void 0 : options.www) ? "www." : ""}${result}`;
|
|
79
|
+
}
|
|
80
|
+
if (options === null || options === void 0 ? void 0 : options.min) {
|
|
81
|
+
result = result + ".min.js";
|
|
82
|
+
}
|
|
83
|
+
else if (options === null || options === void 0 ? void 0 : options.js) {
|
|
84
|
+
result = result + ".js";
|
|
85
|
+
}
|
|
86
|
+
if (options === null || options === void 0 ? void 0 : options.query) {
|
|
87
|
+
result += "?" + options.query;
|
|
88
|
+
}
|
|
89
|
+
return result;
|
|
90
|
+
}
|
|
91
|
+
function loadScript(src, options) {
|
|
76
92
|
const found = findScript(src);
|
|
77
93
|
if (found !== undefined) {
|
|
78
94
|
const status = found === null || found === void 0 ? void 0 : found.getAttribute("status");
|
|
@@ -87,13 +103,13 @@
|
|
|
87
103
|
}
|
|
88
104
|
}
|
|
89
105
|
return new Promise((resolve, reject) => {
|
|
90
|
-
var _a;
|
|
106
|
+
var _a, _b;
|
|
91
107
|
const script = window.document.createElement("script");
|
|
92
108
|
script.type = "text/javascript";
|
|
93
|
-
script.src = src;
|
|
109
|
+
script.src = buildScriptSrc(src, options);
|
|
94
110
|
script.async = true;
|
|
95
111
|
script.setAttribute("status", "loading");
|
|
96
|
-
for (const [k, v] of Object.entries(attributes !== null &&
|
|
112
|
+
for (const [k, v] of Object.entries((_a = options === null || options === void 0 ? void 0 : options.attributes) !== null && _a !== void 0 ? _a : {})) {
|
|
97
113
|
script.setAttribute(k, v);
|
|
98
114
|
}
|
|
99
115
|
script.onload = () => {
|
|
@@ -107,7 +123,7 @@
|
|
|
107
123
|
reject(new Error(`Failed to load ${src}`));
|
|
108
124
|
};
|
|
109
125
|
const tag = window.document.getElementsByTagName("script")[0];
|
|
110
|
-
(
|
|
126
|
+
(_b = tag.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(script, tag);
|
|
111
127
|
});
|
|
112
128
|
}
|
|
113
129
|
|
|
@@ -207,6 +223,7 @@
|
|
|
207
223
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
208
224
|
});
|
|
209
225
|
};
|
|
226
|
+
const cdn = "cdn.lr-ingest.io/";
|
|
210
227
|
const logrocketPlugin = {
|
|
211
228
|
id: "logrocket",
|
|
212
229
|
handle(config, payload) {
|
|
@@ -257,7 +274,7 @@
|
|
|
257
274
|
return;
|
|
258
275
|
}
|
|
259
276
|
setLogRocketState("loading");
|
|
260
|
-
loadScript(
|
|
277
|
+
loadScript(`${cdn}LogRocket`, { min: true, attributes: { crossOrigin: "anonymous" } })
|
|
261
278
|
.then(() => {
|
|
262
279
|
if (window["LogRocket"]) {
|
|
263
280
|
try {
|
|
@@ -380,8 +397,8 @@
|
|
|
380
397
|
event: "gtm.js",
|
|
381
398
|
});
|
|
382
399
|
const dl = l != "dataLayer" ? "&l=" + l : "";
|
|
383
|
-
const scriptSrc = "
|
|
384
|
-
loadScript(scriptSrc)
|
|
400
|
+
const scriptSrc = "googletagmanager.com/gtm";
|
|
401
|
+
loadScript(scriptSrc, { www: true, js: true, query: "id=" + i + dl })
|
|
385
402
|
.then(() => {
|
|
386
403
|
setGtmState("loaded");
|
|
387
404
|
})
|
|
@@ -402,7 +419,7 @@
|
|
|
402
419
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
403
420
|
});
|
|
404
421
|
};
|
|
405
|
-
const defaultScriptSrc = "
|
|
422
|
+
const defaultScriptSrc = "googletagmanager.com/gtag/js";
|
|
406
423
|
const ga4Plugin = {
|
|
407
424
|
id: "ga4-tag",
|
|
408
425
|
handle(config, payload) {
|
|
@@ -464,7 +481,6 @@
|
|
|
464
481
|
const dlParam = dlName !== "dataLayer" ? "&l=" + dlName : "";
|
|
465
482
|
// to work with both GA4 and GTM
|
|
466
483
|
const tagId = config.measurementIds;
|
|
467
|
-
const scriptSrc = `${defaultScriptSrc}?id=${tagId}${dlParam}`;
|
|
468
484
|
window[dlName] = window[dlName] || [];
|
|
469
485
|
const gtag = function () {
|
|
470
486
|
window[dlName].push(arguments);
|
|
@@ -474,7 +490,7 @@
|
|
|
474
490
|
gtag(
|
|
475
491
|
// @ts-ignore
|
|
476
492
|
"config", tagId, Object.assign(Object.assign({}, (payload.userId ? { user_id: payload.userId } : {})), (!config.autoPageView ? { send_page_view: false } : {})));
|
|
477
|
-
loadScript(
|
|
493
|
+
loadScript(defaultScriptSrc, { query: `id=${tagId}${dlParam}`, www: true })
|
|
478
494
|
.then(() => {
|
|
479
495
|
setGa4State("loaded");
|
|
480
496
|
})
|
|
@@ -1113,8 +1129,15 @@
|
|
|
1113
1129
|
return undefined;
|
|
1114
1130
|
}
|
|
1115
1131
|
}
|
|
1116
|
-
function removeCookie(name) {
|
|
1117
|
-
document.cookie =
|
|
1132
|
+
function removeCookie(name, { domain, secure }) {
|
|
1133
|
+
document.cookie =
|
|
1134
|
+
name +
|
|
1135
|
+
"=;domain=" +
|
|
1136
|
+
domain +
|
|
1137
|
+
";path=/" +
|
|
1138
|
+
";expires=Thu, 01 Jan 1970 00:00:01 GMT;SameSite=" +
|
|
1139
|
+
(secure ? "None" : "Lax") +
|
|
1140
|
+
(secure ? ";secure" : "");
|
|
1118
1141
|
}
|
|
1119
1142
|
function setCookie(name, val, { domain, secure }) {
|
|
1120
1143
|
document.cookie =
|
|
@@ -1156,7 +1179,18 @@
|
|
|
1156
1179
|
return parse(result);
|
|
1157
1180
|
},
|
|
1158
1181
|
removeItem(key) {
|
|
1159
|
-
removeCookie(key2cookie[key] || key
|
|
1182
|
+
removeCookie(key2cookie[key] || key, {
|
|
1183
|
+
domain: cookieDomain,
|
|
1184
|
+
secure: window.location.protocol === "https:",
|
|
1185
|
+
});
|
|
1186
|
+
},
|
|
1187
|
+
reset() {
|
|
1188
|
+
for (const v of Object.values(key2cookie)) {
|
|
1189
|
+
removeCookie(v, {
|
|
1190
|
+
domain: cookieDomain,
|
|
1191
|
+
secure: window.location.protocol === "https:",
|
|
1192
|
+
});
|
|
1193
|
+
}
|
|
1160
1194
|
},
|
|
1161
1195
|
};
|
|
1162
1196
|
};
|
|
@@ -1227,6 +1261,9 @@
|
|
|
1227
1261
|
store() {
|
|
1228
1262
|
const storage = {};
|
|
1229
1263
|
return {
|
|
1264
|
+
reset() {
|
|
1265
|
+
Object.keys(storage).forEach(key => delete storage[key]);
|
|
1266
|
+
},
|
|
1230
1267
|
setItem(key, val) {
|
|
1231
1268
|
if (config.debug) {
|
|
1232
1269
|
console.log(`[JITSU EMPTY RUNTIME] Set storage item ${key}=${JSON.stringify(val)}`);
|
|
@@ -1292,6 +1329,17 @@
|
|
|
1292
1329
|
}
|
|
1293
1330
|
return path;
|
|
1294
1331
|
}
|
|
1332
|
+
const hashRegex = /#.*$/;
|
|
1333
|
+
/**
|
|
1334
|
+
* for compatibility with path produced by analytics.js
|
|
1335
|
+
* @param url
|
|
1336
|
+
*/
|
|
1337
|
+
function urlPath(url) {
|
|
1338
|
+
const regex = /(http[s]?:\/\/)?([^\/\s]+\/)(.*)/g;
|
|
1339
|
+
const matches = regex.exec(url);
|
|
1340
|
+
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1341
|
+
return "/" + pathMatch;
|
|
1342
|
+
}
|
|
1295
1343
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1296
1344
|
var _a, _b;
|
|
1297
1345
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1299,8 +1347,9 @@
|
|
|
1299
1347
|
const parsedUrl = safeCall(() => new URL(url), undefined);
|
|
1300
1348
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1301
1349
|
const properties = payload.properties || {};
|
|
1302
|
-
if (
|
|
1303
|
-
properties.
|
|
1350
|
+
if (payload.type === "page" && url) {
|
|
1351
|
+
properties.url = url.replace(hashRegex, "");
|
|
1352
|
+
properties.path = fixPath(urlPath(url));
|
|
1304
1353
|
}
|
|
1305
1354
|
const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
|
|
1306
1355
|
(_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
|
|
@@ -1498,10 +1547,13 @@
|
|
|
1498
1547
|
console.warn(`[JITSU] ${payload.type} responded with list of ${responseJson.destinations.length} destinations. However, this code is running in server-to-server mode, so destinations will be ignored`, jitsuConfig.debug ? JSON.stringify(responseJson.destinations, null, 2) : undefined);
|
|
1499
1548
|
}
|
|
1500
1549
|
else {
|
|
1501
|
-
|
|
1502
|
-
|
|
1550
|
+
//double protection, ingest should not return destinations in s2s mode
|
|
1551
|
+
if (isInBrowser()) {
|
|
1552
|
+
if (jitsuConfig.debug) {
|
|
1553
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(responseJson.destinations, null, 2));
|
|
1554
|
+
}
|
|
1555
|
+
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1503
1556
|
}
|
|
1504
|
-
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1505
1557
|
}
|
|
1506
1558
|
}
|
|
1507
1559
|
return adjustedPayload;
|
|
@@ -1541,9 +1593,11 @@
|
|
|
1541
1593
|
return send("identify", payload, config, instance, storage);
|
|
1542
1594
|
},
|
|
1543
1595
|
reset: args => {
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1596
|
+
const { config, instance } = args;
|
|
1597
|
+
const storage = pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage;
|
|
1598
|
+
storage === null || storage === void 0 ? void 0 : storage.reset();
|
|
1599
|
+
if (config.debug) {
|
|
1600
|
+
console.log("[JITSU DEBUG] Resetting Jitsu plugin storage");
|
|
1547
1601
|
}
|
|
1548
1602
|
},
|
|
1549
1603
|
methods: {
|
|
@@ -1646,9 +1700,9 @@
|
|
|
1646
1700
|
},
|
|
1647
1701
|
reset() {
|
|
1648
1702
|
for (const key of [...Object.keys(storageCache)]) {
|
|
1649
|
-
storage.removeItem(key);
|
|
1650
1703
|
delete storageCache[key];
|
|
1651
1704
|
}
|
|
1705
|
+
storage.reset();
|
|
1652
1706
|
},
|
|
1653
1707
|
removeItem(key) {
|
|
1654
1708
|
if (opts.debug) {
|
|
@@ -1705,7 +1759,20 @@
|
|
|
1705
1759
|
userState.anonymousId = id;
|
|
1706
1760
|
}
|
|
1707
1761
|
analytics.setAnonymousId(id);
|
|
1708
|
-
},
|
|
1762
|
+
}, reset() {
|
|
1763
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1764
|
+
if (opts.debug) {
|
|
1765
|
+
console.log("[JITSU DEBUG] Called reset(). Storage state", JSON.stringify(analytics.user()));
|
|
1766
|
+
}
|
|
1767
|
+
storage.reset();
|
|
1768
|
+
yield analytics.reset();
|
|
1769
|
+
this.setAnonymousId(uuid());
|
|
1770
|
+
if (opts.debug) {
|
|
1771
|
+
console.log("[JITSU DEBUG] User state after reset", JSON.stringify(analytics.user()));
|
|
1772
|
+
}
|
|
1773
|
+
});
|
|
1774
|
+
},
|
|
1775
|
+
group(groupId, traits, options, callback) {
|
|
1709
1776
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1710
1777
|
const results = [];
|
|
1711
1778
|
for (const plugin of Object.values(analytics.plugins)) {
|
|
@@ -1754,6 +1821,15 @@
|
|
|
1754
1821
|
// result.loaded(createUnderlyingAnalyticsInstance(opts, rt));
|
|
1755
1822
|
// }
|
|
1756
1823
|
}
|
|
1824
|
+
function uuid() {
|
|
1825
|
+
var u = "", m = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx", i = 0, rb = (Math.random() * 0xffffffff) | 0;
|
|
1826
|
+
while (i++ < 36) {
|
|
1827
|
+
var c = m[i - 1], r = rb & 0xf, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
1828
|
+
u += c == "-" || c == "4" ? c : v.toString(16);
|
|
1829
|
+
rb = i % 8 == 0 ? (Math.random() * 0xffffffff) | 0 : rb >> 4;
|
|
1830
|
+
}
|
|
1831
|
+
return u;
|
|
1832
|
+
}
|
|
1757
1833
|
|
|
1758
1834
|
function snakeToCamel(s) {
|
|
1759
1835
|
return s.replace(/([-_][a-z])/gi, $1 => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jitsu/js",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.5",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "Jitsu Dev Team <dev@jitsu.com>",
|
|
6
6
|
"main": "dist/jitsu.cjs.js",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"rollup": "^3.2.5",
|
|
35
35
|
"ts-jest": "29.0.5",
|
|
36
36
|
"typescript": "^5.3.3",
|
|
37
|
-
"@jitsu/protocols": "1.9.
|
|
38
|
-
"jsondiffpatch": "1.9.
|
|
37
|
+
"@jitsu/protocols": "1.9.5",
|
|
38
|
+
"jsondiffpatch": "1.9.5"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
41
|
"analytics": "0.8.9"
|
package/src/analytics-plugin.ts
CHANGED
|
@@ -123,8 +123,15 @@ function getGa4Ids(runtime: RuntimeFacade) {
|
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
125
|
|
|
126
|
-
function removeCookie(name: string) {
|
|
127
|
-
document.cookie =
|
|
126
|
+
function removeCookie(name: string, { domain, secure }: { domain: string; secure: boolean }) {
|
|
127
|
+
document.cookie =
|
|
128
|
+
name +
|
|
129
|
+
"=;domain=" +
|
|
130
|
+
domain +
|
|
131
|
+
";path=/" +
|
|
132
|
+
";expires=Thu, 01 Jan 1970 00:00:01 GMT;SameSite=" +
|
|
133
|
+
(secure ? "None" : "Lax") +
|
|
134
|
+
(secure ? ";secure" : "");
|
|
128
135
|
}
|
|
129
136
|
|
|
130
137
|
function setCookie(name: string, val: string, { domain, secure }: { domain: string; secure: boolean }) {
|
|
@@ -169,7 +176,18 @@ const cookieStorage: StorageFactory = (cookieDomain, key2cookie) => {
|
|
|
169
176
|
return parse(result);
|
|
170
177
|
},
|
|
171
178
|
removeItem(key: string) {
|
|
172
|
-
removeCookie(key2cookie[key] || key
|
|
179
|
+
removeCookie(key2cookie[key] || key, {
|
|
180
|
+
domain: cookieDomain,
|
|
181
|
+
secure: window.location.protocol === "https:",
|
|
182
|
+
});
|
|
183
|
+
},
|
|
184
|
+
reset() {
|
|
185
|
+
for (const v of Object.values(key2cookie)) {
|
|
186
|
+
removeCookie(v, {
|
|
187
|
+
domain: cookieDomain,
|
|
188
|
+
secure: window.location.protocol === "https:",
|
|
189
|
+
});
|
|
190
|
+
}
|
|
173
191
|
},
|
|
174
192
|
};
|
|
175
193
|
};
|
|
@@ -244,6 +262,9 @@ export const emptyRuntime = (config: JitsuOptions): RuntimeFacade => ({
|
|
|
244
262
|
store(): PersistentStorage {
|
|
245
263
|
const storage = {};
|
|
246
264
|
return {
|
|
265
|
+
reset(): void {
|
|
266
|
+
Object.keys(storage).forEach(key => delete storage[key]);
|
|
267
|
+
},
|
|
247
268
|
setItem(key: string, val: any) {
|
|
248
269
|
if (config.debug) {
|
|
249
270
|
console.log(`[JITSU EMPTY RUNTIME] Set storage item ${key}=${JSON.stringify(val)}`);
|
|
@@ -313,6 +334,19 @@ function fixPath(path: string): string {
|
|
|
313
334
|
return path;
|
|
314
335
|
}
|
|
315
336
|
|
|
337
|
+
const hashRegex = /#.*$/;
|
|
338
|
+
|
|
339
|
+
/**
|
|
340
|
+
* for compatibility with path produced by analytics.js
|
|
341
|
+
* @param url
|
|
342
|
+
*/
|
|
343
|
+
function urlPath(url) {
|
|
344
|
+
const regex = /(http[s]?:\/\/)?([^\/\s]+\/)(.*)/g;
|
|
345
|
+
const matches = regex.exec(url);
|
|
346
|
+
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
347
|
+
return "/" + pathMatch;
|
|
348
|
+
}
|
|
349
|
+
|
|
316
350
|
function adjustPayload(
|
|
317
351
|
payload: any,
|
|
318
352
|
config: JitsuOptions,
|
|
@@ -325,8 +359,9 @@ function adjustPayload(
|
|
|
325
359
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
326
360
|
const properties = payload.properties || {};
|
|
327
361
|
|
|
328
|
-
if (
|
|
329
|
-
properties.
|
|
362
|
+
if (payload.type === "page" && url) {
|
|
363
|
+
properties.url = url.replace(hashRegex, "");
|
|
364
|
+
properties.path = fixPath(urlPath(url));
|
|
330
365
|
}
|
|
331
366
|
|
|
332
367
|
const customContext = payload.properties?.context || {};
|
|
@@ -610,19 +645,22 @@ async function send(
|
|
|
610
645
|
jitsuConfig.debug ? JSON.stringify(responseJson.destinations, null, 2) : undefined
|
|
611
646
|
);
|
|
612
647
|
} else {
|
|
613
|
-
|
|
614
|
-
|
|
648
|
+
//double protection, ingest should not return destinations in s2s mode
|
|
649
|
+
if (isInBrowser()) {
|
|
650
|
+
if (jitsuConfig.debug) {
|
|
651
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(responseJson.destinations, null, 2));
|
|
652
|
+
}
|
|
653
|
+
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
615
654
|
}
|
|
616
|
-
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
617
655
|
}
|
|
618
656
|
}
|
|
619
657
|
return adjustedPayload;
|
|
620
658
|
}
|
|
621
659
|
|
|
622
660
|
export type JitsuPluginConfig = JitsuOptions & {
|
|
623
|
-
storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage
|
|
661
|
+
storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage;
|
|
624
662
|
};
|
|
625
|
-
const jitsuAnalyticsPlugin = (pluginConfig: JitsuPluginConfig = {}): AnalyticsPlugin => {
|
|
663
|
+
export const jitsuAnalyticsPlugin = (pluginConfig: JitsuPluginConfig = {}): AnalyticsPlugin => {
|
|
626
664
|
const instanceConfig = {
|
|
627
665
|
...defaultConfig,
|
|
628
666
|
...pluginConfig,
|
|
@@ -672,9 +710,11 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuPluginConfig = {}): AnalyticsPl
|
|
|
672
710
|
return send("identify", payload, config, instance, storage);
|
|
673
711
|
},
|
|
674
712
|
reset: args => {
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
713
|
+
const { config, instance } = args;
|
|
714
|
+
const storage = pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage;
|
|
715
|
+
storage?.reset();
|
|
716
|
+
if (config.debug) {
|
|
717
|
+
console.log("[JITSU DEBUG] Resetting Jitsu plugin storage");
|
|
678
718
|
}
|
|
679
719
|
},
|
|
680
720
|
methods: {
|
|
@@ -735,5 +775,3 @@ function hash(str: string, seed: number = 0): number {
|
|
|
735
775
|
|
|
736
776
|
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
737
777
|
}
|
|
738
|
-
|
|
739
|
-
export default jitsuAnalyticsPlugin;
|
|
@@ -2,7 +2,7 @@ import { loadScript } from "../script-loader";
|
|
|
2
2
|
import { AnalyticsClientEvent } from "@jitsu/protocols/analytics";
|
|
3
3
|
import { applyFilters, CommonDestinationCredentials, InternalPlugin } from "./index";
|
|
4
4
|
|
|
5
|
-
const defaultScriptSrc = "
|
|
5
|
+
const defaultScriptSrc = "googletagmanager.com/gtag/js";
|
|
6
6
|
|
|
7
7
|
export type Ga4DestinationCredentials = {
|
|
8
8
|
debug?: boolean;
|
|
@@ -94,7 +94,6 @@ async function initGa4IfNeeded(config: Ga4DestinationCredentials, payload: Analy
|
|
|
94
94
|
|
|
95
95
|
// to work with both GA4 and GTM
|
|
96
96
|
const tagId = config.measurementIds;
|
|
97
|
-
const scriptSrc = `${defaultScriptSrc}?id=${tagId}${dlParam}`;
|
|
98
97
|
|
|
99
98
|
window[dlName] = window[dlName] || [];
|
|
100
99
|
const gtag = function () {
|
|
@@ -112,7 +111,7 @@ async function initGa4IfNeeded(config: Ga4DestinationCredentials, payload: Analy
|
|
|
112
111
|
}
|
|
113
112
|
);
|
|
114
113
|
|
|
115
|
-
loadScript(
|
|
114
|
+
loadScript(defaultScriptSrc, { query: `id=${tagId}${dlParam}`, www: true })
|
|
116
115
|
.then(() => {
|
|
117
116
|
setGa4State("loaded");
|
|
118
117
|
})
|
|
@@ -129,8 +129,8 @@ async function initGtmIfNeeded(config: GtmDestinationCredentials, payload: Analy
|
|
|
129
129
|
event: "gtm.js",
|
|
130
130
|
});
|
|
131
131
|
const dl = l != "dataLayer" ? "&l=" + l : "";
|
|
132
|
-
const scriptSrc = "
|
|
133
|
-
loadScript(scriptSrc)
|
|
132
|
+
const scriptSrc = "googletagmanager.com/gtm";
|
|
133
|
+
loadScript(scriptSrc, { www: true, js: true, query: "id=" + i + dl })
|
|
134
134
|
.then(() => {
|
|
135
135
|
setGtmState("loaded");
|
|
136
136
|
})
|
|
@@ -6,6 +6,8 @@ export type LogRocketDestinationCredentials = {
|
|
|
6
6
|
appId: string;
|
|
7
7
|
} & CommonDestinationCredentials;
|
|
8
8
|
|
|
9
|
+
const cdn = "cdn.lr-ingest.io/";
|
|
10
|
+
|
|
9
11
|
export const logrocketPlugin: InternalPlugin<LogRocketDestinationCredentials> = {
|
|
10
12
|
id: "logrocket",
|
|
11
13
|
async handle(config, payload: AnalyticsClientEvent) {
|
|
@@ -63,7 +65,7 @@ async function initLogrocketIfNeeded(appId: string) {
|
|
|
63
65
|
return;
|
|
64
66
|
}
|
|
65
67
|
setLogRocketState("loading");
|
|
66
|
-
loadScript(
|
|
68
|
+
loadScript(`${cdn}LogRocket`, { min: true, attributes: { crossOrigin: "anonymous" } })
|
|
67
69
|
.then(() => {
|
|
68
70
|
if (window["LogRocket"]) {
|
|
69
71
|
try {
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Analytics from "analytics";
|
|
2
2
|
import { AnalyticsInterface, JitsuOptions, PersistentStorage, RuntimeFacade } from "./jitsu";
|
|
3
|
-
import jitsuAnalyticsPlugin,
|
|
3
|
+
import { jitsuAnalyticsPlugin, emptyRuntime, isInBrowser, windowRuntime } from "./analytics-plugin";
|
|
4
4
|
import { Callback, DispatchedEvent, ID, JSONObject, Options } from "@jitsu/protocols/analytics";
|
|
5
5
|
|
|
6
6
|
export default function parse(input) {
|
|
@@ -64,9 +64,9 @@ function createUnderlyingAnalyticsInstance(
|
|
|
64
64
|
},
|
|
65
65
|
reset() {
|
|
66
66
|
for (const key of [...Object.keys(storageCache)]) {
|
|
67
|
-
storage.removeItem(key);
|
|
68
67
|
delete storageCache[key];
|
|
69
68
|
}
|
|
69
|
+
storage.reset();
|
|
70
70
|
},
|
|
71
71
|
removeItem(key: string) {
|
|
72
72
|
if (opts.debug) {
|
|
@@ -133,6 +133,17 @@ function createUnderlyingAnalyticsInstance(
|
|
|
133
133
|
}
|
|
134
134
|
(analytics as any).setAnonymousId(id);
|
|
135
135
|
},
|
|
136
|
+
async reset() {
|
|
137
|
+
if (opts.debug) {
|
|
138
|
+
console.log("[JITSU DEBUG] Called reset(). Storage state", JSON.stringify(analytics.user()));
|
|
139
|
+
}
|
|
140
|
+
storage.reset();
|
|
141
|
+
await analytics.reset();
|
|
142
|
+
this.setAnonymousId(uuid());
|
|
143
|
+
if (opts.debug) {
|
|
144
|
+
console.log("[JITSU DEBUG] User state after reset", JSON.stringify(analytics.user()));
|
|
145
|
+
}
|
|
146
|
+
},
|
|
136
147
|
async group(
|
|
137
148
|
groupId?: ID,
|
|
138
149
|
traits?: JSONObject | null,
|
|
@@ -194,5 +205,22 @@ export function jitsuAnalytics(_opts: JitsuOptions): AnalyticsInterface {
|
|
|
194
205
|
// }
|
|
195
206
|
}
|
|
196
207
|
|
|
208
|
+
function uuid() {
|
|
209
|
+
var u = "",
|
|
210
|
+
m = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx",
|
|
211
|
+
i = 0,
|
|
212
|
+
rb = (Math.random() * 0xffffffff) | 0;
|
|
213
|
+
|
|
214
|
+
while (i++ < 36) {
|
|
215
|
+
var c = m[i - 1],
|
|
216
|
+
r = rb & 0xf,
|
|
217
|
+
v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
218
|
+
|
|
219
|
+
u += c == "-" || c == "4" ? c : v.toString(16);
|
|
220
|
+
rb = i % 8 == 0 ? (Math.random() * 0xffffffff) | 0 : rb >> 4;
|
|
221
|
+
}
|
|
222
|
+
return u;
|
|
223
|
+
}
|
|
224
|
+
|
|
197
225
|
export * from "./jitsu";
|
|
198
226
|
export * from "./analytics-plugin";
|
package/src/jitsu.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AnalyticsInterface } from "@jitsu/protocols/analytics";
|
|
2
|
-
import type { AnalyticsPlugin } from "analytics";
|
|
3
2
|
|
|
4
3
|
type JitsuOptions = {
|
|
5
4
|
/**
|
|
@@ -56,6 +55,7 @@ type PersistentStorage = {
|
|
|
56
55
|
getItem: (key: string, options?: any) => any;
|
|
57
56
|
setItem: (key: string, value: any, options?: any) => void;
|
|
58
57
|
removeItem: (key: string, options?: any) => void;
|
|
58
|
+
reset: () => void;
|
|
59
59
|
};
|
|
60
60
|
|
|
61
61
|
type RuntimeFacade = {
|
|
@@ -83,6 +83,4 @@ type RuntimeFacade = {
|
|
|
83
83
|
|
|
84
84
|
export declare function jitsuAnalytics(opts: JitsuOptions): AnalyticsInterface;
|
|
85
85
|
|
|
86
|
-
export declare const jitsuAnalyticsPlugin: AnalyticsPlugin;
|
|
87
|
-
|
|
88
86
|
export { AnalyticsInterface, JitsuOptions, PersistentStorage, RuntimeFacade };
|
package/src/script-loader.ts
CHANGED
|
@@ -3,7 +3,32 @@ function findScript(src: string): HTMLScriptElement | undefined {
|
|
|
3
3
|
return scripts.find(s => s.src === src);
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
-
export
|
|
6
|
+
export type ScriptOptions = {
|
|
7
|
+
attributes?: Record<string, string>;
|
|
8
|
+
www?: boolean;
|
|
9
|
+
js?: boolean;
|
|
10
|
+
min?: boolean;
|
|
11
|
+
query?: string;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
function buildScriptSrc(src: string, options?: ScriptOptions): string {
|
|
15
|
+
let result = src;
|
|
16
|
+
if (!result.startsWith("http")) {
|
|
17
|
+
result = `https://${options?.www ? "www." : ""}${result}`;
|
|
18
|
+
}
|
|
19
|
+
if (options?.min) {
|
|
20
|
+
result = result + ".min.js";
|
|
21
|
+
} else if (options?.js) {
|
|
22
|
+
result = result + ".js";
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
if (options?.query) {
|
|
26
|
+
result += "?" + options.query;
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function loadScript(src: string, options?: ScriptOptions): Promise<HTMLScriptElement> {
|
|
7
32
|
const found = findScript(src);
|
|
8
33
|
|
|
9
34
|
if (found !== undefined) {
|
|
@@ -25,11 +50,11 @@ export function loadScript(src: string, attributes?: Record<string, string>): Pr
|
|
|
25
50
|
const script = window.document.createElement("script");
|
|
26
51
|
|
|
27
52
|
script.type = "text/javascript";
|
|
28
|
-
script.src = src;
|
|
53
|
+
script.src = buildScriptSrc(src, options);
|
|
29
54
|
script.async = true;
|
|
30
55
|
|
|
31
56
|
script.setAttribute("status", "loading");
|
|
32
|
-
for (const [k, v] of Object.entries(attributes ?? {})) {
|
|
57
|
+
for (const [k, v] of Object.entries(options?.attributes ?? {})) {
|
|
33
58
|
script.setAttribute(k, v);
|
|
34
59
|
}
|
|
35
60
|
|