@unboundcx/sdk 4.13.50 → 4.13.53
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/base.js +9 -2
- package/index.js +10 -3
- package/package.json +1 -1
- package/services/messaging/EmailService.js +4 -0
- package/services/objects.js +75 -0
- package/services/taskRouter/TaskService.js +134 -8
package/base.js
CHANGED
|
@@ -387,8 +387,15 @@ export class BaseSDK {
|
|
|
387
387
|
|
|
388
388
|
// Add query parameters
|
|
389
389
|
if (query) {
|
|
390
|
-
|
|
391
|
-
|
|
390
|
+
// Drop undefined/null so optional args don't serialize as the literal
|
|
391
|
+
// string "undefined" (URLSearchParams would send limit=undefined).
|
|
392
|
+
const cleanQuery = Object.fromEntries(
|
|
393
|
+
Object.entries(query).filter(
|
|
394
|
+
([, v]) => v !== undefined && v !== null,
|
|
395
|
+
),
|
|
396
|
+
);
|
|
397
|
+
const params = new URLSearchParams(cleanQuery).toString();
|
|
398
|
+
if (params) url += `?${params}`;
|
|
392
399
|
}
|
|
393
400
|
|
|
394
401
|
// Handle body
|
package/index.js
CHANGED
|
@@ -74,10 +74,17 @@ class UnboundSDK extends BaseSDK {
|
|
|
74
74
|
}
|
|
75
75
|
} else {
|
|
76
76
|
// New object-based parameters
|
|
77
|
-
const {
|
|
78
|
-
|
|
77
|
+
const {
|
|
78
|
+
namespace,
|
|
79
|
+
callId,
|
|
80
|
+
token,
|
|
81
|
+
fwRequestId,
|
|
82
|
+
url,
|
|
83
|
+
socketStore,
|
|
84
|
+
baseURL,
|
|
85
|
+
} = options;
|
|
79
86
|
|
|
80
|
-
super({ namespace, callId, token, fwRequestId });
|
|
87
|
+
super({ namespace, callId, token, fwRequestId, baseURL });
|
|
81
88
|
|
|
82
89
|
// Handle client-side specific parameters
|
|
83
90
|
if (url) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.13.
|
|
3
|
+
"version": "4.13.53",
|
|
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",
|
|
@@ -642,6 +642,7 @@ export class EmailService {
|
|
|
642
642
|
limit = 25,
|
|
643
643
|
offset = 0,
|
|
644
644
|
assignedUserId,
|
|
645
|
+
includeTasked = false,
|
|
645
646
|
} = {},
|
|
646
647
|
) {
|
|
647
648
|
this.sdk.validateParams(
|
|
@@ -655,6 +656,7 @@ export class EmailService {
|
|
|
655
656
|
limit,
|
|
656
657
|
offset,
|
|
657
658
|
assignedUserId,
|
|
659
|
+
includeTasked,
|
|
658
660
|
},
|
|
659
661
|
{
|
|
660
662
|
mailboxId: { type: 'string', required: true },
|
|
@@ -666,12 +668,14 @@ export class EmailService {
|
|
|
666
668
|
limit: { type: 'number', required: false },
|
|
667
669
|
offset: { type: 'number', required: false },
|
|
668
670
|
assignedUserId: { type: 'string', required: false },
|
|
671
|
+
includeTasked: { type: 'boolean', required: false },
|
|
669
672
|
},
|
|
670
673
|
);
|
|
671
674
|
|
|
672
675
|
const query = { folder, includeDrafts, sortBy, sortOrder, limit, offset };
|
|
673
676
|
if (search) query.search = search;
|
|
674
677
|
if (assignedUserId) query.assignedUserId = assignedUserId;
|
|
678
|
+
if (includeTasked) query.includeTasked = true;
|
|
675
679
|
|
|
676
680
|
const params = {
|
|
677
681
|
query,
|
package/services/objects.js
CHANGED
|
@@ -1291,6 +1291,81 @@ export class ObjectsService {
|
|
|
1291
1291
|
});
|
|
1292
1292
|
}
|
|
1293
1293
|
|
|
1294
|
+
/**
|
|
1295
|
+
* Engagement-session participant roster (requester + durable CCs).
|
|
1296
|
+
* `recordId` is an engagement session id.
|
|
1297
|
+
*
|
|
1298
|
+
* GET /object/:id/participants
|
|
1299
|
+
*
|
|
1300
|
+
* @param {string} recordId
|
|
1301
|
+
* @returns {Promise<{participants: Array<{
|
|
1302
|
+
* id: string,
|
|
1303
|
+
* engagementSessionId: string,
|
|
1304
|
+
* role: string,
|
|
1305
|
+
* email: string|null,
|
|
1306
|
+
* peopleId: string|null,
|
|
1307
|
+
* displayName: string|null,
|
|
1308
|
+
* addedBy: {id: string, name: string|null}|null,
|
|
1309
|
+
* createdAt: string
|
|
1310
|
+
* }>}>}
|
|
1311
|
+
*/
|
|
1312
|
+
async listParticipants(recordId) {
|
|
1313
|
+
this.sdk.validateParams(
|
|
1314
|
+
{ recordId },
|
|
1315
|
+
{ recordId: { type: 'string', required: true } },
|
|
1316
|
+
);
|
|
1317
|
+
return internalRequest(
|
|
1318
|
+
this.sdk,
|
|
1319
|
+
`/object/${recordId}/participants`,
|
|
1320
|
+
'GET',
|
|
1321
|
+
);
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
/**
|
|
1325
|
+
* Add a durable CC on an engagement session (PR5).
|
|
1326
|
+
* PUT /object/:id/participants
|
|
1327
|
+
*
|
|
1328
|
+
* @param {string} recordId engagement session id
|
|
1329
|
+
* @param {{email: string, displayName?: string, peopleId?: string}} body
|
|
1330
|
+
*/
|
|
1331
|
+
async addParticipant(recordId, body = {}) {
|
|
1332
|
+
this.sdk.validateParams(
|
|
1333
|
+
{ recordId, email: body.email },
|
|
1334
|
+
{
|
|
1335
|
+
recordId: { type: 'string', required: true },
|
|
1336
|
+
email: { type: 'string', required: true },
|
|
1337
|
+
},
|
|
1338
|
+
);
|
|
1339
|
+
return internalRequest(
|
|
1340
|
+
this.sdk,
|
|
1341
|
+
`/object/${recordId}/participants`,
|
|
1342
|
+
'PUT',
|
|
1343
|
+
{ body },
|
|
1344
|
+
);
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
/**
|
|
1348
|
+
* Remove a durable CC from an engagement session (PR5).
|
|
1349
|
+
* DELETE /object/:id/participants/:participantId
|
|
1350
|
+
*
|
|
1351
|
+
* @param {string} recordId engagement session id
|
|
1352
|
+
* @param {string} participantId
|
|
1353
|
+
*/
|
|
1354
|
+
async removeParticipant(recordId, participantId) {
|
|
1355
|
+
this.sdk.validateParams(
|
|
1356
|
+
{ recordId, participantId },
|
|
1357
|
+
{
|
|
1358
|
+
recordId: { type: 'string', required: true },
|
|
1359
|
+
participantId: { type: 'string', required: true },
|
|
1360
|
+
},
|
|
1361
|
+
);
|
|
1362
|
+
return internalRequest(
|
|
1363
|
+
this.sdk,
|
|
1364
|
+
`/object/${recordId}/participants/${participantId}`,
|
|
1365
|
+
'DELETE',
|
|
1366
|
+
);
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1294
1369
|
/**
|
|
1295
1370
|
* Marketing programs dashboard (programs + totals).
|
|
1296
1371
|
* @returns {Promise<object>}
|
|
@@ -23,6 +23,9 @@ export class TaskService {
|
|
|
23
23
|
* @param {boolean} [options.createEngagement=false] - Whether to automatically create an engagement session for this task
|
|
24
24
|
* @param {string} [options.relatedObject] - Related object type for metadata tracking (automatically set if createEngagement is true)
|
|
25
25
|
* @param {string} [options.relatedId] - Related object ID for metadata tracking (automatically set if createEngagement is true)
|
|
26
|
+
* @param {string} [options.parentTaskId] - Parent task id (wrapUp follow-up / requeue)
|
|
27
|
+
* @param {string} [options.preferredWorkerId] - Preferred worker id persisted on create INSERT
|
|
28
|
+
* @param {string} [options.source] - Engagement `source` when `createEngagement` is true (e.g. `'portal'`)
|
|
26
29
|
* @param {Object} [options.metadata] - Arbitrary metadata to attach to the task at creation (e.g. `{ textConversationId }`). Passed through as-is; whether it is persisted depends on the receiving endpoint honoring `metadata` in the request body.
|
|
27
30
|
* @returns {Promise<Object>} Object containing the created task information
|
|
28
31
|
* @returns {string} result.id - The unique identifier for the created task
|
|
@@ -84,7 +87,11 @@ export class TaskService {
|
|
|
84
87
|
cdrId,
|
|
85
88
|
sipCallId,
|
|
86
89
|
aiChatSessionId,
|
|
90
|
+
parentTaskId,
|
|
91
|
+
preferredWorkerId,
|
|
92
|
+
isRoutable,
|
|
87
93
|
metadata,
|
|
94
|
+
source,
|
|
88
95
|
} = options;
|
|
89
96
|
|
|
90
97
|
this.sdk.validateParams(
|
|
@@ -104,7 +111,11 @@ export class TaskService {
|
|
|
104
111
|
relatedId,
|
|
105
112
|
sipCallId,
|
|
106
113
|
aiChatSessionId,
|
|
114
|
+
parentTaskId,
|
|
115
|
+
preferredWorkerId,
|
|
116
|
+
isRoutable,
|
|
107
117
|
metadata,
|
|
118
|
+
source,
|
|
108
119
|
},
|
|
109
120
|
{
|
|
110
121
|
type: { type: 'string', required: true },
|
|
@@ -122,7 +133,11 @@ export class TaskService {
|
|
|
122
133
|
relatedId: { type: 'string', required: false },
|
|
123
134
|
sipCallId: { type: 'string', required: false },
|
|
124
135
|
aiChatSessionId: { type: 'string', required: false },
|
|
136
|
+
parentTaskId: { type: 'string', required: false },
|
|
137
|
+
preferredWorkerId: { type: 'string', required: false },
|
|
138
|
+
isRoutable: { type: 'boolean', required: false },
|
|
125
139
|
metadata: { type: 'object', required: false },
|
|
140
|
+
source: { type: 'string', required: false },
|
|
126
141
|
},
|
|
127
142
|
);
|
|
128
143
|
|
|
@@ -185,10 +200,26 @@ export class TaskService {
|
|
|
185
200
|
params.body.aiChatSessionId = aiChatSessionId;
|
|
186
201
|
}
|
|
187
202
|
|
|
203
|
+
if (parentTaskId !== undefined) {
|
|
204
|
+
params.body.parentTaskId = parentTaskId;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
if (preferredWorkerId !== undefined) {
|
|
208
|
+
params.body.preferredWorkerId = preferredWorkerId;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
if (isRoutable !== undefined) {
|
|
212
|
+
params.body.isRoutable = isRoutable;
|
|
213
|
+
}
|
|
214
|
+
|
|
188
215
|
if (metadata !== undefined) {
|
|
189
216
|
params.body.metadata = metadata;
|
|
190
217
|
}
|
|
191
218
|
|
|
219
|
+
if (source !== undefined) {
|
|
220
|
+
params.body.source = source;
|
|
221
|
+
}
|
|
222
|
+
|
|
192
223
|
const result = await internalRequest(this.sdk, '/taskRouter/tasks', 'POST', params);
|
|
193
224
|
return result;
|
|
194
225
|
}
|
|
@@ -444,44 +475,53 @@ export class TaskService {
|
|
|
444
475
|
}
|
|
445
476
|
|
|
446
477
|
/**
|
|
447
|
-
* Toggle task hold status
|
|
478
|
+
* Toggle or set task hold status
|
|
448
479
|
* Place a connected task on hold or resume a held task.
|
|
449
|
-
* If the
|
|
450
|
-
* If
|
|
480
|
+
* If `held` is omitted, the current status is toggled: 'connected' -> 'hold'
|
|
481
|
+
* and 'hold' -> 'connected'. If `held` is a boolean, it explicitly sets the
|
|
482
|
+
* target status: `true` -> 'hold', `false` -> 'connected'.
|
|
451
483
|
*
|
|
452
484
|
* @param {Object} options - Parameters
|
|
453
485
|
* @param {string} options.taskId - The task ID to hold/resume (required)
|
|
486
|
+
* @param {boolean} [options.held] - Explicit target hold state; omit for legacy toggle behavior
|
|
454
487
|
* @returns {Promise<Object>} Object containing the task ID and new status
|
|
455
488
|
* @returns {string} result.taskId - The task ID that was modified
|
|
456
489
|
* @returns {string} result.status - The new status ('hold' or 'connected')
|
|
490
|
+
* @returns {boolean} result.changed - Whether the status actually changed
|
|
457
491
|
*
|
|
458
492
|
* @example
|
|
459
493
|
* // Put a connected task on hold
|
|
460
|
-
* const result = await sdk.taskRouter.task.hold({ taskId: 'task123' });
|
|
494
|
+
* const result = await sdk.taskRouter.task.hold({ taskId: 'task123', held: true });
|
|
461
495
|
* console.log(result.status); // "hold"
|
|
462
496
|
*
|
|
463
497
|
* @example
|
|
464
498
|
* // Resume a held task
|
|
465
|
-
* const result = await sdk.taskRouter.task.hold({ taskId: 'task123' });
|
|
499
|
+
* const result = await sdk.taskRouter.task.hold({ taskId: 'task123', held: false });
|
|
466
500
|
* console.log(result.status); // "connected"
|
|
501
|
+
*
|
|
502
|
+
* @example
|
|
503
|
+
* // Legacy toggle (no `held`)
|
|
504
|
+
* const result = await sdk.taskRouter.task.hold({ taskId: 'task123' });
|
|
467
505
|
*/
|
|
468
506
|
async hold(options = {}) {
|
|
469
|
-
const { taskId } = options;
|
|
507
|
+
const { taskId, held } = options;
|
|
470
508
|
|
|
471
509
|
this.sdk.validateParams(
|
|
472
|
-
{ taskId },
|
|
510
|
+
{ taskId, held },
|
|
473
511
|
{
|
|
474
512
|
taskId: { type: 'string', required: true },
|
|
513
|
+
held: { type: 'boolean', required: false },
|
|
475
514
|
},
|
|
476
515
|
);
|
|
477
516
|
|
|
478
517
|
const params = {
|
|
479
518
|
body: {
|
|
480
519
|
taskId,
|
|
520
|
+
...(typeof held === 'boolean' && { held }),
|
|
481
521
|
},
|
|
482
522
|
};
|
|
483
523
|
|
|
484
|
-
const result = await internalRequest(this.sdk,
|
|
524
|
+
const result = await internalRequest(this.sdk,
|
|
485
525
|
'/taskRouter/tasks/hold',
|
|
486
526
|
'PUT',
|
|
487
527
|
params,
|
|
@@ -880,6 +920,92 @@ export class TaskService {
|
|
|
880
920
|
);
|
|
881
921
|
}
|
|
882
922
|
|
|
923
|
+
/**
|
|
924
|
+
* Resume a parked task ("customer is back"). Flips the task back to
|
|
925
|
+
* pending so the distributor re-offers it; preferredWorkerId (stamped by
|
|
926
|
+
* park) is left alone so the parking worker gets first refusal.
|
|
927
|
+
*
|
|
928
|
+
* PUT /taskRouter/tasks/unpark
|
|
929
|
+
*
|
|
930
|
+
* @param {Object} options - Parameters
|
|
931
|
+
* @param {string} options.taskId - The parked task ID (required)
|
|
932
|
+
* @returns {Promise<Object>} { taskId, status: 'pending' }
|
|
933
|
+
*/
|
|
934
|
+
async unpark(options = {}) {
|
|
935
|
+
const { taskId } = options;
|
|
936
|
+
|
|
937
|
+
this.sdk.validateParams(
|
|
938
|
+
{ taskId },
|
|
939
|
+
{ taskId: { type: 'string', required: true } },
|
|
940
|
+
);
|
|
941
|
+
|
|
942
|
+
const params = { body: { taskId } };
|
|
943
|
+
|
|
944
|
+
return await internalRequest(
|
|
945
|
+
this.sdk,
|
|
946
|
+
'/taskRouter/tasks/unpark',
|
|
947
|
+
'PUT',
|
|
948
|
+
params,
|
|
949
|
+
);
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* Public reply on a ticket task: writes the customer-visible post and
|
|
954
|
+
* emails requester + CCs (transactional) from the queue mailbox.
|
|
955
|
+
*
|
|
956
|
+
* POST /taskRouter/tasks/:id/public-reply
|
|
957
|
+
*
|
|
958
|
+
* @param {Object} options
|
|
959
|
+
* @param {string} options.taskId
|
|
960
|
+
* @param {string} [options.html]
|
|
961
|
+
* @param {string} [options.text]
|
|
962
|
+
* @param {string|string[]} [options.extraTo]
|
|
963
|
+
* @param {string|string[]} [options.extraCc]
|
|
964
|
+
* @param {string|string[]} [options.extraBcc]
|
|
965
|
+
* @param {string|string[]} [options.attachments]
|
|
966
|
+
* @param {boolean} [options.addExtrasToTicket]
|
|
967
|
+
* @param {string} [options.retryVisitorMessageId]
|
|
968
|
+
*/
|
|
969
|
+
async publicReply(options = {}) {
|
|
970
|
+
const {
|
|
971
|
+
taskId,
|
|
972
|
+
html,
|
|
973
|
+
text,
|
|
974
|
+
extraTo,
|
|
975
|
+
extraCc,
|
|
976
|
+
extraBcc,
|
|
977
|
+
attachments,
|
|
978
|
+
addExtrasToTicket,
|
|
979
|
+
retryVisitorMessageId,
|
|
980
|
+
} = options;
|
|
981
|
+
|
|
982
|
+
this.sdk.validateParams(
|
|
983
|
+
{ taskId },
|
|
984
|
+
{ taskId: { type: 'string', required: true } },
|
|
985
|
+
);
|
|
986
|
+
|
|
987
|
+
const body = {};
|
|
988
|
+
if (html !== undefined) body.html = html;
|
|
989
|
+
if (text !== undefined) body.text = text;
|
|
990
|
+
if (extraTo !== undefined) body.extraTo = extraTo;
|
|
991
|
+
if (extraCc !== undefined) body.extraCc = extraCc;
|
|
992
|
+
if (extraBcc !== undefined) body.extraBcc = extraBcc;
|
|
993
|
+
if (attachments !== undefined) body.attachments = attachments;
|
|
994
|
+
if (addExtrasToTicket !== undefined) {
|
|
995
|
+
body.addExtrasToTicket = addExtrasToTicket;
|
|
996
|
+
}
|
|
997
|
+
if (retryVisitorMessageId !== undefined) {
|
|
998
|
+
body.retryVisitorMessageId = retryVisitorMessageId;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
return await internalRequest(
|
|
1002
|
+
this.sdk,
|
|
1003
|
+
`/taskRouter/tasks/${taskId}/public-reply`,
|
|
1004
|
+
'POST',
|
|
1005
|
+
{ body },
|
|
1006
|
+
);
|
|
1007
|
+
}
|
|
1008
|
+
|
|
883
1009
|
/**
|
|
884
1010
|
* Mark a task's inbound messages as read for one channel (or all).
|
|
885
1011
|
* Channel ids: sms | webchat | email | whatsApp | rcs | all.
|