@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.
package/README.md CHANGED
@@ -1,7 +1,7 @@
1
1
  ## Install
2
2
 
3
3
  ```bash
4
- npm install --save @jitsu/jitsu-react
4
+ npm install --save @jitsu/jitsu-js
5
5
  ```
6
6
 
7
7
  ## Usage
@@ -10,6 +10,7 @@
10
10
  window.testOnload = async j => {
11
11
  await j.setAnonymousId("john-doe-id-1");
12
12
  await j.identify("john-nondoe", { email: "john@example.com" });
13
+ await j.identify("john-nondoe", { email: "john2@example.com", $doNotSend: true });
13
14
  await j.track("pageLoaded", { trackParam: "trackValue" });
14
15
  await j.reset();
15
16
  await j.track("pageLoaded", { trackParam: "trackValue" });
@@ -273,6 +273,9 @@ test("reset", async ({ browser }) => {
273
273
  const newAnonymousId = cookies[0].value;
274
274
  console.log(`🍪Cookies`, cookies);
275
275
 
276
+ //second identify call should not reach the server, but it should change the traits
277
+ expect(firstTrack.body.context.traits?.email).toEqual("john2@example.com");
278
+
276
279
  expect(secondTrack.body.anonymousId).not.toBeNull();
277
280
  expect(secondTrack.body.anonymousId).toBeDefined();
278
281
  expect(secondTrack.body.anonymousId).toEqual(newAnonymousId);
package/dist/jitsu.cjs.js CHANGED
@@ -1065,6 +1065,7 @@ const defaultConfig = {
1065
1065
  fetchTimeoutMs: undefined,
1066
1066
  s2s: undefined,
1067
1067
  idEndpoint: undefined,
1068
+ errorPolicy: "log",
1068
1069
  privacy: {
1069
1070
  dontSend: false,
1070
1071
  disableUserIds: false,
@@ -1401,18 +1402,19 @@ function urlPath(url) {
1401
1402
  return "/" + pathMatch;
1402
1403
  }
1403
1404
  function adjustPayload(payload, config, storage, s2s) {
1404
- var _a, _b, _c, _d, _e;
1405
+ var _a, _b, _c, _d, _e, _f;
1405
1406
  const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
1406
1407
  const url = runtime.pageUrl();
1407
1408
  const parsedUrl = safeCall(() => new URL(url), undefined);
1408
1409
  const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
1409
1410
  const properties = payload.properties || {};
1410
- if (payload.type === "page" && url) {
1411
- properties.url = url.replace(hashRegex, "");
1412
- properties.path = fixPath(urlPath(url));
1411
+ if (payload.type === "page" && (properties.url || url)) {
1412
+ const targetUrl = properties.url || url;
1413
+ properties.url = targetUrl.replace(hashRegex, "");
1414
+ properties.path = fixPath(urlPath(targetUrl));
1413
1415
  }
1414
- const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
1415
- (_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
1416
+ const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {};
1417
+ (_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
1416
1418
  const referrer = runtime.referrer();
1417
1419
  const context = {
1418
1420
  library: {
@@ -1420,7 +1422,7 @@ function adjustPayload(payload, config, storage, s2s) {
1420
1422
  version: jitsuVersion,
1421
1423
  env: isInBrowser() ? "browser" : "node",
1422
1424
  },
1423
- consent: ((_c = config.privacy) === null || _c === void 0 ? void 0 : _c.consentCategories)
1425
+ consent: ((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.consentCategories)
1424
1426
  ? {
1425
1427
  categoryPreferences: config.privacy.consentCategories,
1426
1428
  }
@@ -1439,14 +1441,14 @@ function adjustPayload(payload, config, storage, s2s) {
1439
1441
  url: properties.url || url,
1440
1442
  encoding: properties.encoding || runtime.documentEncoding(),
1441
1443
  },
1442
- clientIds: !((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.disableUserIds)
1444
+ clientIds: !((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds)
1443
1445
  ? Object.assign({ fbc: runtime.getCookie("_fbc"), fbp: runtime.getCookie("_fbp") }, getGa4Ids(runtime)) : undefined,
1444
1446
  campaign: parseUtms(query),
1445
1447
  };
1446
1448
  const withContext = Object.assign(Object.assign({}, payload), { timestamp: new Date().toISOString(), sentAt: new Date().toISOString(), messageId: randomId(properties.path || (parsedUrl && parsedUrl.pathname)), writeKey: maskWriteKey(config.writeKey), groupId: storage.getItem("__group_id"), context: deepMerge(context, customContext) });
1447
1449
  delete withContext.meta;
1448
1450
  delete withContext.options;
1449
- if ((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds) {
1451
+ if ((_f = config.privacy) === null || _f === void 0 ? void 0 : _f.disableUserIds) {
1450
1452
  delete withContext.userId;
1451
1453
  delete withContext.anonymousId;
1452
1454
  delete withContext.context.traits;
@@ -1555,6 +1557,23 @@ function maskWriteKey(writeKey) {
1555
1557
  }
1556
1558
  return writeKey;
1557
1559
  }
1560
+ function getErrorHandler(opts) {
1561
+ const configuredHandler = opts.errorPolicy || "log";
1562
+ if (typeof configuredHandler === "function") {
1563
+ return configuredHandler;
1564
+ }
1565
+ else if (configuredHandler === "rethrow") {
1566
+ return (msg, ...args) => {
1567
+ //ignore args, not clear what to do with them
1568
+ throw new Error(msg);
1569
+ };
1570
+ }
1571
+ else {
1572
+ return (msg, ...args) => {
1573
+ console.error(msg, ...args);
1574
+ };
1575
+ }
1576
+ }
1558
1577
  function send(method, payload, jitsuConfig, instance, store) {
1559
1578
  return __awaiter$1(this, void 0, void 0, function* () {
1560
1579
  var _a, _b;
@@ -1566,6 +1585,7 @@ function send(method, payload, jitsuConfig, instance, store) {
1566
1585
  const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`;
1567
1586
  const fetch = jitsuConfig.fetch || globalThis.fetch;
1568
1587
  if (!fetch) {
1588
+ //don't run it through error handler since error is critical and should be addressed
1569
1589
  throw new Error("Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope");
1570
1590
  }
1571
1591
  const debugHeader = jitsuConfig.debug ? { "X-Enable-Debug": "true" } : {};
@@ -1596,7 +1616,8 @@ function send(method, payload, jitsuConfig, instance, store) {
1596
1616
  }
1597
1617
  }
1598
1618
  catch (e) {
1599
- throw new Error(`Calling ${url} failed: ${e.message}`);
1619
+ getErrorHandler(jitsuConfig)(`Call to ${url} failed with error ${e.message}`);
1620
+ return Promise.resolve();
1600
1621
  }
1601
1622
  let responseText;
1602
1623
  try {
@@ -1616,7 +1637,8 @@ function send(method, payload, jitsuConfig, instance, store) {
1616
1637
  responseJson = JSON.parse(responseText);
1617
1638
  }
1618
1639
  catch (e) {
1619
- return Promise.reject(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1640
+ getErrorHandler(jitsuConfig)(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1641
+ return Promise.resolve();
1620
1642
  }
1621
1643
  if (responseJson.destinations && responseJson.destinations.length > 0) {
1622
1644
  if (jitsuConfig.s2s) {
@@ -1635,6 +1657,22 @@ function send(method, payload, jitsuConfig, instance, store) {
1635
1657
  return adjustedPayload;
1636
1658
  });
1637
1659
  }
1660
+ const controllingTraits = ["$doNotSend"];
1661
+ /**
1662
+ * Remove all members of traits that controls identify/group behavior (see analytics.d.ts), and should not be recorded. Returns
1663
+ * copy of the object with these members removed.
1664
+ *
1665
+ * Do not modify traits object, but creates one
1666
+ * @param traits
1667
+ */
1668
+ function stripControllingTraits(traits) {
1669
+ const res = Object.assign({}, traits);
1670
+ // see Traits definition in analytics.d.ts. We cannot define const here, so here's a little code duplication
1671
+ for (const key of controllingTraits) {
1672
+ delete res[key];
1673
+ }
1674
+ return res;
1675
+ }
1638
1676
  const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1639
1677
  // just to make sure that all undefined values are replaced with defaultConfig values
1640
1678
  mergeConfig(jitsuOptions, jitsuOptions);
@@ -1693,16 +1731,21 @@ const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1693
1731
  return send("track", payload, config, instance, storage);
1694
1732
  },
1695
1733
  identify: args => {
1696
- var _a, _b;
1734
+ var _a, _b, _c;
1697
1735
  const { payload, config, instance } = args;
1698
1736
  if (((_a = config.privacy) === null || _a === void 0 ? void 0 : _a.dontSend) || ((_b = config.privacy) === null || _b === void 0 ? void 0 : _b.disableUserIds)) {
1699
1737
  return;
1700
1738
  }
1701
1739
  // Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
1702
1740
  storage.setItem("__user_id", payload.userId);
1741
+ const doNotSend = (_c = payload.traits) === null || _c === void 0 ? void 0 : _c.$doNotSend;
1703
1742
  if (payload.traits && typeof payload.traits === "object") {
1743
+ payload.traits = stripControllingTraits(payload.traits);
1704
1744
  storage.setItem("__user_traits", payload.traits);
1705
1745
  }
1746
+ if (doNotSend) {
1747
+ return Promise.resolve();
1748
+ }
1706
1749
  return send("identify", payload, config, instance, storage);
1707
1750
  },
1708
1751
  reset: args => {
@@ -1747,9 +1790,14 @@ const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1747
1790
  const userId = (options === null || options === void 0 ? void 0 : options.userId) || (user === null || user === void 0 ? void 0 : user.userId);
1748
1791
  const anonymousId = (options === null || options === void 0 ? void 0 : options.anonymousId) || (user === null || user === void 0 ? void 0 : user.anonymousId) || storage.getItem("__anon_id");
1749
1792
  storage.setItem("__group_id", groupId);
1793
+ const doNotSend = traits === null || traits === void 0 ? void 0 : traits.$doNotSend;
1750
1794
  if (traits && typeof traits === "object") {
1795
+ traits = stripControllingTraits(traits);
1751
1796
  storage.setItem("__group_traits", traits);
1752
1797
  }
1798
+ if (doNotSend) {
1799
+ return Promise.resolve();
1800
+ }
1753
1801
  return send("group", Object.assign(Object.assign({ type: "group", groupId, traits }, (anonymousId ? { anonymousId } : {})), (userId ? { userId } : {})), jitsuOptions, instance, storage);
1754
1802
  },
1755
1803
  },
package/dist/jitsu.es.js CHANGED
@@ -1063,6 +1063,7 @@ const defaultConfig = {
1063
1063
  fetchTimeoutMs: undefined,
1064
1064
  s2s: undefined,
1065
1065
  idEndpoint: undefined,
1066
+ errorPolicy: "log",
1066
1067
  privacy: {
1067
1068
  dontSend: false,
1068
1069
  disableUserIds: false,
@@ -1399,18 +1400,19 @@ function urlPath(url) {
1399
1400
  return "/" + pathMatch;
1400
1401
  }
1401
1402
  function adjustPayload(payload, config, storage, s2s) {
1402
- var _a, _b, _c, _d, _e;
1403
+ var _a, _b, _c, _d, _e, _f;
1403
1404
  const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
1404
1405
  const url = runtime.pageUrl();
1405
1406
  const parsedUrl = safeCall(() => new URL(url), undefined);
1406
1407
  const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
1407
1408
  const properties = payload.properties || {};
1408
- if (payload.type === "page" && url) {
1409
- properties.url = url.replace(hashRegex, "");
1410
- properties.path = fixPath(urlPath(url));
1409
+ if (payload.type === "page" && (properties.url || url)) {
1410
+ const targetUrl = properties.url || url;
1411
+ properties.url = targetUrl.replace(hashRegex, "");
1412
+ properties.path = fixPath(urlPath(targetUrl));
1411
1413
  }
1412
- const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
1413
- (_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
1414
+ const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {};
1415
+ (_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
1414
1416
  const referrer = runtime.referrer();
1415
1417
  const context = {
1416
1418
  library: {
@@ -1418,7 +1420,7 @@ function adjustPayload(payload, config, storage, s2s) {
1418
1420
  version: jitsuVersion,
1419
1421
  env: isInBrowser() ? "browser" : "node",
1420
1422
  },
1421
- consent: ((_c = config.privacy) === null || _c === void 0 ? void 0 : _c.consentCategories)
1423
+ consent: ((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.consentCategories)
1422
1424
  ? {
1423
1425
  categoryPreferences: config.privacy.consentCategories,
1424
1426
  }
@@ -1437,14 +1439,14 @@ function adjustPayload(payload, config, storage, s2s) {
1437
1439
  url: properties.url || url,
1438
1440
  encoding: properties.encoding || runtime.documentEncoding(),
1439
1441
  },
1440
- clientIds: !((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.disableUserIds)
1442
+ clientIds: !((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds)
1441
1443
  ? Object.assign({ fbc: runtime.getCookie("_fbc"), fbp: runtime.getCookie("_fbp") }, getGa4Ids(runtime)) : undefined,
1442
1444
  campaign: parseUtms(query),
1443
1445
  };
1444
1446
  const withContext = Object.assign(Object.assign({}, payload), { timestamp: new Date().toISOString(), sentAt: new Date().toISOString(), messageId: randomId(properties.path || (parsedUrl && parsedUrl.pathname)), writeKey: maskWriteKey(config.writeKey), groupId: storage.getItem("__group_id"), context: deepMerge(context, customContext) });
1445
1447
  delete withContext.meta;
1446
1448
  delete withContext.options;
1447
- if ((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds) {
1449
+ if ((_f = config.privacy) === null || _f === void 0 ? void 0 : _f.disableUserIds) {
1448
1450
  delete withContext.userId;
1449
1451
  delete withContext.anonymousId;
1450
1452
  delete withContext.context.traits;
@@ -1553,6 +1555,23 @@ function maskWriteKey(writeKey) {
1553
1555
  }
1554
1556
  return writeKey;
1555
1557
  }
1558
+ function getErrorHandler(opts) {
1559
+ const configuredHandler = opts.errorPolicy || "log";
1560
+ if (typeof configuredHandler === "function") {
1561
+ return configuredHandler;
1562
+ }
1563
+ else if (configuredHandler === "rethrow") {
1564
+ return (msg, ...args) => {
1565
+ //ignore args, not clear what to do with them
1566
+ throw new Error(msg);
1567
+ };
1568
+ }
1569
+ else {
1570
+ return (msg, ...args) => {
1571
+ console.error(msg, ...args);
1572
+ };
1573
+ }
1574
+ }
1556
1575
  function send(method, payload, jitsuConfig, instance, store) {
1557
1576
  return __awaiter$1(this, void 0, void 0, function* () {
1558
1577
  var _a, _b;
@@ -1564,6 +1583,7 @@ function send(method, payload, jitsuConfig, instance, store) {
1564
1583
  const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`;
1565
1584
  const fetch = jitsuConfig.fetch || globalThis.fetch;
1566
1585
  if (!fetch) {
1586
+ //don't run it through error handler since error is critical and should be addressed
1567
1587
  throw new Error("Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope");
1568
1588
  }
1569
1589
  const debugHeader = jitsuConfig.debug ? { "X-Enable-Debug": "true" } : {};
@@ -1594,7 +1614,8 @@ function send(method, payload, jitsuConfig, instance, store) {
1594
1614
  }
1595
1615
  }
1596
1616
  catch (e) {
1597
- throw new Error(`Calling ${url} failed: ${e.message}`);
1617
+ getErrorHandler(jitsuConfig)(`Call to ${url} failed with error ${e.message}`);
1618
+ return Promise.resolve();
1598
1619
  }
1599
1620
  let responseText;
1600
1621
  try {
@@ -1614,7 +1635,8 @@ function send(method, payload, jitsuConfig, instance, store) {
1614
1635
  responseJson = JSON.parse(responseText);
1615
1636
  }
1616
1637
  catch (e) {
1617
- return Promise.reject(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1638
+ getErrorHandler(jitsuConfig)(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1639
+ return Promise.resolve();
1618
1640
  }
1619
1641
  if (responseJson.destinations && responseJson.destinations.length > 0) {
1620
1642
  if (jitsuConfig.s2s) {
@@ -1633,6 +1655,22 @@ function send(method, payload, jitsuConfig, instance, store) {
1633
1655
  return adjustedPayload;
1634
1656
  });
1635
1657
  }
1658
+ const controllingTraits = ["$doNotSend"];
1659
+ /**
1660
+ * Remove all members of traits that controls identify/group behavior (see analytics.d.ts), and should not be recorded. Returns
1661
+ * copy of the object with these members removed.
1662
+ *
1663
+ * Do not modify traits object, but creates one
1664
+ * @param traits
1665
+ */
1666
+ function stripControllingTraits(traits) {
1667
+ const res = Object.assign({}, traits);
1668
+ // see Traits definition in analytics.d.ts. We cannot define const here, so here's a little code duplication
1669
+ for (const key of controllingTraits) {
1670
+ delete res[key];
1671
+ }
1672
+ return res;
1673
+ }
1636
1674
  const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1637
1675
  // just to make sure that all undefined values are replaced with defaultConfig values
1638
1676
  mergeConfig(jitsuOptions, jitsuOptions);
@@ -1691,16 +1729,21 @@ const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1691
1729
  return send("track", payload, config, instance, storage);
1692
1730
  },
1693
1731
  identify: args => {
1694
- var _a, _b;
1732
+ var _a, _b, _c;
1695
1733
  const { payload, config, instance } = args;
1696
1734
  if (((_a = config.privacy) === null || _a === void 0 ? void 0 : _a.dontSend) || ((_b = config.privacy) === null || _b === void 0 ? void 0 : _b.disableUserIds)) {
1697
1735
  return;
1698
1736
  }
1699
1737
  // Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
1700
1738
  storage.setItem("__user_id", payload.userId);
1739
+ const doNotSend = (_c = payload.traits) === null || _c === void 0 ? void 0 : _c.$doNotSend;
1701
1740
  if (payload.traits && typeof payload.traits === "object") {
1741
+ payload.traits = stripControllingTraits(payload.traits);
1702
1742
  storage.setItem("__user_traits", payload.traits);
1703
1743
  }
1744
+ if (doNotSend) {
1745
+ return Promise.resolve();
1746
+ }
1704
1747
  return send("identify", payload, config, instance, storage);
1705
1748
  },
1706
1749
  reset: args => {
@@ -1745,9 +1788,14 @@ const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1745
1788
  const userId = (options === null || options === void 0 ? void 0 : options.userId) || (user === null || user === void 0 ? void 0 : user.userId);
1746
1789
  const anonymousId = (options === null || options === void 0 ? void 0 : options.anonymousId) || (user === null || user === void 0 ? void 0 : user.anonymousId) || storage.getItem("__anon_id");
1747
1790
  storage.setItem("__group_id", groupId);
1791
+ const doNotSend = traits === null || traits === void 0 ? void 0 : traits.$doNotSend;
1748
1792
  if (traits && typeof traits === "object") {
1793
+ traits = stripControllingTraits(traits);
1749
1794
  storage.setItem("__group_traits", traits);
1750
1795
  }
1796
+ if (doNotSend) {
1797
+ return Promise.resolve();
1798
+ }
1751
1799
  return send("group", Object.assign(Object.assign({ type: "group", groupId, traits }, (anonymousId ? { anonymousId } : {})), (userId ? { userId } : {})), jitsuOptions, instance, storage);
1752
1800
  },
1753
1801
  },
package/dist/web/p.js.txt CHANGED
@@ -1066,6 +1066,7 @@
1066
1066
  fetchTimeoutMs: undefined,
1067
1067
  s2s: undefined,
1068
1068
  idEndpoint: undefined,
1069
+ errorPolicy: "log",
1069
1070
  privacy: {
1070
1071
  dontSend: false,
1071
1072
  disableUserIds: false,
@@ -1402,18 +1403,19 @@
1402
1403
  return "/" + pathMatch;
1403
1404
  }
1404
1405
  function adjustPayload(payload, config, storage, s2s) {
1405
- var _a, _b, _c, _d, _e;
1406
+ var _a, _b, _c, _d, _e, _f;
1406
1407
  const runtime = config.runtime || (isInBrowser() ? windowRuntime(config) : emptyRuntime(config));
1407
1408
  const url = runtime.pageUrl();
1408
1409
  const parsedUrl = safeCall(() => new URL(url), undefined);
1409
1410
  const query = parsedUrl ? parseQuery(parsedUrl.search) : {};
1410
1411
  const properties = payload.properties || {};
1411
- if (payload.type === "page" && url) {
1412
- properties.url = url.replace(hashRegex, "");
1413
- properties.path = fixPath(urlPath(url));
1412
+ if (payload.type === "page" && (properties.url || url)) {
1413
+ const targetUrl = properties.url || url;
1414
+ properties.url = targetUrl.replace(hashRegex, "");
1415
+ properties.path = fixPath(urlPath(targetUrl));
1414
1416
  }
1415
- const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || {};
1416
- (_b = payload.properties) === null || _b === void 0 ? true : delete _b.context;
1417
+ const customContext = ((_a = payload.properties) === null || _a === void 0 ? void 0 : _a.context) || ((_b = payload.options) === null || _b === void 0 ? void 0 : _b.context) || {};
1418
+ (_c = payload.properties) === null || _c === void 0 ? true : delete _c.context;
1417
1419
  const referrer = runtime.referrer();
1418
1420
  const context = {
1419
1421
  library: {
@@ -1421,7 +1423,7 @@
1421
1423
  version: jitsuVersion,
1422
1424
  env: isInBrowser() ? "browser" : "node",
1423
1425
  },
1424
- consent: ((_c = config.privacy) === null || _c === void 0 ? void 0 : _c.consentCategories)
1426
+ consent: ((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.consentCategories)
1425
1427
  ? {
1426
1428
  categoryPreferences: config.privacy.consentCategories,
1427
1429
  }
@@ -1440,14 +1442,14 @@
1440
1442
  url: properties.url || url,
1441
1443
  encoding: properties.encoding || runtime.documentEncoding(),
1442
1444
  },
1443
- clientIds: !((_d = config.privacy) === null || _d === void 0 ? void 0 : _d.disableUserIds)
1445
+ clientIds: !((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds)
1444
1446
  ? Object.assign({ fbc: runtime.getCookie("_fbc"), fbp: runtime.getCookie("_fbp") }, getGa4Ids(runtime)) : undefined,
1445
1447
  campaign: parseUtms(query),
1446
1448
  };
1447
1449
  const withContext = Object.assign(Object.assign({}, payload), { timestamp: new Date().toISOString(), sentAt: new Date().toISOString(), messageId: randomId(properties.path || (parsedUrl && parsedUrl.pathname)), writeKey: maskWriteKey(config.writeKey), groupId: storage.getItem("__group_id"), context: deepMerge(context, customContext) });
1448
1450
  delete withContext.meta;
1449
1451
  delete withContext.options;
1450
- if ((_e = config.privacy) === null || _e === void 0 ? void 0 : _e.disableUserIds) {
1452
+ if ((_f = config.privacy) === null || _f === void 0 ? void 0 : _f.disableUserIds) {
1451
1453
  delete withContext.userId;
1452
1454
  delete withContext.anonymousId;
1453
1455
  delete withContext.context.traits;
@@ -1556,6 +1558,23 @@
1556
1558
  }
1557
1559
  return writeKey;
1558
1560
  }
1561
+ function getErrorHandler(opts) {
1562
+ const configuredHandler = opts.errorPolicy || "log";
1563
+ if (typeof configuredHandler === "function") {
1564
+ return configuredHandler;
1565
+ }
1566
+ else if (configuredHandler === "rethrow") {
1567
+ return (msg, ...args) => {
1568
+ //ignore args, not clear what to do with them
1569
+ throw new Error(msg);
1570
+ };
1571
+ }
1572
+ else {
1573
+ return (msg, ...args) => {
1574
+ console.error(msg, ...args);
1575
+ };
1576
+ }
1577
+ }
1559
1578
  function send(method, payload, jitsuConfig, instance, store) {
1560
1579
  return __awaiter$1(this, void 0, void 0, function* () {
1561
1580
  var _a, _b;
@@ -1567,6 +1586,7 @@
1567
1586
  const url = s2s ? `${jitsuConfig.host}/api/s/s2s/${method}` : `${jitsuConfig.host}/api/s/${method}`;
1568
1587
  const fetch = jitsuConfig.fetch || globalThis.fetch;
1569
1588
  if (!fetch) {
1589
+ //don't run it through error handler since error is critical and should be addressed
1570
1590
  throw new Error("Please specify fetch function in jitsu plugin initialization, fetch isn't available in global scope");
1571
1591
  }
1572
1592
  const debugHeader = jitsuConfig.debug ? { "X-Enable-Debug": "true" } : {};
@@ -1597,7 +1617,8 @@
1597
1617
  }
1598
1618
  }
1599
1619
  catch (e) {
1600
- throw new Error(`Calling ${url} failed: ${e.message}`);
1620
+ getErrorHandler(jitsuConfig)(`Call to ${url} failed with error ${e.message}`);
1621
+ return Promise.resolve();
1601
1622
  }
1602
1623
  let responseText;
1603
1624
  try {
@@ -1617,7 +1638,8 @@
1617
1638
  responseJson = JSON.parse(responseText);
1618
1639
  }
1619
1640
  catch (e) {
1620
- return Promise.reject(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1641
+ getErrorHandler(jitsuConfig)(`Can't parse JSON: ${responseText}: ${e === null || e === void 0 ? void 0 : e.message}`);
1642
+ return Promise.resolve();
1621
1643
  }
1622
1644
  if (responseJson.destinations && responseJson.destinations.length > 0) {
1623
1645
  if (jitsuConfig.s2s) {
@@ -1636,6 +1658,22 @@
1636
1658
  return adjustedPayload;
1637
1659
  });
1638
1660
  }
1661
+ const controllingTraits = ["$doNotSend"];
1662
+ /**
1663
+ * Remove all members of traits that controls identify/group behavior (see analytics.d.ts), and should not be recorded. Returns
1664
+ * copy of the object with these members removed.
1665
+ *
1666
+ * Do not modify traits object, but creates one
1667
+ * @param traits
1668
+ */
1669
+ function stripControllingTraits(traits) {
1670
+ const res = Object.assign({}, traits);
1671
+ // see Traits definition in analytics.d.ts. We cannot define const here, so here's a little code duplication
1672
+ for (const key of controllingTraits) {
1673
+ delete res[key];
1674
+ }
1675
+ return res;
1676
+ }
1639
1677
  const jitsuAnalyticsPlugin = (jitsuOptions = {}, storage) => {
1640
1678
  // just to make sure that all undefined values are replaced with defaultConfig values
1641
1679
  mergeConfig(jitsuOptions, jitsuOptions);
@@ -1694,16 +1732,21 @@
1694
1732
  return send("track", payload, config, instance, storage);
1695
1733
  },
1696
1734
  identify: args => {
1697
- var _a, _b;
1735
+ var _a, _b, _c;
1698
1736
  const { payload, config, instance } = args;
1699
1737
  if (((_a = config.privacy) === null || _a === void 0 ? void 0 : _a.dontSend) || ((_b = config.privacy) === null || _b === void 0 ? void 0 : _b.disableUserIds)) {
1700
1738
  return;
1701
1739
  }
1702
1740
  // Store traits in cache to be able to use them in page and track events that run asynchronously with current identify.
1703
1741
  storage.setItem("__user_id", payload.userId);
1742
+ const doNotSend = (_c = payload.traits) === null || _c === void 0 ? void 0 : _c.$doNotSend;
1704
1743
  if (payload.traits && typeof payload.traits === "object") {
1744
+ payload.traits = stripControllingTraits(payload.traits);
1705
1745
  storage.setItem("__user_traits", payload.traits);
1706
1746
  }
1747
+ if (doNotSend) {
1748
+ return Promise.resolve();
1749
+ }
1707
1750
  return send("identify", payload, config, instance, storage);
1708
1751
  },
1709
1752
  reset: args => {
@@ -1748,9 +1791,14 @@
1748
1791
  const userId = (options === null || options === void 0 ? void 0 : options.userId) || (user === null || user === void 0 ? void 0 : user.userId);
1749
1792
  const anonymousId = (options === null || options === void 0 ? void 0 : options.anonymousId) || (user === null || user === void 0 ? void 0 : user.anonymousId) || storage.getItem("__anon_id");
1750
1793
  storage.setItem("__group_id", groupId);
1794
+ const doNotSend = traits === null || traits === void 0 ? void 0 : traits.$doNotSend;
1751
1795
  if (traits && typeof traits === "object") {
1796
+ traits = stripControllingTraits(traits);
1752
1797
  storage.setItem("__group_traits", traits);
1753
1798
  }
1799
+ if (doNotSend) {
1800
+ return Promise.resolve();
1801
+ }
1754
1802
  return send("group", Object.assign(Object.assign({ type: "group", groupId, traits }, (anonymousId ? { anonymousId } : {})), (userId ? { userId } : {})), jitsuOptions, instance, storage);
1755
1803
  },
1756
1804
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jitsu/js",
3
- "version": "1.9.9",
3
+ "version": "1.9.11",
4
4
  "description": "",
5
5
  "author": "Jitsu Dev Team <dev@jitsu.com>",
6
6
  "main": "dist/jitsu.cjs.js",
@@ -35,8 +35,8 @@
35
35
  "rollup": "^3.29.5",
36
36
  "ts-jest": "29.0.5",
37
37
  "typescript": "^5.6.3",
38
- "@jitsu/protocols": "1.9.9",
39
- "jsondiffpatch": "1.9.9"
38
+ "@jitsu/protocols": "1.9.11",
39
+ "jsondiffpatch": "1.9.11"
40
40
  },
41
41
  "dependencies": {
42
42
  "analytics": "0.8.9"