@onedeskpro/chatbot-core 0.1.0 → 0.2.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @onedeskpro/chatbot-core
2
2
 
3
- Framework-independent core for the [Onedesk Pro](https://onedeskpro.com) chatbot. Ships the chat engine, the session manager, the API client, and a self-contained widget you can drop into any page — no framework required.
3
+ Framework-independent core for the [Onedesk Pro](https://onedeskpro.com) chatbot. Ships the chat engine, visitor identification, AI-to-human handoff, the API and socket clients, and a self-contained widget you can drop into any page — no framework required.
4
4
 
5
5
  Using React? Install [`@onedeskpro/chatbot-react`](https://www.npmjs.com/package/@onedeskpro/chatbot-react) instead.
6
6
 
@@ -28,7 +28,52 @@ await chatbot.init({
28
28
  });
29
29
  ```
30
30
 
31
- `init` mounts the widget and connects to the Onedesk Pro API. Only `apiKey` is required.
31
+ `init` connects to the Onedesk Pro API and adds the widget to the page once the agent can reply. Only `apiKey` is required — use the publishable workspace API key, never a server secret.
32
+
33
+ ### When the widget appears
34
+
35
+ Nothing is added to the page straight away. `init` first checks that the Onedesk Pro server is reachable and that the agent is ready to reply, and the launcher appears only once both hold and a returning visitor's identity has been checked:
36
+
37
+ | Situation | `blockReason` | What happens |
38
+ | --- | --- | --- |
39
+ | Ready | `null` | The launcher appears (and the panel opens, with `autoOpen`). |
40
+ | The server cannot be reached, times out, or answers with a 5xx | `server-unavailable` | Stays hidden and checks again after 5, 15, 30 and 60 seconds, then gives up until the next page load. |
41
+ | The agent has no system prompt or no knowledge base | `no-prompt`, `no-collections` | Stays hidden. |
42
+ | The platform's AI models are not configured | `ai-unavailable` | Stays hidden. |
43
+ | The workspace has used its AI token budget | `no-credits` | Stays hidden. |
44
+ | No agent is assigned to the Website channel | `no-agent` | Stays hidden. |
45
+ | The API key is rejected or the site's origin is not allowed | `null`, with `error` set | Stays hidden. |
46
+
47
+ `init` resolves after the first check, and the `ready` event fires once the outcome is settled: when the widget appears, when a configuration problem rules it out, or when the last retry fails. A custom UI built on the state can show `blockReason` to explain why chat is unavailable.
48
+
49
+ ### Visitor identification
50
+
51
+ A visitor must identify with a name and phone number before chatting. The widget shows its own form for this (name, phone with a country picker, optional email), so with the built-in UI there is nothing to wire up.
52
+
53
+ On success the API returns a visitor token. The SDK stores it and verifies it on the next `init`, so a returning visitor goes straight to the chat. While `getState().needsIdentify` is `true`, nothing is sent and `sendMessage` rejects.
54
+
55
+ If you build your own UI, collect the details yourself and call `submitIdentify`:
56
+
57
+ ```ts
58
+ await chatbot.submitIdentify({
59
+ name: 'Ada Lovelace',
60
+ phone: '+8801712345678', // international format, with country code
61
+ email: 'ada@example.com', // optional
62
+ });
63
+ ```
64
+
65
+ ### Human handoff
66
+
67
+ Every conversation runs in one of four modes, exposed as `getState().mode`:
68
+
69
+ | Mode | Meaning |
70
+ | --- | --- |
71
+ | `ai` | The AI agent is answering. This is the default. |
72
+ | `waiting` | A human was requested and no agent has picked the conversation up yet. |
73
+ | `human` | A human agent is replying. Their messages arrive live with `type: 'agent'`. |
74
+ | `closed` | The conversation was closed. Sending is disabled until `resetSession()`. |
75
+
76
+ The widget shows a "Request human agent" control once a conversation has started, and a banner for the `waiting`, `human`, and `closed` modes. From your own UI call `requestHuman()`. The mode also changes on its own — when the AI escalates, an agent takes over, hands back to the AI, or closes the conversation — so follow the `ticket-status` or `state-change` event rather than assuming the result of your own call.
32
77
 
33
78
  ### Script tag / CDN
34
79
 
@@ -50,12 +95,14 @@ The IIFE build exposes a `window.OnedeskProChatbot` global:
50
95
  | Method | Description |
51
96
  | --- | --- |
52
97
  | `init(options)` | Mounts the widget and loads remote config. Returns a promise. |
53
- | `sendMessage(text)` | Sends a message and appends the reply. Returns a promise. |
98
+ | `submitIdentify({ name, phone, email? })` | Identifies the visitor and unlocks the chat. Returns a promise. |
99
+ | `sendMessage(text)` | Sends a message and, in `ai` mode, appends the reply. Returns a promise that rejects if the visitor has not identified. |
100
+ | `requestHuman()` | Escalates the conversation to a human agent. Does nothing unless the mode is `ai` and a conversation has started. Returns a promise. |
54
101
  | `open()` / `close()` / `toggle()` | Control widget visibility. |
55
- | `resetSession()` | Clears the conversation and starts a new session. |
102
+ | `resetSession()` | Clears a `closed` conversation so the visitor can start a new one. Does nothing in any other mode. |
56
103
  | `getState()` | Returns a readonly `ChatbotState` snapshot. |
57
104
  | `on(event, listener)` | Subscribes to an event. Returns an unsubscribe function. |
58
- | `destroy()` | Unmounts the widget and releases listeners. |
105
+ | `destroy()` | Unmounts the widget, disconnects the socket, and cancels any in-flight `init`. |
59
106
 
60
107
  ### Options — `ChatbotInitOptions`
61
108
 
@@ -70,19 +117,37 @@ The IIFE build exposes a `window.OnedeskProChatbot` global:
70
117
  | `welcomeMessage` | `string` | — |
71
118
  | `placeholder` | `string` | — |
72
119
  | `autoOpen` | `boolean` | `false` |
73
- | `sessionId` | `string` | generated and persisted |
74
120
  | `requestTimeoutMs` | `number` | `30000` |
75
121
 
122
+ `sessionId` is deprecated and ignored: visitor tokens replace client session ids.
123
+
124
+ ### State — `ChatbotState`
125
+
126
+ | Field | Type | Meaning |
127
+ | --- | --- | --- |
128
+ | `isOpen` | `boolean` | The panel is showing. |
129
+ | `isLoading` | `boolean` | A send, identify, or human request is in flight. |
130
+ | `isReady` | `boolean` | The server answered and the agent can reply; the widget is on the page. |
131
+ | `needsIdentify` | `boolean` | The visitor has not identified yet. |
132
+ | `blockReason` | `ChatbotBlockReason` | Why the agent cannot answer, or `null`. See [When the widget appears](#when-the-widget-appears). |
133
+ | `messages` | `ChatMessage[]` | The conversation so far. `message.type` is `'human'`, `'ai'`, or `'agent'`. |
134
+ | `visitorToken` | `string \| null` | The identified visitor's token. |
135
+ | `visitorName` | `string \| null` | The identified visitor's name. |
136
+ | `mode` | `ChatbotTicketMode` | `'ai'`, `'waiting'`, `'human'`, or `'closed'`. |
137
+ | `error` | `string \| null` | The last error message. |
138
+
76
139
  ### Events — `ChatbotEventMap`
77
140
 
78
141
  | Event | Payload | Fires when |
79
142
  | --- | --- | --- |
80
- | `message` | `ChatMessage` | A message is added — human and AI alike. |
143
+ | `message` | `ChatMessage` | A message is added — visitor, AI, and human agent alike. |
81
144
  | `state-change` | `ChatbotState` | Any state changes, including `isLoading` while a reply is in flight. |
82
- | `ready` | — | Init finished and readiness has been checked. |
145
+ | `ready` | — | The readiness check settled: the widget appeared, or it will not (see `blockReason` and `error`). |
83
146
  | `open` / `close` | — | The panel is shown or hidden. |
84
- | `error` | `Error` | A send failed, including on timeout. |
85
- | `session-reset` | — | The conversation was cleared. |
147
+ | `ticket-status` | `TicketStatusData` | The mode changed — on restore, after a send, or pushed live. |
148
+ | `human-requested` | — | `requestHuman()` succeeded. |
149
+ | `error` | `Error` | A send, identify, or human request failed (including on timeout), or the live connection could not be established. |
150
+ | `session-reset` | — | A closed conversation was cleared. |
86
151
 
87
152
  Prefer `state-change` when you are mirroring state into your own UI — it is the only event that covers every transition.
88
153
 
@@ -93,13 +158,29 @@ off(); // unsubscribe
93
158
 
94
159
  ## Also exported
95
160
 
96
- `ApiClient`, `EventEmitter`, `SessionManager`, `DEFAULT_API_BASE_URL`, `DEFAULT_REQUEST_TIMEOUT_MS`, the `ChatbotRequestError` type, and every type from `@onedeskpro/chatbot-types`.
161
+ `ApiClient`, `SdkSocket`, `resolveSdkSocketUrl`, `EventEmitter`, `SessionManager`, `isChatbotRequestError`, `DEFAULT_API_BASE_URL`, `DEFAULT_REQUEST_TIMEOUT_MS`, the `ChatbotRequestError` and `SdkSocketConnectOptions` types, and every type from `@onedeskpro/chatbot-types`.
162
+
163
+ `SessionManager` is deprecated. It is now the visitor token store and is kept only so existing imports keep resolving.
97
164
 
98
165
  ## Notes
99
166
 
100
- Requests abort after `requestTimeoutMs` (30s by default) and surface as an `error` event with `code: 'TIMEOUT'`, so a hung network never leaves the widget stuck. Errors thrown by the client carry `status` and a structured `apiError`.
167
+ Requests abort after `requestTimeoutMs` (30s by default) and surface as an `error` event with `code: 'TIMEOUT'`, so a hung network never leaves the widget stuck. Errors thrown by the client carry `status` and a structured `apiError`; narrow them with `isChatbotRequestError`.
168
+
169
+ The visitor token persists in `localStorage`, scoped per agent, where storage is available and falls back to in-memory when it is not — private browsing, blocked site data, or a sandboxed iframe. A token the API no longer accepts is discarded and the visitor is asked to identify again.
170
+
171
+ Once the visitor has identified, the SDK opens a Socket.IO connection to the API for live mode changes and human agent messages. It reconnects on its own and re-reads the mode when it does.
172
+
173
+ Earlier messages are not restored on reload. A returning visitor keeps their identity and mode but starts with an empty message list.
174
+
175
+ ## Upgrading from 0.1
176
+
177
+ 0.2.0 is a breaking release. The API no longer accepts the `sessionId`-based chat requests that 0.1 sends, so 0.1 cannot chat against the current API.
101
178
 
102
- Session ids persist in `localStorage` where it is available and fall back to in-memory when it is not — private browsing, blocked site data, or a sandboxed iframe.
179
+ - With the built-in widget, upgrading is enough: the identify form and handoff controls are included.
180
+ - With a custom UI, add an identify step (`needsIdentify` and `submitIdentify`) before the first `sendMessage`, and render `'agent'` messages alongside `'human'` and `'ai'`.
181
+ - `ChatbotState.sessionId` is replaced by `visitorToken`, and the `sessionId` init option is ignored.
182
+ - `ApiClient.fetchHistory` is removed.
183
+ - `resetSession()` now only clears a `closed` conversation.
103
184
 
104
185
  ## License
105
186