@primexperts.co/pulse-agent 5.1.0 → 5.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/README.md +400 -57
- package/docs/CHANGELOG.md +31 -0
- package/docs/DEVELOPER.md +42 -0
- package/docs/FAQ.md +58 -0
- package/docs/IMPLEMENTATION-GUIDE.md +324 -0
- package/docs/INTEGRATION-CHANNELS.md +143 -0
- package/docs/TROUBLESHOOTING.md +86 -0
- package/package.json +40 -39
package/README.md
CHANGED
|
@@ -1,97 +1,440 @@
|
|
|
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
|
+
## Why Teams Use Pulse Agent
|
|
40
|
+
|
|
41
|
+
Pulse Agent is useful when a business has customer messages arriving through public-facing channels, but the team needs a controlled place to handle them.
|
|
42
|
+
|
|
43
|
+
Typical use cases:
|
|
44
|
+
|
|
45
|
+
- A website visitor starts a chat and any available team member can respond from Pulse.
|
|
46
|
+
- A support mailbox can be connected so the team manages customer email from a shared workspace instead of one person's inbox.
|
|
47
|
+
- Conversation history stays attached to the customer interaction, so the next team member can continue with context.
|
|
48
|
+
- Teams can separate customer communication by organization/application using the `slug` and `appKey`.
|
|
49
|
+
- Website errors can be reported into Pulse so support and operations can see when customers are affected.
|
|
50
|
+
|
|
51
|
+
The result is a team inbox model: one public channel for customers, multiple internal users for response and follow-up.
|
|
52
|
+
|
|
53
|
+
## Channel Model
|
|
54
|
+
|
|
55
|
+
| Channel | Current role | What the customer sees | What the team gets in Pulse |
|
|
56
|
+
| --- | --- | --- | --- |
|
|
57
|
+
| Webchat | Supported through this package | Website chat launcher | Shared conversation thread, visitor profile, realtime replies, history, transcript action |
|
|
58
|
+
| Email | Supported by Pulse integrations | Normal support email address | Shared email conversations in Pulse, independent of one person's mailbox |
|
|
59
|
+
| WhatsApp | Planned/optional depending on deployment | WhatsApp contact path | Intended shared handling model when enabled; do not promise as active unless configured |
|
|
60
|
+
| Error Monitoring | Supported through this package | No visible customer UI | Browser exceptions and failed request reports tied to the website/application |
|
|
61
|
+
|
|
62
|
+
## What You Need From Pulse
|
|
63
|
+
|
|
64
|
+
You need these values before going live:
|
|
65
|
+
|
|
66
|
+
| Value | Example | Required | Where it comes from |
|
|
67
|
+
| --- | --- | --- | --- |
|
|
68
|
+
| Organization slug | `vayakids` | Yes | Pulse organization/webchat setup |
|
|
69
|
+
| Application key | `app_...` | Recommended | Pulse Dashboard application/webchat setup |
|
|
70
|
+
| API base URL | `https://pulse.service.primexperts.co.za` | Yes | Pulse production API host |
|
|
71
|
+
| Allowed website origin | `https://www.example.com` | Yes | Must be allowed by Pulse CORS/backend configuration |
|
|
72
|
+
|
|
73
|
+
You usually do not need a widget token. The widget resolves it automatically by calling Pulse with your `slug` and `appKey`.
|
|
74
|
+
|
|
75
|
+
## Configuration Keys
|
|
76
|
+
|
|
77
|
+
| Option | Type | Default | Description |
|
|
78
|
+
| --- | --- | --- | --- |
|
|
79
|
+
| `slug` | `string` | Required | Public organization slug used to resolve the active webchat widget. |
|
|
80
|
+
| `appKey` | `string` | Optional but recommended | Public application key, normally starts with `app_`. Use this for application-specific setup and error attribution. |
|
|
81
|
+
| `appSlug` | `string` | Optional | Alternative application identifier when an app key is not available. |
|
|
82
|
+
| `apiBaseUrl` | `string` | `https://pulse.service.primexperts.co.za` | Pulse API host only. Do not include `/api/...` paths. |
|
|
83
|
+
| `title` | `string` | Organization/app name | Chat panel title. |
|
|
84
|
+
| `mount` | `HTMLElement \| string` | `document.body` | Element or selector where the widget root should be mounted. |
|
|
85
|
+
| `autoOpen` | `boolean` | `false` | Opens the chat panel immediately after initialization. |
|
|
86
|
+
| `requireProfile` | `boolean` | `true` | Requires visitor name/email before first message. |
|
|
87
|
+
| `followUpEmailTo` | `string` | Optional | Destination used by transcript/follow-up email actions. |
|
|
88
|
+
| `dashboardUrl` | `string` | `https://pulse.primexperts.co.za` | Dashboard link used in setup/error states. |
|
|
89
|
+
| `dashboardSetupPath` | `string` | `/integrations` | Dashboard path linked when setup is incomplete. |
|
|
90
|
+
| `whatsappUrl` | `string` | Optional | Adds a WhatsApp launcher alongside Pulse Chat. |
|
|
91
|
+
| `widgetToken` | `string` | Optional | Advanced bypass for resolve flow. Leave unset unless Pulse gives you a specific token. |
|
|
92
|
+
| `errorMonitoring` | `boolean` | `false` | Enables browser error reporting. Must be `true` before any capture happens. |
|
|
93
|
+
| `captureUnhandledErrors` | `boolean` | `true` when monitoring is enabled | Captures `window.onerror` events. |
|
|
94
|
+
| `captureUnhandledRejections` | `boolean` | `true` when monitoring is enabled | Captures unhandled promise rejections. |
|
|
95
|
+
| `captureFetchErrors` | `boolean` | `true` when monitoring is enabled | Wraps browser `fetch` to report failed requests and thrown network errors. |
|
|
96
|
+
| `environment` | `string` | Optional | Environment label such as `production`, `staging`, or `development`. |
|
|
97
|
+
| `release` | `string` | Optional | Application release/version label for error context. |
|
|
98
|
+
|
|
99
|
+
## Environment Variables
|
|
100
|
+
|
|
101
|
+
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`.
|
|
102
|
+
|
|
103
|
+
Recommended names:
|
|
104
|
+
|
|
105
|
+
```env
|
|
106
|
+
PULSE_AGENT_SLUG=your-organization-slug
|
|
107
|
+
PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
108
|
+
PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
109
|
+
PULSE_AGENT_TITLE=Support
|
|
110
|
+
PULSE_AGENT_ENVIRONMENT=production
|
|
111
|
+
PULSE_AGENT_RELEASE=web-1.0.0
|
|
112
|
+
|
|
113
|
+
PULSE_AGENT_ERROR_MONITORING=true
|
|
114
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
115
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
116
|
+
PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Optional names:
|
|
120
|
+
|
|
121
|
+
```env
|
|
122
|
+
PULSE_AGENT_FOLLOW_UP_EMAIL_TO=support@example.com
|
|
123
|
+
PULSE_AGENT_DASHBOARD_URL=https://pulse.primexperts.co.za
|
|
124
|
+
PULSE_AGENT_DASHBOARD_SETUP_PATH=/integrations
|
|
125
|
+
PULSE_AGENT_AUTO_OPEN=false
|
|
126
|
+
PULSE_AGENT_REQUIRE_PROFILE=true
|
|
127
|
+
PULSE_AGENT_WHATSAPP_URL=https://api.whatsapp.com/send?phone=27123456789
|
|
128
|
+
PULSE_AGENT_WIDGET_TOKEN=
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
Leave `PULSE_AGENT_WIDGET_TOKEN` unset unless Pulse Support explicitly gives you one. It is not the `app_*` key.
|
|
132
|
+
|
|
133
|
+
## Heroku Config Vars
|
|
134
|
+
|
|
135
|
+
Set these in Heroku under Settings -> Config Vars, or with the Heroku CLI:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
heroku config:set PULSE_AGENT_SLUG=your-organization-slug
|
|
139
|
+
heroku config:set PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
140
|
+
heroku config:set PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
141
|
+
heroku config:set PULSE_AGENT_TITLE=Support
|
|
142
|
+
heroku config:set PULSE_AGENT_ENVIRONMENT=production
|
|
143
|
+
heroku config:set PULSE_AGENT_ERROR_MONITORING=true
|
|
144
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
145
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
146
|
+
heroku config:set PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
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.
|
|
150
|
+
|
|
151
|
+
## Runtime Config Pattern
|
|
152
|
+
|
|
153
|
+
A common production-safe pattern is to load `/runtime-config.js` before your app bundle:
|
|
154
|
+
|
|
155
|
+
```html
|
|
156
|
+
<script src="/runtime-config.js"></script>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Example generated file:
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
window.__APP_RUNTIME_CONFIG__ = {
|
|
163
|
+
pulseAgent: {
|
|
164
|
+
slug: 'your-organization-slug',
|
|
165
|
+
appKey: 'app_your_public_application_key',
|
|
166
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
167
|
+
title: 'Support',
|
|
168
|
+
errorMonitoring: true,
|
|
169
|
+
captureUnhandledErrors: true,
|
|
170
|
+
captureUnhandledRejections: true,
|
|
171
|
+
captureFetchErrors: true,
|
|
172
|
+
environment: 'production'
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
Then initialize in your app entry point:
|
|
178
|
+
|
|
179
|
+
```ts
|
|
180
|
+
import { createPulseAgent, type PulseAgentOptions } from '@primexperts.co/pulse-agent';
|
|
181
|
+
|
|
182
|
+
declare global {
|
|
183
|
+
interface Window {
|
|
184
|
+
__APP_RUNTIME_CONFIG__?: {
|
|
185
|
+
pulseAgent?: Partial<PulseAgentOptions>;
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
const config = window.__APP_RUNTIME_CONFIG__?.pulseAgent;
|
|
191
|
+
|
|
192
|
+
if (config?.slug) {
|
|
193
|
+
createPulseAgent({
|
|
194
|
+
...config,
|
|
195
|
+
slug: config.slug
|
|
196
|
+
});
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
## Browser/CDN Usage
|
|
201
|
+
|
|
202
|
+
Use this when you cannot install npm packages:
|
|
36
203
|
|
|
37
204
|
```html
|
|
38
205
|
<script src="https://unpkg.com/@primexperts.co/pulse-agent@latest/dist/browser/pulse-agent.global.js"></script>
|
|
39
206
|
<script>
|
|
40
|
-
|
|
41
|
-
slug: '
|
|
42
|
-
|
|
207
|
+
window.PulseAgent.createPulseAgent({
|
|
208
|
+
slug: 'your-organization-slug',
|
|
209
|
+
appKey: 'app_your_public_application_key',
|
|
210
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
211
|
+
title: 'Support',
|
|
212
|
+
errorMonitoring: true
|
|
43
213
|
});
|
|
44
214
|
</script>
|
|
45
215
|
```
|
|
46
216
|
|
|
47
|
-
##
|
|
217
|
+
## Framework Examples
|
|
218
|
+
|
|
219
|
+
### Angular
|
|
220
|
+
|
|
221
|
+
Initialize in `main.ts` or a browser-only root component. For SSR, guard against server execution.
|
|
48
222
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
- `GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>`
|
|
223
|
+
```ts
|
|
224
|
+
import { bootstrapApplication } from '@angular/platform-browser';
|
|
225
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
226
|
+
import { AppComponent } from './app/app.component';
|
|
54
227
|
|
|
55
|
-
|
|
228
|
+
if (typeof window !== 'undefined') {
|
|
229
|
+
createPulseAgent({
|
|
230
|
+
slug: 'your-organization-slug',
|
|
231
|
+
appKey: 'app_your_public_application_key',
|
|
232
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
233
|
+
errorMonitoring: true
|
|
234
|
+
});
|
|
235
|
+
}
|
|
56
236
|
|
|
57
|
-
|
|
237
|
+
bootstrapApplication(AppComponent);
|
|
238
|
+
```
|
|
58
239
|
|
|
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.
|
|
240
|
+
### React
|
|
68
241
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
-
|
|
72
|
-
- `destroy()`
|
|
73
|
-
- `update(partialOptions)`
|
|
242
|
+
```tsx
|
|
243
|
+
import { useEffect } from 'react';
|
|
244
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
74
245
|
|
|
75
|
-
|
|
246
|
+
export function PulseAgentBootstrap() {
|
|
247
|
+
useEffect(() => {
|
|
248
|
+
const 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
|
+
});
|
|
76
254
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
- If widget keys cannot be resolved, the chat shows an error message and retries resolution on the next send attempt.
|
|
80
|
-
- `npm run build` now outputs:
|
|
81
|
-
- ESM + type declarations in `dist/`
|
|
82
|
-
- browser global bundle in `dist/browser/pulse-agent.global.js`
|
|
255
|
+
return () => agent.destroy();
|
|
256
|
+
}, []);
|
|
83
257
|
|
|
84
|
-
|
|
258
|
+
return null;
|
|
259
|
+
}
|
|
260
|
+
```
|
|
85
261
|
|
|
86
|
-
|
|
262
|
+
### Vue
|
|
87
263
|
|
|
88
|
-
```
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
264
|
+
```ts
|
|
265
|
+
import { onBeforeUnmount, onMounted } from 'vue';
|
|
266
|
+
import { createPulseAgent, type PulseAgentHandle } from '@primexperts.co/pulse-agent';
|
|
267
|
+
|
|
268
|
+
let agent: PulseAgentHandle | null = null;
|
|
269
|
+
|
|
270
|
+
onMounted(() => {
|
|
271
|
+
agent = createPulseAgent({
|
|
272
|
+
slug: 'your-organization-slug',
|
|
273
|
+
appKey: 'app_your_public_application_key',
|
|
274
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
275
|
+
errorMonitoring: true
|
|
276
|
+
});
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
onBeforeUnmount(() => agent?.destroy());
|
|
95
280
|
```
|
|
96
281
|
|
|
97
|
-
|
|
282
|
+
## How Widget Resolution Works
|
|
283
|
+
|
|
284
|
+
At startup or first send, Pulse Agent calls:
|
|
285
|
+
|
|
286
|
+
```text
|
|
287
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>[&appKey=<app_...>]
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
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.
|
|
291
|
+
|
|
292
|
+
Do not confuse these values:
|
|
293
|
+
|
|
294
|
+
| Name | Format | Purpose | User action |
|
|
295
|
+
| --- | --- | --- | --- |
|
|
296
|
+
| `appKey` | `app_...` | Public application key from Pulse Dashboard | Put in config/env. |
|
|
297
|
+
| `widgetToken` | Token generated by Pulse | Internal public webchat token used by endpoints | Usually leave unset. |
|
|
298
|
+
| `slug` | human-readable slug | Identifies organization | Put in config/env. |
|
|
299
|
+
|
|
300
|
+
## Error Monitoring
|
|
301
|
+
|
|
302
|
+
Error monitoring is opt-in. Installing the package does not capture anything until `errorMonitoring: true` is passed to `createPulseAgent`.
|
|
303
|
+
|
|
304
|
+
When enabled, Pulse Agent can capture:
|
|
305
|
+
|
|
306
|
+
- Unhandled JavaScript errors from `window.onerror`.
|
|
307
|
+
- Unhandled promise rejections from `window.onunhandledrejection`.
|
|
308
|
+
- Failed `fetch` responses, including HTTP statuses from failed API calls.
|
|
309
|
+
- Network errors thrown by `fetch`.
|
|
310
|
+
- Manual error reports through `agent.captureException(...)`.
|
|
311
|
+
|
|
312
|
+
Manual capture example:
|
|
313
|
+
|
|
314
|
+
```ts
|
|
315
|
+
try {
|
|
316
|
+
await saveOrder();
|
|
317
|
+
} catch (error) {
|
|
318
|
+
agent.captureException(error, {
|
|
319
|
+
source: 'checkout.saveOrder',
|
|
320
|
+
errorType: 'checkout-error',
|
|
321
|
+
endpoint: '/api/orders',
|
|
322
|
+
pageUrl: window.location.href
|
|
323
|
+
});
|
|
324
|
+
throw error;
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
Report count example:
|
|
329
|
+
|
|
330
|
+
```ts
|
|
331
|
+
const reportsLastSevenDays = agent.getErrorReportCount(7);
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
### What Error Monitoring Does Not Do
|
|
335
|
+
|
|
336
|
+
Pulse Agent does not:
|
|
337
|
+
|
|
338
|
+
- Catch errors before the widget is initialized.
|
|
339
|
+
- Catch server-side errors unless those errors are exposed to the browser as failed requests.
|
|
340
|
+
- Replace backend logging, APM, or infrastructure monitoring.
|
|
341
|
+
- Read private app state, passwords, tokens, or request bodies intentionally.
|
|
342
|
+
- Automatically fix errors.
|
|
343
|
+
- Capture errors if `errorMonitoring` is missing or `false`.
|
|
344
|
+
|
|
345
|
+
## Public Backend Endpoints
|
|
346
|
+
|
|
347
|
+
The widget expects these Pulse endpoints:
|
|
348
|
+
|
|
349
|
+
```text
|
|
350
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>[&appKey=<appKey>]
|
|
351
|
+
POST /api/pulse/public/webchat/{widgetToken}/message
|
|
352
|
+
GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<id>
|
|
353
|
+
POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<id>
|
|
354
|
+
GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>
|
|
355
|
+
POST /api/pulse/public/webchat/{widgetToken}/errors
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
Admin setup endpoints are separate and should remain authenticated.
|
|
359
|
+
|
|
360
|
+
## Benefits
|
|
361
|
+
|
|
362
|
+
- One package for webchat and optional browser error monitoring.
|
|
363
|
+
- Framework-agnostic browser integration.
|
|
364
|
+
- Works with npm or a script tag.
|
|
365
|
+
- Supports runtime configuration, which is useful for Heroku, Docker, static hosting, and multi-environment deployments.
|
|
366
|
+
- Uses `slug` + `appKey` so users do not need to handle internal widget tokens.
|
|
367
|
+
- Supports visitor profile capture, history loading, transcript email requests, SSE replies, WhatsApp launcher/contact path where configured, manual open/close, and manual exception reporting.
|
|
368
|
+
- Supports operational workflows verified in the Pulse source: assignment, status/priority updates, internal notes, follow-ups, customer profiles, tags, notifications, activity logs, exports, and dashboard KPIs.
|
|
369
|
+
- Supports role-based team operation: admins manage setup and assignment, while agents work assigned conversations.
|
|
370
|
+
|
|
371
|
+
## Limitations
|
|
372
|
+
|
|
373
|
+
- Browser-only. Initialize after mount/hydration in SSR frameworks.
|
|
374
|
+
- Requires the website origin to be allowed by Pulse CORS configuration.
|
|
375
|
+
- Requires an active Pulse Webchat integration for the organization/application.
|
|
376
|
+
- Requires `fetch` and `EventSource` support for full behavior.
|
|
377
|
+
- SSE can be affected by proxies, corporate networks, browser extensions, and load balancer timeouts.
|
|
378
|
+
- Error monitoring starts only after initialization and only when enabled.
|
|
379
|
+
- `fetch` monitoring covers `window.fetch`; it does not automatically wrap Axios internals unless Axios uses `fetch` in that environment.
|
|
380
|
+
- `widgetToken` is an advanced bypass and should not be used unless Pulse explicitly provides it.
|
|
381
|
+
|
|
382
|
+
## Production Checklist
|
|
383
|
+
|
|
384
|
+
Before publishing a site with Pulse Agent:
|
|
385
|
+
|
|
386
|
+
1. Confirm Pulse Webchat is enabled in the Pulse Dashboard.
|
|
387
|
+
2. Confirm you have the correct `slug`.
|
|
388
|
+
3. Confirm you have the correct `appKey` beginning with `app_`.
|
|
389
|
+
4. Confirm `apiBaseUrl` is `https://pulse.service.primexperts.co.za`.
|
|
390
|
+
5. Confirm production origin is allowed by Pulse CORS configuration.
|
|
391
|
+
6. Confirm `runtime-config.js` or app config is generated from deployment env values.
|
|
392
|
+
7. Confirm `errorMonitoring` is `true` if you expect browser error reporting.
|
|
393
|
+
8. Open the site and check browser network calls for `resolve`, `message`, `stream`, and `errors` when applicable.
|
|
394
|
+
9. Send a test chat message.
|
|
395
|
+
10. Trigger a test error in a non-production or controlled environment and confirm it appears in Pulse.
|
|
396
|
+
|
|
397
|
+
## Handle API
|
|
398
|
+
|
|
399
|
+
`createPulseAgent(options)` returns:
|
|
400
|
+
|
|
401
|
+
| Method | Description |
|
|
402
|
+
| --- | --- |
|
|
403
|
+
| `open()` | Opens the chat panel. |
|
|
404
|
+
| `close()` | Closes the chat panel. |
|
|
405
|
+
| `destroy()` | Removes DOM, listeners, and fetch wrapping installed by this instance. |
|
|
406
|
+
| `resetConversation()` | Starts a fresh local conversation. |
|
|
407
|
+
| `update(partialOptions)` | Updates runtime options such as title, WhatsApp URL, or widget token. |
|
|
408
|
+
| `captureException(error, context)` | Manually reports an error when monitoring is enabled. |
|
|
409
|
+
| `getErrorReportCount(days)` | Returns locally remembered successful error report count for the last N days. |
|
|
410
|
+
|
|
411
|
+
## Troubleshooting
|
|
412
|
+
|
|
413
|
+
### The widget does not appear
|
|
414
|
+
|
|
415
|
+
Check that initialization runs in the browser, the `slug` is present, and the mount selector exists.
|
|
416
|
+
|
|
417
|
+
### `Failed to resolve widget keys (401/403)`
|
|
418
|
+
|
|
419
|
+
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.
|
|
420
|
+
|
|
421
|
+
### `Failed to resolve widget keys (404)`
|
|
422
|
+
|
|
423
|
+
The slug is wrong, Webchat is not enabled, or the selected organization/application has no active widget.
|
|
424
|
+
|
|
425
|
+
### CORS error in the browser console
|
|
426
|
+
|
|
427
|
+
The website origin is missing from Pulse CORS configuration. Add the exact origin, including protocol and port.
|
|
428
|
+
|
|
429
|
+
### Chat sends but replies do not stream
|
|
430
|
+
|
|
431
|
+
Check that `EventSource` is available and that proxies/load balancers allow long-lived SSE connections.
|
|
432
|
+
|
|
433
|
+
### Errors are not captured
|
|
434
|
+
|
|
435
|
+
Confirm all of the following:
|
|
436
|
+
|
|
437
|
+
- `errorMonitoring: true` is present in runtime config.
|
|
438
|
+
- The widget successfully resolves a widget token.
|
|
439
|
+
- The error happens after `createPulseAgent(...)` runs.
|
|
440
|
+
- The browser can post to `/api/pulse/public/webchat/{widgetToken}/errors`.
|
|
@@ -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.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Pulse Agent Developer Notes
|
|
2
|
+
|
|
3
|
+
This document is for maintainers of `@primexperts.co/pulse-agent`. It is not required for customers installing the widget.
|
|
4
|
+
|
|
5
|
+
## Repository Documentation
|
|
6
|
+
|
|
7
|
+
- `docs/IMPLEMENTATION-GUIDE.md` - end-to-end setup examples and deployment guidance.
|
|
8
|
+
- `docs/TROUBLESHOOTING.md` - diagnostics for CORS, resolve failures, streaming, and monitoring.
|
|
9
|
+
- `docs/FAQ.md` - common integration questions.
|
|
10
|
+
- `docs/INTEGRATION-CHANNELS.md` - channel-level implementation notes.
|
|
11
|
+
|
|
12
|
+
## Build
|
|
13
|
+
|
|
14
|
+
```bash
|
|
15
|
+
npm run build
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Build output includes:
|
|
19
|
+
|
|
20
|
+
- ESM and type declarations in `dist/`.
|
|
21
|
+
- Browser global bundle in `dist/browser/pulse-agent.global.js`.
|
|
22
|
+
|
|
23
|
+
## Publish
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm publish --access public
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`prepublishOnly` runs the build before publishing.
|
|
30
|
+
|
|
31
|
+
## Versioning
|
|
32
|
+
|
|
33
|
+
Use the built-in version script instead of editing package files manually:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
npm run version:patch
|
|
37
|
+
npm run version:minor
|
|
38
|
+
npm run version:major
|
|
39
|
+
npm run version:bump -- 1.2.3
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
This updates both `package.json` and `package-lock.json` when the script is used.
|
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,324 @@
|
|
|
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. It also explains the bigger product model: Pulse Agent is the website entry point into a shared Pulse workspace where multiple users can manage customer conversations from connected channels.
|
|
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/contact path where configured; full WhatsApp shared-inbox handling should be described only when enabled for that deployment.
|
|
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
|
+
## 1.1. Source-Verified Product Capabilities
|
|
21
|
+
|
|
22
|
+
The Pulse source supports more than a website chat bubble:
|
|
23
|
+
|
|
24
|
+
- Authenticated Pulse users can work from an Inbox.
|
|
25
|
+
- Admins can assign or reassign conversations.
|
|
26
|
+
- Agents are assignment-scoped in the current role model.
|
|
27
|
+
- Team members can reply to conversations and add internal notes.
|
|
28
|
+
- Conversations support status, priority, activity, tags, follow-ups, quotes, and customer profiles.
|
|
29
|
+
- Dashboard views show open/pending conversations, team load, and error summaries.
|
|
30
|
+
- Email integrations can connect an inbox through IMAPS polling and convert unread mail into Pulse conversations.
|
|
31
|
+
- Webchat uses public visitor endpoints, rate limiting, history, and SSE streaming.
|
|
32
|
+
- Error monitoring can post browser error reports to Pulse and feed dashboard summaries.
|
|
33
|
+
|
|
34
|
+
This is why the strongest positioning is: Pulse Agent gets the customer conversation or browser issue into Pulse; Pulse gives the team a controlled workspace to manage it together.
|
|
35
|
+
## 2. Required Pulse Values
|
|
36
|
+
|
|
37
|
+
| Value | Required | Example | Notes |
|
|
38
|
+
| --- | --- | --- | --- |
|
|
39
|
+
| `slug` | Yes | `vayakids` | Public organization slug. |
|
|
40
|
+
| `appKey` | Recommended | `app_abc123...` | Public application key from Pulse Dashboard. The agent sends it when present; app-aware Pulse deployments can use it for application separation and reporting context. |
|
|
41
|
+
| `apiBaseUrl` | Yes | `https://pulse.service.primexperts.co.za` | Host only; do not add `/api`. |
|
|
42
|
+
| Website origin | Yes | `https://app.example.com` | Must be allowed by Pulse CORS/backend configuration. |
|
|
43
|
+
|
|
44
|
+
The `appKey` is the value that starts with `app_`. It is not the same as `widgetToken`.
|
|
45
|
+
|
|
46
|
+
A `widgetToken` is normally resolved automatically by Pulse from the organization `slug`; when `appKey` is configured, the agent also sends it for app-aware deployments. Do not configure `widgetToken` unless Pulse explicitly provides a token for a special case.
|
|
47
|
+
|
|
48
|
+
## 3. Install
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
npm install @primexperts.co/pulse-agent@latest
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
For script-tag usage:
|
|
55
|
+
|
|
56
|
+
```html
|
|
57
|
+
<script src="https://unpkg.com/@primexperts.co/pulse-agent@latest/dist/browser/pulse-agent.global.js"></script>
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## 4. Basic Configuration
|
|
61
|
+
|
|
62
|
+
```ts
|
|
63
|
+
import { createPulseAgent } from '@primexperts.co/pulse-agent';
|
|
64
|
+
|
|
65
|
+
createPulseAgent({
|
|
66
|
+
slug: 'vayakids',
|
|
67
|
+
appKey: 'app_your_public_application_key',
|
|
68
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
69
|
+
title: 'VayaKids',
|
|
70
|
+
requireProfile: true,
|
|
71
|
+
autoOpen: false
|
|
72
|
+
});
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
## 5. Error Monitoring Configuration
|
|
76
|
+
|
|
77
|
+
Error monitoring is off by default. Enable it explicitly:
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
createPulseAgent({
|
|
81
|
+
slug: 'vayakids',
|
|
82
|
+
appKey: 'app_your_public_application_key',
|
|
83
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
84
|
+
errorMonitoring: true,
|
|
85
|
+
captureUnhandledErrors: true,
|
|
86
|
+
captureUnhandledRejections: true,
|
|
87
|
+
captureFetchErrors: true,
|
|
88
|
+
environment: 'production',
|
|
89
|
+
release: 'web-1.0.0'
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
When enabled, Pulse Agent reports:
|
|
94
|
+
|
|
95
|
+
- Unhandled browser errors.
|
|
96
|
+
- Unhandled promise rejections.
|
|
97
|
+
- Failed `fetch` HTTP responses.
|
|
98
|
+
- Network errors thrown by `fetch`.
|
|
99
|
+
- Manual errors reported through `captureException`.
|
|
100
|
+
|
|
101
|
+
Manual capture:
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
const agent = createPulseAgent({
|
|
105
|
+
slug: 'vayakids',
|
|
106
|
+
appKey: 'app_your_public_application_key',
|
|
107
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
108
|
+
errorMonitoring: true
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
try {
|
|
112
|
+
await loadImportantData();
|
|
113
|
+
} catch (error) {
|
|
114
|
+
agent.captureException(error, {
|
|
115
|
+
source: 'home.loadImportantData',
|
|
116
|
+
errorType: 'data-load-error',
|
|
117
|
+
endpoint: '/api/important-data',
|
|
118
|
+
pageUrl: window.location.href
|
|
119
|
+
});
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
## 6. Environment Variable Names
|
|
125
|
+
|
|
126
|
+
Use these names in Heroku, Docker, CI, or your hosting platform:
|
|
127
|
+
|
|
128
|
+
```env
|
|
129
|
+
PULSE_AGENT_SLUG=vayakids
|
|
130
|
+
PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
131
|
+
PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
132
|
+
PULSE_AGENT_TITLE=VayaKids
|
|
133
|
+
PULSE_AGENT_ENVIRONMENT=production
|
|
134
|
+
PULSE_AGENT_RELEASE=web-1.0.0
|
|
135
|
+
|
|
136
|
+
PULSE_AGENT_ERROR_MONITORING=true
|
|
137
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
138
|
+
PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
139
|
+
PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Optional:
|
|
143
|
+
|
|
144
|
+
```env
|
|
145
|
+
PULSE_AGENT_FOLLOW_UP_EMAIL_TO=support@example.com
|
|
146
|
+
PULSE_AGENT_DASHBOARD_URL=https://pulse.primexperts.co.za
|
|
147
|
+
PULSE_AGENT_DASHBOARD_SETUP_PATH=/integrations
|
|
148
|
+
PULSE_AGENT_AUTO_OPEN=false
|
|
149
|
+
PULSE_AGENT_REQUIRE_PROFILE=true
|
|
150
|
+
PULSE_AGENT_WHATSAPP_URL=https://api.whatsapp.com/send?phone=27123456789
|
|
151
|
+
PULSE_AGENT_WIDGET_TOKEN=
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
Leave `PULSE_AGENT_WIDGET_TOKEN` empty unless Pulse tells you to use it.
|
|
155
|
+
|
|
156
|
+
## 7. Runtime Config Setup
|
|
157
|
+
|
|
158
|
+
Frontend bundles usually cannot read platform environment variables directly at runtime. Use a runtime config file generated from environment variables.
|
|
159
|
+
|
|
160
|
+
Add this to `index.html` before your app bundle:
|
|
161
|
+
|
|
162
|
+
```html
|
|
163
|
+
<script src="/runtime-config.js"></script>
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
Example `runtime-config.js` output:
|
|
167
|
+
|
|
168
|
+
```js
|
|
169
|
+
window.__APP_RUNTIME_CONFIG__ = {
|
|
170
|
+
pulseAgent: {
|
|
171
|
+
slug: 'vayakids',
|
|
172
|
+
appKey: 'app_your_public_application_key',
|
|
173
|
+
apiBaseUrl: 'https://pulse.service.primexperts.co.za',
|
|
174
|
+
title: 'VayaKids',
|
|
175
|
+
errorMonitoring: true,
|
|
176
|
+
captureUnhandledErrors: true,
|
|
177
|
+
captureUnhandledRejections: true,
|
|
178
|
+
captureFetchErrors: true,
|
|
179
|
+
environment: 'production',
|
|
180
|
+
release: 'web-1.0.0'
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
Initialize from that config:
|
|
186
|
+
|
|
187
|
+
```ts
|
|
188
|
+
import { createPulseAgent, type PulseAgentOptions } from '@primexperts.co/pulse-agent';
|
|
189
|
+
|
|
190
|
+
declare global {
|
|
191
|
+
interface Window {
|
|
192
|
+
__APP_RUNTIME_CONFIG__?: {
|
|
193
|
+
pulseAgent?: Partial<PulseAgentOptions>;
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const pulseAgentConfig = window.__APP_RUNTIME_CONFIG__?.pulseAgent;
|
|
199
|
+
|
|
200
|
+
if (pulseAgentConfig?.slug) {
|
|
201
|
+
createPulseAgent({
|
|
202
|
+
...pulseAgentConfig,
|
|
203
|
+
slug: pulseAgentConfig.slug
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 8. Heroku Setup
|
|
209
|
+
|
|
210
|
+
Set config vars:
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
heroku config:set PULSE_AGENT_SLUG=vayakids
|
|
214
|
+
heroku config:set PULSE_AGENT_APP_KEY=app_your_public_application_key
|
|
215
|
+
heroku config:set PULSE_AGENT_API_BASE_URL=https://pulse.service.primexperts.co.za
|
|
216
|
+
heroku config:set PULSE_AGENT_TITLE=VayaKids
|
|
217
|
+
heroku config:set PULSE_AGENT_ENVIRONMENT=production
|
|
218
|
+
heroku config:set PULSE_AGENT_ERROR_MONITORING=true
|
|
219
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_ERRORS=true
|
|
220
|
+
heroku config:set PULSE_AGENT_CAPTURE_UNHANDLED_REJECTIONS=true
|
|
221
|
+
heroku config:set PULSE_AGENT_CAPTURE_FETCH_ERRORS=true
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
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.
|
|
225
|
+
|
|
226
|
+
## 9. Framework Notes
|
|
227
|
+
|
|
228
|
+
### Angular
|
|
229
|
+
|
|
230
|
+
Initialize in `main.ts` or a browser-only root component. If Angular Universal is used, guard with `typeof window !== 'undefined'`.
|
|
231
|
+
|
|
232
|
+
### React
|
|
233
|
+
|
|
234
|
+
Initialize inside a top-level `useEffect`. Return `agent.destroy()` from cleanup if the component can unmount.
|
|
235
|
+
|
|
236
|
+
### Vue
|
|
237
|
+
|
|
238
|
+
Initialize in `onMounted` and destroy in `onBeforeUnmount`.
|
|
239
|
+
|
|
240
|
+
### Next.js and Nuxt
|
|
241
|
+
|
|
242
|
+
Use a client-only component/plugin. Do not initialize during server rendering.
|
|
243
|
+
|
|
244
|
+
### Static HTML
|
|
245
|
+
|
|
246
|
+
Use the browser global bundle and call `window.PulseAgent.createPulseAgent(...)` after the script loads.
|
|
247
|
+
|
|
248
|
+
## 10. Public Endpoints Used By The Widget
|
|
249
|
+
|
|
250
|
+
Pulse Agent calls these public endpoints:
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
GET /api/pulse/public/webchat/resolve?slug=<slug>[&appKey=<appKey>]
|
|
254
|
+
POST /api/pulse/public/webchat/{widgetToken}/message
|
|
255
|
+
GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<id>
|
|
256
|
+
POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<id>
|
|
257
|
+
GET /api/pulse/public/webchat/{widgetToken}/stream?conversationId=<id>
|
|
258
|
+
POST /api/pulse/public/webchat/{widgetToken}/errors
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
These endpoints are public by design for website visitors. Admin setup endpoints must remain authenticated.
|
|
262
|
+
|
|
263
|
+
## 11. Benefits
|
|
264
|
+
|
|
265
|
+
- One small browser package for chat and optional error reporting.
|
|
266
|
+
- No visitor login required.
|
|
267
|
+
- No need for customers to manage internal widget tokens.
|
|
268
|
+
- Supports runtime config for Heroku and similar platforms.
|
|
269
|
+
- Works with npm, module bundlers, or a CDN script tag.
|
|
270
|
+
- Supports multiple frontend frameworks.
|
|
271
|
+
- Uses standard browser APIs: `fetch`, `EventSource`, and DOM events.
|
|
272
|
+
|
|
273
|
+
## 12. Limitations
|
|
274
|
+
|
|
275
|
+
- Browser-only; no server-side rendering execution.
|
|
276
|
+
- Requires CORS configuration for every website origin.
|
|
277
|
+
- Requires active Pulse Webchat configuration.
|
|
278
|
+
- Requires network access to Pulse API.
|
|
279
|
+
- SSE streaming may be interrupted by proxies or timeout policies.
|
|
280
|
+
- Error monitoring starts only after initialization.
|
|
281
|
+
- Error monitoring does not replace backend logs or APM.
|
|
282
|
+
- `captureFetchErrors` wraps `window.fetch`; non-fetch HTTP clients may need manual reporting.
|
|
283
|
+
- `widgetToken` is advanced and should usually remain unset.
|
|
284
|
+
|
|
285
|
+
## 13. Verification Checklist
|
|
286
|
+
|
|
287
|
+
1. Open the site and confirm the Pulse launcher appears.
|
|
288
|
+
2. In browser dev tools, confirm `resolve?slug=...` succeeds; if your deployment uses app keys, confirm `appKey=...` is included.
|
|
289
|
+
3. Send a test message and confirm `message` succeeds.
|
|
290
|
+
4. Confirm `stream` is open and receives replies.
|
|
291
|
+
5. If history is enabled, confirm `messages?conversationId=...` succeeds.
|
|
292
|
+
6. If transcript email is enabled, confirm the transcript endpoint succeeds.
|
|
293
|
+
7. If error monitoring is enabled, trigger a controlled test error and confirm `/errors` succeeds.
|
|
294
|
+
8. Confirm Pulse Dashboard shows the expected conversation/error entries.
|
|
295
|
+
|
|
296
|
+
## 14. Troubleshooting
|
|
297
|
+
|
|
298
|
+
### Nothing happens after install
|
|
299
|
+
|
|
300
|
+
Installation alone does not run the widget. Your app must import the package and call `createPulseAgent(...)`.
|
|
301
|
+
|
|
302
|
+
### The app key starts with `app_`; where does it go?
|
|
303
|
+
|
|
304
|
+
Use it as `appKey`, or as `PULSE_AGENT_APP_KEY` in environment config.
|
|
305
|
+
|
|
306
|
+
### Where do I get `widgetToken`?
|
|
307
|
+
|
|
308
|
+
Usually nowhere. The widget resolves it automatically from `slug` and `appKey`. Leave `widgetToken` unset unless Pulse gives you one directly.
|
|
309
|
+
|
|
310
|
+
### Errors are not being reported
|
|
311
|
+
|
|
312
|
+
Check that `errorMonitoring` is true, the widget resolves successfully, and the error occurs after initialization.
|
|
313
|
+
|
|
314
|
+
### CORS blocks requests
|
|
315
|
+
|
|
316
|
+
Add the exact frontend origin to Pulse CORS/backend allowlist.
|
|
317
|
+
|
|
318
|
+
### Resolve returns 404
|
|
319
|
+
|
|
320
|
+
Check organization slug, app key, and whether Webchat is enabled for the selected organization/application.
|
|
321
|
+
|
|
322
|
+
### Resolve returns 401 or 403
|
|
323
|
+
|
|
324
|
+
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
|
-
{
|
|
2
|
-
"name": "@primexperts.co/pulse-agent",
|
|
3
|
-
"version": "5.
|
|
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
|
-
"
|
|
17
|
-
"
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
"
|
|
22
|
-
"build:
|
|
23
|
-
"build": "
|
|
24
|
-
"
|
|
25
|
-
"version:
|
|
26
|
-
"version:
|
|
27
|
-
"version:
|
|
28
|
-
"
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
"
|
|
32
|
-
"
|
|
33
|
-
"
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "@primexperts.co/pulse-agent",
|
|
3
|
+
"version": "5.3.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"
|
|
39
|
+
}
|
|
40
|
+
}
|