@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 CHANGED
@@ -1,97 +1,440 @@
1
1
  # @primexperts.co/pulse-agent
2
2
 
3
- Embeddable floating Pulse chat widget for client websites.
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
- ## Documentation
5
+ It is designed for teams that want one lightweight install to do two jobs:
6
6
 
7
- - Adds a floating webchat launcher to any browser-based website or SPA.
8
- - Resolves the active Pulse webchat configuration by organization slug.
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
- ## Install
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 '@primexperts.co/pulse-agent@latest'
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: 'client-abc',
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
- ## Browser/CDN Usage (No Bundler)
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
- const agent = window.PulseAgent.createPulseAgent({
41
- slug: 'client-abc',
42
- apiBaseUrl: 'https://pulse.service.primexperts.co.za'
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
- ## Required Backend Endpoints
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
- - `GET /api/pulse/public/webchat/resolve?slug=<slug>`
50
- - `POST /api/pulse/public/webchat/{widgetToken}/message`
51
- - `GET /api/pulse/public/webchat/{widgetToken}/messages?conversationId=<id>`
52
- - `POST /api/pulse/public/webchat/{widgetToken}/transcript-email?conversationId=<id>`
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
- ## API
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
- ### `createPulseAgent(options)`
237
+ bootstrapApplication(AppComponent);
238
+ ```
58
239
 
59
- Options:
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
- Returns `PulseAgentHandle`:
70
- - `open()`
71
- - `close()`
72
- - `destroy()`
73
- - `update(partialOptions)`
242
+ ```tsx
243
+ import { useEffect } from 'react';
244
+ import { createPulseAgent } from '@primexperts.co/pulse-agent';
74
245
 
75
- ## Notes
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
- - This package is framework-agnostic and browser-only.
78
- - No dashboard/auth code is included in this project.
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
- ## Versioning
258
+ return null;
259
+ }
260
+ ```
85
261
 
86
- Use the built-in version script instead of editing files manually:
262
+ ### Vue
87
263
 
88
- ```bash
89
- npm run version:patch
90
- # or
91
- npm run version:minor
92
- npm run version:major
93
- # or custom semver
94
- npm run version:bump -- 1.2.3
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
- This updates both `package.json` and `package-lock.json`.
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.1.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
- "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
- }
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
+ }