├── .editorconfig ├── .env.example ├── .eslintignore ├── .eslintrc.js ├── .github ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── PULL_REQUEST_TEMPLATE.md ├── funding.yml ├── stale.yml └── workflows │ ├── build.yml │ └── release.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .lintstagedrc.js ├── .nvmrc ├── .prettierignore ├── .prettierrc.js ├── .releaserc.js ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── LICENSE ├── README.md ├── commitlint.config.js ├── jest.config.js ├── jest.setup.js ├── lib ├── __tests__ │ └── twilio.module.test.ts ├── index.ts ├── module │ ├── index.ts │ ├── twilio.module.ts │ └── twilio.service.ts └── utils │ ├── index.ts │ ├── twilio.interface.ts │ ├── twilio.module-definition.ts │ └── twilio.utils.ts ├── nest-cli.json ├── package.json ├── pnpm-lock.yaml ├── renovate.json ├── tsconfig.build.json ├── tsconfig.json └── tsconfig.test.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | root = true 5 | 6 | [*] 7 | # We recommend you to keep these unchanged 8 | end_of_line = lf 9 | charset = utf-8 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | [*.md] 14 | trim_trailing_whitespace = true -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # TESTING ENV 2 | 3 | TWILIO_ACCOUNT_SID= 4 | TWILIO_AUTH_TOKEN= 5 | TWILIO_PHONE_NUMBER= 6 | TWILIO_TARGET_PHONE_NUMBER= -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | dist/ -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: '@typescript-eslint/parser', // Specifies the ESLint parser 3 | parserOptions: { 4 | ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features 5 | sourceType: 'module', // Allows for the use of imports 6 | ecmaFeatures: { 7 | jsx: true, // Allows for the parsing of JSX 8 | }, 9 | }, 10 | extends: [ 11 | 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin 12 | 'plugin:prettier/recommended', // Enables eslint-plugin-prettier and eslint-config-prettier. This will display prettier errors as ESLint errors. Make sure this is always the last configuration in the extends array. 13 | ], 14 | rules: { 15 | // Place to specify ESLint rules. Can be used to overwrite rules specified from the extended configs 16 | }, 17 | }; 18 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Create a bug report 4 | --- 5 | 6 | # Bug Report 7 | 8 | ## Describe the Bug 9 | 10 | A clear and concise description of what the bug is. 11 | 12 | ## How to Reproduce 13 | 14 | Steps to reproduce the behavior, please provide code snippets or a repository: 15 | 16 | 1. Go to '....' 17 | 2. Click on '....' 18 | 3. See error 19 | 20 | ## Expected Behavior 21 | 22 | Tell me what should happen. 23 | 24 | ## Error 25 | 26 | Error resulted by the potential bug. 27 | 28 | ## Your Environment 29 | 30 | - OS: [e.g. macOS, Windows] 31 | - Version of nestjs-twilio: [e.g. v1.0.0] 32 | 33 | ## Error reproducing steps 34 | 35 | Please explain how did your error ocurr, you can also leave gists, repos or any kind of codebase. 36 | 37 | ## Additional Information 38 | 39 | Any other information about the problem here. 40 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💡 Feature Request 3 | about: Create a feature request 4 | --- 5 | 6 | # Feature Request 7 | 8 | ## Describe the Feature 9 | 10 | A clear and concise description of what you want and what your use case is. 11 | 12 | ## Describe the Solution you'd like 13 | 14 | A clear and concise description of what you want to happen. 15 | 16 | ## Describe alternatives you've considered 17 | 18 | A clear and concise description of any alternative solutions or features you've considered. 19 | 20 | ## Additional Information 21 | 22 | Any other information about the feature here. 23 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 12 | 13 | ## What 14 | 15 | What changes are being made? (e.g. feature, bug, docs etc.) 16 | 17 | ## Why 18 | 19 | Why are these changes necessary? 20 | 21 | ## How 22 | 23 | How were these changes implemented? 24 | 25 | ## Checklist 26 | 27 | Have you done all of these things? 28 | 29 | 30 | 31 | 32 | - [ ] Documentation added 33 | - [ ] Tests 34 | - [ ] Typescript definitions updated 35 | - [ ] Ready to be merged 36 | -------------------------------------------------------------------------------- /.github/funding.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective project name. 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: ["https://www.paypal.me/rejvban"] 13 | -------------------------------------------------------------------------------- /.github/stale.yml: -------------------------------------------------------------------------------- 1 | # Configuration for probot-stale - https://github.com/probot/stale 2 | 3 | # Number of days of inactivity before an Issue or Pull Request becomes stale 4 | daysUntilStale: 30 5 | 6 | # Number of days of inactivity before an Issue or Pull Request with the stale label is closed. 7 | # Set to false to disable. If disabled, issues still need to be closed manually, but will remain marked as stale. 8 | daysUntilClose: 7 9 | 10 | # Only issues or pull requests with all of these labels are check if stale. Defaults to `[]` (disabled) 11 | onlyLabels: [] 12 | 13 | # Issues or Pull Requests with these labels will never be considered stale. Set to `[]` to disable 14 | exemptLabels: 15 | - security 16 | 17 | # Set to true to ignore issues in a project (defaults to false) 18 | exemptProjects: false 19 | 20 | # Set to true to ignore issues in a milestone (defaults to false) 21 | exemptMilestones: false 22 | 23 | # Set to true to ignore issues with an assignee (defaults to false) 24 | exemptAssignees: false 25 | 26 | # Label to use when marking as stale 27 | staleLabel: stale 28 | 29 | # Comment to post when marking as stale. Set to `false` to disable 30 | markComment: > 31 | This issue has been automatically marked as stale because it has not had 32 | recent activity. It will be closed if no further activity occurs. Thank you 33 | for your contributions. 34 | 35 | # Comment to post when removing the stale label. 36 | # unmarkComment: > 37 | # Your comment here. 38 | 39 | # Comment to post when closing a stale Issue or Pull Request. 40 | # closeComment: > 41 | # Your comment here. 42 | 43 | # Limit the number of actions per hour, from 1-30. Default is 30 44 | limitPerRun: 30 45 | 46 | # Limit to only `issues` or `pulls` 47 | # only: issues 48 | 49 | # Optionally, specify configuration settings that are specific to just 'issues' or 'pulls': 50 | # pulls: 51 | # daysUntilStale: 30 52 | # markComment: > 53 | # This pull request has been automatically marked as stale because it has not had 54 | # recent activity. It will be closed if no further activity occurs. Thank you 55 | # for your contributions. 56 | 57 | issues: 58 | exemptLabels: 59 | - confirmed 60 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | on: 2 | push: 3 | branches: ['**'] 4 | workflow_dispatch: 5 | 6 | jobs: 7 | install: 8 | runs-on: ubuntu-latest 9 | steps: 10 | - name: Checkout 11 | uses: actions/checkout@v3 12 | 13 | - name: Install Node.js 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: 20 17 | 18 | - name: Install pnpm 19 | uses: pnpm/action-setup@v2 20 | with: 21 | version: 8 22 | run_install: false 23 | 24 | - name: Get pnpm store directory 25 | shell: bash 26 | run: | 27 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 28 | 29 | - name: Setup pnpm cache 30 | uses: actions/cache@v3 31 | with: 32 | path: ${{ env.STORE_PATH }} 33 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 34 | restore-keys: | 35 | ${{ runner.os }}-pnpm-store- 36 | 37 | - name: Install dependencies 38 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 39 | 40 | type-check: 41 | needs: install 42 | runs-on: ubuntu-latest 43 | steps: 44 | - name: Checkout 45 | uses: actions/checkout@v3 46 | 47 | - name: Install Node.js 48 | uses: actions/setup-node@v3 49 | with: 50 | node-version: 20 51 | 52 | - name: Install pnpm 53 | uses: pnpm/action-setup@v2 54 | with: 55 | version: 8 56 | run_install: false 57 | 58 | - name: Get pnpm store directory 59 | shell: bash 60 | run: | 61 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 62 | 63 | - name: Restore pnpm cache 64 | id: cache 65 | uses: actions/cache/restore@v3 66 | with: 67 | path: ${{ env.STORE_PATH }} 68 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 69 | fail-on-cache-miss: true 70 | 71 | - name: Install dependencies 72 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 73 | 74 | - name: Running type-check 75 | run: pnpm type-check 76 | 77 | lint: 78 | needs: install 79 | runs-on: ubuntu-latest 80 | steps: 81 | - name: Checkout 82 | uses: actions/checkout@v3 83 | 84 | - name: Install Node.js 85 | uses: actions/setup-node@v3 86 | with: 87 | node-version: 20 88 | 89 | - name: Install pnpm 90 | uses: pnpm/action-setup@v2 91 | with: 92 | version: 8 93 | run_install: false 94 | 95 | - name: Get pnpm store directory 96 | shell: bash 97 | run: | 98 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 99 | 100 | - name: Restore pnpm cache 101 | id: cache 102 | uses: actions/cache/restore@v3 103 | with: 104 | path: ${{ env.STORE_PATH }} 105 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 106 | fail-on-cache-miss: true 107 | 108 | - name: Install dependencies 109 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 110 | 111 | - name: Running lint 112 | run: pnpm lint 113 | 114 | test: 115 | needs: install 116 | runs-on: ubuntu-latest 117 | steps: 118 | - name: Checkout 119 | uses: actions/checkout@v3 120 | 121 | - name: Install Node.js 122 | uses: actions/setup-node@v3 123 | with: 124 | node-version: 20 125 | 126 | - name: Install pnpm 127 | uses: pnpm/action-setup@v2 128 | with: 129 | version: 8 130 | run_install: false 131 | 132 | - name: Get pnpm store directory 133 | shell: bash 134 | run: | 135 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 136 | 137 | - name: Restore pnpm cache 138 | id: cache 139 | uses: actions/cache/restore@v3 140 | with: 141 | path: ${{ env.STORE_PATH }} 142 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 143 | fail-on-cache-miss: true 144 | 145 | - name: Install dependencies 146 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 147 | 148 | - name: Running test 149 | run: pnpm test:run 150 | env: 151 | TWILIO_ACCOUNT_SID: ${{ secrets.TWILIO_ACCOUNT_SID }} 152 | TWILIO_AUTH_TOKEN: ${{ secrets.TWILIO_AUTH_TOKEN }} 153 | TWILIO_PHONE_NUMBER: ${{ secrets.TWILIO_PHONE_NUMBER }} 154 | TWILIO_TARGET_PHONE_NUMBER: ${{ secrets.TWILIO_TARGET_PHONE_NUMBER }} 155 | 156 | build: 157 | needs: install 158 | runs-on: ubuntu-latest 159 | steps: 160 | - name: Checkout 161 | uses: actions/checkout@v3 162 | 163 | - name: Install Node.js 164 | uses: actions/setup-node@v3 165 | with: 166 | node-version: 20 167 | 168 | - name: Install pnpm 169 | uses: pnpm/action-setup@v2 170 | with: 171 | version: 8 172 | run_install: false 173 | 174 | - name: Get pnpm store directory 175 | shell: bash 176 | run: | 177 | echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV 178 | 179 | - name: Restore pnpm cache 180 | id: cache 181 | uses: actions/cache/restore@v3 182 | with: 183 | path: ${{ env.STORE_PATH }} 184 | key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }} 185 | fail-on-cache-miss: true 186 | 187 | - name: Install dependencies 188 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 189 | 190 | - name: Building dist 191 | run: pnpm build:dist 192 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - master 6 | 7 | permissions: 8 | contents: read 9 | 10 | jobs: 11 | release: 12 | name: Release 13 | runs-on: ubuntu-latest 14 | permissions: 15 | contents: write 16 | issues: write 17 | pull-requests: write 18 | id-token: write 19 | steps: 20 | - name: Checkout 21 | uses: actions/checkout@v3 22 | 23 | - name: Install Node.js 24 | uses: actions/setup-node@v3 25 | with: 26 | node-version: 20 27 | 28 | - name: Install pnpm 29 | uses: pnpm/action-setup@v2 30 | with: 31 | version: 8 32 | run_install: false 33 | 34 | - name: Install dependencies 35 | run: pnpm install --frozen-lockfile --prefer-offline --ignore-scripts 36 | 37 | - name: Verify the integrity of provenance attestations and registry signatures for installed dependencies 38 | run: pnpm audit 39 | 40 | - name: Build 41 | run: pnpm build:dist 42 | 43 | - name: Release 44 | env: 45 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 46 | NPM_TOKEN: ${{ secrets.NPM_AUTH_TOKEN }} 47 | run: npx semantic-release 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # compiled output 2 | /dist 3 | /node_modules 4 | 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | yarn-debug.log* 10 | yarn-error.log* 11 | lerna-debug.log* 12 | 13 | # OS 14 | .DS_Store 15 | 16 | # Tests 17 | /coverage 18 | /.nyc_output 19 | 20 | # IDEs and editors 21 | /.idea 22 | .project 23 | .classpath 24 | .c9/ 25 | *.launch 26 | .settings/ 27 | *.sublime-workspace 28 | 29 | # IDE - VSCode 30 | .vscode/* 31 | !.vscode/settings.json 32 | !.vscode/tasks.json 33 | !.vscode/launch.json 34 | !.vscode/extensions.json 35 | 36 | # ENV 37 | .env -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | . "$(dirname -- "$0")/_/husky.sh" 3 | 4 | pnpm commitlint --edit ${1} 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm lint-staged 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | pnpm test:run 5 | -------------------------------------------------------------------------------- /.lintstagedrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '*.{js,ts,tsx}': 'eslint --fix', 3 | '*.{json,md,yml}': 'prettier --write', 4 | }; 5 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 20.12.0 2 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist/ -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | semi: true, 3 | trailingComma: 'all', 4 | singleQuote: true, 5 | printWidth: 80, 6 | tabWidth: 2, 7 | }; 8 | -------------------------------------------------------------------------------- /.releaserc.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @type {import('semantic-release').GlobalConfig} 3 | */ 4 | module.exports = { 5 | branches: ['master'], 6 | plugins: [ 7 | '@semantic-release/commit-analyzer', 8 | '@semantic-release/release-notes-generator', 9 | '@semantic-release/npm', 10 | '@semantic-release/git', 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | This project adheres to [Semantic Versioning](http://semver.org). 4 | Every release, along with the migration instructions, is documented on the Github [Releases](https://github.com/rejvban/twilio-nestjs/releases) page 5 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, religion, or sexual identity 10 | and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | - Demonstrating empathy and kindness toward other people 21 | - Being respectful of differing opinions, viewpoints, and experiences 22 | - Giving and gracefully accepting constructive feedback 23 | - Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | - Focusing on what is best not just for us as individuals, but for the 26 | overall community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | - The use of sexualized language or imagery, and sexual attention or 31 | advances of any kind 32 | - Trolling, insulting or derogatory comments, and personal or political attacks 33 | - Public or private harassment 34 | - Publishing others' private information, such as a physical or email 35 | address, without their explicit permission 36 | - Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | [INSERT CONTACT METHOD]. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series 86 | of actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or 93 | permanent ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within 113 | the community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.0, available at 119 | https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. 120 | 121 | Community Impact Guidelines were inspired by [Mozilla's code of conduct 122 | enforcement ladder](https://github.com/mozilla/diversity). 123 | 124 | [homepage]: https://www.contributor-covenant.org 125 | 126 | For answers to common questions about this code of conduct, see the FAQ at 127 | https://www.contributor-covenant.org/faq. Translations are available at 128 | https://www.contributor-covenant.org/translations. 129 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2020 Lazar Karic 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 |
7 |
8 |
11 | Injectable Twilio client for Nestjs. 12 |
13 | 14 | 15 | [](https://www.npmjs.com/package/nestjs-twilio) 16 | [](https://bundlephobia.com/result?p=nestjs-twilio) 17 | [](https://github.com/lkaric/nestjs-twilio) 18 | [](https://raw.githubusercontent.com/lkaric/nestjs-twilio/master/LICENSE) 19 | 20 | Implementing the `TwilioModule` from this package you gain access to Twilio client through dependency injection with minimal setup. 21 | 22 | ## Instalation 23 | 24 | ```bash 25 | $ npm install --save nestjs-twilio 26 | ``` 27 | 28 | ```bash 29 | $ yarn add nestjs-twilio 30 | ``` 31 | 32 | ## Getting Started 33 | 34 | To use Twilio client we need to register module for example in app.module.ts 35 | 36 | ```typescript 37 | import { TwilioModule } from 'nestjs-twilio'; 38 | 39 | @Module({ 40 | imports: [ 41 | TwilioModule.forRoot({ 42 | accountSid: process.env.TWILIO_ACCOUNT_SID, 43 | authToken: process.env.TWILIO_AUTH_TOKEN, 44 | }), 45 | ], 46 | }) 47 | export class AppModule {} 48 | ``` 49 | 50 | If you are using the `@nestjs/config package` from nest, you can use the `ConfigModule` using the `registerAsync()` function to inject your environment variables like this in your custom module: 51 | 52 | ```typescript 53 | import { TwilioModule } from 'nestjs-twilio'; 54 | 55 | @Module({ 56 | imports: [ 57 | TwilioModule.forRootAsync({ 58 | imports: [ConfigModule], 59 | useFactory: (cfg: ConfigService) => ({ 60 | accountSid: cfg.get('TWILIO_ACCOUNT_SID'), 61 | authToken: cfg.get('TWILIO_AUTH_TOKEN'), 62 | }), 63 | inject: [ConfigService], 64 | }), 65 | ], 66 | }) 67 | export class AppModule {} 68 | ``` 69 | 70 | Example usage in service. 71 | 72 | ```typescript 73 | import { InjectTwilio, TwilioService } from 'nestjs-twilio'; 74 | 75 | @Injectable() 76 | export class AppService { 77 | public constructor(private readonly twilioService: TwilioService) {} 78 | 79 | async sendSMS() { 80 | return this.twilioService.client.messages.create({ 81 | body: 'SMS Body, sent to the phone!', 82 | from: TWILIO_PHONE_NUMBER, 83 | to: TARGET_PHONE_NUMBER, 84 | }); 85 | } 86 | } 87 | ``` 88 | 89 | For full Client API see Twilio Node SDK reference [here](https://www.twilio.com/docs/libraries/node) 90 | 91 | ## Testing 92 | 93 | Example of testing can be found [here](https://github.com/lkaric/nestjs-twilio/blob/master/lib/__tests__/twilio.module.test.ts). 94 | -------------------------------------------------------------------------------- /commitlint.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { extends: ['@commitlint/config-conventional'] }; 2 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | preset: 'ts-jest', 3 | transform: { 4 | '.test.ts$': [ 5 | 'ts-jest', 6 | { 7 | tsconfig: './tsconfig.test.json', 8 | }, 9 | ], 10 | }, 11 | testRegex: '.test.ts$', 12 | collectCoverageFrom: ['lib/**/*.*.ts'], 13 | setupFiles: ['./jest.setup.js'], 14 | testEnvironment: 'node', 15 | }; 16 | -------------------------------------------------------------------------------- /jest.setup.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | require('dotenv').config(); 3 | 4 | const { TWILIO_ACCOUNT_SID, TWILIO_AUTH_TOKEN } = process.env; 5 | 6 | if (!TWILIO_ACCOUNT_SID || !TWILIO_AUTH_TOKEN) 7 | throw new Error('No testing authorization provided in env!'); 8 | -------------------------------------------------------------------------------- /lib/__tests__/twilio.module.test.ts: -------------------------------------------------------------------------------- 1 | import { Test } from '@nestjs/testing'; 2 | 3 | import { TwilioModule, TwilioService } from '../module'; 4 | 5 | import { OPTIONS_TYPE } from '../utils'; 6 | 7 | describe('TwiliModule', () => { 8 | const { 9 | TWILIO_ACCOUNT_SID, 10 | TWILIO_AUTH_TOKEN, 11 | TWILIO_PHONE_NUMBER, 12 | TWILIO_TARGET_PHONE_NUMBER, 13 | } = process.env; 14 | 15 | if (!TWILIO_PHONE_NUMBER) 16 | throw new Error('No Twilio phone number defined in `.env`!'); 17 | if (!TWILIO_TARGET_PHONE_NUMBER) 18 | throw new Error('No testing target phone number defined in `.env`!'); 19 | 20 | const config: typeof OPTIONS_TYPE = { 21 | accountSid: TWILIO_ACCOUNT_SID, 22 | authToken: TWILIO_AUTH_TOKEN, 23 | }; 24 | 25 | describe('forRoot', () => { 26 | let twilioService: TwilioService; 27 | 28 | beforeEach(async () => { 29 | const module = await Test.createTestingModule({ 30 | imports: [TwilioModule.forRoot(config)], 31 | }).compile(); 32 | 33 | twilioService = module.get(TwilioService); 34 | }); 35 | 36 | it('should provide sentry client', () => { 37 | expect(twilioService).toBeDefined(); 38 | }); 39 | 40 | it('should send a test sms to the phone number defined in env', async () => { 41 | const response = await twilioService.client.messages.create({ 42 | body: 'Automated testing of https://www.github.com/rejvban/nestjs-twilio forRoot', 43 | from: TWILIO_PHONE_NUMBER, 44 | to: TWILIO_TARGET_PHONE_NUMBER, 45 | }); 46 | 47 | expect(response).toBeDefined(); 48 | }); 49 | }); 50 | 51 | describe('forRootAsync with useFactory', () => { 52 | let twilioService: TwilioService; 53 | 54 | beforeEach(async () => { 55 | const module = await Test.createTestingModule({ 56 | imports: [ 57 | TwilioModule.forRootAsync({ 58 | useFactory: () => config, 59 | }), 60 | ], 61 | }).compile(); 62 | 63 | twilioService = module.get(TwilioService); 64 | }); 65 | 66 | it('should provide sentry client', () => { 67 | expect(twilioService).toBeDefined(); 68 | }); 69 | 70 | it('should send a test sms to the phone number defined in env', async () => { 71 | const response = await twilioService.client.messages.create({ 72 | body: 'Automated testing of https://www.github.com/rejvban/nestjs-twilio forRootAsync with useFactory', 73 | from: TWILIO_PHONE_NUMBER, 74 | to: TWILIO_TARGET_PHONE_NUMBER, 75 | }); 76 | 77 | expect(response).toBeDefined(); 78 | }); 79 | }); 80 | }); 81 | -------------------------------------------------------------------------------- /lib/index.ts: -------------------------------------------------------------------------------- 1 | export * from './module'; 2 | export * from './utils/twilio.interface'; 3 | -------------------------------------------------------------------------------- /lib/module/index.ts: -------------------------------------------------------------------------------- 1 | export * from './twilio.module'; 2 | export * from './twilio.service'; 3 | -------------------------------------------------------------------------------- /lib/module/twilio.module.ts: -------------------------------------------------------------------------------- 1 | import { Module } from '@nestjs/common'; 2 | 3 | import { ConfigurableModuleClass } from '../utils'; 4 | 5 | import { TwilioService } from './twilio.service'; 6 | 7 | @Module({ 8 | providers: [TwilioService], 9 | exports: [TwilioService], 10 | }) 11 | export class TwilioModule extends ConfigurableModuleClass {} 12 | -------------------------------------------------------------------------------- /lib/module/twilio.service.ts: -------------------------------------------------------------------------------- 1 | import { Inject, Injectable } from '@nestjs/common'; 2 | 3 | import { 4 | createTwilioClient, 5 | MODULE_OPTIONS_TOKEN, 6 | OPTIONS_TYPE, 7 | } from '../utils'; 8 | 9 | import type { TwilioClient } from '../utils'; 10 | 11 | @Injectable() 12 | export class TwilioService { 13 | private readonly twilioSdk: TwilioClient; 14 | 15 | constructor( 16 | @Inject(MODULE_OPTIONS_TOKEN) private options: typeof OPTIONS_TYPE, 17 | ) { 18 | this.twilioSdk = createTwilioClient(this.options); 19 | } 20 | 21 | public get client(): TwilioClient { 22 | return this.twilioSdk; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/utils/index.ts: -------------------------------------------------------------------------------- 1 | export * from './twilio.module-definition'; 2 | export * from './twilio.interface'; 3 | export * from './twilio.utils'; 4 | -------------------------------------------------------------------------------- /lib/utils/twilio.interface.ts: -------------------------------------------------------------------------------- 1 | import Twilio from 'twilio/lib/rest/Twilio'; 2 | 3 | import type { ClientOpts } from 'twilio/lib/base/BaseTwilio'; 4 | 5 | export type TwilioClient = Twilio; 6 | 7 | export interface ExtraConfiguration { 8 | isGlobal?: boolean; 9 | } 10 | export interface TwilioModuleOptions extends ExtraConfiguration { 11 | accountSid: string | undefined; 12 | authToken: string | undefined; 13 | options?: ClientOpts | undefined; 14 | } 15 | -------------------------------------------------------------------------------- /lib/utils/twilio.module-definition.ts: -------------------------------------------------------------------------------- 1 | import { ConfigurableModuleBuilder } from '@nestjs/common'; 2 | 3 | import { ExtraConfiguration, TwilioModuleOptions } from './twilio.interface'; 4 | 5 | export const { 6 | ConfigurableModuleClass, 7 | MODULE_OPTIONS_TOKEN, 8 | OPTIONS_TYPE, 9 | ASYNC_OPTIONS_TYPE, 10 | } = new ConfigurableModuleBuilder