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

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.2",
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.1",
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,76 @@ 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 & { adminKey: string }
72
+ ) => Promise<ClientTypes.GenerateUserKeyResponse>
65
73
  }
74
+
66
75
  const baseConfigs = {
67
76
  throwOnError: true,
68
77
  } as const satisfies sdk.Options
69
78
 
70
- export const createUser = ({ clientId, apiUrl }: { clientId: string; apiUrl?: string }) => {
79
+ export const createUser = async ({
80
+ clientId,
81
+ apiUrl,
82
+ adminKey,
83
+ }: {
84
+ clientId: string
85
+ apiUrl?: string
86
+ adminKey?: string
87
+ }) => {
71
88
  const baseUrl = `${apiUrl || baseClient.getConfig().baseUrl}/${clientId}`
72
89
 
90
+ // @ts-expect-error - this is a private property
91
+ if (baseClient.interceptors.response._fns.length === 0) {
92
+ baseClient.interceptors.response.use(throwErrorInterceptor)
93
+ }
94
+
95
+ const configs = {
96
+ ...baseConfigs,
97
+ baseUrl,
98
+ }
99
+
100
+ return sdk
101
+ .createUser({
102
+ ...configs,
103
+ body: {},
104
+ headers: adminKey ? { 'x-admin-key': adminKey } : undefined,
105
+ })
106
+ .then(extractData)
107
+ }
108
+
109
+ export const generateUserKey = async ({
110
+ adminKey,
111
+ expiresAt,
112
+ userId,
113
+ apiUrl,
114
+ clientId,
115
+ }: {
116
+ adminKey: string
117
+ expiresAt: number
118
+ userId: string
119
+ apiUrl?: string
120
+ clientId: string
121
+ }) => {
122
+ const headers = { 'x-admin-key': adminKey }
123
+
124
+ const baseUrl = `${apiUrl || baseClient.getConfig().baseUrl}/${clientId}`
73
125
  const configs = {
74
126
  ...baseConfigs,
75
127
  baseUrl,
76
128
  }
77
- return sdk.createUser({ ...configs, body: {} }).then(extractData)
129
+ return sdk.generateUserKey({ ...configs, headers, body: { id: userId, expiresAt } }).then(extractData)
78
130
  }
79
131
 
80
132
  export const createClient = ({
@@ -96,7 +148,12 @@ export const createClient = ({
96
148
  baseUrl,
97
149
  }
98
150
 
99
- return {
151
+ // @ts-expect-error - this is a private property
152
+ if (baseClient.interceptors.response._fns.length === 0) {
153
+ baseClient.interceptors.response.use(throwErrorInterceptor)
154
+ }
155
+
156
+ const client: Client = {
100
157
  createConversation: () => sdk.createConversation({ ...configs, headers, body: {} }).then(extractData),
101
158
  getConversation: ({ conversationId }) =>
102
159
  sdk.getConversation({ ...configs, headers, path: { id: conversationId } }).then(extractData),
@@ -136,12 +193,18 @@ export const createClient = ({
136
193
  deleteUser: () => sdk.deleteUser({ ...configs, headers }).then(extractData),
137
194
  createEvent: (body) => sdk.createEvent({ ...configs, headers, body }).then(extractData),
138
195
  getEvent: ({ eventId }) => sdk.getEvent({ ...configs, headers, path: { id: eventId } }).then(extractData),
196
+ addMessageFeedback: ({ messageId, ...body }) =>
197
+ sdk.addMessageFeedback({ ...configs, headers, path: { id: messageId }, body }).then(extractData),
198
+ removeMessageFeedback: ({ messageId }) =>
199
+ sdk.removeMessageFeedback({ ...configs, headers, path: { id: messageId } }).then(extractData),
200
+ generateUserKey: ({ adminKey, ...body }) =>
201
+ sdk.generateUserKey({ ...configs, headers: { 'x-admin-key': adminKey }, body }).then(extractData),
139
202
  listenConversation: ({ conversationId }) => {
140
203
  const MAX_RETRIES = 10
141
204
  const RETRY_INTERVAL = 3000 // ms
142
205
  let retryCount = 0
143
206
  let eventSource: EventSource | null = null
144
- const eventEmitter = new EventEmitter<Record<Event['type'], Event['data']>>()
207
+ const eventEmitter = createEventEmitter<Record<Event['type'], Event['data']>>()
145
208
 
146
209
  const connect = () => {
147
210
  if (eventSource) {
@@ -177,9 +240,11 @@ export const createClient = ({
177
240
  }
178
241
  }
179
242
  connect()
180
- return eventEmitter.on.bind(eventEmitter)
243
+ return eventEmitter.on
181
244
  },
182
245
  }
246
+
247
+ return client
183
248
  }
184
249
 
185
250
  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