@signalhousellc/sdk 1.0.53 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@signalhousellc/sdk",
3
- "version": "1.0.53",
3
+ "version": "1.0.55",
4
4
  "description": "Signal House SDK for use with the Signal House platform",
5
5
  "type": "module",
6
6
  "main": "src/SignalHouseSDK.js",
@@ -198,6 +198,29 @@ export class Brands {
198
198
  return this.client(`/brand/externalvetting/${safeBrandId}`, { method: "POST", ...options });
199
199
  }
200
200
 
201
+ /**
202
+ * Import an existing external vetting record for a brand
203
+ *
204
+ * Unlike createExternalVetting (which orders a new, billable vetting), this attaches a vetting the
205
+ * brand already completed directly with the provider, using the provider-issued vettingId and
206
+ * vettingToken. It is synchronous and not billable.
207
+ * @async
208
+ * @roles api, admin, developer, billing, user
209
+ * @param {Object} params - The parameters for importing external vetting
210
+ * @param {string} params.brandId - The ID of the brand to import external vetting for
211
+ * @param {string} params.vettingProviderId - The external vetting provider (AEGIS, WMC, CV)
212
+ * @param {string} params.vettingId - The provider-issued vetting / transaction ID to import
213
+ * @param {string} [params.vettingToken] - The provider-issued vetting token (required by some providers, e.g. AEGIS)
214
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
215
+ * @throws {Error} Throws an error if brandId, vettingProviderId, or vettingId is missing
216
+ * @returns {Promise<Object>} The response from the server
217
+ */
218
+ async importExternalVetting({ brandId, vettingProviderId, vettingId, vettingToken, options = {} }) {
219
+ this.client._require({ brandId, vettingProviderId, vettingId });
220
+ const safeBrandId = encodeURIComponent(brandId);
221
+ return this.client(`/brand/externalvetting/import/${safeBrandId}`, { method: "POST", body: { vettingProviderId, vettingId, vettingToken }, ...options });
222
+ }
223
+
201
224
  /**
202
225
  * Update a brand's information
203
226
  * @async
@@ -18,6 +18,8 @@ export class Messages {
18
18
  * @param {string} [params.status] - Filter messages by their status (ENQUEUED, DEQUEUED, SENT, FAILED, DELIVERED)
19
19
  * @param {string} [params.direction] - Filter messages by their direction (INBOUND, OUTBOUND)
20
20
  * @param {string|string[]} [params.messageType] - Filter messages by their type. Accepts a single value or an array (e.g. ["SMS", "MMS"]). Allowed values: SMS, MMS, RCS, WHATSAPP, VIBER, P2P. When omitted, defaults to all non-P2P types.
21
+ * @param {string|string[]} [params.channel] - Filter messages by messaging channel. Accepts a single value or an array (cumulative). Allowed values: TEN_DLC, TOLL_FREE, P2P. Channel is derived on read from the associated campaign/brand registrationType (or messageType "P2P"); it is not stored on the message. Ignored when matchAny is true (matchAny takes precedence).
22
+ * @param {boolean} [params.matchAny] - When true, the provided campaignId/brandId/phoneNumber filters are OR'd (a message matches ANY of them) instead of the default most-specific-single behavior. subgroupId stays an AND scope. Opt-in/additive.
21
23
  * @param {string} [params.carrier] - Filter messages by the carrier used for sending
22
24
  * @param {string} [params.senderPhoneNumber] - Filter messages by the sender's phone number
23
25
  * @param {string} [params.recipientPhoneNumber] - Filter messages by the recipient's phone number
@@ -42,6 +44,8 @@ export class Messages {
42
44
  status,
43
45
  direction,
44
46
  messageType,
47
+ channel,
48
+ matchAny,
45
49
  carrier,
46
50
  startDate,
47
51
  endDate,
@@ -51,7 +55,7 @@ export class Messages {
51
55
  limit,
52
56
  options = {},
53
57
  }) {
54
- const filters = { id, campaignId, brandId, subgroupId, groupId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, carrier, startDate, endDate, sortField, sortOrder, page, limit };
58
+ const filters = { id, campaignId, brandId, subgroupId, groupId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, channel, matchAny, carrier, startDate, endDate, sortField, sortOrder, page, limit };
55
59
  const queryString = this.client._getQueryString(filters);
56
60
  return this.client(`/message${queryString}`, { method: "GET", ...options });
57
61
  }
@@ -89,11 +93,13 @@ export class Messages {
89
93
  * @param {string} [params.carrier] - Filter analytics by the carrier used for sending
90
94
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; normalized to start-of-UTC-day (inclusive)
91
95
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; normalized to end-of-UTC-day (inclusive). Hourly resolution is not supported
96
+ * @param {boolean} [params.matchAny] - When true, the provided campaignId/brandId/phoneNumber filters are OR'd (match ANY) instead of the default most-specific-single behavior. subgroupId stays an AND scope. Opt-in/additive.
97
+ * @param {string|string[]} [params.channel] - Filter analytics by messaging channel (TEN_DLC, TOLL_FREE). Derived on read from the campaign/brand registrationType; resolves to the channel's campaigns so the analytics count matches the channel-filtered message list. Accepts a single value or array (cumulative). Ignored when matchAny is true (matchAny takes precedence).
92
98
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
93
99
  * @returns {Promise<Object>} - A promise that resolves to the analytics data
94
100
  */
95
- async getAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, options = {} }) {
96
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate };
101
+ async getAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, matchAny, options = {} }) {
102
+ const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, matchAny };
97
103
  const queryString = this.client._getQueryString(filters);
98
104
  return this.client(`/message/analytics${queryString}`, { method: "GET", ...options });
99
105
  }
@@ -267,13 +273,17 @@ export class Messages {
267
273
  * @param {string[]} params.recipientPhoneNumbers - The phone number(s) to send the message to
268
274
  * @param {string} params.messageBody - The body of the P2P message
269
275
  * @param {string} [params.statusCallbackUrl] - The URL to receive status callbacks
276
+ * @param {boolean} [params.useSignalHouseShortlinks] - When false, SignalHouse applies no link-shortening
277
+ * or text-spin and your pre-spun links/content are sent verbatim (bring-your-own spinner). Defaults to
278
+ * true server-side (the SignalHouse shortlink system, which mints unique per-recipient links).
270
279
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
271
280
  * @returns {Promise<Object>} - A promise that resolves to the response data from the server
272
281
  */
273
- async sendP2P({ recipientPhoneNumbers, messageBody, statusCallbackUrl, options = {} }) {
282
+ async sendP2P({ recipientPhoneNumbers, messageBody, statusCallbackUrl, useSignalHouseShortlinks, options = {} }) {
274
283
  this.client._require({ recipientPhoneNumbers, messageBody });
275
284
  const body = { recipientPhoneNumber: recipientPhoneNumbers, messageBody };
276
285
  if (statusCallbackUrl) body.statusCallbackUrl = statusCallbackUrl;
286
+ if (typeof useSignalHouseShortlinks === "boolean") body.useSignalHouseShortlinks = useSignalHouseShortlinks;
277
287
  return this.client(`/message/p2p`, {
278
288
  method: "POST",
279
289
  body,
@@ -134,15 +134,16 @@ export class Numbers {
134
134
  /**
135
135
  * Read the outcome of a Toll-Free number purchase by the `orderId` returned from
136
136
  * {@link Numbers#purchaseTollFreeNumbers}. Reports per-number status as ready / provisioning / failed
137
- * counts (plus failure reasons) so a client can poll until the order reaches a terminal state. The
138
- * provisioned numbers themselves appear in the regular numbers list as they materialize.
137
+ * counts (plus failure reasons) so a client can poll until the order reaches a terminal state, and
138
+ * returns the provisioned phone numbers for the order so a client can act on exactly those numbers.
139
+ * `numbers` is empty until each number is provisioned (it fills in as the order completes).
139
140
  * @async
140
141
  * @roles api, admin, developer, billing, user
141
142
  * @param {Object} params - The parameters for reading the order status
142
143
  * @param {string} params.orderId - The order id returned by `purchaseTollFreeNumbers`
143
144
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
144
145
  * @throws {Error} Throws an error if the orderId parameter is missing
145
- * @returns {Promise<Object>} A promise that resolves to `{ orderId, counts: { ready, provisioning, failed }, failures: [{ reason }] }`.
146
+ * @returns {Promise<Object>} A promise that resolves to `{ orderId, counts: { ready, provisioning, failed }, failures: [{ reason }], numbers: string[] }`.
146
147
  */
147
148
  async getTollFreeOrderStatus({ orderId, options = {} }) {
148
149
  this.client._require({ orderId });
@@ -141,6 +141,104 @@ export class Call {
141
141
  }
142
142
  }
143
143
 
144
+ /**
145
+ * Mute or unmute the local microphone. Twilio-shape: pass `true` to mute,
146
+ * `false` to unmute. Stops/resumes sending audio RTP at the media layer —
147
+ * no SIP signaling, so it works regardless of server support.
148
+ * @param {boolean} [shouldMute=true]
149
+ */
150
+ mute(shouldMute = true) {
151
+ if (this.status !== "in_progress") {
152
+ console.warn(`[Call.mute] no-op: call is not in_progress (status=${this.status})`);
153
+ return;
154
+ }
155
+ try {
156
+ if (shouldMute) this._session.mute({ audio: true });
157
+ else this._session.unmute({ audio: true });
158
+ } catch (err) {
159
+ console.warn(`[Call.mute] threw: ${err?.message || err}`);
160
+ }
161
+ }
162
+
163
+ /** Unmute the local microphone. Convenience for `mute(false)`. */
164
+ unmute() {
165
+ this.mute(false);
166
+ }
167
+
168
+ /**
169
+ * @returns {boolean} whether the local microphone is currently muted.
170
+ */
171
+ isMuted() {
172
+ try {
173
+ return Boolean(this._session.isMuted?.()?.audio);
174
+ } catch {
175
+ return false;
176
+ }
177
+ }
178
+
179
+ /**
180
+ * Put the call on hold, or resume it. Sends a re-INVITE with the audio
181
+ * direction set to sendonly (hold) / sendrecv (resume); the media server
182
+ * (rtpengine) handles it. Pass `false` to resume.
183
+ * @param {boolean} [shouldHold=true]
184
+ * @returns {boolean} whether the (un)hold was initiated.
185
+ */
186
+ hold(shouldHold = true) {
187
+ if (this.status !== "in_progress") {
188
+ console.warn(`[Call.hold] no-op: call is not in_progress (status=${this.status})`);
189
+ return false;
190
+ }
191
+ try {
192
+ return shouldHold ? this._session.hold() : this._session.unhold();
193
+ } catch (err) {
194
+ console.warn(`[Call.hold] threw: ${err?.message || err}`);
195
+ return false;
196
+ }
197
+ }
198
+
199
+ /** Resume a held call. Convenience for `hold(false)`. */
200
+ unhold() {
201
+ return this.hold(false);
202
+ }
203
+
204
+ /**
205
+ * @returns {boolean} whether this leg is locally on hold.
206
+ */
207
+ isOnHold() {
208
+ try {
209
+ return Boolean(this._session.isOnHold?.()?.local);
210
+ } catch {
211
+ return false;
212
+ }
213
+ }
214
+
215
+ /**
216
+ * Blind-transfer (cold transfer) the call to another destination via SIP
217
+ * REFER. The far end is re-routed to `target` and this leg ends once the
218
+ * transfer is accepted. `target` may be a phone number (E.164 or bare
219
+ * digits) or a full SIP URI — bare numbers are normalized against the
220
+ * registered SIP domain by the underlying stack.
221
+ *
222
+ * NOTE: completing the transfer requires the SIP server to honor the REFER
223
+ * (route the new leg / bridge the parties). The client only initiates it.
224
+ * @param {string} target - Destination number or SIP URI.
225
+ */
226
+ transfer(target) {
227
+ if (this.status !== "in_progress") {
228
+ console.warn(`[Call.transfer] no-op: call is not in_progress (status=${this.status})`);
229
+ return;
230
+ }
231
+ if (!target) {
232
+ console.warn("[Call.transfer] no-op: a transfer target is required");
233
+ return;
234
+ }
235
+ try {
236
+ this._session.refer(target);
237
+ } catch (err) {
238
+ console.warn(`[Call.transfer] refer threw: ${err?.message || err}`);
239
+ }
240
+ }
241
+
144
242
  /**
145
243
  * Attach an event listener. Events:
146
244
  * "accepted" — 200 OK received (outbound) or sent (inbound after accept)