@semboja/connect 0.1.0 → 0.1.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/dist/index.d.mts CHANGED
@@ -35,6 +35,18 @@ declare class HttpClient {
35
35
  * POST request
36
36
  */
37
37
  post<T>(path: string, body?: unknown): Promise<T>;
38
+ /**
39
+ * PUT request
40
+ */
41
+ put<T>(path: string, body?: unknown): Promise<T>;
42
+ /**
43
+ * PATCH request
44
+ */
45
+ patch<T>(path: string, body?: unknown): Promise<T>;
46
+ /**
47
+ * DELETE request
48
+ */
49
+ delete<T>(path: string): Promise<T>;
38
50
  }
39
51
 
40
52
  /**
@@ -236,6 +248,40 @@ interface PhoneNumber {
236
248
  verified_name: string;
237
249
  quality_rating?: string;
238
250
  }
251
+ /** Phone number profile from Meta Graph API */
252
+ interface MetaPhoneNumberInfo {
253
+ id: string;
254
+ verified_name: string;
255
+ display_phone_number: string;
256
+ quality_rating: "GREEN" | "YELLOW" | "RED" | "UNKNOWN";
257
+ code_verification_status: "VERIFIED" | "NOT_VERIFIED" | "EXPIRED";
258
+ is_official_business_account: boolean;
259
+ is_pin_enabled: boolean;
260
+ name_status: "APPROVED" | "PENDING" | "DECLINED" | "NONE";
261
+ new_name_status?: "APPROVED" | "PENDING" | "DECLINED" | "NONE";
262
+ messaging_limit_tier?: string;
263
+ platform_type?: string;
264
+ throughput?: {
265
+ level: string;
266
+ };
267
+ account_mode?: "LIVE" | "SANDBOX";
268
+ }
269
+ /** Business profile from Meta Graph API */
270
+ interface MetaBusinessProfile {
271
+ about?: string;
272
+ address?: string;
273
+ description?: string;
274
+ email?: string;
275
+ messaging_product: string;
276
+ profile_picture_url?: string;
277
+ vertical?: string;
278
+ websites?: string[];
279
+ }
280
+ /** Combined phone number profile response */
281
+ interface PhoneNumberProfile {
282
+ phone_number: MetaPhoneNumberInfo;
283
+ business_profile: MetaBusinessProfile;
284
+ }
239
285
  interface UsagePeriod {
240
286
  start: string;
241
287
  end: string;
@@ -469,6 +515,7 @@ declare class Templates {
469
515
  * @example
470
516
  * ```typescript
471
517
  * const phoneNumbers = await client.phoneNumbers.list();
518
+ * const profile = await client.phoneNumbers.getProfile('123456');
472
519
  * ```
473
520
  */
474
521
  declare class PhoneNumbers {
@@ -488,6 +535,60 @@ declare class PhoneNumbers {
488
535
  * ```
489
536
  */
490
537
  list(): Promise<ApiResponse<PhoneNumber[]>>;
538
+ /**
539
+ * Get a specific phone number by ID
540
+ *
541
+ * @param id - The phone number ID (from list response)
542
+ * @returns Phone number details
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * const phone = await client.phoneNumbers.get('phone-number-uuid');
547
+ * console.log(phone.data.display_phone_number);
548
+ * ```
549
+ */
550
+ get(id: string): Promise<ApiResponse<PhoneNumber>>;
551
+ /**
552
+ * Get phone number profile from Meta Graph API
553
+ *
554
+ * Returns detailed information including quality rating, verification status,
555
+ * messaging limits, and business profile.
556
+ *
557
+ * @param id - The phone number ID
558
+ * @returns Phone number profile with Meta API details
559
+ *
560
+ * @example
561
+ * ```typescript
562
+ * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');
563
+ * console.log('Quality:', profile.data.phone_number.quality_rating);
564
+ * console.log('Name:', profile.data.business_profile.about);
565
+ * ```
566
+ */
567
+ getProfile(id: string): Promise<ApiResponse<PhoneNumberProfile>>;
568
+ /**
569
+ * Update business profile for a phone number
570
+ *
571
+ * @param id - The phone number ID
572
+ * @param profile - Profile fields to update
573
+ * @returns Updated business profile
574
+ *
575
+ * @example
576
+ * ```typescript
577
+ * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {
578
+ * about: 'We help businesses grow',
579
+ * description: 'Customer support',
580
+ * email: 'support@example.com',
581
+ * });
582
+ * ```
583
+ */
584
+ updateProfile(id: string, profile: {
585
+ about?: string;
586
+ address?: string;
587
+ description?: string;
588
+ email?: string;
589
+ vertical?: string;
590
+ websites?: string[];
591
+ }): Promise<ApiResponse<PhoneNumberProfile['business_profile']>>;
491
592
  }
492
593
 
493
594
  /**
@@ -736,4 +837,36 @@ declare class NetworkError extends SembojaError {
736
837
  constructor(message: string);
737
838
  }
738
839
 
739
- export { type ApiErrorResponse, type ApiResponse, AuthenticationError, type ClientOptions, type InteractiveButton, type InteractiveListSection, type InteractiveMessage, type ListTemplatesOptions, type MediaObject, type MessageContact, type MessageResponseData, type MessageResult, type MessageType, NetworkError, NotFoundError, type PhoneNumber, RateLimitError, SembojaClient, SembojaError, type SendAudioOptions, type SendDocumentOptions, type SendImageOptions, type SendInteractiveOptions, type SendMessageOptions, type SendReactionOptions, type SendTemplateOptions, type SendTextOptions, type SendVideoOptions, ServerError, type Template, type TemplateComponent, type TemplateInfo, type TemplateLanguage, type TemplateParameter, type TemplateStatus, type TriggerWebhookOptions, type UsageData, type UsageMessages, type UsagePeriod, ValidationError, type VerifyWebhookOptions, parseWebhookPayload, verifyWebhookSignature };
840
+ /**
841
+ * @semboja/connect - Official Node.js SDK for Semboja WhatsApp API Bridge
842
+ *
843
+ * @example
844
+ * ```typescript
845
+ * // Using default import
846
+ * import Semboja from '@semboja/connect';
847
+ * const client = new Semboja('sk_live_your_api_key');
848
+ *
849
+ * // Or using named import
850
+ * import { SembojaClient, verifyWebhookSignature } from '@semboja/connect';
851
+ * const client = new SembojaClient('sk_live_your_api_key');
852
+ *
853
+ * // Send a text message
854
+ * await client.messages.sendText({
855
+ * phoneNumberId: '123456789',
856
+ * to: '+6281234567890',
857
+ * text: 'Hello from Semboja!',
858
+ * });
859
+ *
860
+ * // Verify webhook signature
861
+ * const isValid = verifyWebhookSignature({
862
+ * payload: req.body,
863
+ * signature: req.headers['x-semboja-signature'],
864
+ * timestamp: req.headers['x-semboja-timestamp'],
865
+ * secret: process.env.WEBHOOK_SECRET,
866
+ * });
867
+ * ```
868
+ *
869
+ * @packageDocumentation
870
+ */
871
+
872
+ export { type ApiErrorResponse, type ApiResponse, AuthenticationError, type ClientOptions, type InteractiveButton, type InteractiveListSection, type InteractiveMessage, type ListTemplatesOptions, type MediaObject, type MessageContact, type MessageResponseData, type MessageResult, type MessageType, type MetaBusinessProfile, type MetaPhoneNumberInfo, NetworkError, NotFoundError, type PhoneNumber, type PhoneNumberProfile, RateLimitError, SembojaClient, SembojaError, type SendAudioOptions, type SendDocumentOptions, type SendImageOptions, type SendInteractiveOptions, type SendMessageOptions, type SendReactionOptions, type SendTemplateOptions, type SendTextOptions, type SendVideoOptions, ServerError, type Template, type TemplateComponent, type TemplateInfo, type TemplateLanguage, type TemplateParameter, type TemplateStatus, type TriggerWebhookOptions, type UsageData, type UsageMessages, type UsagePeriod, ValidationError, type VerifyWebhookOptions, SembojaClient as default, parseWebhookPayload, verifyWebhookSignature };
package/dist/index.d.ts CHANGED
@@ -35,6 +35,18 @@ declare class HttpClient {
35
35
  * POST request
36
36
  */
37
37
  post<T>(path: string, body?: unknown): Promise<T>;
38
+ /**
39
+ * PUT request
40
+ */
41
+ put<T>(path: string, body?: unknown): Promise<T>;
42
+ /**
43
+ * PATCH request
44
+ */
45
+ patch<T>(path: string, body?: unknown): Promise<T>;
46
+ /**
47
+ * DELETE request
48
+ */
49
+ delete<T>(path: string): Promise<T>;
38
50
  }
39
51
 
40
52
  /**
@@ -236,6 +248,40 @@ interface PhoneNumber {
236
248
  verified_name: string;
237
249
  quality_rating?: string;
238
250
  }
251
+ /** Phone number profile from Meta Graph API */
252
+ interface MetaPhoneNumberInfo {
253
+ id: string;
254
+ verified_name: string;
255
+ display_phone_number: string;
256
+ quality_rating: "GREEN" | "YELLOW" | "RED" | "UNKNOWN";
257
+ code_verification_status: "VERIFIED" | "NOT_VERIFIED" | "EXPIRED";
258
+ is_official_business_account: boolean;
259
+ is_pin_enabled: boolean;
260
+ name_status: "APPROVED" | "PENDING" | "DECLINED" | "NONE";
261
+ new_name_status?: "APPROVED" | "PENDING" | "DECLINED" | "NONE";
262
+ messaging_limit_tier?: string;
263
+ platform_type?: string;
264
+ throughput?: {
265
+ level: string;
266
+ };
267
+ account_mode?: "LIVE" | "SANDBOX";
268
+ }
269
+ /** Business profile from Meta Graph API */
270
+ interface MetaBusinessProfile {
271
+ about?: string;
272
+ address?: string;
273
+ description?: string;
274
+ email?: string;
275
+ messaging_product: string;
276
+ profile_picture_url?: string;
277
+ vertical?: string;
278
+ websites?: string[];
279
+ }
280
+ /** Combined phone number profile response */
281
+ interface PhoneNumberProfile {
282
+ phone_number: MetaPhoneNumberInfo;
283
+ business_profile: MetaBusinessProfile;
284
+ }
239
285
  interface UsagePeriod {
240
286
  start: string;
241
287
  end: string;
@@ -469,6 +515,7 @@ declare class Templates {
469
515
  * @example
470
516
  * ```typescript
471
517
  * const phoneNumbers = await client.phoneNumbers.list();
518
+ * const profile = await client.phoneNumbers.getProfile('123456');
472
519
  * ```
473
520
  */
474
521
  declare class PhoneNumbers {
@@ -488,6 +535,60 @@ declare class PhoneNumbers {
488
535
  * ```
489
536
  */
490
537
  list(): Promise<ApiResponse<PhoneNumber[]>>;
538
+ /**
539
+ * Get a specific phone number by ID
540
+ *
541
+ * @param id - The phone number ID (from list response)
542
+ * @returns Phone number details
543
+ *
544
+ * @example
545
+ * ```typescript
546
+ * const phone = await client.phoneNumbers.get('phone-number-uuid');
547
+ * console.log(phone.data.display_phone_number);
548
+ * ```
549
+ */
550
+ get(id: string): Promise<ApiResponse<PhoneNumber>>;
551
+ /**
552
+ * Get phone number profile from Meta Graph API
553
+ *
554
+ * Returns detailed information including quality rating, verification status,
555
+ * messaging limits, and business profile.
556
+ *
557
+ * @param id - The phone number ID
558
+ * @returns Phone number profile with Meta API details
559
+ *
560
+ * @example
561
+ * ```typescript
562
+ * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');
563
+ * console.log('Quality:', profile.data.phone_number.quality_rating);
564
+ * console.log('Name:', profile.data.business_profile.about);
565
+ * ```
566
+ */
567
+ getProfile(id: string): Promise<ApiResponse<PhoneNumberProfile>>;
568
+ /**
569
+ * Update business profile for a phone number
570
+ *
571
+ * @param id - The phone number ID
572
+ * @param profile - Profile fields to update
573
+ * @returns Updated business profile
574
+ *
575
+ * @example
576
+ * ```typescript
577
+ * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {
578
+ * about: 'We help businesses grow',
579
+ * description: 'Customer support',
580
+ * email: 'support@example.com',
581
+ * });
582
+ * ```
583
+ */
584
+ updateProfile(id: string, profile: {
585
+ about?: string;
586
+ address?: string;
587
+ description?: string;
588
+ email?: string;
589
+ vertical?: string;
590
+ websites?: string[];
591
+ }): Promise<ApiResponse<PhoneNumberProfile['business_profile']>>;
491
592
  }
492
593
 
493
594
  /**
@@ -736,4 +837,36 @@ declare class NetworkError extends SembojaError {
736
837
  constructor(message: string);
737
838
  }
738
839
 
739
- export { type ApiErrorResponse, type ApiResponse, AuthenticationError, type ClientOptions, type InteractiveButton, type InteractiveListSection, type InteractiveMessage, type ListTemplatesOptions, type MediaObject, type MessageContact, type MessageResponseData, type MessageResult, type MessageType, NetworkError, NotFoundError, type PhoneNumber, RateLimitError, SembojaClient, SembojaError, type SendAudioOptions, type SendDocumentOptions, type SendImageOptions, type SendInteractiveOptions, type SendMessageOptions, type SendReactionOptions, type SendTemplateOptions, type SendTextOptions, type SendVideoOptions, ServerError, type Template, type TemplateComponent, type TemplateInfo, type TemplateLanguage, type TemplateParameter, type TemplateStatus, type TriggerWebhookOptions, type UsageData, type UsageMessages, type UsagePeriod, ValidationError, type VerifyWebhookOptions, parseWebhookPayload, verifyWebhookSignature };
840
+ /**
841
+ * @semboja/connect - Official Node.js SDK for Semboja WhatsApp API Bridge
842
+ *
843
+ * @example
844
+ * ```typescript
845
+ * // Using default import
846
+ * import Semboja from '@semboja/connect';
847
+ * const client = new Semboja('sk_live_your_api_key');
848
+ *
849
+ * // Or using named import
850
+ * import { SembojaClient, verifyWebhookSignature } from '@semboja/connect';
851
+ * const client = new SembojaClient('sk_live_your_api_key');
852
+ *
853
+ * // Send a text message
854
+ * await client.messages.sendText({
855
+ * phoneNumberId: '123456789',
856
+ * to: '+6281234567890',
857
+ * text: 'Hello from Semboja!',
858
+ * });
859
+ *
860
+ * // Verify webhook signature
861
+ * const isValid = verifyWebhookSignature({
862
+ * payload: req.body,
863
+ * signature: req.headers['x-semboja-signature'],
864
+ * timestamp: req.headers['x-semboja-timestamp'],
865
+ * secret: process.env.WEBHOOK_SECRET,
866
+ * });
867
+ * ```
868
+ *
869
+ * @packageDocumentation
870
+ */
871
+
872
+ export { type ApiErrorResponse, type ApiResponse, AuthenticationError, type ClientOptions, type InteractiveButton, type InteractiveListSection, type InteractiveMessage, type ListTemplatesOptions, type MediaObject, type MessageContact, type MessageResponseData, type MessageResult, type MessageType, type MetaBusinessProfile, type MetaPhoneNumberInfo, NetworkError, NotFoundError, type PhoneNumber, type PhoneNumberProfile, RateLimitError, SembojaClient, SembojaError, type SendAudioOptions, type SendDocumentOptions, type SendImageOptions, type SendInteractiveOptions, type SendMessageOptions, type SendReactionOptions, type SendTemplateOptions, type SendTextOptions, type SendVideoOptions, ServerError, type Template, type TemplateComponent, type TemplateInfo, type TemplateLanguage, type TemplateParameter, type TemplateStatus, type TriggerWebhookOptions, type UsageData, type UsageMessages, type UsagePeriod, ValidationError, type VerifyWebhookOptions, SembojaClient as default, parseWebhookPayload, verifyWebhookSignature };
package/dist/index.js CHANGED
@@ -28,6 +28,7 @@ __export(index_exports, {
28
28
  SembojaError: () => SembojaError,
29
29
  ServerError: () => ServerError,
30
30
  ValidationError: () => ValidationError,
31
+ default: () => index_default,
31
32
  parseWebhookPayload: () => parseWebhookPayload,
32
33
  verifyWebhookSignature: () => verifyWebhookSignature
33
34
  });
@@ -199,6 +200,24 @@ var HttpClient = class {
199
200
  async post(path, body) {
200
201
  return this.request({ method: "POST", path, body });
201
202
  }
203
+ /**
204
+ * PUT request
205
+ */
206
+ async put(path, body) {
207
+ return this.request({ method: "PUT", path, body });
208
+ }
209
+ /**
210
+ * PATCH request
211
+ */
212
+ async patch(path, body) {
213
+ return this.request({ method: "PATCH", path, body });
214
+ }
215
+ /**
216
+ * DELETE request
217
+ */
218
+ async delete(path) {
219
+ return this.request({ method: "DELETE", path });
220
+ }
202
221
  };
203
222
 
204
223
  // src/resources/messages.ts
@@ -468,6 +487,59 @@ var PhoneNumbers = class {
468
487
  async list() {
469
488
  return this.http.get("/api/v1/phone-numbers");
470
489
  }
490
+ /**
491
+ * Get a specific phone number by ID
492
+ *
493
+ * @param id - The phone number ID (from list response)
494
+ * @returns Phone number details
495
+ *
496
+ * @example
497
+ * ```typescript
498
+ * const phone = await client.phoneNumbers.get('phone-number-uuid');
499
+ * console.log(phone.data.display_phone_number);
500
+ * ```
501
+ */
502
+ async get(id) {
503
+ return this.http.get(`/api/v1/phone-numbers/${id}`);
504
+ }
505
+ /**
506
+ * Get phone number profile from Meta Graph API
507
+ *
508
+ * Returns detailed information including quality rating, verification status,
509
+ * messaging limits, and business profile.
510
+ *
511
+ * @param id - The phone number ID
512
+ * @returns Phone number profile with Meta API details
513
+ *
514
+ * @example
515
+ * ```typescript
516
+ * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');
517
+ * console.log('Quality:', profile.data.phone_number.quality_rating);
518
+ * console.log('Name:', profile.data.business_profile.about);
519
+ * ```
520
+ */
521
+ async getProfile(id) {
522
+ return this.http.get(`/api/v1/phone-numbers/${id}/profile`);
523
+ }
524
+ /**
525
+ * Update business profile for a phone number
526
+ *
527
+ * @param id - The phone number ID
528
+ * @param profile - Profile fields to update
529
+ * @returns Updated business profile
530
+ *
531
+ * @example
532
+ * ```typescript
533
+ * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {
534
+ * about: 'We help businesses grow',
535
+ * description: 'Customer support',
536
+ * email: 'support@example.com',
537
+ * });
538
+ * ```
539
+ */
540
+ async updateProfile(id, profile) {
541
+ return this.http.patch(`/api/v1/phone-numbers/${id}/profile`, profile);
542
+ }
471
543
  };
472
544
 
473
545
  // src/resources/usage.ts
@@ -619,6 +691,9 @@ function parseWebhookPayload(payload) {
619
691
  }
620
692
  return payload;
621
693
  }
694
+
695
+ // src/index.ts
696
+ var index_default = SembojaClient;
622
697
  // Annotate the CommonJS export names for ESM import in node:
623
698
  0 && (module.exports = {
624
699
  AuthenticationError,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/lib/http.ts","../src/resources/messages.ts","../src/resources/templates.ts","../src/resources/phone-numbers.ts","../src/resources/usage.ts","../src/resources/test.ts","../src/client.ts","../src/webhooks/verify.ts"],"sourcesContent":["/**\n * @semboja/connect - Official Node.js SDK for Semboja WhatsApp API Bridge\n * \n * @example\n * ```typescript\n * import { SembojaClient, verifyWebhookSignature } from '@semboja/connect';\n * \n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // Send a text message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * \n * // Verify webhook signature\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'],\n * timestamp: req.headers['x-semboja-timestamp'],\n * secret: process.env.WEBHOOK_SECRET,\n * });\n * ```\n * \n * @packageDocumentation\n */\n\n// Main client\nexport { SembojaClient } from './client';\n\n// Webhook utilities\nexport { verifyWebhookSignature, parseWebhookPayload } from './webhooks/verify';\n\n// Error classes\nexport {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from './errors';\n\n// Types\nexport type {\n // Client\n ClientOptions,\n ApiResponse,\n ApiErrorResponse,\n \n // Messages\n MessageType,\n SendMessageOptions,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n Template,\n TemplateLanguage,\n TemplateComponent,\n TemplateParameter,\n MediaObject,\n InteractiveMessage,\n InteractiveButton,\n InteractiveListSection,\n MessageResponseData,\n MessageContact,\n MessageResult,\n \n // Templates\n TemplateStatus,\n TemplateInfo,\n ListTemplatesOptions,\n \n // Phone Numbers\n PhoneNumber,\n \n // Usage\n UsageData,\n UsagePeriod,\n UsageMessages,\n \n // Test\n TriggerWebhookOptions,\n \n // Webhooks\n VerifyWebhookOptions,\n} from './types';\n","/**\n * Base error class for all Semboja API errors\n */\nexport class SembojaError extends Error {\n /** Error code from the API */\n readonly code: string;\n /** HTTP status code */\n readonly statusCode: number;\n /** Request ID for debugging */\n readonly requestId?: string;\n\n constructor(\n message: string,\n code: string,\n statusCode: number,\n requestId?: string\n ) {\n super(message);\n this.name = 'SembojaError';\n this.code = code;\n this.statusCode = statusCode;\n this.requestId = requestId;\n Object.setPrototypeOf(this, SembojaError.prototype);\n }\n}\n\n/**\n * Authentication error (invalid or missing API key)\n */\nexport class AuthenticationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INVALID_API_KEY', 401, requestId);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Rate limit exceeded error\n */\nexport class RateLimitError extends SembojaError {\n /** When the rate limit resets (Unix timestamp) */\n readonly resetAt?: number;\n\n constructor(message: string, requestId?: string, resetAt?: number) {\n super(message, 'RATE_LIMITED', 429, requestId);\n this.name = 'RateLimitError';\n this.resetAt = resetAt;\n Object.setPrototypeOf(this, RateLimitError.prototype);\n }\n}\n\n/**\n * Validation error (invalid request parameters)\n */\nexport class ValidationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'VALIDATION_ERROR', 400, requestId);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Resource not found error\n */\nexport class NotFoundError extends SembojaError {\n constructor(message: string, code: string, requestId?: string) {\n super(message, code, 404, requestId);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n\n/**\n * Server error from Semboja API\n */\nexport class ServerError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INTERNAL_ERROR', 500, requestId);\n this.name = 'ServerError';\n Object.setPrototypeOf(this, ServerError.prototype);\n }\n}\n\n/**\n * Network or connection error\n */\nexport class NetworkError extends SembojaError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR', 0);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n","import {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from '../errors';\nimport type { ApiErrorResponse } from '../types';\n\nexport interface HttpClientOptions {\n baseUrl: string;\n apiKey: string;\n timeout: number;\n retries: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate exponential backoff delay\n */\nfunction getBackoffDelay(attempt: number, baseDelay = 1000): number {\n return Math.min(baseDelay * Math.pow(2, attempt), 30000);\n}\n\n/**\n * HTTP client for making API requests\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.timeout = options.timeout;\n this.retries = options.retries;\n }\n\n /**\n * Make an HTTP request with retry logic\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n ...options.headers,\n };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = await response.json();\n\n // Handle errors\n if (!response.ok) {\n throw this.parseError(response.status, data as ApiErrorResponse);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except rate limits\n if (error instanceof SembojaError) {\n if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {\n throw error;\n }\n }\n\n // Don't retry on abort (timeout)\n if (error instanceof Error && error.name === 'AbortError') {\n throw new NetworkError(`Request timeout after ${this.timeout}ms`);\n }\n\n // Retry on network errors and rate limits\n if (attempt < this.retries) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n }\n }\n\n // If we get here, all retries failed\n if (lastError instanceof SembojaError) {\n throw lastError;\n }\n throw new NetworkError(lastError?.message || 'Request failed');\n }\n\n /**\n * Parse error response into appropriate error class\n */\n private parseError(statusCode: number, data: ApiErrorResponse): SembojaError {\n const message = data.error?.message || 'Unknown error';\n const code = data.error?.code || 'UNKNOWN_ERROR';\n const requestId = data.meta?.request_id;\n\n switch (statusCode) {\n case 401:\n return new AuthenticationError(message, requestId);\n case 429:\n return new RateLimitError(message, requestId);\n case 400:\n return new ValidationError(message, requestId);\n case 404:\n return new NotFoundError(message, code, requestId);\n case 500:\n case 502:\n case 503:\n return new ServerError(message, requestId);\n default:\n return new SembojaError(message, code, statusCode, requestId);\n }\n }\n\n /**\n * GET request\n */\n async get<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'GET', path });\n }\n\n /**\n * POST request\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'POST', path, body });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type {\n ApiResponse,\n MessageResponseData,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n} from '../types';\n\n/**\n * Messages API resource\n * \n * @example\n * ```typescript\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class Messages {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Send a text message\n * \n * @param options - Text message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello, World!',\n * previewUrl: true,\n * });\n * console.log('Message ID:', result.data.messages[0].id);\n * ```\n */\n async sendText(options: SendTextOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/text', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n text: options.text,\n preview_url: options.previewUrl,\n reply_to: options.replyTo,\n });\n }\n\n /**\n * Send a template message\n * \n * @param options - Template message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendTemplate({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * template: {\n * name: 'hello_world',\n * language: { code: 'en' },\n * },\n * });\n * ```\n */\n async sendTemplate(options: SendTemplateOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/template', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n template: options.template,\n });\n }\n\n /**\n * Send an image message\n * \n * @param options - Image message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendImage({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * image: {\n * link: 'https://example.com/image.jpg',\n * caption: 'Check this out!',\n * },\n * });\n * ```\n */\n async sendImage(options: SendImageOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'image',\n image: options.image,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a video message\n * \n * @param options - Video message options\n * @returns Message response with message ID\n */\n async sendVideo(options: SendVideoOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'video',\n video: options.video,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send an audio message\n * \n * @param options - Audio message options\n * @returns Message response with message ID\n */\n async sendAudio(options: SendAudioOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'audio',\n audio: options.audio,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a document message\n * \n * @param options - Document message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendDocument({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * document: {\n * link: 'https://example.com/invoice.pdf',\n * filename: 'invoice.pdf',\n * caption: 'Your invoice',\n * },\n * });\n * ```\n */\n async sendDocument(options: SendDocumentOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'document',\n document: options.document,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a reaction to a message\n * \n * @param options - Reaction options\n * @returns Message response\n * \n * @example\n * ```typescript\n * // Add reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '👍',\n * },\n * });\n * \n * // Remove reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '',\n * },\n * });\n * ```\n */\n async sendReaction(options: SendReactionOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'reaction',\n reaction: {\n message_id: options.reaction.messageId,\n emoji: options.reaction.emoji,\n },\n });\n }\n\n /**\n * Send an interactive message (buttons, lists, etc.)\n * \n * @param options - Interactive message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * // Button message\n * await client.messages.sendInteractive({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * interactive: {\n * type: 'button',\n * body: { text: 'Choose an option:' },\n * action: {\n * buttons: [\n * { type: 'reply', reply: { id: 'yes', title: 'Yes' } },\n * { type: 'reply', reply: { id: 'no', title: 'No' } },\n * ],\n * },\n * },\n * });\n * ```\n */\n async sendInteractive(options: SendInteractiveOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'interactive',\n interactive: options.interactive,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TemplateInfo, ListTemplatesOptions } from '../types';\n\n/**\n * Templates API resource\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all message templates\n * \n * @param options - Optional filters\n * @returns List of templates\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * console.log('Templates:', templates.data);\n * \n * // Filter by status\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\n async list(options?: ListTemplatesOptions): Promise<ApiResponse<TemplateInfo[]>> {\n let path = '/api/v1/templates';\n \n if (options?.status) {\n path += `?status=${encodeURIComponent(options.status)}`;\n }\n \n return this.http.get(path);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, PhoneNumber } from '../types';\n\n/**\n * Phone Numbers API resource\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * ```\n */\nexport class PhoneNumbers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all phone numbers configured for your account\n * \n * @returns List of phone numbers\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * for (const phone of phoneNumbers.data) {\n * console.log(`${phone.verified_name}: ${phone.display_phone_number}`);\n * }\n * ```\n */\n async list(): Promise<ApiResponse<PhoneNumber[]>> {\n return this.http.get('/api/v1/phone-numbers');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, UsageData } from '../types';\n\n/**\n * Usage API resource\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Sent: ${usage.data.messages.sent}`);\n * ```\n */\nexport class Usage {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get current usage statistics for the billing period\n * \n * @returns Usage statistics\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);\n * console.log(`Messages sent: ${usage.data.messages.sent}`);\n * console.log(`Messages received: ${usage.data.messages.received}`);\n * console.log(`API calls: ${usage.data.api_calls}`);\n * ```\n */\n async get(): Promise<ApiResponse<UsageData>> {\n return this.http.get('/api/v1/usage');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TriggerWebhookOptions } from '../types';\n\n/**\n * Test API resource (only works with sk_test_* keys)\n * \n * @example\n * ```typescript\n * // Trigger a test webhook\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Test message',\n * });\n * ```\n */\nexport class Test {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Trigger a test webhook to simulate an incoming message\n * \n * **Note:** This only works with test API keys (sk_test_*)\n * \n * @param options - Webhook trigger options\n * @returns Success response\n * \n * @example\n * ```typescript\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Hello, this is a test incoming message!',\n * });\n * ```\n */\n async triggerWebhook(options: TriggerWebhookOptions): Promise<ApiResponse<{ queued: boolean }>> {\n return this.http.post('/api/v1/test/webhooks/trigger', {\n phone_number_id: options.phoneNumberId,\n type: options.type || 'text',\n from: options.from,\n text: options.text,\n });\n }\n}\n","import { HttpClient } from './lib/http';\nimport { Messages } from './resources/messages';\nimport { Templates } from './resources/templates';\nimport { PhoneNumbers } from './resources/phone-numbers';\nimport { Usage } from './resources/usage';\nimport { Test } from './resources/test';\nimport type { ClientOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://connect.semboja.tech';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Semboja WhatsApp API Client\n * \n * @example\n * ```typescript\n * import { SembojaClient } from '@semboja/connect';\n * \n * // Simple initialization\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // With options\n * const client = new SembojaClient({\n * apiKey: process.env.SEMBOJA_API_KEY!,\n * timeout: 60000,\n * retries: 5,\n * });\n * \n * // Send a message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class SembojaClient {\n /** Messages API */\n readonly messages: Messages;\n \n /** Templates API */\n readonly templates: Templates;\n \n /** Phone Numbers API */\n readonly phoneNumbers: PhoneNumbers;\n \n /** Usage API */\n readonly usage: Usage;\n \n /** Test API (only works with sk_test_* keys) */\n readonly test: Test;\n\n /** Whether the client is in test mode */\n readonly isTestMode: boolean;\n\n private readonly http: HttpClient;\n\n /**\n * Create a new Semboja client\n * \n * @param optionsOrApiKey - API key string or client options object\n * \n * @example\n * ```typescript\n * // Using API key directly\n * const client = new SembojaClient('sk_live_xxx');\n * \n * // Using options object\n * const client = new SembojaClient({\n * apiKey: 'sk_live_xxx',\n * timeout: 60000,\n * retries: 5,\n * });\n * ```\n */\n constructor(optionsOrApiKey: string | ClientOptions) {\n const options: ClientOptions = typeof optionsOrApiKey === 'string'\n ? { apiKey: optionsOrApiKey }\n : optionsOrApiKey;\n\n // Validate API key\n if (!options.apiKey) {\n throw new Error('API key is required');\n }\n\n if (!options.apiKey.startsWith('sk_live_') && !options.apiKey.startsWith('sk_test_')) {\n throw new Error('Invalid API key format. Must start with sk_live_ or sk_test_');\n }\n\n // Determine if test mode\n this.isTestMode = options.apiKey.startsWith('sk_test_');\n\n // Create HTTP client\n this.http = new HttpClient({\n baseUrl: options.baseUrl || DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeout: options.timeout || DEFAULT_TIMEOUT,\n retries: options.retries ?? DEFAULT_RETRIES,\n });\n\n // Initialize resources\n this.messages = new Messages(this.http);\n this.templates = new Templates(this.http);\n this.phoneNumbers = new PhoneNumbers(this.http);\n this.usage = new Usage(this.http);\n this.test = new Test(this.http);\n }\n}\n","import { createHmac, timingSafeEqual } from 'crypto';\nimport type { VerifyWebhookOptions } from '../types';\n\n/**\n * Verify a webhook signature from Semboja\n * \n * @param options - Verification options\n * @returns true if the signature is valid, false otherwise\n * \n * @example\n * ```typescript\n * import { verifyWebhookSignature } from '@semboja/connect';\n * \n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'] as string,\n * timestamp: req.headers['x-semboja-timestamp'] as string,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return res.status(401).send('Invalid signature');\n * }\n * \n * // Process the webhook\n * const event = JSON.parse(req.body.toString());\n * console.log('Received event:', event);\n * \n * res.status(200).send('OK');\n * });\n * ```\n * \n * @example\n * ```typescript\n * // Hono example\n * app.post('/webhook', async (c) => {\n * const body = await c.req.text();\n * const signature = c.req.header('x-semboja-signature');\n * const timestamp = c.req.header('x-semboja-timestamp');\n * \n * const isValid = verifyWebhookSignature({\n * payload: body,\n * signature: signature!,\n * timestamp: timestamp!,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return c.text('Invalid signature', 401);\n * }\n * \n * const event = JSON.parse(body);\n * // Process the webhook...\n * \n * return c.text('OK');\n * });\n * ```\n */\nexport function verifyWebhookSignature(options: VerifyWebhookOptions): boolean {\n const { payload, signature, timestamp, secret } = options;\n\n // Validate inputs\n if (!payload || !signature || !timestamp || !secret) {\n return false;\n }\n\n // Check timestamp to prevent replay attacks (5 minute tolerance)\n const timestampNum = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n const tolerance = 5 * 60; // 5 minutes\n\n if (isNaN(timestampNum) || Math.abs(now - timestampNum) > tolerance) {\n return false;\n }\n\n // Stringify payload if it's an object\n const payloadString = typeof payload === 'string' \n ? payload \n : JSON.stringify(payload);\n\n // Compute expected signature\n const signatureData = timestamp + payloadString;\n const expectedSignature = 'sha256=' + createHmac('sha256', secret)\n .update(signatureData)\n .digest('hex');\n\n // Compare signatures using timing-safe comparison\n try {\n const sigBuffer = Buffer.from(signature);\n const expectedBuffer = Buffer.from(expectedSignature);\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(sigBuffer, expectedBuffer);\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a webhook payload into a typed event object\n * \n * @param payload - Raw webhook payload (string or object)\n * @returns Parsed webhook event\n */\nexport function parseWebhookPayload<T = unknown>(payload: string | object): T {\n if (typeof payload === 'string') {\n return JSON.parse(payload) as T;\n }\n return payload as T;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/errors.ts","../src/lib/http.ts","../src/resources/messages.ts","../src/resources/templates.ts","../src/resources/phone-numbers.ts","../src/resources/usage.ts","../src/resources/test.ts","../src/client.ts","../src/webhooks/verify.ts"],"sourcesContent":["/**\n * @semboja/connect - Official Node.js SDK for Semboja WhatsApp API Bridge\n * \n * @example\n * ```typescript\n * // Using default import\n * import Semboja from '@semboja/connect';\n * const client = new Semboja('sk_live_your_api_key');\n * \n * // Or using named import\n * import { SembojaClient, verifyWebhookSignature } from '@semboja/connect';\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // Send a text message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * \n * // Verify webhook signature\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'],\n * timestamp: req.headers['x-semboja-timestamp'],\n * secret: process.env.WEBHOOK_SECRET,\n * });\n * ```\n * \n * @packageDocumentation\n */\n\n// Main client\nexport { SembojaClient } from './client';\n\n// Default export for convenience\nimport { SembojaClient as Client } from './client';\nexport default Client;\n\n// Webhook utilities\nexport { verifyWebhookSignature, parseWebhookPayload } from './webhooks/verify';\n\n// Error classes\nexport {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from './errors';\n\n// Types\nexport type {\n // Client\n ClientOptions,\n ApiResponse,\n ApiErrorResponse,\n \n // Messages\n MessageType,\n SendMessageOptions,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n Template,\n TemplateLanguage,\n TemplateComponent,\n TemplateParameter,\n MediaObject,\n InteractiveMessage,\n InteractiveButton,\n InteractiveListSection,\n MessageResponseData,\n MessageContact,\n MessageResult,\n \n // Templates\n TemplateStatus,\n TemplateInfo,\n ListTemplatesOptions,\n \n // Phone Numbers\n PhoneNumber,\n PhoneNumberProfile,\n MetaPhoneNumberInfo,\n MetaBusinessProfile,\n \n // Usage\n UsageData,\n UsagePeriod,\n UsageMessages,\n \n // Test\n TriggerWebhookOptions,\n \n // Webhooks\n VerifyWebhookOptions,\n} from './types';\n","/**\n * Base error class for all Semboja API errors\n */\nexport class SembojaError extends Error {\n /** Error code from the API */\n readonly code: string;\n /** HTTP status code */\n readonly statusCode: number;\n /** Request ID for debugging */\n readonly requestId?: string;\n\n constructor(\n message: string,\n code: string,\n statusCode: number,\n requestId?: string\n ) {\n super(message);\n this.name = 'SembojaError';\n this.code = code;\n this.statusCode = statusCode;\n this.requestId = requestId;\n Object.setPrototypeOf(this, SembojaError.prototype);\n }\n}\n\n/**\n * Authentication error (invalid or missing API key)\n */\nexport class AuthenticationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INVALID_API_KEY', 401, requestId);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Rate limit exceeded error\n */\nexport class RateLimitError extends SembojaError {\n /** When the rate limit resets (Unix timestamp) */\n readonly resetAt?: number;\n\n constructor(message: string, requestId?: string, resetAt?: number) {\n super(message, 'RATE_LIMITED', 429, requestId);\n this.name = 'RateLimitError';\n this.resetAt = resetAt;\n Object.setPrototypeOf(this, RateLimitError.prototype);\n }\n}\n\n/**\n * Validation error (invalid request parameters)\n */\nexport class ValidationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'VALIDATION_ERROR', 400, requestId);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Resource not found error\n */\nexport class NotFoundError extends SembojaError {\n constructor(message: string, code: string, requestId?: string) {\n super(message, code, 404, requestId);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n\n/**\n * Server error from Semboja API\n */\nexport class ServerError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INTERNAL_ERROR', 500, requestId);\n this.name = 'ServerError';\n Object.setPrototypeOf(this, ServerError.prototype);\n }\n}\n\n/**\n * Network or connection error\n */\nexport class NetworkError extends SembojaError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR', 0);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n","import {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from '../errors';\nimport type { ApiErrorResponse } from '../types';\n\nexport interface HttpClientOptions {\n baseUrl: string;\n apiKey: string;\n timeout: number;\n retries: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate exponential backoff delay\n */\nfunction getBackoffDelay(attempt: number, baseDelay = 1000): number {\n return Math.min(baseDelay * Math.pow(2, attempt), 30000);\n}\n\n/**\n * HTTP client for making API requests\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.timeout = options.timeout;\n this.retries = options.retries;\n }\n\n /**\n * Make an HTTP request with retry logic\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n ...options.headers,\n };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = await response.json();\n\n // Handle errors\n if (!response.ok) {\n throw this.parseError(response.status, data as ApiErrorResponse);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except rate limits\n if (error instanceof SembojaError) {\n if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {\n throw error;\n }\n }\n\n // Don't retry on abort (timeout)\n if (error instanceof Error && error.name === 'AbortError') {\n throw new NetworkError(`Request timeout after ${this.timeout}ms`);\n }\n\n // Retry on network errors and rate limits\n if (attempt < this.retries) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n }\n }\n\n // If we get here, all retries failed\n if (lastError instanceof SembojaError) {\n throw lastError;\n }\n throw new NetworkError(lastError?.message || 'Request failed');\n }\n\n /**\n * Parse error response into appropriate error class\n */\n private parseError(statusCode: number, data: ApiErrorResponse): SembojaError {\n const message = data.error?.message || 'Unknown error';\n const code = data.error?.code || 'UNKNOWN_ERROR';\n const requestId = data.meta?.request_id;\n\n switch (statusCode) {\n case 401:\n return new AuthenticationError(message, requestId);\n case 429:\n return new RateLimitError(message, requestId);\n case 400:\n return new ValidationError(message, requestId);\n case 404:\n return new NotFoundError(message, code, requestId);\n case 500:\n case 502:\n case 503:\n return new ServerError(message, requestId);\n default:\n return new SembojaError(message, code, statusCode, requestId);\n }\n }\n\n /**\n * GET request\n */\n async get<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'GET', path });\n }\n\n /**\n * POST request\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'POST', path, body });\n }\n\n /**\n * PUT request\n */\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'PUT', path, body });\n }\n\n /**\n * PATCH request\n */\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'PATCH', path, body });\n }\n\n /**\n * DELETE request\n */\n async delete<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'DELETE', path });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type {\n ApiResponse,\n MessageResponseData,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n} from '../types';\n\n/**\n * Messages API resource\n * \n * @example\n * ```typescript\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class Messages {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Send a text message\n * \n * @param options - Text message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello, World!',\n * previewUrl: true,\n * });\n * console.log('Message ID:', result.data.messages[0].id);\n * ```\n */\n async sendText(options: SendTextOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/text', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n text: options.text,\n preview_url: options.previewUrl,\n reply_to: options.replyTo,\n });\n }\n\n /**\n * Send a template message\n * \n * @param options - Template message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendTemplate({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * template: {\n * name: 'hello_world',\n * language: { code: 'en' },\n * },\n * });\n * ```\n */\n async sendTemplate(options: SendTemplateOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/template', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n template: options.template,\n });\n }\n\n /**\n * Send an image message\n * \n * @param options - Image message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendImage({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * image: {\n * link: 'https://example.com/image.jpg',\n * caption: 'Check this out!',\n * },\n * });\n * ```\n */\n async sendImage(options: SendImageOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'image',\n image: options.image,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a video message\n * \n * @param options - Video message options\n * @returns Message response with message ID\n */\n async sendVideo(options: SendVideoOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'video',\n video: options.video,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send an audio message\n * \n * @param options - Audio message options\n * @returns Message response with message ID\n */\n async sendAudio(options: SendAudioOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'audio',\n audio: options.audio,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a document message\n * \n * @param options - Document message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendDocument({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * document: {\n * link: 'https://example.com/invoice.pdf',\n * filename: 'invoice.pdf',\n * caption: 'Your invoice',\n * },\n * });\n * ```\n */\n async sendDocument(options: SendDocumentOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'document',\n document: options.document,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a reaction to a message\n * \n * @param options - Reaction options\n * @returns Message response\n * \n * @example\n * ```typescript\n * // Add reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '👍',\n * },\n * });\n * \n * // Remove reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '',\n * },\n * });\n * ```\n */\n async sendReaction(options: SendReactionOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'reaction',\n reaction: {\n message_id: options.reaction.messageId,\n emoji: options.reaction.emoji,\n },\n });\n }\n\n /**\n * Send an interactive message (buttons, lists, etc.)\n * \n * @param options - Interactive message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * // Button message\n * await client.messages.sendInteractive({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * interactive: {\n * type: 'button',\n * body: { text: 'Choose an option:' },\n * action: {\n * buttons: [\n * { type: 'reply', reply: { id: 'yes', title: 'Yes' } },\n * { type: 'reply', reply: { id: 'no', title: 'No' } },\n * ],\n * },\n * },\n * });\n * ```\n */\n async sendInteractive(options: SendInteractiveOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'interactive',\n interactive: options.interactive,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TemplateInfo, ListTemplatesOptions } from '../types';\n\n/**\n * Templates API resource\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all message templates\n * \n * @param options - Optional filters\n * @returns List of templates\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * console.log('Templates:', templates.data);\n * \n * // Filter by status\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\n async list(options?: ListTemplatesOptions): Promise<ApiResponse<TemplateInfo[]>> {\n let path = '/api/v1/templates';\n \n if (options?.status) {\n path += `?status=${encodeURIComponent(options.status)}`;\n }\n \n return this.http.get(path);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, PhoneNumber, PhoneNumberProfile } from '../types';\n\n/**\n * Phone Numbers API resource\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * const profile = await client.phoneNumbers.getProfile('123456');\n * ```\n */\nexport class PhoneNumbers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all phone numbers configured for your account\n * \n * @returns List of phone numbers\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * for (const phone of phoneNumbers.data) {\n * console.log(`${phone.verified_name}: ${phone.display_phone_number}`);\n * }\n * ```\n */\n async list(): Promise<ApiResponse<PhoneNumber[]>> {\n return this.http.get('/api/v1/phone-numbers');\n }\n\n /**\n * Get a specific phone number by ID\n * \n * @param id - The phone number ID (from list response)\n * @returns Phone number details\n * \n * @example\n * ```typescript\n * const phone = await client.phoneNumbers.get('phone-number-uuid');\n * console.log(phone.data.display_phone_number);\n * ```\n */\n async get(id: string): Promise<ApiResponse<PhoneNumber>> {\n return this.http.get(`/api/v1/phone-numbers/${id}`);\n }\n\n /**\n * Get phone number profile from Meta Graph API\n * \n * Returns detailed information including quality rating, verification status,\n * messaging limits, and business profile.\n * \n * @param id - The phone number ID\n * @returns Phone number profile with Meta API details\n * \n * @example\n * ```typescript\n * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');\n * console.log('Quality:', profile.data.phone_number.quality_rating);\n * console.log('Name:', profile.data.business_profile.about);\n * ```\n */\n async getProfile(id: string): Promise<ApiResponse<PhoneNumberProfile>> {\n return this.http.get(`/api/v1/phone-numbers/${id}/profile`);\n }\n\n /**\n * Update business profile for a phone number\n * \n * @param id - The phone number ID\n * @param profile - Profile fields to update\n * @returns Updated business profile\n * \n * @example\n * ```typescript\n * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {\n * about: 'We help businesses grow',\n * description: 'Customer support',\n * email: 'support@example.com',\n * });\n * ```\n */\n async updateProfile(id: string, profile: {\n about?: string;\n address?: string;\n description?: string;\n email?: string;\n vertical?: string;\n websites?: string[];\n }): Promise<ApiResponse<PhoneNumberProfile['business_profile']>> {\n return this.http.patch(`/api/v1/phone-numbers/${id}/profile`, profile);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, UsageData } from '../types';\n\n/**\n * Usage API resource\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Sent: ${usage.data.messages.sent}`);\n * ```\n */\nexport class Usage {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get current usage statistics for the billing period\n * \n * @returns Usage statistics\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);\n * console.log(`Messages sent: ${usage.data.messages.sent}`);\n * console.log(`Messages received: ${usage.data.messages.received}`);\n * console.log(`API calls: ${usage.data.api_calls}`);\n * ```\n */\n async get(): Promise<ApiResponse<UsageData>> {\n return this.http.get('/api/v1/usage');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TriggerWebhookOptions } from '../types';\n\n/**\n * Test API resource (only works with sk_test_* keys)\n * \n * @example\n * ```typescript\n * // Trigger a test webhook\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Test message',\n * });\n * ```\n */\nexport class Test {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Trigger a test webhook to simulate an incoming message\n * \n * **Note:** This only works with test API keys (sk_test_*)\n * \n * @param options - Webhook trigger options\n * @returns Success response\n * \n * @example\n * ```typescript\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Hello, this is a test incoming message!',\n * });\n * ```\n */\n async triggerWebhook(options: TriggerWebhookOptions): Promise<ApiResponse<{ queued: boolean }>> {\n return this.http.post('/api/v1/test/webhooks/trigger', {\n phone_number_id: options.phoneNumberId,\n type: options.type || 'text',\n from: options.from,\n text: options.text,\n });\n }\n}\n","import { HttpClient } from './lib/http';\nimport { Messages } from './resources/messages';\nimport { Templates } from './resources/templates';\nimport { PhoneNumbers } from './resources/phone-numbers';\nimport { Usage } from './resources/usage';\nimport { Test } from './resources/test';\nimport type { ClientOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://connect.semboja.tech';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Semboja WhatsApp API Client\n * \n * @example\n * ```typescript\n * import { SembojaClient } from '@semboja/connect';\n * \n * // Simple initialization\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // With options\n * const client = new SembojaClient({\n * apiKey: process.env.SEMBOJA_API_KEY!,\n * timeout: 60000,\n * retries: 5,\n * });\n * \n * // Send a message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class SembojaClient {\n /** Messages API */\n readonly messages: Messages;\n \n /** Templates API */\n readonly templates: Templates;\n \n /** Phone Numbers API */\n readonly phoneNumbers: PhoneNumbers;\n \n /** Usage API */\n readonly usage: Usage;\n \n /** Test API (only works with sk_test_* keys) */\n readonly test: Test;\n\n /** Whether the client is in test mode */\n readonly isTestMode: boolean;\n\n private readonly http: HttpClient;\n\n /**\n * Create a new Semboja client\n * \n * @param optionsOrApiKey - API key string or client options object\n * \n * @example\n * ```typescript\n * // Using API key directly\n * const client = new SembojaClient('sk_live_xxx');\n * \n * // Using options object\n * const client = new SembojaClient({\n * apiKey: 'sk_live_xxx',\n * timeout: 60000,\n * retries: 5,\n * });\n * ```\n */\n constructor(optionsOrApiKey: string | ClientOptions) {\n const options: ClientOptions = typeof optionsOrApiKey === 'string'\n ? { apiKey: optionsOrApiKey }\n : optionsOrApiKey;\n\n // Validate API key\n if (!options.apiKey) {\n throw new Error('API key is required');\n }\n\n if (!options.apiKey.startsWith('sk_live_') && !options.apiKey.startsWith('sk_test_')) {\n throw new Error('Invalid API key format. Must start with sk_live_ or sk_test_');\n }\n\n // Determine if test mode\n this.isTestMode = options.apiKey.startsWith('sk_test_');\n\n // Create HTTP client\n this.http = new HttpClient({\n baseUrl: options.baseUrl || DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeout: options.timeout || DEFAULT_TIMEOUT,\n retries: options.retries ?? DEFAULT_RETRIES,\n });\n\n // Initialize resources\n this.messages = new Messages(this.http);\n this.templates = new Templates(this.http);\n this.phoneNumbers = new PhoneNumbers(this.http);\n this.usage = new Usage(this.http);\n this.test = new Test(this.http);\n }\n}\n","import { createHmac, timingSafeEqual } from 'crypto';\nimport type { VerifyWebhookOptions } from '../types';\n\n/**\n * Verify a webhook signature from Semboja\n * \n * @param options - Verification options\n * @returns true if the signature is valid, false otherwise\n * \n * @example\n * ```typescript\n * import { verifyWebhookSignature } from '@semboja/connect';\n * \n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'] as string,\n * timestamp: req.headers['x-semboja-timestamp'] as string,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return res.status(401).send('Invalid signature');\n * }\n * \n * // Process the webhook\n * const event = JSON.parse(req.body.toString());\n * console.log('Received event:', event);\n * \n * res.status(200).send('OK');\n * });\n * ```\n * \n * @example\n * ```typescript\n * // Hono example\n * app.post('/webhook', async (c) => {\n * const body = await c.req.text();\n * const signature = c.req.header('x-semboja-signature');\n * const timestamp = c.req.header('x-semboja-timestamp');\n * \n * const isValid = verifyWebhookSignature({\n * payload: body,\n * signature: signature!,\n * timestamp: timestamp!,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return c.text('Invalid signature', 401);\n * }\n * \n * const event = JSON.parse(body);\n * // Process the webhook...\n * \n * return c.text('OK');\n * });\n * ```\n */\nexport function verifyWebhookSignature(options: VerifyWebhookOptions): boolean {\n const { payload, signature, timestamp, secret } = options;\n\n // Validate inputs\n if (!payload || !signature || !timestamp || !secret) {\n return false;\n }\n\n // Check timestamp to prevent replay attacks (5 minute tolerance)\n const timestampNum = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n const tolerance = 5 * 60; // 5 minutes\n\n if (isNaN(timestampNum) || Math.abs(now - timestampNum) > tolerance) {\n return false;\n }\n\n // Stringify payload if it's an object\n const payloadString = typeof payload === 'string' \n ? payload \n : JSON.stringify(payload);\n\n // Compute expected signature\n const signatureData = timestamp + payloadString;\n const expectedSignature = 'sha256=' + createHmac('sha256', secret)\n .update(signatureData)\n .digest('hex');\n\n // Compare signatures using timing-safe comparison\n try {\n const sigBuffer = Buffer.from(signature);\n const expectedBuffer = Buffer.from(expectedSignature);\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(sigBuffer, expectedBuffer);\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a webhook payload into a typed event object\n * \n * @param payload - Raw webhook payload (string or object)\n * @returns Parsed webhook event\n */\nexport function parseWebhookPayload<T = unknown>(payload: string | object): T {\n if (typeof payload === 'string') {\n return JSON.parse(payload) as T;\n }\n return payload as T;\n}\n"],"mappings":"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","names":[]}
package/dist/index.mjs CHANGED
@@ -164,6 +164,24 @@ var HttpClient = class {
164
164
  async post(path, body) {
165
165
  return this.request({ method: "POST", path, body });
166
166
  }
167
+ /**
168
+ * PUT request
169
+ */
170
+ async put(path, body) {
171
+ return this.request({ method: "PUT", path, body });
172
+ }
173
+ /**
174
+ * PATCH request
175
+ */
176
+ async patch(path, body) {
177
+ return this.request({ method: "PATCH", path, body });
178
+ }
179
+ /**
180
+ * DELETE request
181
+ */
182
+ async delete(path) {
183
+ return this.request({ method: "DELETE", path });
184
+ }
167
185
  };
168
186
 
169
187
  // src/resources/messages.ts
@@ -433,6 +451,59 @@ var PhoneNumbers = class {
433
451
  async list() {
434
452
  return this.http.get("/api/v1/phone-numbers");
435
453
  }
454
+ /**
455
+ * Get a specific phone number by ID
456
+ *
457
+ * @param id - The phone number ID (from list response)
458
+ * @returns Phone number details
459
+ *
460
+ * @example
461
+ * ```typescript
462
+ * const phone = await client.phoneNumbers.get('phone-number-uuid');
463
+ * console.log(phone.data.display_phone_number);
464
+ * ```
465
+ */
466
+ async get(id) {
467
+ return this.http.get(`/api/v1/phone-numbers/${id}`);
468
+ }
469
+ /**
470
+ * Get phone number profile from Meta Graph API
471
+ *
472
+ * Returns detailed information including quality rating, verification status,
473
+ * messaging limits, and business profile.
474
+ *
475
+ * @param id - The phone number ID
476
+ * @returns Phone number profile with Meta API details
477
+ *
478
+ * @example
479
+ * ```typescript
480
+ * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');
481
+ * console.log('Quality:', profile.data.phone_number.quality_rating);
482
+ * console.log('Name:', profile.data.business_profile.about);
483
+ * ```
484
+ */
485
+ async getProfile(id) {
486
+ return this.http.get(`/api/v1/phone-numbers/${id}/profile`);
487
+ }
488
+ /**
489
+ * Update business profile for a phone number
490
+ *
491
+ * @param id - The phone number ID
492
+ * @param profile - Profile fields to update
493
+ * @returns Updated business profile
494
+ *
495
+ * @example
496
+ * ```typescript
497
+ * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {
498
+ * about: 'We help businesses grow',
499
+ * description: 'Customer support',
500
+ * email: 'support@example.com',
501
+ * });
502
+ * ```
503
+ */
504
+ async updateProfile(id, profile) {
505
+ return this.http.patch(`/api/v1/phone-numbers/${id}/profile`, profile);
506
+ }
436
507
  };
437
508
 
438
509
  // src/resources/usage.ts
@@ -584,6 +655,9 @@ function parseWebhookPayload(payload) {
584
655
  }
585
656
  return payload;
586
657
  }
658
+
659
+ // src/index.ts
660
+ var index_default = SembojaClient;
587
661
  export {
588
662
  AuthenticationError,
589
663
  NetworkError,
@@ -593,6 +667,7 @@ export {
593
667
  SembojaError,
594
668
  ServerError,
595
669
  ValidationError,
670
+ index_default as default,
596
671
  parseWebhookPayload,
597
672
  verifyWebhookSignature
598
673
  };
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/lib/http.ts","../src/resources/messages.ts","../src/resources/templates.ts","../src/resources/phone-numbers.ts","../src/resources/usage.ts","../src/resources/test.ts","../src/client.ts","../src/webhooks/verify.ts"],"sourcesContent":["/**\n * Base error class for all Semboja API errors\n */\nexport class SembojaError extends Error {\n /** Error code from the API */\n readonly code: string;\n /** HTTP status code */\n readonly statusCode: number;\n /** Request ID for debugging */\n readonly requestId?: string;\n\n constructor(\n message: string,\n code: string,\n statusCode: number,\n requestId?: string\n ) {\n super(message);\n this.name = 'SembojaError';\n this.code = code;\n this.statusCode = statusCode;\n this.requestId = requestId;\n Object.setPrototypeOf(this, SembojaError.prototype);\n }\n}\n\n/**\n * Authentication error (invalid or missing API key)\n */\nexport class AuthenticationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INVALID_API_KEY', 401, requestId);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Rate limit exceeded error\n */\nexport class RateLimitError extends SembojaError {\n /** When the rate limit resets (Unix timestamp) */\n readonly resetAt?: number;\n\n constructor(message: string, requestId?: string, resetAt?: number) {\n super(message, 'RATE_LIMITED', 429, requestId);\n this.name = 'RateLimitError';\n this.resetAt = resetAt;\n Object.setPrototypeOf(this, RateLimitError.prototype);\n }\n}\n\n/**\n * Validation error (invalid request parameters)\n */\nexport class ValidationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'VALIDATION_ERROR', 400, requestId);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Resource not found error\n */\nexport class NotFoundError extends SembojaError {\n constructor(message: string, code: string, requestId?: string) {\n super(message, code, 404, requestId);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n\n/**\n * Server error from Semboja API\n */\nexport class ServerError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INTERNAL_ERROR', 500, requestId);\n this.name = 'ServerError';\n Object.setPrototypeOf(this, ServerError.prototype);\n }\n}\n\n/**\n * Network or connection error\n */\nexport class NetworkError extends SembojaError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR', 0);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n","import {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from '../errors';\nimport type { ApiErrorResponse } from '../types';\n\nexport interface HttpClientOptions {\n baseUrl: string;\n apiKey: string;\n timeout: number;\n retries: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate exponential backoff delay\n */\nfunction getBackoffDelay(attempt: number, baseDelay = 1000): number {\n return Math.min(baseDelay * Math.pow(2, attempt), 30000);\n}\n\n/**\n * HTTP client for making API requests\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.timeout = options.timeout;\n this.retries = options.retries;\n }\n\n /**\n * Make an HTTP request with retry logic\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n ...options.headers,\n };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = await response.json();\n\n // Handle errors\n if (!response.ok) {\n throw this.parseError(response.status, data as ApiErrorResponse);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except rate limits\n if (error instanceof SembojaError) {\n if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {\n throw error;\n }\n }\n\n // Don't retry on abort (timeout)\n if (error instanceof Error && error.name === 'AbortError') {\n throw new NetworkError(`Request timeout after ${this.timeout}ms`);\n }\n\n // Retry on network errors and rate limits\n if (attempt < this.retries) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n }\n }\n\n // If we get here, all retries failed\n if (lastError instanceof SembojaError) {\n throw lastError;\n }\n throw new NetworkError(lastError?.message || 'Request failed');\n }\n\n /**\n * Parse error response into appropriate error class\n */\n private parseError(statusCode: number, data: ApiErrorResponse): SembojaError {\n const message = data.error?.message || 'Unknown error';\n const code = data.error?.code || 'UNKNOWN_ERROR';\n const requestId = data.meta?.request_id;\n\n switch (statusCode) {\n case 401:\n return new AuthenticationError(message, requestId);\n case 429:\n return new RateLimitError(message, requestId);\n case 400:\n return new ValidationError(message, requestId);\n case 404:\n return new NotFoundError(message, code, requestId);\n case 500:\n case 502:\n case 503:\n return new ServerError(message, requestId);\n default:\n return new SembojaError(message, code, statusCode, requestId);\n }\n }\n\n /**\n * GET request\n */\n async get<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'GET', path });\n }\n\n /**\n * POST request\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'POST', path, body });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type {\n ApiResponse,\n MessageResponseData,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n} from '../types';\n\n/**\n * Messages API resource\n * \n * @example\n * ```typescript\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class Messages {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Send a text message\n * \n * @param options - Text message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello, World!',\n * previewUrl: true,\n * });\n * console.log('Message ID:', result.data.messages[0].id);\n * ```\n */\n async sendText(options: SendTextOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/text', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n text: options.text,\n preview_url: options.previewUrl,\n reply_to: options.replyTo,\n });\n }\n\n /**\n * Send a template message\n * \n * @param options - Template message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendTemplate({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * template: {\n * name: 'hello_world',\n * language: { code: 'en' },\n * },\n * });\n * ```\n */\n async sendTemplate(options: SendTemplateOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/template', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n template: options.template,\n });\n }\n\n /**\n * Send an image message\n * \n * @param options - Image message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendImage({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * image: {\n * link: 'https://example.com/image.jpg',\n * caption: 'Check this out!',\n * },\n * });\n * ```\n */\n async sendImage(options: SendImageOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'image',\n image: options.image,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a video message\n * \n * @param options - Video message options\n * @returns Message response with message ID\n */\n async sendVideo(options: SendVideoOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'video',\n video: options.video,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send an audio message\n * \n * @param options - Audio message options\n * @returns Message response with message ID\n */\n async sendAudio(options: SendAudioOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'audio',\n audio: options.audio,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a document message\n * \n * @param options - Document message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendDocument({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * document: {\n * link: 'https://example.com/invoice.pdf',\n * filename: 'invoice.pdf',\n * caption: 'Your invoice',\n * },\n * });\n * ```\n */\n async sendDocument(options: SendDocumentOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'document',\n document: options.document,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a reaction to a message\n * \n * @param options - Reaction options\n * @returns Message response\n * \n * @example\n * ```typescript\n * // Add reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '👍',\n * },\n * });\n * \n * // Remove reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '',\n * },\n * });\n * ```\n */\n async sendReaction(options: SendReactionOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'reaction',\n reaction: {\n message_id: options.reaction.messageId,\n emoji: options.reaction.emoji,\n },\n });\n }\n\n /**\n * Send an interactive message (buttons, lists, etc.)\n * \n * @param options - Interactive message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * // Button message\n * await client.messages.sendInteractive({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * interactive: {\n * type: 'button',\n * body: { text: 'Choose an option:' },\n * action: {\n * buttons: [\n * { type: 'reply', reply: { id: 'yes', title: 'Yes' } },\n * { type: 'reply', reply: { id: 'no', title: 'No' } },\n * ],\n * },\n * },\n * });\n * ```\n */\n async sendInteractive(options: SendInteractiveOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'interactive',\n interactive: options.interactive,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TemplateInfo, ListTemplatesOptions } from '../types';\n\n/**\n * Templates API resource\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all message templates\n * \n * @param options - Optional filters\n * @returns List of templates\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * console.log('Templates:', templates.data);\n * \n * // Filter by status\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\n async list(options?: ListTemplatesOptions): Promise<ApiResponse<TemplateInfo[]>> {\n let path = '/api/v1/templates';\n \n if (options?.status) {\n path += `?status=${encodeURIComponent(options.status)}`;\n }\n \n return this.http.get(path);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, PhoneNumber } from '../types';\n\n/**\n * Phone Numbers API resource\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * ```\n */\nexport class PhoneNumbers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all phone numbers configured for your account\n * \n * @returns List of phone numbers\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * for (const phone of phoneNumbers.data) {\n * console.log(`${phone.verified_name}: ${phone.display_phone_number}`);\n * }\n * ```\n */\n async list(): Promise<ApiResponse<PhoneNumber[]>> {\n return this.http.get('/api/v1/phone-numbers');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, UsageData } from '../types';\n\n/**\n * Usage API resource\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Sent: ${usage.data.messages.sent}`);\n * ```\n */\nexport class Usage {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get current usage statistics for the billing period\n * \n * @returns Usage statistics\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);\n * console.log(`Messages sent: ${usage.data.messages.sent}`);\n * console.log(`Messages received: ${usage.data.messages.received}`);\n * console.log(`API calls: ${usage.data.api_calls}`);\n * ```\n */\n async get(): Promise<ApiResponse<UsageData>> {\n return this.http.get('/api/v1/usage');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TriggerWebhookOptions } from '../types';\n\n/**\n * Test API resource (only works with sk_test_* keys)\n * \n * @example\n * ```typescript\n * // Trigger a test webhook\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Test message',\n * });\n * ```\n */\nexport class Test {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Trigger a test webhook to simulate an incoming message\n * \n * **Note:** This only works with test API keys (sk_test_*)\n * \n * @param options - Webhook trigger options\n * @returns Success response\n * \n * @example\n * ```typescript\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Hello, this is a test incoming message!',\n * });\n * ```\n */\n async triggerWebhook(options: TriggerWebhookOptions): Promise<ApiResponse<{ queued: boolean }>> {\n return this.http.post('/api/v1/test/webhooks/trigger', {\n phone_number_id: options.phoneNumberId,\n type: options.type || 'text',\n from: options.from,\n text: options.text,\n });\n }\n}\n","import { HttpClient } from './lib/http';\nimport { Messages } from './resources/messages';\nimport { Templates } from './resources/templates';\nimport { PhoneNumbers } from './resources/phone-numbers';\nimport { Usage } from './resources/usage';\nimport { Test } from './resources/test';\nimport type { ClientOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://connect.semboja.tech';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Semboja WhatsApp API Client\n * \n * @example\n * ```typescript\n * import { SembojaClient } from '@semboja/connect';\n * \n * // Simple initialization\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // With options\n * const client = new SembojaClient({\n * apiKey: process.env.SEMBOJA_API_KEY!,\n * timeout: 60000,\n * retries: 5,\n * });\n * \n * // Send a message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class SembojaClient {\n /** Messages API */\n readonly messages: Messages;\n \n /** Templates API */\n readonly templates: Templates;\n \n /** Phone Numbers API */\n readonly phoneNumbers: PhoneNumbers;\n \n /** Usage API */\n readonly usage: Usage;\n \n /** Test API (only works with sk_test_* keys) */\n readonly test: Test;\n\n /** Whether the client is in test mode */\n readonly isTestMode: boolean;\n\n private readonly http: HttpClient;\n\n /**\n * Create a new Semboja client\n * \n * @param optionsOrApiKey - API key string or client options object\n * \n * @example\n * ```typescript\n * // Using API key directly\n * const client = new SembojaClient('sk_live_xxx');\n * \n * // Using options object\n * const client = new SembojaClient({\n * apiKey: 'sk_live_xxx',\n * timeout: 60000,\n * retries: 5,\n * });\n * ```\n */\n constructor(optionsOrApiKey: string | ClientOptions) {\n const options: ClientOptions = typeof optionsOrApiKey === 'string'\n ? { apiKey: optionsOrApiKey }\n : optionsOrApiKey;\n\n // Validate API key\n if (!options.apiKey) {\n throw new Error('API key is required');\n }\n\n if (!options.apiKey.startsWith('sk_live_') && !options.apiKey.startsWith('sk_test_')) {\n throw new Error('Invalid API key format. Must start with sk_live_ or sk_test_');\n }\n\n // Determine if test mode\n this.isTestMode = options.apiKey.startsWith('sk_test_');\n\n // Create HTTP client\n this.http = new HttpClient({\n baseUrl: options.baseUrl || DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeout: options.timeout || DEFAULT_TIMEOUT,\n retries: options.retries ?? DEFAULT_RETRIES,\n });\n\n // Initialize resources\n this.messages = new Messages(this.http);\n this.templates = new Templates(this.http);\n this.phoneNumbers = new PhoneNumbers(this.http);\n this.usage = new Usage(this.http);\n this.test = new Test(this.http);\n }\n}\n","import { createHmac, timingSafeEqual } from 'crypto';\nimport type { VerifyWebhookOptions } from '../types';\n\n/**\n * Verify a webhook signature from Semboja\n * \n * @param options - Verification options\n * @returns true if the signature is valid, false otherwise\n * \n * @example\n * ```typescript\n * import { verifyWebhookSignature } from '@semboja/connect';\n * \n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'] as string,\n * timestamp: req.headers['x-semboja-timestamp'] as string,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return res.status(401).send('Invalid signature');\n * }\n * \n * // Process the webhook\n * const event = JSON.parse(req.body.toString());\n * console.log('Received event:', event);\n * \n * res.status(200).send('OK');\n * });\n * ```\n * \n * @example\n * ```typescript\n * // Hono example\n * app.post('/webhook', async (c) => {\n * const body = await c.req.text();\n * const signature = c.req.header('x-semboja-signature');\n * const timestamp = c.req.header('x-semboja-timestamp');\n * \n * const isValid = verifyWebhookSignature({\n * payload: body,\n * signature: signature!,\n * timestamp: timestamp!,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return c.text('Invalid signature', 401);\n * }\n * \n * const event = JSON.parse(body);\n * // Process the webhook...\n * \n * return c.text('OK');\n * });\n * ```\n */\nexport function verifyWebhookSignature(options: VerifyWebhookOptions): boolean {\n const { payload, signature, timestamp, secret } = options;\n\n // Validate inputs\n if (!payload || !signature || !timestamp || !secret) {\n return false;\n }\n\n // Check timestamp to prevent replay attacks (5 minute tolerance)\n const timestampNum = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n const tolerance = 5 * 60; // 5 minutes\n\n if (isNaN(timestampNum) || Math.abs(now - timestampNum) > tolerance) {\n return false;\n }\n\n // Stringify payload if it's an object\n const payloadString = typeof payload === 'string' \n ? payload \n : JSON.stringify(payload);\n\n // Compute expected signature\n const signatureData = timestamp + payloadString;\n const expectedSignature = 'sha256=' + createHmac('sha256', secret)\n .update(signatureData)\n .digest('hex');\n\n // Compare signatures using timing-safe comparison\n try {\n const sigBuffer = Buffer.from(signature);\n const expectedBuffer = Buffer.from(expectedSignature);\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(sigBuffer, expectedBuffer);\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a webhook payload into a typed event object\n * \n * @param payload - Raw webhook payload (string or object)\n * @returns Parsed webhook event\n */\nexport function parseWebhookPayload<T = unknown>(payload: string | object): T {\n if (typeof payload === 'string') {\n return JSON.parse(payload) as T;\n }\n return payload as T;\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/lib/http.ts","../src/resources/messages.ts","../src/resources/templates.ts","../src/resources/phone-numbers.ts","../src/resources/usage.ts","../src/resources/test.ts","../src/client.ts","../src/webhooks/verify.ts","../src/index.ts"],"sourcesContent":["/**\n * Base error class for all Semboja API errors\n */\nexport class SembojaError extends Error {\n /** Error code from the API */\n readonly code: string;\n /** HTTP status code */\n readonly statusCode: number;\n /** Request ID for debugging */\n readonly requestId?: string;\n\n constructor(\n message: string,\n code: string,\n statusCode: number,\n requestId?: string\n ) {\n super(message);\n this.name = 'SembojaError';\n this.code = code;\n this.statusCode = statusCode;\n this.requestId = requestId;\n Object.setPrototypeOf(this, SembojaError.prototype);\n }\n}\n\n/**\n * Authentication error (invalid or missing API key)\n */\nexport class AuthenticationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INVALID_API_KEY', 401, requestId);\n this.name = 'AuthenticationError';\n Object.setPrototypeOf(this, AuthenticationError.prototype);\n }\n}\n\n/**\n * Rate limit exceeded error\n */\nexport class RateLimitError extends SembojaError {\n /** When the rate limit resets (Unix timestamp) */\n readonly resetAt?: number;\n\n constructor(message: string, requestId?: string, resetAt?: number) {\n super(message, 'RATE_LIMITED', 429, requestId);\n this.name = 'RateLimitError';\n this.resetAt = resetAt;\n Object.setPrototypeOf(this, RateLimitError.prototype);\n }\n}\n\n/**\n * Validation error (invalid request parameters)\n */\nexport class ValidationError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'VALIDATION_ERROR', 400, requestId);\n this.name = 'ValidationError';\n Object.setPrototypeOf(this, ValidationError.prototype);\n }\n}\n\n/**\n * Resource not found error\n */\nexport class NotFoundError extends SembojaError {\n constructor(message: string, code: string, requestId?: string) {\n super(message, code, 404, requestId);\n this.name = 'NotFoundError';\n Object.setPrototypeOf(this, NotFoundError.prototype);\n }\n}\n\n/**\n * Server error from Semboja API\n */\nexport class ServerError extends SembojaError {\n constructor(message: string, requestId?: string) {\n super(message, 'INTERNAL_ERROR', 500, requestId);\n this.name = 'ServerError';\n Object.setPrototypeOf(this, ServerError.prototype);\n }\n}\n\n/**\n * Network or connection error\n */\nexport class NetworkError extends SembojaError {\n constructor(message: string) {\n super(message, 'NETWORK_ERROR', 0);\n this.name = 'NetworkError';\n Object.setPrototypeOf(this, NetworkError.prototype);\n }\n}\n","import {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from '../errors';\nimport type { ApiErrorResponse } from '../types';\n\nexport interface HttpClientOptions {\n baseUrl: string;\n apiKey: string;\n timeout: number;\n retries: number;\n}\n\nexport interface RequestOptions {\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n}\n\n/**\n * Sleep for a given number of milliseconds\n */\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\n/**\n * Calculate exponential backoff delay\n */\nfunction getBackoffDelay(attempt: number, baseDelay = 1000): number {\n return Math.min(baseDelay * Math.pow(2, attempt), 30000);\n}\n\n/**\n * HTTP client for making API requests\n */\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(options: HttpClientOptions) {\n this.baseUrl = options.baseUrl.replace(/\\/$/, '');\n this.apiKey = options.apiKey;\n this.timeout = options.timeout;\n this.retries = options.retries;\n }\n\n /**\n * Make an HTTP request with retry logic\n */\n async request<T>(options: RequestOptions): Promise<T> {\n const url = `${this.baseUrl}${options.path}`;\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n 'X-API-Key': this.apiKey,\n ...options.headers,\n };\n\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt <= this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: options.method,\n headers,\n body: options.body ? JSON.stringify(options.body) : undefined,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n // Parse response\n const data = await response.json();\n\n // Handle errors\n if (!response.ok) {\n throw this.parseError(response.status, data as ApiErrorResponse);\n }\n\n return data as T;\n } catch (error) {\n lastError = error as Error;\n\n // Don't retry on client errors (4xx) except rate limits\n if (error instanceof SembojaError) {\n if (error.statusCode >= 400 && error.statusCode < 500 && error.statusCode !== 429) {\n throw error;\n }\n }\n\n // Don't retry on abort (timeout)\n if (error instanceof Error && error.name === 'AbortError') {\n throw new NetworkError(`Request timeout after ${this.timeout}ms`);\n }\n\n // Retry on network errors and rate limits\n if (attempt < this.retries) {\n const delay = getBackoffDelay(attempt);\n await sleep(delay);\n continue;\n }\n }\n }\n\n // If we get here, all retries failed\n if (lastError instanceof SembojaError) {\n throw lastError;\n }\n throw new NetworkError(lastError?.message || 'Request failed');\n }\n\n /**\n * Parse error response into appropriate error class\n */\n private parseError(statusCode: number, data: ApiErrorResponse): SembojaError {\n const message = data.error?.message || 'Unknown error';\n const code = data.error?.code || 'UNKNOWN_ERROR';\n const requestId = data.meta?.request_id;\n\n switch (statusCode) {\n case 401:\n return new AuthenticationError(message, requestId);\n case 429:\n return new RateLimitError(message, requestId);\n case 400:\n return new ValidationError(message, requestId);\n case 404:\n return new NotFoundError(message, code, requestId);\n case 500:\n case 502:\n case 503:\n return new ServerError(message, requestId);\n default:\n return new SembojaError(message, code, statusCode, requestId);\n }\n }\n\n /**\n * GET request\n */\n async get<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'GET', path });\n }\n\n /**\n * POST request\n */\n async post<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'POST', path, body });\n }\n\n /**\n * PUT request\n */\n async put<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'PUT', path, body });\n }\n\n /**\n * PATCH request\n */\n async patch<T>(path: string, body?: unknown): Promise<T> {\n return this.request<T>({ method: 'PATCH', path, body });\n }\n\n /**\n * DELETE request\n */\n async delete<T>(path: string): Promise<T> {\n return this.request<T>({ method: 'DELETE', path });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type {\n ApiResponse,\n MessageResponseData,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n} from '../types';\n\n/**\n * Messages API resource\n * \n * @example\n * ```typescript\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class Messages {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Send a text message\n * \n * @param options - Text message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello, World!',\n * previewUrl: true,\n * });\n * console.log('Message ID:', result.data.messages[0].id);\n * ```\n */\n async sendText(options: SendTextOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/text', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n text: options.text,\n preview_url: options.previewUrl,\n reply_to: options.replyTo,\n });\n }\n\n /**\n * Send a template message\n * \n * @param options - Template message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendTemplate({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * template: {\n * name: 'hello_world',\n * language: { code: 'en' },\n * },\n * });\n * ```\n */\n async sendTemplate(options: SendTemplateOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages/template', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n template: options.template,\n });\n }\n\n /**\n * Send an image message\n * \n * @param options - Image message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendImage({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * image: {\n * link: 'https://example.com/image.jpg',\n * caption: 'Check this out!',\n * },\n * });\n * ```\n */\n async sendImage(options: SendImageOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'image',\n image: options.image,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a video message\n * \n * @param options - Video message options\n * @returns Message response with message ID\n */\n async sendVideo(options: SendVideoOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'video',\n video: options.video,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send an audio message\n * \n * @param options - Audio message options\n * @returns Message response with message ID\n */\n async sendAudio(options: SendAudioOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'audio',\n audio: options.audio,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a document message\n * \n * @param options - Document message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * const result = await client.messages.sendDocument({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * document: {\n * link: 'https://example.com/invoice.pdf',\n * filename: 'invoice.pdf',\n * caption: 'Your invoice',\n * },\n * });\n * ```\n */\n async sendDocument(options: SendDocumentOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'document',\n document: options.document,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n\n /**\n * Send a reaction to a message\n * \n * @param options - Reaction options\n * @returns Message response\n * \n * @example\n * ```typescript\n * // Add reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '👍',\n * },\n * });\n * \n * // Remove reaction\n * await client.messages.sendReaction({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * reaction: {\n * messageId: 'wamid.xxx',\n * emoji: '',\n * },\n * });\n * ```\n */\n async sendReaction(options: SendReactionOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'reaction',\n reaction: {\n message_id: options.reaction.messageId,\n emoji: options.reaction.emoji,\n },\n });\n }\n\n /**\n * Send an interactive message (buttons, lists, etc.)\n * \n * @param options - Interactive message options\n * @returns Message response with message ID\n * \n * @example\n * ```typescript\n * // Button message\n * await client.messages.sendInteractive({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * interactive: {\n * type: 'button',\n * body: { text: 'Choose an option:' },\n * action: {\n * buttons: [\n * { type: 'reply', reply: { id: 'yes', title: 'Yes' } },\n * { type: 'reply', reply: { id: 'no', title: 'No' } },\n * ],\n * },\n * },\n * });\n * ```\n */\n async sendInteractive(options: SendInteractiveOptions): Promise<ApiResponse<MessageResponseData>> {\n return this.http.post('/api/v1/messages', {\n phone_number_id: options.phoneNumberId,\n to: options.to,\n type: 'interactive',\n interactive: options.interactive,\n context: options.replyTo ? { message_id: options.replyTo } : undefined,\n });\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TemplateInfo, ListTemplatesOptions } from '../types';\n\n/**\n * Templates API resource\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all message templates\n * \n * @param options - Optional filters\n * @returns List of templates\n * \n * @example\n * ```typescript\n * const templates = await client.templates.list();\n * console.log('Templates:', templates.data);\n * \n * // Filter by status\n * const approved = await client.templates.list({ status: 'APPROVED' });\n * ```\n */\n async list(options?: ListTemplatesOptions): Promise<ApiResponse<TemplateInfo[]>> {\n let path = '/api/v1/templates';\n \n if (options?.status) {\n path += `?status=${encodeURIComponent(options.status)}`;\n }\n \n return this.http.get(path);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, PhoneNumber, PhoneNumberProfile } from '../types';\n\n/**\n * Phone Numbers API resource\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * const profile = await client.phoneNumbers.getProfile('123456');\n * ```\n */\nexport class PhoneNumbers {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * List all phone numbers configured for your account\n * \n * @returns List of phone numbers\n * \n * @example\n * ```typescript\n * const phoneNumbers = await client.phoneNumbers.list();\n * for (const phone of phoneNumbers.data) {\n * console.log(`${phone.verified_name}: ${phone.display_phone_number}`);\n * }\n * ```\n */\n async list(): Promise<ApiResponse<PhoneNumber[]>> {\n return this.http.get('/api/v1/phone-numbers');\n }\n\n /**\n * Get a specific phone number by ID\n * \n * @param id - The phone number ID (from list response)\n * @returns Phone number details\n * \n * @example\n * ```typescript\n * const phone = await client.phoneNumbers.get('phone-number-uuid');\n * console.log(phone.data.display_phone_number);\n * ```\n */\n async get(id: string): Promise<ApiResponse<PhoneNumber>> {\n return this.http.get(`/api/v1/phone-numbers/${id}`);\n }\n\n /**\n * Get phone number profile from Meta Graph API\n * \n * Returns detailed information including quality rating, verification status,\n * messaging limits, and business profile.\n * \n * @param id - The phone number ID\n * @returns Phone number profile with Meta API details\n * \n * @example\n * ```typescript\n * const profile = await client.phoneNumbers.getProfile('phone-number-uuid');\n * console.log('Quality:', profile.data.phone_number.quality_rating);\n * console.log('Name:', profile.data.business_profile.about);\n * ```\n */\n async getProfile(id: string): Promise<ApiResponse<PhoneNumberProfile>> {\n return this.http.get(`/api/v1/phone-numbers/${id}/profile`);\n }\n\n /**\n * Update business profile for a phone number\n * \n * @param id - The phone number ID\n * @param profile - Profile fields to update\n * @returns Updated business profile\n * \n * @example\n * ```typescript\n * const updated = await client.phoneNumbers.updateProfile('phone-number-uuid', {\n * about: 'We help businesses grow',\n * description: 'Customer support',\n * email: 'support@example.com',\n * });\n * ```\n */\n async updateProfile(id: string, profile: {\n about?: string;\n address?: string;\n description?: string;\n email?: string;\n vertical?: string;\n websites?: string[];\n }): Promise<ApiResponse<PhoneNumberProfile['business_profile']>> {\n return this.http.patch(`/api/v1/phone-numbers/${id}/profile`, profile);\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, UsageData } from '../types';\n\n/**\n * Usage API resource\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Sent: ${usage.data.messages.sent}`);\n * ```\n */\nexport class Usage {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Get current usage statistics for the billing period\n * \n * @returns Usage statistics\n * \n * @example\n * ```typescript\n * const usage = await client.usage.get();\n * console.log(`Period: ${usage.data.period.start} - ${usage.data.period.end}`);\n * console.log(`Messages sent: ${usage.data.messages.sent}`);\n * console.log(`Messages received: ${usage.data.messages.received}`);\n * console.log(`API calls: ${usage.data.api_calls}`);\n * ```\n */\n async get(): Promise<ApiResponse<UsageData>> {\n return this.http.get('/api/v1/usage');\n }\n}\n","import type { HttpClient } from '../lib/http';\nimport type { ApiResponse, TriggerWebhookOptions } from '../types';\n\n/**\n * Test API resource (only works with sk_test_* keys)\n * \n * @example\n * ```typescript\n * // Trigger a test webhook\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Test message',\n * });\n * ```\n */\nexport class Test {\n constructor(private readonly http: HttpClient) {}\n\n /**\n * Trigger a test webhook to simulate an incoming message\n * \n * **Note:** This only works with test API keys (sk_test_*)\n * \n * @param options - Webhook trigger options\n * @returns Success response\n * \n * @example\n * ```typescript\n * await client.test.triggerWebhook({\n * phoneNumberId: '123456789',\n * type: 'text',\n * from: '+6281234567890',\n * text: 'Hello, this is a test incoming message!',\n * });\n * ```\n */\n async triggerWebhook(options: TriggerWebhookOptions): Promise<ApiResponse<{ queued: boolean }>> {\n return this.http.post('/api/v1/test/webhooks/trigger', {\n phone_number_id: options.phoneNumberId,\n type: options.type || 'text',\n from: options.from,\n text: options.text,\n });\n }\n}\n","import { HttpClient } from './lib/http';\nimport { Messages } from './resources/messages';\nimport { Templates } from './resources/templates';\nimport { PhoneNumbers } from './resources/phone-numbers';\nimport { Usage } from './resources/usage';\nimport { Test } from './resources/test';\nimport type { ClientOptions } from './types';\n\nconst DEFAULT_BASE_URL = 'https://connect.semboja.tech';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Semboja WhatsApp API Client\n * \n * @example\n * ```typescript\n * import { SembojaClient } from '@semboja/connect';\n * \n * // Simple initialization\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // With options\n * const client = new SembojaClient({\n * apiKey: process.env.SEMBOJA_API_KEY!,\n * timeout: 60000,\n * retries: 5,\n * });\n * \n * // Send a message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * ```\n */\nexport class SembojaClient {\n /** Messages API */\n readonly messages: Messages;\n \n /** Templates API */\n readonly templates: Templates;\n \n /** Phone Numbers API */\n readonly phoneNumbers: PhoneNumbers;\n \n /** Usage API */\n readonly usage: Usage;\n \n /** Test API (only works with sk_test_* keys) */\n readonly test: Test;\n\n /** Whether the client is in test mode */\n readonly isTestMode: boolean;\n\n private readonly http: HttpClient;\n\n /**\n * Create a new Semboja client\n * \n * @param optionsOrApiKey - API key string or client options object\n * \n * @example\n * ```typescript\n * // Using API key directly\n * const client = new SembojaClient('sk_live_xxx');\n * \n * // Using options object\n * const client = new SembojaClient({\n * apiKey: 'sk_live_xxx',\n * timeout: 60000,\n * retries: 5,\n * });\n * ```\n */\n constructor(optionsOrApiKey: string | ClientOptions) {\n const options: ClientOptions = typeof optionsOrApiKey === 'string'\n ? { apiKey: optionsOrApiKey }\n : optionsOrApiKey;\n\n // Validate API key\n if (!options.apiKey) {\n throw new Error('API key is required');\n }\n\n if (!options.apiKey.startsWith('sk_live_') && !options.apiKey.startsWith('sk_test_')) {\n throw new Error('Invalid API key format. Must start with sk_live_ or sk_test_');\n }\n\n // Determine if test mode\n this.isTestMode = options.apiKey.startsWith('sk_test_');\n\n // Create HTTP client\n this.http = new HttpClient({\n baseUrl: options.baseUrl || DEFAULT_BASE_URL,\n apiKey: options.apiKey,\n timeout: options.timeout || DEFAULT_TIMEOUT,\n retries: options.retries ?? DEFAULT_RETRIES,\n });\n\n // Initialize resources\n this.messages = new Messages(this.http);\n this.templates = new Templates(this.http);\n this.phoneNumbers = new PhoneNumbers(this.http);\n this.usage = new Usage(this.http);\n this.test = new Test(this.http);\n }\n}\n","import { createHmac, timingSafeEqual } from 'crypto';\nimport type { VerifyWebhookOptions } from '../types';\n\n/**\n * Verify a webhook signature from Semboja\n * \n * @param options - Verification options\n * @returns true if the signature is valid, false otherwise\n * \n * @example\n * ```typescript\n * import { verifyWebhookSignature } from '@semboja/connect';\n * \n * // Express.js example\n * app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'] as string,\n * timestamp: req.headers['x-semboja-timestamp'] as string,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return res.status(401).send('Invalid signature');\n * }\n * \n * // Process the webhook\n * const event = JSON.parse(req.body.toString());\n * console.log('Received event:', event);\n * \n * res.status(200).send('OK');\n * });\n * ```\n * \n * @example\n * ```typescript\n * // Hono example\n * app.post('/webhook', async (c) => {\n * const body = await c.req.text();\n * const signature = c.req.header('x-semboja-signature');\n * const timestamp = c.req.header('x-semboja-timestamp');\n * \n * const isValid = verifyWebhookSignature({\n * payload: body,\n * signature: signature!,\n * timestamp: timestamp!,\n * secret: process.env.WEBHOOK_SECRET!,\n * });\n * \n * if (!isValid) {\n * return c.text('Invalid signature', 401);\n * }\n * \n * const event = JSON.parse(body);\n * // Process the webhook...\n * \n * return c.text('OK');\n * });\n * ```\n */\nexport function verifyWebhookSignature(options: VerifyWebhookOptions): boolean {\n const { payload, signature, timestamp, secret } = options;\n\n // Validate inputs\n if (!payload || !signature || !timestamp || !secret) {\n return false;\n }\n\n // Check timestamp to prevent replay attacks (5 minute tolerance)\n const timestampNum = parseInt(timestamp, 10);\n const now = Math.floor(Date.now() / 1000);\n const tolerance = 5 * 60; // 5 minutes\n\n if (isNaN(timestampNum) || Math.abs(now - timestampNum) > tolerance) {\n return false;\n }\n\n // Stringify payload if it's an object\n const payloadString = typeof payload === 'string' \n ? payload \n : JSON.stringify(payload);\n\n // Compute expected signature\n const signatureData = timestamp + payloadString;\n const expectedSignature = 'sha256=' + createHmac('sha256', secret)\n .update(signatureData)\n .digest('hex');\n\n // Compare signatures using timing-safe comparison\n try {\n const sigBuffer = Buffer.from(signature);\n const expectedBuffer = Buffer.from(expectedSignature);\n\n if (sigBuffer.length !== expectedBuffer.length) {\n return false;\n }\n\n return timingSafeEqual(sigBuffer, expectedBuffer);\n } catch {\n return false;\n }\n}\n\n/**\n * Parse a webhook payload into a typed event object\n * \n * @param payload - Raw webhook payload (string or object)\n * @returns Parsed webhook event\n */\nexport function parseWebhookPayload<T = unknown>(payload: string | object): T {\n if (typeof payload === 'string') {\n return JSON.parse(payload) as T;\n }\n return payload as T;\n}\n","/**\n * @semboja/connect - Official Node.js SDK for Semboja WhatsApp API Bridge\n * \n * @example\n * ```typescript\n * // Using default import\n * import Semboja from '@semboja/connect';\n * const client = new Semboja('sk_live_your_api_key');\n * \n * // Or using named import\n * import { SembojaClient, verifyWebhookSignature } from '@semboja/connect';\n * const client = new SembojaClient('sk_live_your_api_key');\n * \n * // Send a text message\n * await client.messages.sendText({\n * phoneNumberId: '123456789',\n * to: '+6281234567890',\n * text: 'Hello from Semboja!',\n * });\n * \n * // Verify webhook signature\n * const isValid = verifyWebhookSignature({\n * payload: req.body,\n * signature: req.headers['x-semboja-signature'],\n * timestamp: req.headers['x-semboja-timestamp'],\n * secret: process.env.WEBHOOK_SECRET,\n * });\n * ```\n * \n * @packageDocumentation\n */\n\n// Main client\nexport { SembojaClient } from './client';\n\n// Default export for convenience\nimport { SembojaClient as Client } from './client';\nexport default Client;\n\n// Webhook utilities\nexport { verifyWebhookSignature, parseWebhookPayload } from './webhooks/verify';\n\n// Error classes\nexport {\n SembojaError,\n AuthenticationError,\n RateLimitError,\n ValidationError,\n NotFoundError,\n ServerError,\n NetworkError,\n} from './errors';\n\n// Types\nexport type {\n // Client\n ClientOptions,\n ApiResponse,\n ApiErrorResponse,\n \n // Messages\n MessageType,\n SendMessageOptions,\n SendTextOptions,\n SendTemplateOptions,\n SendImageOptions,\n SendVideoOptions,\n SendAudioOptions,\n SendDocumentOptions,\n SendReactionOptions,\n SendInteractiveOptions,\n Template,\n TemplateLanguage,\n TemplateComponent,\n TemplateParameter,\n MediaObject,\n InteractiveMessage,\n InteractiveButton,\n InteractiveListSection,\n MessageResponseData,\n MessageContact,\n MessageResult,\n \n // Templates\n TemplateStatus,\n TemplateInfo,\n ListTemplatesOptions,\n \n // Phone Numbers\n PhoneNumber,\n PhoneNumberProfile,\n MetaPhoneNumberInfo,\n MetaBusinessProfile,\n \n // Usage\n UsageData,\n UsagePeriod,\n UsageMessages,\n \n // Test\n TriggerWebhookOptions,\n \n // Webhooks\n VerifyWebhookOptions,\n} from './types';\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@semboja/connect",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Official Node.js SDK for Semboja WhatsApp API Bridge",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",