@unboundcx/sdk 4.13.39 → 4.13.41

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.39",
3
+ "version": "4.13.41",
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",
package/services/chat.js CHANGED
@@ -497,6 +497,49 @@ export class ChatService {
497
497
  );
498
498
  }
499
499
 
500
+ /**
501
+ * Send a message on a kind:'text' channel (sms-routing-plan.md §3.3.1).
502
+ * Plain body only — no ProseMirror `message`, no threads/cards. The API
503
+ * intercepts this route for text channels and sends the plain-text body
504
+ * as a real SMS/MMS via the same pipeline as sdk.messaging.sms.send
505
+ * (unless `internal` is set, which stays a regular chat message).
506
+ * @param {string} channelId
507
+ * @param {Object} params
508
+ * @param {string} [params.text] - Plain message text
509
+ * @param {string[]} [params.storageIds] - Image attachment storage ids
510
+ * @param {boolean} [params.internal] - Internal note; never sent as SMS
511
+ * @param {boolean} [params.force] - Force-send past a busy-conversation
512
+ * (409 TEXT_CONVERSATION_BUSY) collision
513
+ * @returns {Promise<Object>} Created message
514
+ */
515
+ async sendTextMessage(channelId, { text, storageIds, internal, force } = {}) {
516
+ this.sdk.validateParams(
517
+ { channelId, text, storageIds, internal, force },
518
+ {
519
+ channelId: { type: "string", required: true },
520
+ text: { type: "string", required: false },
521
+ storageIds: { type: "array", required: false },
522
+ internal: { type: "boolean", required: false },
523
+ force: { type: "boolean", required: false },
524
+ },
525
+ );
526
+
527
+ const body = {};
528
+ if (text !== undefined) body.text = text;
529
+ if (storageIds !== undefined) body.storageIds = storageIds;
530
+ if (internal !== undefined) body.internal = internal;
531
+ if (force !== undefined) body.force = force;
532
+
533
+ return internalRequest(
534
+ this.sdk,
535
+ `/chat/channels/${channelId}/messages`,
536
+ "POST",
537
+ {
538
+ body,
539
+ },
540
+ );
541
+ }
542
+
500
543
  /**
501
544
  * Edit a message body (ProseMirror JSON).
502
545
  * @param {string} id
@@ -844,7 +887,11 @@ export class ChatService {
844
887
  * reason"; channel must be a non-archived public/private channel.
845
888
  * @returns {Promise<Object>} `{allowReports, reportReasons, reportNotifications}`
846
889
  */
847
- async adminPutSettings({ allowReports, reportReasons, reportNotifications } = {}) {
890
+ async adminPutSettings({
891
+ allowReports,
892
+ reportReasons,
893
+ reportNotifications,
894
+ } = {}) {
848
895
  this.sdk.validateParams(
849
896
  { allowReports, reportReasons, reportNotifications },
850
897
  {
@@ -1145,7 +1192,10 @@ export class ChatService {
1145
1192
  * @param {'open'|'in_review'} [params.status]
1146
1193
  * @returns {Promise<Object>}
1147
1194
  */
1148
- async adminUpdateCase(id, { title, category, description, ownerId, status } = {}) {
1195
+ async adminUpdateCase(
1196
+ id,
1197
+ { title, category, description, ownerId, status } = {},
1198
+ ) {
1149
1199
  this.sdk.validateParams(
1150
1200
  { id, title, category, description, ownerId, status },
1151
1201
  {
@@ -10,7 +10,8 @@ export class SmsService {
10
10
  /**
11
11
  * Send an SMS/MMS message
12
12
  * @param {Object} params - Message parameters
13
- * @param {string} params.to - Recipient phone number (required)
13
+ * @param {string|string[]} params.to - Recipient phone number, or an
14
+ * array of up to 8 for a group MMS send (required)
14
15
  * @param {string} [params.from] - Sender phone number
15
16
  * @param {string} [params.message] - Message text
16
17
  * @param {string} [params.templateId] - Template ID to use
@@ -21,6 +22,8 @@ export class SmsService {
21
22
  * to attach this message to, so it surfaces on that record's feed
22
23
  * @param {string} [params.engagementSessionId] - Engagement to attach this message to
23
24
  * @param {string} [params.taskId] - Task the message was sent under (multi-channel-per-task attribution)
25
+ * @param {boolean} [params.force] - Force-send past a busy-conversation
26
+ * (409 TEXT_CONVERSATION_BUSY) collision
24
27
  * @returns {Promise<Object>} Message details
25
28
  */
26
29
  async send({
@@ -34,6 +37,7 @@ export class SmsService {
34
37
  relatedId,
35
38
  engagementSessionId,
36
39
  taskId,
40
+ force,
37
41
  }) {
38
42
  const messageData = {};
39
43
  if (from) messageData.from = from;
@@ -45,11 +49,26 @@ export class SmsService {
45
49
  if (relatedId) messageData.relatedId = relatedId;
46
50
  if (engagementSessionId) messageData.engagementSessionId = engagementSessionId;
47
51
  if (taskId) messageData.taskId = taskId;
52
+ if (force !== undefined) messageData.force = force;
53
+
54
+ // `to` is string | string[] (group MMS, up to 8 recipients) --
55
+ // validated by hand since sdk.validateParams has no multi-type support
56
+ // (see TaskService.js's ['string','array'] usage, which hits the same
57
+ // gap) rather than compounding that on a new call site.
58
+ if (to === undefined || to === null) {
59
+ throw new Error('Missing required parameter to');
60
+ }
61
+ if (Array.isArray(to)) {
62
+ if (!to.length || !to.every((n) => typeof n === 'string')) {
63
+ throw new Error('Invalid type for parameter to: expected string or string[]');
64
+ }
65
+ } else if (typeof to !== 'string') {
66
+ throw new Error('Invalid type for parameter to: expected string or string[]');
67
+ }
48
68
 
49
69
  this.sdk.validateParams(
50
- { to, ...messageData },
70
+ { ...messageData },
51
71
  {
52
- to: { type: 'string', required: true },
53
72
  from: { type: 'string', required: false },
54
73
  message: { type: 'string', required: false },
55
74
  templateId: { type: 'string', required: false },
@@ -59,6 +78,7 @@ export class SmsService {
59
78
  relatedId: { type: 'string', required: false },
60
79
  engagementSessionId: { type: 'string', required: false },
61
80
  taskId: { type: 'string', required: false },
81
+ force: { type: 'boolean', required: false },
62
82
  },
63
83
  );
64
84
 
package/services/text.js CHANGED
@@ -97,6 +97,56 @@ export class TextConversationsService {
97
97
  body: { queueId, workflowId, workflowVersionId },
98
98
  });
99
99
  }
100
+
101
+ /**
102
+ * Move a TASK-owned conversation to a user (or UC Chat group) or to a
103
+ * workflow (sms-routing-plan.md K4, plan §3.4 "task -> user"/"task ->
104
+ * workflow"). Caller must be the task's current worker or a manager --
105
+ * enforced server-side. Moving to a user creates/reuses the UC Chat
106
+ * channel for that (identity, counterparty) pair starting from now --
107
+ * prior message history is NOT backfilled into the channel.
108
+ * @param {string} id - textConversations id (required)
109
+ * @param {Object} options - Parameters
110
+ * @param {'user'|'workflow'} options.to - Move target (required)
111
+ * @param {string} [options.userId] - Target user (required if to:'user' and no groupId)
112
+ * @param {string} [options.groupId] - Target UC Chat group (required if to:'user' and no userId)
113
+ * @param {'private'|'public'} [options.visibility] - New channel visibility (to:'user' only)
114
+ * @param {string} [options.workflowId] - Move to a workflow's current version
115
+ * @param {string} [options.workflowVersionId] - Move to a pinned workflow version
116
+ * @returns {Promise<Object>} The updated conversation row
117
+ */
118
+ async move(id, options = {}) {
119
+ const { to, userId, groupId, visibility, workflowId, workflowVersionId } =
120
+ options;
121
+
122
+ this.sdk.validateParams(
123
+ { id, to, userId, groupId, visibility, workflowId, workflowVersionId },
124
+ {
125
+ id: { type: 'string', required: true },
126
+ to: { type: 'string', required: true },
127
+ userId: { type: 'string', required: false },
128
+ groupId: { type: 'string', required: false },
129
+ visibility: { type: 'string', required: false },
130
+ workflowId: { type: 'string', required: false },
131
+ workflowVersionId: { type: 'string', required: false },
132
+ },
133
+ );
134
+ if (to !== 'user' && to !== 'workflow') {
135
+ throw new Error("move requires to: 'user' or 'workflow'");
136
+ }
137
+ if (to === 'user' && !userId && !groupId) {
138
+ throw new Error("move to:'user' requires userId or groupId");
139
+ }
140
+ if (to === 'workflow' && !workflowId && !workflowVersionId) {
141
+ throw new Error(
142
+ "move to:'workflow' requires workflowId or workflowVersionId",
143
+ );
144
+ }
145
+
146
+ return internalRequest(this.sdk, `/text/conversations/${id}/move`, 'POST', {
147
+ body: { to, userId, groupId, visibility, workflowId, workflowVersionId },
148
+ });
149
+ }
100
150
  }
101
151
 
102
152
  export class TextService {