@chordcommerce/analytics 1.24.3 → 1.24.5

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.
Files changed (35) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/client/cdp.js +2 -2
  3. package/dist/cjs/client/consent/index.js +2 -2
  4. package/dist/cjs/client/consent/onetrust-api.d.ts +1 -1
  5. package/dist/cjs/client/consent/onetrust.d.ts +2 -2
  6. package/dist/cjs/client/consent/segment.js +19 -6
  7. package/dist/cjs/client/consent/shopify.d.ts +5 -1
  8. package/dist/cjs/client/consent/shopify.js +70 -21
  9. package/dist/cjs/client/index.js +16 -8
  10. package/dist/cjs/client/utils.js +1 -2
  11. package/dist/cjs/utils.d.ts +1 -1
  12. package/dist/cjs/utils.js +2 -2
  13. package/dist/cjs/validators/custom.d.ts +4 -38
  14. package/dist/cjs/validators/custom.js +5 -5
  15. package/dist/cjs/validators/objects.d.ts +73 -584
  16. package/dist/cjs/validators/objects.js +110 -111
  17. package/dist/cjs/validators/tracking-plan-map.d.ts +172 -5126
  18. package/dist/cjs/validators/tracking-plan.d.ts +272 -7008
  19. package/dist/cjs/validators/tracking-plan.js +1722 -1649
  20. package/dist/client/consent/onetrust-api.d.ts +1 -1
  21. package/dist/client/consent/onetrust.d.ts +2 -2
  22. package/dist/client/consent/segment.js +1 -1
  23. package/dist/client/consent/shopify.d.ts +5 -1
  24. package/dist/client/consent/shopify.js +70 -21
  25. package/dist/client/index.js +84 -84
  26. package/dist/tsconfig-build-cjs.tsbuildinfo +1 -0
  27. package/dist/utils.d.ts +1 -1
  28. package/dist/validators/custom.d.ts +4 -38
  29. package/dist/validators/custom.js +1 -1
  30. package/dist/validators/objects.d.ts +73 -584
  31. package/dist/validators/objects.js +27 -28
  32. package/dist/validators/tracking-plan-map.d.ts +172 -5126
  33. package/dist/validators/tracking-plan.d.ts +272 -7008
  34. package/dist/validators/tracking-plan.js +219 -146
  35. package/package.json +4 -4
package/README.md CHANGED
@@ -47,7 +47,7 @@ const { ChordPixel } = require('@chordcommerce/analytics/dist/cjs')
47
47
  | `cdp` | false | _Required when using a CDP other than Chord._ A reference to the CDP library, or a function that returns a reference to the CDP library. For example, if using Segment's [analytics.js](https://www.npmjs.com/package/@segment/analytics-next) library, this could be `window.analytics` or `() => window.analytics`. |
48
48
  | `cdpDomain` | false | _Required when using Chord CDP._ The Chord CDP domain. To be provided by the Chord team. |
49
49
  | `cdpWriteKey` | false | _Required when using Chord CDP._ The Chord CDP write key. To be provided by the Chord team. |
50
- | `debug` | false | Defaults to `false`. When set to `true`, events are validated against Chord's tracking plan and errors are logged. We recommend enabling this for development and disabling for production. |
50
+ | `debug` | false | Defaults to `false`. When set to `true`, events are validated against Chord's tracking plan and errors are logged. Validation uses zod 4. We recommend enabling this for development and disabling for production. |
51
51
  | `enableLogging` | false | Defaults to `true`. When set to `true`, errors are logged using `console.log`. |
52
52
  | `formatters` | true | Functions that are used to construct tracking events. There are two types of formatters, objects and events. `formatters.objects` is required. See below for details. |
53
53
  | `metadata` | true | Event metadata. See below for details. |
@@ -10,8 +10,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
10
10
  });
11
11
  };
12
12
  var __generator = (this && this.__generator) || function (thisArg, body) {
13
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
14
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
13
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
14
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
15
15
  function verb(n) { return function (v) { return step([n, v]); }; }
16
16
  function step(op) {
17
17
  if (f) throw new TypeError("Generator is already executing.");
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
14
  function verb(n) { return function (v) { return step([n, v]); }; }
15
15
  function step(op) {
16
16
  if (f) throw new TypeError("Generator is already executing.");
@@ -109,5 +109,5 @@ export declare const getNormalizedCategories: () => Record<string, boolean>;
109
109
  * @param model - OneTrust consent model name
110
110
  * @returns 'opt-in' or 'opt-out'
111
111
  */
112
- export declare const coerceConsentModel: (model: OtConsentModel | string) => 'opt-in' | 'opt-out';
112
+ export declare const coerceConsentModel: (model: OtConsentModel | string) => "opt-in" | "opt-out";
113
113
  export {};
@@ -5,6 +5,6 @@ export declare const onetrustConsentAdapter: (options: ChordAnalyticsOptions) =>
5
5
  userCanBeTracked: () => boolean;
6
6
  getCategories: () => Record<string, boolean>;
7
7
  isConsentReady: () => boolean;
8
- getConsentModel: () => 'opt-in' | 'opt-out';
9
- getApi: () => import("./onetrust-api.js").OneTrustGlobal;
8
+ getConsentModel: () => "opt-in" | "opt-out";
9
+ getApi: () => import("./onetrust-api.js").OneTrustGlobal | undefined;
10
10
  };
@@ -20,8 +20,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
20
20
  });
21
21
  };
22
22
  var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
25
  function verb(n) { return function (v) { return step([n, v]); }; }
26
26
  function step(op) {
27
27
  if (f) throw new TypeError("Generator is already executing.");
@@ -46,17 +46,30 @@ var __generator = (this && this.__generator) || function (thisArg, body) {
46
46
  if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
47
47
  }
48
48
  };
49
+ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
50
+ if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
51
+ if (ar || !(i in from)) {
52
+ if (!ar) ar = Array.prototype.slice.call(from, 0, i);
53
+ ar[i] = from[i];
54
+ }
55
+ }
56
+ return to.concat(ar || Array.prototype.slice.call(from));
57
+ };
49
58
  Object.defineProperty(exports, "__esModule", { value: true });
50
59
  exports.segmentConsentAdapter = void 0;
51
60
  var getApi = function () { return window.segmentConsent; };
52
61
  /**
53
62
  * Waits for the Segment consent API to be populated with retry logic.
54
63
  */
55
- var waitForApi = function (maxRetries, baseDelay) {
56
- if (maxRetries === void 0) { maxRetries = 10; }
57
- if (baseDelay === void 0) { baseDelay = 100; }
58
- return __awaiter(void 0, void 0, void 0, function () {
64
+ var waitForApi = function () {
65
+ var args_1 = [];
66
+ for (var _i = 0; _i < arguments.length; _i++) {
67
+ args_1[_i] = arguments[_i];
68
+ }
69
+ return __awaiter(void 0, __spreadArray([], args_1, true), void 0, function (maxRetries, baseDelay) {
59
70
  var attempt, checkAndWait;
71
+ if (maxRetries === void 0) { maxRetries = 10; }
72
+ if (baseDelay === void 0) { baseDelay = 100; }
60
73
  return __generator(this, function (_a) {
61
74
  attempt = 0;
62
75
  checkAndWait = function () { return __awaiter(void 0, void 0, void 0, function () {
@@ -2,7 +2,11 @@ import type { ConsentConfiguration } from '../../types/index.js';
2
2
  declare global {
3
3
  interface Window {
4
4
  Shopify?: {
5
- customerPrivacy?: ShopifyCustomerPrivacyApi;
5
+ customerPrivacy?: Partial<ShopifyCustomerPrivacyApi>;
6
+ loadFeatures?: (features: {
7
+ name: string;
8
+ version: string;
9
+ }[], callback?: (error?: unknown) => void) => void;
6
10
  };
7
11
  }
8
12
  }
@@ -2,9 +2,44 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.shopifyConsentAdapter = void 0;
4
4
  /**
5
- * Returns Shopify's Customer Privacy API.
5
+ * Returns Shopify's Customer Privacy API, or undefined until its methods load.
6
+ *
7
+ * Shopify puts a placeholder `customerPrivacy` object on every storefront that
8
+ * holds only cached values. The methods appear once a script requests the
9
+ * `consent-tracking-api` feature, so the placeholder alone is not usable.
10
+ */
11
+ var getApi = function () {
12
+ var _a;
13
+ var api = (_a = window.Shopify) === null || _a === void 0 ? void 0 : _a.customerPrivacy;
14
+ if (typeof (api === null || api === void 0 ? void 0 : api.analyticsProcessingAllowed) !== 'function' ||
15
+ typeof api.marketingAllowed !== 'function' ||
16
+ typeof api.preferencesProcessingAllowed !== 'function' ||
17
+ typeof api.saleOfDataAllowed !== 'function') {
18
+ return undefined;
19
+ }
20
+ return api;
21
+ };
22
+ /**
23
+ * Requests the Customer Privacy API from Shopify when no other script has.
24
+ * CMPs such as CookieYes load it themselves; Shopify's own banner does not
25
+ * expose it, which left every event waiting on a consent check that threw.
6
26
  */
7
- var getApi = function () { var _a; return (_a = window.Shopify) === null || _a === void 0 ? void 0 : _a.customerPrivacy; };
27
+ var loadApi = function () {
28
+ var _a;
29
+ if (getApi() || typeof ((_a = window.Shopify) === null || _a === void 0 ? void 0 : _a.loadFeatures) !== 'function')
30
+ return;
31
+ try {
32
+ window.Shopify.loadFeatures([{ name: 'consent-tracking-api', version: '0.1' }], function (error) {
33
+ // eslint-disable-next-line no-console
34
+ if (error)
35
+ console.error('Could not load Shopify consent API', error);
36
+ });
37
+ }
38
+ catch (error) {
39
+ // eslint-disable-next-line no-console
40
+ console.error('Could not load Shopify consent API', error);
41
+ }
42
+ };
8
43
  /**
9
44
  * Returns whether the user can currently be tracked.
10
45
  *
@@ -20,21 +55,28 @@ var userCanBeTracked = function () {
20
55
  return !!(api.analyticsProcessingAllowed() && api.marketingAllowed());
21
56
  };
22
57
  /**
23
- * Returns the user's current consent configuration.
58
+ * Returns the user's current consent categories, or an empty object until the
59
+ * API has loaded.
24
60
  */
25
- var getCurrentConsent = function () {
61
+ var getCategories = function () {
26
62
  var api = getApi();
27
63
  if (!api)
28
64
  return {};
29
65
  return {
30
- consentCategories: {
31
- analytics: api.analyticsProcessingAllowed(),
32
- marketing: api.marketingAllowed(),
33
- preferences: api.preferencesProcessingAllowed(),
34
- sale_of_data: api.saleOfDataAllowed(),
35
- },
66
+ analytics: api.analyticsProcessingAllowed(),
67
+ marketing: api.marketingAllowed(),
68
+ preferences: api.preferencesProcessingAllowed(),
69
+ sale_of_data: api.saleOfDataAllowed(),
36
70
  };
37
71
  };
72
+ /**
73
+ * Returns the user's current consent configuration.
74
+ */
75
+ var getCurrentConsent = function () {
76
+ if (!getApi())
77
+ return {};
78
+ return { consentCategories: getCategories() };
79
+ };
38
80
  /**
39
81
  * Handles subsequent changes to consent configuration.
40
82
  */
@@ -44,22 +86,29 @@ var handleConsentUpdates = function (updateCdpConsent) {
44
86
  });
45
87
  };
46
88
  var shopifyConsentAdapter = function () {
89
+ // Requested once per adapter. Retried from isConsentReady() because the
90
+ // SDK can start before Shopify defines loadFeatures.
91
+ var apiRequested = false;
92
+ var requestApi = function () {
93
+ var _a;
94
+ if (apiRequested || typeof ((_a = window.Shopify) === null || _a === void 0 ? void 0 : _a.loadFeatures) !== 'function') {
95
+ return;
96
+ }
97
+ apiRequested = true;
98
+ loadApi();
99
+ };
100
+ requestApi();
47
101
  return {
48
102
  getCurrentConsent: getCurrentConsent,
49
103
  handleConsentUpdates: handleConsentUpdates,
50
104
  userCanBeTracked: userCanBeTracked,
51
- getCategories: function () {
52
- var api = getApi();
53
- if (!api)
54
- return {};
55
- return {
56
- analytics: api.analyticsProcessingAllowed(),
57
- marketing: api.marketingAllowed(),
58
- preferences: api.preferencesProcessingAllowed(),
59
- sale_of_data: api.saleOfDataAllowed(),
60
- };
105
+ getCategories: getCategories,
106
+ isConsentReady: function () {
107
+ if (getApi())
108
+ return true;
109
+ requestApi();
110
+ return false;
61
111
  },
62
- isConsentReady: function () { return !!getApi(); },
63
112
  };
64
113
  };
65
114
  exports.shopifyConsentAdapter = shopifyConsentAdapter;
@@ -20,8 +20,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
20
20
  });
21
21
  };
22
22
  var __generator = (this && this.__generator) || function (thisArg, body) {
23
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
24
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
23
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
24
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
25
25
  function verb(n) { return function (v) { return step([n, v]); }; }
26
26
  function step(op) {
27
27
  if (f) throw new TypeError("Generator is already executing.");
@@ -743,10 +743,14 @@ var ChordAnalytics = /** @class */ (function () {
743
743
  * Send a `page` event to the CDP.
744
744
  * If consent is not ready, the event is queued until consent is available.
745
745
  */
746
- this.page = function (options, props) {
747
- if (props === void 0) { props = {}; }
748
- return __awaiter(_this, void 0, void 0, function () {
746
+ this.page = function (options_1) {
747
+ var args_1 = [];
748
+ for (var _i = 1; _i < arguments.length; _i++) {
749
+ args_1[_i - 1] = arguments[_i];
750
+ }
751
+ return __awaiter(_this, __spreadArray([options_1], args_1, true), void 0, function (options, props) {
749
752
  var gate;
753
+ if (props === void 0) { props = {}; }
750
754
  return __generator(this, function (_a) {
751
755
  switch (_a.label) {
752
756
  case 0:
@@ -772,10 +776,14 @@ var ChordAnalytics = /** @class */ (function () {
772
776
  /**
773
777
  * Internal method to actually send a page event to CDP.
774
778
  */
775
- this.sendPageEvent = function (options, props) {
776
- if (props === void 0) { props = {}; }
777
- return __awaiter(_this, void 0, void 0, function () {
779
+ this.sendPageEvent = function (options_1) {
780
+ var args_1 = [];
781
+ for (var _i = 1; _i < arguments.length; _i++) {
782
+ args_1[_i - 1] = arguments[_i];
783
+ }
784
+ return __awaiter(_this, __spreadArray([options_1], args_1, true), void 0, function (options, props) {
778
785
  var _this = this;
786
+ if (props === void 0) { props = {}; }
779
787
  return __generator(this, function (_a) {
780
788
  switch (_a.label) {
781
789
  case 0:
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.normalizeCDPDomain = void 0;
3
+ exports.normalizeCDPDomain = normalizeCDPDomain;
4
4
  function normalizeCDPDomain(cdpDomain) {
5
5
  var domain = cdpDomain.replace(/\/+$/, '');
6
6
  if (domain.endsWith('/p.js')) {
@@ -9,4 +9,3 @@ function normalizeCDPDomain(cdpDomain) {
9
9
  }
10
10
  return domain;
11
11
  }
12
- exports.normalizeCDPDomain = normalizeCDPDomain;
@@ -27,4 +27,4 @@ export declare const isPromise: (value: unknown) => value is Promise<unknown>;
27
27
  * The timer is cleared either way, so a promise that settles quickly does not
28
28
  * leave a pending timeout behind.
29
29
  */
30
- export declare const withTimeout: <T>(promise: Promise<T>, ms: number) => Promise<typeof TIMED_OUT | T>;
30
+ export declare const withTimeout: <T>(promise: Promise<T>, ms: number) => Promise<T | typeof TIMED_OUT>;
package/dist/cjs/utils.js CHANGED
@@ -9,8 +9,8 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  var __generator = (this && this.__generator) || function (thisArg, body) {
12
- var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
13
- return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
12
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
13
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
14
14
  function verb(n) { return function (v) { return step([n, v]); }; }
15
15
  function step(op) {
16
16
  if (f) throw new TypeError("Generator is already executing.");
@@ -1,43 +1,9 @@
1
- import { z } from 'zod';
2
- export declare const productInProductsSchema: z.ZodEffects<z.ZodObject<{
1
+ import * as z from 'zod';
2
+ export declare const productInProductsSchema: z.ZodObject<{
3
3
  product_id: z.ZodString;
4
4
  sku: z.ZodString;
5
5
  products: z.ZodArray<z.ZodObject<{
6
6
  product_id: z.ZodString;
7
7
  sku: z.ZodString;
8
- }, "strip", z.ZodTypeAny, {
9
- product_id?: string;
10
- sku?: string;
11
- }, {
12
- product_id?: string;
13
- sku?: string;
14
- }>, "many">;
15
- }, "strip", z.ZodTypeAny, {
16
- product_id?: string;
17
- sku?: string;
18
- products?: {
19
- product_id?: string;
20
- sku?: string;
21
- }[];
22
- }, {
23
- product_id?: string;
24
- sku?: string;
25
- products?: {
26
- product_id?: string;
27
- sku?: string;
28
- }[];
29
- }>, {
30
- product_id?: string;
31
- sku?: string;
32
- products?: {
33
- product_id?: string;
34
- sku?: string;
35
- }[];
36
- }, {
37
- product_id?: string;
38
- sku?: string;
39
- products?: {
40
- product_id?: string;
41
- sku?: string;
42
- }[];
43
- }>;
8
+ }, z.z.core.$strip>>;
9
+ }, z.z.core.$strip>;
@@ -1,12 +1,12 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.productInProductsSchema = void 0;
4
- var zod_1 = require("zod");
5
- exports.productInProductsSchema = zod_1.z
4
+ var z = require("zod");
5
+ exports.productInProductsSchema = z
6
6
  .object({
7
- product_id: zod_1.z.string(),
8
- sku: zod_1.z.string(),
9
- products: zod_1.z.array(zod_1.z.object({ product_id: zod_1.z.string(), sku: zod_1.z.string() })),
7
+ product_id: z.string(),
8
+ sku: z.string(),
9
+ products: z.array(z.object({ product_id: z.string(), sku: z.string() })),
10
10
  })
11
11
  .refine(function (event) {
12
12
  var productInCart = event.products.find(function (p) {