@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 +3 -2
- package/src/modules/catalog.js +28 -10
- package/src/modules/search.js +103 -2
- package/src/types/catalog.d.ts +1 -0
- package/src/types/search.d.ts +8 -0
package/package.json
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@constructor-io/constructorio-node",
|
|
3
|
-
"version": "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
|
|
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/*",
|
package/src/modules/catalog.js
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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, '
|
|
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
|
package/src/modules/search.js
CHANGED
|
@@ -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
|
-
|
|
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;
|
package/src/types/catalog.d.ts
CHANGED
package/src/types/search.d.ts
CHANGED
|
@@ -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;
|