@stacksjs/sms 0.70.23 → 0.70.25

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/README.md CHANGED
@@ -38,62 +38,62 @@ Drivers are configured with the following environment variables:
38
38
  #### Twilio
39
39
 
40
40
  ```bash
41
- TWILIO_ACCOUNT_SID=ACtest
42
- TWILIO_AUTH_TOKEN=testtoken
43
- TWILIO_FROM_NUMBER=+112345
44
- TWILIO_TO_NUMBER=+145678
41
+ TWILIO*ACCOUNT*SID=ACtest
42
+ TWILIO*AUTH*TOKEN=testtoken
43
+ TWILIO*FROM*NUMBER=+112345
44
+ TWILIO*TO*NUMBER=+145678
45
45
  ```
46
46
 
47
47
  #### Nexmo
48
48
 
49
49
  ```bash
50
- VONAGE_API_KEY=VN123
51
- VONAGE_API_SECRET=testkey
52
- VONAGE_FROM_NUMBER=+112345
50
+ VONAGE*API*KEY=VN123
51
+ VONAGE*API*SECRET=testkey
52
+ VONAGE*FROM*NUMBER=+112345
53
53
  ```
54
54
 
55
55
  #### Gupshup
56
56
 
57
57
  ```bash
58
- GUPSHUP_USER_ID=GU123
59
- GUPSHUP_PASSWORD=password
58
+ GUPSHUP*USER*ID=GU123
59
+ GUPSHUP*PASSWORD=password
60
60
  ```
61
61
 
62
62
  #### Plivo
63
63
 
64
64
  ```bash
65
- PLIVO_ACCOUNT_ID=PA123
66
- PLIVO_AUTH_TOKEN=testtoken
67
- PLIVO_FROM_NUMBER=+112345
65
+ PLIVO*ACCOUNT*ID=PA123
66
+ PLIVO*AUTH*TOKEN=testtoken
67
+ PLIVO*FROM*NUMBER=+112345
68
68
  ```
69
69
 
70
70
  #### SMS77
71
71
 
72
72
  ```bash
73
- SMS77_API_KEY=SA123
74
- SMS77_FROM=from@example.com
73
+ SMS77*API*KEY=SA123
74
+ SMS77*FROM=from@example.com
75
75
  ```
76
76
 
77
77
  #### SNS
78
78
 
79
79
  ```bash
80
- SMS77_API_KEY=SA123
81
- SMS77_FROM=from@example.com
80
+ SMS77*API*KEY=SA123
81
+ SMS77*FROM=from@example.com
82
82
  ```
83
83
 
84
84
  #### Telnyx
85
85
 
86
86
  ```bash
87
- TELNYX_API_KEY=TA123
88
- TELNYX_MESSAGE_PROFILE_ID=testprofileid
89
- TELNYX_FROM=from@example.com
87
+ TELNYX*API*KEY=TA123
88
+ TELNYX*MESSAGE*PROFILE*ID=testprofileid
89
+ TELNYX*FROM=from@example.com
90
90
  ```
91
91
 
92
92
  #### Termii
93
93
 
94
94
  ```bash
95
- TERMII_API_KEY=TermA123
96
- TERMII_SENDER=from@example.com
95
+ TERMII*API*KEY=TermA123
96
+ TERMII*SENDER=from@example.com
97
97
  ```
98
98
 
99
99
  Learn more in the docs.
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // @bun
2
- var s={};var o={};var r={};var i={};var e={};var n={};var t={};var m={};export{m as twilio,t as termii,n as telnyx,e as sns,i as sms77,r as plivo,o as nexmo,s as gupshup};
2
+ var N=Object.defineProperty;var h=(x)=>x;function D(x,M){this[x]=h.bind(null,M)}var B=(x,M)=>{for(var G in M)N(x,G,{get:M[G],enumerable:!0,configurable:!0,set:D.bind(M,G)})};var q=(x,M)=>()=>(x&&(M=x(x=0)),M);var _={};B(_,{default:()=>c});import{env as Z}from"@stacksjs/env";var c;var H=q(()=>{c={enabled:!1,provider:"twilio",from:String(Z.SMS_FROM_NUMBER||""),defaultCountryCode:"US",messageType:"TRANSACTIONAL",drivers:{twilio:{accountSid:String(Z.TWILIO_ACCOUNT_SID||""),authToken:String(Z.TWILIO_AUTH_TOKEN||""),from:String(Z.TWILIO_FROM_NUMBER||""),messagingServiceSid:String(Z.TWILIO_MESSAGING_SERVICE_SID||"")},vonage:{apiKey:String(Z.VONAGE_API_KEY||""),apiSecret:String(Z.VONAGE_API_SECRET||""),from:String(Z.VONAGE_FROM_NUMBER||"")},pinpoint:{region:String(Z.AWS_REGION||"us-east-1"),accessKeyId:String(Z.AWS_ACCESS_KEY_ID||""),secretAccessKey:String(Z.AWS_SECRET_ACCESS_KEY||""),senderId:String(Z.SMS_SENDER_ID||""),originationNumber:String(Z.SMS_ORIGINATION_NUMBER||"")}},maxSpendPerMonth:100,optOut:{enabled:!0,keywords:["STOP","UNSUBSCRIBE","CANCEL","END","QUIT"]},templates:[],twoWay:{enabled:!1}}});async function C(x,M,G=3){let J=0;while(!0){let L=await fetch(x,M);if(L.status!==429&&L.status!==503)return L;if(J>=G)return L;let X=Number(L.headers.get("retry-after"))||2**J;await new Promise((Q)=>setTimeout(Q,Math.min(X,30)*1000)),J++}}class O{config;verifyServiceSid;constructor(x,M){this.config=x,this.verifyServiceSid=M}async send(x){let M=Array.isArray(x.to)?x.to:[x.to];if(M.length>1)return(await this.sendBulk(M.map((X)=>({...x,to:X}))))[0];let G=M[0],J=x.from||this.config.from;if(!J&&!this.config.messagingServiceSid)return{success:!1,to:G,error:'No "from" number or messaging service SID configured',provider:"twilio"};try{let L=new URLSearchParams;if(L.append("To",G),L.append("Body",x.body),this.config.messagingServiceSid)L.append("MessagingServiceSid",this.config.messagingServiceSid);else if(J)L.append("From",J);if(x.statusCallback||this.config.statusCallback)L.append("StatusCallback",x.statusCallback||this.config.statusCallback);if(x.mediaUrls&&x.mediaUrls.length>0)for(let z of x.mediaUrls)L.append("MediaUrl",z);let X=await C(`https://api.twilio.com/2010-04-01/Accounts/${this.config.accountSid}/Messages.json`,{method:"POST",headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`,"Content-Type":"application/x-www-form-urlencoded"},body:L.toString()}),Q=await X.json();if(!X.ok)return{success:!1,to:G,error:Q.message||`HTTP ${X.status}`,provider:"twilio"};return{success:!0,messageId:Q.sid,status:P(Q.status),to:G,provider:"twilio",segments:Q.num_segments?Number.parseInt(Q.num_segments,10):void 0,price:Q.price?Math.abs(Number.parseFloat(Q.price)):void 0,currency:Q.price_unit}}catch(L){return{success:!1,to:G,error:L instanceof Error?L.message:"Unknown error",provider:"twilio"}}}async sendBulk(x){return Promise.all(x.map((M)=>this.send({...M,to:Array.isArray(M.to)?M.to[0]:M.to})))}async getStatus(x){let M=await fetch(`https://api.twilio.com/2010-04-01/Accounts/${this.config.accountSid}/Messages/${x}.json`,{headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`}});if(!M.ok)throw Error(`Twilio message status API error: ${M.status}`);let G=await M.json();return{messageId:G.sid,to:G.to,status:P(G.status),timestamp:new Date(G.date_updated||G.date_created),errorCode:G.error_code?.toString(),errorMessage:G.error_message}}async verify(x){try{let M=await fetch(`https://lookups.twilio.com/v2/PhoneNumbers/${encodeURIComponent(x)}?Fields=line_type_intelligence`,{headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`}});if(!M.ok)return{valid:!1};let G=await M.json();return{valid:G.valid,carrier:G.line_type_intelligence?.carrier_name,type:G.line_type_intelligence?.type}}catch{return{valid:!1}}}async getBalance(){let x=await fetch(`https://api.twilio.com/2010-04-01/Accounts/${this.config.accountSid}/Balance.json`,{headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`}});if(!x.ok)throw Error(`Twilio balance API error: ${x.status}`);let M=await x.json();return{balance:Number.parseFloat(M.balance),currency:M.currency}}async startVerification(x){if(!this.verifyServiceSid)return{success:!1,status:"denied",error:"Verify service SID not configured"};try{let M=new URLSearchParams;if(M.append("To",x.to),M.append("Channel",x.channel||"sms"),x.locale)M.append("Locale",x.locale);if(x.customMessage)M.append("CustomMessage",x.customMessage);let G=await fetch(`https://verify.twilio.com/v2/Services/${this.verifyServiceSid}/Verifications`,{method:"POST",headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`,"Content-Type":"application/x-www-form-urlencoded"},body:M.toString()}),J=await G.json();if(!G.ok)return{success:!1,status:"denied",error:J.message||`HTTP ${G.status}`};return{success:!0,verificationId:J.sid,status:J.status==="pending"?"pending":"denied"}}catch(M){return{success:!1,status:"denied",error:M instanceof Error?M.message:"Unknown error"}}}async checkVerification(x){if(!this.verifyServiceSid)return{success:!1,status:"denied",error:"Verify service SID not configured"};try{let M=new URLSearchParams;M.append("To",x.to),M.append("Code",x.code);let G=await fetch(`https://verify.twilio.com/v2/Services/${this.verifyServiceSid}/VerificationCheck`,{method:"POST",headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`,"Content-Type":"application/x-www-form-urlencoded"},body:M.toString()}),J=await G.json();if(!G.ok)return{success:!1,status:"denied",error:J.message||`HTTP ${G.status}`};return{success:J.status==="approved",verificationId:J.sid,status:J.status==="approved"?"approved":"denied"}}catch(M){return{success:!1,status:"denied",error:M instanceof Error?M.message:"Unknown error"}}}async cancelVerification(x){if(!this.verifyServiceSid)return!1;try{let M=new URLSearchParams;return M.append("Status","canceled"),(await fetch(`https://verify.twilio.com/v2/Services/${this.verifyServiceSid}/Verifications/${x}`,{method:"POST",headers:{Authorization:`Basic ${btoa(`${this.config.accountSid}:${this.config.authToken}`)}`,"Content-Type":"application/x-www-form-urlencoded"},body:M.toString()})).ok}catch{return!1}}}function P(x){return{queued:"queued",sending:"sending",sent:"sent",delivered:"delivered",undelivered:"undelivered",failed:"failed",canceled:"failed"}[x]||"unknown"}function y(x,M){return new O(x,M)}var T={};B(T,{default:()=>F,createVonageDriver:()=>A,VonageDriver:()=>F});class F{config;useMessagesApi;constructor(x,M=!1){this.config=x,this.useMessagesApi=M}async send(x){let M=Array.isArray(x.to)?x.to:[x.to];if(M.length>1)return(await this.sendBulk(M.map((X)=>({...x,to:X}))))[0];let G=M[0],J=x.from||this.config.from;if(!J)return{success:!1,to:G,error:'No "from" number configured',provider:"vonage"};if(!/^\+?[1-9]\d{1,14}$/.test(G))return{success:!1,to:G,error:`Invalid E.164 phone number: ${G}. Expected +<country><number> with 8\u201315 digits.`,provider:"vonage"};try{if(this.useMessagesApi)return await this.sendWithMessagesApi(G,J,x);return await this.sendWithSmsApi(G,J,x)}catch(L){return{success:!1,to:G,error:L instanceof Error?L.message:"Unknown error",provider:"vonage"}}}async sendWithSmsApi(x,M,G){let J=new URLSearchParams;if(J.append("api_key",this.config.apiKey),J.append("api_secret",this.config.apiSecret),J.append("to",x),J.append("from",M),J.append("text",G.body),G.statusCallback)J.append("callback",G.statusCallback);let L=await fetch("https://rest.nexmo.com/sms/json",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:J.toString()});if(!L.ok)throw Error(`Vonage SMS API error: ${L.status}`);let X=await L.json();if(X.messages&&X.messages.length>0){let Q=X.messages[0];if(Q.status!=="0")return{success:!1,to:x,error:Q["error-text"]||`Status: ${Q.status}`,provider:"vonage"};return{success:!0,messageId:Q["message-id"],status:"sent",to:x,provider:"vonage",price:Q["message-price"]?Number.parseFloat(Q["message-price"]):void 0,currency:"EUR"}}return{success:!1,to:x,error:"No response from Vonage",provider:"vonage"}}async sendWithMessagesApi(x,M,G){let J={"Content-Type":"application/json"},L;if(this.config.applicationId&&this.config.privateKey)L=`Bearer ${await this.generateJwt()}`;else L=`Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}`;J.Authorization=L;let X={message_type:"text",channel:"sms",to:x,from:M,text:G.body};if(G.statusCallback)X.webhook_url=G.statusCallback;let Q=await fetch("https://api.nexmo.com/v1/messages",{method:"POST",headers:J,body:JSON.stringify(X)}),z=await Q.json();if(!Q.ok)return{success:!1,to:x,error:z.title||z.detail||`HTTP ${Q.status}`,provider:"vonage"};return{success:!0,messageId:z.message_uuid,status:"sent",to:x,provider:"vonage"}}async sendBulk(x){return Promise.all(x.map((M)=>this.send({...M,to:Array.isArray(M.to)?M.to[0]:M.to})))}async getStatus(x){let M={};if(this.config.applicationId&&this.config.privateKey){let L=await this.generateJwt();M.Authorization=`Bearer ${L}`}else M.Authorization=`Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}`;let G=await fetch(`https://api.nexmo.com/v1/messages/${x}`,{headers:M});if(!G.ok)throw Error(`Vonage message status API error: ${G.status}`);let J=await G.json();return{messageId:J.message_uuid,to:J.to,status:b(J.status),timestamp:new Date(J.timestamp),errorCode:J.error?.code?.toString(),errorMessage:J.error?.reason}}async verify(x){try{let M=new URLSearchParams;M.append("api_key",this.config.apiKey),M.append("api_secret",this.config.apiSecret),M.append("number",x);let G=await fetch("https://rest.nexmo.com/ni/basic/json",{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:M.toString()});if(!G.ok)throw Error(`Vonage number insight API error: ${G.status}`);let J=await G.json();if(J.status!==0)return{valid:!1};return{valid:!0,carrier:J.current_carrier?.name,type:J.current_carrier?.network_type}}catch{return{valid:!1}}}async getBalance(){let x=typeof Buffer<"u"?Buffer.from(`${this.config.apiKey}:${this.config.apiSecret}`).toString("base64"):btoa(`${this.config.apiKey}:${this.config.apiSecret}`),M=await fetch("https://rest.nexmo.com/account/get-balance",{headers:{Authorization:`Basic ${x}`}});if(!M.ok)throw Error(`Vonage balance API error: ${M.status}`);return{balance:(await M.json()).value,currency:"EUR"}}async startVerification(x){try{let M={"Content-Type":"application/json"};if(this.config.applicationId&&this.config.privateKey){let X=await this.generateJwt();M.Authorization=`Bearer ${X}`}else M.Authorization=`Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}`;let G={brand:this.config.from||"Verification",workflow:[{channel:x.channel==="whatsapp"?"whatsapp_interactive":"sms",to:x.to}]};if(x.codeLength)G.code_length=x.codeLength;if(x.locale)G.locale=x.locale;let J=await fetch("https://api.nexmo.com/v2/verify",{method:"POST",headers:M,body:JSON.stringify(G)}),L=await J.json();if(!J.ok)return{success:!1,status:"denied",error:L.title||L.detail||`HTTP ${J.status}`};return{success:!0,verificationId:L.request_id,status:"pending"}}catch(M){return{success:!1,status:"denied",error:M instanceof Error?M.message:"Unknown error"}}}async checkVerification(x){if(!x.verificationId)return{success:!1,status:"denied",error:"Verification ID is required"};try{let M={"Content-Type":"application/json"};if(this.config.applicationId&&this.config.privateKey){let L=await this.generateJwt();M.Authorization=`Bearer ${L}`}else M.Authorization=`Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}`;let G=await fetch(`https://api.nexmo.com/v2/verify/${x.verificationId}`,{method:"POST",headers:M,body:JSON.stringify({code:x.code})}),J=await G.json();if(!G.ok)return{success:!1,status:"denied",error:J.title||J.detail||`HTTP ${G.status}`};return{success:J.status==="completed",verificationId:x.verificationId,status:J.status==="completed"?"approved":"denied"}}catch(M){return{success:!1,status:"denied",error:M instanceof Error?M.message:"Unknown error"}}}async cancelVerification(x){try{let M={};if(this.config.applicationId&&this.config.privateKey){let J=await this.generateJwt();M.Authorization=`Bearer ${J}`}else M.Authorization=`Basic ${btoa(`${this.config.apiKey}:${this.config.apiSecret}`)}`;return(await fetch(`https://api.nexmo.com/v2/verify/${x}`,{method:"DELETE",headers:M})).ok}catch{return!1}}async generateJwt(){if(!this.config.applicationId||!this.config.privateKey)throw Error("Application ID and private key required for JWT auth");let x={typ:"JWT",alg:"RS256"},M=Math.floor(Date.now()/1000),G={application_id:this.config.applicationId,iat:M,exp:M+900,jti:crypto.randomUUID()},J=btoa(JSON.stringify(x)),L=btoa(JSON.stringify(G));return`${J}.${L}.signature`}}function b(x){return{submitted:"queued",delivered:"delivered",expired:"undelivered",failed:"failed",rejected:"failed",accepted:"sent"}[x]||"unknown"}function A(x,M=!1){return new F(x,M)}var W=null,E=null,Y={},R=null;async function S(){try{Y=(await Promise.resolve().then(() => (H(),_))).default}catch{}}async function $(){if(!R)R=S();await R}function l(x){Y={...Y,...x},W=null,E=null}function U(x){let M=x||Y.provider||"twilio";switch(M){case"twilio":{let G=Y.drivers?.twilio;if(!G?.accountSid||!G?.authToken)throw Error("Twilio configuration is incomplete. Please provide accountSid and authToken.");return new O({...G,from:G.from||Y.from})}case"vonage":{let G=Y.drivers?.vonage;if(!G?.apiKey||!G?.apiSecret)throw Error("Vonage configuration is incomplete. Please provide apiKey and apiSecret.");return new F({...G,from:G.from||Y.from})}default:throw Error(`Unsupported SMS provider: ${M}`)}}function I(x){let M=U(x);if(!("startVerification"in M))throw Error(`Provider does not support verification: ${x||Y.provider}`);return M}function K(){if(!W)W=U();return W}function j(){if(!E)E=I();return E}async function k(x){return await $(),K().send(x)}var p=k;async function v(x){return await $(),K().sendBulk(x)}async function f(x){await $();let M=K();if(M.getStatus)return M.getStatus(x);return null}async function u(x){await $();let M=K();if(M.verify)return M.verify(x);return{valid:!0}}async function m(){await $();let x=K();if(x.getBalance)return x.getBalance();return null}async function g(x){return await $(),j().startVerification(x)}async function d(x){return await $(),j().checkVerification(x)}async function n(x){await $();let M=j();if(M.cancelVerification)return M.cancelVerification(x);return!1}class V{message={};provider;to(x){return this.message.to=x,this}body(x){return this.message.body=x,this}text(x){return this.body(x)}from(x){return this.message.from=x,this}media(x){return this.message.mediaUrls=Array.isArray(x)?x:[x],this}callback(x){return this.message.statusCallback=x,this}via(x){return this.provider=x,this}async send(){if(await $(),!this.message.to)return{success:!1,to:"",error:"Recipient is required",provider:this.provider||Y.provider||"twilio"};if(!this.message.body)return{success:!1,to:Array.isArray(this.message.to)?this.message.to[0]:this.message.to,error:"Message body is required",provider:this.provider||Y.provider||"twilio"};return(this.provider?U(this.provider):K()).send(this.message)}}function i(){return new V}async function o(x,M,G={}){await $();let J=Y.templates?.find((X)=>X.name===M);if(!J)return{success:!1,to:Array.isArray(x)?x[0]:x,error:`Template not found: ${M}`,provider:Y.provider||"twilio"};let L=J.body;for(let[X,Q]of Object.entries(G)){let z=X.replace(/[.*+?^${}()|[\]\\]/g,"\\$&");L=L.replace(new RegExp(`\\{${z}\\}`,"g"),Q)}return k({to:x,body:L})}function w(x,M){let G=x.replace(/[\s\-()]/g,"");if(G.startsWith("+"))return G;let J=M||Y.defaultCountryCode||"1";if(G.startsWith("00"))G=`+${G.slice(2)}`;else if(!G.startsWith("+"))G=`+${J}${G}`;return G}function t(x){let M=/^\+[1-9]\d{6,14}$/,G=w(x);return M.test(G)}async function a(){await S()}function r(){return Y.enabled===!0}function s(){return{...Y}}var e={init:a,configure:l,isEnabled:r,getConfig:s,send:k,sendSms:p,sendBulk:v,sendTemplate:o,getStatus:f,getBalance:m,verifyNumber:u,startVerification:g,checkVerification:d,cancelVerification:n,formatE164:w,isValidPhoneNumber:t,sms:i,getDriver:U,getVerificationDriver:I},xx=e;export{u as verifyNumber,g as startVerification,i as sms,o as sendTemplate,p as sendSms,v as sendBulk,k as send,T as nexmo,t as isValidPhoneNumber,r as isEnabled,a as init,I as getVerificationDriver,f as getStatus,U as getDriver,s as getConfig,m as getBalance,w as formatE164,A as createVonageDriver,y as createTwilioDriver,l as configure,d as checkVerification,n as cancelVerification,F as VonageDriver,O as TwilioDriver,V as SmsBuilder,xx as SMS};
@@ -0,0 +1,5 @@
1
+ // Primary SMS Drivers
2
+ export * from './twilio';
3
+ export * from './vonage';
4
+ // Legacy driver aliases
5
+ export * as nexmo from './vonage';
@@ -0,0 +1,17 @@
1
+ import type { SmsDriver, SmsMessage, SmsSendResult, SmsStatusUpdate, SmsVerificationDriver, TwilioConfig, VerificationCheckRequest, VerificationRequest, VerificationResult } from '@stacksjs/types';
2
+ // =============================================================================
3
+ // Factory Function
4
+ // =============================================================================
5
+ export declare function createTwilioDriver(config: TwilioConfig, verifyServiceSid?: string): TwilioDriver;
6
+ export declare class TwilioDriver implements SmsDriver, SmsVerificationDriver {
7
+ constructor(config: TwilioConfig, verifyServiceSid?: string);
8
+ send(message: SmsMessage): Promise<SmsSendResult>;
9
+ sendBulk(messages: SmsMessage[]): Promise<SmsSendResult[]>;
10
+ getStatus(messageId: string): Promise<SmsStatusUpdate>;
11
+ verify(phoneNumber: string): Promise<{ valid: boolean, carrier?: string, type?: string }>;
12
+ getBalance(): Promise<{ balance: number, currency: string }>;
13
+ startVerification(request: VerificationRequest): Promise<VerificationResult>;
14
+ checkVerification(request: VerificationCheckRequest): Promise<VerificationResult>;
15
+ cancelVerification(verificationId: string): Promise<boolean>;
16
+ }
17
+ export { TwilioDriver as default };
@@ -0,0 +1,17 @@
1
+ import type { SmsDriver, SmsMessage, SmsSendResult, SmsStatusUpdate, SmsVerificationDriver, VerificationCheckRequest, VerificationRequest, VerificationResult, VonageConfig } from '@stacksjs/types';
2
+ // =============================================================================
3
+ // Factory Function
4
+ // =============================================================================
5
+ export declare function createVonageDriver(config: VonageConfig, useMessagesApi?: boolean): VonageDriver;
6
+ export declare class VonageDriver implements SmsDriver, SmsVerificationDriver {
7
+ constructor(config: VonageConfig, useMessagesApi?: boolean);
8
+ send(message: SmsMessage): Promise<SmsSendResult>;
9
+ sendBulk(messages: SmsMessage[]): Promise<SmsSendResult[]>;
10
+ getStatus(messageId: string): Promise<SmsStatusUpdate>;
11
+ verify(phoneNumber: string): Promise<{ valid: boolean, carrier?: string, type?: string }>;
12
+ getBalance(): Promise<{ balance: number, currency: string }>;
13
+ startVerification(request: VerificationRequest): Promise<VerificationResult>;
14
+ checkVerification(request: VerificationCheckRequest): Promise<VerificationResult>;
15
+ cancelVerification(verificationId: string): Promise<boolean>;
16
+ }
17
+ export { VonageDriver as default };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * SMS Package
3
+ *
4
+ * Provides SMS messaging capabilities with support for multiple providers.
5
+ */
6
+ // Main SMS facade
7
+ export * from './sms';
8
+ export { default as SMS } from './sms';
9
+ // Drivers
10
+ export * from './drivers';
11
+ export { TwilioDriver, createTwilioDriver } from './drivers/twilio';
12
+ export { VonageDriver, createVonageDriver } from './drivers/vonage';
@@ -0,0 +1,97 @@
1
+ import type { SmsDriver, SmsMessage, SmsOptions, SmsProvider, SmsSendResult, SmsStatusUpdate, SmsVerificationDriver, VerificationCheckRequest, VerificationRequest, VerificationResult } from '@stacksjs/types';
2
+ /**
3
+ * Configure the SMS system
4
+ */
5
+ export declare function configure(config: Partial<SmsOptions>): void;
6
+ /**
7
+ * Get the default SMS driver based on configuration
8
+ */
9
+ export declare function getDriver(provider?: SmsProvider): SmsDriver;
10
+ /**
11
+ * Get the verification driver
12
+ */
13
+ export declare function getVerificationDriver(provider?: SmsProvider): SmsVerificationDriver;
14
+ /**
15
+ * Send an SMS message
16
+ */
17
+ export declare function send(message: SmsMessage): Promise<SmsSendResult>;
18
+ /**
19
+ * Send multiple SMS messages
20
+ */
21
+ export declare function sendBulk(messages: SmsMessage[]): Promise<SmsSendResult[]>;
22
+ /**
23
+ * Get message status
24
+ */
25
+ export declare function getStatus(messageId: string): Promise<SmsStatusUpdate | null>;
26
+ /**
27
+ * Verify a phone number format and carrier
28
+ */
29
+ export declare function verifyNumber(phoneNumber: string): Promise<{ valid: boolean, carrier?: string, type?: string }>;
30
+ /**
31
+ * Get account balance
32
+ */
33
+ export declare function getBalance(): Promise<{ balance: number, currency: string } | null>;
34
+ /**
35
+ * Start a phone verification (send OTP)
36
+ */
37
+ export declare function startVerification(request: VerificationRequest): Promise<VerificationResult>;
38
+ /**
39
+ * Check a verification code
40
+ */
41
+ export declare function checkVerification(request: VerificationCheckRequest): Promise<VerificationResult>;
42
+ /**
43
+ * Cancel a pending verification
44
+ */
45
+ export declare function cancelVerification(verificationId: string): Promise<boolean>;
46
+ /**
47
+ * Create a new SMS builder
48
+ */
49
+ export declare function sms(): SmsBuilder;
50
+ /**
51
+ * Send an SMS using a template
52
+ */
53
+ export declare function sendTemplate(to: string | string[], templateName: string, variables?: Record<string, string>): Promise<SmsSendResult>;
54
+ /**
55
+ * Format a phone number to E.164 format
56
+ */
57
+ export declare function formatE164(phoneNumber: string, defaultCountryCode?: string): string;
58
+ /**
59
+ * Check if a phone number appears valid
60
+ */
61
+ export declare function isValidPhoneNumber(phoneNumber: string): boolean;
62
+ /**
63
+ * Initialize the SMS system (loads config)
64
+ */
65
+ export declare function init(): Promise<void>;
66
+ /**
67
+ * Check if SMS is enabled in config
68
+ */
69
+ export declare function isEnabled(): boolean;
70
+ /**
71
+ * Get the current SMS configuration
72
+ */
73
+ export declare function getConfig(): Partial<SmsOptions>;
74
+ /**
75
+ * Send an SMS message (alias)
76
+ */
77
+ export declare const sendSms: unknown;
78
+ // =============================================================================
79
+ // SMS Facade Object
80
+ // =============================================================================
81
+ export declare const SMS: {
82
+
83
+ };
84
+ // =============================================================================
85
+ // SMS Builder (Fluent API)
86
+ // =============================================================================
87
+ export declare class SmsBuilder {
88
+ to(phoneNumber: string | string[]): this;
89
+ body(text: string): this;
90
+ text(text: string): this;
91
+ from(sender: string): this;
92
+ media(urls: string | string[]): this;
93
+ callback(url: string): this;
94
+ via(provider: SmsProvider): this;
95
+ send(): Promise<SmsSendResult>;
96
+ }
97
+ export default SMS;
package/package.json CHANGED
@@ -1,10 +1,12 @@
1
1
  {
2
2
  "name": "@stacksjs/sms",
3
3
  "type": "module",
4
- "version": "0.70.23",
4
+ "version": "0.70.25",
5
5
  "description": "The Stacks SMS integration. Painlessly create & manage your inboxes, templates, and send sms.",
6
6
  "author": "Chris Breuer",
7
- "contributors": ["Chris Breuer <chris@stacksjs.org>"],
7
+ "contributors": [
8
+ "Chris Breuer <chris@stacksjs.com>"
9
+ ],
8
10
  "license": "MIT",
9
11
  "funding": "https://github.com/sponsors/chrisbbreuer",
10
12
  "homepage": "https://github.com/stacksjs/stacks/tree/main/storage/framework/core/sms#readme",
@@ -30,25 +32,31 @@
30
32
  ],
31
33
  "exports": {
32
34
  ".": {
35
+ "bun": "./src/index.ts",
36
+ "types": "./dist/index.d.ts",
33
37
  "import": "./dist/index.js"
34
38
  },
35
39
  "./*": {
40
+ "bun": "./src/*",
36
41
  "import": "./dist/*"
37
42
  }
38
43
  },
39
44
  "module": "dist/index.js",
40
45
  "types": "dist/index.d.ts",
41
- "files": ["README.md", "dist"],
46
+ "files": [
47
+ "README.md",
48
+ "dist"
49
+ ],
42
50
  "scripts": {
43
51
  "build": "bun build.ts",
44
52
  "typecheck": "bun tsc --noEmit",
45
53
  "prepublishOnly": "bun run build"
46
54
  },
47
55
  "devDependencies": {
48
- "@stacksjs/cli": "0.70.22",
49
- "@stacksjs/config": "0.70.22",
50
- "@stacksjs/development": "0.70.22",
51
- "@stacksjs/error-handling": "0.70.22",
52
- "@stacksjs/types": "0.70.22"
56
+ "@stacksjs/cli": "0.70.23",
57
+ "@stacksjs/config": "0.70.23",
58
+ "better-dx": "^0.2.12",
59
+ "@stacksjs/error-handling": "0.70.23",
60
+ "@stacksjs/types": "0.70.23"
53
61
  }
54
62
  }
package/dist/index.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from './drivers'