@primexperts.co/pulse-agent 5.1.0 → 5.2.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/README.md +401 -53
- package/docs/CHANGELOG.md +31 -0
- package/docs/FAQ.md +58 -0
- package/docs/IMPLEMENTATION-GUIDE.md +309 -0
- package/docs/INTEGRATION-CHANNELS.md +143 -0
- package/docs/TROUBLESHOOTING.md +86 -0
- package/package.json +37 -36
package/README.md
CHANGED
|
@@ -1,97 +1,445 @@
|
|
|
1
1
|
# @primexperts.co/pulse-agent
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Pulse Agent is a browser-only customer support widget for adding Pulse Webchat and optional website error reporting to any public website, SPA, or client-rendered application.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It is designed for teams that want one lightweight install to do two jobs:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
- Sends visitor messages over public REST endpoints and receives agent replies over Server-Sent Events.
|
|
10
|
-
- Supports optional pre-chat profile capture, conversation history loading, transcript email requests, and manual open/close controls.
|
|
11
|
-
- Works with Angular, React, Vue, Next.js/Nuxt client components, static sites, and plain browser JavaScript.
|
|
7
|
+
- Add a floating Pulse chat launcher to a website.
|
|
8
|
+
- Report browser errors and failed API calls back to Pulse when error monitoring is enabled.
|
|
12
9
|
|
|
13
|
-
|
|
10
|
+
The package is framework-agnostic. It works with Angular, React, Vue, static HTML, and SSR frameworks when initialized on the client side.
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
14
13
|
|
|
15
14
|
```bash
|
|
16
|
-
npm install
|
|
15
|
+
npm install @primexperts.co/pulse-agent@latest
|
|
17
16
|
```
|
|
18
17
|
|
|
19
|
-
## Usage
|
|
20
|
-
|
|
21
18
|
```ts
|
|
22
19
|
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
23
20
|
|
|
24
21
|
const agent = createPulseAgent({
|
|
25
|
-
slug: '
|
|
22
|
+
slug: 'your-organization-slug',
|
|
23
|
+
appKey: 'app_your_public_application_key',
|
|
26
24
|
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
25
|
+
title: 'Support',
|
|
27
26
|
requireProfile: true,
|
|
28
|
-
autoOpen: false
|
|
27
|
+
autoOpen: false,
|
|
28
|
+
errorMonitoring: true,
|
|
29
|
+
captureUnhandledErrors: true,
|
|
30
|
+
captureUnhandledRejections: true,
|
|
31
|
+
captureFetchErrors: true,
|
|
32
|
+
environment: 'production',
|
|
33
|
+
release: 'web-1.0.0'
|
|
29
34
|
});
|
|
30
35
|
|
|
31
|
-
// optional
|
|
32
36
|
agent.open();
|
|
33
37
|
```
|
|
34
38
|
|
|
35
|
-
##
|
|
39
|
+
## What You Need From Pulse
|
|
40
|
+
|
|
41
|
+
You need these values before going live:
|
|
42
|
+
|
|
43
|
+
| Value | Example | Required | Where it comes from |
|
|
44
|
+
| --- | --- | --- | --- |
|
|
45
|
+
| Organization slug | `vayakids` | Yes | Pulse organization/webchat setup |
|
|
46
|
+
| Application key | `app_...` | Recommended | Pulse Dashboard application/webchat setup |
|
|
47
|
+
| API base URL | `https://pulse.service.primexperts.co.za` | Yes | Pulse production API host |
|
|
48
|
+
| Allowed website origin | `https://www.example.com` | Yes | Must be allowed by Pulse CORS/backend configuration |
|
|
49
|
+
|
|
50
|
+
You usually do not need a widget token. The widget resolves it automatically by calling Pulse with your `slug` and `appKey`.
|
|
51
|
+
|
|
52
|
+
## Configuration Keys
|
|
53
|
+
|
|
54
|
+
| Option | Type | Default | Description |
|
|
55
|
+
| --- | --- | --- | --- |
|
|
56
|
+
| `slug` | `string` | Required | Public organization slug used to resolve the active webchat widget. |
|
|
57
|
+
| `appKey` | `string` | Optional but recommended | Public application key, normally starts with `app_`. Use this for application-specific setup and error attribution. |
|
|
58
|
+
| `appSlug` | `string` | Optional | Alternative application identifier when an app key is not available. |
|
|
59
|
+
| `apiBaseUrl` | `string` | `https://pulse.service.primexperts.co.za` | Pulse API host only. Do not include `/api/...` paths. |
|
|
60
|
+
| `title` | `string` | Organization/app name | Chat panel title. |
|
|
61
|
+
| `mount` | `HTMLElement \| string` | `document.body` | Element or selector where the widget root should be mounted. |
|
|
62
|
+
| `autoOpen` | `boolean` | `false` | Opens the chat panel immediately after initialization. |
|
|
63
|
+
| `requireProfile` | `boolean` | `true` | Requires visitor name/email before first message. |
|
|
64
|
+
| `followUpEmailTo` | `string` | Optional | Destination used by transcript/follow-up email actions. |
|
|
65
|
+
| `dashboardUrl` | `string` | `https://pulse.primexperts.co.za` | Dashboard link used in setup/error states. |
|
|
66
|
+
| `dashboardSetupPath` | `string` | `/integrations` | Dashboard path linked when setup is incomplete. |
|
|
67
|
+
| `whatsappUrl` | `string` | Optional | Adds a WhatsApp launcher alongside Pulse Chat. |
|
|
68
|
+
| `widgetToken` | `string` | Optional | Advanced bypass for resolve flow. Leave unset unless Pulse gives you a specific token. |
|
|
69
|
+
| `errorMonitoring` | `boolean` | `false` | Enables browser error reporting. Must be `true` before any capture happens. |
|
|
70
|
+
| `captureUnhandledErrors` | `boolean` | `true` when monitoring is enabled | Captures `window.onerror` events. |
|
|
71
|
+
| `captureUnhandledRejections` | `boolean` | `true` when monitoring is enabled | Captures unhandled promise rejections. |
|
|
72
|
+
| `captureFetchErrors` | `boolean` | `true` when monitoring is enabled | Wraps browser `fetch` to report failed requests and thrown network errors. |
|
|
73
|
+
| `environment` | `string` | Optional | Environment label such as `production`, `staging`, or `development`. |
|
|
74
|
+
| `release` | `string` | Optional | Application release/version label for error context. |
|
|
75
|
+
|
|
76
|
+
## Environment Variables
|
|
77
|
+
|
|
78
|
+
Pulse Agent itself receives JavaScript options. For deployed apps, put values in your platform environment and generate or serve a runtime config file that passes those values to `createPulseAgent`.
|
|
79
|
+
|
|
80
|
+
Recommended names:
|
|
81
|
+
|
|
82
|
+
```env
|
|
83
|
+
PULSE_AGENT_SLUG=your-organization-slug
|
|
84
|
+
PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
85
|
+
PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
86
|
+
PULSE_AGENT_TITLE=Support
|
|
87
|
+
PULSE_AGENT_ENVIRONMENT=production
|
|
88
|
+
PULSE_AGENT_RELEASE=web-1.0.0
|
|
89
|
+
|
|
90
|
+
PULSE_AGENT_ERROR_MONITORING=true
|
|
91
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
92
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
93
|
+
PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Optional names:
|
|
97
|
+
|
|
98
|
+
```env
|
|
99
|
+
PULSE_AGENT_FOLLOW_UP_EMAIL_TO=support@example.com
|
|
100
|
+
PULSE_AGENT_DASHBOARD_URL=https://pulse.primexperts.co.za
|
|
101
|
+
PULSE_AGENT_DASHBOARD_SETUP_PATH=/integrations
|
|
102
|
+
PULSE_AGENT_AUTO_OPEN=false
|
|
103
|
+
PULSE_AGENT_REQUIRE_PROFILE=true
|
|
104
|
+
PULSE_AGENT_WHATSAPP_URL=https://api.whatsapp.com/send?phone=27123456789
|
|
105
|
+
PULSE_AGENT_WIDGET_TOKEN=
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Leave `PULSE_AGENT_WIDGET_TOKEN` unset unless Pulse Support explicitly gives you one. It is not the `app_*` key.
|
|
109
|
+
|
|
110
|
+
## Heroku Config Vars
|
|
111
|
+
|
|
112
|
+
Set these in Heroku under Settings -> Config Vars, or with the Heroku CLI:
|
|
113
|
+
|
|
114
|
+
```bash
|
|
115
|
+
heroku config:set PULSE_AGENT_SLUG=your-organization-slug
|
|
116
|
+
heroku config:set PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
117
|
+
heroku config:set PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
118
|
+
heroku config:set PULSE_AGENT_TITLE=Support
|
|
119
|
+
heroku config:set PULSE_AGENT_ENVIRONMENT=production
|
|
120
|
+
heroku config:set PULSE_AGENT_ERROR_MONITORING=true
|
|
121
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
122
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
123
|
+
heroku config:set PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
If your app uses a `runtime-config.js` file, make sure Heroku serves that file from environment values at request time or regenerates it during build/startup.
|
|
127
|
+
|
|
128
|
+
## Runtime Config Pattern
|
|
129
|
+
|
|
130
|
+
A common production-safe pattern is to load `/runtime-config.js` before your app bundle:
|
|
131
|
+
|
|
132
|
+
```html
|
|
133
|
+
<script src="/runtime-config.js"></script>
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Example generated file:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
window.__APP_RUNTIME_CONFIG__ = {
|
|
140
|
+
pulseAgent: {
|
|
141
|
+
slug: 'your-organization-slug',
|
|
142
|
+
appKey: 'app_your_public_application_key',
|
|
143
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
144
|
+
title: 'Support',
|
|
145
|
+
errorMonitoring: true,
|
|
146
|
+
captureUnhandledErrors: true,
|
|
147
|
+
captureUnhandledRejections: true,
|
|
148
|
+
captureFetchErrors: true,
|
|
149
|
+
environment: 'production'
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Then initialize in your app entry point:
|
|
155
|
+
|
|
156
|
+
```ts
|
|
157
|
+
import { createPulseAgent, type PulseAgentOptions } from '@primexperts.co/pulse-agent';
|
|
158
|
+
|
|
159
|
+
declare global {
|
|
160
|
+
interface Window {
|
|
161
|
+
__APP_RUNTIME_CONFIG__?: {
|
|
162
|
+
pulseAgent?: Partial<PulseAgentOptions>;
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const config = window.__APP_RUNTIME_CONFIG__?.pulseAgent;
|
|
168
|
+
|
|
169
|
+
if (config?.slug) {
|
|
170
|
+
createPulseAgent({
|
|
171
|
+
...config,
|
|
172
|
+
slug: config.slug
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Browser/CDN Usage
|
|
178
|
+
|
|
179
|
+
Use this when you cannot install npm packages:
|
|
36
180
|
|
|
37
181
|
```html
|
|
38
182
|
<script src="https://unpkg.com/@primexperts.co/pulse-agent@latest/dist/browser/pulse-agent.global.js"></script>
|
|
39
183
|
<script>
|
|
40
|
-
|
|
41
|
-
slug: '
|
|
42
|
-
|
|
184
|
+
window.PulseAgent.createPulseAgent({
|
|
185
|
+
slug: 'your-organization-slug',
|
|
186
|
+
appKey: 'app_your_public_application_key',
|
|
187
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
188
|
+
title: 'Support',
|
|
189
|
+
errorMonitoring: true
|
|
43
190
|
});
|
|
44
191
|
</script>
|
|
45
192
|
```
|
|
46
193
|
|
|
47
|
-
##
|
|
194
|
+
## Framework Examples
|
|
195
|
+
|
|
196
|
+
### Angular
|
|
197
|
+
|
|
198
|
+
Initialize in `main.ts` or a browser-only root component. For SSR, guard against server execution.
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
202
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
203
|
+
import { AppComponent } from './app/app.component';
|
|
204
|
+
|
|
205
|
+
if (typeof window !== 'undefined') {
|
|
206
|
+
createPulseAgent({
|
|
207
|
+
slug: 'your-organization-slug',
|
|
208
|
+
appKey: 'app_your_public_application_key',
|
|
209
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
210
|
+
errorMonitoring: true
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
bootstrapApplication(AppComponent);
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### React
|
|
218
|
+
|
|
219
|
+
```tsx
|
|
220
|
+
import { useEffect } from 'react';
|
|
221
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
48
222
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
223
|
+
export function PulseAgentBootstrap() {
|
|
224
|
+
useEffect(() => {
|
|
225
|
+
const agent = createPulseAgent({
|
|
226
|
+
slug: 'your-organization-slug',
|
|
227
|
+
appKey: 'app_your_public_application_key',
|
|
228
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
229
|
+
errorMonitoring: true
|
|
230
|
+
});
|
|
54
231
|
|
|
55
|
-
|
|
232
|
+
return () => agent.destroy();
|
|
233
|
+
}, []);
|
|
56
234
|
|
|
57
|
-
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
```
|
|
58
238
|
|
|
59
|
-
|
|
60
|
-
- `slug` (required): public organization slug.
|
|
61
|
-
- `apiBaseUrl` (optional): defaults to `https://pulse.service.primexperts.co.za`.
|
|
62
|
-
- `followUpEmailTo` (optional): preferred destination for transcript follow-up emails.
|
|
63
|
-
- `mount` (optional): container element or selector, defaults to `document.body`.
|
|
64
|
-
- `autoOpen` (optional): open panel immediately.
|
|
65
|
-
- `requireProfile` (optional): requires name/email before first message, default `true`.
|
|
66
|
-
- `widgetToken` (optional): bypass slug resolution.
|
|
67
|
-
- `title` (optional): panel title.
|
|
239
|
+
### Vue
|
|
68
240
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
|
|
73
|
-
|
|
241
|
+
```ts
|
|
242
|
+
import { onBeforeUnmount, onMounted } from 'vue';
|
|
243
|
+
import { createPulseAgent, type PulseAgentHandle } from '@primexperts.co/pulse-agent';
|
|
244
|
+
|
|
245
|
+
let agent: PulseAgentHandle | null = null;
|
|
246
|
+
|
|
247
|
+
onMounted(() => {
|
|
248
|
+
agent = createPulseAgent({
|
|
249
|
+
slug: 'your-organization-slug',
|
|
250
|
+
appKey: 'app_your_public_application_key',
|
|
251
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
252
|
+
errorMonitoring: true
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
onBeforeUnmount(() => agent?.destroy());
|
|
257
|
+
```
|
|
74
258
|
|
|
75
|
-
##
|
|
259
|
+
## How Widget Resolution Works
|
|
76
260
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
261
|
+
At startup or first send, Pulse Agent calls:
|
|
262
|
+
|
|
263
|
+
```text
|
|
264
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>&appKey=<app_...>
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Pulse returns the active widget configuration, including an internal `widgetToken`. The widget then uses that token for chat, history, streaming, transcript email, and error reporting.
|
|
268
|
+
|
|
269
|
+
Do not confuse these values:
|
|
270
|
+
|
|
271
|
+
| Name | Format | Purpose | User action |
|
|
272
|
+
| --- | --- | --- | --- |
|
|
273
|
+
| `appKey` | `app_...` | Public application key from Pulse Dashboard | Put in config/env. |
|
|
274
|
+
| `widgetToken` | Token generated by Pulse | Internal public webchat token used by endpoints | Usually leave unset. |
|
|
275
|
+
| `slug` | human-readable slug | Identifies organization | Put in config/env. |
|
|
276
|
+
|
|
277
|
+
## Error Monitoring
|
|
278
|
+
|
|
279
|
+
Error monitoring is opt-in. Installing the package does not capture anything until `errorMonitoring: true` is passed to `createPulseAgent`.
|
|
280
|
+
|
|
281
|
+
When enabled, Pulse Agent can capture:
|
|
282
|
+
|
|
283
|
+
- Unhandled JavaScript errors from `window.onerror`.
|
|
284
|
+
- Unhandled promise rejections from `window.onunhandledrejection`.
|
|
285
|
+
- Failed `fetch` responses, including HTTP statuses from failed API calls.
|
|
286
|
+
- Network errors thrown by `fetch`.
|
|
287
|
+
- Manual error reports through `agent.captureException(...)`.
|
|
288
|
+
|
|
289
|
+
Manual capture example:
|
|
290
|
+
|
|
291
|
+
```ts
|
|
292
|
+
try {
|
|
293
|
+
await saveOrder();
|
|
294
|
+
} catch (error) {
|
|
295
|
+
agent.captureException(error, {
|
|
296
|
+
source: 'checkout.saveOrder',
|
|
297
|
+
errorType: 'checkout-error',
|
|
298
|
+
endpoint: '/api/orders',
|
|
299
|
+
pageUrl: window.location.href
|
|
300
|
+
});
|
|
301
|
+
throw error;
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
Report count example:
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
const reportsLastSevenDays = agent.getErrorReportCount(7);
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### What Error Monitoring Does Not Do
|
|
312
|
+
|
|
313
|
+
Pulse Agent does not:
|
|
314
|
+
|
|
315
|
+
- Catch errors before the widget is initialized.
|
|
316
|
+
- Catch server-side errors unless those errors are exposed to the browser as failed requests.
|
|
317
|
+
- Replace backend logging, APM, or infrastructure monitoring.
|
|
318
|
+
- Read private app state, passwords, tokens, or request bodies intentionally.
|
|
319
|
+
- Automatically fix errors.
|
|
320
|
+
- Capture errors if `errorMonitoring` is missing or `false`.
|
|
321
|
+
|
|
322
|
+
## Public Backend Endpoints
|
|
323
|
+
|
|
324
|
+
The widget expects these Pulse endpoints:
|
|
325
|
+
|
|
326
|
+
```text
|
|
327
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>&appKey=<appKey>
|
|
328
|
+
POST /api/pulse/public/webchat/{widgetToken}/message
|
|
329
|
+
GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<id>
|
|
330
|
+
POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<id>
|
|
331
|
+
GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>
|
|
332
|
+
POST /api/pulse/public/webchat/{widgetToken}/errors
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
Admin setup endpoints are separate and should remain authenticated.
|
|
336
|
+
|
|
337
|
+
## Benefits
|
|
338
|
+
|
|
339
|
+
- One package for webchat and optional browser error monitoring.
|
|
340
|
+
- Framework-agnostic browser integration.
|
|
341
|
+
- Works with npm or a script tag.
|
|
342
|
+
- Supports runtime configuration, which is useful for Heroku, Docker, static hosting, and multi-environment deployments.
|
|
343
|
+
- Uses `slug` + `appKey` so users do not need to handle internal widget tokens.
|
|
344
|
+
- Supports visitor profile capture, history loading, transcript email requests, SSE replies, WhatsApp launcher, manual open/close, and manual exception reporting.
|
|
345
|
+
|
|
346
|
+
## Limitations
|
|
347
|
+
|
|
348
|
+
- Browser-only. Initialize after mount/hydration in SSR frameworks.
|
|
349
|
+
- Requires the website origin to be allowed by Pulse CORS configuration.
|
|
350
|
+
- Requires an active Pulse Webchat integration for the organization/application.
|
|
351
|
+
- Requires `fetch` and `EventSource` support for full behavior.
|
|
352
|
+
- SSE can be affected by proxies, corporate networks, browser extensions, and load balancer timeouts.
|
|
353
|
+
- Error monitoring starts only after initialization and only when enabled.
|
|
354
|
+
- `fetch` monitoring covers `window.fetch`; it does not automatically wrap Axios internals unless Axios uses `fetch` in that environment.
|
|
355
|
+
- `widgetToken` is an advanced bypass and should not be used unless Pulse explicitly provides it.
|
|
356
|
+
|
|
357
|
+
## Production Checklist
|
|
358
|
+
|
|
359
|
+
Before publishing a site with Pulse Agent:
|
|
360
|
+
|
|
361
|
+
1. Confirm Pulse Webchat is enabled in the Pulse Dashboard.
|
|
362
|
+
2. Confirm you have the correct `slug`.
|
|
363
|
+
3. Confirm you have the correct `appKey` beginning with `app_`.
|
|
364
|
+
4. Confirm `apiBaseUrl` is `https://pulse.service.primexperts.co.za`.
|
|
365
|
+
5. Confirm production origin is allowed by Pulse CORS configuration.
|
|
366
|
+
6. Confirm `runtime-config.js` or app config is generated from deployment env values.
|
|
367
|
+
7. Confirm `errorMonitoring` is `true` if you expect browser error reporting.
|
|
368
|
+
8. Open the site and check browser network calls for `resolve`, `message`, `stream`, and `errors` when applicable.
|
|
369
|
+
9. Send a test chat message.
|
|
370
|
+
10. Trigger a test error in a non-production or controlled environment and confirm it appears in Pulse.
|
|
371
|
+
|
|
372
|
+
## Handle API
|
|
373
|
+
|
|
374
|
+
`createPulseAgent(options)` returns:
|
|
375
|
+
|
|
376
|
+
| Method | Description |
|
|
377
|
+
| --- | --- |
|
|
378
|
+
| `open()` | Opens the chat panel. |
|
|
379
|
+
| `close()` | Closes the chat panel. |
|
|
380
|
+
| `destroy()` | Removes DOM, listeners, and fetch wrapping installed by this instance. |
|
|
381
|
+
| `resetConversation()` | Starts a fresh local conversation. |
|
|
382
|
+
| `update(partialOptions)` | Updates runtime options such as title, WhatsApp URL, or widget token. |
|
|
383
|
+
| `captureException(error, context)` | Manually reports an error when monitoring is enabled. |
|
|
384
|
+
| `getErrorReportCount(days)` | Returns locally remembered successful error report count for the last N days. |
|
|
385
|
+
|
|
386
|
+
## Troubleshooting
|
|
387
|
+
|
|
388
|
+
### The widget does not appear
|
|
389
|
+
|
|
390
|
+
Check that initialization runs in the browser, the `slug` is present, and the mount selector exists.
|
|
391
|
+
|
|
392
|
+
### `Failed to resolve widget keys (401/403)`
|
|
393
|
+
|
|
394
|
+
The public resolve endpoint is protected or the key is not accepted. Confirm the Pulse public webchat routes are accessible and the `appKey` is correct.
|
|
395
|
+
|
|
396
|
+
### `Failed to resolve widget keys (404)`
|
|
397
|
+
|
|
398
|
+
The slug is wrong, webchat is not enabled, or the selected application has no active widget.
|
|
399
|
+
|
|
400
|
+
### CORS error in the browser console
|
|
401
|
+
|
|
402
|
+
The website origin is missing from Pulse CORS configuration. Add the exact origin, including protocol and port.
|
|
403
|
+
|
|
404
|
+
### Chat sends but replies do not stream
|
|
405
|
+
|
|
406
|
+
Check that `EventSource` is available and that proxies/load balancers allow long-lived SSE connections.
|
|
407
|
+
|
|
408
|
+
### Errors are not captured
|
|
409
|
+
|
|
410
|
+
Confirm all of the following:
|
|
411
|
+
|
|
412
|
+
- `errorMonitoring: true` is present in runtime config.
|
|
413
|
+
- The widget successfully resolves a widget token.
|
|
414
|
+
- The error happens after `createPulseAgent(...)` runs.
|
|
415
|
+
- The browser can post to `/api/pulse/public/webchat/{widgetToken}/errors`.
|
|
416
|
+
|
|
417
|
+
## Additional Documentation
|
|
418
|
+
|
|
419
|
+
- `docs/IMPLEMENTATION-GUIDE.md` for end-to-end setup examples.
|
|
420
|
+
- `docs/TROUBLESHOOTING.md` for diagnostics.
|
|
421
|
+
- `docs/FAQ.md` for common questions.
|
|
422
|
+
- `docs/INTEGRATION-CHANNELS.md` for channel-level implementation notes.
|
|
423
|
+
|
|
424
|
+
## Build and Publish
|
|
425
|
+
|
|
426
|
+
```bash
|
|
427
|
+
npm run build
|
|
428
|
+
npm publish --access public
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
Build output includes:
|
|
432
|
+
|
|
433
|
+
- ESM and type declarations in `dist/`.
|
|
434
|
+
- Browser global bundle in `dist/browser/pulse-agent.global.js`.
|
|
83
435
|
|
|
84
436
|
## Versioning
|
|
85
437
|
|
|
86
|
-
Use the built-in version script instead of editing files manually:
|
|
438
|
+
Use the built-in version script instead of editing package files manually:
|
|
87
439
|
|
|
88
440
|
```bash
|
|
89
441
|
npm run version:patch
|
|
90
|
-
# or
|
|
91
442
|
npm run version:minor
|
|
92
443
|
npm run version:major
|
|
93
|
-
# or custom semver
|
|
94
444
|
npm run version:bump -- 1.2.3
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
This updates both `package.json` and `package-lock.json`.
|
|
445
|
+
```
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes for Pulse Agent documentation and integration behavior are listed here.
|
|
4
|
+
|
|
5
|
+
## 2026-03-02
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- `docs/INTEGRATION-CHANNELS.md` with channel-based integration documentation for:
|
|
9
|
+
- Webchat (public widget + realtime SSE flow)
|
|
10
|
+
- Email (IMAPS ingestion + scheduler behavior)
|
|
11
|
+
- WhatsApp (planned/reserved status)
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
- `README.md` documentation section now links to the integration channels guide.
|
|
15
|
+
|
|
16
|
+
## 2026-02-28
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
- `docs/IMPLEMENTATION-GUIDE.md` with end-to-end implementation instructions.
|
|
20
|
+
- `docs/FAQ.md` for common integration and deployment questions.
|
|
21
|
+
- `docs/TROUBLESHOOTING.md` with error-based diagnostics and fixes.
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Standardized API base URL guidance to:
|
|
25
|
+
- `https://pulse.service.primexperts.co.za`
|
|
26
|
+
- Removed manual organization key fallback flow from widget implementation.
|
|
27
|
+
- Updated setup behavior to rely on slug-based resolve endpoint.
|
|
28
|
+
- Updated README examples and notes to match current widget behavior.
|
|
29
|
+
|
|
30
|
+
### Notes
|
|
31
|
+
- Public webchat flow depends on backend exposing public endpoints and correct CORS allowlist.
|
package/docs/FAQ.md
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# Pulse Agent FAQ
|
|
2
|
+
|
|
3
|
+
## What is Pulse Agent?
|
|
4
|
+
|
|
5
|
+
Pulse Agent is an embeddable browser chat widget for websites. It connects to Pulse public webchat endpoints to resolve an organization and start conversations.
|
|
6
|
+
|
|
7
|
+
## Which API base URL should I use?
|
|
8
|
+
|
|
9
|
+
Use:
|
|
10
|
+
|
|
11
|
+
`https://pulse.service.primexperts.co.za`
|
|
12
|
+
|
|
13
|
+
Do not use dashboard host URLs as API base URLs.
|
|
14
|
+
|
|
15
|
+
## What slug should I use?
|
|
16
|
+
|
|
17
|
+
Use the organization slug generated from organization name (lowercase, alphanumeric, hyphen-separated).
|
|
18
|
+
Example: `PrimeXperts` -> `primexperts`
|
|
19
|
+
|
|
20
|
+
## Do users need to log in to use the widget?
|
|
21
|
+
|
|
22
|
+
For public website chat, no. Public webchat endpoints should allow anonymous access.
|
|
23
|
+
|
|
24
|
+
## Which endpoints must be public?
|
|
25
|
+
|
|
26
|
+
- `GET /api/pulse/public/webchat/resolve?slug=<slug>`
|
|
27
|
+
- `POST /api/pulse/public/webchat/{widgetToken}/message`
|
|
28
|
+
- `GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>`
|
|
29
|
+
|
|
30
|
+
## Why do I get CORS errors on localhost?
|
|
31
|
+
|
|
32
|
+
Your frontend origin is not in backend CORS allowlist. Add:
|
|
33
|
+
|
|
34
|
+
- `http://localhost:4200` (and other local ports you use)
|
|
35
|
+
|
|
36
|
+
## Does this support Angular, React, and Vue?
|
|
37
|
+
|
|
38
|
+
Yes. Any browser-based frontend can use it.
|
|
39
|
+
|
|
40
|
+
## Does this work in SSR?
|
|
41
|
+
|
|
42
|
+
Only on the client side. Initialize after mount/hydration.
|
|
43
|
+
|
|
44
|
+
## What does 401/403 from resolve mean?
|
|
45
|
+
|
|
46
|
+
The resolve endpoint is protected. For anonymous website chat, make it public.
|
|
47
|
+
|
|
48
|
+
## What does 404 from resolve mean?
|
|
49
|
+
|
|
50
|
+
No active webchat widget exists for that slug, or slug is wrong.
|
|
51
|
+
|
|
52
|
+
## What should I secure if endpoints are public?
|
|
53
|
+
|
|
54
|
+
- Rate limiting
|
|
55
|
+
- Payload size limits
|
|
56
|
+
- Input validation
|
|
57
|
+
- Anti-spam controls
|
|
58
|
+
|
|
@@ -0,0 +1,309 @@
|
|
|
1
|
+
# Pulse Agent Implementation Guide
|
|
2
|
+
|
|
3
|
+
This guide explains how to add Pulse Agent to a website, configure it from environment variables, enable browser error monitoring, and verify the integration before production release.
|
|
4
|
+
|
|
5
|
+
## 1. What Pulse Agent Does
|
|
6
|
+
|
|
7
|
+
Pulse Agent is a browser widget for public websites. It provides:
|
|
8
|
+
|
|
9
|
+
- Floating Pulse Webchat launcher.
|
|
10
|
+
- Visitor profile capture before chat, when enabled.
|
|
11
|
+
- Public chat message ingestion.
|
|
12
|
+
- Conversation history loading.
|
|
13
|
+
- Realtime replies through Server-Sent Events.
|
|
14
|
+
- Optional transcript/follow-up email action.
|
|
15
|
+
- Optional WhatsApp launcher.
|
|
16
|
+
- Optional website error monitoring for browser exceptions and failed fetch calls.
|
|
17
|
+
|
|
18
|
+
Installing the package only makes the code available. The widget and error monitoring start only after your app calls `createPulseAgent(...)` with valid configuration.
|
|
19
|
+
|
|
20
|
+
## 2. Required Pulse Values
|
|
21
|
+
|
|
22
|
+
| Value | Required | Example | Notes |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| `slug` | Yes | `vayakids` | Public organization slug. |
|
|
25
|
+
| `appKey` | Recommended | `app_abc123...` | Public application key from Pulse Dashboard. |
|
|
26
|
+
| `apiBaseUrl` | Yes | `https://pulse.service.primexperts.co.za` | Host only; do not add `/api`. |
|
|
27
|
+
| Website origin | Yes | `https://app.example.com` | Must be allowed by Pulse CORS/backend configuration. |
|
|
28
|
+
|
|
29
|
+
The `appKey` is the value that starts with `app_`. It is not the same as `widgetToken`.
|
|
30
|
+
|
|
31
|
+
A `widgetToken` is normally resolved automatically by Pulse. Do not configure it unless Pulse explicitly provides a token for a special case.
|
|
32
|
+
|
|
33
|
+
## 3. Install
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm install @primexperts.co/pulse-agent@latest
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For script-tag usage:
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<script src="https://unpkg.com/@primexperts.co/pulse-agent@latest/dist/browser/pulse-agent.global.js"></script>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## 4. Basic Configuration
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
49
|
+
|
|
50
|
+
createPulseAgent({
|
|
51
|
+
slug: 'vayakids',
|
|
52
|
+
appKey: 'app_your_public_application_key',
|
|
53
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
54
|
+
title: 'VayaKids',
|
|
55
|
+
requireProfile: true,
|
|
56
|
+
autoOpen: false
|
|
57
|
+
});
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 5. Error Monitoring Configuration
|
|
61
|
+
|
|
62
|
+
Error monitoring is off by default. Enable it explicitly:
|
|
63
|
+
|
|
64
|
+
```ts
|
|
65
|
+
createPulseAgent({
|
|
66
|
+
slug: 'vayakids',
|
|
67
|
+
appKey: 'app_your_public_application_key',
|
|
68
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
69
|
+
errorMonitoring: true,
|
|
70
|
+
captureUnhandledErrors: true,
|
|
71
|
+
captureUnhandledRejections: true,
|
|
72
|
+
captureFetchErrors: true,
|
|
73
|
+
environment: 'production',
|
|
74
|
+
release: 'web-1.0.0'
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
When enabled, Pulse Agent reports:
|
|
79
|
+
|
|
80
|
+
- Unhandled browser errors.
|
|
81
|
+
- Unhandled promise rejections.
|
|
82
|
+
- Failed `fetch` HTTP responses.
|
|
83
|
+
- Network errors thrown by `fetch`.
|
|
84
|
+
- Manual errors reported through `captureException`.
|
|
85
|
+
|
|
86
|
+
Manual capture:
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
const agent = createPulseAgent({
|
|
90
|
+
slug: 'vayakids',
|
|
91
|
+
appKey: 'app_your_public_application_key',
|
|
92
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
93
|
+
errorMonitoring: true
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await loadImportantData();
|
|
98
|
+
} catch (error) {
|
|
99
|
+
agent.captureException(error, {
|
|
100
|
+
source: 'home.loadImportantData',
|
|
101
|
+
errorType: 'data-load-error',
|
|
102
|
+
endpoint: '/api/important-data',
|
|
103
|
+
pageUrl: window.location.href
|
|
104
|
+
});
|
|
105
|
+
throw error;
|
|
106
|
+
}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
## 6. Environment Variable Names
|
|
110
|
+
|
|
111
|
+
Use these names in Heroku, Docker, CI, or your hosting platform:
|
|
112
|
+
|
|
113
|
+
```env
|
|
114
|
+
PULSE_AGENT_SLUG=vayakids
|
|
115
|
+
PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
116
|
+
PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
117
|
+
PULSE_AGENT_TITLE=VayaKids
|
|
118
|
+
PULSE_AGENT_ENVIRONMENT=production
|
|
119
|
+
PULSE_AGENT_RELEASE=web-1.0.0
|
|
120
|
+
|
|
121
|
+
PULSE_AGENT_ERROR_MONITORING=true
|
|
122
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
123
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
124
|
+
PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Optional:
|
|
128
|
+
|
|
129
|
+
```env
|
|
130
|
+
PULSE_AGENT_FOLLOW_UP_EMAIL_TO=support@example.com
|
|
131
|
+
PULSE_AGENT_DASHBOARD_URL=https://pulse.primexperts.co.za
|
|
132
|
+
PULSE_AGENT_DASHBOARD_SETUP_PATH=/integrations
|
|
133
|
+
PULSE_AGENT_AUTO_OPEN=false
|
|
134
|
+
PULSE_AGENT_REQUIRE_PROFILE=true
|
|
135
|
+
PULSE_AGENT_WHATSAPP_URL=https://api.whatsapp.com/send?phone=27123456789
|
|
136
|
+
PULSE_AGENT_WIDGET_TOKEN=
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Leave `PULSE_AGENT_WIDGET_TOKEN` empty unless Pulse tells you to use it.
|
|
140
|
+
|
|
141
|
+
## 7. Runtime Config Setup
|
|
142
|
+
|
|
143
|
+
Frontend bundles usually cannot read platform environment variables directly at runtime. Use a runtime config file generated from environment variables.
|
|
144
|
+
|
|
145
|
+
Add this to `index.html` before your app bundle:
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<script src="/runtime-config.js"></script>
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Example `runtime-config.js` output:
|
|
152
|
+
|
|
153
|
+
```js
|
|
154
|
+
window.__APP_RUNTIME_CONFIG__ = {
|
|
155
|
+
pulseAgent: {
|
|
156
|
+
slug: 'vayakids',
|
|
157
|
+
appKey: 'app_your_public_application_key',
|
|
158
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
159
|
+
title: 'VayaKids',
|
|
160
|
+
errorMonitoring: true,
|
|
161
|
+
captureUnhandledErrors: true,
|
|
162
|
+
captureUnhandledRejections: true,
|
|
163
|
+
captureFetchErrors: true,
|
|
164
|
+
environment: 'production',
|
|
165
|
+
release: 'web-1.0.0'
|
|
166
|
+
}
|
|
167
|
+
};
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
Initialize from that config:
|
|
171
|
+
|
|
172
|
+
```ts
|
|
173
|
+
import { createPulseAgent, type PulseAgentOptions } from '@primexperts.co/pulse-agent';
|
|
174
|
+
|
|
175
|
+
declare global {
|
|
176
|
+
interface Window {
|
|
177
|
+
__APP_RUNTIME_CONFIG__?: {
|
|
178
|
+
pulseAgent?: Partial<PulseAgentOptions>;
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const pulseAgentConfig = window.__APP_RUNTIME_CONFIG__?.pulseAgent;
|
|
184
|
+
|
|
185
|
+
if (pulseAgentConfig?.slug) {
|
|
186
|
+
createPulseAgent({
|
|
187
|
+
...pulseAgentConfig,
|
|
188
|
+
slug: pulseAgentConfig.slug
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## 8. Heroku Setup
|
|
194
|
+
|
|
195
|
+
Set config vars:
|
|
196
|
+
|
|
197
|
+
```bash
|
|
198
|
+
heroku config:set PULSE_AGENT_SLUG=vayakids
|
|
199
|
+
heroku config:set PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
200
|
+
heroku config:set PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
201
|
+
heroku config:set PULSE_AGENT_TITLE=VayaKids
|
|
202
|
+
heroku config:set PULSE_AGENT_ENVIRONMENT=production
|
|
203
|
+
heroku config:set PULSE_AGENT_ERROR_MONITORING=true
|
|
204
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
205
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
206
|
+
heroku config:set PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
If your app uses a generated `public/runtime-config.js`, run the generator during build or startup. If your app serves `/runtime-config.js` from Node/Express, read `process.env` and emit the config response at request time.
|
|
210
|
+
|
|
211
|
+
## 9. Framework Notes
|
|
212
|
+
|
|
213
|
+
### Angular
|
|
214
|
+
|
|
215
|
+
Initialize in `main.ts` or a browser-only root component. If Angular Universal is used, guard with `typeof window !== 'undefined'`.
|
|
216
|
+
|
|
217
|
+
### React
|
|
218
|
+
|
|
219
|
+
Initialize inside a top-level `useEffect`. Return `agent.destroy()` from cleanup if the component can unmount.
|
|
220
|
+
|
|
221
|
+
### Vue
|
|
222
|
+
|
|
223
|
+
Initialize in `onMounted` and destroy in `onBeforeUnmount`.
|
|
224
|
+
|
|
225
|
+
### Next.js and Nuxt
|
|
226
|
+
|
|
227
|
+
Use a client-only component/plugin. Do not initialize during server rendering.
|
|
228
|
+
|
|
229
|
+
### Static HTML
|
|
230
|
+
|
|
231
|
+
Use the browser global bundle and call `window.PulseAgent.createPulseAgent(...)` after the script loads.
|
|
232
|
+
|
|
233
|
+
## 10. Public Endpoints Used By The Widget
|
|
234
|
+
|
|
235
|
+
Pulse Agent calls these public endpoints:
|
|
236
|
+
|
|
237
|
+
```text
|
|
238
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>&appKey=<appKey>
|
|
239
|
+
POST /api/pulse/public/webchat/{widgetToken}/message
|
|
240
|
+
GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<id>
|
|
241
|
+
POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<id>
|
|
242
|
+
GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>
|
|
243
|
+
POST /api/pulse/public/webchat/{widgetToken}/errors
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
These endpoints are public by design for website visitors. Admin setup endpoints must remain authenticated.
|
|
247
|
+
|
|
248
|
+
## 11. Benefits
|
|
249
|
+
|
|
250
|
+
- One small browser package for chat and optional error reporting.
|
|
251
|
+
- No visitor login required.
|
|
252
|
+
- No need for customers to manage internal widget tokens.
|
|
253
|
+
- Supports runtime config for Heroku and similar platforms.
|
|
254
|
+
- Works with npm, module bundlers, or a CDN script tag.
|
|
255
|
+
- Supports multiple frontend frameworks.
|
|
256
|
+
- Uses standard browser APIs: `fetch`, `EventSource`, and DOM events.
|
|
257
|
+
|
|
258
|
+
## 12. Limitations
|
|
259
|
+
|
|
260
|
+
- Browser-only; no server-side rendering execution.
|
|
261
|
+
- Requires CORS configuration for every website origin.
|
|
262
|
+
- Requires active Pulse Webchat configuration.
|
|
263
|
+
- Requires network access to Pulse API.
|
|
264
|
+
- SSE streaming may be interrupted by proxies or timeout policies.
|
|
265
|
+
- Error monitoring starts only after initialization.
|
|
266
|
+
- Error monitoring does not replace backend logs or APM.
|
|
267
|
+
- `captureFetchErrors` wraps `window.fetch`; non-fetch HTTP clients may need manual reporting.
|
|
268
|
+
- `widgetToken` is advanced and should usually remain unset.
|
|
269
|
+
|
|
270
|
+
## 13. Verification Checklist
|
|
271
|
+
|
|
272
|
+
1. Open the site and confirm the Pulse launcher appears.
|
|
273
|
+
2. In browser dev tools, confirm `resolve?slug=...&appKey=...` succeeds.
|
|
274
|
+
3. Send a test message and confirm `message` succeeds.
|
|
275
|
+
4. Confirm `stream` is open and receives replies.
|
|
276
|
+
5. If history is enabled, confirm `messages?conversationId=...` succeeds.
|
|
277
|
+
6. If transcript email is enabled, confirm the transcript endpoint succeeds.
|
|
278
|
+
7. If error monitoring is enabled, trigger a controlled test error and confirm `/errors` succeeds.
|
|
279
|
+
8. Confirm Pulse Dashboard shows the expected conversation/error entries.
|
|
280
|
+
|
|
281
|
+
## 14. Troubleshooting
|
|
282
|
+
|
|
283
|
+
### Nothing happens after install
|
|
284
|
+
|
|
285
|
+
Installation alone does not run the widget. Your app must import the package and call `createPulseAgent(...)`.
|
|
286
|
+
|
|
287
|
+
### The app key starts with `app_`; where does it go?
|
|
288
|
+
|
|
289
|
+
Use it as `appKey`, or as `PULSE_AGENT_APP_KEY` in environment config.
|
|
290
|
+
|
|
291
|
+
### Where do I get `widgetToken`?
|
|
292
|
+
|
|
293
|
+
Usually nowhere. The widget resolves it automatically from `slug` and `appKey`. Leave `widgetToken` unset unless Pulse gives you one directly.
|
|
294
|
+
|
|
295
|
+
### Errors are not being reported
|
|
296
|
+
|
|
297
|
+
Check that `errorMonitoring` is true, the widget resolves successfully, and the error occurs after initialization.
|
|
298
|
+
|
|
299
|
+
### CORS blocks requests
|
|
300
|
+
|
|
301
|
+
Add the exact frontend origin to Pulse CORS/backend allowlist.
|
|
302
|
+
|
|
303
|
+
### Resolve returns 404
|
|
304
|
+
|
|
305
|
+
Check organization slug, app key, and whether Webchat is enabled for the selected organization/application.
|
|
306
|
+
|
|
307
|
+
### Resolve returns 401 or 403
|
|
308
|
+
|
|
309
|
+
Check whether the public resolve route is accessible and whether the app key is valid.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# Pulse Integration Channels Guide
|
|
2
|
+
|
|
3
|
+
This guide documents how to integrate Pulse by channel type and which technologies are used by each integration.
|
|
4
|
+
|
|
5
|
+
## 1. Channel Support Matrix
|
|
6
|
+
|
|
7
|
+
| Channel | Current Status | Main Purpose | Supporting Technologies |
|
|
8
|
+
|---|---|---|---|
|
|
9
|
+
| Webchat | Supported | Public website visitor chat | `@primexperts.co/pulse-agent` widget, REST APIs, SSE realtime stream, browser `fetch`/`EventSource`, CORS |
|
|
10
|
+
| Email | Supported | Ingest inbound mailbox emails into Pulse conversations | IMAPS polling (`jakarta.mail`), scheduled worker (`@Scheduled every 5m`), REST admin config APIs |
|
|
11
|
+
| WhatsApp | Planned (type exists, no active API flow) | Future messaging channel | Data model/enum placeholders only |
|
|
12
|
+
|
|
13
|
+
## 2. Common Integration Flow
|
|
14
|
+
|
|
15
|
+
1. Configure integration in authenticated admin APIs under `/api/pulse/integrations/*`.
|
|
16
|
+
2. Enable integration and verify status is `ACTIVE`.
|
|
17
|
+
3. Send/receive messages through channel-specific endpoints/workers.
|
|
18
|
+
4. Monitor `lastSyncAt` and operational logs for health.
|
|
19
|
+
|
|
20
|
+
## 3. Webchat Integration
|
|
21
|
+
|
|
22
|
+
### 3.1 What You Need
|
|
23
|
+
|
|
24
|
+
- Frontend: browser app or website.
|
|
25
|
+
- Package: `@primexperts.co/pulse-agent`.
|
|
26
|
+
- API base URL (example): `https://pulse.service.primexperts.co.za`.
|
|
27
|
+
- Organization slug with active webchat integration.
|
|
28
|
+
|
|
29
|
+
### 3.2 Admin Endpoints (Authenticated)
|
|
30
|
+
|
|
31
|
+
- `GET /api/pulse/integrations`
|
|
32
|
+
- `POST /api/pulse/integrations/webchat`
|
|
33
|
+
- `POST /api/pulse/integrations/{type}/disable`
|
|
34
|
+
- `GET /api/pulse/integrations/webchat/snippet`
|
|
35
|
+
|
|
36
|
+
### 3.3 Public Endpoints (Unauthenticated)
|
|
37
|
+
|
|
38
|
+
- `GET /api/pulse/public/webchat/resolve?slug=<slug>`
|
|
39
|
+
- `POST /api/pulse/public/webchat/{widgetToken}/message`
|
|
40
|
+
- `GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<uuid>`
|
|
41
|
+
- `POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<uuid>`
|
|
42
|
+
- `GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<uuid>` (SSE)
|
|
43
|
+
|
|
44
|
+
### 3.4 Example Widget Bootstrap
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
48
|
+
|
|
49
|
+
createPulseAgent({
|
|
50
|
+
slug: 'primexperts',
|
|
51
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
52
|
+
requireProfile: true
|
|
53
|
+
});
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### 3.5 Supporting Technologies
|
|
57
|
+
|
|
58
|
+
- Browser runtime (framework-agnostic).
|
|
59
|
+
- Realtime via Server-Sent Events (`EventSource`).
|
|
60
|
+
- JSON over HTTPS (`fetch`).
|
|
61
|
+
- Backend rate limiting per widget token on public ingest.
|
|
62
|
+
- CORS allowlist on Pulse API.
|
|
63
|
+
|
|
64
|
+
## 4. Email Integration
|
|
65
|
+
|
|
66
|
+
### 4.1 What You Need
|
|
67
|
+
|
|
68
|
+
- Admin access to configure mailbox credentials.
|
|
69
|
+
- Reachable IMAPS inbox server.
|
|
70
|
+
- Dedicated mailbox credentials recommended.
|
|
71
|
+
|
|
72
|
+
### 4.2 Admin Endpoints (Authenticated)
|
|
73
|
+
|
|
74
|
+
- `GET /api/pulse/integrations`
|
|
75
|
+
- `POST /api/pulse/integrations/email`
|
|
76
|
+
- `PATCH /api/pulse/integrations/email`
|
|
77
|
+
- `POST /api/pulse/integrations/email/test`
|
|
78
|
+
- `POST /api/pulse/integrations/{type}/disable`
|
|
79
|
+
|
|
80
|
+
### 4.3 Email Config Payload
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"inboxHost": "imap.example.com",
|
|
85
|
+
"inboxPort": 993,
|
|
86
|
+
"inboxUsername": "support@example.com",
|
|
87
|
+
"inboxPassword": "********",
|
|
88
|
+
"inboxFolder": "INBOX",
|
|
89
|
+
"smtpHost": "smtp.example.com",
|
|
90
|
+
"smtpUsername": "support@example.com",
|
|
91
|
+
"smtpPassword": "********"
|
|
92
|
+
}
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 4.4 Runtime Behavior
|
|
96
|
+
|
|
97
|
+
- A scheduler polls active email integrations every `5m` (after initial startup delay).
|
|
98
|
+
- Ingestion uses IMAPS (`mail.store.protocol=imaps`, SSL enabled).
|
|
99
|
+
- Unread messages are converted into Pulse conversations/messages.
|
|
100
|
+
- Deduplication is handled using `Message-ID` and a computed fingerprint.
|
|
101
|
+
- Conversation source is stored as `EMAIL`.
|
|
102
|
+
|
|
103
|
+
### 4.5 Supporting Technologies
|
|
104
|
+
|
|
105
|
+
- `jakarta.mail` for mailbox access.
|
|
106
|
+
- Quarkus scheduler (`@Scheduled`) for polling.
|
|
107
|
+
- Domain events + realtime publish for newly ingested messages.
|
|
108
|
+
- Notification service hooks for integration status and transcript emails.
|
|
109
|
+
|
|
110
|
+
## 5. WhatsApp Integration
|
|
111
|
+
|
|
112
|
+
### 5.1 Current State
|
|
113
|
+
|
|
114
|
+
- `WHATSAPP` exists in enums and DB constraints.
|
|
115
|
+
- No dedicated configure/ingest API resource is currently exposed.
|
|
116
|
+
- No worker or provider adapter is currently implemented.
|
|
117
|
+
|
|
118
|
+
### 5.2 Integration Planning Notes
|
|
119
|
+
|
|
120
|
+
- Treat as reserved channel type until APIs and provider contracts are added.
|
|
121
|
+
- Do not mark it as production-ready in client-facing onboarding docs yet.
|
|
122
|
+
|
|
123
|
+
## 6. Security and Operations Checklist
|
|
124
|
+
|
|
125
|
+
- Keep admin integration APIs protected with bearer auth.
|
|
126
|
+
- Keep only public webchat endpoints unauthenticated.
|
|
127
|
+
- Enforce CORS allowlist for website origins.
|
|
128
|
+
- Rotate mailbox credentials and monitor failed IMAPS logins.
|
|
129
|
+
- Confirm SSE support in reverse proxy/load balancer configuration.
|
|
130
|
+
|
|
131
|
+
## 7. Quick Start by Team
|
|
132
|
+
|
|
133
|
+
### Frontend Team
|
|
134
|
+
|
|
135
|
+
1. Integrate `@primexperts.co/pulse-agent`.
|
|
136
|
+
2. Configure slug and API base URL.
|
|
137
|
+
3. Validate resolve -> message -> stream flow in browser network logs.
|
|
138
|
+
|
|
139
|
+
### Backend/Platform Team
|
|
140
|
+
|
|
141
|
+
1. Enable `WEBCHAT` and/or configure `EMAIL` integration.
|
|
142
|
+
2. Confirm integration records are `ACTIVE`.
|
|
143
|
+
3. Monitor `lastSyncAt`, ingestion logs, and rate-limit behavior.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Pulse Agent Troubleshooting
|
|
2
|
+
|
|
3
|
+
## 1) CORS: `No 'Access-Control-Allow-Origin' header`
|
|
4
|
+
|
|
5
|
+
### Symptoms
|
|
6
|
+
- Browser blocks requests to Pulse API.
|
|
7
|
+
- Console shows CORS policy errors.
|
|
8
|
+
|
|
9
|
+
### Fix
|
|
10
|
+
- Ensure backend CORS includes your frontend origin.
|
|
11
|
+
- Example allowed origins:
|
|
12
|
+
- `https://pulse.primexperts.co.za`
|
|
13
|
+
- `http://localhost:4200`
|
|
14
|
+
|
|
15
|
+
## 2) Wrong API host called in network tab
|
|
16
|
+
|
|
17
|
+
### Symptoms
|
|
18
|
+
- Requests go to old/incorrect host (e.g., `api.pulsecrm.com`).
|
|
19
|
+
|
|
20
|
+
### Fix
|
|
21
|
+
- Set widget config explicitly:
|
|
22
|
+
- `apiBaseUrl: 'https://pulse.service.primexperts.co.za'`
|
|
23
|
+
- Clear stale local config in app storage if applicable.
|
|
24
|
+
|
|
25
|
+
## 3) Resolve endpoint returns 401 or 403
|
|
26
|
+
|
|
27
|
+
### Symptoms
|
|
28
|
+
- `GET /api/pulse/public/webchat/resolve?slug=...` is unauthorized.
|
|
29
|
+
|
|
30
|
+
### Fix
|
|
31
|
+
- Mark public webchat endpoints as anonymous/permitAll in backend security.
|
|
32
|
+
|
|
33
|
+
## 4) Resolve endpoint returns 404
|
|
34
|
+
|
|
35
|
+
### Symptoms
|
|
36
|
+
- `Failed to resolve widget keys (404)` message.
|
|
37
|
+
|
|
38
|
+
### Fix
|
|
39
|
+
- Verify slug is correct.
|
|
40
|
+
- Ensure webchat integration is enabled for that organization.
|
|
41
|
+
|
|
42
|
+
## 5) Stream not receiving agent messages
|
|
43
|
+
|
|
44
|
+
### Symptoms
|
|
45
|
+
- Message POST works, no realtime replies appear.
|
|
46
|
+
|
|
47
|
+
### Fix
|
|
48
|
+
- Verify SSE endpoint is reachable:
|
|
49
|
+
- `GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>`
|
|
50
|
+
- Check proxies/load balancers for SSE support and timeouts.
|
|
51
|
+
|
|
52
|
+
## 6) Keycloak timeout logs
|
|
53
|
+
|
|
54
|
+
### Symptoms
|
|
55
|
+
- Logs like `Keycloak init timed out`.
|
|
56
|
+
|
|
57
|
+
### Fix
|
|
58
|
+
- Confirm Keycloak URL/realm/client config.
|
|
59
|
+
- Verify redirect URIs and web origins in Keycloak client.
|
|
60
|
+
- Treat separately from webchat CORS unless proven linked.
|
|
61
|
+
|
|
62
|
+
## 7) Slug validation quick check
|
|
63
|
+
|
|
64
|
+
If slug is generated using:
|
|
65
|
+
|
|
66
|
+
```sql
|
|
67
|
+
regexp_replace(
|
|
68
|
+
regexp_replace(lower(trim(name)), '[^a-z0-9]+', '-', 'g'),
|
|
69
|
+
'(^-+|-+$)', '', 'g'
|
|
70
|
+
)
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Then:
|
|
74
|
+
- `PrimeXperts` -> `primexperts`
|
|
75
|
+
|
|
76
|
+
Resolve URL:
|
|
77
|
+
|
|
78
|
+
`https://pulse.service.primexperts.co.za/api/pulse/public/webchat/resolve?slug=primexperts`
|
|
79
|
+
|
|
80
|
+
## 8) Quick verification checklist
|
|
81
|
+
|
|
82
|
+
- Widget config uses correct `apiBaseUrl`
|
|
83
|
+
- Backend CORS includes current frontend origin
|
|
84
|
+
- Public webchat endpoints are accessible without auth
|
|
85
|
+
- Organization slug is correct
|
|
86
|
+
- Webchat integration is active
|
package/package.json
CHANGED
|
@@ -1,39 +1,40 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
2
|
+
"name": "@primexperts.co/pulse-agent",
|
|
3
|
+
"version": "5.2.0",
|
|
4
|
+
"description": "Embeddable Pulse floating chat agent widget.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"files": [
|
|
15
|
+
"dist",
|
|
16
|
+
"docs",
|
|
17
|
+
"README.md",
|
|
18
|
+
"LICENSE"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"clean": "node -e \"if(require('fs').existsSync('dist')) require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
22
|
+
"build:types": "tsc -p tsconfig.build.json",
|
|
23
|
+
"build:browser": "node scripts/build-browser-global.mjs",
|
|
24
|
+
"build": "npm run clean && npm run build:types && npm run build:browser",
|
|
25
|
+
"version:bump": "node scripts/bump-version.mjs",
|
|
26
|
+
"version:patch": "node scripts/bump-version.mjs patch",
|
|
27
|
+
"version:minor": "node scripts/bump-version.mjs minor",
|
|
28
|
+
"version:major": "node scripts/bump-version.mjs major",
|
|
29
|
+
"prepublishOnly": "npm run build"
|
|
30
|
+
},
|
|
31
|
+
"private": false,
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"author": "PrimExperts",
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"tslib": "^2.8.1"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"typescript": "~5.8.2"
|
|
12
39
|
}
|
|
13
|
-
},
|
|
14
|
-
"files": [
|
|
15
|
-
"dist",
|
|
16
|
-
"README.md",
|
|
17
|
-
"LICENSE"
|
|
18
|
-
],
|
|
19
|
-
"scripts": {
|
|
20
|
-
"clean": "node -e \"if(require('fs').existsSync('dist')) require('fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
21
|
-
"build:types": "tsc -p tsconfig.build.json",
|
|
22
|
-
"build:browser": "node scripts/build-browser-global.mjs",
|
|
23
|
-
"build": "npm run clean && npm run build:types && npm run build:browser",
|
|
24
|
-
"version:bump": "node scripts/bump-version.mjs",
|
|
25
|
-
"version:patch": "node scripts/bump-version.mjs patch",
|
|
26
|
-
"version:minor": "node scripts/bump-version.mjs minor",
|
|
27
|
-
"version:major": "node scripts/bump-version.mjs major",
|
|
28
|
-
"prepublishOnly": "npm run build"
|
|
29
|
-
},
|
|
30
|
-
"private": false,
|
|
31
|
-
"license": "MIT",
|
|
32
|
-
"author": "PrimExperts",
|
|
33
|
-
"dependencies": {
|
|
34
|
-
"tslib": "^2.8.1"
|
|
35
|
-
},
|
|
36
|
-
"devDependencies": {
|
|
37
|
-
"typescript": "~5.8.2"
|
|
38
|
-
}
|
|
39
40
|
}
|