{"_id":"@ciphercross/nestjs-twilio-otp","_rev":"2-59862c6256ad83bbc437c26f340e90e7","name":"@ciphercross/nestjs-twilio-otp","dist-tags":{"latest":"1.0.1"},"versions":{"1.0.0":{"name":"@ciphercross/nestjs-twilio-otp","version":"1.0.0","keywords":["nestjs","twilio","otp","sms","verification","authentication"],"author":{"name":"Viktoriia Scherba","email":"viktoriia.scherba"},"license":"MIT","_id":"@ciphercross/nestjs-twilio-otp@1.0.0","maintainers":[{"name":"mykyta-ciphercross","email":"mykyta.shevchenko@ciphercross.com"},{"name":"viktoriia.scherba","email":"viktoriia.scherba@ciphercross.com"}],"homepage":"https://github.com/CipherCross/nestjs-twilio-otp#readme","bugs":{"url":"https://github.com/CipherCross/nestjs-twilio-otp/issues"},"dist":{"shasum":"084c0389067090f925b7b5365e08221bc01c17ba","tarball":"https://registry.npmjs.org/@ciphercross/nestjs-twilio-otp/-/nestjs-twilio-otp-1.0.0.tgz","fileCount":19,"integrity":"sha512-zuaElLxlp6IyEJSLrXUvgvp/moqvl8Cp60odB2qwSFviSQ3FsER1W22s/KKWI48dL9Qsusvzx1Gt1HjPtj9Ojw==","signatures":[{"sig":"MEUCIQD3RqClZvm3Qiy0+Ff0sArR8pBfpDEp3hbTY8cVTrnF0AIgE9sJTHUpCfWKfRLMDbIrj3/iobyTZHv3cIJOGO+/AKE=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":282557},"main":"dist/index.js","types":"dist/index.d.ts","gitHead":"c23c3254a9317742f1fd9b75499cb0cc07e2118f","scripts":{"test":"jest","build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"mykyta-ciphercross","email":"mykyta.shevchenko@ciphercross.com"},"repository":{"url":"git+https://github.com/CipherCross/nestjs-twilio-otp.git","type":"git"},"_npmVersion":"10.8.2","description":"Universal NestJS module for Twilio OTP SMS sending with dynamic configuration","directories":{},"_nodeVersion":"20.19.5","publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","twilio":"^5.9.0","ts-jest":"^29.2.5","typescript":"^5.7.3","@types/jest":"^29.5.14","@types/node":"^22.0.0","@nestjs/common":"^11.0.1","@nestjs/config":"^4.0.2","@nestjs/testing":"^11.0.1"},"peerDependencies":{"twilio":"^4.0.0 || ^5.0.0","@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/config":"^3.0.0 || ^4.0.0"},"peerDependenciesMeta":{"@nestjs/config":{"optional":true},"libphonenumber-js":{"optional":true}},"_npmOperationalInternal":{"tmp":"tmp/nestjs-twilio-otp_1.0.0_1764165441411_0.5245418610463513","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@ciphercross/nestjs-twilio-otp","version":"1.0.1","description":"Universal NestJS module for Twilio OTP SMS sending with dynamic configuration","author":{"name":"Viktoriia Scherba","email":"viktoriia.scherba"},"license":"MIT","main":"dist/index.js","types":"dist/index.d.ts","scripts":{"build":"tsc","test":"jest","prepublishOnly":"npm run build"},"peerDependencies":{"@nestjs/common":"^10.0.0 || ^11.0.0","@nestjs/config":"^3.0.0 || ^4.0.0","twilio":"^4.0.0 || ^5.0.0"},"peerDependenciesMeta":{"@nestjs/config":{"optional":true},"libphonenumber-js":{"optional":true}},"devDependencies":{"@nestjs/common":"^11.0.1","@nestjs/config":"^4.0.2","@nestjs/testing":"^11.0.1","@types/jest":"^29.5.14","jest":"^29.7.0","ts-jest":"^29.2.5","@types/node":"^22.0.0","twilio":"^5.9.0","typescript":"^5.7.3"},"repository":{"type":"git","url":"git+https://github.com/CipherCross/nestjs-twilio-otp.git"},"homepage":"https://github.com/CipherCross/nestjs-twilio-otp#readme","publishConfig":{"access":"public"},"keywords":["nestjs","twilio","otp","sms","verification","authentication"],"_id":"@ciphercross/nestjs-twilio-otp@1.0.1","gitHead":"d410781bdb49796f31e4dfeea311e595b08e4647","bugs":{"url":"https://github.com/CipherCross/nestjs-twilio-otp/issues"},"_nodeVersion":"20.19.6","_npmVersion":"10.8.2","dist":{"integrity":"sha512-SpJblP8OnrpcLv6s+O5YRYWXgNpBxIqqeShYWbqunlJ2Hk2JFewGWmBDGr4k8FGXSlxvAAB3IzTKtG/zWEFn5w==","shasum":"f943ed51fcbfc6a473ad4d578f16859c4da3716d","tarball":"https://registry.npmjs.org/@ciphercross/nestjs-twilio-otp/-/nestjs-twilio-otp-1.0.1.tgz","fileCount":22,"unpackedSize":283174,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIDQXjIOWYWjPjDZDydpWZrTQIXsr3dT4QD0ZXRg9bAJ7AiAA6m+Tq0Zk3o5f0NOazJfIBJZ863yOZhLTHOsiyvc7QA=="}]},"_npmUser":{"name":"mykyta-ciphercross","email":"mykyta.shevchenko@ciphercross.com"},"directories":{},"maintainers":[{"name":"mykyta-ciphercross","email":"mykyta.shevchenko@ciphercross.com"},{"name":"viktoriia.scherba","email":"viktoriia.scherba@ciphercross.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/nestjs-twilio-otp_1.0.1_1765464616014_0.7427302925772259"},"_hasShrinkwrap":false}},"time":{"created":"2025-11-26T13:57:21.292Z","modified":"2025-12-11T14:50:16.460Z","1.0.0":"2025-11-26T13:57:21.619Z","1.0.1":"2025-12-11T14:50:16.223Z"},"bugs":{"url":"https://github.com/CipherCross/nestjs-twilio-otp/issues"},"author":{"name":"Viktoriia Scherba","email":"viktoriia.scherba"},"license":"MIT","homepage":"https://github.com/CipherCross/nestjs-twilio-otp#readme","keywords":["nestjs","twilio","otp","sms","verification","authentication"],"repository":{"type":"git","url":"git+https://github.com/CipherCross/nestjs-twilio-otp.git"},"description":"Universal NestJS module for Twilio OTP SMS sending with dynamic configuration","maintainers":[{"name":"mykyta-ciphercross","email":"mykyta.shevchenko@ciphercross.com"},{"name":"viktoriia.scherba","email":"viktoriia.scherba@ciphercross.com"}],"readme":"# 🚀 @ciphercross/nestjs-twilio-otp\n\n**Production-ready NestJS module for sending OTP SMS via Twilio**  \n\nwith **dynamic configuration**, **async factory support**,  \n\n**built-in templates**, **mock mode**, and **phone utilities**.\n\n> Ideal for authentication flows, onboarding, PIN resets,  \n\n> and any SMS-based verification logic.\n\n---\n\n## 📦 Installation\n\n```bash\nnpm install @ciphercross/nestjs-twilio-otp twilio\n# or\nyarn add @ciphercross/nestjs-twilio-otp twilio\n```\n\n**Optional**: For enhanced international phone number validation, install `libphonenumber-js`:\n\n```bash\nnpm install libphonenumber-js\n# or\nyarn add libphonenumber-js\n```\n\nIf `libphonenumber-js` is installed, the module will automatically use it for more accurate phone number validation. Otherwise, it falls back to basic regex validation.\n\n## ⚙️ Features\n\n- 🔐 OTP SMS sending with templates\n- ⚡ Twilio-powered delivery\n- 🔁 forRoot, forRootAsync, forRootWithConfig\n- 🎛️ Configurable through ConfigModule\n- 🧪 Mock mode (enabled: false) for dev/test environments\n- 🌍 Phone formatting & validation helpers\n- 💡 Custom OTP message templates\n- 🧰 Fully typed TypeScript API\n- 🧱 Works with NestJS 10.x / 11.x\n\n## 🚀 Quick Start\n\n### 1) Basic usage (forRoot)\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { TwilioModule } from '@ciphercross/nestjs-twilio-otp';\n\n@Module({\n  imports: [\n    TwilioModule.forRoot({\n      accountSid: 'your-account-sid',\n      authToken: 'your-auth-token',\n      phoneNumber: '+1234567890', // or messagingServiceSid\n      messagingServiceSid: 'your-service-sid', // optional\n      enabled: true,\n      appName: 'MyApp',\n      defaultOtpExpiryMinutes: 10,\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n### 2) Configuration using ConfigModule\n\n```typescript\nimport { Module } from '@nestjs/common';\nimport { ConfigModule } from '@nestjs/config';\nimport { TwilioModule } from '@ciphercross/nestjs-twilio-otp';\n\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    TwilioModule.forRootWithConfig('twilio'), // configService.get('twilio.*')\n  ],\n})\nexport class AppModule {}\n```\n\n**Example `.env`:**\n\n```env\nTWILIO_ACCOUNT_SID=...\nTWILIO_AUTH_TOKEN=...\nTWILIO_PHONE_NUMBER=+1234567890\nTWILIO_MESSAGING_SERVICE_SID=...\nTWILIO_ENABLED=true\n```\n\n### 3) Async factory (forRootAsync)\n\n```typescript\n@Module({\n  imports: [\n    ConfigModule.forRoot(),\n    TwilioModule.forRootAsync({\n      imports: [ConfigModule],\n      useFactory: (config: ConfigService) => ({\n        accountSid: config.get('TWILIO_ACCOUNT_SID'),\n        authToken: config.get('TWILIO_AUTH_TOKEN'),\n        phoneNumber: config.get('TWILIO_PHONE_NUMBER'),\n        messagingServiceSid: config.get('TWILIO_MESSAGING_SERVICE_SID'),\n        enabled: config.get('TWILIO_ENABLED') === 'true',\n        appName: 'MyApp',\n        defaultOtpExpiryMinutes: 10,\n      }),\n      inject: [ConfigService],\n    }),\n  ],\n})\nexport class AppModule {}\n```\n\n## 📤 Sending SMS & OTP\n\n### TwilioService example\n\n```typescript\nimport { Injectable } from '@nestjs/common';\nimport { TwilioService } from '@ciphercross/nestjs-twilio-otp';\n\n@Injectable()\nexport class AuthService {\n  constructor(private readonly twilio: TwilioService) {}\n\n  async sendOtp(phone: string, code: string) {\n    const result = await this.twilio.sendOtpSms(phone, code, 'sign_up');\n    if (result.success) {\n      console.log('OTP sent:', result.messageId);\n    } else {\n      console.error('Failed to send OTP:', result.error);\n    }\n  }\n\n  async sendCustomSms(phone: string, message: string) {\n    return this.twilio.sendSms({\n      to: phone,\n      message,\n      purpose: 'notification',\n    });\n  }\n\n  validatePhone(phone: string) {\n    return this.twilio.validatePhoneNumber(phone);\n  }\n\n  formatPhone(phone: string) {\n    return this.twilio.formatPhoneNumber(phone, '+1');\n  }\n}\n```\n\n## 🎨 Custom OTP Message\n\n```typescript\nTwilioModule.forRoot({\n  accountSid: 'sid',\n  authToken: 'token',\n  phoneNumber: '+1234567890',\n  customMessageFormatter: (code: string, purpose: string) =>\n    `Your verification code is ${code} (${purpose})`,\n});\n```\n\n## 🧪 Mock Mode (No SMS Sent)\n\nPerfect for development & automated tests.\n\n```typescript\nTwilioModule.forRoot({\n  accountSid: 'test',\n  authToken: 'test',\n  enabled: false, // no requests sent to Twilio\n});\n```\n\n**Mock response example:**\n\n```json\n{\n  \"success\": true,\n  \"messageId\": \"mock-<uuid>\"\n}\n```\n\n## 📘 API Reference\n\n### TwilioService\n\n#### Methods\n\n| Method | Description |\n|--------|-------------|\n| `sendSms(options)` | Send any SMS message |\n| `sendOtpSms(phone, code, purpose)` | Send OTP code |\n| `validatePhoneNumber(phone)` | Validate phone format |\n| `formatPhoneNumber(phone, countryCode?)` | Format into E.164 |\n| `getMessageTemplate(code, purpose)` | Build OTP message |\n| `getConfigStatus()` | Check Twilio configuration state |\n| `testConnection()` | Verify Twilio credentials |\n\n## 🔑 Supported OTP Purposes\n\n- `sign_up`\n- `sign_in`\n- `pin_reset`\n- `password_reset`\n- `business_secret_reset`\n- `phone_change`\n- (any custom string uses fallback template)\n\n## 🧰 Phone Utilities\n\nStandalone import:\n\n```typescript\nimport {\n  formatPhoneNumber,\n  maskPhoneNumber,\n  normalizePhoneNumber,\n  isValidPhoneFormat,\n  extractCountryCode,\n  validatePhoneNumber,\n} from '@ciphercross/nestjs-twilio-otp';\n```\n\n## ⚠️ Rate Limiting & Security\n\n**Important**: This module does not implement rate limiting. To protect your application from abuse and prevent excessive SMS costs, you should implement rate limiting in your application layer.\n\n**Recommended approaches:**\n- Use NestJS throttler guards (`@nestjs/throttler`)\n- Implement rate limiting middleware (e.g., `express-rate-limit` with Redis)\n- Track OTP requests per phone number/IP address\n- Set maximum requests per time window (e.g., 3 requests per 15 minutes per phone number)\n\n**Example with NestJS Throttler:**\n\n```typescript\nimport { ThrottlerGuard, ThrottlerModule } from '@nestjs/throttler';\nimport { APP_GUARD } from '@nestjs/core';\n\n@Module({\n  imports: [\n    ThrottlerModule.forRoot([{\n      ttl: 60000, // 1 minute\n      limit: 3, // 3 requests per minute\n    }]),\n    TwilioModule.forRoot({...}),\n  ],\n  providers: [\n    {\n      provide: APP_GUARD,\n      useClass: ThrottlerGuard,\n    },\n  ],\n})\nexport class AppModule {}\n```\n\n## 📄 License\n\nMIT\n","readmeFilename":"README.md"}