@jitsu/js 1.7.2 → 1.8.1
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 +85 -105
- package/.turbo/turbo-clean.log +5 -5
- package/.turbo/turbo-test.log +1955 -1369
- package/__tests__/node/nodejs.test.ts +12 -8
- package/__tests__/playwright/cases/basic.html +1 -1
- package/__tests__/playwright/cases/url-bug.html +20 -0
- package/__tests__/playwright/integration.test.ts +60 -8
- package/dist/analytics-plugin.d.ts +6 -1
- package/dist/jitsu.cjs.js +204 -112
- package/dist/jitsu.d.ts +6 -0
- package/dist/jitsu.es.js +204 -112
- package/dist/version.d.ts +2 -1
- package/dist/web/p.js.txt +206 -114
- package/package.json +3 -3
- package/src/analytics-plugin.ts +138 -85
- package/src/browser.ts +3 -2
- package/src/index.ts +87 -17
- package/src/jitsu.ts +7 -0
- package/src/version.ts +4 -1
package/src/analytics-plugin.ts
CHANGED
|
@@ -20,6 +20,7 @@ const defaultConfig: Required<JitsuOptions> = {
|
|
|
20
20
|
echoEvents: false,
|
|
21
21
|
cookieDomain: undefined,
|
|
22
22
|
runtime: undefined,
|
|
23
|
+
s2s: undefined,
|
|
23
24
|
};
|
|
24
25
|
|
|
25
26
|
export const parseQuery = (qs?: string): Record<string, string> => {
|
|
@@ -62,11 +63,24 @@ function safeCall<T>(f: () => T, defaultVal?: T): T | undefined {
|
|
|
62
63
|
}
|
|
63
64
|
|
|
64
65
|
function restoreTraits(storage: PersistentStorage) {
|
|
65
|
-
|
|
66
|
+
let val = storage.getItem("__user_traits");
|
|
66
67
|
if (typeof val === "string") {
|
|
67
|
-
|
|
68
|
+
val = safeCall(() => JSON.parse(val), {});
|
|
68
69
|
}
|
|
69
|
-
|
|
70
|
+
if (typeof val !== "object" || val === null) {
|
|
71
|
+
val = {};
|
|
72
|
+
}
|
|
73
|
+
let groupVal = storage.getItem("__group_traits");
|
|
74
|
+
if (typeof groupVal === "string") {
|
|
75
|
+
groupVal = safeCall(() => JSON.parse(groupVal), {});
|
|
76
|
+
}
|
|
77
|
+
if (typeof groupVal !== "object" || groupVal === null) {
|
|
78
|
+
groupVal = {};
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
...(groupVal || {}),
|
|
82
|
+
...(val || {}), //user traits override group traits
|
|
83
|
+
};
|
|
70
84
|
}
|
|
71
85
|
|
|
72
86
|
export type StorageFactory = (cookieDomain: string, cookie2key: Record<string, string>) => PersistentStorage;
|
|
@@ -284,12 +298,33 @@ export function isInBrowser() {
|
|
|
284
298
|
return typeof document !== "undefined" && typeof window !== "undefined";
|
|
285
299
|
}
|
|
286
300
|
|
|
287
|
-
|
|
301
|
+
/**
|
|
302
|
+
* Fixes a weird bug in analytics URL where path
|
|
303
|
+
* of https://test.com becomes //test.com
|
|
304
|
+
*/
|
|
305
|
+
function fixPath(path: string): string {
|
|
306
|
+
if (path.indexOf("//") === 0 && path.lastIndexOf("/") === 1) {
|
|
307
|
+
return "/";
|
|
308
|
+
}
|
|
309
|
+
return path;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function adjustPayload(
|
|
313
|
+
payload: any,
|
|
314
|
+
config: JitsuOptions,
|
|
315
|
+
storage: PersistentStorage,
|
|
316
|
+
s2s: boolean
|
|
317
|
+
): AnalyticsClientEvent {
|
|
288
318
|
const runtime: RuntimeFacade = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
|
|
289
319
|
const url = runtime.pageUrl();
|
|
290
320
|
const parsedUrl = safeCall(() => new URL(url), undefined);
|
|
291
321
|
const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
|
|
292
322
|
const properties = payload.properties || {};
|
|
323
|
+
|
|
324
|
+
if (properties.path) {
|
|
325
|
+
properties.path = fixPath(properties.path);
|
|
326
|
+
}
|
|
327
|
+
|
|
293
328
|
const customContext = payload.properties?.context || {};
|
|
294
329
|
delete payload.properties?.context;
|
|
295
330
|
const referrer = runtime.referrer();
|
|
@@ -297,6 +332,7 @@ function adjustPayload(payload: any, config: JitsuOptions, storage: PersistentSt
|
|
|
297
332
|
library: {
|
|
298
333
|
name: jitsuLibraryName,
|
|
299
334
|
version: jitsuVersion,
|
|
335
|
+
env: s2s ? "node" : "browser",
|
|
300
336
|
},
|
|
301
337
|
userAgent: runtime.userAgent(),
|
|
302
338
|
locale: runtime.language(),
|
|
@@ -325,6 +361,7 @@ function adjustPayload(payload: any, config: JitsuOptions, storage: PersistentSt
|
|
|
325
361
|
sentAt: new Date().toISOString(),
|
|
326
362
|
messageId: randomId(properties.path || (parsedUrl && parsedUrl.pathname)),
|
|
327
363
|
writeKey: maskWriteKey(config.writeKey),
|
|
364
|
+
groupId: storage.getItem("__group_id"),
|
|
328
365
|
context: deepMerge(context, customContext),
|
|
329
366
|
};
|
|
330
367
|
delete withContext.meta;
|
|
@@ -471,19 +508,19 @@ function maskWriteKey(writeKey?: string): string | undefined {
|
|
|
471
508
|
return writeKey;
|
|
472
509
|
}
|
|
473
510
|
|
|
474
|
-
function send(
|
|
511
|
+
async function send(
|
|
475
512
|
method,
|
|
476
513
|
payload,
|
|
477
514
|
jitsuConfig: Required<JitsuOptions>,
|
|
478
515
|
instance: AnalyticsInstance,
|
|
479
516
|
store: PersistentStorage
|
|
480
|
-
): Promise<
|
|
517
|
+
): Promise<any> {
|
|
481
518
|
if (jitsuConfig.echoEvents) {
|
|
482
519
|
console.log(`[JITSU DEBUG] sending '${method}' event:`, payload);
|
|
483
520
|
return;
|
|
484
521
|
}
|
|
485
|
-
|
|
486
|
-
const url = `${jitsuConfig.host}/api/s/${method}`;
|
|
522
|
+
const s2s = jitsuConfig.s2s === undefined ? !isInBrowser() : jitsuConfig.s2s;
|
|
523
|
+
const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`;
|
|
487
524
|
const fetch = jitsuConfig.fetch || globalThis.fetch;
|
|
488
525
|
if (!fetch) {
|
|
489
526
|
throw new Error(
|
|
@@ -495,85 +532,72 @@ function send(
|
|
|
495
532
|
// if (jitsuConfig.debug) {
|
|
496
533
|
// console.log(`[JITSU] Sending event to ${url}: `, JSON.stringify(payload, null, 2));
|
|
497
534
|
// }
|
|
498
|
-
const adjustedPayload = adjustPayload(payload, jitsuConfig, store);
|
|
535
|
+
const adjustedPayload = adjustPayload(payload, jitsuConfig, store, s2s);
|
|
499
536
|
|
|
500
537
|
const authHeader = jitsuConfig.writeKey ? { "X-Write-Key": jitsuConfig.writeKey } : {};
|
|
538
|
+
let fetchResult;
|
|
539
|
+
try {
|
|
540
|
+
fetchResult = await fetch(url, {
|
|
541
|
+
method: "POST",
|
|
542
|
+
headers: {
|
|
543
|
+
"Content-Type": "application/json",
|
|
501
544
|
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
545
|
+
...authHeader,
|
|
546
|
+
...debugHeader,
|
|
547
|
+
},
|
|
548
|
+
body: JSON.stringify(adjustedPayload),
|
|
549
|
+
});
|
|
550
|
+
} catch (e: any) {
|
|
551
|
+
throw new Error(`Calling ${url} failed: ${e.message}`);
|
|
552
|
+
}
|
|
553
|
+
let responseText;
|
|
554
|
+
try {
|
|
555
|
+
responseText = await fetchResult.text();
|
|
556
|
+
} catch (e) {
|
|
557
|
+
console.warn(
|
|
558
|
+
`Can't read response text from ${url} (status - ${fetchResult.status} ${fetchResult.statusText}): ${e?.message}`
|
|
559
|
+
);
|
|
560
|
+
}
|
|
561
|
+
if (jitsuConfig.debug) {
|
|
562
|
+
console.log(
|
|
563
|
+
`[JITSU DEBUG] ${url} replied ${fetchResult.status}: ${responseText}. Original payload:\n${JSON.stringify(
|
|
564
|
+
adjustedPayload,
|
|
565
|
+
null,
|
|
566
|
+
2
|
|
567
|
+
)}`
|
|
568
|
+
);
|
|
569
|
+
}
|
|
570
|
+
if (!fetchResult.ok) {
|
|
571
|
+
throw new Error(`Jitsu ${url} replied ${fetchResult.status} - ${fetchResult.statusText}: ${responseText}`);
|
|
572
|
+
}
|
|
506
573
|
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
} else {
|
|
522
|
-
return Promise.reject(res.text());
|
|
523
|
-
}
|
|
524
|
-
})
|
|
525
|
-
.then(responseText => {
|
|
526
|
-
let response: any;
|
|
527
|
-
try {
|
|
528
|
-
response = JSON.parse(responseText);
|
|
529
|
-
} catch (e) {
|
|
530
|
-
return Promise.reject(`Can't parse JSON: ${responseText}: ${e?.message}`);
|
|
531
|
-
}
|
|
532
|
-
if (response.destinations) {
|
|
533
|
-
if (jitsuConfig.debug) {
|
|
534
|
-
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(response.destinations, null, 2));
|
|
535
|
-
}
|
|
536
|
-
return processDestinations(response.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
537
|
-
}
|
|
538
|
-
})
|
|
539
|
-
.catch(err => {
|
|
574
|
+
let responseJson: any;
|
|
575
|
+
try {
|
|
576
|
+
responseJson = JSON.parse(responseText);
|
|
577
|
+
} catch (e) {
|
|
578
|
+
return Promise.reject(`Can't parse JSON: ${responseText}: ${e?.message}`);
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (responseJson.destinations && responseJson.destinations.length > 0) {
|
|
582
|
+
if (jitsuConfig.s2s) {
|
|
583
|
+
console.warn(
|
|
584
|
+
`[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`,
|
|
585
|
+
jitsuConfig.debug ? JSON.stringify(responseJson.destinations, null, 2) : undefined
|
|
586
|
+
);
|
|
587
|
+
} else {
|
|
540
588
|
if (jitsuConfig.debug) {
|
|
541
|
-
console.
|
|
589
|
+
console.log(`[JITSU] Processing device destinations: `, JSON.stringify(responseJson.destinations, null, 2));
|
|
542
590
|
}
|
|
543
|
-
|
|
591
|
+
return processDestinations(responseJson.destinations, method, adjustedPayload, !!jitsuConfig.debug, instance);
|
|
592
|
+
}
|
|
593
|
+
}
|
|
594
|
+
return adjustedPayload;
|
|
544
595
|
}
|
|
545
596
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
// 'page' call will load traits from storage before 'identify' call had a change to save them.
|
|
551
|
-
// to avoid that we use in-memory cache for storage
|
|
552
|
-
const cachingStorageWrapper = (persistentStorage: PersistentStorage): PersistentStorage => ({
|
|
553
|
-
setItem(key: string, val: any) {
|
|
554
|
-
if (pluginConfig.debug) {
|
|
555
|
-
console.log(`[JITSU DEBUG] Caching storage setItem: ${key}=${val}`);
|
|
556
|
-
}
|
|
557
|
-
storageCache[key] = val;
|
|
558
|
-
persistentStorage.setItem(key, val);
|
|
559
|
-
},
|
|
560
|
-
getItem(key: string) {
|
|
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;
|
|
568
|
-
},
|
|
569
|
-
removeItem(key: string) {
|
|
570
|
-
if (pluginConfig.debug) {
|
|
571
|
-
console.log(`[JITSU DEBUG] Caching storage removeItem: ${key}`);
|
|
572
|
-
}
|
|
573
|
-
delete storageCache[key];
|
|
574
|
-
persistentStorage.removeItem(key);
|
|
575
|
-
},
|
|
576
|
-
});
|
|
597
|
+
export type JitsuPluginConfig = JitsuOptions & {
|
|
598
|
+
storageWrapper?: (persistentStorage: PersistentStorage) => PersistentStorage & { reset: () => void };
|
|
599
|
+
};
|
|
600
|
+
const jitsuAnalyticsPlugin = (pluginConfig: JitsuPluginConfig = {}): AnalyticsPlugin => {
|
|
577
601
|
const instanceConfig = {
|
|
578
602
|
...defaultConfig,
|
|
579
603
|
...pluginConfig,
|
|
@@ -594,30 +618,59 @@ const jitsuAnalyticsPlugin = (pluginConfig: JitsuOptions = {}): AnalyticsPlugin
|
|
|
594
618
|
},
|
|
595
619
|
page: args => {
|
|
596
620
|
const { payload, config, instance } = args;
|
|
597
|
-
return send(
|
|
621
|
+
return send(
|
|
622
|
+
"page",
|
|
623
|
+
payload,
|
|
624
|
+
config,
|
|
625
|
+
instance,
|
|
626
|
+
pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage
|
|
627
|
+
);
|
|
598
628
|
},
|
|
599
629
|
track: args => {
|
|
600
630
|
const { payload, config, instance } = args;
|
|
601
|
-
return send(
|
|
631
|
+
return send(
|
|
632
|
+
"track",
|
|
633
|
+
payload,
|
|
634
|
+
config,
|
|
635
|
+
instance,
|
|
636
|
+
pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage
|
|
637
|
+
);
|
|
602
638
|
},
|
|
603
639
|
identify: args => {
|
|
604
640
|
const { payload, config, instance } = args;
|
|
605
641
|
// Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
|
|
606
|
-
|
|
607
|
-
|
|
642
|
+
const storage = pluginConfig.storageWrapper ? pluginConfig.storageWrapper(instance.storage) : instance.storage;
|
|
643
|
+
storage.setItem("__user_id", payload.userId);
|
|
644
|
+
if (payload.traits && typeof payload.traits === "object") {
|
|
645
|
+
storage.setItem("__user_traits", payload.traits);
|
|
646
|
+
}
|
|
647
|
+
return send("identify", payload, config, instance, storage);
|
|
608
648
|
},
|
|
609
649
|
reset: args => {
|
|
610
650
|
//clear storage cache
|
|
611
|
-
|
|
651
|
+
if (pluginConfig.storageWrapper) {
|
|
652
|
+
pluginConfig.storageWrapper(args.instance.storage).reset();
|
|
653
|
+
}
|
|
612
654
|
},
|
|
613
655
|
methods: {
|
|
614
656
|
//analytics doesn't support group as a base method, so we need to add it manually
|
|
615
657
|
group(groupId?: ID, traits?: JSONObject | null, options?: Options, callback?: Callback) {
|
|
658
|
+
if (typeof groupId === "number") {
|
|
659
|
+
//fix potential issues with group id being used incorrectly
|
|
660
|
+
groupId = groupId + "";
|
|
661
|
+
}
|
|
662
|
+
|
|
616
663
|
const analyticsInstance = this.instance;
|
|
617
|
-
const cacheWrap =
|
|
664
|
+
const cacheWrap = pluginConfig.storageWrapper
|
|
665
|
+
? pluginConfig.storageWrapper(analyticsInstance.storage)
|
|
666
|
+
: analyticsInstance.storage;
|
|
618
667
|
const user = analyticsInstance.user();
|
|
619
668
|
const userId = options?.userId || user?.userId;
|
|
620
669
|
const anonymousId = options?.anonymousId || user?.anonymousId || cacheWrap.getItem("__anon_id");
|
|
670
|
+
cacheWrap.setItem("__group_id", groupId);
|
|
671
|
+
if (traits && typeof traits === "object") {
|
|
672
|
+
cacheWrap.setItem("__group_traits", traits);
|
|
673
|
+
}
|
|
621
674
|
return send(
|
|
622
675
|
"group",
|
|
623
676
|
{ type: "group", groupId, traits, ...(anonymousId ? { anonymousId } : {}), ...(userId ? { userId } : {}) },
|
package/src/browser.ts
CHANGED
|
@@ -75,7 +75,8 @@ function getScriptAttributes(scriptElement: HTMLScriptElement) {
|
|
|
75
75
|
* New callback based queue, see below
|
|
76
76
|
*/
|
|
77
77
|
//make a copy of the queue
|
|
78
|
-
const callbackQueue =
|
|
78
|
+
const callbackQueue =
|
|
79
|
+
window[JITSU_V2_ID + "Q"] && window[JITSU_V2_ID + "Q"].length ? [...window[JITSU_V2_ID + "Q"]] : [];
|
|
79
80
|
//replace push with a function that calls callback immediately
|
|
80
81
|
window[JITSU_V2_ID + "Q"] = {
|
|
81
82
|
push: (callback: any) => {
|
|
@@ -88,7 +89,7 @@ function getScriptAttributes(scriptElement: HTMLScriptElement) {
|
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
if (options.debug) {
|
|
91
|
-
console.log(`Jitsu callback queue size: ${callbackQueue.length}`, callbackQueue);
|
|
92
|
+
console.log(`[JITSU DEBUG] Jitsu callback queue size: ${callbackQueue.length}`, callbackQueue);
|
|
92
93
|
}
|
|
93
94
|
callbackQueue.forEach((callback: any) => {
|
|
94
95
|
try {
|
package/src/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import Analytics from "analytics";
|
|
2
|
-
import { AnalyticsInterface, JitsuOptions, RuntimeFacade } from "./jitsu";
|
|
2
|
+
import { AnalyticsInterface, JitsuOptions, PersistentStorage, RuntimeFacade } from "./jitsu";
|
|
3
3
|
import jitsuAnalyticsPlugin, { emptyRuntime, isInBrowser, windowRuntime } from "./analytics-plugin";
|
|
4
4
|
import { Callback, DispatchedEvent, ID, JSONObject, Options } from "@jitsu/protocols/analytics";
|
|
5
5
|
|
|
@@ -39,25 +39,87 @@ function createUnderlyingAnalyticsInstance(
|
|
|
39
39
|
plugins: any[] = []
|
|
40
40
|
): AnalyticsInterface {
|
|
41
41
|
const storage = rt.store();
|
|
42
|
+
|
|
43
|
+
const storageCache: any = {};
|
|
44
|
+
|
|
45
|
+
// AnalyticsInstance's storage is async somewhere inside. So if we make 'page' call right after 'identify' call
|
|
46
|
+
// 'page' call will load traits from storage before 'identify' call had a change to save them.
|
|
47
|
+
// to avoid that we use in-memory cache for storage
|
|
48
|
+
const cachingStorageWrapper = (persistentStorage: PersistentStorage) => ({
|
|
49
|
+
setItem(key: string, val: any) {
|
|
50
|
+
if (opts.debug) {
|
|
51
|
+
console.log(`[JITSU DEBUG] Caching storage setItem: ${key}=${val}`);
|
|
52
|
+
}
|
|
53
|
+
storageCache[key] = val;
|
|
54
|
+
persistentStorage.setItem(key, val);
|
|
55
|
+
},
|
|
56
|
+
getItem(key: string) {
|
|
57
|
+
const value = storageCache[key] || persistentStorage.getItem(key);
|
|
58
|
+
if (opts.debug) {
|
|
59
|
+
console.log(
|
|
60
|
+
`[JITSU DEBUG] Caching storage getItem: ${key}=${value}. Evicted from cache: ${!storageCache[key]}`
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
return value;
|
|
64
|
+
},
|
|
65
|
+
reset() {
|
|
66
|
+
for (const key of [...Object.keys(storageCache)]) {
|
|
67
|
+
storage.removeItem(key);
|
|
68
|
+
delete storageCache[key];
|
|
69
|
+
}
|
|
70
|
+
},
|
|
71
|
+
removeItem(key: string) {
|
|
72
|
+
if (opts.debug) {
|
|
73
|
+
console.log(`[JITSU DEBUG] Caching storage removeItem: ${key}`);
|
|
74
|
+
}
|
|
75
|
+
delete storageCache[key];
|
|
76
|
+
persistentStorage.removeItem(key);
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
|
|
42
80
|
const analytics = Analytics({
|
|
43
|
-
app: "test",
|
|
44
81
|
debug: !!opts.debug,
|
|
45
82
|
storage,
|
|
46
|
-
plugins: [jitsuAnalyticsPlugin(opts), ...plugins],
|
|
83
|
+
plugins: [jitsuAnalyticsPlugin({ ...opts, storageWrapper: cachingStorageWrapper }), ...plugins],
|
|
47
84
|
} as any);
|
|
48
|
-
|
|
49
|
-
analytics.page = (...args) => {
|
|
50
|
-
if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "object") {
|
|
51
|
-
return originalPage({
|
|
52
|
-
name: args[0],
|
|
53
|
-
...args[1],
|
|
54
|
-
});
|
|
55
|
-
} else {
|
|
56
|
-
return originalPage(...args);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
85
|
+
|
|
59
86
|
return {
|
|
60
87
|
...analytics,
|
|
88
|
+
page: (...args) => {
|
|
89
|
+
if (args.length === 2 && typeof args[0] === "string" && typeof args[1] === "object") {
|
|
90
|
+
return analytics.page({
|
|
91
|
+
name: args[0],
|
|
92
|
+
...args[1],
|
|
93
|
+
});
|
|
94
|
+
} else {
|
|
95
|
+
return (analytics.page as any)(...args);
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
identify: (...args) => {
|
|
99
|
+
if (args[0] && typeof args[0] !== "object" && typeof args[0] !== "string") {
|
|
100
|
+
//fix the quirk of analytics.js: if you pass number as first argument, it will be converted to string
|
|
101
|
+
args[0] = args[0] + "";
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
//analytics.js sets userId and traits asynchronously, so if
|
|
105
|
+
//we want them to be available immediately after identify call in subsequent page() calls,
|
|
106
|
+
//we need to put them into storage manually
|
|
107
|
+
const storage = (analytics as any).storage;
|
|
108
|
+
const storageWrapper = cachingStorageWrapper(storage);
|
|
109
|
+
if (typeof args[0] === "string") {
|
|
110
|
+
//first argument is user id
|
|
111
|
+
storageWrapper.setItem("__user_id", args[0]);
|
|
112
|
+
} else if (typeof args[0] === "object") {
|
|
113
|
+
//first argument is traits
|
|
114
|
+
storageWrapper.setItem("__user_traits", args[0]);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
if (args.length === 2 && typeof args[1] === "object") {
|
|
118
|
+
//first argument is user id, second is traits
|
|
119
|
+
storageWrapper.setItem("__user_traits", args[1]);
|
|
120
|
+
}
|
|
121
|
+
return (analytics.identify as any)(...args);
|
|
122
|
+
},
|
|
61
123
|
setAnonymousId: (id: string) => {
|
|
62
124
|
if (opts.debug) {
|
|
63
125
|
console.log("[JITSU DEBUG] Setting anonymous id to " + id);
|
|
@@ -71,13 +133,21 @@ function createUnderlyingAnalyticsInstance(
|
|
|
71
133
|
(analytics as any).setAnonymousId(id);
|
|
72
134
|
}
|
|
73
135
|
},
|
|
74
|
-
group(
|
|
136
|
+
async group(
|
|
137
|
+
groupId?: ID,
|
|
138
|
+
traits?: JSONObject | null,
|
|
139
|
+
options?: Options,
|
|
140
|
+
callback?: Callback
|
|
141
|
+
): Promise<DispatchedEvent> {
|
|
142
|
+
const results: any[] = [];
|
|
75
143
|
for (const plugin of Object.values(analytics.plugins)) {
|
|
76
144
|
if (plugin["group"]) {
|
|
77
|
-
plugin["group"](groupId, traits, options, callback);
|
|
145
|
+
results.push(await plugin["group"](groupId, traits, options, callback));
|
|
78
146
|
}
|
|
79
147
|
}
|
|
80
|
-
|
|
148
|
+
//It's incorrect at many levels. First, it's not a dispatched event. Second, we take a first result
|
|
149
|
+
//However, since returned values are used for debugging purposes only, it's ok
|
|
150
|
+
return results[0];
|
|
81
151
|
},
|
|
82
152
|
} as AnalyticsInterface;
|
|
83
153
|
}
|
package/src/jitsu.ts
CHANGED
|
@@ -38,6 +38,13 @@ type JitsuOptions = {
|
|
|
38
38
|
* writeKey / host. It's useful for debugging development environment
|
|
39
39
|
*/
|
|
40
40
|
echoEvents?: boolean;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* If true, events will go to s2s endpoints like ${host}/api/s/s2s/{type}. Otherwise they'll go to ${host}/api/s/{type}.
|
|
44
|
+
*
|
|
45
|
+
* If not set at all, it will be detected automatically by presence of `window` object
|
|
46
|
+
*/
|
|
47
|
+
s2s?: boolean;
|
|
41
48
|
};
|
|
42
49
|
|
|
43
50
|
type PersistentStorage = {
|
package/src/version.ts
CHANGED