helpdesk-app-framework-sdk 1.0.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 ADDED
@@ -0,0 +1,587 @@
1
+ # BoldDesk App Framework SDK
2
+
3
+ The BoldDesk App Framework (BAF) SDK is a JavaScript library that simplifies cross-frame communication between iframed apps and the BoldDesk App Framework, enabling seamless integration of custom applications into the BoldDesk helpdesk platform.
4
+
5
+ ## Overview
6
+
7
+ The BAF SDK provides a unified interface for:
8
+ - **Data Access**: Retrieve and update ticket, contact, and chat information
9
+ - **Event Handling**: Listen to and respond to platform events
10
+ - **Cross-Frame Communication**: Safely communicate between iframes and the host
11
+ - **API Requests**: Make secure HTTP requests through BoldDesk proxy
12
+ - **App Instances**: Manage app instances and multi-instance scenarios
13
+ - **Context & Metadata**: Access runtime context and app metadata
14
+
15
+ ## Getting Started
16
+
17
+ ### Installation
18
+
19
+ ```bash
20
+ npm install bolddesk_app_framework_sdk
21
+ ```
22
+
23
+ ### Basic Usage
24
+
25
+ ```html
26
+ <script src="path/to/baf_sdk.min.js"></script>
27
+ <script>
28
+ const client = BAFClient.init((context) => {
29
+ console.log('App initialized!');
30
+ console.log('User:', context.user.name);
31
+ });
32
+ </script>
33
+ ```
34
+
35
+ ### Or as an ES Module
36
+
37
+ ```javascript
38
+ import BAFClient from 'bolddesk_app_framework_sdk';
39
+
40
+ const client = BAFClient.init((context) => {
41
+ console.log('App initialized!');
42
+ });
43
+ ```
44
+
45
+ ## Core Concepts
46
+
47
+ ### Client Initialization
48
+
49
+ Initialize the SDK when your app loads:
50
+
51
+ ```javascript
52
+ const client = BAFClient.init((context) => {
53
+ // Called when app is registered and ready
54
+ console.log('Module:', context.module); // ticket, contact, chat, etc.
55
+ console.log('Object ID:', context.objectId); // Current object being viewed
56
+ console.log('User:', context.user.name); // Current user information
57
+ });
58
+ ```
59
+
60
+ The `init()` function returns a Client instance that provides access to all APIs.
61
+
62
+ ## API Reference
63
+
64
+ ### Context API
65
+
66
+ Access runtime environment information through the `context` object.
67
+
68
+ ```javascript
69
+ // Get organization details
70
+ client.context.getOrgId();
71
+ client.context.getOrgName();
72
+
73
+ // Get brand information
74
+ client.context.getBrandId();
75
+ client.context.getBrandName();
76
+
77
+ // Get current module and object
78
+ client.context.getModule(); // 'ticket', 'contact', 'chat', etc.
79
+ client.context.getObjectId(); // ID of current object
80
+
81
+ // Get user information
82
+ client.context.getUser(); // Full user object
83
+ client.context.getUserId();
84
+ client.context.getUserEmail();
85
+ client.context.getUserName();
86
+ client.context.getUserTimezone();
87
+
88
+ // Get plan information
89
+ const plan = client.context.getPlan();
90
+ console.log(plan.id, plan.name);
91
+ ```
92
+
93
+ ### Metadata API
94
+
95
+ Access app and installation metadata through the `metadata` object.
96
+
97
+ ```javascript
98
+ // Get app information
99
+ client.metadata.getAppId();
100
+ client.metadata.getAppName();
101
+ client.metadata.getVersion();
102
+
103
+ // Get installation details
104
+ client.metadata.getInstallationId();
105
+ client.metadata.getInstallDate();
106
+
107
+ // Check permissions
108
+ if (client.metadata.hasReadAccess()) {
109
+ // App has read permission
110
+ }
111
+
112
+ if (client.metadata.hasWriteAccess()) {
113
+ // App has write permission
114
+ }
115
+
116
+ // Check status
117
+ client.metadata.isActive();
118
+ client.metadata.isEnabled();
119
+
120
+ // Get locations
121
+ const locations = client.metadata.getLocations();
122
+ console.log(locations); // ['desk.ticket.view.rightpanel', ...]
123
+
124
+ // Check if location is supported
125
+ if (client.metadata.isLocationSupported('desk.ticket.view.rightpanel')) {
126
+ // Location is supported
127
+ }
128
+ ```
129
+
130
+ ### Data API (get/set)
131
+
132
+ Retrieve and update data from the platform context.
133
+
134
+ #### Get Data
135
+
136
+ ```javascript
137
+ // Get single data point
138
+ client.get('ticket.subject').then(data => {
139
+ console.log(data['ticket.subject']);
140
+ });
141
+
142
+ // Get multiple data points
143
+ client.get(['ticket.subject', 'ticket.description']).then(data => {
144
+ console.log(data['ticket.subject']);
145
+ console.log(data['ticket.description']);
146
+ });
147
+
148
+ // Error handling
149
+ client.get('ticket.id')
150
+ .then(data => console.log(data))
151
+ .catch(error => console.error('Error:', error));
152
+ ```
153
+
154
+ #### Set Data
155
+
156
+ ```javascript
157
+ // Update single field
158
+ client.set('ticket.subject', 'Updated Subject')
159
+ .then(() => console.log('Updated!'))
160
+ .catch(error => console.error('Error:', error));
161
+
162
+ // Set structured data
163
+ client.set('ticket.customFields', {
164
+ field1: 'value1',
165
+ field2: 'value2'
166
+ });
167
+ ```
168
+
169
+ ### Event Handling (on/off)
170
+
171
+ Listen to platform events and react to changes.
172
+
173
+ ```javascript
174
+ // Listen for ticket updates
175
+ client.on('ticket.updated', (ticket) => {
176
+ console.log('Ticket updated:', ticket);
177
+ });
178
+
179
+ // Listen for custom events
180
+ client.on('contact.selected', (contact) => {
181
+ console.log('Contact selected:', contact);
182
+ });
183
+
184
+ // Remove specific listener
185
+ const handler = (ticket) => console.log(ticket);
186
+ client.on('ticket.updated', handler);
187
+ client.off('ticket.updated', handler);
188
+
189
+ // Remove all listeners for an event
190
+ client.off('ticket.updated');
191
+ ```
192
+
193
+ ### Invoke Actions (invoke)
194
+
195
+ Execute platform-exposed methods.
196
+
197
+ ```javascript
198
+ // Open a modal
199
+ client.invoke('modal.open', {
200
+ title: 'Confirm Action',
201
+ message: 'Are you sure?',
202
+ buttons: ['Yes', 'No']
203
+ }).then(result => {
204
+ console.log('User clicked:', result);
205
+ });
206
+
207
+ // Show notification
208
+ client.invoke('notification.show', {
209
+ type: 'success',
210
+ message: 'Operation completed'
211
+ });
212
+
213
+ // Navigate to view
214
+ client.invoke('navigation.goto', {
215
+ view: 'ticket',
216
+ id: '12345'
217
+ });
218
+ ```
219
+
220
+ ### Custom Events (trigger)
221
+
222
+ Emit custom events to communicate with other parts of the system.
223
+
224
+ ```javascript
225
+ // Emit custom event
226
+ client.trigger('custom.dataUpdated', {
227
+ status: 'success',
228
+ recordId: '12345'
229
+ });
230
+
231
+ // Listen for your own events
232
+ client.on('custom.dataUpdated', (data) => {
233
+ console.log('Data updated:', data);
234
+ });
235
+ ```
236
+
237
+ ### Capability Check (has)
238
+
239
+ Check if a specific capability or data path is available.
240
+
241
+ ```javascript
242
+ // Check if a custom field exists
243
+ client.has('ticket.custom_field_123').then(exists => {
244
+ if (exists) {
245
+ console.log('Custom field is available');
246
+ }
247
+ });
248
+
249
+ // Check if a capability is available
250
+ client.has('capability.updateTicket').then(available => {
251
+ if (available) {
252
+ console.log('Can update tickets');
253
+ }
254
+ });
255
+ ```
256
+
257
+ ### Request API (Secure Proxy)
258
+
259
+ Make HTTP requests securely through the BoldDesk proxy.
260
+
261
+ **Important**: Storage and resources APIs are not available in Zendesk-compatible mode.
262
+
263
+ ```javascript
264
+ // Basic GET request
265
+ client.request.get('https://api.example.com/data')
266
+ .then(response => console.log(response.data))
267
+ .catch(error => console.error(error));
268
+
269
+ // POST request with data
270
+ client.request.post('https://api.example.com/tickets', {
271
+ subject: 'New Ticket',
272
+ priority: 'high'
273
+ }).then(response => console.log('Created:', response.data));
274
+
275
+ // Using full request method
276
+ client.request.request({
277
+ url: 'https://api.example.com/users',
278
+ method: 'GET',
279
+ headers: {
280
+ 'Authorization': 'Bearer {{setting.api_key}}' // Secure setting placeholder
281
+ },
282
+ params: {
283
+ status: 'active',
284
+ limit: 20
285
+ },
286
+ timeout: 30000,
287
+ autoRetry: true,
288
+ maxRetry: 3
289
+ }).then(response => {
290
+ console.log('Status:', response.status);
291
+ console.log('Data:', response.data);
292
+ });
293
+
294
+ // PUT request
295
+ client.request.put('https://api.example.com/tickets/123', {
296
+ status: 'resolved'
297
+ });
298
+
299
+ // DELETE request
300
+ client.request.delete('https://api.example.com/tickets/123');
301
+
302
+ // PATCH request
303
+ client.request.patch('https://api.example.com/tickets/123', {
304
+ priority: 'low'
305
+ });
306
+ ```
307
+
308
+ #### Request Options
309
+
310
+ | Option | Type | Required | Default | Description |
311
+ |--------|------|----------|---------|-------------|
312
+ | `url` | string | Yes | - | Full URL of API endpoint |
313
+ | `method` | string | Yes | - | HTTP method (GET, POST, PUT, DELETE, PATCH) |
314
+ | `headers` | object | No | {} | HTTP headers |
315
+ | `params` | object | No | - | Query parameters |
316
+ | `body` | object/string | No | - | Request payload (POST/PUT/PATCH) |
317
+ | `timeout` | number | No | 15000 | Timeout in ms (max 30000) |
318
+ | `autoRetry` | boolean | No | true | Auto-retry on 429/5xx |
319
+ | `maxRetry` | number | No | 3 | Max retry attempts |
320
+ | `retryDelay` | number | No | 1000 | Delay between retries (ms) |
321
+
322
+ #### Request Limitations
323
+
324
+ - Maximum request payload: 100 KB
325
+ - Maximum response size: 6 MB
326
+ - Default timeout: 15 seconds (configurable up to 30 seconds)
327
+ - Rate limit: 50 requests per minute per app per account
328
+ - Binary file upload/download: Not supported
329
+
330
+ ### Instance API
331
+
332
+ Manage app instances (for multi-instance widgets).
333
+
334
+ ```javascript
335
+ // Get current instance
336
+ const currentInstance = client.instance.current();
337
+ console.log('Instance ID:', currentInstance.getId());
338
+
339
+ // Get specific instance
340
+ const instance = client.instance.get('instance-id-123');
341
+
342
+ // Get all active instances
343
+ const allInstances = client.instance.all();
344
+ allInstances.forEach(inst => {
345
+ console.log(inst.getId());
346
+ });
347
+
348
+ // Create new instance
349
+ client.instance.create({
350
+ widgets: ['widget1', 'widget2']
351
+ }).then(instance => {
352
+ console.log('Created instance:', instance.getId());
353
+ });
354
+
355
+ // Send message to other instances
356
+ client.instance.send(['instance-1', 'instance-2'], 'update-channel', {
357
+ type: 'refresh',
358
+ data: newData
359
+ });
360
+
361
+ // Receive messages from other instances
362
+ client.instance.receive('update-channel', (message) => {
363
+ console.log('Received message:', message);
364
+ });
365
+
366
+ // Resize widget
367
+ client.instance.resize(500); // Set height to 500px
368
+
369
+ // Close current instance
370
+ client.instance.close();
371
+ ```
372
+
373
+ ## Widget Locations
374
+
375
+ Apps can be placed in specific locations in the BoldDesk UI:
376
+
377
+ | Location | Area | Description |
378
+ |----------|------|-------------|
379
+ | `desk.menu.left` | Left Sidebar | Full-screen app in left menu |
380
+ | `desk.ticket.view.rightpanel` | Right Panel (Ticket View) | Contextual panel on ticket page |
381
+ | `desk.contact.view.rightpanel` | Right Panel (Contact View) | Contextual panel on contact page |
382
+ | `desk.contactgroup.view.rightpanel` | Right Panel (Contact Group View) | Contextual panel on contact group page |
383
+ | `desk.chat.view.rightpanel` | Right Panel (Chat View) | Contextual panel on chat page |
384
+ | `desk.cti.widget` | Bottom-Left | CTI widget in bottom-left corner |
385
+
386
+ ## Manifest Configuration
387
+
388
+ Your app requires a `manifest.json` file:
389
+
390
+ ```json
391
+ {
392
+ "name": "My BoldDesk App",
393
+ "version": "1.0.0",
394
+ "frameworkVersion": "1.0.0",
395
+ "product": "BoldDesk",
396
+ "developer": {
397
+ "name": "John Doe",
398
+ "contactEmail": "john@example.com",
399
+ "supportEmail": "support@example.com",
400
+ "websiteUrl": "https://myapp.com",
401
+ "privacyUrl": "https://myapp.com/privacy",
402
+ "termsOfUseUrl": "https://myapp.com/terms"
403
+ },
404
+ "widgets": [
405
+ {
406
+ "name": "Ticket Widget",
407
+ "location": "desk.ticket.view.rightpanel",
408
+ "url": "widgets/ticket/index.html"
409
+ }
410
+ ],
411
+ "trustedDomains": [
412
+ "https://api.example.com",
413
+ "https://cdn.example.com"
414
+ ],
415
+ "settings": {
416
+ "enablePermission": true,
417
+ "enableReadPermission": true,
418
+ "enableWritePermission": false,
419
+ "fields": [
420
+ {
421
+ "key": "api_key",
422
+ "label": "API Key",
423
+ "type": "text",
424
+ "required": true,
425
+ "secure": true
426
+ }
427
+ ]
428
+ },
429
+ "internalAuth": {
430
+ "authType": "oauth",
431
+ "clientId": "your-client-id",
432
+ "clientSecret": "your-client-secret",
433
+ "authorizeUri": "https://auth.example.com/oauth/authorize",
434
+ "accessTokenUri": "https://auth.example.com/oauth/token",
435
+ "redirectUri": "https://myapp.com/oauth/callback",
436
+ "scopes": ["read", "write"]
437
+ }
438
+ }
439
+ ```
440
+
441
+ ## Security Best Practices
442
+
443
+ 1. **Never expose sensitive data in client code**
444
+ - Use `secure: true` in manifest for sensitive settings
445
+ - Reference settings as `{{setting.key}}` in API requests
446
+ - Platform replaces values server-side
447
+
448
+ 2. **Validate all data**
449
+ - Validate user input before API calls
450
+ - Check response data types and values
451
+ - Handle errors gracefully
452
+
453
+ 3. **Use trusted domains**
454
+ - Only add domains to `trustedDomains` that you control
455
+ - Verify HTTPS certificates for external APIs
456
+
457
+ 4. **Handle permissions**
458
+ - Check `metadata.hasReadAccess()` and `metadata.hasWriteAccess()`
459
+ - Gracefully degrade functionality for limited permissions
460
+
461
+ ## Error Handling
462
+
463
+ ```javascript
464
+ // Handle promise errors
465
+ client.get('ticket.id')
466
+ .then(data => console.log(data))
467
+ .catch(error => {
468
+ console.error('Error:', error.message);
469
+ // Show user-friendly error message
470
+ });
471
+
472
+ // Try-catch with async/await
473
+ async function fetchTicketData() {
474
+ try {
475
+ const data = await client.get('ticket.id');
476
+ console.log(data);
477
+ } catch (error) {
478
+ console.error('Failed to fetch ticket:', error);
479
+ }
480
+ }
481
+ ```
482
+
483
+ ## Development
484
+
485
+ ### Build
486
+
487
+ ```bash
488
+ npm install
489
+ npm run build
490
+ ```
491
+
492
+ ### Development Build
493
+
494
+ ```bash
495
+ npm run build:dev
496
+ npm run server # Serve at http://localhost:9001
497
+ ```
498
+
499
+ ### Testing
500
+
501
+ ```bash
502
+ npm test
503
+ ```
504
+
505
+ ### Linting
506
+
507
+ ```bash
508
+ npm run lint
509
+ ```
510
+
511
+ ## Limitations & Compatibility
512
+
513
+ - **Storage API**: Not available (use secure settings or your own backend)
514
+ - **Resources API**: Not available (resources are managed via manifest)
515
+ - **Binary transfers**: Not supported via request proxy
516
+ - **CORS**: Handled by proxy (no direct CORS in app code)
517
+ - **Maximum payload**: 100 KB requests, 6 MB responses
518
+ - **Rate limiting**: 50 requests/minute per app per account
519
+
520
+ ## Examples
521
+
522
+ ### Complete Ticket Widget
523
+
524
+ ```javascript
525
+ import BAFClient from 'bolddesk_app_framework_sdk';
526
+
527
+ const client = BAFClient.init(async (context) => {
528
+ console.log('App loaded for:', context.module);
529
+
530
+ try {
531
+ // Get ticket data
532
+ const data = await client.get([
533
+ 'ticket.subject',
534
+ 'ticket.description',
535
+ 'ticket.status',
536
+ 'ticket.requester.email'
537
+ ]);
538
+
539
+ console.log('Ticket:', data);
540
+
541
+ // Listen for updates
542
+ client.on('ticket.updated', (ticket) => {
543
+ console.log('Ticket updated:', ticket);
544
+ });
545
+
546
+ // Listen for status changes
547
+ client.on('ticket.statusChanged', (status) => {
548
+ console.log('New status:', status);
549
+ });
550
+
551
+ } catch (error) {
552
+ console.error('Error loading ticket:', error);
553
+ }
554
+ });
555
+ ```
556
+
557
+ ### API Integration Example
558
+
559
+ ```javascript
560
+ // Make secure API request with auth
561
+ client.request.post('https://api.partner.com/sync', {
562
+ ticketId: ticketData.id,
563
+ subject: ticketData.subject,
564
+ description: ticketData.description
565
+ }, {
566
+ headers: {
567
+ 'Authorization': 'Bearer {{setting.partner_api_key}}',
568
+ 'X-App-Version': '1.0.0'
569
+ },
570
+ timeout: 30000,
571
+ autoRetry: true
572
+ }).then(response => {
573
+ console.log('Sync successful:', response.data);
574
+ }).catch(error => {
575
+ console.error('Sync failed:', error);
576
+ });
577
+ ```
578
+
579
+ ## Support
580
+
581
+ For issues, questions, or feature requests, please contact support@bolddesk.com or visit https://www.bolddesk.com/developer
582
+
583
+ ## License
584
+
585
+ Licensed under the Apache License, Version 2.0. See LICENSE file for details.
586
+
587
+ Copyright © 2026 BoldDesk