@jitsu/js 1.7.1 → 1.7.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jitsu/js",
3
- "version": "1.7.1",
3
+ "version": "1.7.2",
4
4
  "description": "",
5
5
  "author": "Jitsu Dev Team <dev@jitsu.com>",
6
6
  "main": "dist/jitsu.cjs.js",
@@ -34,10 +34,10 @@
34
34
  "rollup": "^3.2.5",
35
35
  "ts-jest": "29.0.5",
36
36
  "typescript": "^4.9.5",
37
- "@jitsu/protocols": "1.7.1"
37
+ "@jitsu/protocols": "1.7.2"
38
38
  },
39
39
  "dependencies": {
40
- "analytics": "^0.8.1"
40
+ "analytics": "0.8.9"
41
41
  },
42
42
  "scripts": {
43
43
  "clean": "rm -rf ./dist",
package/rollup.config.js CHANGED
@@ -4,9 +4,16 @@ const commonjs = require("@rollup/plugin-commonjs");
4
4
  const rollupJson = require("@rollup/plugin-json");
5
5
  const terser = require("@rollup/plugin-terser");
6
6
 
7
+
7
8
  module.exports = [
8
9
  {
9
- plugins: [multi(), resolve({ preferBuiltins: false }), commonjs(), rollupJson(), terser()],
10
+ plugins: [
11
+ multi(),
12
+ resolve({ preferBuiltins: false }),
13
+ commonjs(),
14
+ rollupJson(),
15
+ (process.JITSU_JS_DEBUG_BUILD = "1" ? undefined : terser()),
16
+ ],
10
17
  input: "./compiled/src/browser.js",
11
18
  output: {
12
19
  file: `dist/web/p.js.txt`,
@@ -77,25 +77,32 @@ function getCookie(name: string) {
77
77
  return parts.length === 2 ? parts.pop().split(";").shift() : undefined;
78
78
  }
79
79
 
80
- function getGa4Sessions(allCookies: Record<string, string>): Record<string, string> | undefined {
81
- const gaCookies = Object.entries(allCookies).filter(([key]) => key.startsWith("_ga_"));
82
- if (gaCookies.length === 0) {
80
+ function getGa4Ids(runtime: RuntimeFacade) {
81
+ const allCookies = runtime.getCookies();
82
+ const clientId = allCookies["_ga"]?.split(".").slice(-2).join(".");
83
+ const gaSessionCookies = Object.entries(allCookies).filter(([key]) => key.startsWith("_ga_"));
84
+ const sessionIds =
85
+ gaSessionCookies.length > 0
86
+ ? Object.fromEntries(
87
+ gaSessionCookies
88
+ .map(([key, value]) => {
89
+ if (typeof value !== "string") {
90
+ return null;
91
+ }
92
+ const parts = value.split(".");
93
+ if (parts.length < 3) {
94
+ return null;
95
+ }
96
+ return [key.substring("_ga_".length), parts[2]];
97
+ })
98
+ .filter(v => v !== null)
99
+ )
100
+ : undefined;
101
+ if (clientId || sessionIds) {
102
+ return { ga4: { clientId, sessionIds } };
103
+ } else {
83
104
  return undefined;
84
105
  }
85
- return Object.fromEntries(
86
- gaCookies
87
- .map(([key, value]) => {
88
- if (typeof value !== "string") {
89
- return null;
90
- }
91
- const parts = value.split(".");
92
- if (parts.length < 3) {
93
- return null;
94
- }
95
- return [key.substring("_ga_".length), parts[2]];
96
- })
97
- .filter(v => v !== null)
98
- );
99
106
  }
100
107
 
101
108
  function removeCookie(name: string) {
@@ -308,10 +315,7 @@ function adjustPayload(payload: any, config: JitsuOptions, storage: PersistentSt
308
315
  clientIds: {
309
316
  fbc: runtime.getCookie("_fbc"),
310
317
  fbp: runtime.getCookie("_fbp"),
311
- ga4: {
312
- clientId: runtime.getCookie("_ga")?.split(".").slice(-2).join("."), //last 2 parts of GA cookie
313
- sessions: getGa4Sessions(runtime.getCookies()),
314
- },
318
+ ...getGa4Ids(runtime),
315
319
  },
316
320
  campaign: parseUtms(query),
317
321
  };
@@ -475,7 +479,7 @@ function send(
475
479
  store: PersistentStorage
476
480
  ): Promise<void> {
477
481
  if (jitsuConfig.echoEvents) {
478
- console.log(`[JITSU] sending '${method}' event:`, payload);
482
+ console.log(`[JITSU DEBUG] sending '${method}' event:`, payload);
479
483
  return;
480
484
  }
481
485
 
@@ -541,18 +545,31 @@ function send(
541
545
 
542
546
  const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin => {
543
547
  const storageCache: any = {};
548
+
544
549
  // AnalyticsInstance's storage is async somewhere inside. So if we make 'page' call right after 'identify' call
545
550
  // 'page' call will load traits from storage before 'identify' call had a change to save them.
546
551
  // to avoid that we use in-memory cache for storage
547
552
  const cachingStorageWrapper = (persistentStorage: PersistentStorage): PersistentStorage => ({
548
553
  setItem(key: string, val: any) {
554
+ if (pluginConfig.debug) {
555
+ console.log(`[JITSU DEBUG] Caching storage setItem: ${key}=${val}`);
556
+ }
549
557
  storageCache[key] = val;
550
558
  persistentStorage.setItem(key, val);
551
559
  },
552
560
  getItem(key: string) {
553
- return storageCache[key] || persistentStorage.getItem(key);
561
+ const value = storageCache[key] || persistentStorage.getItem(key);
562
+ if (pluginConfig.debug) {
563
+ console.log(
564
+ `[JITSU DEBUG] Caching storage getItem: ${key}=${value}. Evicted from cache: ${!storageCache[key]}`
565
+ );
566
+ }
567
+ return value;
554
568
  },
555
569
  removeItem(key: string) {
570
+ if (pluginConfig.debug) {
571
+ console.log(`[JITSU DEBUG] Caching storage removeItem: ${key}`);
572
+ }
556
573
  delete storageCache[key];
557
574
  persistentStorage.removeItem(key);
558
575
  },
@@ -564,10 +581,11 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin
564
581
  return {
565
582
  name: "jitsu",
566
583
  config: instanceConfig,
584
+
567
585
  initialize: args => {
568
586
  const { config } = args;
569
587
  if (config.debug) {
570
- console.debug("[JITSU] Initializing Jitsu plugin with config: ", JSON.stringify(config));
588
+ console.debug("[JITSU DEBUG] Initializing Jitsu plugin with config: ", JSON.stringify(config, null, 2));
571
589
  }
572
590
  if (!config.host && !config.echoEvents) {
573
591
  throw new Error("Please specify host variable in jitsu plugin initialization, or set echoEvents to true");
@@ -596,15 +614,16 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin
596
614
  //analytics doesn't support group as a base method, so we need to add it manually
597
615
  group(groupId?: ID, traits?: JSONObject | null, options?: Options, callback?: Callback) {
598
616
  const analyticsInstance = this.instance;
617
+ const cacheWrap = cachingStorageWrapper(analyticsInstance.storage);
599
618
  const user = analyticsInstance.user();
600
619
  const userId = options?.userId || user?.userId;
601
- const anonymousId = options?.anonymousId || user?.anonymousId;
620
+ const anonymousId = options?.anonymousId || user?.anonymousId || cacheWrap.getItem("__anon_id");
602
621
  return send(
603
622
  "group",
604
623
  { type: "group", groupId, traits, ...(anonymousId ? { anonymousId } : {}), ...(userId ? { userId } : {}) },
605
624
  instanceConfig,
606
625
  analyticsInstance,
607
- cachingStorageWrapper(analyticsInstance.storage)
626
+ cacheWrap
608
627
  );
609
628
  },
610
629
  },
package/src/browser.ts CHANGED
@@ -53,35 +53,10 @@ function getScriptAttributes(scriptElement: HTMLScriptElement) {
53
53
 
54
54
  const options = readJitsuOptions();
55
55
  const JITSU_V2_ID: string = options.namespace || "jitsu";
56
- const queue = [];
57
- if (window[JITSU_V2_ID]) {
58
- if (Array.isArray(window[JITSU_V2_ID])) {
59
- //processing queue of events
60
- if (options.debug) {
61
- console.log(
62
- `Initializing Jitsu with prior events queue size of ${window[JITSU_V2_ID].length}`,
63
- window[JITSU_V2_ID]
64
- );
65
- }
66
- queue.push(...window[JITSU_V2_ID]);
67
- } else {
68
- console.warn("Attempted to initialize Jitsu twice. Returning the existing instance");
69
- }
70
- }
71
56
  if (options.debug) {
72
57
  console.log(`Jitsu options: `, JSON.stringify(options));
73
58
  }
74
59
  const jitsu = jitsuAnalytics(options);
75
- for (const [method, args] of queue) {
76
- if (options.debug) {
77
- console.log(`Processing event ${method} from Jitsu queue on`, args);
78
- }
79
- try {
80
- jitsu[method](...args);
81
- } catch (e: any) {
82
- console.warn(`Error processing event ${method} from Jitsu queue on`, args, e);
83
- }
84
- }
85
60
 
86
61
  if (options.onload) {
87
62
  const onloadFunction = window[options.onload] as any;
@@ -96,8 +71,22 @@ function getScriptAttributes(scriptElement: HTMLScriptElement) {
96
71
  }
97
72
  window[JITSU_V2_ID] = jitsu;
98
73
 
99
- //new callback based queue
100
- const callbackQueue = window[JITSU_V2_ID + "Q"] || [];
74
+ /**
75
+ * New callback based queue, see below
76
+ */
77
+ //make a copy of the queue
78
+ const callbackQueue = [...(window[JITSU_V2_ID + "Q"] || [])];
79
+ //replace push with a function that calls callback immediately
80
+ window[JITSU_V2_ID + "Q"] = {
81
+ push: (callback: any) => {
82
+ if (typeof callback === "function") {
83
+ callback(jitsu);
84
+ } else {
85
+ console.warn(`${JITSU_V2_ID}Q.push() accepts only function, ${typeof callback} given`);
86
+ }
87
+ },
88
+ };
89
+
101
90
  if (options.debug) {
102
91
  console.log(`Jitsu callback queue size: ${callbackQueue.length}`, callbackQueue);
103
92
  }
package/src/index.ts CHANGED
@@ -23,7 +23,8 @@ export default function parse(input) {
23
23
  return value;
24
24
  }
25
25
 
26
- export const emptyAnalytics = {
26
+ export const emptyAnalytics: AnalyticsInterface = {
27
+ setAnonymousId: () => {},
27
28
  track: () => Promise.resolve(),
28
29
  page: () => Promise.resolve(),
29
30
  user: () => ({}),
@@ -37,10 +38,11 @@ function createUnderlyingAnalyticsInstance(
37
38
  rt: RuntimeFacade,
38
39
  plugins: any[] = []
39
40
  ): AnalyticsInterface {
41
+ const storage = rt.store();
40
42
  const analytics = Analytics({
41
43
  app: "test",
42
44
  debug: !!opts.debug,
43
- storage: rt.store(),
45
+ storage,
44
46
  plugins: [jitsuAnalyticsPlugin(opts), ...plugins],
45
47
  } as any);
46
48
  const originalPage = analytics.page;
@@ -56,6 +58,19 @@ function createUnderlyingAnalyticsInstance(
56
58
  };
57
59
  return {
58
60
  ...analytics,
61
+ setAnonymousId: (id: string) => {
62
+ if (opts.debug) {
63
+ console.log("[JITSU DEBUG] Setting anonymous id to " + id);
64
+ //Workaround for analytics.js bug. Underlying setAnonymousId doesn't work set the id immediately,
65
+ //so we got to it manually here. See https://github.com/jitsucom/jitsu/issues/1060
66
+ storage.setItem("__anon_id", id);
67
+ const userState = analytics.user();
68
+ if (userState) {
69
+ userState.anonymousId = id;
70
+ }
71
+ (analytics as any).setAnonymousId(id);
72
+ }
73
+ },
59
74
  group(groupId?: ID, traits?: JSONObject | null, options?: Options, callback?: Callback): Promise<DispatchedEvent> {
60
75
  for (const plugin of Object.values(analytics.plugins)) {
61
76
  if (plugin["group"]) {