@jitsu/js 1.1.0-canary.227.20230222142636 → 1.1.0-canary.388.20230519133920
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 +53 -23
- package/.turbo/turbo-clean.log +1 -1
- package/__tests__/node/nodejs.test.ts +14 -6
- package/__tests__/playwright/integration.test.ts +1 -2
- package/dist/index.d.ts +1 -0
- package/dist/jitsu.cjs.js +249 -53
- package/dist/jitsu.d.ts +1 -1
- package/dist/jitsu.es.js +249 -53
- package/dist/web/p.js.txt +248 -53
- package/package.json +5 -4
- package/src/analytics-plugin.ts +30 -11
- package/src/destination-plugins/gtm.ts +102 -0
- package/src/destination-plugins/index.ts +32 -0
- package/src/destination-plugins/logrocket.ts +83 -0
- package/src/{destination-plugins.ts → destination-plugins/tag.ts} +3 -28
- package/src/index.ts +13 -3
- package/src/jitsu.ts +1 -1
- package/dist/destination-plugins.d.ts +0 -13
package/dist/web/p.js.txt
CHANGED
|
@@ -68,7 +68,50 @@
|
|
|
68
68
|
return ke(_objectSpread2(_objectSpread2({}, defaultSettings), opts));
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
function findScript(src) {
|
|
72
|
+
const scripts = Array.prototype.slice.call(window.document.querySelectorAll("script"));
|
|
73
|
+
return scripts.find(s => s.src === src);
|
|
74
|
+
}
|
|
75
|
+
function loadScript(src, attributes) {
|
|
76
|
+
const found = findScript(src);
|
|
77
|
+
if (found !== undefined) {
|
|
78
|
+
const status = found === null || found === void 0 ? void 0 : found.getAttribute("status");
|
|
79
|
+
if (status === "loaded") {
|
|
80
|
+
return Promise.resolve(found);
|
|
81
|
+
}
|
|
82
|
+
if (status === "loading") {
|
|
83
|
+
return new Promise((resolve, reject) => {
|
|
84
|
+
found.addEventListener("load", () => resolve(found));
|
|
85
|
+
found.addEventListener("error", err => reject(err));
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return new Promise((resolve, reject) => {
|
|
90
|
+
var _a;
|
|
91
|
+
const script = window.document.createElement("script");
|
|
92
|
+
script.type = "text/javascript";
|
|
93
|
+
script.src = src;
|
|
94
|
+
script.async = true;
|
|
95
|
+
script.setAttribute("status", "loading");
|
|
96
|
+
for (const [k, v] of Object.entries(attributes !== null && attributes !== void 0 ? attributes : {})) {
|
|
97
|
+
script.setAttribute(k, v);
|
|
98
|
+
}
|
|
99
|
+
script.onload = () => {
|
|
100
|
+
script.onerror = script.onload = null;
|
|
101
|
+
script.setAttribute("status", "loaded");
|
|
102
|
+
resolve(script);
|
|
103
|
+
};
|
|
104
|
+
script.onerror = () => {
|
|
105
|
+
script.onerror = script.onload = null;
|
|
106
|
+
script.setAttribute("status", "error");
|
|
107
|
+
reject(new Error(`Failed to load ${src}`));
|
|
108
|
+
};
|
|
109
|
+
const tag = window.document.getElementsByTagName("script")[0];
|
|
110
|
+
(_a = tag.parentElement) === null || _a === void 0 ? void 0 : _a.insertBefore(script, tag);
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
var __awaiter$3 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
72
115
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
73
116
|
return new (P || (P = Promise))(function (resolve, reject) {
|
|
74
117
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
@@ -77,18 +120,10 @@
|
|
|
77
120
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
78
121
|
});
|
|
79
122
|
};
|
|
80
|
-
function satisfyFilter(filter, subject) {
|
|
81
|
-
return filter === "*" || filter.toLowerCase().trim() === (subject || "").trim().toLowerCase();
|
|
82
|
-
}
|
|
83
|
-
function applyFilters(event, creds) {
|
|
84
|
-
const { hosts = ["*"], events = ["*"] } = creds;
|
|
85
|
-
return (!!hosts.find(hostFilter => { var _a; return satisfyFilter(hostFilter, (_a = event.context) === null || _a === void 0 ? void 0 : _a.host); }) &&
|
|
86
|
-
!!events.find(eventFilter => satisfyFilter(eventFilter, event.type)));
|
|
87
|
-
}
|
|
88
123
|
const tagPlugin = {
|
|
89
124
|
id: "tag",
|
|
90
125
|
handle(config, payload) {
|
|
91
|
-
return __awaiter$
|
|
126
|
+
return __awaiter$3(this, void 0, void 0, function* () {
|
|
92
127
|
if (!applyFilters(payload, config)) {
|
|
93
128
|
return;
|
|
94
129
|
}
|
|
@@ -156,53 +191,193 @@
|
|
|
156
191
|
function replaceMacro(code, event) {
|
|
157
192
|
return code.replace(/{{\s*event\s*}}/g, JSON.stringify(event));
|
|
158
193
|
}
|
|
159
|
-
const internalDestinationPlugins = {
|
|
160
|
-
[tagPlugin.id]: tagPlugin,
|
|
161
|
-
};
|
|
162
194
|
|
|
163
|
-
function
|
|
164
|
-
|
|
165
|
-
return
|
|
195
|
+
var __awaiter$2 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
196
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
197
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
198
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
199
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
200
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
201
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
202
|
+
});
|
|
203
|
+
};
|
|
204
|
+
const logrocketPlugin = {
|
|
205
|
+
id: "logrocket",
|
|
206
|
+
handle(config, payload) {
|
|
207
|
+
return __awaiter$2(this, void 0, void 0, function* () {
|
|
208
|
+
if (!applyFilters(payload, config)) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
initLogrocketIfNeeded(config.appId);
|
|
212
|
+
const action = logRocket => {
|
|
213
|
+
if (payload.type === "identify" && payload.userId) {
|
|
214
|
+
logRocket.identify(payload.userId, payload.traits || {});
|
|
215
|
+
}
|
|
216
|
+
};
|
|
217
|
+
getLogRocketQueue().push(action);
|
|
218
|
+
if (getLogRocketState() === "loaded") {
|
|
219
|
+
flushLogRocketQueue(window["LogRocket"]);
|
|
220
|
+
}
|
|
221
|
+
});
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
function getLogRocketState() {
|
|
225
|
+
return window["__jitsuLrState"] || "fresh";
|
|
166
226
|
}
|
|
167
|
-
function
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
227
|
+
function setLogRocketState(s) {
|
|
228
|
+
window["__jitsuLrState"] = s;
|
|
229
|
+
}
|
|
230
|
+
function getLogRocketQueue() {
|
|
231
|
+
return window["__jitsuLrQueue"] || (window["__jitsuLrQueue"] = []);
|
|
232
|
+
}
|
|
233
|
+
function flushLogRocketQueue(lr) {
|
|
234
|
+
const queue = getLogRocketQueue();
|
|
235
|
+
while (queue.length > 0) {
|
|
236
|
+
const method = queue.shift();
|
|
237
|
+
try {
|
|
238
|
+
const res = method(lr);
|
|
239
|
+
if (res) {
|
|
240
|
+
res.catch(e => console.warn(`Async LogRocket method failed: ${e.message}`, e));
|
|
241
|
+
}
|
|
173
242
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
found.addEventListener("load", () => resolve(found));
|
|
177
|
-
found.addEventListener("error", err => reject(err));
|
|
178
|
-
});
|
|
243
|
+
catch (e) {
|
|
244
|
+
console.warn(`LogRocket method failed: ${e.message}`, e);
|
|
179
245
|
}
|
|
180
246
|
}
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
script.async = true;
|
|
187
|
-
script.setAttribute("status", "loading");
|
|
188
|
-
for (const [k, v] of Object.entries(attributes !== null && attributes !== void 0 ? attributes : {})) {
|
|
189
|
-
script.setAttribute(k, v);
|
|
247
|
+
}
|
|
248
|
+
function initLogrocketIfNeeded(appId) {
|
|
249
|
+
return __awaiter$2(this, void 0, void 0, function* () {
|
|
250
|
+
if (getLogRocketState() !== "fresh") {
|
|
251
|
+
return;
|
|
190
252
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
253
|
+
setLogRocketState("loading");
|
|
254
|
+
loadScript(`https://cdn.lr-ingest.io/LogRocket.min.js`, { crossOrigin: "anonymous" })
|
|
255
|
+
.then(() => {
|
|
256
|
+
if (window["LogRocket"]) {
|
|
257
|
+
try {
|
|
258
|
+
window["LogRocket"].init(appId);
|
|
259
|
+
}
|
|
260
|
+
catch (e) {
|
|
261
|
+
console.warn(`LogRocket (id=${appId}) init failed: ${e.message}`, e);
|
|
262
|
+
setLogRocketState("failed");
|
|
263
|
+
}
|
|
264
|
+
setLogRocketState("loaded");
|
|
265
|
+
flushLogRocketQueue(window["LogRocket"]);
|
|
266
|
+
}
|
|
267
|
+
})
|
|
268
|
+
.catch(e => {
|
|
269
|
+
console.warn(`LogRocket (id=${appId}) init failed: ${e.message}`, e);
|
|
270
|
+
setLogRocketState("failed");
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
var __awaiter$1 = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
276
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
277
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
278
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
279
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
280
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
281
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
282
|
+
});
|
|
283
|
+
};
|
|
284
|
+
const defaultScriptSrc = "https://www.googletagmanager.com/gtag/js";
|
|
285
|
+
const gtmPlugin = {
|
|
286
|
+
id: "gtm",
|
|
287
|
+
handle(config, payload) {
|
|
288
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
289
|
+
if (!applyFilters(payload, config)) {
|
|
290
|
+
return;
|
|
291
|
+
}
|
|
292
|
+
yield initGtmIfNeeded(config);
|
|
293
|
+
const dataLayer = window[config.dataLayerName || "dataLayer"];
|
|
294
|
+
switch (payload.type) {
|
|
295
|
+
case "page":
|
|
296
|
+
const { properties: pageProperties } = payload;
|
|
297
|
+
const pageEvent = Object.assign({ event: "page_view" }, pageProperties);
|
|
298
|
+
if (config.debug) {
|
|
299
|
+
console.log("gtag push", pageEvent);
|
|
300
|
+
}
|
|
301
|
+
dataLayer.push(pageEvent);
|
|
302
|
+
break;
|
|
303
|
+
case "track":
|
|
304
|
+
const { properties: trackProperties } = payload;
|
|
305
|
+
const trackEvent = Object.assign({ event: payload.event }, trackProperties);
|
|
306
|
+
if (config.debug) {
|
|
307
|
+
console.log("gtag push", trackEvent);
|
|
308
|
+
}
|
|
309
|
+
dataLayer.push(trackEvent);
|
|
310
|
+
break;
|
|
311
|
+
case "identify":
|
|
312
|
+
const { anonymousId, userId, traits } = payload;
|
|
313
|
+
const user = traits;
|
|
314
|
+
if (userId) {
|
|
315
|
+
user.userId = userId;
|
|
316
|
+
}
|
|
317
|
+
if (anonymousId) {
|
|
318
|
+
user.anonymousId = anonymousId;
|
|
319
|
+
}
|
|
320
|
+
const identifyEvent = { event: "identify", user: user };
|
|
321
|
+
if (config.debug) {
|
|
322
|
+
console.log("gtag push", identifyEvent);
|
|
323
|
+
}
|
|
324
|
+
dataLayer.push(identifyEvent);
|
|
325
|
+
break;
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
},
|
|
329
|
+
};
|
|
330
|
+
function getGtmState() {
|
|
331
|
+
return window["__jitsuGtmState"] || "fresh";
|
|
332
|
+
}
|
|
333
|
+
function setGtmState(s) {
|
|
334
|
+
window["__jitsuGtmState"] = s;
|
|
335
|
+
}
|
|
336
|
+
function initGtmIfNeeded(config) {
|
|
337
|
+
return __awaiter$1(this, void 0, void 0, function* () {
|
|
338
|
+
if (getGtmState() !== "fresh") {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
setGtmState("loading");
|
|
342
|
+
const dlName = config.dataLayerName || "dataLayer";
|
|
343
|
+
const dlParam = dlName !== "dataLayer" ? "&l=" + dlName : "";
|
|
344
|
+
const previewParams = config.preview
|
|
345
|
+
? `>m_preview=${config.preview}>m_auth=${config.auth}>m_cookies_win=x`
|
|
346
|
+
: "";
|
|
347
|
+
const scriptSrc = `${config.customScriptSrc || defaultScriptSrc}?id=${config.containerId}${dlParam}${previewParams}`;
|
|
348
|
+
window[dlName] = window[dlName] || [];
|
|
349
|
+
const gtag = function () {
|
|
350
|
+
window[dlName].push(arguments);
|
|
200
351
|
};
|
|
201
|
-
|
|
202
|
-
(
|
|
352
|
+
// @ts-ignore
|
|
353
|
+
gtag("js", new Date());
|
|
354
|
+
// @ts-ignore
|
|
355
|
+
gtag("config", config.containerId);
|
|
356
|
+
loadScript(scriptSrc)
|
|
357
|
+
.then(() => {
|
|
358
|
+
setGtmState("loaded");
|
|
359
|
+
})
|
|
360
|
+
.catch(e => {
|
|
361
|
+
console.warn(`GTM (containerId=${config.containerId}) init failed: ${e.message}`, e);
|
|
362
|
+
setGtmState("failed");
|
|
363
|
+
});
|
|
203
364
|
});
|
|
204
365
|
}
|
|
205
366
|
|
|
367
|
+
function satisfyFilter(filter, subject) {
|
|
368
|
+
return filter === "*" || filter.toLowerCase().trim() === (subject || "").trim().toLowerCase();
|
|
369
|
+
}
|
|
370
|
+
function applyFilters(event, creds) {
|
|
371
|
+
const { hosts = ["*"], events = ["*"] } = creds;
|
|
372
|
+
return (!!hosts.find(hostFilter => { var _a; return satisfyFilter(hostFilter, (_a = event.context) === null || _a === void 0 ? void 0 : _a.host); }) &&
|
|
373
|
+
!!events.find(eventFilter => satisfyFilter(eventFilter, event.type)));
|
|
374
|
+
}
|
|
375
|
+
const internalDestinationPlugins = {
|
|
376
|
+
[tagPlugin.id]: tagPlugin,
|
|
377
|
+
[gtmPlugin.id]: gtmPlugin,
|
|
378
|
+
[logrocketPlugin.id]: logrocketPlugin,
|
|
379
|
+
};
|
|
380
|
+
|
|
206
381
|
/* global analytics */
|
|
207
382
|
var __awaiter = (undefined && undefined.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
208
383
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
@@ -221,6 +396,8 @@
|
|
|
221
396
|
debug: false,
|
|
222
397
|
fetch: null,
|
|
223
398
|
echoEvents: false,
|
|
399
|
+
cookieDomain: undefined,
|
|
400
|
+
runtime: undefined,
|
|
224
401
|
};
|
|
225
402
|
const parseQuery = (qs) => {
|
|
226
403
|
if (!qs) {
|
|
@@ -444,7 +621,7 @@
|
|
|
444
621
|
userAgent: runtime.userAgent(),
|
|
445
622
|
locale: runtime.language(),
|
|
446
623
|
screen: runtime.screen(),
|
|
447
|
-
traits: payload.type != "identify" ? Object.assign({}, (restoreTraits(storage) || {})) : undefined,
|
|
624
|
+
traits: payload.type != "identify" && payload.type != "group" ? Object.assign({}, (restoreTraits(storage) || {})) : undefined,
|
|
448
625
|
page: {
|
|
449
626
|
path: properties.path || (parsedUrl && parsedUrl.pathname),
|
|
450
627
|
referrer: referrer,
|
|
@@ -453,7 +630,7 @@
|
|
|
453
630
|
search: properties.search || (parsedUrl && parsedUrl.search),
|
|
454
631
|
title: properties.title || runtime.pageTitle(),
|
|
455
632
|
url: properties.url || url,
|
|
456
|
-
|
|
633
|
+
encoding: properties.encoding || runtime.documentEncoding(),
|
|
457
634
|
},
|
|
458
635
|
campaign: parseUtms(query),
|
|
459
636
|
};
|
|
@@ -529,12 +706,12 @@
|
|
|
529
706
|
if (!fetch) {
|
|
530
707
|
throw new Error("Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope");
|
|
531
708
|
}
|
|
532
|
-
const authHeader = {};
|
|
533
709
|
const debugHeader = jitsuConfig.debug ? { "X-Enable-Debug": "true" } : {};
|
|
534
710
|
// if (jitsuConfig.debug) {
|
|
535
711
|
// console.log(`[JITSU] Sending event to ${url}: `, JSON.stringify(payload, null, 2));
|
|
536
712
|
// }
|
|
537
713
|
const adjustedPayload = adjustPayload(payload, jitsuConfig, store);
|
|
714
|
+
const authHeader = adjustedPayload.writeKey ? { "X-Write-Key": adjustedPayload.writeKey } : {};
|
|
538
715
|
return fetch(url, {
|
|
539
716
|
method: "POST",
|
|
540
717
|
headers: Object.assign(Object.assign({ "Content-Type": "application/json" }, authHeader), debugHeader),
|
|
@@ -561,7 +738,7 @@
|
|
|
561
738
|
}
|
|
562
739
|
if (response.destinations) {
|
|
563
740
|
if (jitsuConfig.debug) {
|
|
564
|
-
console.log(`[JITSU] Processing device
|
|
741
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(response.destinations, null, 2));
|
|
565
742
|
}
|
|
566
743
|
return processDestinations(response.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
567
744
|
}
|
|
@@ -590,9 +767,10 @@
|
|
|
590
767
|
persistentStorage.removeItem(key);
|
|
591
768
|
},
|
|
592
769
|
});
|
|
770
|
+
const instanceConfig = Object.assign(Object.assign({}, config), pluginConfig);
|
|
593
771
|
return {
|
|
594
772
|
name: "jitsu",
|
|
595
|
-
config:
|
|
773
|
+
config: instanceConfig,
|
|
596
774
|
initialize: args => {
|
|
597
775
|
const { config } = args;
|
|
598
776
|
if (config.debug) {
|
|
@@ -620,6 +798,16 @@
|
|
|
620
798
|
//clear storage cache
|
|
621
799
|
Object.keys(storageCache).forEach(key => delete storageCache[key]);
|
|
622
800
|
},
|
|
801
|
+
methods: {
|
|
802
|
+
//analytics doesn't support group as a base method, so we need to add it manually
|
|
803
|
+
group(groupId, traits, options, callback) {
|
|
804
|
+
const analyticsInstance = this.instance;
|
|
805
|
+
const user = analyticsInstance.user();
|
|
806
|
+
const userId = (options === null || options === void 0 ? void 0 : options.userId) || (user === null || user === void 0 ? void 0 : user.userId);
|
|
807
|
+
const anonymousId = (options === null || options === void 0 ? void 0 : options.anonymousId) || (user === null || user === void 0 ? void 0 : user.anonymousId);
|
|
808
|
+
return send("group", Object.assign(Object.assign({ type: "group", groupId, traits }, (anonymousId ? { anonymousId } : {})), (userId ? { userId } : {})), instanceConfig, analyticsInstance, cachingStorageWrapper(analyticsInstance.storage));
|
|
809
|
+
},
|
|
810
|
+
},
|
|
623
811
|
};
|
|
624
812
|
};
|
|
625
813
|
function getSeed() {
|
|
@@ -683,7 +871,14 @@
|
|
|
683
871
|
return originalPage(...args);
|
|
684
872
|
}
|
|
685
873
|
};
|
|
686
|
-
return analytics
|
|
874
|
+
return Object.assign(Object.assign({}, analytics), { group(groupId, traits, options, callback) {
|
|
875
|
+
for (const plugin of Object.values(analytics.plugins)) {
|
|
876
|
+
if (plugin["group"]) {
|
|
877
|
+
plugin["group"](groupId, traits, options, callback);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
return Promise.resolve({});
|
|
881
|
+
} });
|
|
687
882
|
}
|
|
688
883
|
function jitsuAnalytics(opts) {
|
|
689
884
|
const inBrowser = isInBrowser();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jitsu/js",
|
|
3
|
-
"version": "1.1.0-canary.
|
|
3
|
+
"version": "1.1.0-canary.388.20230519133920",
|
|
4
4
|
"description": "",
|
|
5
5
|
"author": "Jitsu Dev Team <dev@jitsu.com>",
|
|
6
6
|
"main": "dist/jitsu.cjs.js",
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"license": "MIT",
|
|
13
13
|
"private": false,
|
|
14
14
|
"devDependencies": {
|
|
15
|
-
"@playwright/test": "
|
|
15
|
+
"@playwright/test": "1.31.2",
|
|
16
16
|
"@rollup/plugin-commonjs": "^23.0.2",
|
|
17
17
|
"@rollup/plugin-json": "^5.0.1",
|
|
18
18
|
"@rollup/plugin-multi-entry": "^6.0.0",
|
|
@@ -32,8 +32,9 @@
|
|
|
32
32
|
"node-forge": "^1.3.1",
|
|
33
33
|
"raw-loader": "^4.0.2",
|
|
34
34
|
"rollup": "^3.2.5",
|
|
35
|
-
"ts-jest": "
|
|
36
|
-
"
|
|
35
|
+
"ts-jest": "29.0.5",
|
|
36
|
+
"typescript": "^4.9.5",
|
|
37
|
+
"@jitsu/protocols": "1.1.0-canary.388.20230519133920"
|
|
37
38
|
},
|
|
38
39
|
"dependencies": {
|
|
39
40
|
"analytics": "^0.8.1"
|
package/src/analytics-plugin.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
/* global analytics */
|
|
2
2
|
|
|
3
3
|
import { JitsuOptions, PersistentStorage, RuntimeFacade } from "./jitsu";
|
|
4
|
-
import { AnalyticsClientEvent } from "@jitsu/protocols/analytics";
|
|
4
|
+
import { AnalyticsClientEvent, Callback, ID, JSONObject, Options } from "@jitsu/protocols/analytics";
|
|
5
5
|
import parse from "./index";
|
|
6
6
|
import { AnalyticsInstance, AnalyticsPlugin } from "analytics";
|
|
7
|
-
import { internalDestinationPlugins } from "./destination-plugins";
|
|
8
7
|
import { loadScript } from "./script-loader";
|
|
8
|
+
import { internalDestinationPlugins } from "./destination-plugins";
|
|
9
9
|
|
|
10
|
-
const config: JitsuOptions = {
|
|
10
|
+
const config: Required<JitsuOptions> = {
|
|
11
11
|
/* Your segment writeKey */
|
|
12
12
|
writeKey: null,
|
|
13
13
|
/* Disable anonymous MTU */
|
|
@@ -15,6 +15,8 @@ const config: JitsuOptions = {
|
|
|
15
15
|
debug: false,
|
|
16
16
|
fetch: null,
|
|
17
17
|
echoEvents: false,
|
|
18
|
+
cookieDomain: undefined,
|
|
19
|
+
runtime: undefined,
|
|
18
20
|
};
|
|
19
21
|
|
|
20
22
|
export const parseQuery = (qs?: string): Record<string, string> => {
|
|
@@ -261,7 +263,7 @@ function adjustPayload(payload: any, config: JitsuOptions, storage: PersistentSt
|
|
|
261
263
|
userAgent: runtime.userAgent(),
|
|
262
264
|
locale: runtime.language(),
|
|
263
265
|
screen: runtime.screen(),
|
|
264
|
-
traits: payload.type != "identify" ? { ...(restoreTraits(storage) || {}) } : undefined,
|
|
266
|
+
traits: payload.type != "identify" && payload.type != "group" ? { ...(restoreTraits(storage) || {}) } : undefined,
|
|
265
267
|
page: {
|
|
266
268
|
path: properties.path || (parsedUrl && parsedUrl.pathname),
|
|
267
269
|
referrer: referrer,
|
|
@@ -270,7 +272,7 @@ function adjustPayload(payload: any, config: JitsuOptions, storage: PersistentSt
|
|
|
270
272
|
search: properties.search || (parsedUrl && parsedUrl.search),
|
|
271
273
|
title: properties.title || runtime.pageTitle(),
|
|
272
274
|
url: properties.url || url,
|
|
273
|
-
|
|
275
|
+
encoding: properties.encoding || runtime.documentEncoding(),
|
|
274
276
|
},
|
|
275
277
|
campaign: parseUtms(query),
|
|
276
278
|
};
|
|
@@ -402,13 +404,13 @@ function send(
|
|
|
402
404
|
"Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope"
|
|
403
405
|
);
|
|
404
406
|
}
|
|
405
|
-
const authHeader = {};
|
|
406
407
|
const debugHeader = jitsuConfig.debug ? { "X-Enable-Debug": "true" } : {};
|
|
407
408
|
|
|
408
409
|
// if (jitsuConfig.debug) {
|
|
409
410
|
// console.log(`[JITSU] Sending event to ${url}: `, JSON.stringify(payload, null, 2));
|
|
410
411
|
// }
|
|
411
412
|
const adjustedPayload = adjustPayload(payload, jitsuConfig, store);
|
|
413
|
+
const authHeader = adjustedPayload.writeKey ? { "X-Write-Key": adjustedPayload.writeKey } : {};
|
|
412
414
|
return fetch(url, {
|
|
413
415
|
method: "POST",
|
|
414
416
|
headers: {
|
|
@@ -441,7 +443,7 @@ function send(
|
|
|
441
443
|
}
|
|
442
444
|
if (response.destinations) {
|
|
443
445
|
if (jitsuConfig.debug) {
|
|
444
|
-
console.log(`[JITSU] Processing device
|
|
446
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(response.destinations, null, 2));
|
|
445
447
|
}
|
|
446
448
|
return processDestinations(response.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
447
449
|
}
|
|
@@ -471,12 +473,13 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin
|
|
|
471
473
|
persistentStorage.removeItem(key);
|
|
472
474
|
},
|
|
473
475
|
});
|
|
476
|
+
const instanceConfig = {
|
|
477
|
+
...config,
|
|
478
|
+
...pluginConfig,
|
|
479
|
+
};
|
|
474
480
|
return {
|
|
475
481
|
name: "jitsu",
|
|
476
|
-
config:
|
|
477
|
-
...config,
|
|
478
|
-
...pluginConfig,
|
|
479
|
-
},
|
|
482
|
+
config: instanceConfig,
|
|
480
483
|
initialize: args => {
|
|
481
484
|
const { config } = args;
|
|
482
485
|
if (config.debug) {
|
|
@@ -504,6 +507,22 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin
|
|
|
504
507
|
//clear storage cache
|
|
505
508
|
Object.keys(storageCache).forEach(key => delete storageCache[key]);
|
|
506
509
|
},
|
|
510
|
+
methods: {
|
|
511
|
+
//analytics doesn't support group as a base method, so we need to add it manually
|
|
512
|
+
group(groupId?: ID, traits?: JSONObject | null, options?: Options, callback?: Callback) {
|
|
513
|
+
const analyticsInstance = this.instance;
|
|
514
|
+
const user = analyticsInstance.user();
|
|
515
|
+
const userId = options?.userId || user?.userId;
|
|
516
|
+
const anonymousId = options?.anonymousId || user?.anonymousId;
|
|
517
|
+
return send(
|
|
518
|
+
"group",
|
|
519
|
+
{ type: "group", groupId, traits, ...(anonymousId ? { anonymousId } : {}), ...(userId ? { userId } : {}) },
|
|
520
|
+
instanceConfig,
|
|
521
|
+
analyticsInstance,
|
|
522
|
+
cachingStorageWrapper(analyticsInstance.storage)
|
|
523
|
+
);
|
|
524
|
+
},
|
|
525
|
+
},
|
|
507
526
|
};
|
|
508
527
|
};
|
|
509
528
|
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { loadScript } from "../script-loader";
|
|
2
|
+
import { AnalyticsClientEvent } from "@jitsu/protocols/analytics";
|
|
3
|
+
import { applyFilters, CommonDestinationCredentials, InternalPlugin } from "./index";
|
|
4
|
+
|
|
5
|
+
const defaultScriptSrc = "https://www.googletagmanager.com/gtag/js";
|
|
6
|
+
|
|
7
|
+
export type GtmDestinationCredentials = {
|
|
8
|
+
debug: boolean;
|
|
9
|
+
containerId: string;
|
|
10
|
+
dataLayerName: string;
|
|
11
|
+
preview: string;
|
|
12
|
+
auth: string;
|
|
13
|
+
customScriptSrc: string;
|
|
14
|
+
} & CommonDestinationCredentials;
|
|
15
|
+
|
|
16
|
+
export const gtmPlugin: InternalPlugin<GtmDestinationCredentials> = {
|
|
17
|
+
id: "gtm",
|
|
18
|
+
async handle(config, payload: AnalyticsClientEvent) {
|
|
19
|
+
if (!applyFilters(payload, config)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
await initGtmIfNeeded(config);
|
|
23
|
+
|
|
24
|
+
const dataLayer = window[config.dataLayerName || "dataLayer"];
|
|
25
|
+
|
|
26
|
+
switch (payload.type) {
|
|
27
|
+
case "page":
|
|
28
|
+
const { properties: pageProperties } = payload;
|
|
29
|
+
const pageEvent = { event: "page_view", ...pageProperties };
|
|
30
|
+
if (config.debug) {
|
|
31
|
+
console.log("gtag push", pageEvent);
|
|
32
|
+
}
|
|
33
|
+
dataLayer.push(pageEvent);
|
|
34
|
+
break;
|
|
35
|
+
case "track":
|
|
36
|
+
const { properties: trackProperties } = payload;
|
|
37
|
+
const trackEvent = { event: payload.event, ...trackProperties };
|
|
38
|
+
if (config.debug) {
|
|
39
|
+
console.log("gtag push", trackEvent);
|
|
40
|
+
}
|
|
41
|
+
dataLayer.push(trackEvent);
|
|
42
|
+
break;
|
|
43
|
+
case "identify":
|
|
44
|
+
const { anonymousId, userId, traits } = payload;
|
|
45
|
+
const user = traits;
|
|
46
|
+
if (userId) {
|
|
47
|
+
user.userId = userId;
|
|
48
|
+
}
|
|
49
|
+
if (anonymousId) {
|
|
50
|
+
user.anonymousId = anonymousId;
|
|
51
|
+
}
|
|
52
|
+
const identifyEvent = { event: "identify", user: user };
|
|
53
|
+
if (config.debug) {
|
|
54
|
+
console.log("gtag push", identifyEvent);
|
|
55
|
+
}
|
|
56
|
+
dataLayer.push(identifyEvent);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
type GtmState = "fresh" | "loading" | "loaded" | "failed";
|
|
63
|
+
|
|
64
|
+
function getGtmState(): GtmState {
|
|
65
|
+
return window["__jitsuGtmState"] || "fresh";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function setGtmState(s: GtmState) {
|
|
69
|
+
window["__jitsuGtmState"] = s;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
async function initGtmIfNeeded(config: GtmDestinationCredentials) {
|
|
73
|
+
if (getGtmState() !== "fresh") {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
setGtmState("loading");
|
|
77
|
+
|
|
78
|
+
const dlName = config.dataLayerName || "dataLayer";
|
|
79
|
+
const dlParam = dlName !== "dataLayer" ? "&l=" + dlName : "";
|
|
80
|
+
const previewParams = config.preview
|
|
81
|
+
? `>m_preview=${config.preview}>m_auth=${config.auth}>m_cookies_win=x`
|
|
82
|
+
: "";
|
|
83
|
+
const scriptSrc = `${config.customScriptSrc || defaultScriptSrc}?id=${config.containerId}${dlParam}${previewParams}`;
|
|
84
|
+
|
|
85
|
+
window[dlName] = window[dlName] || [];
|
|
86
|
+
const gtag = function () {
|
|
87
|
+
window[dlName].push(arguments);
|
|
88
|
+
};
|
|
89
|
+
// @ts-ignore
|
|
90
|
+
gtag("js", new Date());
|
|
91
|
+
// @ts-ignore
|
|
92
|
+
gtag("config", config.containerId);
|
|
93
|
+
|
|
94
|
+
loadScript(scriptSrc)
|
|
95
|
+
.then(() => {
|
|
96
|
+
setGtmState("loaded");
|
|
97
|
+
})
|
|
98
|
+
.catch(e => {
|
|
99
|
+
console.warn(`GTM (containerId=${config.containerId}) init failed: ${e.message}`, e);
|
|
100
|
+
setGtmState("failed");
|
|
101
|
+
});
|
|
102
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { AnalyticsClientEvent } from "@jitsu/protocols/analytics";
|
|
2
|
+
import { tagPlugin } from "./tag";
|
|
3
|
+
import { logrocketPlugin } from "./logrocket";
|
|
4
|
+
import { gtmPlugin } from "./gtm";
|
|
5
|
+
|
|
6
|
+
export type InternalPlugin<T> = {
|
|
7
|
+
id: string;
|
|
8
|
+
handle(config: T, payload: AnalyticsClientEvent): Promise<void>;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
export type CommonDestinationCredentials = {
|
|
12
|
+
hosts?: string[];
|
|
13
|
+
events?: string[];
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export function satisfyFilter(filter: string, subject: string | undefined): boolean {
|
|
17
|
+
return filter === "*" || filter.toLowerCase().trim() === (subject || "").trim().toLowerCase();
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function applyFilters(event: AnalyticsClientEvent, creds: CommonDestinationCredentials): boolean {
|
|
21
|
+
const { hosts = ["*"], events = ["*"] } = creds;
|
|
22
|
+
return (
|
|
23
|
+
!!hosts.find(hostFilter => satisfyFilter(hostFilter, event.context?.host)) &&
|
|
24
|
+
!!events.find(eventFilter => satisfyFilter(eventFilter, event.type))
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export const internalDestinationPlugins: Record<string, InternalPlugin<any>> = {
|
|
29
|
+
[tagPlugin.id]: tagPlugin,
|
|
30
|
+
[gtmPlugin.id]: gtmPlugin,
|
|
31
|
+
[logrocketPlugin.id]: logrocketPlugin,
|
|
32
|
+
};
|