ss-support-widget 1.0.8 → 1.0.10

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/index.html CHANGED
@@ -1,19 +1,17 @@
1
1
  <!doctype html>
2
2
  <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <title>Widget test</title>
6
- </head>
7
- <body style="height: 100vh;">
8
- <div style="height: 600px;">test</div>
9
- <div style="height: 600px;">test</div>
10
- <script>
11
- window.ChatBotConfig = {
12
- clientId: "694802ab424bd274310d61d8",
13
- apiBaseUrl: "https://ai-chatbots-api.azurewebsites.net/",
14
- };
15
- </script>
16
- <script type="module" src="/src/element.tsx"></script>
17
- <!-- <script src="https://cdn.jsdelivr.net/npm/ss-support-widget@1.0.4/dist/chat-bot-widget.js"></script> -->
18
- </body>
19
- </html>
3
+
4
+ <head>
5
+ <meta charset="utf-8" />
6
+ <title>Widget test</title>
7
+ <script type="module"
8
+ src="http://localhost:5173/src/main.ts"
9
+ data-client-id="87c06405-7571-4133-b30a-c78f56678af6"></script>
10
+ </head>
11
+
12
+ <body>
13
+
14
+ <!-- <script src="https://cdn.jsdelivr.net/npm/ss-support-widget@1.0.4/dist/chat-bot-widget.js"></script> -->
15
+ </body>
16
+
17
+ </html>
package/package.json CHANGED
@@ -1,29 +1,31 @@
1
- {
2
- "name": "ss-support-widget",
3
- "version": "1.0.8",
4
- "description": "Chatbot widget for customer support",
5
- "main": "index.js",
6
- "scripts": {
7
- "build:script": "tsup src/element.tsx --format iife --global-name ChatBot --minify --clean --out-dir dist"
8
- },
9
- "keywords": [],
10
- "author": "SS SRL",
11
- "license": "ISC",
12
- "type": "commonjs",
13
- "devDependencies": {
14
- "@types/react-dom": "^19.2.3",
15
- "@vitejs/plugin-react": "^5.1.2",
16
- "typescript": "^5.9.3",
17
- "vite": "^7.2.7"
18
- },
19
- "dependencies": {
20
- "@emotion/cache": "^11.14.0",
21
- "@emotion/react": "^11.14.0",
22
- "@emotion/styled": "^11.14.1",
23
- "@mui/icons-material": "^7.3.6",
24
- "@mui/material": "^7.3.6",
25
- "react": "^19.2.3",
26
- "react-dom": "^19.2.3",
27
- "react-markdown": "^10.1.0"
28
- }
29
- }
1
+ {
2
+ "name": "ss-support-widget",
3
+ "version": "1.0.10",
4
+ "description": "Chatbot widget for customer support",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "build:script": "tsup src/main.ts --format iife --global-name ChatBot --minify --clean --out-dir dist"
8
+ },
9
+ "keywords": [],
10
+ "author": "SS SRL",
11
+ "license": "ISC",
12
+ "type": "commonjs",
13
+ "devDependencies": {
14
+ "@types/react-dom": "^19.2.3",
15
+ "@vitejs/plugin-react": "^5.1.2",
16
+ "typescript": "^5.9.3",
17
+ "vite": "^7.2.7"
18
+ },
19
+ "dependencies": {
20
+ "@emotion/cache": "^11.14.0",
21
+ "@emotion/react": "^11.14.0",
22
+ "@emotion/styled": "^11.14.1",
23
+ "@microsoft/signalr": "^10.0.0",
24
+ "@mui/icons-material": "^7.3.6",
25
+ "@mui/material": "^7.3.6",
26
+ "bson": "^7.0.0",
27
+ "react": "^19.2.3",
28
+ "react-dom": "^19.2.3",
29
+ "react-markdown": "^10.1.0"
30
+ }
31
+ }
package/readme.md CHANGED
@@ -1,7 +1,7 @@
1
- <script>
2
- window.ChatBotConfig = {
3
- clientId: "abc123",
4
- apiBaseUrl: "https://api.firma.ro",
5
- };
6
- </script>
7
- <script src="https://cdn.firma.ro/chat-bot-widget.js" async></script>
1
+ <script>
2
+ window.ChatBotConfig = {
3
+ clientId: "abc123",
4
+ apiBaseUrl: "https://api.firma.ro",
5
+ };
6
+ </script>
7
+ <script src="https://cdn.firma.ro/chat-bot-widget.js" async></script>
@@ -0,0 +1,80 @@
1
+ import { authFetch } from "../authentification/token";
2
+ import { chatBasePath } from "../constants";
3
+ import { Config, ConversationStatus, MsgDelta } from "../types";
4
+
5
+
6
+ export async function getHistoryMessages(config: Config,
7
+ conversationId: string,
8
+ onSucces: (delta: MsgDelta[]) => void)
9
+ : Promise<void> {
10
+ authFetch(config.apiBaseUrl + chatBasePath + "/" + config.clientId + "/messages/", {
11
+ method: "GET",
12
+ headers: {
13
+ "Content-Type": "application/json",
14
+ "X-Conversation-Id": conversationId,
15
+ },
16
+ })
17
+ .then(res => {
18
+ if (!res.ok) {
19
+ throw new Error("Request failed");
20
+ }
21
+ return res.json();
22
+ })
23
+ .then(data => {
24
+ onSucces(data.map((d: any) => d as MsgDelta));
25
+ })
26
+ .catch(err => {
27
+ console.error(err);
28
+ });
29
+ }
30
+
31
+ export async function getConversationStatus(config: Config, conversationId: string)
32
+ : Promise<ConversationStatus> {
33
+ const res = await authFetch(config.apiBaseUrl + chatBasePath + "/" + config.clientId + "/conversation-status/", {
34
+ method: "GET",
35
+ headers: {
36
+ "Content-Type": "application/json",
37
+ "X-Conversation-Id": conversationId,
38
+ },
39
+ })
40
+
41
+ if (!res.ok) {
42
+ // TO DO
43
+ }
44
+
45
+ return await res.json() as ConversationStatus;
46
+ }
47
+
48
+ export async function getApiStatus(config: Config): Promise<boolean> {
49
+
50
+ const res = await authFetch(config.apiBaseUrl + "/api/health/" + config.clientId, {
51
+ method: "GET",
52
+ headers: {
53
+ "Content-Type": "application/json",
54
+ },
55
+ });
56
+
57
+ return res.ok;
58
+ }
59
+
60
+ type ClientActivityStatus = {
61
+ isActive: boolean;
62
+ hideForUrls: string[];
63
+ };
64
+
65
+ export async function getClientActivityStatus(config: Config, conversationId?: string | null): Promise<ClientActivityStatus> {
66
+
67
+ const res = await authFetch(config.apiBaseUrl + chatBasePath + "/" + config.clientId + "/client-activity-status", {
68
+ method: "GET",
69
+ headers: {
70
+ "Content-Type": "application/json",
71
+ ...(conversationId ? { "X-Conversation-Id": conversationId } : {}),
72
+ },
73
+ });
74
+
75
+ if (!res.ok) {
76
+ return { isActive: false, hideForUrls: [] };
77
+ }
78
+
79
+ return res.body ? await res.json() as ClientActivityStatus : { isActive: false, hideForUrls: [] };
80
+ }
@@ -1,55 +1,58 @@
1
- import { MsgDelta } from "./MsgDelta";
2
-
3
- type StreamArgs = {
4
- url: string;
5
- token?: string;
6
- clientId?: string;
7
- threadId?: string;
8
- body: string;
9
- onDelta: (delta: MsgDelta) => void;
10
- };
11
-
12
- export async function streamChat(a: StreamArgs): Promise<void> {
13
- const res = await fetch(a.url, {
14
- method: "POST",
15
- headers: {
16
- "Content-Type": "application/json",
17
- ...(a.token ? { Authorization: "Bearer " + a.token } : {}),
18
- ...(a.clientId ? { "X-Client-Id": a.clientId } : {}),
19
- ...(a.threadId ? { "X-Thread-Id": a.threadId } : {}),
20
- },
21
- body: JSON.stringify(a.body),
22
- });
23
-
24
- if (!res.ok) {
25
- throw new Error("HTTP " + res.status);
26
- }
27
-
28
- if (!res.body) {
29
- throw new Error("ReadableStream missing");
30
- }
31
-
32
- const reader = res.body.getReader();
33
- const decoder = new TextDecoder("utf-8");
34
- let buffer = "";
35
-
36
- while (true) {
37
- const { value, done } = await reader.read();
38
- if (done) break;
39
-
40
- buffer += decoder.decode(value, { stream: true });
41
-
42
- let idx;
43
- while ((idx = buffer.indexOf("\n")) !== -1) {
44
- const line = buffer.slice(0, idx).trim();
45
- buffer = buffer.slice(idx + 1);
46
-
47
- if (!line) continue;
48
-
49
- const obj = JSON.parse(line) as MsgDelta;
50
- a.onDelta(obj);
51
- }
52
- }
53
-
54
- // a.onDelta({ id: "", threadId: "", text: decoder.decode() });
55
- }
1
+ import { authFetch } from "../authentification/token";
2
+ import { MsgDelta } from "../types";
3
+ import getDeviceType from "../utils/deviceInfo";
4
+
5
+ type StreamArgs = {
6
+ url: string;
7
+ token?: string | undefined | null;
8
+ clientId?: string;
9
+ conversationId?: string | null;
10
+ messageId?: string;
11
+ body: string;
12
+ onDelta: (delta: MsgDelta) => void;
13
+ };
14
+
15
+ export async function streamChat(a: StreamArgs): Promise<void> {
16
+ const res = await authFetch(a.url, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ "X-Device-Type": getDeviceType(),
21
+ ...(a.clientId ? { "X-Client-Id": a.clientId } : {}),
22
+ ...(a.conversationId ? { "X-Conversation-Id": a.conversationId } : {}),
23
+ ...(a.messageId ? { "X-Message-Id": a.messageId } : {}),
24
+ },
25
+ body: JSON.stringify(a.body),
26
+ });
27
+
28
+ if (!res.ok) {
29
+ throw new Error("HTTP " + res.status);
30
+ }
31
+
32
+ if (!res.body) {
33
+ throw new Error("ReadableStream missing");
34
+ }
35
+
36
+ const reader = res.body.getReader();
37
+ const decoder = new TextDecoder("utf-8");
38
+ let buffer = "";
39
+
40
+ while (true) {
41
+ const { value, done } = await reader.read();
42
+ if (done) break;
43
+
44
+ buffer += decoder.decode(value, { stream: true });
45
+
46
+ let idx;
47
+ while ((idx = buffer.indexOf("\n")) !== -1) {
48
+ const line = buffer.slice(0, idx).trim();
49
+ buffer = buffer.slice(idx + 1);
50
+
51
+ if (!line) continue;
52
+
53
+ const obj = JSON.parse(line) as MsgDelta;
54
+ a.onDelta(obj);
55
+ }
56
+
57
+ }
58
+ }
@@ -0,0 +1,57 @@
1
+ import { sessionBasePath } from "../constants";
2
+ import { getChatBotConfig } from "../services/chatConfiguration";
3
+
4
+ let refreshPromise: Promise<string> | null = null;
5
+
6
+ export async function getSessionAccessToken(): Promise<string> {
7
+ const chatConfiguration = getChatBotConfig()
8
+ if (!refreshPromise) {
9
+ refreshPromise = fetch(`${chatConfiguration?.apiBaseUrl}${sessionBasePath}/${chatConfiguration?.clientId}/authorize`, {
10
+ method: "POST",
11
+ headers: {
12
+ "Content-Type": "application/json",
13
+ },
14
+ })
15
+ .then((r: Response) => {
16
+ if (!r.ok) {
17
+ throw new Error("refresh failed");
18
+ }
19
+ return r.json();
20
+ })
21
+ .then((token: string) => {
22
+ if (chatConfiguration) {
23
+ chatConfiguration.sessionToken = token;
24
+ }
25
+ return token;
26
+ })
27
+ .finally(() => {
28
+ refreshPromise = null;
29
+ });
30
+ }
31
+
32
+ return refreshPromise;
33
+ }
34
+
35
+
36
+ export async function authFetch(
37
+ input: RequestInfo | URL,
38
+ init: RequestInit = {}
39
+ ): Promise<Response> {
40
+ const headers = new Headers(init.headers);
41
+ const chatConfiguration = getChatBotConfig()
42
+ if (chatConfiguration?.sessionToken) {
43
+ headers.set("Authorization", `Bearer ${chatConfiguration?.sessionToken}`);
44
+ }
45
+
46
+ const response = await fetch(input, { ...init, headers });
47
+
48
+ if (response.status !== 401) {
49
+ return response;
50
+ }
51
+
52
+ const newToken = await getSessionAccessToken();
53
+
54
+ headers.set("Authorization", `Bearer ${newToken}`);
55
+
56
+ return fetch(input, { ...init, headers });
57
+ }