@unboundcx/sdk 1.0.2 → 1.0.4
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 +73 -54
- package/base.js +24 -16
- package/index.js +27 -15
- package/package.json +2 -2
- package/services/ai.js +62 -16
- package/services/enroll.js +48 -11
- package/services/externalOAuth.js +11 -3
- package/services/generateId.js +1 -1
- package/services/googleCalendar.js +22 -6
- package/services/layouts.js +12 -8
- package/services/login.js +12 -3
- package/services/lookup.js +1 -1
- package/services/messaging.js +140 -52
- package/services/notes.js +2 -8
- package/services/objects.js +34 -28
- package/services/phoneNumbers.js +85 -53
- package/services/portals.js +19 -4
- package/services/recordTypes.js +14 -3
- package/services/sipEndpoints.js +10 -3
- package/services/storage.js +227 -11
- package/services/subscriptions.js +19 -11
- package/services/verification.js +11 -3
- package/services/video.js +55 -22
- package/services/voice.js +169 -32
- package/services/workflows.js +122 -54
- package/test-backwards-compatibility.js +82 -51
- package/test-complete-coverage.js +113 -73
- package/test-constructor-patterns.js +32 -11
package/README.md
CHANGED
|
@@ -12,7 +12,7 @@ The official JavaScript SDK for Unbound's comprehensive communication and AI pla
|
|
|
12
12
|
- 📞 **Voice**: Call management, conferencing, recording, transcription
|
|
13
13
|
- 📹 **Video**: Video conferencing with advanced controls
|
|
14
14
|
- 🤖 **AI**: Generative AI chat and text-to-speech
|
|
15
|
-
- 💾 **Data**: Object management with queries and relationships
|
|
15
|
+
- 💾 **Data**: Object management with queries and relationships
|
|
16
16
|
- 🔄 **Workflows**: Programmable workflow execution
|
|
17
17
|
- 🔌 **Extensible**: Plugin system for transports and extensions
|
|
18
18
|
- ⚡ **Performance**: Automatic transport optimization (NATS/Socket/HTTP)
|
|
@@ -45,10 +45,10 @@ import SDK from '@unboundcx/sdk';
|
|
|
45
45
|
// Initialize the SDK
|
|
46
46
|
const api = new SDK({
|
|
47
47
|
namespace: 'your-namespace',
|
|
48
|
-
token: 'your-jwt-token'
|
|
48
|
+
token: 'your-jwt-token',
|
|
49
49
|
});
|
|
50
50
|
|
|
51
|
-
// Or using legacy positional parameters (backwards compatible)
|
|
51
|
+
// Or using legacy positional parameters (backwards compatible)
|
|
52
52
|
const api = new SDK('your-namespace', null, 'your-jwt-token');
|
|
53
53
|
|
|
54
54
|
// Login (gets JWT token)
|
|
@@ -57,15 +57,15 @@ const login = await api.login.login('username', 'password');
|
|
|
57
57
|
// Send SMS
|
|
58
58
|
const sms = await api.messaging.sms.send({
|
|
59
59
|
from: '+1234567890',
|
|
60
|
-
to: '+0987654321',
|
|
61
|
-
message: 'Hello from Unbound!'
|
|
60
|
+
to: '+0987654321',
|
|
61
|
+
message: 'Hello from Unbound!',
|
|
62
62
|
});
|
|
63
63
|
|
|
64
64
|
// Create video meeting
|
|
65
65
|
const meeting = await api.video.createRoom({
|
|
66
66
|
name: 'Team Meeting',
|
|
67
67
|
startTime: '2024-01-15T10:00:00Z',
|
|
68
|
-
duration: 60
|
|
68
|
+
duration: 60,
|
|
69
69
|
});
|
|
70
70
|
```
|
|
71
71
|
|
|
@@ -78,13 +78,13 @@ import { socketAppStore } from './stores/socket.js';
|
|
|
78
78
|
// Initialize for browser usage
|
|
79
79
|
const api = new SDK({
|
|
80
80
|
namespace: 'your-namespace',
|
|
81
|
-
socketStore: socketAppStore
|
|
81
|
+
socketStore: socketAppStore, // Optional: for optimized WebSocket transport
|
|
82
82
|
});
|
|
83
83
|
|
|
84
84
|
// The SDK automatically connects to your-namespace.api.unbound.cx
|
|
85
|
-
const objects = await api.objects.query('contacts', {
|
|
85
|
+
const objects = await api.objects.query('contacts', {
|
|
86
86
|
limit: 10,
|
|
87
|
-
orderBy: 'createdAt'
|
|
87
|
+
orderBy: 'createdAt',
|
|
88
88
|
});
|
|
89
89
|
```
|
|
90
90
|
|
|
@@ -93,18 +93,18 @@ const objects = await api.objects.query('contacts', {
|
|
|
93
93
|
```javascript
|
|
94
94
|
import SDK from '@unboundcx/sdk';
|
|
95
95
|
|
|
96
|
-
// Initialize for server-side usage
|
|
96
|
+
// Initialize for server-side usage
|
|
97
97
|
const api = new SDK({
|
|
98
98
|
namespace: 'your-namespace',
|
|
99
99
|
token: 'jwt-token',
|
|
100
|
-
callId: 'call-id'
|
|
100
|
+
callId: 'call-id', // Optional: for request tracking
|
|
101
101
|
});
|
|
102
102
|
|
|
103
103
|
// Automatically connects to your-namespace.api.unbound.cx
|
|
104
104
|
const result = await api.objects.create('leads', {
|
|
105
105
|
name: 'John Doe',
|
|
106
106
|
email: 'john@example.com',
|
|
107
|
-
phone: '+1234567890'
|
|
107
|
+
phone: '+1234567890',
|
|
108
108
|
});
|
|
109
109
|
```
|
|
110
110
|
|
|
@@ -116,11 +116,11 @@ The SDK constructor supports both object-based and legacy positional parameters:
|
|
|
116
116
|
|
|
117
117
|
```javascript
|
|
118
118
|
const api = new SDK({
|
|
119
|
-
namespace: 'your-namespace',
|
|
120
|
-
token: 'jwt-token',
|
|
121
|
-
callId: 'call-123',
|
|
122
|
-
fwRequestId: 'request-456',
|
|
123
|
-
socketStore: socketAppStore
|
|
119
|
+
namespace: 'your-namespace', // Required: Your Unbound namespace
|
|
120
|
+
token: 'jwt-token', // Optional: JWT authentication token
|
|
121
|
+
callId: 'call-123', // Optional: Call tracking ID
|
|
122
|
+
fwRequestId: 'request-456', // Optional: Request forwarding ID
|
|
123
|
+
socketStore: socketAppStore, // Optional: Socket.io store (browser only)
|
|
124
124
|
});
|
|
125
125
|
```
|
|
126
126
|
|
|
@@ -128,10 +128,10 @@ const api = new SDK({
|
|
|
128
128
|
|
|
129
129
|
```javascript
|
|
130
130
|
const api = new SDK(
|
|
131
|
-
'your-namespace',
|
|
132
|
-
'call-123',
|
|
133
|
-
'jwt-token',
|
|
134
|
-
'request-456'
|
|
131
|
+
'your-namespace', // namespace
|
|
132
|
+
'call-123', // callId
|
|
133
|
+
'jwt-token', // token
|
|
134
|
+
'request-456', // fwRequestId
|
|
135
135
|
);
|
|
136
136
|
```
|
|
137
137
|
|
|
@@ -142,7 +142,7 @@ import { createSDK } from '@unboundcx/sdk';
|
|
|
142
142
|
|
|
143
143
|
const api = createSDK({
|
|
144
144
|
namespace: 'your-namespace',
|
|
145
|
-
token: 'jwt-token'
|
|
145
|
+
token: 'jwt-token',
|
|
146
146
|
});
|
|
147
147
|
```
|
|
148
148
|
|
|
@@ -151,6 +151,7 @@ const api = createSDK({
|
|
|
151
151
|
### Core Services
|
|
152
152
|
|
|
153
153
|
#### Authentication (`api.login`)
|
|
154
|
+
|
|
154
155
|
```javascript
|
|
155
156
|
// Login and get session
|
|
156
157
|
await api.login.login('username', 'password');
|
|
@@ -159,10 +160,14 @@ await api.login.validate();
|
|
|
159
160
|
await api.login.changePassword('current', 'new');
|
|
160
161
|
```
|
|
161
162
|
|
|
162
|
-
#### Objects (`api.objects`)
|
|
163
|
+
#### Objects (`api.objects`)
|
|
164
|
+
|
|
163
165
|
```javascript
|
|
164
166
|
// CRUD operations on data objects
|
|
165
|
-
await api.objects.create('contacts', {
|
|
167
|
+
await api.objects.create('contacts', {
|
|
168
|
+
name: 'John',
|
|
169
|
+
email: 'john@example.com',
|
|
170
|
+
});
|
|
166
171
|
await api.objects.query('contacts', { limit: 10 });
|
|
167
172
|
await api.objects.byId('contact-123');
|
|
168
173
|
await api.objects.updateById('contacts', 'contact-123', { name: 'Jane' });
|
|
@@ -172,39 +177,41 @@ await api.objects.list(); // List all object types
|
|
|
172
177
|
```
|
|
173
178
|
|
|
174
179
|
#### Messaging (`api.messaging`)
|
|
180
|
+
|
|
175
181
|
```javascript
|
|
176
182
|
// SMS/MMS
|
|
177
183
|
await api.messaging.sms.send({
|
|
178
184
|
from: '+1234567890',
|
|
179
185
|
to: '+0987654321',
|
|
180
186
|
message: 'Hello!',
|
|
181
|
-
mediaUrls: ['https://example.com/image.jpg']
|
|
187
|
+
mediaUrls: ['https://example.com/image.jpg'],
|
|
182
188
|
});
|
|
183
189
|
|
|
184
|
-
// Email
|
|
190
|
+
// Email
|
|
185
191
|
await api.messaging.email.send({
|
|
186
192
|
from: 'sender@example.com',
|
|
187
|
-
to: 'recipient@example.com',
|
|
193
|
+
to: 'recipient@example.com',
|
|
188
194
|
subject: 'Hello',
|
|
189
|
-
htmlBody: '<h1>Hello World!</h1>'
|
|
195
|
+
htmlBody: '<h1>Hello World!</h1>',
|
|
190
196
|
});
|
|
191
197
|
|
|
192
198
|
// Templates
|
|
193
199
|
await api.messaging.sms.templates.create({
|
|
194
200
|
name: 'welcome',
|
|
195
201
|
message: 'Welcome {{name}}!',
|
|
196
|
-
variables: { name: 'string' }
|
|
202
|
+
variables: { name: 'string' },
|
|
197
203
|
});
|
|
198
204
|
|
|
199
205
|
// Campaign Management
|
|
200
206
|
await api.messaging.campaigns.tollFree.create({
|
|
201
207
|
companyName: 'Acme Corp',
|
|
202
208
|
phoneNumber: '+1234567890',
|
|
203
|
-
description: 'Marketing campaign'
|
|
209
|
+
description: 'Marketing campaign',
|
|
204
210
|
});
|
|
205
211
|
```
|
|
206
212
|
|
|
207
213
|
#### Video Conferencing (`api.video`)
|
|
214
|
+
|
|
208
215
|
```javascript
|
|
209
216
|
// Room Management
|
|
210
217
|
const room = await api.video.createRoom({
|
|
@@ -212,7 +219,7 @@ const room = await api.video.createRoom({
|
|
|
212
219
|
password: 'secret123',
|
|
213
220
|
startTime: '2024-01-15T10:00:00Z',
|
|
214
221
|
waitingRoom: true,
|
|
215
|
-
hosts: ['user@example.com']
|
|
222
|
+
hosts: ['user@example.com'],
|
|
216
223
|
});
|
|
217
224
|
|
|
218
225
|
// Join meeting
|
|
@@ -225,18 +232,19 @@ await api.video.removeParticipant(room.id, 'participant-id');
|
|
|
225
232
|
// Analytics
|
|
226
233
|
const analytics = await api.video.getMeetingAnalytics(room.id, {
|
|
227
234
|
startTime: '2024-01-15T10:00:00Z',
|
|
228
|
-
endTime: '2024-01-15T11:00:00Z'
|
|
235
|
+
endTime: '2024-01-15T11:00:00Z',
|
|
229
236
|
});
|
|
230
237
|
```
|
|
231
238
|
|
|
232
239
|
#### Voice Calling (`api.voice`)
|
|
240
|
+
|
|
233
241
|
```javascript
|
|
234
242
|
// Make calls
|
|
235
243
|
const call = await api.voice.createCall({
|
|
236
244
|
to: '+1234567890',
|
|
237
245
|
from: '+0987654321',
|
|
238
246
|
record: true,
|
|
239
|
-
transcribe: true
|
|
247
|
+
transcribe: true,
|
|
240
248
|
});
|
|
241
249
|
|
|
242
250
|
// Call controls
|
|
@@ -252,32 +260,34 @@ await api.voice.joinConference(call.callControlId, conference.id);
|
|
|
252
260
|
```
|
|
253
261
|
|
|
254
262
|
#### AI Services (`api.ai`)
|
|
263
|
+
|
|
255
264
|
```javascript
|
|
256
265
|
// Generative AI
|
|
257
266
|
const response = await api.ai.generative.chat({
|
|
258
267
|
messages: [{ role: 'user', content: 'Hello AI!' }],
|
|
259
268
|
model: 'gpt-4',
|
|
260
269
|
temperature: 0.7,
|
|
261
|
-
method: 'openai'
|
|
270
|
+
method: 'openai',
|
|
262
271
|
});
|
|
263
272
|
|
|
264
273
|
// Text-to-Speech
|
|
265
274
|
const audio = await api.ai.tts.create({
|
|
266
275
|
text: 'Hello, this is a test message',
|
|
267
276
|
voice: 'en-US-Standard-A',
|
|
268
|
-
audioEncoding: 'MP3'
|
|
277
|
+
audioEncoding: 'MP3',
|
|
269
278
|
});
|
|
270
279
|
```
|
|
271
280
|
|
|
272
281
|
### Utility Services
|
|
273
282
|
|
|
274
283
|
#### File Storage (`api.storage`)
|
|
284
|
+
|
|
275
285
|
```javascript
|
|
276
286
|
// Upload files
|
|
277
287
|
const files = await api.storage.uploadFiles(fileData, {
|
|
278
288
|
classification: 'documents',
|
|
279
289
|
isPublic: false,
|
|
280
|
-
expireAfter: '30d'
|
|
290
|
+
expireAfter: '30d',
|
|
281
291
|
});
|
|
282
292
|
|
|
283
293
|
// Get files
|
|
@@ -286,21 +296,22 @@ await api.storage.deleteFile(files[0].storageId);
|
|
|
286
296
|
```
|
|
287
297
|
|
|
288
298
|
#### Workflows (`api.workflows`)
|
|
299
|
+
|
|
289
300
|
```javascript
|
|
290
301
|
// Workflow items
|
|
291
302
|
await api.workflows.items.create({
|
|
292
303
|
workflowVersionId: 'wf-123',
|
|
293
304
|
category: 'communication',
|
|
294
305
|
type: 'sendEmail',
|
|
295
|
-
settings: { template: 'welcome' }
|
|
306
|
+
settings: { template: 'welcome' },
|
|
296
307
|
});
|
|
297
308
|
|
|
298
309
|
// Connections
|
|
299
310
|
await api.workflows.connections.create({
|
|
300
311
|
workflowItemId: 'item-1',
|
|
301
312
|
workflowItemPortId: 'output',
|
|
302
|
-
inWorkflowItemId: 'item-2',
|
|
303
|
-
inWorkflowItemPortId: 'input'
|
|
313
|
+
inWorkflowItemId: 'item-2',
|
|
314
|
+
inWorkflowItemPortId: 'input',
|
|
304
315
|
});
|
|
305
316
|
```
|
|
306
317
|
|
|
@@ -309,7 +320,7 @@ await api.workflows.connections.create({
|
|
|
309
320
|
The SDK automatically optimizes transport based on environment:
|
|
310
321
|
|
|
311
322
|
- **Node.js**: NATS → HTTP fallback
|
|
312
|
-
- **Browser**: WebSocket → HTTP fallback
|
|
323
|
+
- **Browser**: WebSocket → HTTP fallback
|
|
313
324
|
- **Always available**: HTTP fetch
|
|
314
325
|
|
|
315
326
|
### Custom Transports
|
|
@@ -322,13 +333,15 @@ class CustomTransport {
|
|
|
322
333
|
this.config = config;
|
|
323
334
|
this.name = 'custom';
|
|
324
335
|
}
|
|
325
|
-
|
|
326
|
-
getPriority() {
|
|
327
|
-
|
|
336
|
+
|
|
337
|
+
getPriority() {
|
|
338
|
+
return 10;
|
|
339
|
+
} // Lower = higher priority
|
|
340
|
+
|
|
328
341
|
async isAvailable() {
|
|
329
342
|
return true; // Check if transport is ready
|
|
330
343
|
}
|
|
331
|
-
|
|
344
|
+
|
|
332
345
|
async request(endpoint, method, params, options) {
|
|
333
346
|
// Custom transport logic
|
|
334
347
|
return response;
|
|
@@ -350,9 +363,9 @@ const api = new SDK({ namespace: 'namespace' });
|
|
|
350
363
|
|
|
351
364
|
// Add custom functionality via extensions
|
|
352
365
|
api.extend({
|
|
353
|
-
customMethod: function() {
|
|
366
|
+
customMethod: function () {
|
|
354
367
|
return this.objects.query('custom', {});
|
|
355
|
-
}
|
|
368
|
+
},
|
|
356
369
|
});
|
|
357
370
|
|
|
358
371
|
// Use custom method
|
|
@@ -362,6 +375,7 @@ await api.customMethod();
|
|
|
362
375
|
## Environment Support
|
|
363
376
|
|
|
364
377
|
### Node.js
|
|
378
|
+
|
|
365
379
|
```javascript
|
|
366
380
|
import SDK from '@unboundcx/sdk';
|
|
367
381
|
|
|
@@ -370,23 +384,25 @@ const api = new SDK({ namespace: process.env.UNBOUND_NAMESPACE });
|
|
|
370
384
|
```
|
|
371
385
|
|
|
372
386
|
### Browser/Webpack
|
|
387
|
+
|
|
373
388
|
```javascript
|
|
374
389
|
import SDK from '@unboundcx/sdk';
|
|
375
390
|
|
|
376
391
|
const api = new SDK({
|
|
377
|
-
namespace: 'your-namespace'
|
|
392
|
+
namespace: 'your-namespace',
|
|
378
393
|
});
|
|
379
394
|
// Automatically connects to your-namespace.api.unbound.cx
|
|
380
395
|
```
|
|
381
396
|
|
|
382
397
|
### Svelte
|
|
398
|
+
|
|
383
399
|
```javascript
|
|
384
400
|
import SDK from '@unboundcx/sdk';
|
|
385
401
|
import { socketAppStore } from '$lib/stores/socket.js';
|
|
386
402
|
|
|
387
403
|
const api = new SDK({
|
|
388
404
|
namespace: 'your-namespace',
|
|
389
|
-
socketStore: socketAppStore
|
|
405
|
+
socketStore: socketAppStore, // Enables WebSocket transport
|
|
390
406
|
});
|
|
391
407
|
// Automatically connects to your-namespace.api.unbound.cx
|
|
392
408
|
```
|
|
@@ -397,10 +413,10 @@ const api = new SDK({
|
|
|
397
413
|
try {
|
|
398
414
|
await api.messaging.sms.send({ to: 'invalid' });
|
|
399
415
|
} catch (error) {
|
|
400
|
-
console.log(error.name);
|
|
416
|
+
console.log(error.name); // 'API :: Error :: https :: POST :: /messaging/sms :: ...'
|
|
401
417
|
console.log(error.message); // 'Invalid phone number format'
|
|
402
|
-
console.log(error.status);
|
|
403
|
-
console.log(error.method);
|
|
418
|
+
console.log(error.status); // 400
|
|
419
|
+
console.log(error.method); // 'POST'
|
|
404
420
|
console.log(error.endpoint); // '/messaging/sms'
|
|
405
421
|
}
|
|
406
422
|
```
|
|
@@ -417,14 +433,15 @@ const api: SDK = new SDK({ namespace: 'namespace', token: 'token' });
|
|
|
417
433
|
// Full type safety
|
|
418
434
|
const sms: any = await api.messaging.sms.send({
|
|
419
435
|
from: '+1234567890',
|
|
420
|
-
to: '+0987654321',
|
|
421
|
-
message: 'Hello TypeScript!'
|
|
436
|
+
to: '+0987654321',
|
|
437
|
+
message: 'Hello TypeScript!',
|
|
422
438
|
});
|
|
423
439
|
```
|
|
424
440
|
|
|
425
441
|
## Development
|
|
426
442
|
|
|
427
443
|
### Setup
|
|
444
|
+
|
|
428
445
|
```bash
|
|
429
446
|
git clone https://github.com/unbound/sdk-js.git
|
|
430
447
|
cd sdk-js
|
|
@@ -432,6 +449,7 @@ npm install
|
|
|
432
449
|
```
|
|
433
450
|
|
|
434
451
|
### Testing
|
|
452
|
+
|
|
435
453
|
```bash
|
|
436
454
|
npm test # Run all tests
|
|
437
455
|
npm run test:unit # Unit tests only
|
|
@@ -440,6 +458,7 @@ npm run test:watch # Watch mode
|
|
|
440
458
|
```
|
|
441
459
|
|
|
442
460
|
### Building
|
|
461
|
+
|
|
443
462
|
```bash
|
|
444
463
|
npm run build # Build for production
|
|
445
464
|
npm run lint # Check code style
|
|
@@ -463,4 +482,4 @@ This project is licensed under the MIT License - see the [LICENSE](LICENSE) file
|
|
|
463
482
|
- 📚 [Documentation](https://docs.unbound.cx/sdk)
|
|
464
483
|
- 🐛 [Issue Tracker](https://github.com/unbound/sdk-js/issues)
|
|
465
484
|
- 💬 [Community Forum](https://community.unbound.cx)
|
|
466
|
-
- 📧 [Email Support](mailto:support@unbound.cx)
|
|
485
|
+
- 📧 [Email Support](mailto:support@unbound.cx)
|
package/base.js
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
/*
|
|
5
5
|
* Base SDK Class with Transport Plugin System
|
|
6
|
-
*
|
|
6
|
+
*
|
|
7
7
|
* Optional Dependencies:
|
|
8
8
|
* - mime-types: For accurate MIME type detection (automatically imported if available)
|
|
9
9
|
*
|
|
@@ -30,14 +30,14 @@ export class BaseSDK {
|
|
|
30
30
|
this.token = token;
|
|
31
31
|
this.fwRequestId = fwRequestId;
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
|
|
34
34
|
this.transports = new Map();
|
|
35
35
|
this._initializeEnvironment();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
38
|
_initializeEnvironment() {
|
|
39
39
|
const defaultDomain = 'api.unbound.cx';
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
if (typeof window === 'undefined') {
|
|
42
42
|
// Server-side (Node.js)
|
|
43
43
|
this.environment = 'node';
|
|
@@ -47,7 +47,8 @@ export class BaseSDK {
|
|
|
47
47
|
} else {
|
|
48
48
|
// Client-side (browser)
|
|
49
49
|
this.environment = 'browser';
|
|
50
|
-
this.baseUrl =
|
|
50
|
+
this.baseUrl =
|
|
51
|
+
this.baseUrl || process?.env?.API_BASE_URL || defaultDomain;
|
|
51
52
|
if (this.baseUrl && !this.baseUrl.startsWith('api.')) {
|
|
52
53
|
this.baseUrl = `api.${this.baseUrl}`;
|
|
53
54
|
}
|
|
@@ -62,7 +63,7 @@ export class BaseSDK {
|
|
|
62
63
|
setNamespace(namespace) {
|
|
63
64
|
this.namespace = namespace;
|
|
64
65
|
const defaultDomain = 'api.unbound.cx';
|
|
65
|
-
|
|
66
|
+
|
|
66
67
|
if (this.environment === 'node') {
|
|
67
68
|
this.baseURL = `https://${this.namespace ? this.namespace : 'login'}.${
|
|
68
69
|
process.env?.API_BASE_URL || defaultDomain
|
|
@@ -76,13 +77,13 @@ export class BaseSDK {
|
|
|
76
77
|
if (!transport || typeof transport.request !== 'function') {
|
|
77
78
|
throw new Error('Transport must have a request method');
|
|
78
79
|
}
|
|
79
|
-
|
|
80
|
+
|
|
80
81
|
const priority = transport.getPriority ? transport.getPriority() : 50;
|
|
81
82
|
const name = transport.name || `transport_${Date.now()}`;
|
|
82
|
-
|
|
83
|
+
|
|
83
84
|
this.transports.set(name, {
|
|
84
85
|
transport,
|
|
85
|
-
priority
|
|
86
|
+
priority,
|
|
86
87
|
});
|
|
87
88
|
}
|
|
88
89
|
|
|
@@ -96,16 +97,20 @@ export class BaseSDK {
|
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
// Sort transports by priority (lower number = higher priority)
|
|
99
|
-
const sortedTransports = Array.from(this.transports.values())
|
|
100
|
-
|
|
100
|
+
const sortedTransports = Array.from(this.transports.values()).sort(
|
|
101
|
+
(a, b) => a.priority - b.priority,
|
|
102
|
+
);
|
|
101
103
|
|
|
102
104
|
for (const { transport } of sortedTransports) {
|
|
103
105
|
try {
|
|
104
|
-
if (transport.isAvailable && await transport.isAvailable()) {
|
|
106
|
+
if (transport.isAvailable && (await transport.isAvailable())) {
|
|
105
107
|
return transport;
|
|
106
108
|
}
|
|
107
109
|
} catch (err) {
|
|
108
|
-
console.debug(
|
|
110
|
+
console.debug(
|
|
111
|
+
`Transport ${transport.name} not available:`,
|
|
112
|
+
err.message,
|
|
113
|
+
);
|
|
109
114
|
continue;
|
|
110
115
|
}
|
|
111
116
|
}
|
|
@@ -169,7 +174,10 @@ export class BaseSDK {
|
|
|
169
174
|
});
|
|
170
175
|
return result;
|
|
171
176
|
} catch (err) {
|
|
172
|
-
console.warn(
|
|
177
|
+
console.warn(
|
|
178
|
+
`Transport ${transport.name} failed, falling back to HTTP:`,
|
|
179
|
+
err.message,
|
|
180
|
+
);
|
|
173
181
|
// Fall through to HTTP
|
|
174
182
|
}
|
|
175
183
|
}
|
|
@@ -180,7 +188,7 @@ export class BaseSDK {
|
|
|
180
188
|
|
|
181
189
|
async _httpRequest(endpoint, method, params = {}) {
|
|
182
190
|
const { body, query, headers = {} } = params;
|
|
183
|
-
|
|
191
|
+
|
|
184
192
|
const options = {
|
|
185
193
|
method,
|
|
186
194
|
headers: {
|
|
@@ -257,10 +265,10 @@ export class BaseSDK {
|
|
|
257
265
|
statusText: response?.statusText,
|
|
258
266
|
};
|
|
259
267
|
}
|
|
260
|
-
|
|
268
|
+
|
|
261
269
|
console.log(
|
|
262
270
|
`API :: https :: ${method} :: ${endpoint} :: ${responseRequestId}`,
|
|
263
271
|
);
|
|
264
272
|
return bodyResponse;
|
|
265
273
|
}
|
|
266
|
-
}
|
|
274
|
+
}
|
package/index.js
CHANGED
|
@@ -35,35 +35,36 @@ class UnboundSDK extends BaseSDK {
|
|
|
35
35
|
const fwRequestId = arguments[3];
|
|
36
36
|
const url = arguments[4];
|
|
37
37
|
const socketStore = arguments[5];
|
|
38
|
-
|
|
38
|
+
|
|
39
39
|
super({ namespace, callId, token, fwRequestId });
|
|
40
|
-
|
|
40
|
+
|
|
41
41
|
// Handle client-side specific parameters
|
|
42
42
|
if (url) {
|
|
43
43
|
this.baseUrl = url;
|
|
44
44
|
this._initializeEnvironment();
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
|
|
47
47
|
if (socketStore) {
|
|
48
48
|
this.socketStore = socketStore;
|
|
49
49
|
}
|
|
50
50
|
} else {
|
|
51
51
|
// New object-based parameters
|
|
52
|
-
const { namespace, callId, token, fwRequestId, url, socketStore } =
|
|
53
|
-
|
|
52
|
+
const { namespace, callId, token, fwRequestId, url, socketStore } =
|
|
53
|
+
options;
|
|
54
|
+
|
|
54
55
|
super({ namespace, callId, token, fwRequestId });
|
|
55
|
-
|
|
56
|
+
|
|
56
57
|
// Handle client-side specific parameters
|
|
57
58
|
if (url) {
|
|
58
59
|
this.baseUrl = url;
|
|
59
60
|
this._initializeEnvironment();
|
|
60
61
|
}
|
|
61
|
-
|
|
62
|
+
|
|
62
63
|
if (socketStore) {
|
|
63
64
|
this.socketStore = socketStore;
|
|
64
65
|
}
|
|
65
66
|
}
|
|
66
|
-
|
|
67
|
+
|
|
67
68
|
// Initialize all service modules
|
|
68
69
|
this.login = new LoginService(this);
|
|
69
70
|
this.objects = new ObjectsService(this);
|
|
@@ -86,7 +87,7 @@ class UnboundSDK extends BaseSDK {
|
|
|
86
87
|
this.phoneNumbers = new PhoneNumbersService(this);
|
|
87
88
|
this.recordTypes = new RecordTypesService(this);
|
|
88
89
|
this.generateId = new GenerateIdService(this);
|
|
89
|
-
|
|
90
|
+
|
|
90
91
|
// Add additional services that might be missing
|
|
91
92
|
this._initializeAdditionalServices();
|
|
92
93
|
}
|
|
@@ -112,10 +113,13 @@ class UnboundSDK extends BaseSDK {
|
|
|
112
113
|
if (typeof extension === 'function') {
|
|
113
114
|
// Extension is a class constructor
|
|
114
115
|
const instance = new extension(this);
|
|
115
|
-
|
|
116
|
+
|
|
116
117
|
// Merge extension methods/properties into this SDK
|
|
117
118
|
for (const key in instance) {
|
|
118
|
-
if (
|
|
119
|
+
if (
|
|
120
|
+
instance.hasOwnProperty(key) &&
|
|
121
|
+
typeof instance[key] !== 'undefined'
|
|
122
|
+
) {
|
|
119
123
|
this[key] = instance[key];
|
|
120
124
|
}
|
|
121
125
|
}
|
|
@@ -143,7 +147,9 @@ class UnboundSDK extends BaseSDK {
|
|
|
143
147
|
async buildMasterAuth({ namespace, accountId, userId }) {
|
|
144
148
|
// This method should only be available in Node.js environment
|
|
145
149
|
// and will be added via internal SDK extension
|
|
146
|
-
throw new Error(
|
|
150
|
+
throw new Error(
|
|
151
|
+
'buildMasterAuth is only available with the internal SDK extension. Please use: sdk.use(InternalExtension)',
|
|
152
|
+
);
|
|
147
153
|
}
|
|
148
154
|
}
|
|
149
155
|
|
|
@@ -175,7 +181,13 @@ export { SipEndpointsService } from './services/sipEndpoints.js';
|
|
|
175
181
|
export { ExternalOAuthService } from './services/externalOAuth.js';
|
|
176
182
|
export { GoogleCalendarService } from './services/googleCalendar.js';
|
|
177
183
|
export { EnrollService } from './services/enroll.js';
|
|
178
|
-
export {
|
|
179
|
-
|
|
184
|
+
export {
|
|
185
|
+
PhoneNumbersService,
|
|
186
|
+
PhoneNumberCarrierService,
|
|
187
|
+
} from './services/phoneNumbers.js';
|
|
188
|
+
export {
|
|
189
|
+
RecordTypesService,
|
|
190
|
+
UserRecordTypeDefaultsService,
|
|
191
|
+
} from './services/recordTypes.js';
|
|
180
192
|
export { GenerateIdService } from './services/generateId.js';
|
|
181
|
-
export { BaseSDK } from './base.js';
|
|
193
|
+
export { BaseSDK } from './base.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"type": "module",
|
|
@@ -30,7 +30,7 @@
|
|
|
30
30
|
"license": "MIT",
|
|
31
31
|
"repository": {
|
|
32
32
|
"type": "git",
|
|
33
|
-
"url": "https://github.com/unbound/sdk-js.git"
|
|
33
|
+
"url": "git+https://github.com/unbound/sdk-js.git"
|
|
34
34
|
},
|
|
35
35
|
"bugs": {
|
|
36
36
|
"url": "https://github.com/unbound/sdk-js/issues"
|