@sendly/node 3.17.0 → 3.18.0

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/dist/index.d.mts CHANGED
@@ -59,6 +59,11 @@ interface SendMessageRequest {
59
59
  * Stored on the message record and included in webhook event payloads.
60
60
  */
61
61
  metadata?: Record<string, any>;
62
+ /**
63
+ * URLs of media files to include as MMS attachments.
64
+ * Must be publicly accessible HTTPS URLs. Max 10 per message.
65
+ */
66
+ mediaUrls?: string[];
62
67
  }
63
68
  /**
64
69
  * Message status values
@@ -185,6 +190,42 @@ interface MessageListResponse {
185
190
  */
186
191
  count: number;
187
192
  }
193
+ /**
194
+ * An uploaded media file for MMS
195
+ */
196
+ interface MediaFile {
197
+ /**
198
+ * Unique media file identifier
199
+ */
200
+ id: string;
201
+ /**
202
+ * Publicly accessible URL for the media file
203
+ */
204
+ url: string;
205
+ /**
206
+ * MIME type of the file (e.g., "image/jpeg")
207
+ */
208
+ contentType: string;
209
+ /**
210
+ * File size in bytes
211
+ */
212
+ sizeBytes: number;
213
+ }
214
+ /**
215
+ * Options for uploading a media file
216
+ */
217
+ interface MediaUploadOptions {
218
+ /**
219
+ * Filename for the upload
220
+ * @default "upload.jpg"
221
+ */
222
+ filename?: string;
223
+ /**
224
+ * MIME content type
225
+ * @default "image/jpeg"
226
+ */
227
+ contentType?: string;
228
+ }
188
229
  /**
189
230
  * Request payload for scheduling an SMS message
190
231
  */
@@ -1500,6 +1541,10 @@ declare class HttpClient {
1500
1541
  * Make an HTTP request to the API
1501
1542
  */
1502
1543
  request<T>(options: RequestOptions): Promise<T>;
1544
+ /**
1545
+ * Make an HTTP request with a raw body (for multipart uploads)
1546
+ */
1547
+ requestFormData<T>(path: string, body: FormData, headers?: Record<string, string>): Promise<T>;
1503
1548
  /**
1504
1549
  * Execute the HTTP request
1505
1550
  */
@@ -2954,6 +2999,57 @@ declare class ContactListsResource {
2954
2999
  private transformList;
2955
3000
  }
2956
3001
 
3002
+ /**
3003
+ * Media Resource
3004
+ * @packageDocumentation
3005
+ */
3006
+
3007
+ /**
3008
+ * Media API resource
3009
+ *
3010
+ * @example
3011
+ * ```typescript
3012
+ * // Upload an image and send as MMS
3013
+ * const file = fs.readFileSync('photo.jpg');
3014
+ * const media = await sendly.media.upload(file, {
3015
+ * filename: 'photo.jpg',
3016
+ * contentType: 'image/jpeg'
3017
+ * });
3018
+ *
3019
+ * await sendly.messages.send({
3020
+ * to: '+15551234567',
3021
+ * text: 'Check out this photo!',
3022
+ * mediaUrls: [media.url]
3023
+ * });
3024
+ * ```
3025
+ */
3026
+ declare class MediaResource {
3027
+ private readonly http;
3028
+ constructor(http: HttpClient);
3029
+ /**
3030
+ * Upload a media file for use in MMS messages
3031
+ *
3032
+ * @param file - File data as a Buffer or ReadableStream
3033
+ * @param options - Upload options (filename, content type)
3034
+ * @returns The uploaded media file with URL
3035
+ *
3036
+ * @example
3037
+ * ```typescript
3038
+ * const media = await sendly.media.upload(
3039
+ * fs.readFileSync('image.png'),
3040
+ * { filename: 'image.png', contentType: 'image/png' }
3041
+ * );
3042
+ *
3043
+ * console.log(media.url); // https://...
3044
+ * ```
3045
+ *
3046
+ * @throws {ValidationError} If the file is invalid or too large
3047
+ * @throws {AuthenticationError} If the API key is invalid
3048
+ * @throws {RateLimitError} If rate limit is exceeded
3049
+ */
3050
+ upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
3051
+ }
3052
+
2957
3053
  /**
2958
3054
  * Sendly Client
2959
3055
  * @packageDocumentation
@@ -3124,6 +3220,26 @@ declare class Sendly {
3124
3220
  * ```
3125
3221
  */
3126
3222
  readonly contacts: ContactsResource;
3223
+ /**
3224
+ * Media API resource - Upload media for MMS
3225
+ *
3226
+ * @example
3227
+ * ```typescript
3228
+ * // Upload a file
3229
+ * const media = await sendly.media.upload(fileBuffer, {
3230
+ * filename: 'photo.jpg',
3231
+ * contentType: 'image/jpeg'
3232
+ * });
3233
+ *
3234
+ * // Send as MMS
3235
+ * await sendly.messages.send({
3236
+ * to: '+15551234567',
3237
+ * text: 'Check this out!',
3238
+ * mediaUrls: [media.url]
3239
+ * });
3240
+ * ```
3241
+ */
3242
+ readonly media: MediaResource;
3127
3243
  private readonly http;
3128
3244
  private readonly config;
3129
3245
  /**
@@ -3574,4 +3690,4 @@ declare class Webhooks {
3574
3690
  */
3575
3691
  type WebhookMessageData = WebhookMessageObject;
3576
3692
 
3577
- export { ALL_SUPPORTED_COUNTRIES, type Account, type ApiErrorResponse, type ApiKey, AuthenticationError, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreditTransaction, type Credits, type DeliveryStatus, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type Message, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type PricingTier, RateLimitError, type RateLimitInfo, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
3693
+ export { ALL_SUPPORTED_COUNTRIES, type Account, type ApiErrorResponse, type ApiKey, AuthenticationError, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreditTransaction, type Credits, type DeliveryStatus, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type PricingTier, RateLimitError, type RateLimitInfo, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -59,6 +59,11 @@ interface SendMessageRequest {
59
59
  * Stored on the message record and included in webhook event payloads.
60
60
  */
61
61
  metadata?: Record<string, any>;
62
+ /**
63
+ * URLs of media files to include as MMS attachments.
64
+ * Must be publicly accessible HTTPS URLs. Max 10 per message.
65
+ */
66
+ mediaUrls?: string[];
62
67
  }
63
68
  /**
64
69
  * Message status values
@@ -185,6 +190,42 @@ interface MessageListResponse {
185
190
  */
186
191
  count: number;
187
192
  }
193
+ /**
194
+ * An uploaded media file for MMS
195
+ */
196
+ interface MediaFile {
197
+ /**
198
+ * Unique media file identifier
199
+ */
200
+ id: string;
201
+ /**
202
+ * Publicly accessible URL for the media file
203
+ */
204
+ url: string;
205
+ /**
206
+ * MIME type of the file (e.g., "image/jpeg")
207
+ */
208
+ contentType: string;
209
+ /**
210
+ * File size in bytes
211
+ */
212
+ sizeBytes: number;
213
+ }
214
+ /**
215
+ * Options for uploading a media file
216
+ */
217
+ interface MediaUploadOptions {
218
+ /**
219
+ * Filename for the upload
220
+ * @default "upload.jpg"
221
+ */
222
+ filename?: string;
223
+ /**
224
+ * MIME content type
225
+ * @default "image/jpeg"
226
+ */
227
+ contentType?: string;
228
+ }
188
229
  /**
189
230
  * Request payload for scheduling an SMS message
190
231
  */
@@ -1500,6 +1541,10 @@ declare class HttpClient {
1500
1541
  * Make an HTTP request to the API
1501
1542
  */
1502
1543
  request<T>(options: RequestOptions): Promise<T>;
1544
+ /**
1545
+ * Make an HTTP request with a raw body (for multipart uploads)
1546
+ */
1547
+ requestFormData<T>(path: string, body: FormData, headers?: Record<string, string>): Promise<T>;
1503
1548
  /**
1504
1549
  * Execute the HTTP request
1505
1550
  */
@@ -2954,6 +2999,57 @@ declare class ContactListsResource {
2954
2999
  private transformList;
2955
3000
  }
2956
3001
 
3002
+ /**
3003
+ * Media Resource
3004
+ * @packageDocumentation
3005
+ */
3006
+
3007
+ /**
3008
+ * Media API resource
3009
+ *
3010
+ * @example
3011
+ * ```typescript
3012
+ * // Upload an image and send as MMS
3013
+ * const file = fs.readFileSync('photo.jpg');
3014
+ * const media = await sendly.media.upload(file, {
3015
+ * filename: 'photo.jpg',
3016
+ * contentType: 'image/jpeg'
3017
+ * });
3018
+ *
3019
+ * await sendly.messages.send({
3020
+ * to: '+15551234567',
3021
+ * text: 'Check out this photo!',
3022
+ * mediaUrls: [media.url]
3023
+ * });
3024
+ * ```
3025
+ */
3026
+ declare class MediaResource {
3027
+ private readonly http;
3028
+ constructor(http: HttpClient);
3029
+ /**
3030
+ * Upload a media file for use in MMS messages
3031
+ *
3032
+ * @param file - File data as a Buffer or ReadableStream
3033
+ * @param options - Upload options (filename, content type)
3034
+ * @returns The uploaded media file with URL
3035
+ *
3036
+ * @example
3037
+ * ```typescript
3038
+ * const media = await sendly.media.upload(
3039
+ * fs.readFileSync('image.png'),
3040
+ * { filename: 'image.png', contentType: 'image/png' }
3041
+ * );
3042
+ *
3043
+ * console.log(media.url); // https://...
3044
+ * ```
3045
+ *
3046
+ * @throws {ValidationError} If the file is invalid or too large
3047
+ * @throws {AuthenticationError} If the API key is invalid
3048
+ * @throws {RateLimitError} If rate limit is exceeded
3049
+ */
3050
+ upload(file: Buffer | NodeJS.ReadableStream, options?: MediaUploadOptions): Promise<MediaFile>;
3051
+ }
3052
+
2957
3053
  /**
2958
3054
  * Sendly Client
2959
3055
  * @packageDocumentation
@@ -3124,6 +3220,26 @@ declare class Sendly {
3124
3220
  * ```
3125
3221
  */
3126
3222
  readonly contacts: ContactsResource;
3223
+ /**
3224
+ * Media API resource - Upload media for MMS
3225
+ *
3226
+ * @example
3227
+ * ```typescript
3228
+ * // Upload a file
3229
+ * const media = await sendly.media.upload(fileBuffer, {
3230
+ * filename: 'photo.jpg',
3231
+ * contentType: 'image/jpeg'
3232
+ * });
3233
+ *
3234
+ * // Send as MMS
3235
+ * await sendly.messages.send({
3236
+ * to: '+15551234567',
3237
+ * text: 'Check this out!',
3238
+ * mediaUrls: [media.url]
3239
+ * });
3240
+ * ```
3241
+ */
3242
+ readonly media: MediaResource;
3127
3243
  private readonly http;
3128
3244
  private readonly config;
3129
3245
  /**
@@ -3574,4 +3690,4 @@ declare class Webhooks {
3574
3690
  */
3575
3691
  type WebhookMessageData = WebhookMessageObject;
3576
3692
 
3577
- export { ALL_SUPPORTED_COUNTRIES, type Account, type ApiErrorResponse, type ApiKey, AuthenticationError, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreditTransaction, type Credits, type DeliveryStatus, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type Message, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type PricingTier, RateLimitError, type RateLimitInfo, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
3693
+ export { ALL_SUPPORTED_COUNTRIES, type Account, type ApiErrorResponse, type ApiKey, AuthenticationError, type BatchListResponse, type BatchMessageItem, type BatchMessageRequest, type BatchMessageResponse, type BatchMessageResult, type BatchStatus, CREDITS_PER_SMS, type Campaign, type CampaignListResponse, type CampaignPreview, type CampaignStatus, type CancelledMessageResponse, type CheckVerificationRequest, type CheckVerificationResponse, type CircuitState, type Contact, type ContactList, type ContactListResponse, type ContactListsResponse, type CreateCampaignRequest, type CreateContactListRequest, type CreateContactRequest, type CreateTemplateRequest, type CreateVerifySessionRequest, type CreateWebhookOptions, type CreditTransaction, type Credits, type DeliveryStatus, type ImportContactItem, type ImportContactsError, type ImportContactsRequest, type ImportContactsResponse, InsufficientCreditsError, type ListBatchesOptions, type ListCampaignsOptions, type ListContactsOptions, type ListMessagesOptions, type ListScheduledMessagesOptions, type ListVerificationsOptions, type MediaFile, type MediaUploadOptions, type Message, type MessageListResponse, type MessageStatus, type MessageType, NetworkError, NotFoundError, type PricingTier, RateLimitError, type RateLimitInfo, SANDBOX_TEST_NUMBERS, SUPPORTED_COUNTRIES, type ScheduleCampaignRequest, type ScheduleMessageRequest, type ScheduledMessage, type ScheduledMessageListResponse, type ScheduledMessageStatus, type SendMessageRequest, type SendVerificationRequest, type SendVerificationResponse, type SenderType, Sendly, type SendlyConfig, SendlyError, type SendlyErrorCode, type Template, type TemplateListResponse, type TemplatePreview, type TemplateStatus, type TemplateVariable, TimeoutError, type UpdateCampaignRequest, type UpdateContactListRequest, type UpdateContactRequest, type UpdateTemplateRequest, type UpdateWebhookOptions, type ValidateSessionTokenRequest, type ValidateSessionTokenResponse, ValidationError, type Verification, type VerificationDeliveryStatus, type VerificationListResponse, type VerificationStatus, type VerifySession, type VerifySessionStatus, type Webhook, type WebhookCreatedResponse, type WebhookDelivery, type WebhookEvent, type WebhookEventType, type WebhookMessageData, type WebhookMessageStatus, type WebhookSecretRotation, WebhookSignatureError, type WebhookTestResult, Webhooks, calculateSegments, Sendly as default, generateWebhookSignature, getCountryFromPhone, isCountrySupported, parseWebhookEvent, validateMessageText, validatePhoneNumber, validateSenderId, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -268,6 +268,44 @@ var HttpClient = class {
268
268
  }
269
269
  throw lastError || new NetworkError("Request failed after retries");
270
270
  }
271
+ /**
272
+ * Make an HTTP request with a raw body (for multipart uploads)
273
+ */
274
+ async requestFormData(path, body, headers = {}) {
275
+ const url = this.buildUrl(path);
276
+ const baseHeaders = this.buildHeaders();
277
+ delete baseHeaders["Content-Type"];
278
+ const mergedHeaders = { ...baseHeaders, ...headers };
279
+ let lastError;
280
+ for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
281
+ try {
282
+ const response = await this.executeRequest(url, {
283
+ method: "POST",
284
+ headers: mergedHeaders,
285
+ body
286
+ });
287
+ this.updateRateLimitInfo(response.headers);
288
+ const data = await this.parseResponse(response);
289
+ return data;
290
+ } catch (error) {
291
+ lastError = error;
292
+ if (error instanceof SendlyError) {
293
+ if (error.statusCode === 401 || error.statusCode === 403 || error.statusCode === 400 || error.statusCode === 404 || error.statusCode === 402) {
294
+ throw error;
295
+ }
296
+ if (error instanceof RateLimitError) {
297
+ throw error;
298
+ }
299
+ }
300
+ if (attempt < this.config.maxRetries) {
301
+ const backoffTime = this.calculateBackoff(attempt);
302
+ await this.sleep(backoffTime);
303
+ continue;
304
+ }
305
+ }
306
+ }
307
+ throw lastError || new NetworkError("Request failed after retries");
308
+ }
271
309
  /**
272
310
  * Execute the HTTP request
273
311
  */
@@ -640,7 +678,8 @@ var MessagesResource = class {
640
678
  text: request.text,
641
679
  ...request.from && { from: request.from },
642
680
  ...request.messageType && { messageType: request.messageType },
643
- ...request.metadata && { metadata: request.metadata }
681
+ ...request.metadata && { metadata: request.metadata },
682
+ ...request.mediaUrls && { mediaUrls: request.mediaUrls }
644
683
  }
645
684
  });
646
685
  return message;
@@ -2757,6 +2796,43 @@ var ContactListsResource = class {
2757
2796
  }
2758
2797
  };
2759
2798
 
2799
+ // src/resources/media.ts
2800
+ var MediaResource = class {
2801
+ http;
2802
+ constructor(http) {
2803
+ this.http = http;
2804
+ }
2805
+ /**
2806
+ * Upload a media file for use in MMS messages
2807
+ *
2808
+ * @param file - File data as a Buffer or ReadableStream
2809
+ * @param options - Upload options (filename, content type)
2810
+ * @returns The uploaded media file with URL
2811
+ *
2812
+ * @example
2813
+ * ```typescript
2814
+ * const media = await sendly.media.upload(
2815
+ * fs.readFileSync('image.png'),
2816
+ * { filename: 'image.png', contentType: 'image/png' }
2817
+ * );
2818
+ *
2819
+ * console.log(media.url); // https://...
2820
+ * ```
2821
+ *
2822
+ * @throws {ValidationError} If the file is invalid or too large
2823
+ * @throws {AuthenticationError} If the API key is invalid
2824
+ * @throws {RateLimitError} If rate limit is exceeded
2825
+ */
2826
+ async upload(file, options) {
2827
+ const filename = options?.filename || "upload.jpg";
2828
+ const contentType = options?.contentType || "image/jpeg";
2829
+ const blob = file instanceof Buffer ? new Blob([file], { type: contentType }) : file;
2830
+ const form = new FormData();
2831
+ form.append("file", blob, filename);
2832
+ return this.http.requestFormData("/media", form);
2833
+ }
2834
+ };
2835
+
2760
2836
  // src/client.ts
2761
2837
  var DEFAULT_BASE_URL2 = "https://sendly.live/api/v1";
2762
2838
  var DEFAULT_TIMEOUT2 = 3e4;
@@ -2895,6 +2971,26 @@ var Sendly = class {
2895
2971
  * ```
2896
2972
  */
2897
2973
  contacts;
2974
+ /**
2975
+ * Media API resource - Upload media for MMS
2976
+ *
2977
+ * @example
2978
+ * ```typescript
2979
+ * // Upload a file
2980
+ * const media = await sendly.media.upload(fileBuffer, {
2981
+ * filename: 'photo.jpg',
2982
+ * contentType: 'image/jpeg'
2983
+ * });
2984
+ *
2985
+ * // Send as MMS
2986
+ * await sendly.messages.send({
2987
+ * to: '+15551234567',
2988
+ * text: 'Check this out!',
2989
+ * mediaUrls: [media.url]
2990
+ * });
2991
+ * ```
2992
+ */
2993
+ media;
2898
2994
  http;
2899
2995
  config;
2900
2996
  /**
@@ -2931,6 +3027,7 @@ var Sendly = class {
2931
3027
  this.templates = new TemplatesResource(this.http);
2932
3028
  this.campaigns = new CampaignsResource(this.http);
2933
3029
  this.contacts = new ContactsResource(this.http);
3030
+ this.media = new MediaResource(this.http);
2934
3031
  }
2935
3032
  /**
2936
3033
  * Check if the client is using a test API key
package/dist/index.mjs CHANGED
@@ -208,6 +208,44 @@ var HttpClient = class {
208
208
  }
209
209
  throw lastError || new NetworkError("Request failed after retries");
210
210
  }
211
+ /**
212
+ * Make an HTTP request with a raw body (for multipart uploads)
213
+ */
214
+ async requestFormData(path, body, headers = {}) {
215
+ const url = this.buildUrl(path);
216
+ const baseHeaders = this.buildHeaders();
217
+ delete baseHeaders["Content-Type"];
218
+ const mergedHeaders = { ...baseHeaders, ...headers };
219
+ let lastError;
220
+ for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
221
+ try {
222
+ const response = await this.executeRequest(url, {
223
+ method: "POST",
224
+ headers: mergedHeaders,
225
+ body
226
+ });
227
+ this.updateRateLimitInfo(response.headers);
228
+ const data = await this.parseResponse(response);
229
+ return data;
230
+ } catch (error) {
231
+ lastError = error;
232
+ if (error instanceof SendlyError) {
233
+ if (error.statusCode === 401 || error.statusCode === 403 || error.statusCode === 400 || error.statusCode === 404 || error.statusCode === 402) {
234
+ throw error;
235
+ }
236
+ if (error instanceof RateLimitError) {
237
+ throw error;
238
+ }
239
+ }
240
+ if (attempt < this.config.maxRetries) {
241
+ const backoffTime = this.calculateBackoff(attempt);
242
+ await this.sleep(backoffTime);
243
+ continue;
244
+ }
245
+ }
246
+ }
247
+ throw lastError || new NetworkError("Request failed after retries");
248
+ }
211
249
  /**
212
250
  * Execute the HTTP request
213
251
  */
@@ -580,7 +618,8 @@ var MessagesResource = class {
580
618
  text: request.text,
581
619
  ...request.from && { from: request.from },
582
620
  ...request.messageType && { messageType: request.messageType },
583
- ...request.metadata && { metadata: request.metadata }
621
+ ...request.metadata && { metadata: request.metadata },
622
+ ...request.mediaUrls && { mediaUrls: request.mediaUrls }
584
623
  }
585
624
  });
586
625
  return message;
@@ -2697,6 +2736,43 @@ var ContactListsResource = class {
2697
2736
  }
2698
2737
  };
2699
2738
 
2739
+ // src/resources/media.ts
2740
+ var MediaResource = class {
2741
+ http;
2742
+ constructor(http) {
2743
+ this.http = http;
2744
+ }
2745
+ /**
2746
+ * Upload a media file for use in MMS messages
2747
+ *
2748
+ * @param file - File data as a Buffer or ReadableStream
2749
+ * @param options - Upload options (filename, content type)
2750
+ * @returns The uploaded media file with URL
2751
+ *
2752
+ * @example
2753
+ * ```typescript
2754
+ * const media = await sendly.media.upload(
2755
+ * fs.readFileSync('image.png'),
2756
+ * { filename: 'image.png', contentType: 'image/png' }
2757
+ * );
2758
+ *
2759
+ * console.log(media.url); // https://...
2760
+ * ```
2761
+ *
2762
+ * @throws {ValidationError} If the file is invalid or too large
2763
+ * @throws {AuthenticationError} If the API key is invalid
2764
+ * @throws {RateLimitError} If rate limit is exceeded
2765
+ */
2766
+ async upload(file, options) {
2767
+ const filename = options?.filename || "upload.jpg";
2768
+ const contentType = options?.contentType || "image/jpeg";
2769
+ const blob = file instanceof Buffer ? new Blob([file], { type: contentType }) : file;
2770
+ const form = new FormData();
2771
+ form.append("file", blob, filename);
2772
+ return this.http.requestFormData("/media", form);
2773
+ }
2774
+ };
2775
+
2700
2776
  // src/client.ts
2701
2777
  var DEFAULT_BASE_URL2 = "https://sendly.live/api/v1";
2702
2778
  var DEFAULT_TIMEOUT2 = 3e4;
@@ -2835,6 +2911,26 @@ var Sendly = class {
2835
2911
  * ```
2836
2912
  */
2837
2913
  contacts;
2914
+ /**
2915
+ * Media API resource - Upload media for MMS
2916
+ *
2917
+ * @example
2918
+ * ```typescript
2919
+ * // Upload a file
2920
+ * const media = await sendly.media.upload(fileBuffer, {
2921
+ * filename: 'photo.jpg',
2922
+ * contentType: 'image/jpeg'
2923
+ * });
2924
+ *
2925
+ * // Send as MMS
2926
+ * await sendly.messages.send({
2927
+ * to: '+15551234567',
2928
+ * text: 'Check this out!',
2929
+ * mediaUrls: [media.url]
2930
+ * });
2931
+ * ```
2932
+ */
2933
+ media;
2838
2934
  http;
2839
2935
  config;
2840
2936
  /**
@@ -2871,6 +2967,7 @@ var Sendly = class {
2871
2967
  this.templates = new TemplatesResource(this.http);
2872
2968
  this.campaigns = new CampaignsResource(this.http);
2873
2969
  this.contacts = new ContactsResource(this.http);
2970
+ this.media = new MediaResource(this.http);
2874
2971
  }
2875
2972
  /**
2876
2973
  * Check if the client is using a test API key
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sendly/node",
3
- "version": "3.17.0",
3
+ "version": "3.18.0",
4
4
  "description": "Official Sendly Node.js SDK for SMS messaging",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",