@constructor-io/constructorio-node 3.5.4 → 3.7.0

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
@@ -3,19 +3,26 @@
3
3
  [![npm](https://img.shields.io/npm/v/@constructor-io/constructorio-node)](https://www.npmjs.com/package/@constructor-io/constructorio-node)
4
4
  [![MIT licensed](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/Constructor-io/constructorio-node/blob/master/LICENSE)
5
5
  [![Minzipped Size](https://img.shields.io/bundlephobia/minzip/@constructor-io/constructorio-node)](https://bundlephobia.com/result?p=@constructor-io/constructorio-node)
6
- [![Dependencies](https://img.shields.io/david/Constructor-io/constructorio-node)](https://david-dm.org/constructor-io/constructorio-node)
7
6
 
8
7
  A Node.js client for [Constructor.io](http://constructor.io/). [Constructor.io](http://constructor.io/) provides search as a service that optimizes results using artificial intelligence (including natural language processing, re-ranking to optimize for conversions, and user personalization).
9
8
 
10
- ## 1. Install
9
+ > This client is intended for use in server side integrations. If you want a JavaScript client for client side (i.e. front end) integrations please use [@constructor-io/constructorio-client-javascript](https://github.com/Constructor-io/constructorio-client-javascript)
10
+
11
+ ## 1. Review the Requirements
12
+
13
+ Requesting results from your Node.js back-end can be useful in order to control result rendering logic on your server, or augment/hydrate results with data from another system. However, a back-end integration has additional requirements compared to a front-end integration. Please review [Back End API Integration](https://constructorio.zendesk.com/hc/en-us/articles/360047993194-Back-end-API-Integration) for more detail.
14
+
15
+ ## 2. Install
11
16
 
12
17
  This package can be installed via npm: `npm i @constructor-io/constructorio-node`. Once installed, simply import or require the package into your repository.
13
18
 
14
- ## 2. Retrieve an API key and token
19
+ **Important**: this library should only be used in a server-side context.
20
+
21
+ ## 3. Retrieve an API key and token
15
22
 
16
23
  You can find this in your [Constructor.io dashboard](https://constructor.io/dashboard). Contact sales if you'd like to sign up, or support if you believe your company already has an account.
17
24
 
18
- ## 3. Implement the Client
25
+ ## 4. Implement the Client
19
26
 
20
27
  Once imported, an instance of the client can be created as follows:
21
28
 
@@ -27,7 +34,7 @@ var constructorio = new ConstructorIOClient({
27
34
  });
28
35
  ```
29
36
 
30
- ## 4. Retrieve Results
37
+ ## 5. Retrieve Results
31
38
 
32
39
  After instantiating an instance of the client, four modules will be exposed as properties to help retrieve data from Constructor.io: `search`, `browse`, `autocomplete`, `recommendations`, `catalog` and `tracker`.
33
40
 
package/package.json CHANGED
@@ -1,13 +1,13 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-node",
3
- "version": "3.5.4",
3
+ "version": "3.7.0",
4
4
  "description": "Constructor.io Node.js client",
5
5
  "main": "src/constructorio.js",
6
6
  "scripts": {
7
7
  "version": "chmod +x ./scripts/verify-node-version.sh && ./scripts/verify-node-version.sh && npm run docs && git add ./docs/*",
8
8
  "check-lisc": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT'",
9
9
  "lint": "chmod 766 .git/hooks/pre-push && eslint 'src/**/*.js' 'spec/**/*.js'",
10
- "test": "mkdir -p test && cp -rf src/* test && mocha ./spec/* --opts ./mocha.opts --recursive",
10
+ "test": "mkdir -p test && cp -rf src/* test && mocha ./spec/*",
11
11
  "precoverage": "rm -rf ./coverage && rm -rf ./.nyc_output",
12
12
  "coverage": "nyc --all --reporter=html npm run test",
13
13
  "postcoverage": "serve --listen 8080 --config ./serve.json && rm -rf test",
@@ -36,19 +36,19 @@
36
36
  "chai": "^4.3.4",
37
37
  "chai-as-promised": "^7.1.1",
38
38
  "dotenv": "^8.6.0",
39
- "eslint": "^5.12.1",
40
- "eslint-config-airbnb-base": "^13.1.0",
39
+ "eslint": "^8.2.0",
40
+ "eslint-config-airbnb-base": "^15.0.0",
41
41
  "eslint-plugin-import": "^2.24.2",
42
42
  "jsdoc": "^3.6.7",
43
43
  "jsdom": "^15.1.1",
44
44
  "license-checker": "^25.0.1",
45
45
  "lodash.clonedeep": "^4.5.0",
46
46
  "minami": "^1.2.3",
47
- "mocha": "^6.2.0",
47
+ "mocha": "^9.1.3",
48
48
  "mocha-jsdom": "^2.0.0",
49
- "nyc": "^14.1.1",
49
+ "nyc": "^15.1.0",
50
50
  "pre-push": "^0.1.1",
51
- "serve": "^11.3.2",
51
+ "serve": "^13.0.2",
52
52
  "sinon": "^7.5.0",
53
53
  "sinon-chai": "^3.7.0",
54
54
  "uuid": "^8.3.2"
@@ -14,19 +14,20 @@ const { version: packageVersion } = require('../package.json');
14
14
  */
15
15
  class ConstructorIO {
16
16
  /**
17
- * @param {string} apiKey - Constructor.io API key
18
- * @param {string} [apiToken] - Constructor.io API token (required for catalog methods)
19
- * @param {string} [securityToken] - Constructor security token
20
- * @param {string} [serviceUrl='https://ac.cnstrc.com'] - API URL endpoint
21
- * @param {function} [fetch] - If supplied, will be utilized for requests rather than default Fetch API
22
- * @param {object} [networkParameters] - Parameters relevant to network requests
23
- * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds) - may be overridden within individual method calls
24
- * @property {object} [search] - Interface to {@link module:search}
25
- * @property {object} [browse] - Interface to {@link module:browse}
26
- * @property {object} [autocomplete] - Interface to {@link module:autocomplete}
27
- * @property {object} [recommendations] - Interface to {@link module:recommendations}
28
- * @property {object} [tracker] - Interface to {@link module:tracker}
29
- * @property {object} [catalog] - Interface to {@link module:catalog}
17
+ * @param {object} parameters - Parameters for client instantiation
18
+ * @param {string} parameters.apiKey - Constructor.io API key
19
+ * @param {string} [parameters.apiToken] - Constructor.io API token (required for catalog methods)
20
+ * @param {string} [parameters.securityToken] - Constructor security token
21
+ * @param {string} [parameters.serviceUrl='https://ac.cnstrc.com'] - API URL endpoint
22
+ * @param {function} [parameters.fetch] - If supplied, will be utilized for requests rather than default Fetch API
23
+ * @param {object} [parameters.networkParameters] - Parameters relevant to network requests
24
+ * @param {number} [parameters.networkParameters.timeout] - Request timeout (in milliseconds) - may be overridden within individual method calls
25
+ * @property {object} search - Interface to {@link module:search}
26
+ * @property {object} browse - Interface to {@link module:browse}
27
+ * @property {object} autocomplete - Interface to {@link module:autocomplete}
28
+ * @property {object} recommendations - Interface to {@link module:recommendations}
29
+ * @property {object} tracker - Interface to {@link module:tracker}
30
+ * @property {object} catalog - Interface to {@link module:catalog}
30
31
  * @returns {class}
31
32
  */
32
33
  constructor(options = {}) {
@@ -49,7 +50,7 @@ class ConstructorIO {
49
50
  apiToken: apiToken || '',
50
51
  securityToken: securityToken || '',
51
52
  version: version || global.CLIENT_VERSION || `cio-node-${packageVersion}`,
52
- serviceUrl: serviceUrl || 'https://ac.cnstrc.com',
53
+ serviceUrl: (serviceUrl && serviceUrl.replace(/\/$/, '')) || 'https://ac.cnstrc.com',
53
54
  fetch,
54
55
  networkParameters: networkParameters || {},
55
56
  };
@@ -96,6 +96,7 @@ class Autocomplete {
96
96
  * Retrieve autocomplete results from API
97
97
  *
98
98
  * @function getAutocompleteResults
99
+ * @param {string} query - Term to use to perform an autocomplete search
99
100
  * @param {object} [parameters] - Additional parameters to refine result set
100
101
  * @param {number} [parameters.numResults] - The total number of results to return
101
102
  * @param {object} [parameters.filters] - Filters used to refine search
@@ -104,7 +105,7 @@ class Autocomplete {
104
105
  * @param {object} [userParameters] - Parameters relevant to the user request
105
106
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
106
107
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
107
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
108
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
108
109
  * @param {string} [userParameters.segments] - User segments
109
110
  * @param {string} [userParameters.testCells] - User test cells
110
111
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -195,7 +195,7 @@ class Browse {
195
195
  * @param {object} [userParameters] - Parameters relevant to the user request
196
196
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
197
197
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
198
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
198
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
199
199
  * @param {string} [userParameters.segments] - User segments
200
200
  * @param {string} [userParameters.testCells] - User test cells
201
201
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -272,7 +272,7 @@ class Browse {
272
272
  * @param {object} [userParameters] - Parameters relevant to the user request
273
273
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
274
274
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
275
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
275
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
276
276
  * @param {string} [userParameters.segments] - User segments
277
277
  * @param {string} [userParameters.testCells] - User test cells
278
278
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -336,7 +336,7 @@ class Browse {
336
336
  * @param {object} [userParameters] - Parameters relevant to the user request
337
337
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
338
338
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
339
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
339
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
340
340
  * @param {string} [userParameters.segments] - User segments
341
341
  * @param {string} [userParameters.testCells] - User test cells
342
342
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -393,7 +393,7 @@ class Browse {
393
393
  * @param {object} [userParameters] - Parameters relevant to the user request
394
394
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
395
395
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
396
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
396
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
397
397
  * @param {string} [userParameters.segments] - User segments
398
398
  * @param {string} [userParameters.testCells] - User test cells
399
399
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -517,7 +517,7 @@ class Catalog {
517
517
  }
518
518
 
519
519
  return helpers.throwHttpErrorFromResponse(new Error(), response);
520
- }).then(json => json);
520
+ }).then((json) => json);
521
521
  }
522
522
 
523
523
  /**
@@ -581,7 +581,7 @@ class Catalog {
581
581
  }
582
582
 
583
583
  return helpers.throwHttpErrorFromResponse(new Error(), response);
584
- }).then(json => json);
584
+ }).then((json) => json);
585
585
  }
586
586
 
587
587
  /**
@@ -712,7 +712,7 @@ class Catalog {
712
712
  }
713
713
 
714
714
  return helpers.throwHttpErrorFromResponse(new Error(), response);
715
- }).then(json => json);
715
+ }).then((json) => json);
716
716
  }
717
717
 
718
718
  /**
@@ -752,7 +752,7 @@ class Catalog {
752
752
  }
753
753
 
754
754
  return helpers.throwHttpErrorFromResponse(new Error(), response);
755
- }).then(json => json);
755
+ }).then((json) => json);
756
756
  }
757
757
 
758
758
  /**
@@ -795,7 +795,7 @@ class Catalog {
795
795
  }
796
796
 
797
797
  return helpers.throwHttpErrorFromResponse(new Error(), response);
798
- }).then(json => json);
798
+ }).then((json) => json);
799
799
  }
800
800
 
801
801
  /**
@@ -842,7 +842,7 @@ class Catalog {
842
842
  }
843
843
 
844
844
  return helpers.throwHttpErrorFromResponse(new Error(), response);
845
- }).then(json => json);
845
+ }).then((json) => json);
846
846
  }
847
847
 
848
848
  /**
@@ -879,7 +879,7 @@ class Catalog {
879
879
  }
880
880
 
881
881
  return helpers.throwHttpErrorFromResponse(new Error(), response);
882
- }).then(json => json);
882
+ }).then((json) => json);
883
883
  }
884
884
 
885
885
  /**
@@ -1013,7 +1013,7 @@ class Catalog {
1013
1013
  }
1014
1014
 
1015
1015
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1016
- }).then(json => json);
1016
+ }).then((json) => json);
1017
1017
  }
1018
1018
 
1019
1019
  /**
@@ -1071,7 +1071,7 @@ class Catalog {
1071
1071
  }
1072
1072
 
1073
1073
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1074
- }).then(json => json);
1074
+ }).then((json) => json);
1075
1075
  }
1076
1076
 
1077
1077
  /**
@@ -1197,7 +1197,7 @@ class Catalog {
1197
1197
  }
1198
1198
 
1199
1199
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1200
- }).then(json => json);
1200
+ }).then((json) => json);
1201
1201
  }
1202
1202
 
1203
1203
  /**
@@ -1281,7 +1281,7 @@ class Catalog {
1281
1281
  }
1282
1282
 
1283
1283
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1284
- }).then(json => json);
1284
+ }).then((json) => json);
1285
1285
  }
1286
1286
 
1287
1287
  /**
@@ -1338,10 +1338,9 @@ class Catalog {
1338
1338
  }
1339
1339
 
1340
1340
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1341
- }).then(json => json);
1341
+ }).then((json) => json);
1342
1342
  }
1343
1343
 
1344
-
1345
1344
  /**
1346
1345
  * Remove synonym group for supplied ID
1347
1346
  *
@@ -1464,7 +1463,7 @@ class Catalog {
1464
1463
  }
1465
1464
 
1466
1465
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1467
- }).then(json => json);
1466
+ }).then((json) => json);
1468
1467
  }
1469
1468
 
1470
1469
  /**
@@ -1514,7 +1513,7 @@ class Catalog {
1514
1513
  }
1515
1514
 
1516
1515
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1517
- }).then(json => json);
1516
+ }).then((json) => json);
1518
1517
  }
1519
1518
 
1520
1519
  /**
@@ -1564,7 +1563,7 @@ class Catalog {
1564
1563
  }
1565
1564
 
1566
1565
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1567
- }).then(json => json);
1566
+ }).then((json) => json);
1568
1567
  }
1569
1568
 
1570
1569
  /**
@@ -1603,7 +1602,7 @@ class Catalog {
1603
1602
  }
1604
1603
 
1605
1604
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1606
- }).then(json => json);
1605
+ }).then((json) => json);
1607
1606
  }
1608
1607
 
1609
1608
  /**
@@ -1670,7 +1669,7 @@ class Catalog {
1670
1669
  }
1671
1670
 
1672
1671
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1673
- }).then(json => json);
1672
+ }).then((json) => json);
1674
1673
  }
1675
1674
 
1676
1675
  /**
@@ -1709,7 +1708,7 @@ class Catalog {
1709
1708
  }
1710
1709
 
1711
1710
  return helpers.throwHttpErrorFromResponse(new Error(), response);
1712
- }).then(json => json);
1711
+ }).then((json) => json);
1713
1712
  }
1714
1713
 
1715
1714
  /**
@@ -100,7 +100,7 @@ class Recommendations {
100
100
  * @param {object} [userParameters] - Parameters relevant to the user request
101
101
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
102
102
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
103
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
103
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
104
104
  * @param {string} [userParameters.segments] - User segments
105
105
  * @param {string} [userParameters.testCells] - User test cells
106
106
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -54,7 +54,6 @@ function createSearchUrl(query, parameters, userParameters, options) {
54
54
  sortBy,
55
55
  sortOrder,
56
56
  section,
57
- collectionId,
58
57
  fmtOptions,
59
58
  hiddenFields,
60
59
  } = parameters;
@@ -89,11 +88,6 @@ function createSearchUrl(query, parameters, userParameters, options) {
89
88
  queryParams.section = section;
90
89
  }
91
90
 
92
- // Pull collection id from parameters
93
- if (collectionId) {
94
- queryParams.collection_id = collectionId;
95
- }
96
-
97
91
  // Pull format options from parameters
98
92
  if (fmtOptions) {
99
93
  queryParams.fmt_options = fmtOptions;
@@ -136,12 +130,13 @@ class Search {
136
130
  * @param {object} [parameters.filters] - Filters used to refine search
137
131
  * @param {string} [parameters.sortBy='relevance'] - The sort method for results
138
132
  * @param {string} [parameters.sortOrder='descending'] - The sort order for results
133
+ * @param {string} [parameters.section='Products'] - The section name for results
139
134
  * @param {object} [parameters.fmtOptions] - The format options used to refine result groups
140
135
  * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return
141
136
  * @param {object} [userParameters] - Parameters relevant to the user request
142
137
  * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
143
138
  * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
144
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
139
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
145
140
  * @param {string} [userParameters.segments] - User segments
146
141
  * @param {string} [userParameters.testCells] - User test cells
147
142
  * @param {string} [userParameters.userIp] - Origin user IP, from client
@@ -77,7 +77,7 @@ function applyParamsAsString(parameters, userParameters, options) {
77
77
  }
78
78
 
79
79
  // Send request to server
80
- function send(url, userParameters, networkParameters, method = 'GET', body) { // eslint-disable-line max-params
80
+ function send(url, userParameters, networkParameters, method = 'GET', body = {}) { // eslint-disable-line max-params
81
81
  let request;
82
82
  const fetch = (this.options && this.options.fetch) || nodeFetch;
83
83
  const controller = new AbortController();
@@ -190,7 +190,7 @@ class Tracker {
190
190
  * @param {object} userParameters - Parameters relevant to the user request
191
191
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
192
192
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
193
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
193
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
194
194
  * @param {string} [userParameters.segments] - User segments
195
195
  * @param {string} [userParameters.testCells] - User test cells
196
196
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -229,7 +229,7 @@ class Tracker {
229
229
  * @param {object} userParameters - Parameters relevant to the user request
230
230
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
231
231
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
232
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
232
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
233
233
  * @param {string} [userParameters.segments] - User segments
234
234
  * @param {string} [userParameters.testCells] - User test cells
235
235
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -276,7 +276,7 @@ class Tracker {
276
276
  * @param {object} userParameters - Parameters relevant to the user request
277
277
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
278
278
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
279
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
279
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
280
280
  * @param {string} [userParameters.segments] - User segments
281
281
  * @param {string} [userParameters.testCells] - User test cells
282
282
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -369,7 +369,7 @@ class Tracker {
369
369
  * @param {object} userParameters - Parameters relevant to the user request
370
370
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
371
371
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
372
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
372
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
373
373
  * @param {string} [userParameters.segments] - User segments
374
374
  * @param {string} [userParameters.testCells] - User test cells
375
375
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -440,11 +440,11 @@ class Tracker {
440
440
  * @param {string} term - Search results query term
441
441
  * @param {object} parameters - Additional parameters to be sent with request
442
442
  * @param {number} parameters.num_results - Number of search results in total
443
- * @param {array} [parameters.item_ids] - List of product item unique identifiers in search results listing
443
+ * @param {string[]} [parameters.item_ids] - List of product item unique identifiers in search results listing
444
444
  * @param {object} userParameters - Parameters relevant to the user request
445
445
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
446
446
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
447
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
447
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
448
448
  * @param {string} [userParameters.segments] - User segments
449
449
  * @param {string} [userParameters.testCells] - User test cells
450
450
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -477,6 +477,7 @@ class Tracker {
477
477
  const url = `${this.options.serviceUrl}/behavior?`;
478
478
  const queryParams = { action: 'search-results', term };
479
479
  const { num_results, customer_ids, item_ids } = parameters;
480
+ let customerIDs;
480
481
 
481
482
  if (!helpers.isNil(num_results)) {
482
483
  queryParams.num_results = num_results;
@@ -484,10 +485,15 @@ class Tracker {
484
485
 
485
486
  // Ensure support for both item_ids and customer_ids as parameters
486
487
  if (item_ids && Array.isArray(item_ids)) {
487
- queryParams.customer_ids = item_ids.join(',');
488
+ customerIDs = item_ids;
488
489
  } else if (customer_ids && Array.isArray(customer_ids)) {
489
- queryParams.customer_ids = customer_ids.join(',');
490
+ customerIDs = customer_ids;
490
491
  }
492
+
493
+ if (customerIDs && Array.isArray(customerIDs) && customerIDs.length) {
494
+ queryParams.customer_ids = customerIDs.slice(0, 100).join(',');
495
+ }
496
+
491
497
  const requestUrl = `${url}${applyParamsAsString(queryParams, userParameters, this.options)}`;
492
498
 
493
499
  send.call(
@@ -519,7 +525,7 @@ class Tracker {
519
525
  * @param {object} userParameters - Parameters relevant to the user request
520
526
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
521
527
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
522
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
528
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
523
529
  * @param {string} [userParameters.segments] - User segments
524
530
  * @param {string} [userParameters.testCells] - User test cells
525
531
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -598,10 +604,10 @@ class Tracker {
598
604
  * Send conversion event to API
599
605
  *
600
606
  * @function trackConversion
601
- * @param {string} term - Search results query term
607
+ * @param {string} [term] - Search results query term that led to conversion event
602
608
  * @param {object} parameters - Additional parameters to be sent with request
603
609
  * @param {string} parameters.item_id - Product item unique identifier
604
- * @param {string} parameters.revenue - Revenue (price) of product item
610
+ * @param {number} [parameters.revenue] - Sale price if available, otherwise the regular (retail) price of item
605
611
  * @param {string} [parameters.item_name] - Product item name
606
612
  * @param {string} [parameters.variation_id] - Product item variation unique identifier
607
613
  * @param {string} [parameters.type='add_to_cart'] - Conversion type
@@ -612,7 +618,7 @@ class Tracker {
612
618
  * @param {object} userParameters - Parameters relevant to the user request
613
619
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
614
620
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
615
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
621
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
616
622
  * @param {string} [userParameters.segments] - User segments
617
623
  * @param {string} [userParameters.testCells] - User test cells
618
624
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -624,6 +630,7 @@ class Tracker {
624
630
  * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
625
631
  * @returns {(true|Error)}
626
632
  * @description User performed an action indicating interest in an item (add to cart, add to wishlist, etc.)
633
+ * @see https://docs.constructor.io/rest_api/behavioral_logging/conversions
627
634
  * @example
628
635
  * constructorio.tracker.trackConversion(
629
636
  * 'T-Shirt',
@@ -729,14 +736,14 @@ class Tracker {
729
736
  *
730
737
  * @function trackPurchase
731
738
  * @param {object} parameters - Additional parameters to be sent with request
732
- * @param {array} parameters.items - List of product item objects
733
- * @param {number} parameters.revenue - Revenue
739
+ * @param {object[]} parameters.items - List of product item objects
740
+ * @param {number} parameters.revenue - The subtotal (excluding taxes, shipping, etc.) of the entire order
734
741
  * @param {string} [parameters.order_id] - Unique order identifier
735
742
  * @param {string} [parameters.section] - Index section
736
743
  * @param {object} userParameters - Parameters relevant to the user request
737
744
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
738
745
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
739
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
746
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
740
747
  * @param {string} [userParameters.segments] - User segments
741
748
  * @param {string} [userParameters.testCells] - User test cells
742
749
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -822,7 +829,7 @@ class Tracker {
822
829
  * @param {object} userParameters - Parameters relevant to the user request
823
830
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
824
831
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
825
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
832
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
826
833
  * @param {string} [userParameters.segments] - User segments
827
834
  * @param {string} [userParameters.testCells] - User test cells
828
835
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -931,7 +938,7 @@ class Tracker {
931
938
  * @param {object} userParameters - Parameters relevant to the user request
932
939
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
933
940
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
934
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
941
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
935
942
  * @param {string} [userParameters.segments] - User segments
936
943
  * @param {string} [userParameters.testCells] - User test cells
937
944
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -1053,14 +1060,14 @@ class Tracker {
1053
1060
  * @param {number} [parameters.result_count] - Number of results displayed
1054
1061
  * @param {number} [parameters.result_page] - Page number of results
1055
1062
  * @param {string} [parameters.result_id] - Browse result identifier (returned in response from Constructor)
1056
- * @param {string} [parameters.selected_filters] - Selected filters
1063
+ * @param {object} [parameters.selected_filters] - Selected filters
1057
1064
  * @param {string} [parameters.sort_order] - Sort order ('ascending' or 'descending')
1058
1065
  * @param {string} [parameters.sort_by] - Sorting method
1059
- * @param {array} [parameters.items] - List of product item objects
1066
+ * @param {object[]} [parameters.items] - List of product item objects
1060
1067
  * @param {object} userParameters - Parameters relevant to the user request
1061
1068
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
1062
1069
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
1063
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
1070
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
1064
1071
  * @param {string} [userParameters.segments] - User segments
1065
1072
  * @param {string} [userParameters.testCells] - User test cells
1066
1073
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -1078,7 +1085,7 @@ class Tracker {
1078
1085
  * result_count: 22,
1079
1086
  * result_page: 2,
1080
1087
  * result_id: '019927c2-f955-4020-8b8d-6b21b93cb5a2',
1081
- * selected_filters: [ 'brand', 'color' ],
1088
+ * selected_filters: { brand: ['foo'], color: ['black'] },
1082
1089
  * sort_order: 'ascending',
1083
1090
  * sort_by: 'price',
1084
1091
  * items: [{ item_id: 'KMH876' }, { item_id: 'KMH140' }],
@@ -1154,7 +1161,7 @@ class Tracker {
1154
1161
  }
1155
1162
 
1156
1163
  if (items && Array.isArray(items)) {
1157
- bodyParams.items = items;
1164
+ bodyParams.items = items.slice(0, 100);
1158
1165
  }
1159
1166
 
1160
1167
  const requestUrl = `${requestPath}${applyParamsAsString({}, userParameters, this.options)}`;
@@ -1191,11 +1198,11 @@ class Tracker {
1191
1198
  * @param {number} [parameters.result_page] - Page number of results
1192
1199
  * @param {number} [parameters.result_position_on_page] - Position of clicked item
1193
1200
  * @param {number} [parameters.num_results_per_page] - Number of results shown
1194
- * @param {string} [parameters.selected_filters] - Selected filters
1201
+ * @param {object} [parameters.selected_filters] - Selected filters
1195
1202
  * @param {object} userParameters - Parameters relevant to the user request
1196
1203
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
1197
1204
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
1198
- * @param {object} [userParameters.userId] - User ID, utilized to personalize results
1205
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
1199
1206
  * @param {string} [userParameters.segments] - User segments
1200
1207
  * @param {string} [userParameters.testCells] - User test cells
1201
1208
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -1216,7 +1223,7 @@ class Tracker {
1216
1223
  * result_page: 2,
1217
1224
  * result_position_on_page: 2,
1218
1225
  * num_results_per_page: 12,
1219
- * selected_filters: [ 'brand', 'color' ],
1226
+ * selected_filters: { brand: ['foo'], color: ['black'] },
1220
1227
  * filter_name: 'brand',
1221
1228
  * filter_value: 'XYZ',
1222
1229
  * item_id: 'KMH876',
@@ -1323,7 +1330,7 @@ class Tracker {
1323
1330
  * @param {object} [userParameters] - Parameters relevant to the user request
1324
1331
  * @param {number} userParameters.sessionId - Session ID, utilized to personalize results
1325
1332
  * @param {number} userParameters.clientId - Client ID, utilized to personalize results
1326
- * @param {object} userParameters.userId - User ID, utilized to personalize results
1333
+ * @param {string} userParameters.userId - User ID, utilized to personalize results
1327
1334
  * @param {string} [userParameters.segments] - User segments
1328
1335
  * @param {string} [userParameters.testCells] - User test cells
1329
1336
  * @param {string} [userParameters.originReferrer] - Client page URL (including path)
@@ -3,14 +3,18 @@ const qs = require('qs');
3
3
 
4
4
  const utils = {
5
5
  ourEncodeURIComponent: (str) => {
6
- if (str) {
7
- const parsedStrObj = qs.parse(`s=${str.replace(/&/g, '%26')}`);
6
+ if (str && typeof str === 'string') {
7
+ const cleanedString = str
8
+ .replace(/\[/g, '%5B') // Replace [
9
+ .replace(/\]/g, '%5D') // Replace ]
10
+ .replace(/&/g, '%26'); // Replace &
11
+ const trimmedCleanedString = cleanedString.trim();
12
+ const parsedStrObj = qs.parse(`s=${trimmedCleanedString}`);
8
13
 
9
14
  parsedStrObj.s = parsedStrObj.s.replace(/\s/g, ' ');
10
15
 
11
16
  return qs.stringify(parsedStrObj).split('=')[1];
12
17
  }
13
-
14
18
  return null;
15
19
  },
16
20
 
@@ -42,7 +46,7 @@ const utils = {
42
46
  throw error;
43
47
  }),
44
48
 
45
- isNil: value => value == null,
49
+ isNil: (value) => value == null,
46
50
 
47
51
  // Create authorization header to be transmitted with requests
48
52
  createAuthHeader: (options) => {
@@ -53,8 +57,10 @@ const utils = {
53
57
 
54
58
  // Abort network request based on supplied timeout interval (in milliseconds)
55
59
  // - method call parameter takes precedence over global options parameter
56
- applyNetworkTimeout: (options = {}, networkParameters = {}, controller) => {
57
- const timeout = options.networkParameters.timeout || networkParameters.timeout;
60
+ applyNetworkTimeout: (options = {}, networkParameters = {}, controller = undefined) => {
61
+ const optionsTimeout = options && options.networkParameters && options.networkParameters.timeout;
62
+ const networkParametersTimeout = networkParameters && networkParameters.timeout;
63
+ const timeout = optionsTimeout || networkParametersTimeout;
58
64
 
59
65
  if (typeof timeout === 'number') {
60
66
  setTimeout(() => controller.abort(), timeout);