@jitsu/js 1.10.3 → 1.10.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/jitsu-no-ext.cjs.js +60 -9
- package/dist/jitsu-no-ext.es.js +60 -9
- package/dist/jitsu.cjs.js +60 -9
- package/dist/jitsu.es.js +60 -9
- package/dist/web/p.js.txt +60 -9
- package/package.json +3 -3
package/dist/jitsu-no-ext.cjs.js
CHANGED
|
@@ -742,6 +742,19 @@ function getClientIds(runtime, customCookieCapture) {
|
|
|
742
742
|
}, {});
|
|
743
743
|
return Object.assign(Object.assign({}, clientIds), getGa4Ids(runtime));
|
|
744
744
|
}
|
|
745
|
+
function parseGa4SessionId(cookieValue) {
|
|
746
|
+
if (typeof cookieValue !== "string") {
|
|
747
|
+
return undefined;
|
|
748
|
+
}
|
|
749
|
+
if (cookieValue.startsWith("GA1") || cookieValue.startsWith("GS1")) {
|
|
750
|
+
return cookieValue.split(".")[2];
|
|
751
|
+
}
|
|
752
|
+
else {
|
|
753
|
+
// parse new GA4 cookie format, e.g.: GS2.1.s1747323152$o28$g0$t1747323152$j60$l0$h69286059
|
|
754
|
+
const match = cookieValue.match(/^GS\d+\.\d+\.(?:[\w_-]+[$])*s(\d+)(?:$|[$])/);
|
|
755
|
+
return match ? match[1] : undefined;
|
|
756
|
+
}
|
|
757
|
+
}
|
|
745
758
|
function getGa4Ids(runtime) {
|
|
746
759
|
var _a;
|
|
747
760
|
const allCookies = runtime.getCookies();
|
|
@@ -750,14 +763,11 @@ function getGa4Ids(runtime) {
|
|
|
750
763
|
const sessionIds = gaSessionCookies.length > 0
|
|
751
764
|
? Object.fromEntries(gaSessionCookies
|
|
752
765
|
.map(([key, value]) => {
|
|
753
|
-
|
|
766
|
+
const sessionId = parseGa4SessionId(value);
|
|
767
|
+
if (!sessionId) {
|
|
754
768
|
return null;
|
|
755
769
|
}
|
|
756
|
-
|
|
757
|
-
if (parts.length < 3) {
|
|
758
|
-
return null;
|
|
759
|
-
}
|
|
760
|
-
return [key.substring("_ga_".length), parts[2]];
|
|
770
|
+
return [key.substring("_ga_".length), sessionId];
|
|
761
771
|
})
|
|
762
772
|
.filter(v => v !== null))
|
|
763
773
|
: undefined;
|
|
@@ -981,6 +991,15 @@ const emptyRuntime = (config) => ({
|
|
|
981
991
|
return undefined;
|
|
982
992
|
},
|
|
983
993
|
});
|
|
994
|
+
function deepCopy(o) {
|
|
995
|
+
if (typeof o !== "object") {
|
|
996
|
+
return o;
|
|
997
|
+
}
|
|
998
|
+
if (!o) {
|
|
999
|
+
return o;
|
|
1000
|
+
}
|
|
1001
|
+
return JSON.parse(JSON.stringify(o));
|
|
1002
|
+
}
|
|
984
1003
|
function deepMerge(target, source) {
|
|
985
1004
|
if (typeof source !== "object" || source === null) {
|
|
986
1005
|
return source;
|
|
@@ -1017,6 +1036,28 @@ function urlPath(url) {
|
|
|
1017
1036
|
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1018
1037
|
return "/" + pathMatch;
|
|
1019
1038
|
}
|
|
1039
|
+
function canonicalUrl() {
|
|
1040
|
+
if (!isInBrowser())
|
|
1041
|
+
return;
|
|
1042
|
+
const tags = document.getElementsByTagName("link");
|
|
1043
|
+
for (var i = 0, tag; (tag = tags[i]); i++) {
|
|
1044
|
+
if (tag.getAttribute("rel") === "canonical") {
|
|
1045
|
+
return tag.getAttribute("href");
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
/**
|
|
1050
|
+
* bugged analytics.js logic that produces 'url' parameter by concating canonical URL with current search part
|
|
1051
|
+
* I produces broken results in some cases like SPA where path is changed but canonical URL is not updated
|
|
1052
|
+
*/
|
|
1053
|
+
function analyticsJsUrl() {
|
|
1054
|
+
if (!isInBrowser())
|
|
1055
|
+
return;
|
|
1056
|
+
const canonical = canonicalUrl();
|
|
1057
|
+
if (!canonical)
|
|
1058
|
+
return window.location.href.replace(hashRegex, "");
|
|
1059
|
+
return canonical.match(/\?/) ? canonical : canonical + window.location.search;
|
|
1060
|
+
}
|
|
1020
1061
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1021
1062
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1022
1063
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1025,9 +1066,16 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1025
1066
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1026
1067
|
const properties = payload.properties || {};
|
|
1027
1068
|
if (payload.type === "page" && (properties.url || url)) {
|
|
1028
|
-
|
|
1069
|
+
// we don't trust analytics.js URL logic since it's sticks with canonical URL on SPA pages
|
|
1070
|
+
let targetUrl = url || properties.url;
|
|
1071
|
+
if (properties.url && properties.url !== analyticsJsUrl()) {
|
|
1072
|
+
// properties.url is not the same as provided by analytics.js
|
|
1073
|
+
// it means that it was not overridden by user and we should use it
|
|
1074
|
+
targetUrl = properties.url;
|
|
1075
|
+
}
|
|
1029
1076
|
properties.url = targetUrl.replace(hashRegex, "");
|
|
1030
1077
|
properties.path = fixPath(urlPath(targetUrl));
|
|
1078
|
+
// other properties are correctly based on window.location in analytics.js
|
|
1031
1079
|
}
|
|
1032
1080
|
const customContext = deepMerge(config.defaultPayloadContext, ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {});
|
|
1033
1081
|
(_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
|
|
@@ -1081,15 +1129,18 @@ function processDestinations(destinations, method, originalEvent, debug, analyti
|
|
|
1081
1129
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1082
1130
|
const promises = [];
|
|
1083
1131
|
for (const destination of destinations) {
|
|
1084
|
-
let newEvents = [
|
|
1132
|
+
let newEvents = [];
|
|
1085
1133
|
if (destination.newEvents) {
|
|
1086
1134
|
try {
|
|
1087
|
-
newEvents = destination.newEvents.map(e => e === "same" ? originalEvent : isDiff(e) ? diff.patch(originalEvent, e.__diff) : e);
|
|
1135
|
+
newEvents = destination.newEvents.map(e => e === "same" ? deepCopy(originalEvent) : isDiff(e) ? diff.patch(deepCopy(originalEvent), e.__diff) : e);
|
|
1088
1136
|
}
|
|
1089
1137
|
catch (e) {
|
|
1090
1138
|
console.error(`[JITSU] Error applying '${destination.id}' changes to event: ${e === null || e === void 0 ? void 0 : e.message}`, e);
|
|
1091
1139
|
}
|
|
1092
1140
|
}
|
|
1141
|
+
else {
|
|
1142
|
+
newEvents = [deepCopy(originalEvent)];
|
|
1143
|
+
}
|
|
1093
1144
|
const credentials = Object.assign(Object.assign({}, destination.credentials), destination.options);
|
|
1094
1145
|
if (destination.deviceOptions.type === "internal-plugin") {
|
|
1095
1146
|
const plugin = internalDestinationPlugins[destination.deviceOptions.name];
|
package/dist/jitsu-no-ext.es.js
CHANGED
|
@@ -740,6 +740,19 @@ function getClientIds(runtime, customCookieCapture) {
|
|
|
740
740
|
}, {});
|
|
741
741
|
return Object.assign(Object.assign({}, clientIds), getGa4Ids(runtime));
|
|
742
742
|
}
|
|
743
|
+
function parseGa4SessionId(cookieValue) {
|
|
744
|
+
if (typeof cookieValue !== "string") {
|
|
745
|
+
return undefined;
|
|
746
|
+
}
|
|
747
|
+
if (cookieValue.startsWith("GA1") || cookieValue.startsWith("GS1")) {
|
|
748
|
+
return cookieValue.split(".")[2];
|
|
749
|
+
}
|
|
750
|
+
else {
|
|
751
|
+
// parse new GA4 cookie format, e.g.: GS2.1.s1747323152$o28$g0$t1747323152$j60$l0$h69286059
|
|
752
|
+
const match = cookieValue.match(/^GS\d+\.\d+\.(?:[\w_-]+[$])*s(\d+)(?:$|[$])/);
|
|
753
|
+
return match ? match[1] : undefined;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
743
756
|
function getGa4Ids(runtime) {
|
|
744
757
|
var _a;
|
|
745
758
|
const allCookies = runtime.getCookies();
|
|
@@ -748,14 +761,11 @@ function getGa4Ids(runtime) {
|
|
|
748
761
|
const sessionIds = gaSessionCookies.length > 0
|
|
749
762
|
? Object.fromEntries(gaSessionCookies
|
|
750
763
|
.map(([key, value]) => {
|
|
751
|
-
|
|
764
|
+
const sessionId = parseGa4SessionId(value);
|
|
765
|
+
if (!sessionId) {
|
|
752
766
|
return null;
|
|
753
767
|
}
|
|
754
|
-
|
|
755
|
-
if (parts.length < 3) {
|
|
756
|
-
return null;
|
|
757
|
-
}
|
|
758
|
-
return [key.substring("_ga_".length), parts[2]];
|
|
768
|
+
return [key.substring("_ga_".length), sessionId];
|
|
759
769
|
})
|
|
760
770
|
.filter(v => v !== null))
|
|
761
771
|
: undefined;
|
|
@@ -979,6 +989,15 @@ const emptyRuntime = (config) => ({
|
|
|
979
989
|
return undefined;
|
|
980
990
|
},
|
|
981
991
|
});
|
|
992
|
+
function deepCopy(o) {
|
|
993
|
+
if (typeof o !== "object") {
|
|
994
|
+
return o;
|
|
995
|
+
}
|
|
996
|
+
if (!o) {
|
|
997
|
+
return o;
|
|
998
|
+
}
|
|
999
|
+
return JSON.parse(JSON.stringify(o));
|
|
1000
|
+
}
|
|
982
1001
|
function deepMerge(target, source) {
|
|
983
1002
|
if (typeof source !== "object" || source === null) {
|
|
984
1003
|
return source;
|
|
@@ -1015,6 +1034,28 @@ function urlPath(url) {
|
|
|
1015
1034
|
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1016
1035
|
return "/" + pathMatch;
|
|
1017
1036
|
}
|
|
1037
|
+
function canonicalUrl() {
|
|
1038
|
+
if (!isInBrowser())
|
|
1039
|
+
return;
|
|
1040
|
+
const tags = document.getElementsByTagName("link");
|
|
1041
|
+
for (var i = 0, tag; (tag = tags[i]); i++) {
|
|
1042
|
+
if (tag.getAttribute("rel") === "canonical") {
|
|
1043
|
+
return tag.getAttribute("href");
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
/**
|
|
1048
|
+
* bugged analytics.js logic that produces 'url' parameter by concating canonical URL with current search part
|
|
1049
|
+
* I produces broken results in some cases like SPA where path is changed but canonical URL is not updated
|
|
1050
|
+
*/
|
|
1051
|
+
function analyticsJsUrl() {
|
|
1052
|
+
if (!isInBrowser())
|
|
1053
|
+
return;
|
|
1054
|
+
const canonical = canonicalUrl();
|
|
1055
|
+
if (!canonical)
|
|
1056
|
+
return window.location.href.replace(hashRegex, "");
|
|
1057
|
+
return canonical.match(/\?/) ? canonical : canonical + window.location.search;
|
|
1058
|
+
}
|
|
1018
1059
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1019
1060
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1020
1061
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1023,9 +1064,16 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1023
1064
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1024
1065
|
const properties = payload.properties || {};
|
|
1025
1066
|
if (payload.type === "page" && (properties.url || url)) {
|
|
1026
|
-
|
|
1067
|
+
// we don't trust analytics.js URL logic since it's sticks with canonical URL on SPA pages
|
|
1068
|
+
let targetUrl = url || properties.url;
|
|
1069
|
+
if (properties.url && properties.url !== analyticsJsUrl()) {
|
|
1070
|
+
// properties.url is not the same as provided by analytics.js
|
|
1071
|
+
// it means that it was not overridden by user and we should use it
|
|
1072
|
+
targetUrl = properties.url;
|
|
1073
|
+
}
|
|
1027
1074
|
properties.url = targetUrl.replace(hashRegex, "");
|
|
1028
1075
|
properties.path = fixPath(urlPath(targetUrl));
|
|
1076
|
+
// other properties are correctly based on window.location in analytics.js
|
|
1029
1077
|
}
|
|
1030
1078
|
const customContext = deepMerge(config.defaultPayloadContext, ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {});
|
|
1031
1079
|
(_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
|
|
@@ -1079,15 +1127,18 @@ function processDestinations(destinations, method, originalEvent, debug, analyti
|
|
|
1079
1127
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1080
1128
|
const promises = [];
|
|
1081
1129
|
for (const destination of destinations) {
|
|
1082
|
-
let newEvents = [
|
|
1130
|
+
let newEvents = [];
|
|
1083
1131
|
if (destination.newEvents) {
|
|
1084
1132
|
try {
|
|
1085
|
-
newEvents = destination.newEvents.map(e => e === "same" ? originalEvent : isDiff(e) ? diff.patch(originalEvent, e.__diff) : e);
|
|
1133
|
+
newEvents = destination.newEvents.map(e => e === "same" ? deepCopy(originalEvent) : isDiff(e) ? diff.patch(deepCopy(originalEvent), e.__diff) : e);
|
|
1086
1134
|
}
|
|
1087
1135
|
catch (e) {
|
|
1088
1136
|
console.error(`[JITSU] Error applying '${destination.id}' changes to event: ${e === null || e === void 0 ? void 0 : e.message}`, e);
|
|
1089
1137
|
}
|
|
1090
1138
|
}
|
|
1139
|
+
else {
|
|
1140
|
+
newEvents = [deepCopy(originalEvent)];
|
|
1141
|
+
}
|
|
1091
1142
|
const credentials = Object.assign(Object.assign({}, destination.credentials), destination.options);
|
|
1092
1143
|
if (destination.deviceOptions.type === "internal-plugin") {
|
|
1093
1144
|
const plugin = internalDestinationPlugins[destination.deviceOptions.name];
|
package/dist/jitsu.cjs.js
CHANGED
|
@@ -1164,6 +1164,19 @@ function getClientIds(runtime, customCookieCapture) {
|
|
|
1164
1164
|
}, {});
|
|
1165
1165
|
return Object.assign(Object.assign({}, clientIds), getGa4Ids(runtime));
|
|
1166
1166
|
}
|
|
1167
|
+
function parseGa4SessionId(cookieValue) {
|
|
1168
|
+
if (typeof cookieValue !== "string") {
|
|
1169
|
+
return undefined;
|
|
1170
|
+
}
|
|
1171
|
+
if (cookieValue.startsWith("GA1") || cookieValue.startsWith("GS1")) {
|
|
1172
|
+
return cookieValue.split(".")[2];
|
|
1173
|
+
}
|
|
1174
|
+
else {
|
|
1175
|
+
// parse new GA4 cookie format, e.g.: GS2.1.s1747323152$o28$g0$t1747323152$j60$l0$h69286059
|
|
1176
|
+
const match = cookieValue.match(/^GS\d+\.\d+\.(?:[\w_-]+[$])*s(\d+)(?:$|[$])/);
|
|
1177
|
+
return match ? match[1] : undefined;
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1167
1180
|
function getGa4Ids(runtime) {
|
|
1168
1181
|
var _a;
|
|
1169
1182
|
const allCookies = runtime.getCookies();
|
|
@@ -1172,14 +1185,11 @@ function getGa4Ids(runtime) {
|
|
|
1172
1185
|
const sessionIds = gaSessionCookies.length > 0
|
|
1173
1186
|
? Object.fromEntries(gaSessionCookies
|
|
1174
1187
|
.map(([key, value]) => {
|
|
1175
|
-
|
|
1188
|
+
const sessionId = parseGa4SessionId(value);
|
|
1189
|
+
if (!sessionId) {
|
|
1176
1190
|
return null;
|
|
1177
1191
|
}
|
|
1178
|
-
|
|
1179
|
-
if (parts.length < 3) {
|
|
1180
|
-
return null;
|
|
1181
|
-
}
|
|
1182
|
-
return [key.substring("_ga_".length), parts[2]];
|
|
1192
|
+
return [key.substring("_ga_".length), sessionId];
|
|
1183
1193
|
})
|
|
1184
1194
|
.filter(v => v !== null))
|
|
1185
1195
|
: undefined;
|
|
@@ -1403,6 +1413,15 @@ const emptyRuntime = (config) => ({
|
|
|
1403
1413
|
return undefined;
|
|
1404
1414
|
},
|
|
1405
1415
|
});
|
|
1416
|
+
function deepCopy(o) {
|
|
1417
|
+
if (typeof o !== "object") {
|
|
1418
|
+
return o;
|
|
1419
|
+
}
|
|
1420
|
+
if (!o) {
|
|
1421
|
+
return o;
|
|
1422
|
+
}
|
|
1423
|
+
return JSON.parse(JSON.stringify(o));
|
|
1424
|
+
}
|
|
1406
1425
|
function deepMerge(target, source) {
|
|
1407
1426
|
if (typeof source !== "object" || source === null) {
|
|
1408
1427
|
return source;
|
|
@@ -1439,6 +1458,28 @@ function urlPath(url) {
|
|
|
1439
1458
|
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1440
1459
|
return "/" + pathMatch;
|
|
1441
1460
|
}
|
|
1461
|
+
function canonicalUrl() {
|
|
1462
|
+
if (!isInBrowser())
|
|
1463
|
+
return;
|
|
1464
|
+
const tags = document.getElementsByTagName("link");
|
|
1465
|
+
for (var i = 0, tag; (tag = tags[i]); i++) {
|
|
1466
|
+
if (tag.getAttribute("rel") === "canonical") {
|
|
1467
|
+
return tag.getAttribute("href");
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
/**
|
|
1472
|
+
* bugged analytics.js logic that produces 'url' parameter by concating canonical URL with current search part
|
|
1473
|
+
* I produces broken results in some cases like SPA where path is changed but canonical URL is not updated
|
|
1474
|
+
*/
|
|
1475
|
+
function analyticsJsUrl() {
|
|
1476
|
+
if (!isInBrowser())
|
|
1477
|
+
return;
|
|
1478
|
+
const canonical = canonicalUrl();
|
|
1479
|
+
if (!canonical)
|
|
1480
|
+
return window.location.href.replace(hashRegex, "");
|
|
1481
|
+
return canonical.match(/\?/) ? canonical : canonical + window.location.search;
|
|
1482
|
+
}
|
|
1442
1483
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1443
1484
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1444
1485
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1447,9 +1488,16 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1447
1488
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1448
1489
|
const properties = payload.properties || {};
|
|
1449
1490
|
if (payload.type === "page" && (properties.url || url)) {
|
|
1450
|
-
|
|
1491
|
+
// we don't trust analytics.js URL logic since it's sticks with canonical URL on SPA pages
|
|
1492
|
+
let targetUrl = url || properties.url;
|
|
1493
|
+
if (properties.url && properties.url !== analyticsJsUrl()) {
|
|
1494
|
+
// properties.url is not the same as provided by analytics.js
|
|
1495
|
+
// it means that it was not overridden by user and we should use it
|
|
1496
|
+
targetUrl = properties.url;
|
|
1497
|
+
}
|
|
1451
1498
|
properties.url = targetUrl.replace(hashRegex, "");
|
|
1452
1499
|
properties.path = fixPath(urlPath(targetUrl));
|
|
1500
|
+
// other properties are correctly based on window.location in analytics.js
|
|
1453
1501
|
}
|
|
1454
1502
|
const customContext = deepMerge(config.defaultPayloadContext, ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {});
|
|
1455
1503
|
(_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
|
|
@@ -1503,15 +1551,18 @@ function processDestinations(destinations, method, originalEvent, debug, analyti
|
|
|
1503
1551
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1504
1552
|
const promises = [];
|
|
1505
1553
|
for (const destination of destinations) {
|
|
1506
|
-
let newEvents = [
|
|
1554
|
+
let newEvents = [];
|
|
1507
1555
|
if (destination.newEvents) {
|
|
1508
1556
|
try {
|
|
1509
|
-
newEvents = destination.newEvents.map(e => e === "same" ? originalEvent : isDiff(e) ? diff.patch(originalEvent, e.__diff) : e);
|
|
1557
|
+
newEvents = destination.newEvents.map(e => e === "same" ? deepCopy(originalEvent) : isDiff(e) ? diff.patch(deepCopy(originalEvent), e.__diff) : e);
|
|
1510
1558
|
}
|
|
1511
1559
|
catch (e) {
|
|
1512
1560
|
console.error(`[JITSU] Error applying '${destination.id}' changes to event: ${e === null || e === void 0 ? void 0 : e.message}`, e);
|
|
1513
1561
|
}
|
|
1514
1562
|
}
|
|
1563
|
+
else {
|
|
1564
|
+
newEvents = [deepCopy(originalEvent)];
|
|
1565
|
+
}
|
|
1515
1566
|
const credentials = Object.assign(Object.assign({}, destination.credentials), destination.options);
|
|
1516
1567
|
if (destination.deviceOptions.type === "internal-plugin") {
|
|
1517
1568
|
const plugin = internalDestinationPlugins[destination.deviceOptions.name];
|
package/dist/jitsu.es.js
CHANGED
|
@@ -1162,6 +1162,19 @@ function getClientIds(runtime, customCookieCapture) {
|
|
|
1162
1162
|
}, {});
|
|
1163
1163
|
return Object.assign(Object.assign({}, clientIds), getGa4Ids(runtime));
|
|
1164
1164
|
}
|
|
1165
|
+
function parseGa4SessionId(cookieValue) {
|
|
1166
|
+
if (typeof cookieValue !== "string") {
|
|
1167
|
+
return undefined;
|
|
1168
|
+
}
|
|
1169
|
+
if (cookieValue.startsWith("GA1") || cookieValue.startsWith("GS1")) {
|
|
1170
|
+
return cookieValue.split(".")[2];
|
|
1171
|
+
}
|
|
1172
|
+
else {
|
|
1173
|
+
// parse new GA4 cookie format, e.g.: GS2.1.s1747323152$o28$g0$t1747323152$j60$l0$h69286059
|
|
1174
|
+
const match = cookieValue.match(/^GS\d+\.\d+\.(?:[\w_-]+[$])*s(\d+)(?:$|[$])/);
|
|
1175
|
+
return match ? match[1] : undefined;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1165
1178
|
function getGa4Ids(runtime) {
|
|
1166
1179
|
var _a;
|
|
1167
1180
|
const allCookies = runtime.getCookies();
|
|
@@ -1170,14 +1183,11 @@ function getGa4Ids(runtime) {
|
|
|
1170
1183
|
const sessionIds = gaSessionCookies.length > 0
|
|
1171
1184
|
? Object.fromEntries(gaSessionCookies
|
|
1172
1185
|
.map(([key, value]) => {
|
|
1173
|
-
|
|
1186
|
+
const sessionId = parseGa4SessionId(value);
|
|
1187
|
+
if (!sessionId) {
|
|
1174
1188
|
return null;
|
|
1175
1189
|
}
|
|
1176
|
-
|
|
1177
|
-
if (parts.length < 3) {
|
|
1178
|
-
return null;
|
|
1179
|
-
}
|
|
1180
|
-
return [key.substring("_ga_".length), parts[2]];
|
|
1190
|
+
return [key.substring("_ga_".length), sessionId];
|
|
1181
1191
|
})
|
|
1182
1192
|
.filter(v => v !== null))
|
|
1183
1193
|
: undefined;
|
|
@@ -1401,6 +1411,15 @@ const emptyRuntime = (config) => ({
|
|
|
1401
1411
|
return undefined;
|
|
1402
1412
|
},
|
|
1403
1413
|
});
|
|
1414
|
+
function deepCopy(o) {
|
|
1415
|
+
if (typeof o !== "object") {
|
|
1416
|
+
return o;
|
|
1417
|
+
}
|
|
1418
|
+
if (!o) {
|
|
1419
|
+
return o;
|
|
1420
|
+
}
|
|
1421
|
+
return JSON.parse(JSON.stringify(o));
|
|
1422
|
+
}
|
|
1404
1423
|
function deepMerge(target, source) {
|
|
1405
1424
|
if (typeof source !== "object" || source === null) {
|
|
1406
1425
|
return source;
|
|
@@ -1437,6 +1456,28 @@ function urlPath(url) {
|
|
|
1437
1456
|
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1438
1457
|
return "/" + pathMatch;
|
|
1439
1458
|
}
|
|
1459
|
+
function canonicalUrl() {
|
|
1460
|
+
if (!isInBrowser())
|
|
1461
|
+
return;
|
|
1462
|
+
const tags = document.getElementsByTagName("link");
|
|
1463
|
+
for (var i = 0, tag; (tag = tags[i]); i++) {
|
|
1464
|
+
if (tag.getAttribute("rel") === "canonical") {
|
|
1465
|
+
return tag.getAttribute("href");
|
|
1466
|
+
}
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
/**
|
|
1470
|
+
* bugged analytics.js logic that produces 'url' parameter by concating canonical URL with current search part
|
|
1471
|
+
* I produces broken results in some cases like SPA where path is changed but canonical URL is not updated
|
|
1472
|
+
*/
|
|
1473
|
+
function analyticsJsUrl() {
|
|
1474
|
+
if (!isInBrowser())
|
|
1475
|
+
return;
|
|
1476
|
+
const canonical = canonicalUrl();
|
|
1477
|
+
if (!canonical)
|
|
1478
|
+
return window.location.href.replace(hashRegex, "");
|
|
1479
|
+
return canonical.match(/\?/) ? canonical : canonical + window.location.search;
|
|
1480
|
+
}
|
|
1440
1481
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1441
1482
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1442
1483
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1445,9 +1486,16 @@ function adjustPayload(payload, config, storage, s2s) {
|
|
|
1445
1486
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1446
1487
|
const properties = payload.properties || {};
|
|
1447
1488
|
if (payload.type === "page" && (properties.url || url)) {
|
|
1448
|
-
|
|
1489
|
+
// we don't trust analytics.js URL logic since it's sticks with canonical URL on SPA pages
|
|
1490
|
+
let targetUrl = url || properties.url;
|
|
1491
|
+
if (properties.url && properties.url !== analyticsJsUrl()) {
|
|
1492
|
+
// properties.url is not the same as provided by analytics.js
|
|
1493
|
+
// it means that it was not overridden by user and we should use it
|
|
1494
|
+
targetUrl = properties.url;
|
|
1495
|
+
}
|
|
1449
1496
|
properties.url = targetUrl.replace(hashRegex, "");
|
|
1450
1497
|
properties.path = fixPath(urlPath(targetUrl));
|
|
1498
|
+
// other properties are correctly based on window.location in analytics.js
|
|
1451
1499
|
}
|
|
1452
1500
|
const customContext = deepMerge(config.defaultPayloadContext, ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {});
|
|
1453
1501
|
(_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
|
|
@@ -1501,15 +1549,18 @@ function processDestinations(destinations, method, originalEvent, debug, analyti
|
|
|
1501
1549
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1502
1550
|
const promises = [];
|
|
1503
1551
|
for (const destination of destinations) {
|
|
1504
|
-
let newEvents = [
|
|
1552
|
+
let newEvents = [];
|
|
1505
1553
|
if (destination.newEvents) {
|
|
1506
1554
|
try {
|
|
1507
|
-
newEvents = destination.newEvents.map(e => e === "same" ? originalEvent : isDiff(e) ? diff.patch(originalEvent, e.__diff) : e);
|
|
1555
|
+
newEvents = destination.newEvents.map(e => e === "same" ? deepCopy(originalEvent) : isDiff(e) ? diff.patch(deepCopy(originalEvent), e.__diff) : e);
|
|
1508
1556
|
}
|
|
1509
1557
|
catch (e) {
|
|
1510
1558
|
console.error(`[JITSU] Error applying '${destination.id}' changes to event: ${e === null || e === void 0 ? void 0 : e.message}`, e);
|
|
1511
1559
|
}
|
|
1512
1560
|
}
|
|
1561
|
+
else {
|
|
1562
|
+
newEvents = [deepCopy(originalEvent)];
|
|
1563
|
+
}
|
|
1513
1564
|
const credentials = Object.assign(Object.assign({}, destination.credentials), destination.options);
|
|
1514
1565
|
if (destination.deviceOptions.type === "internal-plugin") {
|
|
1515
1566
|
const plugin = internalDestinationPlugins[destination.deviceOptions.name];
|
package/dist/web/p.js.txt
CHANGED
|
@@ -1165,6 +1165,19 @@
|
|
|
1165
1165
|
}, {});
|
|
1166
1166
|
return Object.assign(Object.assign({}, clientIds), getGa4Ids(runtime));
|
|
1167
1167
|
}
|
|
1168
|
+
function parseGa4SessionId(cookieValue) {
|
|
1169
|
+
if (typeof cookieValue !== "string") {
|
|
1170
|
+
return undefined;
|
|
1171
|
+
}
|
|
1172
|
+
if (cookieValue.startsWith("GA1") || cookieValue.startsWith("GS1")) {
|
|
1173
|
+
return cookieValue.split(".")[2];
|
|
1174
|
+
}
|
|
1175
|
+
else {
|
|
1176
|
+
// parse new GA4 cookie format, e.g.: GS2.1.s1747323152$o28$g0$t1747323152$j60$l0$h69286059
|
|
1177
|
+
const match = cookieValue.match(/^GS\d+\.\d+\.(?:[\w_-]+[$])*s(\d+)(?:$|[$])/);
|
|
1178
|
+
return match ? match[1] : undefined;
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1168
1181
|
function getGa4Ids(runtime) {
|
|
1169
1182
|
var _a;
|
|
1170
1183
|
const allCookies = runtime.getCookies();
|
|
@@ -1173,14 +1186,11 @@
|
|
|
1173
1186
|
const sessionIds = gaSessionCookies.length > 0
|
|
1174
1187
|
? Object.fromEntries(gaSessionCookies
|
|
1175
1188
|
.map(([key, value]) => {
|
|
1176
|
-
|
|
1189
|
+
const sessionId = parseGa4SessionId(value);
|
|
1190
|
+
if (!sessionId) {
|
|
1177
1191
|
return null;
|
|
1178
1192
|
}
|
|
1179
|
-
|
|
1180
|
-
if (parts.length < 3) {
|
|
1181
|
-
return null;
|
|
1182
|
-
}
|
|
1183
|
-
return [key.substring("_ga_".length), parts[2]];
|
|
1193
|
+
return [key.substring("_ga_".length), sessionId];
|
|
1184
1194
|
})
|
|
1185
1195
|
.filter(v => v !== null))
|
|
1186
1196
|
: undefined;
|
|
@@ -1404,6 +1414,15 @@
|
|
|
1404
1414
|
return undefined;
|
|
1405
1415
|
},
|
|
1406
1416
|
});
|
|
1417
|
+
function deepCopy(o) {
|
|
1418
|
+
if (typeof o !== "object") {
|
|
1419
|
+
return o;
|
|
1420
|
+
}
|
|
1421
|
+
if (!o) {
|
|
1422
|
+
return o;
|
|
1423
|
+
}
|
|
1424
|
+
return JSON.parse(JSON.stringify(o));
|
|
1425
|
+
}
|
|
1407
1426
|
function deepMerge(target, source) {
|
|
1408
1427
|
if (typeof source !== "object" || source === null) {
|
|
1409
1428
|
return source;
|
|
@@ -1440,6 +1459,28 @@
|
|
|
1440
1459
|
const pathMatch = matches && matches[3] ? matches[3].split("?")[0].replace(hashRegex, "") : "";
|
|
1441
1460
|
return "/" + pathMatch;
|
|
1442
1461
|
}
|
|
1462
|
+
function canonicalUrl() {
|
|
1463
|
+
if (!isInBrowser())
|
|
1464
|
+
return;
|
|
1465
|
+
const tags = document.getElementsByTagName("link");
|
|
1466
|
+
for (var i = 0, tag; (tag = tags[i]); i++) {
|
|
1467
|
+
if (tag.getAttribute("rel") === "canonical") {
|
|
1468
|
+
return tag.getAttribute("href");
|
|
1469
|
+
}
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
/**
|
|
1473
|
+
* bugged analytics.js logic that produces 'url' parameter by concating canonical URL with current search part
|
|
1474
|
+
* I produces broken results in some cases like SPA where path is changed but canonical URL is not updated
|
|
1475
|
+
*/
|
|
1476
|
+
function analyticsJsUrl() {
|
|
1477
|
+
if (!isInBrowser())
|
|
1478
|
+
return;
|
|
1479
|
+
const canonical = canonicalUrl();
|
|
1480
|
+
if (!canonical)
|
|
1481
|
+
return window.location.href.replace(hashRegex, "");
|
|
1482
|
+
return canonical.match(/\?/) ? canonical : canonical + window.location.search;
|
|
1483
|
+
}
|
|
1443
1484
|
function adjustPayload(payload, config, storage, s2s) {
|
|
1444
1485
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q;
|
|
1445
1486
|
const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
@@ -1448,9 +1489,16 @@
|
|
|
1448
1489
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
1449
1490
|
const properties = payload.properties || {};
|
|
1450
1491
|
if (payload.type === "page" && (properties.url || url)) {
|
|
1451
|
-
|
|
1492
|
+
// we don't trust analytics.js URL logic since it's sticks with canonical URL on SPA pages
|
|
1493
|
+
let targetUrl = url || properties.url;
|
|
1494
|
+
if (properties.url && properties.url !== analyticsJsUrl()) {
|
|
1495
|
+
// properties.url is not the same as provided by analytics.js
|
|
1496
|
+
// it means that it was not overridden by user and we should use it
|
|
1497
|
+
targetUrl = properties.url;
|
|
1498
|
+
}
|
|
1452
1499
|
properties.url = targetUrl.replace(hashRegex, "");
|
|
1453
1500
|
properties.path = fixPath(urlPath(targetUrl));
|
|
1501
|
+
// other properties are correctly based on window.location in analytics.js
|
|
1454
1502
|
}
|
|
1455
1503
|
const customContext = deepMerge(config.defaultPayloadContext, ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {});
|
|
1456
1504
|
(_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
|
|
@@ -1504,15 +1552,18 @@
|
|
|
1504
1552
|
return __awaiter$1(this, void 0, void 0, function* () {
|
|
1505
1553
|
const promises = [];
|
|
1506
1554
|
for (const destination of destinations) {
|
|
1507
|
-
let newEvents = [
|
|
1555
|
+
let newEvents = [];
|
|
1508
1556
|
if (destination.newEvents) {
|
|
1509
1557
|
try {
|
|
1510
|
-
newEvents = destination.newEvents.map(e => e === "same" ? originalEvent : isDiff(e) ? diff.patch(originalEvent, e.__diff) : e);
|
|
1558
|
+
newEvents = destination.newEvents.map(e => e === "same" ? deepCopy(originalEvent) : isDiff(e) ? diff.patch(deepCopy(originalEvent), e.__diff) : e);
|
|
1511
1559
|
}
|
|
1512
1560
|
catch (e) {
|
|
1513
1561
|
console.error(`[JITSU] Error applying '${destination.id}' changes to event: ${e === null || e === void 0 ? void 0 : e.message}`, e);
|
|
1514
1562
|
}
|
|
1515
1563
|
}
|
|
1564
|
+
else {
|
|
1565
|
+
newEvents = [deepCopy(originalEvent)];
|
|
1566
|
+
}
|
|
1516
1567
|
const credentials = Object.assign(Object.assign({}, destination.credentials), destination.options);
|
|
1517
1568
|
if (destination.deviceOptions.type === "internal-plugin") {
|
|
1518
1569
|
const plugin = internalDestinationPlugins[destination.deviceOptions.name];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jitsu/js",
|
|
3
|
-
"version": "1.10.
|
|
3
|
+
"version": "1.10.4",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "Jitsu Dev Team <dev@jitsu.com>",
|
|
6
6
|
"main": "dist/jitsu.cjs.js",
|
|
@@ -39,10 +39,10 @@
|
|
|
39
39
|
"rollup": "^3.29.5",
|
|
40
40
|
"ts-jest": "29.0.5",
|
|
41
41
|
"typescript": "^5.6.3",
|
|
42
|
-
"jsondiffpatch": "1.10.
|
|
42
|
+
"jsondiffpatch": "1.10.4"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"@jitsu/protocols": "1.10.
|
|
45
|
+
"@jitsu/protocols": "1.10.4"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
48
|
"analytics": "0.8.9"
|