Skip to main content

stacks-sms

Use when implementing SMS in Stacks - sending text messages, the SmsBuilder fluent API, SMS templates, phone verification (OTP/2FA), bulk sending, Twilio/Vonage drivers, E.164 formatting, or the SMS facade. Covers @stacksjs/sms and config/sms.ts.

소스 정보

저장소
stacksjs/stacks
최근 소스 활동
2026년 10월 11일 22:22
감지된 SKILL.md 언어
영어
스타
636
포크
20

설치 방법

기본적으로 소스를 먼저 확인하는 Prompt가 선택됩니다. 직접 명령으로 전환하거나 로컬 사본을 다운로드할 수도 있습니다.

소스 파일 검토

설치 여부를 결정하기 전에 SKILL.md와 SkillsMP에 표시된 보조 파일을 읽어 보세요.

SKILL.md 표시 중

SKILL.md
소스 지침 · 읽기 전용 미리보기
name
stacks-sms
description
Use when implementing SMS in Stacks - sending text messages, the SmsBuilder fluent API, SMS templates, phone verification (OTP/2FA), bulk sending, Twilio/Vonage drivers, E.164 formatting, or the SMS facade. Covers @stacksjs/sms and config/sms.ts.
license
MIT
compatibility
Bun >= 1.3.0, TypeScript
allowed-tools
Read Edit Write Bash Grep Glob
# Stacks SMS Multi-driver SMS system with verification (OTP), templates, bulk sending, and a fluent builder API. Two fully implemented drivers: Twilio and Vonage. ## Key Paths - Core package: `storage/framework/core/sms/src/` - SMS facade and builder: `storage/framework/core/sms/src/sms.ts` - Twilio driver: `storage/framework/core/sms/src/drivers/twilio.ts` - Vonage driver: `storage/framework/core/sms/src/drivers/vonage.ts` - Drivers index: `storage/framework/core/sms/src/drivers/index.ts` - Configuration: `config/sms.ts` ## Package Exports ```typescript // Main facade and functions import { SMS, sms, send, sendSms, sendBulk, sendTemplate } from '@stacksjs/sms' import { startVerification, checkVerification, cancelVerification } from '@stacksjs/sms' import { formatE164, isValidPhoneNumber, isEnabled, getConfig, configure, getDriver, init } from '@stacksjs/sms' import { SmsBuilder } from '@stacksjs/sms' // Drivers import { TwilioDriver, createTwilioDriver } from '@stacksjs/sms' import { VonageDriver, createVonageDriver } from '@stacksjs/sms' ``` ## SMS Facade Object The named `SMS` export aggregates the SMS facade functions: ```typescript SMS.init() // Load config from config/sms.ts SMS.configure(config) // Override config at runtime SMS.isEnabled() // Check if SMS is enabled (config.enabled) SMS.getConfig() // Get current config (returns copy) SMS.send(message) // Send single SMS SMS.sendSms(message) // Alias for send SMS.sendBulk(messages) // Send multiple SMS SMS.sendTemplate(to, name, vars) // Send using template SMS.getStatus(messageId) // Get delivery status SMS.getBalance() // Get account balance SMS.verifyNumber(phone) // Lookup/verify phone number SMS.startVerification(req) // Start OTP flow SMS.checkVerification(req) // Verify OTP code SMS.cancelVerification(id) // Cancel pending verification SMS.formatE164(phone, cc?) // Format to E.164 SMS.isValidPhoneNumber(phone) // Validate E.164 format SMS.sms() // Create SmsBuilder instance SMS.getDriver(provider?) // Get driver instance SMS.getVerificationDriver(p?) // Get verification driver ``` ## SmsBuilder (Fluent API) ```typescript import { sms } from '@stacksjs/sms' // Basic SMS await sms() .to('+1234567890') .body('Your code is 123456') .from('+0987654321') .send() // With provider selection await sms() .to('+1234567890') .body('Hello!') .via('vonage') .send() // MMS with media and callback await sms() .to(['+1111111111', '+2222222222']) .body('Check this out') .media(['https://example.com/image.jpg']) .callback('https://myapp.com/sms/status') .send() // .text() is an alias for .body() await sms() .to('+1234567890') .text('Hello!') .send() ``` The builder validates that `to` and `body` are set before sending. If missing, it returns a failed `SmsSendResult` without throwing. If `.via(provider)` is set, it creates a new driver for that provider; otherwise uses the default driver. ## Direct Send Functions ```typescript import { send, sendBulk } from '@stacksjs/sms' // SmsMessage shape await send({ to: '+1234567890', // string or string[] body: 'Hello!', from: '+0987654321', // optional, falls back to config mediaUrls: ['url'], // optional, for MMS statusCallback: 'url', // optional, webhook for status updates }) // Bulk send await sendBulk([msg1, msg2, msg3]) // returns SmsSendResult[] ``` `send()` and all sending functions call `ensureConfig()` first, which lazily loads `config/sms.ts` via dynamic import. Runtime `configure()` overrides survive that lazy load and subsequent `init()` calls, including credentials supplied before the first send. ## Message Status & Info ```typescript import { getStatus, verifyNumber, getBalance } from '@stacksjs/sms' // Get delivery status for a message const status = await getStatus('SM_message_id') // Returns SmsStatusUpdate | null (null if driver doesn't support it) // Verify/lookup a phone number const info = await verifyNumber('+1234567890') // Returns { valid: boolean, carrier?: string, type?: string } // Get account balance const balance = await getBalance() // Returns { balance: number, currency: string } | null ``` ## Phone Verification (OTP/2FA) ```typescript import { startVerification, checkVerification, cancelVerification } from '@stacksjs/sms' // Start -- sends OTP code via SMS (or 'call', 'email' for Twilio; 'sms', 'whatsapp' for Vonage) const result = await startVerification({ to: '+1234567890', channel: 'sms', // default: 'sms' codeLength: 6, // optional locale: 'en', // optional customMessage: 'Your code: {code}', // optional, Twilio only }) // Returns { success: boolean, verificationId?: string, status: 'pending' | 'denied', error?: string } // Check -- verify the code the user entered const check = await checkVerification({ to: '+1234567890', // Twilio requires 'to' verificationId: result.verificationId, // Vonage requires this code: '123456', }) // Returns { success: boolean, verificationId?: string, status: 'approved' | 'denied', error?: string } // Cancel -- cancel a pending verification const cancelled = await cancelVerification(result.verificationId!) // Returns boolean ``` **Twilio** uses the Verify service (`verify.twilio.com/v2`) and requires `verifyServiceSid` passed to the TwilioDriver constructor. **Vonage** uses the Verify V2 API (`api.nexmo.com/v2/verify`). Whatsapp channel maps to `whatsapp_interactive`. ## SMS Templates ```typescript import { sendTemplate } from '@stacksjs/sms' await sendTemplate('+1234567890', 'order-confirmation', { orderNumber: '#12345', total: '$29.99', }) ``` Templates are defined in `config/sms.ts` under `templates[]`. Each template has `name`, `body`, and optional `variables`. Variables use single-brace syntax `{variableName}` in the template body. The function finds the template by name, replaces variables, and sends via the default driver. Returns a failed result (without throwing) if the template is not found. ## Phone Number Utilities ```typescript import { formatE164, isValidPhoneNumber } from '@stacksjs/sms' // Normalize to E.164 format formatE164('+1 (234) 567-8900') // '+12345678900' formatE164('2345678900', '1') // '+12345678900' formatE164('002345678900') // '+2345678900' (00 prefix stripped) // Validate E.164 format (regex: /^\+[1-9]\d{6,14}$/) isValidPhoneNumber('+1234567890') // true isValidPhoneNumber('1234567890') // true (formatted first, then validated) ``` `formatE164()` strips spaces, dashes, and parentheses. If the number starts with `+`, returns as-is. If it starts with `00`, replaces with `+`. Otherwise prepends `+` and the default country code (from `config.defaultCountryCode` or `'1'` for US). ## Twilio Driver ```typescript import { TwilioDriver, createTwilioDriver } from '@stacksjs/sms' const driver = new TwilioDriver({ accountSid: 'AC...', authToken: '...', from: '+1234567890', messagingServiceSid: 'MG...', // optional, used instead of 'from' statusCallback: 'https://...', // optional, default callback URL }, 'VA_verify_service_sid') // optional second arg for verification // Or use factory const driver = createTwilioDriver(config, verifyServiceSid?) ``` Uses REST API at `https://api.twilio.com/2010-04-01`. Auth via HTTP Basic (`accountSid:authToken`). Features: - `send(message)` -- sends via Messages API, supports MMS (mediaUrls), statusCallback, messagingServiceSid - `sendBulk(messages)` -- sends in parallel via `Promise.all` - `getStatus(messageId)` -- retrieves message status - `verify(phoneNumber)` -- uses Twilio Lookup API v2 with line_type_intelligence - `getBalance()` -- retrieves account balance - `startVerification(req)` -- Twilio Verify service - `checkVerification(req)` -- check OTP code - `cancelVerification(id)` -- cancel pending verification Status mapping: queued, sending, sent, delivered, undelivered -> `SmsStatus`; canceled -> 'failed'. ## Vonage Driver ```typescript import { VonageDriver, createVonageDriver } from '@stacksjs/sms' const driver = new VonageDriver({ apiKey: '...', apiSecret: '...', from: 'MyApp', applicationId: '...', // optional, for JWT auth privateKey: '...', // optional, for JWT auth }, true) // optional: useMessagesApi (default: false) // Or use factory const driver = createVonageDriver(config, useMessagesApi?) ``` Two send modes: - **SMS API** (legacy, default) -- `https://rest.nexmo.com/sms/json`, uses API key/secret in body - **Messages API** (newer) -- `https://api.nexmo.com/v1/messages`, uses Basic auth or JWT Features: - `send(message)` -- sends via chosen API mode - `sendBulk(messages)` -- sends in parallel - `getStatus(messageId)` -- Messages API only - `verify(phoneNumber)` -- Vonage Number Insight API (basic) - `getBalance()` -- account balance in EUR - `startVerification(req)` -- Vonage Verify V2 API - `checkVerification(req)` -- requires `verificationId` - `cancelVerification(id)` -- DELETE request to cancel The `nexmo` export is a legacy alias for `vonage`. ## Other Drivers (Commented Out / Placeholder) The `drivers/` directory contains placeholder files for: `gupshup`, `nexmo` (alias for vonage), `plivo`, `sms77`, `sns`, `telnyx`, `termii`. These are all commented out and not functional. Only Twilio and Vonage are active. ## config/sms.ts ```typescript { enabled: false, // Must explicitly enable provider: 'twilio', // 'twilio' | 'vonage' from: env.SMS_FROM_NUMBER || '', defaultCountryCode: '1', messageType: 'TRANSACTIONAL', // TRANSACTIONAL or PROMOTIONAL drivers: { twilio: { accountSid: env.TWILIO_ACCOUNT_SID || '', authToken: env.TWILIO_AUTH_TOKEN || '', from: env.TWILIO_FROM_NUMBER || '', messagingServiceSid: env.TWILIO_MESSAGING_SERVICE_SID || '', }, vonage: { apiKey: env.VONAGE_API_KEY || '', apiSecret: env.VONAGE_API_SECRET || '', from: env.VONAGE_FROM_NUMBER || '', }, pinpoint: { region: env.AWS_REGION || 'us-east-1', accessKeyId: env.AWS_ACCESS_KEY_ID || '', secretAccessKey: env.AWS_SECRET_ACCESS_KEY || '', senderId: env.SMS_SENDER_ID || '', originationNumber: env.SMS_ORIGINATION_NUMBER || '', }, }, maxSpendPerMonth: 100, optOut: { enabled: true, keywords: ['STOP', 'UNSUBSCRIBE', 'CANCEL', 'END', 'QUIT'], }, templates: [], // Array of { name, body, variables } twoWay: { enabled: false, }, } satisfies SmsConfig ``` ## Type Interfaces (from @stacksjs/types) ```typescript interface SmsMessage { to: string | string[] body: string from?: string mediaUrls?: string[] statusCallback?: string } interface SmsSendResult { success: boolean messageId?: string status?: SmsStatus to: string provider: string error?: string segments?: number price?: number currency?: string } type SmsStatus = 'queued' | 'sending' | 'sent' | 'delivered' | 'undelivered' | 'failed' | 'unknown' interface SmsStatusUpdate { messageId: string to: string status: SmsStatus timestamp: Date errorCode?: string errorMessage?: string } type SmsProvider = 'twilio' | 'vonage' | 'pinpoint' interface VerificationRequest { to: string channel?: string // 'sms' | 'call' | 'email' | 'whatsapp' codeLength?: number locale?: string
GitHub에서 보기
이 SKILL.md는 매우 커서 SkillsMP가 여기에는 첫 섹션만 미리 보여줍니다. GitHub에서 보기