@onedeskpro/chatbot-core 0.2.0 → 0.3.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.
package/dist/index.d.cts CHANGED
@@ -1,29 +1,36 @@
1
1
  import { ApiError } from '@onedeskpro/chatbot-types';
2
2
  import { ApiResponse } from '@onedeskpro/chatbot-types';
3
+ import { ChatAttachment } from '@onedeskpro/chatbot-types';
3
4
  import { ChatbotBlockReason } from '@onedeskpro/chatbot-types';
4
5
  import { ChatbotEventMap } from '@onedeskpro/chatbot-types';
5
6
  import { ChatbotInitOptions } from '@onedeskpro/chatbot-types';
6
7
  import { ChatbotState } from '@onedeskpro/chatbot-types';
7
8
  import { ChatbotTicketMode } from '@onedeskpro/chatbot-types';
8
9
  import { ChatMessage } from '@onedeskpro/chatbot-types';
10
+ import { ChatMessageKind } from '@onedeskpro/chatbot-types';
9
11
  import { ChatRequest } from '@onedeskpro/chatbot-types';
10
12
  import { ChatResponseData } from '@onedeskpro/chatbot-types';
11
13
  import { IdentifyRequest } from '@onedeskpro/chatbot-types';
12
14
  import { IdentifyResponseData } from '@onedeskpro/chatbot-types';
13
15
  import { SdkConfigResponse } from '@onedeskpro/chatbot-types';
14
16
  import { TicketStatusData } from '@onedeskpro/chatbot-types';
17
+ import { UploadAttachmentResponseData } from '@onedeskpro/chatbot-types';
15
18
  import { VisitorVerifyResponse } from '@onedeskpro/chatbot-types';
19
+ import { VoiceRecording } from '@onedeskpro/chatbot-types';
16
20
 
17
21
  export declare class ApiClient {
18
22
  private baseUrl;
19
23
  private apiKey;
20
24
  private timeoutMs;
25
+ private uploadTimeoutMs;
21
26
  constructor(options: ApiClientOptions);
22
27
  private fail;
23
28
  private request;
24
29
  identify(payload: IdentifyRequest): Promise<IdentifyResponseData>;
25
30
  verifyVisitor(visitorToken: string): Promise<VisitorVerifyResponse>;
26
31
  sendMessage(payload: ChatRequest): Promise<ChatResponseData>;
32
+ /** Uploads one file for a media message; the result goes into `ChatRequest.attachments`. */
33
+ uploadAttachment(file: File, visitorToken: string): Promise<UploadAttachmentResponseData>;
27
34
  fetchConfig(): Promise<SdkConfigResponse>;
28
35
  requestHuman(visitorToken: string): Promise<TicketStatusData>;
29
36
  fetchTicketStatus(visitorToken: string): Promise<TicketStatusData>;
@@ -34,12 +41,16 @@ declare interface ApiClientOptions {
34
41
  apiKey: string;
35
42
  /** Abort a request that has not responded within this many milliseconds. */
36
43
  timeoutMs?: number;
44
+ /** Abort a file upload that has not completed within this many milliseconds. */
45
+ uploadTimeoutMs?: number;
37
46
  }
38
47
 
39
48
  export { ApiError }
40
49
 
41
50
  export { ApiResponse }
42
51
 
52
+ export { ChatAttachment }
53
+
43
54
  export { ChatbotBlockReason }
44
55
 
45
56
  export declare class ChatbotCore {
@@ -57,6 +68,8 @@ export declare class ChatbotCore {
57
68
  * before a ticket exists.
58
69
  */
59
70
  private hasActiveTicket;
71
+ /** Pending readiness re-check while the server is unreachable. */
72
+ private retryTimer;
60
73
  /** Server id of the last `message:receive` push rendered as an agent bubble. */
61
74
  private lastPushId;
62
75
  /**
@@ -79,8 +92,19 @@ export declare class ChatbotCore {
79
92
  private syncWidgetMode;
80
93
  init(options: ChatbotInitOptions): Promise<void>;
81
94
  /**
82
- * Maps `/sdk/config` failures: missing Connected Channels becomes `no-agent`,
83
- * other 403s show the API message, and 401/network stay as `state.error`.
95
+ * Asks `/sdk/config` whether the server is up and the agent can reply, and
96
+ * shows the widget only when both hold. An unreachable server is retried on
97
+ * READINESS_RETRY_DELAYS_MS; a configuration problem is final for this page.
98
+ * `ready` fires once the outcome is settled either way.
99
+ */
100
+ private checkReadiness;
101
+ /** Creates the widget hidden; checkReadiness reveals it once every check passed. */
102
+ private mountWidget;
103
+ private clearRetry;
104
+ /**
105
+ * Maps `/sdk/config` rejections other than an unreachable server: missing
106
+ * Connected Channels becomes `no-agent`; anything else (an invalid key, a
107
+ * disallowed origin) is recorded as `state.error`.
84
108
  */
85
109
  private handleConfigError;
86
110
  private resolveVisitorGate;
@@ -106,7 +130,42 @@ export declare class ChatbotCore {
106
130
  * Escalate the open AI ticket to Unassigned. No-op unless the widget is in `ai` mode.
107
131
  */
108
132
  requestHuman(): Promise<void>;
133
+ /** The visitor token every send needs; throws when the visitor has not identified. */
134
+ private requireVisitorToken;
135
+ /** Adds the visitor's own message optimistically and marks a send in flight. */
136
+ private pushLocalMessage;
137
+ private replaceMessage;
138
+ private removeMessage;
109
139
  sendMessage(text: string): Promise<void>;
140
+ /** Records a send that never left the browser: `state.error`, the composer, and `error`. */
141
+ private rejectSend;
142
+ /**
143
+ * Sends `files` as one media message, with `text` as its caption. The bubble
144
+ * appears at once with local previews, uploads each file through the API, then
145
+ * posts the chat message the same way `sendMessage` does. Rejects when the visitor
146
+ * has not identified; a file that breaks the size or count limit is reported as
147
+ * `state.error` (and an `error` event) without sending anything.
148
+ */
149
+ sendAttachments(files: File[], text?: string): Promise<void>;
150
+ /**
151
+ * Sends a recorded voice note (from `VoiceRecorder` or your own recorder). The
152
+ * recording is re-encoded as mono WAV with a waveform where Web Audio allows,
153
+ * uploaded, and posted as a `voice` message so the inbox shows its voice player.
154
+ * Rejects when the visitor has not identified; an unusable or oversized recording is
155
+ * reported as `state.error` (and an `error` event) without sending anything.
156
+ */
157
+ sendVoice(recording: VoiceRecording): Promise<void>;
158
+ /**
159
+ * Shared tail of every file send: an optimistic `pending` bubble with local previews,
160
+ * one upload per file, then `deliver`. A failed upload removes the bubble; a failed
161
+ * chat post keeps it (the files are already stored) and records the error.
162
+ */
163
+ private uploadThenDeliver;
164
+ /**
165
+ * Posts `payload` to `/sdk/chat` and applies the outcome: the ticket now exists,
166
+ * the mode may have moved, and in `ai` mode the reply becomes a bubble.
167
+ */
168
+ private deliver;
110
169
  on<K extends keyof ChatbotEventMap>(event: K, listener: Listener<K>): () => void;
111
170
  resetSession(): void;
112
171
  open(): void;
@@ -138,6 +197,8 @@ export { ChatbotTicketMode }
138
197
 
139
198
  export { ChatMessage }
140
199
 
200
+ export { ChatMessageKind }
201
+
141
202
  export { ChatRequest }
142
203
 
143
204
  export { ChatResponseData }
@@ -176,6 +237,12 @@ export declare const OnedeskProChatbot: {
176
237
  */
177
238
  export declare function resolveSdkSocketUrl(baseUrl: string): string;
178
239
 
240
+ /** Most attachments one chat message may carry. */
241
+ export declare const SDK_CHAT_MAX_ATTACHMENTS = 10;
242
+
243
+ /** Largest file `POST /sdk/upload` accepts, in bytes (10 MB). */
244
+ export declare const SDK_UPLOAD_MAX_BYTES: number;
245
+
179
246
  export { SdkConfigResponse }
180
247
 
181
248
  /**
@@ -217,6 +284,62 @@ export declare class SessionManager {
217
284
 
218
285
  export { TicketStatusData }
219
286
 
287
+ export { UploadAttachmentResponseData }
288
+
220
289
  export { VisitorVerifyResponse }
221
290
 
291
+ /** Longest voice note the widget records before stopping on its own. */
292
+ export declare const VOICE_MAX_DURATION_SECONDS = 300;
293
+
294
+ /**
295
+ * Records a voice note with `MediaRecorder`. Framework-independent: the widget uses it,
296
+ * and custom UIs built on `ChatbotCore` can too. `destroy()` releases the microphone,
297
+ * timers and audio context; nothing is left running once it returns.
298
+ */
299
+ export declare class VoiceRecorder {
300
+ private readonly onChange;
301
+ private readonly maxDurationSeconds;
302
+ private recorder;
303
+ private stream;
304
+ private chunks;
305
+ private mimeType;
306
+ private startedAt;
307
+ private tickTimer;
308
+ private levelTimer;
309
+ private maxTimer;
310
+ private audioContext;
311
+ private analyser;
312
+ private snapshot;
313
+ constructor(onChange: (snapshot: VoiceRecorderSnapshot) => void, maxDurationSeconds?: number);
314
+ static isSupported(): boolean;
315
+ getSnapshot(): VoiceRecorderSnapshot;
316
+ /** Asks for the microphone and starts recording. Rejects with a visitor-facing message. */
317
+ start(): Promise<void>;
318
+ /** Stops recording and moves to `preview`. Resolves with the recording, or null if none. */
319
+ stop(): Promise<VoiceRecording | null>;
320
+ /** Discards the recording (or the one in preview) and returns to `idle`. */
321
+ cancel(): void;
322
+ destroy(): void;
323
+ private update;
324
+ private elapsedMs;
325
+ private startLevelMeter;
326
+ private clearTimers;
327
+ private releaseMedia;
328
+ private release;
329
+ }
330
+
331
+ export declare interface VoiceRecorderSnapshot {
332
+ state: VoiceRecorderState;
333
+ /** Whole seconds recorded so far (or the final length in `preview`). */
334
+ elapsedSeconds: number;
335
+ /** Microphone loudness 0–1 while recording, 0 otherwise. */
336
+ level: number;
337
+ /** The finished recording while in `preview`. */
338
+ result: VoiceRecording | null;
339
+ }
340
+
341
+ export declare type VoiceRecorderState = 'idle' | 'recording' | 'preview';
342
+
343
+ export { VoiceRecording }
344
+
222
345
  export { }
package/dist/index.d.ts CHANGED
@@ -1,29 +1,36 @@
1
1
  import { ApiError } from '@onedeskpro/chatbot-types';
2
2
  import { ApiResponse } from '@onedeskpro/chatbot-types';
3
+ import { ChatAttachment } from '@onedeskpro/chatbot-types';
3
4
  import { ChatbotBlockReason } from '@onedeskpro/chatbot-types';
4
5
  import { ChatbotEventMap } from '@onedeskpro/chatbot-types';
5
6
  import { ChatbotInitOptions } from '@onedeskpro/chatbot-types';
6
7
  import { ChatbotState } from '@onedeskpro/chatbot-types';
7
8
  import { ChatbotTicketMode } from '@onedeskpro/chatbot-types';
8
9
  import { ChatMessage } from '@onedeskpro/chatbot-types';
10
+ import { ChatMessageKind } from '@onedeskpro/chatbot-types';
9
11
  import { ChatRequest } from '@onedeskpro/chatbot-types';
10
12
  import { ChatResponseData } from '@onedeskpro/chatbot-types';
11
13
  import { IdentifyRequest } from '@onedeskpro/chatbot-types';
12
14
  import { IdentifyResponseData } from '@onedeskpro/chatbot-types';
13
15
  import { SdkConfigResponse } from '@onedeskpro/chatbot-types';
14
16
  import { TicketStatusData } from '@onedeskpro/chatbot-types';
17
+ import { UploadAttachmentResponseData } from '@onedeskpro/chatbot-types';
15
18
  import { VisitorVerifyResponse } from '@onedeskpro/chatbot-types';
19
+ import { VoiceRecording } from '@onedeskpro/chatbot-types';
16
20
 
17
21
  export declare class ApiClient {
18
22
  private baseUrl;
19
23
  private apiKey;
20
24
  private timeoutMs;
25
+ private uploadTimeoutMs;
21
26
  constructor(options: ApiClientOptions);
22
27
  private fail;
23
28
  private request;
24
29
  identify(payload: IdentifyRequest): Promise<IdentifyResponseData>;
25
30
  verifyVisitor(visitorToken: string): Promise<VisitorVerifyResponse>;
26
31
  sendMessage(payload: ChatRequest): Promise<ChatResponseData>;
32
+ /** Uploads one file for a media message; the result goes into `ChatRequest.attachments`. */
33
+ uploadAttachment(file: File, visitorToken: string): Promise<UploadAttachmentResponseData>;
27
34
  fetchConfig(): Promise<SdkConfigResponse>;
28
35
  requestHuman(visitorToken: string): Promise<TicketStatusData>;
29
36
  fetchTicketStatus(visitorToken: string): Promise<TicketStatusData>;
@@ -34,12 +41,16 @@ declare interface ApiClientOptions {
34
41
  apiKey: string;
35
42
  /** Abort a request that has not responded within this many milliseconds. */
36
43
  timeoutMs?: number;
44
+ /** Abort a file upload that has not completed within this many milliseconds. */
45
+ uploadTimeoutMs?: number;
37
46
  }
38
47
 
39
48
  export { ApiError }
40
49
 
41
50
  export { ApiResponse }
42
51
 
52
+ export { ChatAttachment }
53
+
43
54
  export { ChatbotBlockReason }
44
55
 
45
56
  export declare class ChatbotCore {
@@ -57,6 +68,8 @@ export declare class ChatbotCore {
57
68
  * before a ticket exists.
58
69
  */
59
70
  private hasActiveTicket;
71
+ /** Pending readiness re-check while the server is unreachable. */
72
+ private retryTimer;
60
73
  /** Server id of the last `message:receive` push rendered as an agent bubble. */
61
74
  private lastPushId;
62
75
  /**
@@ -79,8 +92,19 @@ export declare class ChatbotCore {
79
92
  private syncWidgetMode;
80
93
  init(options: ChatbotInitOptions): Promise<void>;
81
94
  /**
82
- * Maps `/sdk/config` failures: missing Connected Channels becomes `no-agent`,
83
- * other 403s show the API message, and 401/network stay as `state.error`.
95
+ * Asks `/sdk/config` whether the server is up and the agent can reply, and
96
+ * shows the widget only when both hold. An unreachable server is retried on
97
+ * READINESS_RETRY_DELAYS_MS; a configuration problem is final for this page.
98
+ * `ready` fires once the outcome is settled either way.
99
+ */
100
+ private checkReadiness;
101
+ /** Creates the widget hidden; checkReadiness reveals it once every check passed. */
102
+ private mountWidget;
103
+ private clearRetry;
104
+ /**
105
+ * Maps `/sdk/config` rejections other than an unreachable server: missing
106
+ * Connected Channels becomes `no-agent`; anything else (an invalid key, a
107
+ * disallowed origin) is recorded as `state.error`.
84
108
  */
85
109
  private handleConfigError;
86
110
  private resolveVisitorGate;
@@ -106,7 +130,42 @@ export declare class ChatbotCore {
106
130
  * Escalate the open AI ticket to Unassigned. No-op unless the widget is in `ai` mode.
107
131
  */
108
132
  requestHuman(): Promise<void>;
133
+ /** The visitor token every send needs; throws when the visitor has not identified. */
134
+ private requireVisitorToken;
135
+ /** Adds the visitor's own message optimistically and marks a send in flight. */
136
+ private pushLocalMessage;
137
+ private replaceMessage;
138
+ private removeMessage;
109
139
  sendMessage(text: string): Promise<void>;
140
+ /** Records a send that never left the browser: `state.error`, the composer, and `error`. */
141
+ private rejectSend;
142
+ /**
143
+ * Sends `files` as one media message, with `text` as its caption. The bubble
144
+ * appears at once with local previews, uploads each file through the API, then
145
+ * posts the chat message the same way `sendMessage` does. Rejects when the visitor
146
+ * has not identified; a file that breaks the size or count limit is reported as
147
+ * `state.error` (and an `error` event) without sending anything.
148
+ */
149
+ sendAttachments(files: File[], text?: string): Promise<void>;
150
+ /**
151
+ * Sends a recorded voice note (from `VoiceRecorder` or your own recorder). The
152
+ * recording is re-encoded as mono WAV with a waveform where Web Audio allows,
153
+ * uploaded, and posted as a `voice` message so the inbox shows its voice player.
154
+ * Rejects when the visitor has not identified; an unusable or oversized recording is
155
+ * reported as `state.error` (and an `error` event) without sending anything.
156
+ */
157
+ sendVoice(recording: VoiceRecording): Promise<void>;
158
+ /**
159
+ * Shared tail of every file send: an optimistic `pending` bubble with local previews,
160
+ * one upload per file, then `deliver`. A failed upload removes the bubble; a failed
161
+ * chat post keeps it (the files are already stored) and records the error.
162
+ */
163
+ private uploadThenDeliver;
164
+ /**
165
+ * Posts `payload` to `/sdk/chat` and applies the outcome: the ticket now exists,
166
+ * the mode may have moved, and in `ai` mode the reply becomes a bubble.
167
+ */
168
+ private deliver;
110
169
  on<K extends keyof ChatbotEventMap>(event: K, listener: Listener<K>): () => void;
111
170
  resetSession(): void;
112
171
  open(): void;
@@ -138,6 +197,8 @@ export { ChatbotTicketMode }
138
197
 
139
198
  export { ChatMessage }
140
199
 
200
+ export { ChatMessageKind }
201
+
141
202
  export { ChatRequest }
142
203
 
143
204
  export { ChatResponseData }
@@ -176,6 +237,12 @@ export declare const OnedeskProChatbot: {
176
237
  */
177
238
  export declare function resolveSdkSocketUrl(baseUrl: string): string;
178
239
 
240
+ /** Most attachments one chat message may carry. */
241
+ export declare const SDK_CHAT_MAX_ATTACHMENTS = 10;
242
+
243
+ /** Largest file `POST /sdk/upload` accepts, in bytes (10 MB). */
244
+ export declare const SDK_UPLOAD_MAX_BYTES: number;
245
+
179
246
  export { SdkConfigResponse }
180
247
 
181
248
  /**
@@ -217,6 +284,62 @@ export declare class SessionManager {
217
284
 
218
285
  export { TicketStatusData }
219
286
 
287
+ export { UploadAttachmentResponseData }
288
+
220
289
  export { VisitorVerifyResponse }
221
290
 
291
+ /** Longest voice note the widget records before stopping on its own. */
292
+ export declare const VOICE_MAX_DURATION_SECONDS = 300;
293
+
294
+ /**
295
+ * Records a voice note with `MediaRecorder`. Framework-independent: the widget uses it,
296
+ * and custom UIs built on `ChatbotCore` can too. `destroy()` releases the microphone,
297
+ * timers and audio context; nothing is left running once it returns.
298
+ */
299
+ export declare class VoiceRecorder {
300
+ private readonly onChange;
301
+ private readonly maxDurationSeconds;
302
+ private recorder;
303
+ private stream;
304
+ private chunks;
305
+ private mimeType;
306
+ private startedAt;
307
+ private tickTimer;
308
+ private levelTimer;
309
+ private maxTimer;
310
+ private audioContext;
311
+ private analyser;
312
+ private snapshot;
313
+ constructor(onChange: (snapshot: VoiceRecorderSnapshot) => void, maxDurationSeconds?: number);
314
+ static isSupported(): boolean;
315
+ getSnapshot(): VoiceRecorderSnapshot;
316
+ /** Asks for the microphone and starts recording. Rejects with a visitor-facing message. */
317
+ start(): Promise<void>;
318
+ /** Stops recording and moves to `preview`. Resolves with the recording, or null if none. */
319
+ stop(): Promise<VoiceRecording | null>;
320
+ /** Discards the recording (or the one in preview) and returns to `idle`. */
321
+ cancel(): void;
322
+ destroy(): void;
323
+ private update;
324
+ private elapsedMs;
325
+ private startLevelMeter;
326
+ private clearTimers;
327
+ private releaseMedia;
328
+ private release;
329
+ }
330
+
331
+ export declare interface VoiceRecorderSnapshot {
332
+ state: VoiceRecorderState;
333
+ /** Whole seconds recorded so far (or the final length in `preview`). */
334
+ elapsedSeconds: number;
335
+ /** Microphone loudness 0–1 while recording, 0 otherwise. */
336
+ level: number;
337
+ /** The finished recording while in `preview`. */
338
+ result: VoiceRecording | null;
339
+ }
340
+
341
+ export declare type VoiceRecorderState = 'idle' | 'recording' | 'preview';
342
+
343
+ export { VoiceRecording }
344
+
222
345
  export { }