uapp-communication-sdk 1.0.0-dev.54 → 1.0.0-dev.55
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 +648 -0
- package/package.json +1 -1
package/README.md
ADDED
|
@@ -0,0 +1,648 @@
|
|
|
1
|
+
# UAPP Communication SDK
|
|
2
|
+
|
|
3
|
+
Embed Communication Hub modules inside your own web application with a small, typed JavaScript SDK.
|
|
4
|
+
|
|
5
|
+
The SDK can show these widgets:
|
|
6
|
+
|
|
7
|
+
- **Chat** — conversations, messages, calls, and media.
|
|
8
|
+
- **Bookings** — booking and managing meetings.
|
|
9
|
+
- **Schedule** — calendar and availability screens.
|
|
10
|
+
- **Feed** — posts, updates, and notifications.
|
|
11
|
+
|
|
12
|
+
Package name: `uapp-communication-sdk`
|
|
13
|
+
|
|
14
|
+
> The package is published from the `develop` branch as prerelease builds tagged `dev`.
|
|
15
|
+
> Until a stable release is published, install the dev channel with:
|
|
16
|
+
>
|
|
17
|
+
> ```bash
|
|
18
|
+
> npm install uapp-communication-sdk@dev
|
|
19
|
+
> ```
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. What this SDK does
|
|
24
|
+
|
|
25
|
+
The SDK gives you ready-made Communication Hub widgets that you can place in another website or product.
|
|
26
|
+
|
|
27
|
+
You do **not** build chat, feed, booking, or schedule UI yourself. You only:
|
|
28
|
+
|
|
29
|
+
1. Create an SDK API key in Communication Hub.
|
|
30
|
+
2. Add your site origin to the key allowlist.
|
|
31
|
+
3. Add a small server endpoint that signs the current user.
|
|
32
|
+
4. Install this package and register the widgets.
|
|
33
|
+
5. Place a widget tag such as `<uapp-chat>` on your page.
|
|
34
|
+
|
|
35
|
+
The widget then talks directly to the Communication Hub API using short-lived credentials issued for the current user.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## 2. Requirements
|
|
40
|
+
|
|
41
|
+
Your app needs:
|
|
42
|
+
|
|
43
|
+
- **React 18** and **React DOM 18** when using the npm package through a bundler.
|
|
44
|
+
- A Communication Hub **client key**.
|
|
45
|
+
- A Communication Hub **client secret**.
|
|
46
|
+
- A backend endpoint in your own app that can sign a short-lived assertion for the logged-in user.
|
|
47
|
+
- Your website origin added to the SDK key allowlist, for example `https://example.com`.
|
|
48
|
+
|
|
49
|
+
### Important security rule
|
|
50
|
+
|
|
51
|
+
The **client key** can be visible in the browser.
|
|
52
|
+
|
|
53
|
+
The **client secret must never be sent to the browser**. Keep it only on your server, environment variables, or secret manager. Anyone with the secret can sign in as users for that SDK key.
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
## 3. Installation
|
|
58
|
+
|
|
59
|
+
For the current prerelease/dev channel:
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install uapp-communication-sdk@dev
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
After a stable release exists, normal installation will be:
|
|
66
|
+
|
|
67
|
+
```bash
|
|
68
|
+
npm install uapp-communication-sdk
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
Peer dependencies:
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
npm install react@^18.3.1 react-dom@^18.3.1
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## 4. Quick start: React, Vite, Next.js, or any bundler
|
|
80
|
+
|
|
81
|
+
Register the custom elements once in your application entry file.
|
|
82
|
+
|
|
83
|
+
Example: `src/main.tsx`, `src/App.tsx`, or your layout/bootstrap file.
|
|
84
|
+
|
|
85
|
+
```ts
|
|
86
|
+
import { defineCustomElements } from 'uapp-communication-sdk';
|
|
87
|
+
|
|
88
|
+
// Safe to call more than once. Existing elements are not registered again.
|
|
89
|
+
defineCustomElements();
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
Then place the widget in your page and assign its `config` property.
|
|
93
|
+
|
|
94
|
+
```tsx
|
|
95
|
+
import { useEffect, useRef } from 'react';
|
|
96
|
+
|
|
97
|
+
type UappChatElement = HTMLElement & {
|
|
98
|
+
config?: Record<string, unknown>;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
export function CommunicationHubChat() {
|
|
102
|
+
const chatRef = useRef<UappChatElement | null>(null);
|
|
103
|
+
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
if (!chatRef.current) return;
|
|
106
|
+
|
|
107
|
+
chatRef.current.config = {
|
|
108
|
+
clientKey: 'YOUR_CLIENT_KEY',
|
|
109
|
+
apiBaseUrl: 'https://YOUR_COMMUNICATION_HUB_API_URL',
|
|
110
|
+
modules: ['commhub.chat'],
|
|
111
|
+
auth: {
|
|
112
|
+
kind: 'signed',
|
|
113
|
+
getAssertion: async () => {
|
|
114
|
+
const response = await fetch('/api/commhub-assertion', {
|
|
115
|
+
credentials: 'include',
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
throw new Error('Failed to get Communication Hub assertion');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
return response.text();
|
|
123
|
+
},
|
|
124
|
+
},
|
|
125
|
+
onEvent: (event) => {
|
|
126
|
+
console.log('[Communication Hub]', event.type, event.payload);
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
}, []);
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<uapp-chat
|
|
133
|
+
ref={chatRef}
|
|
134
|
+
style={{ display: 'block', height: 'calc(100vh - 120px)' }}
|
|
135
|
+
/>
|
|
136
|
+
);
|
|
137
|
+
}
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### TypeScript custom element note
|
|
141
|
+
|
|
142
|
+
If TypeScript does not know the widget tags, add a small declaration file such as `src/uapp-sdk.d.ts`:
|
|
143
|
+
|
|
144
|
+
```ts
|
|
145
|
+
import type { DetailedHTMLProps, HTMLAttributes } from 'react';
|
|
146
|
+
|
|
147
|
+
declare module 'react/jsx-runtime' {
|
|
148
|
+
namespace JSX {
|
|
149
|
+
interface IntrinsicElements {
|
|
150
|
+
'uapp-chat': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
151
|
+
'uapp-bookings': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
152
|
+
'uapp-schedule': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
153
|
+
'uapp-feed': DetailedHTMLProps<HTMLAttributes<HTMLElement>, HTMLElement>;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## 5. Available widgets and module scopes
|
|
162
|
+
|
|
163
|
+
Each widget needs the matching module scope. Ask only for the modules used on that page.
|
|
164
|
+
|
|
165
|
+
| Widget tag | Required module scope | What it shows |
|
|
166
|
+
| ----------------- | --------------------- | ----------------------------------------------- |
|
|
167
|
+
| `<uapp-chat>` | `commhub.chat` | Messaging, conversations, calls, and chat media |
|
|
168
|
+
| `<uapp-bookings>` | `commhub.bookings` | Meeting booking and booking management |
|
|
169
|
+
| `<uapp-schedule>` | `commhub.schedule` | Calendar, availability, and schedule blocks |
|
|
170
|
+
| `<uapp-feed>` | `commhub.feed` | Feed posts, updates, and notifications |
|
|
171
|
+
|
|
172
|
+
Example with multiple widgets on one page:
|
|
173
|
+
|
|
174
|
+
```tsx
|
|
175
|
+
useEffect(() => {
|
|
176
|
+
const config = {
|
|
177
|
+
clientKey: 'YOUR_CLIENT_KEY',
|
|
178
|
+
apiBaseUrl: 'https://YOUR_COMMUNICATION_HUB_API_URL',
|
|
179
|
+
modules: ['commhub.chat', 'commhub.feed'],
|
|
180
|
+
auth: {
|
|
181
|
+
kind: 'signed',
|
|
182
|
+
getAssertion: async () => {
|
|
183
|
+
const response = await fetch('/api/commhub-assertion', {
|
|
184
|
+
credentials: 'include',
|
|
185
|
+
});
|
|
186
|
+
return response.text();
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
chatRef.current!.config = config;
|
|
192
|
+
feedRef.current!.config = config;
|
|
193
|
+
}, []);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
If a token is missing a required scope, the widget may load but API calls will fail with permission errors.
|
|
197
|
+
|
|
198
|
+
---
|
|
199
|
+
|
|
200
|
+
## 6. Configuration reference
|
|
201
|
+
|
|
202
|
+
Every widget receives configuration through its DOM `config` property.
|
|
203
|
+
|
|
204
|
+
```ts
|
|
205
|
+
const config = {
|
|
206
|
+
clientKey: 'YOUR_CLIENT_KEY',
|
|
207
|
+
apiBaseUrl: 'https://YOUR_COMMUNICATION_HUB_API_URL',
|
|
208
|
+
modules: ['commhub.chat'],
|
|
209
|
+
auth: {
|
|
210
|
+
kind: 'signed',
|
|
211
|
+
getAssertion: async () => 'SIGNED_ASSERTION_FROM_YOUR_SERVER',
|
|
212
|
+
},
|
|
213
|
+
theme: {
|
|
214
|
+
brand: [221, 83, 53],
|
|
215
|
+
accent: [271, 76, 53],
|
|
216
|
+
radius: 10,
|
|
217
|
+
density: 'comfortable',
|
|
218
|
+
mode: 'system',
|
|
219
|
+
font: 'Inter, system-ui, sans-serif',
|
|
220
|
+
},
|
|
221
|
+
onEvent: (event) => console.log(event),
|
|
222
|
+
};
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
### `clientKey`
|
|
226
|
+
|
|
227
|
+
Your SDK client key from Communication Hub.
|
|
228
|
+
|
|
229
|
+
This is safe to place in browser code. It identifies the SDK client but does not authenticate users by itself.
|
|
230
|
+
|
|
231
|
+
### `apiBaseUrl`
|
|
232
|
+
|
|
233
|
+
The base URL of the Communication Hub API.
|
|
234
|
+
|
|
235
|
+
Example:
|
|
236
|
+
|
|
237
|
+
```ts
|
|
238
|
+
apiBaseUrl: 'https://api.your-communication-hub.com';
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Do not point this to your own app API. Point it to the Communication Hub API that issues SDK tokens and serves widget data.
|
|
242
|
+
|
|
243
|
+
### `modules`
|
|
244
|
+
|
|
245
|
+
The Communication Hub modules this page needs.
|
|
246
|
+
|
|
247
|
+
Allowed values:
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
['commhub.chat', 'commhub.bookings', 'commhub.schedule', 'commhub.feed'];
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
Best practice:
|
|
254
|
+
|
|
255
|
+
- Use `['commhub.chat']` for a chat-only page.
|
|
256
|
+
- Use `['commhub.feed']` for a feed-only page.
|
|
257
|
+
- Use multiple scopes only when the page truly renders multiple modules.
|
|
258
|
+
|
|
259
|
+
Requesting a scope that the API key is not allowed to use fails the token request with `invalid_scope`.
|
|
260
|
+
|
|
261
|
+
### `auth`
|
|
262
|
+
|
|
263
|
+
For browser custom elements, use signed auth:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
auth: {
|
|
267
|
+
kind: 'signed',
|
|
268
|
+
getAssertion: async () => {
|
|
269
|
+
const response = await fetch('/api/commhub-assertion', {
|
|
270
|
+
credentials: 'include',
|
|
271
|
+
});
|
|
272
|
+
return response.text();
|
|
273
|
+
},
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
`getAssertion` should call your own backend. Your backend signs an assertion for the current logged-in user. The browser should never sign assertions itself.
|
|
278
|
+
|
|
279
|
+
### `theme`
|
|
280
|
+
|
|
281
|
+
Optional visual customization.
|
|
282
|
+
|
|
283
|
+
```ts
|
|
284
|
+
theme: {
|
|
285
|
+
brand: [221, 83, 53], // HSL: hue, saturation %, lightness %
|
|
286
|
+
accent: [271, 76, 53], // HSL: hue, saturation %, lightness %
|
|
287
|
+
radius: 10, // corner radius in pixels
|
|
288
|
+
density: 'comfortable', // 'comfortable' or 'compact'
|
|
289
|
+
mode: 'system', // 'light', 'dark', or 'system'
|
|
290
|
+
font: 'Inter, sans-serif',
|
|
291
|
+
}
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
### `onEvent`
|
|
295
|
+
|
|
296
|
+
Optional callback for widget lifecycle and errors.
|
|
297
|
+
|
|
298
|
+
```ts
|
|
299
|
+
onEvent: (event) => {
|
|
300
|
+
if (event.type === 'error') {
|
|
301
|
+
console.error('Communication Hub widget error:', event.payload);
|
|
302
|
+
}
|
|
303
|
+
};
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Events:
|
|
307
|
+
|
|
308
|
+
| Event | Meaning |
|
|
309
|
+
| -------------- | ------------------------------------------------------------------------------------- |
|
|
310
|
+
| `ready` | The widget received a token and is ready. The payload lists granted modules. |
|
|
311
|
+
| `scope-denied` | The token exists but does not include a module required by this widget. |
|
|
312
|
+
| `auth-expired` | A request was rejected as unauthenticated. The widget will ask for another assertion. |
|
|
313
|
+
| `error` | Something failed inside the widget. Log this for support/debugging. |
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## 7. Server side: signing user assertions
|
|
318
|
+
|
|
319
|
+
The widget needs a short-lived signed assertion to exchange for a Communication Hub token.
|
|
320
|
+
|
|
321
|
+
Your server should:
|
|
322
|
+
|
|
323
|
+
1. Verify the user is logged in to your app.
|
|
324
|
+
2. Build a JWT payload for that user.
|
|
325
|
+
3. Sign it with your Communication Hub client secret using `HS256`.
|
|
326
|
+
4. Return the assertion as plain text.
|
|
327
|
+
|
|
328
|
+
### Required assertion claims
|
|
329
|
+
|
|
330
|
+
| Claim | Value |
|
|
331
|
+
| ------- | ----------------------------------------------------------------- |
|
|
332
|
+
| `iss` | Your Communication Hub client key |
|
|
333
|
+
| `aud` | The Communication Hub audience/API URL expected by your Hub setup |
|
|
334
|
+
| `sub` | The current user's ID in your system |
|
|
335
|
+
| `email` | The current user's email |
|
|
336
|
+
| `name` | The current user's display name |
|
|
337
|
+
| `roles` | Your app's role names for this user |
|
|
338
|
+
| `exp` | Expiry time, maximum 5 minutes from now |
|
|
339
|
+
| `jti` | Unique random ID per assertion |
|
|
340
|
+
|
|
341
|
+
Each assertion should be short-lived and single-use. Do not cache it in the browser.
|
|
342
|
+
|
|
343
|
+
### Node.js / Express example
|
|
344
|
+
|
|
345
|
+
Install JWT support:
|
|
346
|
+
|
|
347
|
+
```bash
|
|
348
|
+
npm install jsonwebtoken
|
|
349
|
+
npm install --save-dev @types/jsonwebtoken
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
Server route:
|
|
353
|
+
|
|
354
|
+
```ts
|
|
355
|
+
import crypto from 'node:crypto';
|
|
356
|
+
import jwt from 'jsonwebtoken';
|
|
357
|
+
import type { Request, Response } from 'express';
|
|
358
|
+
|
|
359
|
+
const CLIENT_KEY = process.env.COMMHUB_CLIENT_KEY!;
|
|
360
|
+
const CLIENT_SECRET = process.env.COMMHUB_CLIENT_SECRET!;
|
|
361
|
+
const AUDIENCE = process.env.COMMHUB_AUDIENCE!;
|
|
362
|
+
|
|
363
|
+
function signCommunicationHubAssertion(user: {
|
|
364
|
+
id: string;
|
|
365
|
+
email: string;
|
|
366
|
+
fullName: string;
|
|
367
|
+
roles: string[];
|
|
368
|
+
}) {
|
|
369
|
+
return jwt.sign(
|
|
370
|
+
{
|
|
371
|
+
iss: CLIENT_KEY,
|
|
372
|
+
aud: AUDIENCE,
|
|
373
|
+
sub: user.id,
|
|
374
|
+
email: user.email,
|
|
375
|
+
name: user.fullName,
|
|
376
|
+
roles: user.roles,
|
|
377
|
+
},
|
|
378
|
+
CLIENT_SECRET,
|
|
379
|
+
{
|
|
380
|
+
algorithm: 'HS256',
|
|
381
|
+
expiresIn: '5m',
|
|
382
|
+
jwtid: crypto.randomUUID(),
|
|
383
|
+
},
|
|
384
|
+
);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
app.get('/api/commhub-assertion', requireLogin, (req: Request, res: Response) => {
|
|
388
|
+
const assertion = signCommunicationHubAssertion(req.user);
|
|
389
|
+
res.type('text/plain').send(assertion);
|
|
390
|
+
});
|
|
391
|
+
```
|
|
392
|
+
|
|
393
|
+
Browser side:
|
|
394
|
+
|
|
395
|
+
```ts
|
|
396
|
+
getAssertion: async () => {
|
|
397
|
+
const response = await fetch('/api/commhub-assertion', {
|
|
398
|
+
credentials: 'include',
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
if (!response.ok) {
|
|
402
|
+
throw new Error('Could not create Communication Hub assertion');
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
return response.text();
|
|
406
|
+
};
|
|
407
|
+
```
|
|
408
|
+
|
|
409
|
+
### PHP example
|
|
410
|
+
|
|
411
|
+
Install Firebase JWT:
|
|
412
|
+
|
|
413
|
+
```bash
|
|
414
|
+
composer require firebase/php-jwt
|
|
415
|
+
```
|
|
416
|
+
|
|
417
|
+
Example:
|
|
418
|
+
|
|
419
|
+
```php
|
|
420
|
+
<?php
|
|
421
|
+
use Firebase\JWT\JWT;
|
|
422
|
+
|
|
423
|
+
$clientKey = getenv('COMMHUB_CLIENT_KEY');
|
|
424
|
+
$clientSecret = getenv('COMMHUB_CLIENT_SECRET');
|
|
425
|
+
$audience = getenv('COMMHUB_AUDIENCE');
|
|
426
|
+
|
|
427
|
+
$payload = [
|
|
428
|
+
'iss' => $clientKey,
|
|
429
|
+
'aud' => $audience,
|
|
430
|
+
'iat' => time(),
|
|
431
|
+
'exp' => time() + 300,
|
|
432
|
+
'jti' => bin2hex(random_bytes(16)),
|
|
433
|
+
'sub' => $user->id,
|
|
434
|
+
'email' => $user->email,
|
|
435
|
+
'name' => $user->fullName,
|
|
436
|
+
'roles' => $user->roles,
|
|
437
|
+
];
|
|
438
|
+
|
|
439
|
+
$assertion = JWT::encode($payload, $clientSecret, 'HS256');
|
|
440
|
+
|
|
441
|
+
header('Content-Type: text/plain');
|
|
442
|
+
echo $assertion;
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
## 8. Full working HTML example after registration
|
|
448
|
+
|
|
449
|
+
This example assumes your app has already imported the SDK and called `defineCustomElements()`.
|
|
450
|
+
|
|
451
|
+
```html
|
|
452
|
+
<uapp-chat id="commhub-chat" style="display:block;height:600px"></uapp-chat>
|
|
453
|
+
|
|
454
|
+
<script>
|
|
455
|
+
document.getElementById('commhub-chat').config = {
|
|
456
|
+
clientKey: 'YOUR_CLIENT_KEY',
|
|
457
|
+
apiBaseUrl: 'https://YOUR_COMMUNICATION_HUB_API_URL',
|
|
458
|
+
modules: ['commhub.chat'],
|
|
459
|
+
auth: {
|
|
460
|
+
kind: 'signed',
|
|
461
|
+
getAssertion: async () => {
|
|
462
|
+
const response = await fetch('/api/commhub-assertion', {
|
|
463
|
+
credentials: 'include',
|
|
464
|
+
});
|
|
465
|
+
return response.text();
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
theme: {
|
|
469
|
+
mode: 'system',
|
|
470
|
+
density: 'comfortable',
|
|
471
|
+
},
|
|
472
|
+
onEvent: (event) => console.log('[commhub]', event),
|
|
473
|
+
};
|
|
474
|
+
</script>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
---
|
|
478
|
+
|
|
479
|
+
## 9. Layout rules
|
|
480
|
+
|
|
481
|
+
Give each widget a real height.
|
|
482
|
+
|
|
483
|
+
Good:
|
|
484
|
+
|
|
485
|
+
```html
|
|
486
|
+
<uapp-chat style="display:block;height:600px"></uapp-chat>
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
Good:
|
|
490
|
+
|
|
491
|
+
```html
|
|
492
|
+
<uapp-chat style="display:block;height:calc(100vh - 120px)"></uapp-chat>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Inside a flex layout:
|
|
496
|
+
|
|
497
|
+
```html
|
|
498
|
+
<div style="display:flex;flex-direction:column;height:100vh">
|
|
499
|
+
<header>Header</header>
|
|
500
|
+
<uapp-chat style="display:block;flex:1;min-height:0"></uapp-chat>
|
|
501
|
+
</div>
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Avoid using only `height: 100%` unless every parent element up to the viewport also has a fixed height. Without a definite height, chat panels and composers may appear in the wrong place.
|
|
505
|
+
|
|
506
|
+
---
|
|
507
|
+
|
|
508
|
+
## 10. Common integration flow
|
|
509
|
+
|
|
510
|
+
1. In Communication Hub, create an SDK key.
|
|
511
|
+
2. Enable the modules the site needs: chat, bookings, schedule, or feed.
|
|
512
|
+
3. Add allowed origins, for example:
|
|
513
|
+
- `http://localhost:3000`
|
|
514
|
+
- `https://yourdomain.com`
|
|
515
|
+
4. Save the client key and client secret.
|
|
516
|
+
5. Store the client secret on your server only.
|
|
517
|
+
6. Create `/api/commhub-assertion` in your server app.
|
|
518
|
+
7. Install the SDK package.
|
|
519
|
+
8. Register the custom elements with `defineCustomElements()`.
|
|
520
|
+
9. Add the widget tag to your page.
|
|
521
|
+
10. Assign the config object to the widget element.
|
|
522
|
+
11. Open the browser console and check for the `ready` event.
|
|
523
|
+
|
|
524
|
+
---
|
|
525
|
+
|
|
526
|
+
## 11. Troubleshooting
|
|
527
|
+
|
|
528
|
+
### Widget tag appears in the DOM but nothing renders
|
|
529
|
+
|
|
530
|
+
Make sure `defineCustomElements()` was called before or shortly after the tag is placed on the page.
|
|
531
|
+
|
|
532
|
+
```ts
|
|
533
|
+
import { defineCustomElements } from 'uapp-communication-sdk';
|
|
534
|
+
defineCustomElements();
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### Widget renders but API calls return 403
|
|
538
|
+
|
|
539
|
+
Usually the `modules` array is missing or does not contain the scope required by the widget.
|
|
540
|
+
|
|
541
|
+
Example for chat:
|
|
542
|
+
|
|
543
|
+
```ts
|
|
544
|
+
modules: ['commhub.chat'];
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
### Token request fails with `invalid_scope`
|
|
548
|
+
|
|
549
|
+
The page requested a module that the SDK key is not allowed to use. Enable that module for the key or remove the scope from `modules`.
|
|
550
|
+
|
|
551
|
+
### Token request fails with `invalid_grant`
|
|
552
|
+
|
|
553
|
+
Common causes:
|
|
554
|
+
|
|
555
|
+
- `iss` is not the client key.
|
|
556
|
+
- `aud` does not match the Communication Hub audience.
|
|
557
|
+
- The assertion expired.
|
|
558
|
+
- The assertion lifetime is longer than 5 minutes.
|
|
559
|
+
- The same assertion was reused.
|
|
560
|
+
- The JWT was not signed with `HS256` and the correct client secret.
|
|
561
|
+
|
|
562
|
+
### Token request fails with `unauthorized_client`
|
|
563
|
+
|
|
564
|
+
The current browser origin is not in the key allowlist.
|
|
565
|
+
|
|
566
|
+
Add the exact origin. Include scheme and domain. Include port for local development.
|
|
567
|
+
|
|
568
|
+
Examples:
|
|
569
|
+
|
|
570
|
+
```text
|
|
571
|
+
http://localhost:3000
|
|
572
|
+
https://example.com
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
### Token request fails with `invalid_client`
|
|
576
|
+
|
|
577
|
+
The client key is wrong, disabled, or not known by the Communication Hub API.
|
|
578
|
+
|
|
579
|
+
### Layout looks broken
|
|
580
|
+
|
|
581
|
+
Give the widget a definite height. See [Layout rules](#9-layout-rules).
|
|
582
|
+
|
|
583
|
+
### Browser says the custom element is already defined
|
|
584
|
+
|
|
585
|
+
Calling `defineCustomElements()` from this SDK is idempotent. If you manually register elements elsewhere, remove the manual registration and let the SDK do it.
|
|
586
|
+
|
|
587
|
+
---
|
|
588
|
+
|
|
589
|
+
## 12. Security checklist
|
|
590
|
+
|
|
591
|
+
Before going live, verify:
|
|
592
|
+
|
|
593
|
+
- The client secret is not in frontend code.
|
|
594
|
+
- The assertion endpoint requires your normal user login/session.
|
|
595
|
+
- The assertion endpoint returns an assertion only for the current authenticated user.
|
|
596
|
+
- Assertions expire within 5 minutes.
|
|
597
|
+
- Each assertion has a unique `jti`.
|
|
598
|
+
- The SDK key allowlist contains only trusted origins.
|
|
599
|
+
- The `modules` array asks only for the modules used on the current page.
|
|
600
|
+
- Errors from `onEvent` are logged somewhere useful.
|
|
601
|
+
|
|
602
|
+
---
|
|
603
|
+
|
|
604
|
+
## 13. Package exports
|
|
605
|
+
|
|
606
|
+
```ts
|
|
607
|
+
import {
|
|
608
|
+
defineCustomElements,
|
|
609
|
+
registerChatWidget,
|
|
610
|
+
registerFeedWidget,
|
|
611
|
+
registerBookingsWidget,
|
|
612
|
+
registerScheduleWidget,
|
|
613
|
+
CommsProvider,
|
|
614
|
+
WidgetRoot,
|
|
615
|
+
SDK_MODULE_SCOPES,
|
|
616
|
+
} from 'uapp-communication-sdk';
|
|
617
|
+
|
|
618
|
+
import type {
|
|
619
|
+
AuthConfig,
|
|
620
|
+
CommsProviderProps,
|
|
621
|
+
SdkEvent,
|
|
622
|
+
SdkModuleScope,
|
|
623
|
+
ThemeConfig,
|
|
624
|
+
ThemeDensity,
|
|
625
|
+
ThemeMode,
|
|
626
|
+
WidgetRootProps,
|
|
627
|
+
} from 'uapp-communication-sdk';
|
|
628
|
+
```
|
|
629
|
+
|
|
630
|
+
Most integrations only need `defineCustomElements()`.
|
|
631
|
+
|
|
632
|
+
---
|
|
633
|
+
|
|
634
|
+
## 14. Support information to collect
|
|
635
|
+
|
|
636
|
+
If an integration fails, collect:
|
|
637
|
+
|
|
638
|
+
- Package version from `npm list uapp-communication-sdk`.
|
|
639
|
+
- Browser and browser version.
|
|
640
|
+
- Widget tag used, for example `<uapp-chat>`.
|
|
641
|
+
- `clientKey` value, but **not** the client secret.
|
|
642
|
+
- `apiBaseUrl`.
|
|
643
|
+
- `modules` array.
|
|
644
|
+
- Browser console errors.
|
|
645
|
+
- `onEvent` output.
|
|
646
|
+
- Network response body for the failed token/API request.
|
|
647
|
+
|
|
648
|
+
Never share the client secret in tickets, screenshots, chat, email, or frontend code.
|
package/package.json
CHANGED