@botpress/webchat-client 0.1.1 → 0.2.0-beta.1

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.
@@ -1,105 +1,11 @@
1
- class E extends Error {
2
- constructor(d, s) {
3
- super(d), this.name = "ParseError", this.type = s.type, this.field = s.field, this.value = s.value, this.line = s.line;
4
- }
5
- }
6
- function x(n) {
7
- }
8
- function I(n) {
9
- if (typeof n == "function")
10
- throw new TypeError(
11
- "`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
12
- );
13
- const { onEvent: d = x, onError: s = x, onRetry: r = x, onComment: a } = n;
14
- let i = "", o = !0, f, c = "", p = "";
15
- function b(e) {
16
- const t = o ? e.replace(/^\xEF\xBB\xBF/, "") : e, [l, u] = w(`${i}${t}`);
17
- for (const h of l)
18
- y(h);
19
- i = u, o = !1;
20
- }
21
- function y(e) {
22
- if (e === "") {
23
- v();
24
- return;
25
- }
26
- if (e.startsWith(":")) {
27
- a && a(e.slice(e.startsWith(": ") ? 2 : 1));
28
- return;
29
- }
30
- const t = e.indexOf(":");
31
- if (t !== -1) {
32
- const l = e.slice(0, t), u = e[t + 1] === " " ? 2 : 1, h = e.slice(t + u);
33
- m(l, h, e);
34
- return;
35
- }
36
- m(e, "", e);
37
- }
38
- function m(e, t, l) {
39
- switch (e) {
40
- case "event":
41
- p = t;
42
- break;
43
- case "data":
44
- c = `${c}${t}
45
- `;
46
- break;
47
- case "id":
48
- f = t.includes("\0") ? void 0 : t;
49
- break;
50
- case "retry":
51
- /^\d+$/.test(t) ? r(parseInt(t, 10)) : s(
52
- new E(`Invalid \`retry\` value: "${t}"`, {
53
- type: "invalid-retry",
54
- value: t,
55
- line: l
56
- })
57
- );
58
- break;
59
- default:
60
- s(
61
- new E(
62
- `Unknown field "${e.length > 20 ? `${e.slice(0, 20)}…` : e}"`,
63
- { type: "unknown-field", field: e, value: t, line: l }
64
- )
65
- );
66
- break;
67
- }
68
- }
69
- function v() {
70
- c.length > 0 && d({
71
- id: f,
72
- event: p || void 0,
73
- // If the data buffer's last character is a U+000A LINE FEED (LF) character,
74
- // then remove the last character from the data buffer.
75
- data: c.endsWith(`
76
- `) ? c.slice(0, -1) : c
77
- }), f = void 0, c = "", p = "";
78
- }
79
- function $(e = {}) {
80
- i && e.consume && y(i), o = !0, f = void 0, c = "", p = "", i = "";
81
- }
82
- return { feed: b, reset: $ };
83
- }
84
- function w(n) {
85
- const d = [];
86
- let s = "", r = 0;
87
- for (; r < n.length; ) {
88
- const a = n.indexOf("\r", r), i = n.indexOf(`
89
- `, r);
90
- let o = -1;
91
- if (a !== -1 && i !== -1 ? o = Math.min(a, i) : a !== -1 ? o = a : i !== -1 && (o = i), o === -1) {
92
- s = n.slice(r);
93
- break;
94
- } else {
95
- const f = n.slice(r, o);
96
- d.push(f), r = o + 1, n[r - 1] === "\r" && n[r] === `
97
- ` && r++;
98
- }
99
- }
100
- return [d, s];
101
- }
1
+ const e = (t) => ({
2
+ ...t,
3
+ withCredentials: !0,
4
+ timeout: 6e4,
5
+ maxBodyLength: 104857600,
6
+ maxContentLength: 104857600,
7
+ throwOnError: !0
8
+ });
102
9
  export {
103
- E as ParseError,
104
- I as createParser
10
+ e as createClientConfig
105
11
  };
@@ -1,218 +1,105 @@
1
- var R = Object.defineProperty;
2
- var T = (t, r, e) => r in t ? R(t, r, { enumerable: !0, configurable: !0, writable: !0, value: e }) : t[r] = e;
3
- var j = (t, r, e) => T(t, typeof r != "symbol" ? r + "" : r, e);
4
- var U = async (t, r) => {
5
- let e = typeof r == "function" ? await r(t) : r;
6
- if (e) return t.scheme === "bearer" ? `Bearer ${e}` : t.scheme === "basic" ? `Basic ${btoa(e)}` : e;
7
- }, A = { bodySerializer: (t) => JSON.stringify(t, (r, e) => typeof e == "bigint" ? e.toString() : e) }, _ = (t) => {
8
- switch (t) {
9
- case "label":
10
- return ".";
11
- case "matrix":
12
- return ";";
13
- case "simple":
14
- return ",";
15
- default:
16
- return "&";
1
+ class E extends Error {
2
+ constructor(d, s) {
3
+ super(d), this.name = "ParseError", this.type = s.type, this.field = s.field, this.value = s.value, this.line = s.line;
17
4
  }
18
- }, z = (t) => {
19
- switch (t) {
20
- case "form":
21
- return ",";
22
- case "pipeDelimited":
23
- return "|";
24
- case "spaceDelimited":
25
- return "%20";
26
- default:
27
- return ",";
5
+ }
6
+ function x(n) {
7
+ }
8
+ function I(n) {
9
+ if (typeof n == "function")
10
+ throw new TypeError(
11
+ "`callbacks` must be an object, got a function instead. Did you mean `{onEvent: fn}`?"
12
+ );
13
+ const { onEvent: d = x, onError: s = x, onRetry: r = x, onComment: a } = n;
14
+ let i = "", o = !0, f, c = "", p = "";
15
+ function b(e) {
16
+ const t = o ? e.replace(/^\xEF\xBB\xBF/, "") : e, [l, u] = w(`${i}${t}`);
17
+ for (const h of l)
18
+ y(h);
19
+ i = u, o = !1;
28
20
  }
29
- }, E = (t) => {
30
- switch (t) {
31
- case "label":
32
- return ".";
33
- case "matrix":
34
- return ";";
35
- case "simple":
36
- return ",";
37
- default:
38
- return "&";
39
- }
40
- }, x = ({ allowReserved: t, explode: r, name: e, style: l, value: n }) => {
41
- if (!r) {
42
- let s = (t ? n : n.map((i) => encodeURIComponent(i))).join(z(l));
43
- switch (l) {
44
- case "label":
45
- return `.${s}`;
46
- case "matrix":
47
- return `;${e}=${s}`;
48
- case "simple":
49
- return s;
50
- default:
51
- return `${e}=${s}`;
21
+ function y(e) {
22
+ if (e === "") {
23
+ v();
24
+ return;
52
25
  }
53
- }
54
- let o = _(l), a = n.map((s) => l === "label" || l === "simple" ? t ? s : encodeURIComponent(s) : b({ allowReserved: t, name: e, value: s })).join(o);
55
- return l === "label" || l === "matrix" ? o + a : a;
56
- }, b = ({ allowReserved: t, name: r, value: e }) => {
57
- if (e == null) return "";
58
- if (typeof e == "object") throw new Error("Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these.");
59
- return `${r}=${t ? e : encodeURIComponent(e)}`;
60
- }, $ = ({ allowReserved: t, explode: r, name: e, style: l, value: n }) => {
61
- if (n instanceof Date) return `${e}=${n.toISOString()}`;
62
- if (l !== "deepObject" && !r) {
63
- let s = [];
64
- Object.entries(n).forEach(([d, f]) => {
65
- s = [...s, d, t ? f : encodeURIComponent(f)];
66
- });
67
- let i = s.join(",");
68
- switch (l) {
69
- case "form":
70
- return `${e}=${i}`;
71
- case "label":
72
- return `.${i}`;
73
- case "matrix":
74
- return `;${e}=${i}`;
75
- default:
76
- return i;
26
+ if (e.startsWith(":")) {
27
+ a && a(e.slice(e.startsWith(": ") ? 2 : 1));
28
+ return;
77
29
  }
78
- }
79
- let o = E(l), a = Object.entries(n).map(([s, i]) => b({ allowReserved: t, name: l === "deepObject" ? `${e}[${s}]` : s, value: i })).join(o);
80
- return l === "label" || l === "matrix" ? o + a : a;
81
- }, W = /\{[^{}]+\}/g, D = ({ path: t, url: r }) => {
82
- let e = r, l = r.match(W);
83
- if (l) for (let n of l) {
84
- let o = !1, a = n.substring(1, n.length - 1), s = "simple";
85
- a.endsWith("*") && (o = !0, a = a.substring(0, a.length - 1)), a.startsWith(".") ? (a = a.substring(1), s = "label") : a.startsWith(";") && (a = a.substring(1), s = "matrix");
86
- let i = t[a];
87
- if (i == null) continue;
88
- if (Array.isArray(i)) {
89
- e = e.replace(n, x({ explode: o, name: a, style: s, value: i }));
90
- continue;
91
- }
92
- if (typeof i == "object") {
93
- e = e.replace(n, $({ explode: o, name: a, style: s, value: i }));
94
- continue;
95
- }
96
- if (s === "matrix") {
97
- e = e.replace(n, `;${b({ name: a, value: i })}`);
98
- continue;
99
- }
100
- let d = encodeURIComponent(s === "label" ? `.${i}` : i);
101
- e = e.replace(n, d);
102
- }
103
- return e;
104
- }, q = ({ allowReserved: t, array: r, object: e } = {}) => (l) => {
105
- let n = [];
106
- if (l && typeof l == "object") for (let o in l) {
107
- let a = l[o];
108
- if (a != null) {
109
- if (Array.isArray(a)) {
110
- n = [...n, x({ allowReserved: t, explode: !0, name: o, style: "form", value: a, ...r })];
111
- continue;
112
- }
113
- if (typeof a == "object") {
114
- n = [...n, $({ allowReserved: t, explode: !0, name: o, style: "deepObject", value: a, ...e })];
115
- continue;
116
- }
117
- n = [...n, b({ allowReserved: t, name: o, value: a })];
30
+ const t = e.indexOf(":");
31
+ if (t !== -1) {
32
+ const l = e.slice(0, t), u = e[t + 1] === " " ? 2 : 1, h = e.slice(t + u);
33
+ m(l, h, e);
34
+ return;
118
35
  }
36
+ m(e, "", e);
119
37
  }
120
- return n.join("&");
121
- }, I = (t) => {
122
- var e;
123
- if (!t) return "stream";
124
- let r = (e = t.split(";")[0]) == null ? void 0 : e.trim();
125
- if (r) {
126
- if (r.startsWith("application/json") || r.endsWith("+json")) return "json";
127
- if (r === "multipart/form-data") return "formData";
128
- if (["application/", "audio/", "image/", "video/"].some((l) => r.startsWith(l))) return "blob";
129
- if (r.startsWith("text/")) return "text";
130
- }
131
- }, k = async ({ security: t, ...r }) => {
132
- for (let e of t) {
133
- let l = await U(e, r.auth);
134
- if (!l) continue;
135
- let n = e.name ?? "Authorization";
136
- switch (e.in) {
137
- case "query":
138
- r.query || (r.query = {}), r.query[n] = l;
38
+ function m(e, t, l) {
39
+ switch (e) {
40
+ case "event":
41
+ p = t;
42
+ break;
43
+ case "data":
44
+ c = `${c}${t}
45
+ `;
46
+ break;
47
+ case "id":
48
+ f = t.includes("\0") ? void 0 : t;
139
49
  break;
140
- case "cookie":
141
- r.headers.append("Cookie", `${n}=${l}`);
50
+ case "retry":
51
+ /^\d+$/.test(t) ? r(parseInt(t, 10)) : s(
52
+ new E(`Invalid \`retry\` value: "${t}"`, {
53
+ type: "invalid-retry",
54
+ value: t,
55
+ line: l
56
+ })
57
+ );
142
58
  break;
143
- case "header":
144
59
  default:
145
- r.headers.set(n, l);
60
+ s(
61
+ new E(
62
+ `Unknown field "${e.length > 20 ? `${e.slice(0, 20)}…` : e}"`,
63
+ { type: "unknown-field", field: e, value: t, line: l }
64
+ )
65
+ );
146
66
  break;
147
67
  }
148
- return;
149
- }
150
- }, v = (t) => N({ baseUrl: t.baseUrl, path: t.path, query: t.query, querySerializer: typeof t.querySerializer == "function" ? t.querySerializer : q(t.querySerializer), url: t.url }), N = ({ baseUrl: t, path: r, query: e, querySerializer: l, url: n }) => {
151
- let o = n.startsWith("/") ? n : `/${n}`, a = (t ?? "") + o;
152
- r && (a = D({ path: r, url: a }));
153
- let s = e ? l(e) : "";
154
- return s.startsWith("?") && (s = s.substring(1)), s && (a += `?${s}`), a;
155
- }, g = (t, r) => {
156
- var l;
157
- let e = { ...t, ...r };
158
- return (l = e.baseUrl) != null && l.endsWith("/") && (e.baseUrl = e.baseUrl.substring(0, e.baseUrl.length - 1)), e.headers = C(t.headers, r.headers), e;
159
- }, C = (...t) => {
160
- let r = new Headers();
161
- for (let e of t) {
162
- if (!e || typeof e != "object") continue;
163
- let l = e instanceof Headers ? e.entries() : Object.entries(e);
164
- for (let [n, o] of l) if (o === null) r.delete(n);
165
- else if (Array.isArray(o)) for (let a of o) r.append(n, a);
166
- else o !== void 0 && r.set(n, typeof o == "object" ? JSON.stringify(o) : o);
167
- }
168
- return r;
169
- }, w = class {
170
- constructor() {
171
- j(this, "_fns");
172
- this._fns = [];
173
68
  }
174
- clear() {
175
- this._fns = [];
69
+ function v() {
70
+ c.length > 0 && d({
71
+ id: f,
72
+ event: p || void 0,
73
+ // If the data buffer's last character is a U+000A LINE FEED (LF) character,
74
+ // then remove the last character from the data buffer.
75
+ data: c.endsWith(`
76
+ `) ? c.slice(0, -1) : c
77
+ }), f = void 0, c = "", p = "";
176
78
  }
177
- exists(t) {
178
- return this._fns.indexOf(t) !== -1;
79
+ function $(e = {}) {
80
+ i && e.consume && y(i), o = !0, f = void 0, c = "", p = "", i = "";
179
81
  }
180
- eject(t) {
181
- let r = this._fns.indexOf(t);
182
- r !== -1 && (this._fns = [...this._fns.slice(0, r), ...this._fns.slice(r + 1)]);
183
- }
184
- use(t) {
185
- this._fns = [...this._fns, t];
186
- }
187
- }, P = () => ({ error: new w(), request: new w(), response: new w() }), H = /* @__PURE__ */ q({ allowReserved: !1, array: { explode: !0, style: "form" }, object: { explode: !0, style: "deepObject" } }), J = { "Content-Type": "application/json" }, O = (t = {}) => ({ ...A, headers: J, parseAs: "auto", querySerializer: H, ...t }), B = (t = {}) => {
188
- let r = g(O(), t), e = () => ({ ...r }), l = (a) => (r = g(r, a), e()), n = P(), o = async (a) => {
189
- let s = { ...r, ...a, fetch: a.fetch ?? r.fetch ?? globalThis.fetch, headers: C(r.headers, a.headers) };
190
- s.security && await k({ ...s, security: s.security }), s.body && s.bodySerializer && (s.body = s.bodySerializer(s.body)), (s.body === void 0 || s.body === "") && s.headers.delete("Content-Type");
191
- let i = v(s), d = { redirect: "follow", ...s }, f = new Request(i, d);
192
- for (let c of n.request._fns) f = await c(f, s);
193
- let S = s.fetch, u = await S(f);
194
- for (let c of n.response._fns) u = await c(u, f, s);
195
- let h = { request: f, response: u };
196
- if (u.ok) {
197
- if (u.status === 204 || u.headers.get("Content-Length") === "0") return { data: {}, ...h };
198
- let c = (s.parseAs === "auto" ? I(u.headers.get("Content-Type")) : s.parseAs) ?? "json";
199
- if (c === "stream") return { data: u.body, ...h };
200
- let m = await u[c]();
201
- return c === "json" && (s.responseValidator && await s.responseValidator(m), s.responseTransformer && (m = await s.responseTransformer(m))), { data: m, ...h };
82
+ return { feed: b, reset: $ };
83
+ }
84
+ function w(n) {
85
+ const d = [];
86
+ let s = "", r = 0;
87
+ for (; r < n.length; ) {
88
+ const a = n.indexOf("\r", r), i = n.indexOf(`
89
+ `, r);
90
+ let o = -1;
91
+ if (a !== -1 && i !== -1 ? o = Math.min(a, i) : a !== -1 ? o = a : i !== -1 && (o = i), o === -1) {
92
+ s = n.slice(r);
93
+ break;
94
+ } else {
95
+ const f = n.slice(r, o);
96
+ d.push(f), r = o + 1, n[r - 1] === "\r" && n[r] === `
97
+ ` && r++;
202
98
  }
203
- let y = await u.text();
204
- try {
205
- y = JSON.parse(y);
206
- } catch {
207
- }
208
- let p = y;
209
- for (let c of n.error._fns) p = await c(y, u, f, s);
210
- if (p = p || {}, s.throwOnError) throw p;
211
- return { error: p, ...h };
212
- };
213
- return { buildUrl: v, connect: (a) => o({ ...a, method: "CONNECT" }), delete: (a) => o({ ...a, method: "DELETE" }), get: (a) => o({ ...a, method: "GET" }), getConfig: e, head: (a) => o({ ...a, method: "HEAD" }), interceptors: n, options: (a) => o({ ...a, method: "OPTIONS" }), patch: (a) => o({ ...a, method: "PATCH" }), post: (a) => o({ ...a, method: "POST" }), put: (a) => o({ ...a, method: "PUT" }), request: o, setConfig: l, trace: (a) => o({ ...a, method: "TRACE" }) };
214
- }, V = B, G = O;
99
+ }
100
+ return [d, s];
101
+ }
215
102
  export {
216
- V as createClient,
217
- G as createConfig
103
+ E as ParseError,
104
+ I as createParser
218
105
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botpress/webchat-client",
3
- "version": "0.1.1",
3
+ "version": "0.2.0-beta.1",
4
4
  "description": "",
5
5
  "main": "src/index.ts",
6
6
  "type": "module",
@@ -26,7 +26,7 @@
26
26
  "eventsource": "^3.0.6"
27
27
  },
28
28
  "devDependencies": {
29
- "@bpinternal/webchat-http-client": "0.2.6",
29
+ "@bpinternal/webchat-http-client": "0.4.0",
30
30
  "@hey-api/client-fetch": "^0.10.0",
31
31
  "@hey-api/openapi-ts": "^0.66.4",
32
32
  "@repo/eslint-config": "workspace:*",
@@ -3,7 +3,8 @@ import * as sdk from '../gen/client/sdk.gen'
3
3
  import { client as baseClient } from '../gen/client/client.gen'
4
4
  import { EventSource } from 'eventsource'
5
5
  import type { Signal } from './types/signals'
6
- import { EventEmitter } from './eventEmitter'
6
+ import { throwErrorInterceptor } from './interceptor'
7
+ import { createEventEmitter, EventEmitter } from './emitter'
7
8
 
8
9
  type ConversationIdParam = {
9
10
  conversationId: string
@@ -56,25 +57,78 @@ export type Client = {
56
57
  deleteMessage: (params: MessageIdParam) => Promise<ClientTypes.DeleteMessageResponse>
57
58
  createFile: (params: ClientTypes.CreateFileBody) => Promise<ClientTypes.CreateFileResponse>
58
59
  createUser: (params: ClientTypes.CreateUserBody) => Promise<ClientTypes.CreateUserResponse>
59
- getUser: (params: UserIdParam) => Promise<ClientTypes.GetUserResponse>
60
+ getUser: () => Promise<ClientTypes.GetUserResponse>
60
61
  updateUser: (params: ClientTypes.CreateUserBody) => Promise<ClientTypes.UpdateUserResponse>
61
62
  deleteUser: (params: UserIdParam) => Promise<ClientTypes.DeleteUserResponse>
62
63
  createEvent: (params: ClientTypes.CreateEventBody) => Promise<ClientTypes.CreateEventResponse>
63
64
  getEvent: (params: EventIdParam) => Promise<ClientTypes.GetEventResponse>
64
65
  listenConversation: (params: ConversationIdParam) => EventEmitter<Record<Event['type'], Event['data']>>['on']
66
+ addMessageFeedback: (
67
+ params: MessageIdParam & ClientTypes.AddMessageFeedbackBody
68
+ ) => Promise<ClientTypes.AddMessageFeedbackResponse>
69
+ removeMessageFeedback: (params: MessageIdParam) => Promise<ClientTypes.RemoveMessageFeedbackResponse>
70
+ generateUserKey: (
71
+ params: ClientTypes.GenerateUserKeyBody,
72
+ adminKey?: string
73
+ ) => Promise<ClientTypes.GenerateUserKeyResponse>
65
74
  }
75
+
66
76
  const baseConfigs = {
67
77
  throwOnError: true,
68
78
  } as const satisfies sdk.Options
69
79
 
70
- export const createUser = ({ clientId, apiUrl }: { clientId: string; apiUrl?: string }) => {
80
+ export const createUser = async ({
81
+ clientId,
82
+ apiUrl,
83
+ adminKey,
84
+ }: {
85
+ clientId: string
86
+ apiUrl?: string
87
+ adminKey?: string
88
+ }) => {
71
89
  const baseUrl = `${apiUrl || baseClient.getConfig().baseUrl}/${clientId}`
72
90
 
91
+ // @ts-expect-error - this is a private property
92
+ if (baseClient.interceptors.response._fns.length === 0) {
93
+ baseClient.interceptors.response.use(throwErrorInterceptor)
94
+ }
95
+
96
+ const configs = {
97
+ ...baseConfigs,
98
+ baseUrl,
99
+ }
100
+
101
+ const res = await sdk.createUser({
102
+ ...configs,
103
+ body: {},
104
+ headers: adminKey ? { 'x-admin-key': adminKey } : undefined,
105
+ })
106
+
107
+ return extractData(res)
108
+ }
109
+
110
+ export const generateUserKey = async ({
111
+ adminKey,
112
+ expiresAt,
113
+ userId,
114
+ apiUrl,
115
+ clientId,
116
+ }: {
117
+ adminKey: string
118
+ expiresAt: number
119
+ userId: string
120
+ apiUrl?: string
121
+ clientId: string
122
+ }) => {
123
+ const headers = { 'x-admin-key': adminKey }
124
+ console.log('generateUserKey', userId, expiresAt, headers)
125
+
126
+ const baseUrl = `${apiUrl || baseClient.getConfig().baseUrl}/${clientId}`
73
127
  const configs = {
74
128
  ...baseConfigs,
75
129
  baseUrl,
76
130
  }
77
- return sdk.createUser({ ...configs, body: {} }).then(extractData)
131
+ return sdk.generateUserKey({ ...configs, headers, body: { id: userId, expiresAt } }).then(extractData)
78
132
  }
79
133
 
80
134
  export const createClient = ({
@@ -96,7 +150,12 @@ export const createClient = ({
96
150
  baseUrl,
97
151
  }
98
152
 
99
- return {
153
+ // @ts-expect-error - this is a private property
154
+ if (baseClient.interceptors.response._fns.length === 0) {
155
+ baseClient.interceptors.response.use(throwErrorInterceptor)
156
+ }
157
+
158
+ const client: Client = {
100
159
  createConversation: () => sdk.createConversation({ ...configs, headers, body: {} }).then(extractData),
101
160
  getConversation: ({ conversationId }) =>
102
161
  sdk.getConversation({ ...configs, headers, path: { id: conversationId } }).then(extractData),
@@ -136,12 +195,21 @@ export const createClient = ({
136
195
  deleteUser: () => sdk.deleteUser({ ...configs, headers }).then(extractData),
137
196
  createEvent: (body) => sdk.createEvent({ ...configs, headers, body }).then(extractData),
138
197
  getEvent: ({ eventId }) => sdk.getEvent({ ...configs, headers, path: { id: eventId } }).then(extractData),
198
+ addMessageFeedback: ({ messageId, ...body }) =>
199
+ sdk.addMessageFeedback({ ...configs, headers, path: { id: messageId }, body }).then(extractData),
200
+ removeMessageFeedback: ({ messageId }) =>
201
+ sdk.removeMessageFeedback({ ...configs, headers, path: { id: messageId } }).then(extractData),
202
+ generateUserKey: async (body, adminKey) => {
203
+ const headers = adminKey ? { 'x-admin-key': adminKey } : undefined
204
+ console.log('generateUserKey', body, headers)
205
+ return sdk.generateUserKey({ ...configs, headers, body }).then(extractData)
206
+ },
139
207
  listenConversation: ({ conversationId }) => {
140
208
  const MAX_RETRIES = 10
141
209
  const RETRY_INTERVAL = 3000 // ms
142
210
  let retryCount = 0
143
211
  let eventSource: EventSource | null = null
144
- const eventEmitter = new EventEmitter<Record<Event['type'], Event['data']>>()
212
+ const eventEmitter = createEventEmitter<Record<Event['type'], Event['data']>>()
145
213
 
146
214
  const connect = () => {
147
215
  if (eventSource) {
@@ -177,9 +245,11 @@ export const createClient = ({
177
245
  }
178
246
  }
179
247
  connect()
180
- return eventEmitter.on.bind(eventEmitter)
248
+ return eventEmitter.on
181
249
  },
182
250
  }
251
+
252
+ return client
183
253
  }
184
254
 
185
255
  const safeJsonParse = (data: any) => {
@@ -0,0 +1,27 @@
1
+ type CallbackFn<T> = (args: T) => void
2
+
3
+ export type EventEmitter<T extends Record<string, unknown>> = {
4
+ on: <U extends keyof T>(event: U, callback: CallbackFn<T[U]>) => () => void
5
+ emit: <U extends keyof T>(event: U, arg?: T[U]) => void
6
+ }
7
+
8
+ export const createEventEmitter = <T extends Record<string, unknown>>(): EventEmitter<T> => {
9
+ const eventMap: Partial<Record<keyof T, Set<CallbackFn<any>>>> = {}
10
+
11
+ const on = <U extends keyof T>(event: U, callback: CallbackFn<T[U]>) => {
12
+ if (!eventMap[event]) {
13
+ eventMap[event] = new Set<CallbackFn<T[U]>>()
14
+ }
15
+
16
+ eventMap[event]?.add(callback)
17
+
18
+ return () => eventMap[event]?.delete(callback)
19
+ }
20
+
21
+ const emit = <U extends keyof T>(event: U, arg?: T[U]) => {
22
+ eventMap[event]?.forEach((callback) => callback(arg))
23
+ eventMap['*']?.forEach((callback) => callback({ type: event, payload: arg }))
24
+ }
25
+
26
+ return { on, emit }
27
+ }
@@ -1,2 +1,4 @@
1
1
  export * from './client'
2
2
  export * from './config'
3
+ export * from './types'
4
+ export * from './emitter'
@@ -0,0 +1,16 @@
1
+ import { IntegrationError } from './types'
2
+
3
+ export async function throwErrorInterceptor(response: Response) {
4
+ const clonedResponse = response.clone()
5
+ const data = await clonedResponse.json()
6
+
7
+ if (data?.id?.startsWith('err_')) {
8
+ const error = new Error(data.message) as Error & IntegrationError
9
+ error.id = data.id
10
+ error.code = data.code
11
+ error.type = data.type
12
+ throw error
13
+ }
14
+
15
+ return response
16
+ }
@@ -0,0 +1,8 @@
1
+ type IntegrationError = {
2
+ id: string
3
+ code: number
4
+ type: string
5
+ message: string
6
+ }
7
+
8
+ export type { IntegrationError }
@@ -0,0 +1,2 @@
1
+ export * from './user'
2
+ export * from './error'
@@ -5,6 +5,9 @@ import type { TypingStarted } from './typingStarted'
5
5
  import type { TypingStopped } from './typingStopped'
6
6
  import type { WebchatConfig } from './webchatConfig'
7
7
  import type { WebchatVisibility } from './webchatVisibility'
8
+ import type { ParticipantAdded } from './participantAdded'
9
+ import type { ParticipantRemoved } from './participantRemoved'
10
+ import type { MessageStatusChanged } from './messageStatusChanged'
8
11
 
9
12
  export type Signal =
10
13
  | MessageCreated
@@ -14,3 +17,6 @@ export type Signal =
14
17
  | Custom
15
18
  | TypingStarted
16
19
  | TypingStopped
20
+ | ParticipantAdded
21
+ | ParticipantRemoved
22
+ | MessageStatusChanged