@nlxai/core 1.2.3-alpha.2 → 1.2.3

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/lib/index.cjs CHANGED
@@ -6,7 +6,7 @@ var ReconnectingWebSocket = require('reconnecting-websocket');
6
6
  var uuid = require('uuid');
7
7
 
8
8
  var name = "@nlxai/core";
9
- var version$1 = "1.2.3-alpha.2";
9
+ var version$1 = "1.2.3";
10
10
  var description = "Low-level SDK for building NLX experiences";
11
11
  var type = "module";
12
12
  var main = "lib/index.cjs";
@@ -22,40 +22,40 @@ var exports$1 = {
22
22
  };
23
23
  var scripts = {
24
24
  build: "rm -rf lib && rollup -c --configPlugin typescript --configImportAttributesKey with",
25
- docs: "rm -rf docs/ && typedoc && concat-md --decrease-title-levels --dir-name-as-title docs/ > docs/index.md",
26
25
  "lint:check": "eslint src/ --ext .ts,.tsx,.js,.jsx --max-warnings 0",
27
26
  lint: "eslint src/ --ext .ts,.tsx,.js,.jsx --fix",
28
27
  prepublish: "npm run build",
29
- "preview-docs": "npm run docs && comrak --unsafe --gfm -o docs/index.html docs/index.md && open docs/index.html",
30
- "publish-docs": "npm run docs && mv docs/index.md ../website/src/content/headless-api-reference.md",
31
28
  test: "typedoc --emit none",
32
- tsc: "tsc"
29
+ tsc: "tsc",
30
+ "update-readme:docs": "rm -rf docs/ && typedoc",
31
+ "update-readme:merge": "../../scripts/transclude-markdown.js",
32
+ "update-readme": "npm run update-readme:docs && npm run update-readme:merge"
33
33
  };
34
34
  var author = "Peter Szerzo <peter@nlx.ai>";
35
35
  var license = "MIT";
36
36
  var devDependencies = {
37
- "@types/isomorphic-fetch": "^0.0.36",
38
- "@types/node": "^22.10.1",
39
- "@types/ramda": "0.29.1",
37
+ "@types/isomorphic-fetch": "^0.0.39",
38
+ "@types/node": "^24.10.1",
39
+ "@types/ramda": "0.31.1",
40
40
  "@types/uuid": "^9.0.7",
41
41
  "concat-md": "^0.5.1",
42
42
  "eslint-config-nlx": "*",
43
43
  prettier: "^3.1.0",
44
44
  "rollup-config-nlx": "*",
45
- typedoc: "^0.25.13",
46
- "typedoc-plugin-markdown": "^3.17.1",
45
+ typedoc: "^0.28.14",
46
+ "typedoc-plugin-markdown": "^4.9.0",
47
47
  typescript: "^5.5.4"
48
48
  };
49
49
  var dependencies = {
50
50
  "isomorphic-fetch": "^3.0.0",
51
- ramda: "^0.29.1",
51
+ ramda: "^0.32.0",
52
52
  "reconnecting-websocket": "^4.4.0",
53
53
  uuid: "^9.0.1"
54
54
  };
55
55
  var publishConfig = {
56
56
  access: "public"
57
57
  };
58
- var gitHead = "7b3f2bffccf925bf674d8fef42af177dc17c367c";
58
+ var gitHead = "3902161e95745dd4a9cfb68bb469755a62b421f5";
59
59
  var packageJson = {
60
60
  name: name,
61
61
  version: version$1,
@@ -127,18 +127,6 @@ const safeJsonParse = (val) => {
127
127
  return null;
128
128
  }
129
129
  };
130
- /**
131
- * Helper method to decide when a new {@link Config} requires creating a new {@link ConversationHandler} or whether the old `Config`'s
132
- * `ConversationHandler` can be used.
133
- *
134
- * The order of configs doesn't matter.
135
- * @param config1 -
136
- * @param config2 -
137
- * @returns true if `createConversation` should be called again
138
- */
139
- const shouldReinitialize = (config1, config2) => {
140
- return !ramda.equals(config1, config2);
141
- };
142
130
  const getBaseDomain = (url) => url.match(/(bots\.dev\.studio\.nlx\.ai|bots\.studio\.nlx\.ai|apps\.nlx\.ai|dev\.apps\.nlx\.ai)/g)?.[0] ?? "apps.nlx.ai";
143
131
  /**
144
132
  * When a HTTP URL is provided, deduce the websocket URL. Otherwise, return the argument.
@@ -175,41 +163,45 @@ const normalizeToHttp = (applicationUrl) => {
175
163
  const isWebsocketUrl = (url) => {
176
164
  return url.indexOf("wss://") === 0;
177
165
  };
178
- /**
179
- * Check whether a configuration is value.
180
- * @param config - Chat configuration
181
- * @returns isValid - Whether the configuration is valid
182
- */
183
- const isConfigValid = (config) => {
184
- const applicationUrl = config.applicationUrl ?? "";
185
- return applicationUrl.length > 0;
186
- };
187
166
  /**
188
167
  * Call this to create a conversation handler.
189
- * @param config -
168
+ * @param configuration - The necessary configuration to create the conversation.
190
169
  * @returns The {@link ConversationHandler} is a bundle of functions to interact with the conversation.
170
+ * @example
171
+ * ```typescript
172
+ * import { createConversation } from "@nlx/core";
173
+ *
174
+ * const conversation = createConversation({
175
+ * applicationUrl: "https://apps.nlx.ai/c/cfab3-243ad-232dc",
176
+ * headers: {
177
+ * "nlx-api-key": "4393029032-dwsd",
178
+ * },
179
+ * userId: "abcd-1234",
180
+ * languageCode: "en-US",
181
+ * });
182
+ * ```
191
183
  */
192
- function createConversation(config) {
184
+ function createConversation(configuration) {
193
185
  let socket;
194
186
  let socketMessageQueue = [];
195
187
  let socketMessageQueueCheckInterval = null;
196
188
  let voicePlusSocket;
197
189
  let voicePlusSocketMessageQueue = [];
198
190
  let voicePlusSocketMessageQueueCheckInterval = null;
199
- const applicationUrl = config.applicationUrl ?? "";
191
+ const applicationUrl = configuration.applicationUrl ?? "";
200
192
  // Check if the application URL has a language code appended to it
201
193
  if (/[-|_][a-z]{2,}[-|_][A-Z]{2,}$/.test(applicationUrl)) {
202
194
  Console.warn("Since v1.0.0, the language code is no longer added at the end of the application URL. Please remove the modifier (e.g. '-en-US') from the URL, and specify it in the `languageCode` parameter instead.");
203
195
  }
204
196
  const eventListeners = { voicePlusCommand: [] };
205
- const initialConversationId = config.conversationId ?? uuid.v4();
197
+ const initialConversationId = configuration.conversationId ?? uuid.v4();
206
198
  let state = {
207
- responses: config.responses ?? [],
208
- languageCode: config.languageCode,
209
- userId: config.userId,
199
+ responses: configuration.responses ?? [],
200
+ languageCode: configuration.languageCode,
201
+ userId: configuration.userId,
210
202
  conversationId: initialConversationId,
211
203
  };
212
- const fullApplicationHttpUrl = () => `${normalizeToHttp(applicationUrl)}${config.experimental?.completeApplicationUrl === true
204
+ const fullApplicationHttpUrl = () => `${normalizeToHttp(applicationUrl)}${configuration.experimental?.completeApplicationUrl === true
213
205
  ? ""
214
206
  : `-${state.languageCode}`}`;
215
207
  const setState = (change,
@@ -228,7 +220,7 @@ function createConversation(config) {
228
220
  type: exports.ResponseType.Failure,
229
221
  receivedAt: new Date().getTime(),
230
222
  payload: {
231
- text: config.failureMessage ?? defaultFailureMessage,
223
+ text: configuration.failureMessage ?? defaultFailureMessage,
232
224
  },
233
225
  };
234
226
  setState({
@@ -300,8 +292,8 @@ function createConversation(config) {
300
292
  conversationId: state.conversationId,
301
293
  ...body,
302
294
  languageCode: state.languageCode,
303
- channelType: config.experimental?.channelType,
304
- environment: config.environment,
295
+ channelType: configuration.experimental?.channelType,
296
+ environment: configuration.environment,
305
297
  };
306
298
  if (isWebsocketUrl(applicationUrl)) {
307
299
  if (socket?.readyState === 1) {
@@ -316,7 +308,7 @@ function createConversation(config) {
316
308
  const res = await fetch(fullApplicationHttpUrl(), {
317
309
  method: "POST",
318
310
  headers: {
319
- ...(config.headers ?? {}),
311
+ ...(configuration.headers ?? {}),
320
312
  Accept: "application/json",
321
313
  "Content-Type": "application/json",
322
314
  "nlx-sdk-version": packageJson.version,
@@ -353,7 +345,7 @@ function createConversation(config) {
353
345
  // If the socket is already set up, tear it down first
354
346
  teardownWebsocket();
355
347
  const url = new URL(applicationUrl);
356
- if (config.experimental?.completeApplicationUrl !== true) {
348
+ if (configuration.experimental?.completeApplicationUrl !== true) {
357
349
  url.searchParams.set("languageCode", state.languageCode);
358
350
  url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
359
351
  }
@@ -386,17 +378,17 @@ function createConversation(config) {
386
378
  const setupCommandWebsocket = () => {
387
379
  // If the socket is already set up, tear it down first
388
380
  teardownCommandWebsocket();
389
- if (config.bidirectional !== true) {
381
+ if (configuration.bidirectional !== true) {
390
382
  return;
391
383
  }
392
384
  const url = new URL(normalizeToWebsocket(applicationUrl));
393
- if (config.experimental?.completeApplicationUrl !== true) {
385
+ if (configuration.experimental?.completeApplicationUrl !== true) {
394
386
  url.searchParams.set("languageCode", state.languageCode);
395
387
  url.searchParams.set("channelKey", `${url.searchParams.get("channelKey") ?? ""}-${state.languageCode}`);
396
388
  }
397
389
  url.searchParams.set("conversationId", state.conversationId);
398
390
  url.searchParams.set("type", "voice-plus");
399
- const apiKey = config.headers["nlx-api-key"];
391
+ const apiKey = configuration.headers["nlx-api-key"];
400
392
  if (!isWebsocketUrl(applicationUrl) && apiKey != null) {
401
393
  url.searchParams.set("apiKey", apiKey);
402
394
  }
@@ -540,7 +532,7 @@ function createConversation(config) {
540
532
  const res = await fetch(`${fullApplicationHttpUrl()}/context`, {
541
533
  method: "POST",
542
534
  headers: {
543
- ...(config.headers ?? {}),
535
+ ...(configuration.headers ?? {}),
544
536
  Accept: "application/json",
545
537
  "Content-Type": "application/json",
546
538
  "nlx-conversation-id": state.conversationId,
@@ -621,7 +613,7 @@ function createConversation(config) {
621
613
  const res = await fetch(`${url}-${state.languageCode}/requestToken`, {
622
614
  method: "POST",
623
615
  headers: {
624
- ...(config.headers ?? {}),
616
+ ...(configuration.headers ?? {}),
625
617
  Accept: "application/json",
626
618
  "Content-Type": "application/json",
627
619
  "nlx-conversation-id": state.conversationId,
@@ -682,9 +674,52 @@ function createConversation(config) {
682
674
  };
683
675
  }
684
676
  /**
685
- * Get current expiration timestamp from the current list of reponses
686
- * @param responses - the current list of user and application responses (first argument in the subscribe callback)
687
- * @returns an expiration timestamp in Unix Epoch (`new Date().getTime()`), or `null` if this is not known (typically occurs if the application has not responded yet)
677
+ * Check whether a configuration is valid.
678
+ * @param configuration - Conversation configuration
679
+ * @returns Whether the configuration is valid?
680
+ */
681
+ const isConfigValid = (configuration) => {
682
+ const applicationUrl = configuration.applicationUrl ?? "";
683
+ return applicationUrl.length > 0;
684
+ };
685
+ /**
686
+ * Helper method to decide when a new {@link Config} requires creating a new {@link ConversationHandler} or whether the old `Config`'s
687
+ * `ConversationHandler` can be used.
688
+ *
689
+ * The order of configs doesn't matter.
690
+ * @param config1 -
691
+ * @param config2 -
692
+ * @returns true if `createConversation` should be called again
693
+ */
694
+ const shouldReinitialize = (config1, config2) => {
695
+ return !ramda.equals(config1, config2);
696
+ };
697
+ /**
698
+ * Get current expiration timestamp from a list of responses. Can be used to determine if a conversation has timed out.
699
+ * @example
700
+ * ```typescript
701
+ * import { useState } from "react";
702
+ * import { getCurrentExpirationTimestamp } from "@nlxai/core";
703
+ *
704
+ * const [isTimedOut, setIsTimedOut] = useState(false);
705
+ *
706
+ * conversation.subscribe((responses) => {
707
+ * const expirationTimestamp = getCurrentExpirationTimestamp(responses);
708
+ * if (expirationTimestamp != null && expirationTimestamp < new Date().getTime()) {
709
+ * setIsTimedOut(true);
710
+ * }
711
+ * });
712
+ *
713
+ * return (<div>
714
+ * {isTimedOut ? (
715
+ * <p>Your session has timed out. Please start a new conversation.</p>
716
+ * ) : (
717
+ * <p>Your session is active.</p>
718
+ * )}
719
+ * </div>
720
+ * ```
721
+ * @param responses - The current list of user and application responses (first argument in the subscribe callback)
722
+ * @returns An expiration timestamp in Unix Epoch (`new Date().getTime()`), or `null` if this is not known (typically occurs if the application has not responded yet)
688
723
  */
689
724
  const getCurrentExpirationTimestamp = (responses) => {
690
725
  let expirationTimestamp = null;
@@ -712,7 +747,7 @@ const getCurrentExpirationTimestamp = (responses) => {
712
747
  * console.log(response);
713
748
  * });
714
749
  * ```
715
- * @typeParam T - the type of the function's params, e.g. for `sendText` it's `text: string, context?: Context`
750
+ * @typeParam Params - the type of the function's params, e.g. for `sendText` it's `text: string, context?: Context`
716
751
  * @param fn - the function to wrap (e.g. `convo.sendText`, `convo.sendChoice`, etc.)
717
752
  * @param convo - the `ConversationHandler` (from {@link createConversation})
718
753
  * @param timeout - the timeout in milliseconds