@signalhousellc/sdk 1.4.1 → 1.4.2
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 +1 -1
- package/scripts/install-skills.mjs +0 -0
- package/src/SignalHouseSDK.js +18 -3
- package/src/domains/Campaigns.js +39 -0
package/package.json
CHANGED
|
File without changes
|
package/src/SignalHouseSDK.js
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import axios from "axios";
|
|
2
2
|
|
|
3
|
+
// Bounds every request made by this SDK. Chosen well above typical p99 latency so it only trips on
|
|
4
|
+
// a genuinely hung connection, not a slow-but-completing request.
|
|
5
|
+
const REQUEST_TIMEOUT_MS = 30000;
|
|
6
|
+
|
|
3
7
|
/**
|
|
4
8
|
* @typedef {Object} RequestOptions
|
|
5
9
|
* @property {string} [token] - An optional bearer token to include in the request for authentication
|
|
@@ -100,8 +104,10 @@ export class SignalHouseSDK {
|
|
|
100
104
|
* @returns {Function} A function to make API requests
|
|
101
105
|
*/
|
|
102
106
|
_createClient(isMultipart = false) {
|
|
103
|
-
// Create an Axios instance with the base URL and default headers
|
|
104
|
-
|
|
107
|
+
// Create an Axios instance with the base URL and default headers. `timeout` bounds every
|
|
108
|
+
// request so a hung connection (server-side lock contention, a stalled upstream call) rejects
|
|
109
|
+
// instead of leaving the caller's promise unsettled forever with no error and no feedback.
|
|
110
|
+
const instance = axios.create({ baseURL: this.baseUrl, timeout: REQUEST_TIMEOUT_MS, headers: isMultipart ? {} : { "Content-Type": "application/json" } });
|
|
105
111
|
|
|
106
112
|
// Add a request interceptor to include the API key in the Authorization header
|
|
107
113
|
instance.interceptors.request.use((/** @type {import('axios').InternalAxiosRequestConfig & { token?: string, idempotencyKey?: string }} */ config) => {
|
|
@@ -122,8 +128,17 @@ export class SignalHouseSDK {
|
|
|
122
128
|
return { success: true, data: response.data, status: response.status };
|
|
123
129
|
}),
|
|
124
130
|
|
|
125
|
-
// Non-2xx responses
|
|
131
|
+
// Non-2xx responses, plus timeouts and network failures (no `error.response` at all) - those
|
|
132
|
+
// get a clear message here rather than surfacing axios's internal error.message verbatim.
|
|
126
133
|
(error) => {
|
|
134
|
+
if (!error.response) {
|
|
135
|
+
const isTimeout = error.code === "ECONNABORTED" || /timeout/i.test(error.message || "");
|
|
136
|
+
return {
|
|
137
|
+
success: false,
|
|
138
|
+
error: isTimeout ? "Request timed out. Please try again." : "Network error. Please check your connection and try again.",
|
|
139
|
+
status: null,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
127
142
|
return {
|
|
128
143
|
success: false,
|
|
129
144
|
error: error.response?.data?.message || error.response?.data || error.message || 500,
|
package/src/domains/Campaigns.js
CHANGED
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
* @property {string} privacyPolicyLink - A URL linking to the privacy policy for the campaign (required, must be at most 2048 characters)
|
|
37
37
|
* @property {string} termsAndConditionsLink - A URL linking to the terms and conditions for the campaign (required, must be at most 2048 characters)
|
|
38
38
|
* @property {string} [embeddedLinkSample] - A sample of the embedded link used in the campaign (optional, must be at most 255 characters)
|
|
39
|
+
* @property {string[]} [sampleMediaIds] - Up to 5 mediaIds from uploadSampleMedia: sample MMS media shown to carrier and TCR reviewers (10DLC only)
|
|
39
40
|
* @property {Array<string>} phoneNumbers - An array of phone numbers associated with the campaign (required, each number must be at least 10 digits and contain only digits, a maximum of 5000 numbers is allowed)
|
|
40
41
|
*/
|
|
41
42
|
|
|
@@ -70,6 +71,7 @@
|
|
|
70
71
|
* @property {string} [privacyPolicyLink] - A URL linking to the privacy policy for the campaign (optional, must be at most 2048 characters if provided)
|
|
71
72
|
* @property {string} [termsAndConditionsLink] - A URL linking to the terms and conditions for the campaign (optional, must be at most 2048 characters if provided)
|
|
72
73
|
* @property {string} [embeddedLinkSample] - A sample of the embedded link used in the campaign (optional, must be at most 255 characters if provided)
|
|
74
|
+
* @property {string[]} [sampleMediaIds] - Up to 5 mediaIds from uploadSampleMedia: sample MMS media shown to carrier and TCR reviewers (10DLC only)
|
|
73
75
|
* @property {Object} [tollFree] - Toll-Free editable fields, used when updating a Toll-Free campaign. Mirrors the CreateTollFreeCampaignData `tollFree` object with every field optional (useCase, messageVolume, programSummary (40-500), exampleMessage (≤1000), customerCareEmail, optInImageURLs, optIns, multiNumberReason (≤500), useCases, channels, landingId). Phone numbers cannot be changed via update — Toll-Free numbers are locked to their campaign.
|
|
74
76
|
*/
|
|
75
77
|
|
|
@@ -529,6 +531,43 @@ export class Campaigns {
|
|
|
529
531
|
return this.client(`/campaign/short-code/artifact/${safeArtifactId}`, { method: 'GET', ...options });
|
|
530
532
|
}
|
|
531
533
|
|
|
534
|
+
/**
|
|
535
|
+
* Upload a sample media file (JPEG, PNG, GIF, MP4 or MP3, up to 5MB) for a 10DLC campaign. Reference the
|
|
536
|
+
* returned mediaId in sampleMediaIds on campaign create or update; it is attached to the TCR campaign for
|
|
537
|
+
* carrier review
|
|
538
|
+
* @async
|
|
539
|
+
* @roles api, admin, developer, user
|
|
540
|
+
* @param {Object} params - The parameters for uploading the sample media
|
|
541
|
+
* @param {Blob|File} params.file - The media file to upload, provided as a Blob/File
|
|
542
|
+
* @param {string} [params.groupId] - The group the file belongs to. Required with a staff (signalhouse_*) key, which has no active group; otherwise optional and must be your own group
|
|
543
|
+
* @param {RequestOptions} [params.options] - Additional options for the request
|
|
544
|
+
* @throws {Error} Throws an error if the file parameter is missing
|
|
545
|
+
* @returns {Promise<SdkResponse<any>>} The response from the server containing the mediaId, fileName, mimeType and size
|
|
546
|
+
*/
|
|
547
|
+
async uploadSampleMedia({ file, groupId, options = {} }) {
|
|
548
|
+
this.client._require({ file });
|
|
549
|
+
const formData = new FormData();
|
|
550
|
+
if (groupId) formData.append('groupId', groupId);
|
|
551
|
+
formData.append('file', file);
|
|
552
|
+
return this.multipartClient(`/campaign/sample-media`, { method: 'POST', body: formData, ...options });
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/**
|
|
556
|
+
* Download a campaign sample media file your group owns
|
|
557
|
+
* @async
|
|
558
|
+
* @roles api, admin, developer, user
|
|
559
|
+
* @param {Object} params - The parameters for downloading the sample media
|
|
560
|
+
* @param {string} params.mediaId - The mediaId returned by uploadSampleMedia
|
|
561
|
+
* @param {RequestOptions} [params.options] - Additional options for the request
|
|
562
|
+
* @throws {Error} Throws an error if the mediaId parameter is missing
|
|
563
|
+
* @returns {Promise<SdkResponse<any>>} The response from the server containing the file bytes
|
|
564
|
+
*/
|
|
565
|
+
async readSampleMedia({ mediaId, options = {} }) {
|
|
566
|
+
this.client._require({ mediaId });
|
|
567
|
+
const safeMediaId = encodeURIComponent(mediaId);
|
|
568
|
+
return this.client(`/campaign/sample-media/${safeMediaId}`, { method: 'GET', ...options });
|
|
569
|
+
}
|
|
570
|
+
|
|
532
571
|
/**
|
|
533
572
|
* Upload an opt-in proof image to be hosted on-platform, returning a publicly-fetchable URL suitable for a
|
|
534
573
|
* Toll-Free campaign's optInImageURLs or a Short Code campaign's shortCode.screenshotUrl
|