@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
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="utf-8" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
7
|
+
|
|
8
|
+
<title>Tracking page</title>
|
|
9
|
+
<script>
|
|
10
|
+
window.testOnload = async j => {
|
|
11
|
+
await j.setAnonymousId("john-doe-id-1");
|
|
12
|
+
await j.identify("john-nondoe", { email: "john@example.com" });
|
|
13
|
+
await j.track("pageLoaded", { trackParam: "trackValue" });
|
|
14
|
+
await j.reset();
|
|
15
|
+
await j.track("pageLoaded", { trackParam: "trackValue" });
|
|
16
|
+
};
|
|
17
|
+
</script>
|
|
18
|
+
<script
|
|
19
|
+
type="text/javascript"
|
|
20
|
+
src="<%=trackingBase%>/p.js"
|
|
21
|
+
data-onload="testOnload"
|
|
22
|
+
data-debug="true"
|
|
23
|
+
data-init-only="true"
|
|
24
|
+
defer
|
|
25
|
+
></script>
|
|
26
|
+
</head>
|
|
27
|
+
|
|
28
|
+
<body>
|
|
29
|
+
<h1>Test</h1>
|
|
30
|
+
</body>
|
|
31
|
+
</html>
|
|
@@ -214,8 +214,8 @@ test("jitsu-queue-callbacks", async ({ browser }) => {
|
|
|
214
214
|
expect(requestLog.length).toBe(3);
|
|
215
215
|
});
|
|
216
216
|
|
|
217
|
-
test
|
|
218
|
-
|
|
217
|
+
// Skip this test because jitsu-js no longer relies on canonical URL
|
|
218
|
+
test.skip("url-bug", async ({ browser, context }) => {
|
|
219
219
|
//tests a bug in getanalytics.io where the url without slash provided by
|
|
220
220
|
//<link rel="canonical" ../> causes incorrect page path
|
|
221
221
|
const browserContext = await browser.newContext();
|
|
@@ -244,6 +244,41 @@ test("url-bug", async ({ browser }) => {
|
|
|
244
244
|
expect(pagePath).toEqual("/");
|
|
245
245
|
});
|
|
246
246
|
|
|
247
|
+
test("reset", async ({ browser }) => {
|
|
248
|
+
clearRequestLog();
|
|
249
|
+
const browserContext = await browser.newContext();
|
|
250
|
+
const { page, uncaughtErrors } = await createLoggingPage(browserContext);
|
|
251
|
+
const [pageResult] = await Promise.all([page.goto(`${server.baseUrl}/reset.html`)]);
|
|
252
|
+
await page.waitForFunction(() => window["jitsu"] !== undefined, undefined, {
|
|
253
|
+
timeout: 1000,
|
|
254
|
+
polling: 100,
|
|
255
|
+
});
|
|
256
|
+
expect(pageResult.status()).toBe(200);
|
|
257
|
+
//wait for some time since the server has an artificial latency of 30ms
|
|
258
|
+
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
259
|
+
expect(uncaughtErrors.length).toEqual(0);
|
|
260
|
+
expect(requestLog.length).toBe(3);
|
|
261
|
+
console.log(
|
|
262
|
+
`📝 Request log size of ${requestLog.length}`,
|
|
263
|
+
requestLog.map(x => describeEvent(x.type, x.body))
|
|
264
|
+
);
|
|
265
|
+
const [identifyEvent, firstTrack, secondTrack] = requestLog;
|
|
266
|
+
expect(firstTrack.body.anonymousId).toEqual("john-doe-id-1");
|
|
267
|
+
|
|
268
|
+
const cookies = await browserContext.cookies();
|
|
269
|
+
// all cookies should be cleared by .reset()
|
|
270
|
+
// but new cookie for new anonymousId should be set
|
|
271
|
+
expect(cookies.length).toBe(1);
|
|
272
|
+
expect(cookies[0].name).toEqual("__eventn_id");
|
|
273
|
+
const newAnonymousId = cookies[0].value;
|
|
274
|
+
console.log(`🍪Cookies`, cookies);
|
|
275
|
+
|
|
276
|
+
expect(secondTrack.body.anonymousId).not.toBeNull();
|
|
277
|
+
expect(secondTrack.body.anonymousId).toBeDefined();
|
|
278
|
+
expect(secondTrack.body.anonymousId).toEqual(newAnonymousId);
|
|
279
|
+
expect(secondTrack.body.anonymousId).not.toEqual("john-doe-id-1");
|
|
280
|
+
});
|
|
281
|
+
|
|
247
282
|
test("basic", async ({ browser }) => {
|
|
248
283
|
clearRequestLog();
|
|
249
284
|
const browserContext = await browser.newContext();
|
|
@@ -24,10 +24,7 @@ export type InternalPluginDescriptor = {
|
|
|
24
24
|
};
|
|
25
25
|
export type DeviceOptions = AnalyticsPluginDescriptor | InternalPluginDescriptor;
|
|
26
26
|
export type JitsuPluginConfig = JitsuOptions & {
|
|
27
|
-
storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage
|
|
28
|
-
reset: () => void;
|
|
29
|
-
};
|
|
27
|
+
storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage;
|
|
30
28
|
};
|
|
31
|
-
declare const jitsuAnalyticsPlugin: (pluginConfig?: JitsuPluginConfig) => AnalyticsPlugin;
|
|
29
|
+
export declare const jitsuAnalyticsPlugin: (pluginConfig?: JitsuPluginConfig) => AnalyticsPlugin;
|
|
32
30
|
export declare function randomId(hashString?: string | undefined): string;
|
|
33
|
-
export default jitsuAnalyticsPlugin;
|
package/dist/jitsu.cjs.js
CHANGED
|
@@ -71,7 +71,23 @@ function findScript(src) {
|
|
|
71
71
|
const scripts = Array.prototype.slice.call(window.document.querySelectorAll("script"));
|
|
72
72
|
return scripts.find(s => s.src === src);
|
|
73
73
|
}
|
|
74
|
-
function
|
|
74
|
+
function buildScriptSrc(src, options) {
|
|
75
|
+
let result = src;
|
|
76
|
+
if (!result.startsWith("http")) {
|
|
77
|
+
result = `https://${(options === null || options === void 0 ? void 0 : options.www) ? "www." : ""}${result}`;
|
|
78
|
+
}
|
|
79
|
+
if (options === null || options === void 0 ? void 0 : options.min) {
|
|
80
|
+
result = result + ".min.js";
|
|
81
|
+
}
|
|
82
|
+
else if (options === null || options === void 0 ? void 0 : options.js) {
|
|
83
|
+
result = result + ".js";
|
|
84
|
+
}
|
|
85
|
+
if (options === null || options === void 0 ? void 0 : options.query) {
|
|
86
|
+
result += "?" + options.query;
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
90
|
+
function loadScript(src, options) {
|
|
75
91
|
const found = findScript(src);
|
|
76
92
|
if (found !== undefined) {
|
|
77
93
|
const status = found === null || found === void 0 ? void 0 : found.getAttribute("status");
|
|
@@ -86,13 +102,13 @@ function loadScript(src, attributes) {
|
|
|
86
102
|
}
|
|
87
103
|
}
|
|
88
104
|
return new Promise((resolve, reject) => {
|
|
89
|
-
var _a;
|
|
105
|
+
var _a, _b;
|
|
90
106
|
const script = window.document.createElement("script");
|
|
91
107
|
script.type = "text/javascript";
|
|
92
|
-
script.src = src;
|
|
108
|
+
script.src = buildScriptSrc(src, options);
|
|
93
109
|
script.async = true;
|
|
94
110
|
script.setAttribute("status", "loading");
|
|
95
|
-
for (const [k, v] of Object.entries(attributes !== null &&
|
|
111
|
+
for (const [k, v] of Object.entries((_a = options === null || options === void 0 ? void 0 : options.attributes) !== null && _a !== void 0 ? _a : {})) {
|
|
96
112
|
script.setAttribute(k, v);
|
|
97
113
|
}
|
|
98
114
|
script.onload = () => {
|
|
@@ -106,7 +122,7 @@ function loadScript(src, attributes) {
|
|
|
106
122
|
reject(new Error(`Failed to load ${src}`));
|
|
107
123
|
};
|
|
108
124
|
const tag = window.document.getElementsByTagName("script")[0];
|
|
109
|
-
(
|
|
125
|
+
(_b = tag.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(script, tag);
|
|
110
126
|
});
|
|
111
127
|
}
|
|
112
128
|
|
|
@@ -206,6 +222,7 @@ var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
206
222
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
207
223
|
});
|
|
208
224
|
};
|
|
225
|
+
const cdn = "cdn.lr-ingest.io/";
|
|
209
226
|
const logrocketPlugin = {
|
|
210
227
|
id: "logrocket",
|
|
211
228
|
handle(config, payload) {
|
|
@@ -256,7 +273,7 @@ function initLogrocketIfNeeded(appId) {
|
|
|
256
273
|
return;
|
|
257
274
|
}
|
|
258
275
|
setLogRocketState("loading");
|
|
259
|
-
loadScript(
|
|
276
|
+
loadScript(`${cdn}LogRocket`, { min: true, attributes: { crossOrigin: "anonymous" } })
|
|
260
277
|
.then(() => {
|
|
261
278
|
if (window["LogRocket"]) {
|
|
262
279
|
try {
|
|
@@ -379,8 +396,8 @@ function initGtmIfNeeded(config, payload) {
|
|
|
379
396
|
event: "gtm.js",
|
|
380
397
|
});
|
|
381
398
|
const dl = l != "dataLayer" ? "&l=" + l : "";
|
|
382
|
-
const scriptSrc = "
|
|
383
|
-
loadScript(scriptSrc)
|
|
399
|
+
const scriptSrc = "googletagmanager.com/gtm";
|
|
400
|
+
loadScript(scriptSrc, { www: true, js: true, query: "id=" + i + dl })
|
|
384
401
|
.then(() => {
|
|
385
402
|
setGtmState("loaded");
|
|
386
403
|
})
|
|
@@ -401,7 +418,7 @@ var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
401
418
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
402
419
|
});
|
|
403
420
|
};
|
|
404
|
-
const defaultScriptSrc = "
|
|
421
|
+
const defaultScriptSrc = "googletagmanager.com/gtag/js";
|
|
405
422
|
const ga4Plugin = {
|
|
406
423
|
id: "ga4-tag",
|
|
407
424
|
handle(config, payload) {
|
|
@@ -463,7 +480,6 @@ function initGa4IfNeeded(config, payload) {
|
|
|
463
480
|
const dlParam = dlName !== "dataLayer" ? "&l=" + dlName : "";
|
|
464
481
|
// to work with both GA4 and GTM
|
|
465
482
|
const tagId = config.measurementIds;
|
|
466
|
-
const scriptSrc = `${defaultScriptSrc}?id=${tagId}${dlParam}`;
|
|
467
483
|
window[dlName] = window[dlName] || [];
|
|
468
484
|
const gtag = function () {
|
|
469
485
|
window[dlName].push(arguments);
|
|
@@ -473,7 +489,7 @@ function initGa4IfNeeded(config, payload) {
|
|
|
473
489
|
gtag(
|
|
474
490
|
// @ts-ignore
|
|
475
491
|
"config", tagId, Object.assign(Object.assign({}, (payload.userId ? { user_id: payload.userId } : {})), (!config.autoPageView ? { send_page_view: false } : {})));
|
|
476
|
-
loadScript(
|
|
492
|
+
loadScript(defaultScriptSrc, { query: `id=${tagId}${dlParam}`, www: true })
|
|
477
493
|
.then(() => {
|
|
478
494
|
setGa4State("loaded");
|
|
479
495
|
})
|
|
@@ -1112,8 +1128,15 @@ function getGa4Ids(runtime) {
|
|
|
1112
1128
|
return undefined;
|
|
1113
1129
|
}
|
|
1114
1130
|
}
|
|
1115
|
-
function removeCookie(name) {
|
|
1116
|
-
document.cookie =
|
|
1131
|
+
function removeCookie(name, { domain, secure }) {
|
|
1132
|
+
document.cookie =
|
|
1133
|
+
name +
|
|
1134
|
+
"=;domain=" +
|
|
1135
|
+
domain +
|
|
1136
|
+
";path=/" +
|
|
1137
|
+
";expires=Thu, 01 Jan 1970 00:00:01 GMT;SameSite=" +
|
|
1138
|
+
(secure ? "None" : "Lax") +
|
|
1139
|
+
(secure ? ";secure" : "");
|
|
1117
1140
|
}
|
|
1118
1141
|
function setCookie(name, val, { domain, secure }) {
|
|
1119
1142
|
document.cookie =
|
|
@@ -1155,7 +1178,18 @@ const cookieStorage = (cookieDomain, key2cookie) => {
|
|
|
1155
1178
|
return parse(result);
|
|
1156
1179
|
},
|
|
1157
1180
|
removeItem(key) {
|
|
1158
|
-
removeCookie(key2cookie[key] || key
|
|
1181
|
+
removeCookie(key2cookie[key] || key, {
|
|
1182
|
+
domain: cookieDomain,
|
|
1183
|
+
secure: window.location.protocol === "https:",
|
|
1184
|
+
});
|
|
1185
|
+
},
|
|
1186
|
+
reset() {
|
|
1187
|
+
for (const v of Object.values(key2cookie)) {
|
|
1188
|
+
removeCookie(v, {
|
|
1189
|
+
domain: cookieDomain,
|
|
1190
|
+
secure: window.location.protocol === "https:",
|
|
1191
|
+
});
|
|
1192
|
+
}
|
|
1159
1193
|
},
|
|
1160
1194
|
};
|
|
1161
1195
|
};
|
|
@@ -1226,6 +1260,9 @@ const emptyRuntime = (config) => ({
|
|
|
1226
1260
|
store() {
|
|
1227
1261
|
const storage = {};
|
|
1228
1262
|
return {
|
|
1263
|
+
reset() {
|
|
1264
|
+
Object.keys(storage).forEach(key => delete storage[key]);
|
|
1265
|
+
},
|
|
1229
1266
|
setItem(key, val) {
|
|
1230
1267
|
if (config.debug) {
|
|
1231
1268
|
console.log(`[JITSU EMPTY RUNTIME] Set storage item ${key}=${JSON.stringify(val)}`);
|
|
@@ -1291,6 +1328,17 @@ function fixPath(path) {
|
|
|
1291
1328
|
}
|
|
1292
1329
|
return path;
|
|
1293
1330
|
}
|
|
1331
|
+
const hashRegex = /#.*$/;
|
|
1332
|
+
/**
|
|
1333
|
+
* for compatibility with path produced by analytics.js
|
|
1334
|
+
* @param url
|
|
1335
|
+
*/
|
|
1336
|
+
function urlPath(url) {
|
|
1337
|
+
const regex = /(http[s]?:\/\/)?([^\/\s]+\/)(.*)/g;
|
|
1338
|
+
const matches = regex.exec(url);
|
|
1339
|
+
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1340
|
+
return "/" + pathMatch;
|
|
1341
|
+
}
|
|
1294
1342
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1295
1343
|
var _a, _b;
|
|
1296
1344
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1298,8 +1346,9 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1298
1346
|
const parsedUrl = safeCall(() => new URL(url), undefined);
|
|
1299
1347
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1300
1348
|
const properties = payload.properties || {};
|
|
1301
|
-
if (
|
|
1302
|
-
properties.
|
|
1349
|
+
if (payload.type === "page" && url) {
|
|
1350
|
+
properties.url = url.replace(hashRegex, "");
|
|
1351
|
+
properties.path = fixPath(urlPath(url));
|
|
1303
1352
|
}
|
|
1304
1353
|
const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
|
|
1305
1354
|
(_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
|
|
@@ -1497,10 +1546,13 @@ function send(method, payload, jitsuConfig, instance, store) {
|
|
|
1497
1546
|
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);
|
|
1498
1547
|
}
|
|
1499
1548
|
else {
|
|
1500
|
-
|
|
1501
|
-
|
|
1549
|
+
//double protection, ingest should not return destinations in s2s mode
|
|
1550
|
+
if (isInBrowser()) {
|
|
1551
|
+
if (jitsuConfig.debug) {
|
|
1552
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(responseJson.destinations, null, 2));
|
|
1553
|
+
}
|
|
1554
|
+
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1502
1555
|
}
|
|
1503
|
-
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1504
1556
|
}
|
|
1505
1557
|
}
|
|
1506
1558
|
return adjustedPayload;
|
|
@@ -1540,9 +1592,11 @@ const jitsuAnalyticsPlugin = (pluginConfig = {}) => {
|
|
|
1540
1592
|
return send("identify", payload, config, instance, storage);
|
|
1541
1593
|
},
|
|
1542
1594
|
reset: args => {
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1595
|
+
const { config, instance } = args;
|
|
1596
|
+
const storage = pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage;
|
|
1597
|
+
storage === null || storage === void 0 ? void 0 : storage.reset();
|
|
1598
|
+
if (config.debug) {
|
|
1599
|
+
console.log("[JITSU DEBUG] Resetting Jitsu plugin storage");
|
|
1546
1600
|
}
|
|
1547
1601
|
},
|
|
1548
1602
|
methods: {
|
|
@@ -1654,9 +1708,9 @@ function createUnderlyingAnalyticsInstance(opts, rt, plugins = []) {
|
|
|
1654
1708
|
},
|
|
1655
1709
|
reset() {
|
|
1656
1710
|
for (const key of [...Object.keys(storageCache)]) {
|
|
1657
|
-
storage.removeItem(key);
|
|
1658
1711
|
delete storageCache[key];
|
|
1659
1712
|
}
|
|
1713
|
+
storage.reset();
|
|
1660
1714
|
},
|
|
1661
1715
|
removeItem(key) {
|
|
1662
1716
|
if (opts.debug) {
|
|
@@ -1713,7 +1767,20 @@ function createUnderlyingAnalyticsInstance(opts, rt, plugins = []) {
|
|
|
1713
1767
|
userState.anonymousId = id;
|
|
1714
1768
|
}
|
|
1715
1769
|
analytics.setAnonymousId(id);
|
|
1716
|
-
},
|
|
1770
|
+
}, reset() {
|
|
1771
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1772
|
+
if (opts.debug) {
|
|
1773
|
+
console.log("[JITSU DEBUG] Called reset(). Storage state", JSON.stringify(analytics.user()));
|
|
1774
|
+
}
|
|
1775
|
+
storage.reset();
|
|
1776
|
+
yield analytics.reset();
|
|
1777
|
+
this.setAnonymousId(uuid());
|
|
1778
|
+
if (opts.debug) {
|
|
1779
|
+
console.log("[JITSU DEBUG] User state after reset", JSON.stringify(analytics.user()));
|
|
1780
|
+
}
|
|
1781
|
+
});
|
|
1782
|
+
},
|
|
1783
|
+
group(groupId, traits, options, callback) {
|
|
1717
1784
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1718
1785
|
const results = [];
|
|
1719
1786
|
for (const plugin of Object.values(analytics.plugins)) {
|
|
@@ -1762,11 +1829,21 @@ function jitsuAnalytics(_opts) {
|
|
|
1762
1829
|
// result.loaded(createUnderlyingAnalyticsInstance(opts, rt));
|
|
1763
1830
|
// }
|
|
1764
1831
|
}
|
|
1832
|
+
function uuid() {
|
|
1833
|
+
var u = "", m = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx", i = 0, rb = (Math.random() * 0xffffffff) | 0;
|
|
1834
|
+
while (i++ < 36) {
|
|
1835
|
+
var c = m[i - 1], r = rb & 0xf, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
1836
|
+
u += c == "-" || c == "4" ? c : v.toString(16);
|
|
1837
|
+
rb = i % 8 == 0 ? (Math.random() * 0xffffffff) | 0 : rb >> 4;
|
|
1838
|
+
}
|
|
1839
|
+
return u;
|
|
1840
|
+
}
|
|
1765
1841
|
|
|
1766
1842
|
exports.emptyAnalytics = emptyAnalytics;
|
|
1767
1843
|
exports.emptyRuntime = emptyRuntime;
|
|
1768
1844
|
exports.isInBrowser = isInBrowser;
|
|
1769
1845
|
exports.jitsuAnalytics = jitsuAnalytics;
|
|
1846
|
+
exports.jitsuAnalyticsPlugin = jitsuAnalyticsPlugin;
|
|
1770
1847
|
exports.parseQuery = parseQuery;
|
|
1771
1848
|
exports.randomId = randomId;
|
|
1772
1849
|
exports.windowRuntime = windowRuntime;
|
package/dist/jitsu.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import type { AnalyticsInterface } from "@jitsu/protocols/analytics";
|
|
2
|
-
import type { AnalyticsPlugin } from "analytics";
|
|
3
2
|
type JitsuOptions = {
|
|
4
3
|
/**
|
|
5
4
|
* API Key. Optional. If not set, Jitsu will send event to the server without auth, and server
|
|
@@ -52,6 +51,7 @@ type PersistentStorage = {
|
|
|
52
51
|
getItem: (key: string, options?: any) => any;
|
|
53
52
|
setItem: (key: string, value: any, options?: any) => void;
|
|
54
53
|
removeItem: (key: string, options?: any) => void;
|
|
54
|
+
reset: () => void;
|
|
55
55
|
};
|
|
56
56
|
type RuntimeFacade = {
|
|
57
57
|
store(): PersistentStorage;
|
|
@@ -73,5 +73,4 @@ type RuntimeFacade = {
|
|
|
73
73
|
pageTitle(): string | undefined;
|
|
74
74
|
};
|
|
75
75
|
export declare function jitsuAnalytics(opts: JitsuOptions): AnalyticsInterface;
|
|
76
|
-
export declare const jitsuAnalyticsPlugin: AnalyticsPlugin;
|
|
77
76
|
export { AnalyticsInterface, JitsuOptions, PersistentStorage, RuntimeFacade };
|
package/dist/jitsu.es.js
CHANGED
|
@@ -69,7 +69,23 @@ function findScript(src) {
|
|
|
69
69
|
const scripts = Array.prototype.slice.call(window.document.querySelectorAll("script"));
|
|
70
70
|
return scripts.find(s => s.src === src);
|
|
71
71
|
}
|
|
72
|
-
function
|
|
72
|
+
function buildScriptSrc(src, options) {
|
|
73
|
+
let result = src;
|
|
74
|
+
if (!result.startsWith("http")) {
|
|
75
|
+
result = `https://${(options === null || options === void 0 ? void 0 : options.www) ? "www." : ""}${result}`;
|
|
76
|
+
}
|
|
77
|
+
if (options === null || options === void 0 ? void 0 : options.min) {
|
|
78
|
+
result = result + ".min.js";
|
|
79
|
+
}
|
|
80
|
+
else if (options === null || options === void 0 ? void 0 : options.js) {
|
|
81
|
+
result = result + ".js";
|
|
82
|
+
}
|
|
83
|
+
if (options === null || options === void 0 ? void 0 : options.query) {
|
|
84
|
+
result += "?" + options.query;
|
|
85
|
+
}
|
|
86
|
+
return result;
|
|
87
|
+
}
|
|
88
|
+
function loadScript(src, options) {
|
|
73
89
|
const found = findScript(src);
|
|
74
90
|
if (found !== undefined) {
|
|
75
91
|
const status = found === null || found === void 0 ? void 0 : found.getAttribute("status");
|
|
@@ -84,13 +100,13 @@ function loadScript(src, attributes) {
|
|
|
84
100
|
}
|
|
85
101
|
}
|
|
86
102
|
return new Promise((resolve, reject) => {
|
|
87
|
-
var _a;
|
|
103
|
+
var _a, _b;
|
|
88
104
|
const script = window.document.createElement("script");
|
|
89
105
|
script.type = "text/javascript";
|
|
90
|
-
script.src = src;
|
|
106
|
+
script.src = buildScriptSrc(src, options);
|
|
91
107
|
script.async = true;
|
|
92
108
|
script.setAttribute("status", "loading");
|
|
93
|
-
for (const [k, v] of Object.entries(attributes !== null &&
|
|
109
|
+
for (const [k, v] of Object.entries((_a = options === null || options === void 0 ? void 0 : options.attributes) !== null && _a !== void 0 ? _a : {})) {
|
|
94
110
|
script.setAttribute(k, v);
|
|
95
111
|
}
|
|
96
112
|
script.onload = () => {
|
|
@@ -104,7 +120,7 @@ function loadScript(src, attributes) {
|
|
|
104
120
|
reject(new Error(`Failed to load ${src}`));
|
|
105
121
|
};
|
|
106
122
|
const tag = window.document.getElementsByTagName("script")[0];
|
|
107
|
-
(
|
|
123
|
+
(_b = tag.parentElement) === null || _b === void 0 ? void 0 : _b.insertBefore(script, tag);
|
|
108
124
|
});
|
|
109
125
|
}
|
|
110
126
|
|
|
@@ -204,6 +220,7 @@ var __awaiter$4 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
204
220
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
205
221
|
});
|
|
206
222
|
};
|
|
223
|
+
const cdn = "cdn.lr-ingest.io/";
|
|
207
224
|
const logrocketPlugin = {
|
|
208
225
|
id: "logrocket",
|
|
209
226
|
handle(config, payload) {
|
|
@@ -254,7 +271,7 @@ function initLogrocketIfNeeded(appId) {
|
|
|
254
271
|
return;
|
|
255
272
|
}
|
|
256
273
|
setLogRocketState("loading");
|
|
257
|
-
loadScript(
|
|
274
|
+
loadScript(`${cdn}LogRocket`, { min: true, attributes: { crossOrigin: "anonymous" } })
|
|
258
275
|
.then(() => {
|
|
259
276
|
if (window["LogRocket"]) {
|
|
260
277
|
try {
|
|
@@ -377,8 +394,8 @@ function initGtmIfNeeded(config, payload) {
|
|
|
377
394
|
event: "gtm.js",
|
|
378
395
|
});
|
|
379
396
|
const dl = l != "dataLayer" ? "&l=" + l : "";
|
|
380
|
-
const scriptSrc = "
|
|
381
|
-
loadScript(scriptSrc)
|
|
397
|
+
const scriptSrc = "googletagmanager.com/gtm";
|
|
398
|
+
loadScript(scriptSrc, { www: true, js: true, query: "id=" + i + dl })
|
|
382
399
|
.then(() => {
|
|
383
400
|
setGtmState("loaded");
|
|
384
401
|
})
|
|
@@ -399,7 +416,7 @@ var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _argu
|
|
|
399
416
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
400
417
|
});
|
|
401
418
|
};
|
|
402
|
-
const defaultScriptSrc = "
|
|
419
|
+
const defaultScriptSrc = "googletagmanager.com/gtag/js";
|
|
403
420
|
const ga4Plugin = {
|
|
404
421
|
id: "ga4-tag",
|
|
405
422
|
handle(config, payload) {
|
|
@@ -461,7 +478,6 @@ function initGa4IfNeeded(config, payload) {
|
|
|
461
478
|
const dlParam = dlName !== "dataLayer" ? "&l=" + dlName : "";
|
|
462
479
|
// to work with both GA4 and GTM
|
|
463
480
|
const tagId = config.measurementIds;
|
|
464
|
-
const scriptSrc = `${defaultScriptSrc}?id=${tagId}${dlParam}`;
|
|
465
481
|
window[dlName] = window[dlName] || [];
|
|
466
482
|
const gtag = function () {
|
|
467
483
|
window[dlName].push(arguments);
|
|
@@ -471,7 +487,7 @@ function initGa4IfNeeded(config, payload) {
|
|
|
471
487
|
gtag(
|
|
472
488
|
// @ts-ignore
|
|
473
489
|
"config", tagId, Object.assign(Object.assign({}, (payload.userId ? { user_id: payload.userId } : {})), (!config.autoPageView ? { send_page_view: false } : {})));
|
|
474
|
-
loadScript(
|
|
490
|
+
loadScript(defaultScriptSrc, { query: `id=${tagId}${dlParam}`, www: true })
|
|
475
491
|
.then(() => {
|
|
476
492
|
setGa4State("loaded");
|
|
477
493
|
})
|
|
@@ -1110,8 +1126,15 @@ function getGa4Ids(runtime) {
|
|
|
1110
1126
|
return undefined;
|
|
1111
1127
|
}
|
|
1112
1128
|
}
|
|
1113
|
-
function removeCookie(name) {
|
|
1114
|
-
document.cookie =
|
|
1129
|
+
function removeCookie(name, { domain, secure }) {
|
|
1130
|
+
document.cookie =
|
|
1131
|
+
name +
|
|
1132
|
+
"=;domain=" +
|
|
1133
|
+
domain +
|
|
1134
|
+
";path=/" +
|
|
1135
|
+
";expires=Thu, 01 Jan 1970 00:00:01 GMT;SameSite=" +
|
|
1136
|
+
(secure ? "None" : "Lax") +
|
|
1137
|
+
(secure ? ";secure" : "");
|
|
1115
1138
|
}
|
|
1116
1139
|
function setCookie(name, val, { domain, secure }) {
|
|
1117
1140
|
document.cookie =
|
|
@@ -1153,7 +1176,18 @@ const cookieStorage = (cookieDomain, key2cookie) => {
|
|
|
1153
1176
|
return parse(result);
|
|
1154
1177
|
},
|
|
1155
1178
|
removeItem(key) {
|
|
1156
|
-
removeCookie(key2cookie[key] || key
|
|
1179
|
+
removeCookie(key2cookie[key] || key, {
|
|
1180
|
+
domain: cookieDomain,
|
|
1181
|
+
secure: window.location.protocol === "https:",
|
|
1182
|
+
});
|
|
1183
|
+
},
|
|
1184
|
+
reset() {
|
|
1185
|
+
for (const v of Object.values(key2cookie)) {
|
|
1186
|
+
removeCookie(v, {
|
|
1187
|
+
domain: cookieDomain,
|
|
1188
|
+
secure: window.location.protocol === "https:",
|
|
1189
|
+
});
|
|
1190
|
+
}
|
|
1157
1191
|
},
|
|
1158
1192
|
};
|
|
1159
1193
|
};
|
|
@@ -1224,6 +1258,9 @@ const emptyRuntime = (config) => ({
|
|
|
1224
1258
|
store() {
|
|
1225
1259
|
const storage = {};
|
|
1226
1260
|
return {
|
|
1261
|
+
reset() {
|
|
1262
|
+
Object.keys(storage).forEach(key => delete storage[key]);
|
|
1263
|
+
},
|
|
1227
1264
|
setItem(key, val) {
|
|
1228
1265
|
if (config.debug) {
|
|
1229
1266
|
console.log(`[JITSU EMPTY RUNTIME] Set storage item ${key}=${JSON.stringify(val)}`);
|
|
@@ -1289,6 +1326,17 @@ function fixPath(path) {
|
|
|
1289
1326
|
}
|
|
1290
1327
|
return path;
|
|
1291
1328
|
}
|
|
1329
|
+
const hashRegex = /#.*$/;
|
|
1330
|
+
/**
|
|
1331
|
+
* for compatibility with path produced by analytics.js
|
|
1332
|
+
* @param url
|
|
1333
|
+
*/
|
|
1334
|
+
function urlPath(url) {
|
|
1335
|
+
const regex = /(http[s]?:\/\/)?([^\/\s]+\/)(.*)/g;
|
|
1336
|
+
const matches = regex.exec(url);
|
|
1337
|
+
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1338
|
+
return "/" + pathMatch;
|
|
1339
|
+
}
|
|
1292
1340
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1293
1341
|
var _a, _b;
|
|
1294
1342
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1296,8 +1344,9 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1296
1344
|
const parsedUrl = safeCall(() => new URL(url), undefined);
|
|
1297
1345
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1298
1346
|
const properties = payload.properties || {};
|
|
1299
|
-
if (
|
|
1300
|
-
properties.
|
|
1347
|
+
if (payload.type === "page" && url) {
|
|
1348
|
+
properties.url = url.replace(hashRegex, "");
|
|
1349
|
+
properties.path = fixPath(urlPath(url));
|
|
1301
1350
|
}
|
|
1302
1351
|
const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
|
|
1303
1352
|
(_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
|
|
@@ -1495,10 +1544,13 @@ function send(method, payload, jitsuConfig, instance, store) {
|
|
|
1495
1544
|
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);
|
|
1496
1545
|
}
|
|
1497
1546
|
else {
|
|
1498
|
-
|
|
1499
|
-
|
|
1547
|
+
//double protection, ingest should not return destinations in s2s mode
|
|
1548
|
+
if (isInBrowser()) {
|
|
1549
|
+
if (jitsuConfig.debug) {
|
|
1550
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(responseJson.destinations, null, 2));
|
|
1551
|
+
}
|
|
1552
|
+
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1500
1553
|
}
|
|
1501
|
-
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
1502
1554
|
}
|
|
1503
1555
|
}
|
|
1504
1556
|
return adjustedPayload;
|
|
@@ -1538,9 +1590,11 @@ const jitsuAnalyticsPlugin = (pluginConfig = {}) => {
|
|
|
1538
1590
|
return send("identify", payload, config, instance, storage);
|
|
1539
1591
|
},
|
|
1540
1592
|
reset: args => {
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1593
|
+
const { config, instance } = args;
|
|
1594
|
+
const storage = pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage;
|
|
1595
|
+
storage === null || storage === void 0 ? void 0 : storage.reset();
|
|
1596
|
+
if (config.debug) {
|
|
1597
|
+
console.log("[JITSU DEBUG] Resetting Jitsu plugin storage");
|
|
1544
1598
|
}
|
|
1545
1599
|
},
|
|
1546
1600
|
methods: {
|
|
@@ -1652,9 +1706,9 @@ function createUnderlyingAnalyticsInstance(opts, rt, plugins = []) {
|
|
|
1652
1706
|
},
|
|
1653
1707
|
reset() {
|
|
1654
1708
|
for (const key of [...Object.keys(storageCache)]) {
|
|
1655
|
-
storage.removeItem(key);
|
|
1656
1709
|
delete storageCache[key];
|
|
1657
1710
|
}
|
|
1711
|
+
storage.reset();
|
|
1658
1712
|
},
|
|
1659
1713
|
removeItem(key) {
|
|
1660
1714
|
if (opts.debug) {
|
|
@@ -1711,7 +1765,20 @@ function createUnderlyingAnalyticsInstance(opts, rt, plugins = []) {
|
|
|
1711
1765
|
userState.anonymousId = id;
|
|
1712
1766
|
}
|
|
1713
1767
|
analytics.setAnonymousId(id);
|
|
1714
|
-
},
|
|
1768
|
+
}, reset() {
|
|
1769
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
1770
|
+
if (opts.debug) {
|
|
1771
|
+
console.log("[JITSU DEBUG] Called reset(). Storage state", JSON.stringify(analytics.user()));
|
|
1772
|
+
}
|
|
1773
|
+
storage.reset();
|
|
1774
|
+
yield analytics.reset();
|
|
1775
|
+
this.setAnonymousId(uuid());
|
|
1776
|
+
if (opts.debug) {
|
|
1777
|
+
console.log("[JITSU DEBUG] User state after reset", JSON.stringify(analytics.user()));
|
|
1778
|
+
}
|
|
1779
|
+
});
|
|
1780
|
+
},
|
|
1781
|
+
group(groupId, traits, options, callback) {
|
|
1715
1782
|
return __awaiter(this, void 0, void 0, function* () {
|
|
1716
1783
|
const results = [];
|
|
1717
1784
|
for (const plugin of Object.values(analytics.plugins)) {
|
|
@@ -1760,5 +1827,14 @@ function jitsuAnalytics(_opts) {
|
|
|
1760
1827
|
// result.loaded(createUnderlyingAnalyticsInstance(opts, rt));
|
|
1761
1828
|
// }
|
|
1762
1829
|
}
|
|
1830
|
+
function uuid() {
|
|
1831
|
+
var u = "", m = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx", i = 0, rb = (Math.random() * 0xffffffff) | 0;
|
|
1832
|
+
while (i++ < 36) {
|
|
1833
|
+
var c = m[i - 1], r = rb & 0xf, v = c == "x" ? r : (r & 0x3) | 0x8;
|
|
1834
|
+
u += c == "-" || c == "4" ? c : v.toString(16);
|
|
1835
|
+
rb = i % 8 == 0 ? (Math.random() * 0xffffffff) | 0 : rb >> 4;
|
|
1836
|
+
}
|
|
1837
|
+
return u;
|
|
1838
|
+
}
|
|
1763
1839
|
|
|
1764
|
-
export { emptyAnalytics, emptyRuntime, isInBrowser, jitsuAnalytics, parseQuery, randomId, windowRuntime };
|
|
1840
|
+
export { emptyAnalytics, emptyRuntime, isInBrowser, jitsuAnalytics, jitsuAnalyticsPlugin, parseQuery, randomId, windowRuntime };
|
package/dist/script-loader.d.ts
CHANGED
|
@@ -1 +1,8 @@
|
|
|
1
|
-
export
|
|
1
|
+
export type ScriptOptions = {
|
|
2
|
+
attributes?: Record<string, string>;
|
|
3
|
+
www?: boolean;
|
|
4
|
+
js?: boolean;
|
|
5
|
+
min?: boolean;
|
|
6
|
+
query?: string;
|
|
7
|
+
};
|
|
8
|
+
export declare function loadScript(src: string, options?: ScriptOptions): Promise<HTMLScriptElement>;
|