@jitsu/js 1.9.9 → 1.9.11

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.
@@ -1,15 +1,17 @@
1
1
  /* global analytics */
2
2
 
3
3
  import {
4
- DynamicJitsuOptions,
5
- JitsuOptions,
6
- PersistentStorage,
7
- RuntimeFacade,
8
4
  AnalyticsClientEvent,
9
5
  Callback,
6
+ DynamicJitsuOptions,
7
+ ErrorHandler,
10
8
  ID,
9
+ JitsuOptions,
11
10
  JSONObject,
12
11
  Options,
12
+ PersistentStorage,
13
+ RuntimeFacade,
14
+ Traits,
13
15
  } from "@jitsu/protocols/analytics";
14
16
  import parse from "./index";
15
17
 
@@ -35,6 +37,7 @@ const defaultConfig: Required<JitsuOptions> = {
35
37
  fetchTimeoutMs: undefined,
36
38
  s2s: undefined,
37
39
  idEndpoint: undefined,
40
+ errorPolicy: "log",
38
41
  privacy: {
39
42
  dontSend: false,
40
43
  disableUserIds: false,
@@ -415,12 +418,13 @@ function adjustPayload(
415
418
  const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
416
419
  const properties = payload.properties || {};
417
420
 
418
- if (payload.type === "page" && url) {
419
- properties.url = url.replace(hashRegex, "");
420
- properties.path = fixPath(urlPath(url));
421
+ if (payload.type === "page" && (properties.url || url)) {
422
+ const targetUrl = properties.url || url;
423
+ properties.url = targetUrl.replace(hashRegex, "");
424
+ properties.path = fixPath(urlPath(targetUrl));
421
425
  }
422
426
 
423
- const customContext = payload.properties?.context || {};
427
+ const customContext = payload.properties?.context || payload.options?.context || {};
424
428
  delete payload.properties?.context;
425
429
  const referrer = runtime.referrer();
426
430
  const context: AnalyticsClientEvent["context"] = {
@@ -627,6 +631,22 @@ function maskWriteKey(writeKey?: string): string | undefined {
627
631
  return writeKey;
628
632
  }
629
633
 
634
+ function getErrorHandler(opts: JitsuOptions): ErrorHandler {
635
+ const configuredHandler = opts.errorPolicy || "log";
636
+ if (typeof configuredHandler === "function") {
637
+ return configuredHandler;
638
+ } else if (configuredHandler === "rethrow") {
639
+ return (msg, ...args) => {
640
+ //ignore args, not clear what to do with them
641
+ throw new Error(msg);
642
+ };
643
+ } else {
644
+ return (msg, ...args) => {
645
+ console.error(msg, ...args);
646
+ };
647
+ }
648
+ }
649
+
630
650
  async function send(
631
651
  method,
632
652
  payload,
@@ -642,6 +662,7 @@ async function send(
642
662
  const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`;
643
663
  const fetch = jitsuConfig.fetch || globalThis.fetch;
644
664
  if (!fetch) {
665
+ //don't run it through error handler since error is critical and should be addressed
645
666
  throw new Error(
646
667
  "Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope"
647
668
  );
@@ -681,7 +702,8 @@ async function send(
681
702
  clearTimeout(abortTimeout);
682
703
  }
683
704
  } catch (e: any) {
684
- throw new Error(`Calling ${url} failed: ${e.message}`);
705
+ getErrorHandler(jitsuConfig)(`Call to ${url} failed with error ${e.message}`);
706
+ return Promise.resolve();
685
707
  }
686
708
  let responseText;
687
709
  try {
@@ -708,7 +730,8 @@ async function send(
708
730
  try {
709
731
  responseJson = JSON.parse(responseText);
710
732
  } catch (e) {
711
- return Promise.reject(`Can't parse JSON: ${responseText}: ${e?.message}`);
733
+ getErrorHandler(jitsuConfig)(`Can't parse JSON: ${responseText}: ${e?.message}`);
734
+ return Promise.resolve();
712
735
  }
713
736
 
714
737
  if (responseJson.destinations && responseJson.destinations.length > 0) {
@@ -730,6 +753,23 @@ async function send(
730
753
  return adjustedPayload;
731
754
  }
732
755
 
756
+ const controllingTraits = ["$doNotSend"] as const;
757
+ /**
758
+ * Remove all members of traits that controls identify/group behavior (see analytics.d.ts), and should not be recorded. Returns
759
+ * copy of the object with these members removed.
760
+ *
761
+ * Do not modify traits object, but creates one
762
+ * @param traits
763
+ */
764
+ function stripControllingTraits(traits: Traits): Exclude<Traits, (typeof controllingTraits)[number]> {
765
+ const res = { ...traits };
766
+ // see Traits definition in analytics.d.ts. We cannot define const here, so here's a little code duplication
767
+ for (const key of controllingTraits) {
768
+ delete res[key];
769
+ }
770
+ return res;
771
+ }
772
+
733
773
  export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: PersistentStorage): AnalyticsPlugin => {
734
774
  // just to make sure that all undefined values are replaced with defaultConfig values
735
775
  mergeConfig(jitsuOptions, jitsuOptions);
@@ -792,9 +832,14 @@ export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: P
792
832
  }
793
833
  // Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
794
834
  storage.setItem("__user_id", payload.userId);
835
+ const doNotSend = payload.traits?.$doNotSend;
795
836
  if (payload.traits && typeof payload.traits === "object") {
837
+ payload.traits = stripControllingTraits(payload.traits);
796
838
  storage.setItem("__user_traits", payload.traits);
797
839
  }
840
+ if (doNotSend) {
841
+ return Promise.resolve();
842
+ }
798
843
  return send("identify", payload, config, instance, storage);
799
844
  },
800
845
  reset: args => {
@@ -838,9 +883,14 @@ export const jitsuAnalyticsPlugin = (jitsuOptions: JitsuOptions = {}, storage: P
838
883
  const userId = options?.userId || user?.userId;
839
884
  const anonymousId = options?.anonymousId || user?.anonymousId || storage.getItem("__anon_id");
840
885
  storage.setItem("__group_id", groupId);
886
+ const doNotSend = traits?.$doNotSend;
841
887
  if (traits && typeof traits === "object") {
888
+ traits = stripControllingTraits(traits);
842
889
  storage.setItem("__group_traits", traits);
843
890
  }
891
+ if (doNotSend) {
892
+ return Promise.resolve();
893
+ }
844
894
  return send(
845
895
  "group",
846
896
  { type: "group", groupId, traits, ...(anonymousId ? { anonymousId } : {}), ...(userId ? { userId } : {}) },