@constructor-io/constructorio-node 4.4.4 → 4.4.7

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/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-node",
3
- "version": "4.4.4",
3
+ "version": "4.4.7",
4
4
  "description": "Constructor.io Node.js client",
5
5
  "main": "src/constructorio.js",
6
6
  "types": "src/types/constructorio.d.ts",
7
7
  "scripts": {
8
- "version": "chmod +x ./scripts/verify-node-version.sh && ./scripts/verify-node-version.sh && npm run docs && git add ./docs/*",
8
+ "verify-node-version": "chmod +x ./scripts/verify-node-version.sh && ./scripts/verify-node-version.sh",
9
+ "version": "npm run verify-node-version && npm run docs && git add ./docs/*",
9
10
  "check-lisc": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT'",
10
11
  "lint": "eslint 'src/**/*.js' 'spec/**/*.js' 'src/**/*.d.ts'",
11
12
  "test:parallel": "mkdir -p test && cp -rf src/* test && mocha --parallel ./spec/*",
@@ -55,7 +55,7 @@ async function createQueryParamsAndFormData(parameters) {
55
55
  const formData = new FormData();
56
56
 
57
57
  if (parameters) {
58
- const { section, notificationEmail, force } = parameters;
58
+ const { section, notificationEmail, force, onMissing } = parameters;
59
59
  let { items, variations, item_groups: itemGroups } = parameters;
60
60
 
61
61
  try {
@@ -92,6 +92,16 @@ async function createQueryParamsAndFormData(parameters) {
92
92
  queryParams.force = force;
93
93
  }
94
94
 
95
+ // Pull onMissing from parameters
96
+ if (onMissing) {
97
+ // Validate onMissing parameter
98
+ if (onMissing && !['FAIL', 'IGNORE', 'CREATE'].includes(onMissing)) {
99
+ throw new Error('onMissing must be one of FAIL, IGNORE, or CREATE');
100
+ }
101
+
102
+ queryParams.on_missing = onMissing;
103
+ }
104
+
95
105
  // Pull items from parameters
96
106
  if (items) {
97
107
  formData.append('items', items, {
@@ -119,9 +129,15 @@ async function createQueryParamsAndFormData(parameters) {
119
129
 
120
130
  async function addTarArchiveToFormData(parameters, formData, operation, apiKey) {
121
131
  try {
122
- const { section } = parameters;
132
+ const { section, onMissing } = parameters;
133
+ const onMissingParameter = onMissing && onMissing !== 'FAIL' ? onMissing.toLowerCase() : '';
123
134
  let { tarArchive } = parameters;
124
135
 
136
+ // Validate onMissing parameter
137
+ if (onMissing && !['FAIL', 'IGNORE', 'CREATE'].includes(onMissing)) {
138
+ throw new Error('onMissing must be one of FAIL, IGNORE, or CREATE');
139
+ }
140
+
125
141
  // Convert tarArchive to buffer if passed as stream
126
142
  if (tarArchive instanceof fs.ReadStream || tarArchive instanceof Duplex) {
127
143
  tarArchive = await convertToBuffer(tarArchive);
@@ -135,7 +151,7 @@ async function addTarArchiveToFormData(parameters, formData, operation, apiKey)
135
151
  .replace('T', '-')
136
152
  .replace(/:/g, '-')
137
153
  .slice(0, 19);
138
- const filename = `${apiKey}_${section}_${operation}_${formattedDateTime}.tar.gz`;
154
+ const filename = `${apiKey}_${section}_${operation}${onMissingParameter}_${formattedDateTime}.tar.gz`;
139
155
 
140
156
  formData.append(filename, tarArchive, {
141
157
  filename,
@@ -2087,7 +2103,7 @@ class Catalog {
2087
2103
  * @function replaceCatalog
2088
2104
  * @param {object} parameters - Additional parameters for catalog details
2089
2105
  * @param {string} parameters.section - The section to update
2090
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2106
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2091
2107
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2092
2108
  * @param {file} [parameters.items] - The CSV file with all new items
2093
2109
  * @param {file} [parameters.variations] - The CSV file with all new variations
@@ -2139,7 +2155,7 @@ class Catalog {
2139
2155
  * @function updateCatalog
2140
2156
  * @param {object} parameters - Additional parameters for catalog details
2141
2157
  * @param {string} parameters.section - The section to update
2142
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2158
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2143
2159
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2144
2160
  * @param {file} [parameters.items] - The CSV file with all new items
2145
2161
  * @param {file} [parameters.variations] - The CSV file with all new variations
@@ -2191,8 +2207,9 @@ class Catalog {
2191
2207
  * @function patchCatalog
2192
2208
  * @param {object} parameters - Additional parameters for catalog details
2193
2209
  * @param {string} parameters.section - The section to update
2194
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2210
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2195
2211
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2212
+ * @param {string} [parameters.onMissing] - Defines the strategy for handling items which are present in the file and missing in the system. IGNORE silently prevents adding them to the system, CREATE creates them, FAIL fails the ingestion in case of their presence. Defaults to FAIL
2196
2213
  * @param {file} [parameters.items] - The CSV file with all new items
2197
2214
  * @param {file} [parameters.variations] - The CSV file with all new variations
2198
2215
  * @param {file} [parameters.item_groups] - The CSV file with all new item_groups
@@ -2243,7 +2260,7 @@ class Catalog {
2243
2260
  * @function replaceCatalogUsingTarArchive
2244
2261
  * @param {object} parameters - Additional parameters for catalog details
2245
2262
  * @param {string} parameters.section - The section to update
2246
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2263
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2247
2264
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2248
2265
  * @param {file} [parameters.tarArchive] - The tar file that includes csv files
2249
2266
  * @param {object} [networkParameters] - Parameters relevant to the network request
@@ -2292,7 +2309,7 @@ class Catalog {
2292
2309
  * @function updateCatalogUsingTarArchive
2293
2310
  * @param {object} parameters - Additional parameters for catalog details
2294
2311
  * @param {string} parameters.section - The section to update
2295
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2312
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2296
2313
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2297
2314
  * @param {file} [parameters.tarArchive] - The tar file that includes csv files
2298
2315
  * @param {object} [networkParameters] - Parameters relevant to the network request
@@ -2342,8 +2359,9 @@ class Catalog {
2342
2359
  * @function patchCatalogUsingTarArchive
2343
2360
  * @param {object} parameters - Additional parameters for catalog details
2344
2361
  * @param {string} parameters.section - The section to update
2345
- * @param {string} [parameters.notification_email] - An email address to receive an email notification if the task fails
2362
+ * @param {string} [parameters.notificationEmail] - An email address to receive an email notification if the task fails
2346
2363
  * @param {boolean} [parameters.force=false] - Process the catalog even if it will invalidate a large number of existing items
2364
+ * @param {string} [parameters.onMissing] - Defines the strategy for handling items which are present in the file and missing in the system. IGNORE silently prevents adding them to the system, CREATE creates them, FAIL fails the ingestion in case of their presence. Defaults to FAIL
2347
2365
  * @param {file} [parameters.tarArchive] - The tar file that includes csv files
2348
2366
  * @param {object} [networkParameters] - Parameters relevant to the network request
2349
2367
  * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
@@ -2363,7 +2381,7 @@ class Catalog {
2363
2381
  const controller = new AbortController();
2364
2382
  const { signal } = controller;
2365
2383
  const { queryParams, formData } = await createQueryParamsAndFormData(parameters);
2366
- const formDataWithTarArchive = await addTarArchiveToFormData(parameters, formData, 'delta', apiKey);
2384
+ const formDataWithTarArchive = await addTarArchiveToFormData(parameters, formData, 'patchdelta', apiKey);
2367
2385
  const requestUrl = createCatalogUrl('catalog', this.options, { ...queryParams, patch_delta: true });
2368
2386
 
2369
2387
  // Handle network timeout if specified
@@ -6,7 +6,7 @@ const helpers = require('../utils/helpers');
6
6
 
7
7
  // Create URL from supplied query (term) and parameters
8
8
  // eslint-disable-next-line complexity
9
- function createSearchUrl(query, parameters, userParameters, options) {
9
+ function createSearchUrl(query, parameters, userParameters, options, isVoiceSearch = false) {
10
10
  const {
11
11
  apiKey,
12
12
  version,
@@ -137,7 +137,9 @@ function createSearchUrl(query, parameters, userParameters, options) {
137
137
 
138
138
  const queryString = qs.stringify(queryParams, { indices: false });
139
139
 
140
- return `${serviceUrl}/search/${helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(query))}?${queryString}`;
140
+ const searchUrl = isVoiceSearch ? 'search/natural_language' : 'search';
141
+
142
+ return `${serviceUrl}/${searchUrl}/${helpers.encodeURIComponentRFC3986(helpers.trimNonBreakingSpaces(query))}?${queryString}`;
141
143
  }
142
144
 
143
145
  /**
@@ -255,6 +257,105 @@ class Search {
255
257
  throw new Error('getSearchResults response data is malformed');
256
258
  });
257
259
  }
260
+
261
+ /**
262
+ * Retrieve voice search results from API
263
+ *
264
+ * @function getVoiceSearchResults
265
+ * @param {string} query - Term to use to perform a voice search
266
+ * @param {object} [parameters] - Additional parameters to refine result set
267
+ * @param {number} [parameters.page] - The page number of the results. Can't be used together with 'offset'
268
+ * @param {number} [parameters.offset] - The number of results to skip from the beginning. Can't be used together with 'page'
269
+ * @param {number} [parameters.resultsPerPage] - The number of results per page to return
270
+ * @param {string} [parameters.section='Products'] - The section name for results
271
+ * @param {object} [parameters.fmtOptions] - The format options used to refine result groups
272
+ * @param {string[]} [parameters.hiddenFields] - Hidden metadata fields to return
273
+ * @param {string[]} [parameters.hiddenFacets] - Hidden facet fields to return
274
+ * @param {object} [parameters.variationsMap] - The variations map object to aggregate variations. Please refer to https://docs.constructor.io/rest_api/variations_mapping for details
275
+ * @param {object} [parameters.preFilterExpression] - Faceting expression to scope search results. Please refer to https://docs.constructor.io/rest_api/collections/#add-items-dynamically for details
276
+ * @param {object} [userParameters] - Parameters relevant to the user request
277
+ * @param {number} [userParameters.sessionId] - Session ID, utilized to personalize results
278
+ * @param {number} [userParameters.clientId] - Client ID, utilized to personalize results
279
+ * @param {string} [userParameters.userId] - User ID, utilized to personalize results
280
+ * @param {string} [userParameters.segments] - User segments
281
+ * @param {object} [userParameters.testCells] - User test cells
282
+ * @param {string} [userParameters.userIp] - Origin user IP, from client
283
+ * @param {string} [userParameters.userAgent] - Origin user agent, from client
284
+ * @param {object} [networkParameters] - Parameters relevant to the network request
285
+ * @param {number} [networkParameters.timeout] - Request timeout (in milliseconds)
286
+ * @returns {Promise}
287
+ * @see https://docs.constructor.io/rest_api/search/natural_language_search/
288
+ * @example
289
+ * constructorio.search.getVoiceSearchResults('show me lipstick', {
290
+ * resultsPerPage: 40,
291
+ * }, {
292
+ * testCells: {
293
+ * testName: 'cellName',
294
+ * },
295
+ * });
296
+ */
297
+
298
+ getVoiceSearchResults(query, parameters = {}, userParameters = {}, networkParameters = {}) {
299
+ let requestUrl;
300
+ const { fetch } = this.options;
301
+ const controller = new AbortController();
302
+ const { signal } = controller;
303
+ const headers = {};
304
+
305
+ try {
306
+ const isVoiceSearch = true;
307
+ requestUrl = createSearchUrl(query, parameters, userParameters, this.options, isVoiceSearch);
308
+ } catch (e) {
309
+ return Promise.reject(e);
310
+ }
311
+
312
+ Object.assign(headers, helpers.combineCustomHeaders(this.options, networkParameters));
313
+
314
+ // Append security token as 'x-cnstrc-token' if available
315
+ if (this.options.securityToken && typeof this.options.securityToken === 'string') {
316
+ headers['x-cnstrc-token'] = this.options.securityToken;
317
+ }
318
+
319
+ // Append user IP as 'X-Forwarded-For' if available
320
+ if (userParameters.userIp && typeof userParameters.userIp === 'string') {
321
+ headers['X-Forwarded-For'] = userParameters.userIp;
322
+ }
323
+
324
+ // Append user agent as 'User-Agent' if available
325
+ if (userParameters.userAgent && typeof userParameters.userAgent === 'string') {
326
+ headers['User-Agent'] = userParameters.userAgent;
327
+ }
328
+
329
+ // Handle network timeout if specified
330
+ helpers.applyNetworkTimeout(this.options, networkParameters, controller);
331
+
332
+ return fetch(requestUrl, { headers, signal }).then((response) => {
333
+ if (response.ok) {
334
+ return response.json();
335
+ }
336
+
337
+ return helpers.throwHttpErrorFromResponse(new Error(), response);
338
+ }).then((json) => {
339
+ // Search results
340
+ if (json.response && json.response.results) {
341
+ if (json.result_id) {
342
+ json.response.results.forEach((result) => {
343
+ // eslint-disable-next-line no-param-reassign
344
+ result.result_id = json.result_id;
345
+ });
346
+ }
347
+
348
+ return json;
349
+ }
350
+
351
+ // Redirect rules
352
+ if (json.response && json.response.redirect) {
353
+ return json;
354
+ }
355
+
356
+ throw new Error('getVoiceSearchResults response data is malformed');
357
+ });
358
+ }
258
359
  }
259
360
 
260
361
  module.exports = Search;
@@ -364,6 +364,7 @@ declare class Catalog {
364
364
  section: string;
365
365
  notification_email?: string;
366
366
  force?: boolean;
367
+ onMissing?: 'IGNORE' | 'CREATE' | 'FAIL';
367
368
  items?: File;
368
369
  variations?: File;
369
370
  item_groups?: File;
@@ -40,6 +40,13 @@ declare class Search {
40
40
  userParameters?: UserParameters,
41
41
  networkParameters?: NetworkParameters
42
42
  ): Promise<SearchResponse>;
43
+
44
+ getVoiceSearchResults(
45
+ query: string,
46
+ parameters?: Omit<SearchParameters, 'filters' | 'sortBy' | 'sortOrder'>,
47
+ userParameters?: UserParameters,
48
+ networkParameters?: NetworkParameters
49
+ ): Promise<SearchResponse>;
43
50
  }
44
51
 
45
52
  /* search results returned from server */
@@ -66,6 +73,7 @@ export interface SearchRequestType extends Record<string, any> {
66
73
  section: string;
67
74
  blacklist_rules: boolean;
68
75
  term: string;
76
+ original_query?: string;
69
77
  fmt_options: Partial<FmtOption>;
70
78
  sort_by: string;
71
79
  sort_order: string;