@constructor-io/constructorio-client-javascript 2.47.0 → 2.48.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.
@@ -17,6 +17,7 @@ var EventDispatcher = require('./utils/event-dispatcher');
17
17
  var helpers = require('./utils/helpers');
18
18
  var packageVersion = require('./version');
19
19
  var Quizzes = require('./modules/quizzes');
20
+ var Assistant = require('./modules/assistant');
20
21
 
21
22
  // Compute package version string
22
23
  var computePackageVersion = function computePackageVersion() {
@@ -40,6 +41,7 @@ var ConstructorIO = /*#__PURE__*/function () {
40
41
  * @param {string} parameters.apiKey - Constructor.io API key
41
42
  * @param {string} [parameters.serviceUrl='https://ac.cnstrc.com'] - API URL endpoint
42
43
  * @param {string} [parameters.quizzesServiceUrl='https://quizzes.cnstrc.com'] - Quizzes API URL endpoint
44
+ * @param {string} [parameters.assistantServiceUrl='https://assistant.cnstrc.com'] - AI Assistant API URL endpoint
43
45
  * @param {array} [parameters.segments] - User segments
44
46
  * @param {object} [parameters.testCells] - User test cells
45
47
  * @param {string} [parameters.clientId] - Client ID, defaults to value supplied by 'constructorio-id' module
@@ -61,6 +63,7 @@ var ConstructorIO = /*#__PURE__*/function () {
61
63
  * @property {object} recommendations - Interface to {@link module:recommendations}
62
64
  * @property {object} tracker - Interface to {@link module:tracker}
63
65
  * @property {object} quizzes - Interface to {@link module:quizzes}
66
+ * @property {object} assistant - Interface to {@link module:assistant}
64
67
  * @returns {class}
65
68
  */
66
69
  function ConstructorIO() {
@@ -70,6 +73,7 @@ var ConstructorIO = /*#__PURE__*/function () {
70
73
  versionFromOptions = options.version,
71
74
  serviceUrl = options.serviceUrl,
72
75
  quizzesServiceUrl = options.quizzesServiceUrl,
76
+ assistantServiceUrl = options.assistantServiceUrl,
73
77
  segments = options.segments,
74
78
  testCells = options.testCells,
75
79
  clientId = options.clientId,
@@ -112,6 +116,7 @@ var ConstructorIO = /*#__PURE__*/function () {
112
116
  version: versionFromOptions || versionFromGlobal || computePackageVersion(),
113
117
  serviceUrl: helpers.addHTTPSToString(normalizedServiceUrl) || 'https://ac.cnstrc.com',
114
118
  quizzesServiceUrl: quizzesServiceUrl && quizzesServiceUrl.replace(/\/$/, '') || 'https://quizzes.cnstrc.com',
119
+ assistantServiceUrl: assistantServiceUrl && assistantServiceUrl.replace(/\/$/, '') || 'https://assistant.cnstrc.com',
115
120
  sessionId: sessionId || session_id,
116
121
  clientId: clientId || client_id,
117
122
  userId: userId,
@@ -136,6 +141,7 @@ var ConstructorIO = /*#__PURE__*/function () {
136
141
  this.recommendations = new Recommendations(this.options);
137
142
  this.tracker = new Tracker(this.options);
138
143
  this.quizzes = new Quizzes(this.options);
144
+ this.assistant = new Assistant(this.options);
139
145
 
140
146
  // Dispatch initialization event
141
147
  new EventDispatcher(options.eventDispatcher).queue('instantiated', this.options);
@@ -0,0 +1,205 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
5
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
6
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
7
+ var _require = require('../utils/helpers'),
8
+ cleanParams = _require.cleanParams,
9
+ trimNonBreakingSpaces = _require.trimNonBreakingSpaces,
10
+ encodeURIComponentRFC3986 = _require.encodeURIComponentRFC3986,
11
+ stringify = _require.stringify;
12
+
13
+ // Create URL from supplied intent (term) and parameters
14
+ function createAssistantUrl(intent, parameters, options) {
15
+ var apiKey = options.apiKey,
16
+ version = options.version,
17
+ sessionId = options.sessionId,
18
+ clientId = options.clientId,
19
+ userId = options.userId,
20
+ segments = options.segments,
21
+ testCells = options.testCells,
22
+ assistantServiceUrl = options.assistantServiceUrl;
23
+ var queryParams = {
24
+ c: version
25
+ };
26
+ queryParams.key = apiKey;
27
+ queryParams.i = clientId;
28
+ queryParams.s = sessionId;
29
+
30
+ // Validate intent is provided
31
+ if (!intent || typeof intent !== 'string') {
32
+ throw new Error('intent is a required parameter of type string');
33
+ }
34
+
35
+ // Validate domain is provided
36
+ if (!parameters.domain || typeof parameters.domain !== 'string') {
37
+ throw new Error('parameters.domain is a required parameter of type string');
38
+ }
39
+
40
+ // Pull test cells from options
41
+ if (testCells) {
42
+ Object.keys(testCells).forEach(function (testCellKey) {
43
+ queryParams["ef-".concat(testCellKey)] = testCells[testCellKey];
44
+ });
45
+ }
46
+
47
+ // Pull user segments from options
48
+ if (segments && segments.length) {
49
+ queryParams.us = segments;
50
+ }
51
+
52
+ // Pull user id from options and ensure string
53
+ if (userId) {
54
+ queryParams.ui = String(userId);
55
+ }
56
+ if (parameters) {
57
+ var domain = parameters.domain,
58
+ numResultsPerPage = parameters.numResultsPerPage;
59
+
60
+ // Pull domain from parameters
61
+ if (domain) {
62
+ queryParams.domain = domain;
63
+ }
64
+
65
+ // Pull results number from parameters
66
+ if (numResultsPerPage) {
67
+ queryParams.num_results_per_page = numResultsPerPage;
68
+ }
69
+ }
70
+
71
+ // eslint-disable-next-line no-underscore-dangle
72
+ queryParams._dt = Date.now();
73
+ queryParams = cleanParams(queryParams);
74
+ var queryString = stringify(queryParams);
75
+ var cleanedQuery = intent.replace(/^\//, '|'); // For compatibility with backend API
76
+
77
+ return "".concat(assistantServiceUrl, "/v1/intent/").concat(encodeURIComponentRFC3986(trimNonBreakingSpaces(cleanedQuery)), "?").concat(queryString);
78
+ }
79
+
80
+ // Add event listeners to custom SSE that pushes data to the stream
81
+ function setupEventListeners(eventSource, controller, eventTypes) {
82
+ var addListener = function addListener(type) {
83
+ eventSource.addEventListener(type, function (event) {
84
+ var data = JSON.parse(event.data);
85
+ controller.enqueue({
86
+ type: type,
87
+ data: data
88
+ }); // Enqueue data into the stream
89
+ });
90
+ };
91
+
92
+ // Set up listeners for all event types except END
93
+ Object.values(eventTypes).forEach(function (type) {
94
+ if (type !== eventTypes.END) {
95
+ addListener(type);
96
+ }
97
+ });
98
+
99
+ // Handle the END event separately to close the stream
100
+ eventSource.addEventListener(eventTypes.END, function () {
101
+ controller.close(); // Close the stream
102
+ eventSource.close(); // Close the EventSource connection
103
+ });
104
+
105
+ // Handle errors from the EventSource
106
+ // eslint-disable-next-line no-param-reassign
107
+ eventSource.onerror = function (error) {
108
+ controller.error(error); // Pass the error to the stream
109
+ eventSource.close(); // Close the EventSource connection
110
+ };
111
+ }
112
+
113
+ /**
114
+ * Interface to assistant SSE.
115
+ *
116
+ * @module assistant
117
+ * @inner
118
+ * @returns {object}
119
+ */
120
+ var Assistant = /*#__PURE__*/function () {
121
+ function Assistant(options) {
122
+ (0, _classCallCheck2["default"])(this, Assistant);
123
+ this.options = options || {};
124
+ }
125
+ (0, _createClass2["default"])(Assistant, [{
126
+ key: "getAssistantResultsStream",
127
+ value:
128
+ /**
129
+ * Retrieve assistant results from EventStream
130
+ *
131
+ * @function getAssistantResultsStream
132
+ * @description Retrieve a stream of assistant results from Constructor.io API
133
+ * @param {string} intent - Intent to use to perform an intent based recommendations
134
+ * @param {object} [parameters] - Additional parameters to refine result set
135
+ * @param {string} [parameters.domain] - domain name e.g. swimming sports gear, groceries
136
+ * @param {number} [parameters.numResultsPerPage] - The total number of results to return
137
+ * @returns {ReadableStream} Returns a ReadableStream.
138
+ * @example
139
+ * const readableStream = constructorio.assistant.getAssistantResultsStream('I want to get shoes', {
140
+ * domain: "nike_sportswear",
141
+ * });
142
+ * const reader = readableStream.getReader();
143
+ * const { value, done } = await reader.read();
144
+ */
145
+ function getAssistantResultsStream(query, parameters) {
146
+ var eventSource;
147
+ var readableStream;
148
+ try {
149
+ var requestUrl = createAssistantUrl(query, parameters, this.options);
150
+
151
+ // Create an EventSource that connects to the Server Sent Events API
152
+ eventSource = new EventSource(requestUrl);
153
+
154
+ // Create a readable stream that data will be pushed into
155
+ readableStream = new ReadableStream({
156
+ // To be called on stream start
157
+ start: function start(controller) {
158
+ // Listen to events emitted from ASA Server Sent Events and push data to the ReadableStream
159
+ setupEventListeners(eventSource, controller, Assistant.EventTypes);
160
+ },
161
+ // To be called on stream cancelling
162
+ cancel: function cancel() {
163
+ // Close the EventSource connection when the stream is prematurely canceled
164
+ eventSource.close();
165
+ }
166
+ });
167
+ } catch (e) {
168
+ if (readableStream) {
169
+ var _readableStream;
170
+ (_readableStream = readableStream) === null || _readableStream === void 0 ? void 0 : _readableStream.cancel();
171
+ } else {
172
+ var _eventSource;
173
+ // If the stream was not successfully created, close the EventSource directly
174
+ (_eventSource = eventSource) === null || _eventSource === void 0 ? void 0 : _eventSource.close();
175
+ }
176
+ throw new Error(e.message);
177
+ }
178
+ return readableStream;
179
+ }
180
+ }]);
181
+ return Assistant;
182
+ }();
183
+ (0, _defineProperty2["default"])(Assistant, "EventTypes", {
184
+ START: 'start',
185
+ // Denotes the start of the stream
186
+ GROUP: 'group',
187
+ // Represents a semantic grouping of search results, optionally having textual explanation
188
+ SEARCH_RESULT: 'search_result',
189
+ // Represents a set of results with metadata (used to show results with search refinements)
190
+ ARTICLE_REFERENCE: 'article_reference',
191
+ // Represents a set of content with metadata
192
+ RECIPE_INFO: 'recipe_info',
193
+ // Represents recipes' auxiliary information like cooking times & serving sizes
194
+ RECIPE_INSTRUCTIONS: 'recipe_instructions',
195
+ // Represents recipe instructions
196
+ SERVER_ERROR: 'server_error',
197
+ // Server Error event
198
+ IMAGE_META: 'image_meta',
199
+ // This event type is used for enhancing recommendations with media content such as images
200
+ END: 'end' // Represents the end of data stream
201
+ });
202
+
203
+ module.exports = Assistant;
204
+ module.exports.createAssistantUrl = createAssistantUrl;
205
+ module.exports.setupEventListeners = setupEventListeners;
@@ -0,0 +1,22 @@
1
+ import {
2
+ ConstructorClientOptions,
3
+ } from '.';
4
+
5
+ export default Assistant;
6
+
7
+ export interface IAssistantParameters {
8
+ domain: string;
9
+ numResultsPerPage?: number;
10
+ filters?: Record<string, any>;
11
+ }
12
+
13
+ declare class Assistant {
14
+ constructor(options: ConstructorClientOptions);
15
+
16
+ options: ConstructorClientOptions;
17
+
18
+ getAssistantResultsStream(
19
+ intent: string,
20
+ parameters?: IAssistantParameters,
21
+ ): ReadableStream;
22
+ }
@@ -3,6 +3,7 @@ import Browse from './browse';
3
3
  import Autocomplete from './autocomplete';
4
4
  import Recommendations from './recommendations';
5
5
  import Quizzes from './quizzes';
6
+ import Assistant from './assistant';
6
7
  import Tracker from './tracker';
7
8
  import { ConstructorClientOptions } from '.';
8
9
 
@@ -23,11 +24,13 @@ declare class ConstructorIO {
23
24
 
24
25
  quizzes: Quizzes;
25
26
 
27
+ assistant: Assistant;
28
+
26
29
  tracker: Tracker;
27
30
 
28
31
  setClientOptions(options: ConstructorClientOptions): void;
29
32
  }
30
33
 
31
34
  declare namespace ConstructorIO {
32
- export { Search, Browse, Autocomplete, Recommendations, Quizzes, Tracker };
35
+ export { Search, Browse, Autocomplete, Recommendations, Quizzes, Tracker, Assistant };
33
36
  }
@@ -41,6 +41,8 @@ export interface ConstructorClientOptions {
41
41
  apiKey: string;
42
42
  version?: string;
43
43
  serviceUrl?: string;
44
+ quizzesServiceUrl?: string;
45
+ assistantServiceUrl?: string,
44
46
  sessionId?: number;
45
47
  clientId?: string;
46
48
  userId?: string;
package/lib/version.js CHANGED
@@ -4,5 +4,5 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports["default"] = void 0;
7
- var _default = '2.46.0';
7
+ var _default = '2.48.0';
8
8
  exports["default"] = _default;
package/package.json CHANGED
@@ -1,13 +1,12 @@
1
1
  {
2
2
  "name": "@constructor-io/constructorio-client-javascript",
3
- "version": "2.47.0",
3
+ "version": "2.48.0",
4
4
  "description": "Constructor.io JavaScript client",
5
5
  "main": "lib/constructorio.js",
6
6
  "types": "lib/types/index.d.ts",
7
7
  "scripts": {
8
8
  "clean": "sudo rm -rf node_modules package-lock.json",
9
- "preversion": "node ./src/generateVersion.js",
10
- "version": "npm run verify-node-version && npm run docs && git add ./docs/* && npm run bundle && git add -A ./dist && git add ./src/version.js",
9
+ "version": "node ./src/generateVersion.js && npm run verify-node-version && npm run docs && git add ./docs/* && npm run bundle && git add -A ./dist && git add ./src/version.js",
11
10
  "check-license": "license-checker --production --onlyAllow 'Apache-2.0;BSD-3-Clause;MIT;0BSD;BSD-2-Clause'",
12
11
  "verify-node-version": "chmod +x ./scripts/verify-node-version.sh && ./scripts/verify-node-version.sh",
13
12
  "lint": "eslint 'src/**/*.js' 'spec/**/*.js' 'src/**/*.d.ts'",
@@ -59,6 +58,7 @@
59
58
  "eslint": "^8.17.0",
60
59
  "eslint-config-airbnb-base": "^15.0.0",
61
60
  "eslint-plugin-import": "^2.25.2",
61
+ "eventsource": "^2.0.2",
62
62
  "husky": "^7.0.4",
63
63
  "jsdoc": "^4.0.2",
64
64
  "jsdom": "^16.7.0",
@@ -69,7 +69,8 @@
69
69
  "qs": "^6.11.0",
70
70
  "sinon": "^7.5.0",
71
71
  "sinon-chai": "^3.7.0",
72
- "tsd": "^0.24.1"
72
+ "tsd": "^0.24.1",
73
+ "web-streams-polyfill": "^4.0.0"
73
74
  },
74
75
  "dependencies": {
75
76
  "@constructor-io/constructorio-id": "^2.4.17",