├── .editorconfig ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .instanbul.yml ├── .jscsrc ├── .jshintrc ├── .travis.yml ├── COVERAGE.md ├── LICENSE ├── README.md ├── conf.json ├── deploy.sh ├── deploy_key.enc ├── docs └── api.md ├── gulpfile.js ├── index.js ├── lib ├── RateLimitError.js ├── account.js ├── application.js ├── availableNumber.js ├── bridge.js ├── call.js ├── client.js ├── conference.js ├── domain.js ├── endpoint.js ├── error.js ├── headerParsingLib.js ├── index.js ├── media.js ├── message.js ├── numberInfo.js ├── phoneNumber.js ├── recording.js ├── unexpectedResponseError.js ├── v2 │ ├── message.js │ └── searchAndOrderNumberQueries.js └── xml.js ├── package.json ├── test ├── .jshintrc ├── account-test.js ├── application-test.js ├── availableNumber-test.js ├── bridge-test.js ├── bxml-responses │ ├── call.xml │ ├── chaining.xml │ ├── conference.xml │ ├── gather.xml │ ├── hangup.xml │ ├── multiTransfer.xml │ ├── nesting.xml │ ├── pause.xml │ ├── playAudio.xml │ ├── record.xml │ ├── redirect.xml │ ├── sendDtmf.xml │ ├── sendMessage.xml │ ├── speakSentence.xml │ └── transfer.xml ├── call-test.js ├── client-test.js ├── conference-test.js ├── domain-test.js ├── endpoint-test.js ├── error-test.js ├── headerparsinglib-test.js ├── media-test.js ├── message-test.js ├── message-v2-test.js ├── mocha.opts ├── numberInfo-test.js ├── phoneNumber-test.js ├── recording-test.js ├── searchAndOrderNumberQueries-test.js ├── templates.json └── xml-test.js └── types ├── index.d.ts └── v2 ├── index.d.ts └── searchAndOrderNumberQueries.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = tab 6 | indent_size = 4 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Make sure you've checked off all these things before submitting: 2 | 3 | - [ ] This pull request contains 100% test coverage. 4 | - [ ] This pull request is completely documented. All available fields are listed in the docs with description. 5 | - [ ] Each public facing function should include at least one @example in the jsdoc. 6 | - [ ] Run `npm test` before committing. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring 2 | # files. 3 | # 4 | # If you find yourself ignoring temp files generated by your text editor 5 | # or operating system, you probably want to add a global ignore instead: 6 | # git config --global core.excludesfile ~/.gitignore 7 | 8 | # Ignore npm packaging 9 | node_modules 10 | bower_components 11 | #Ignore IDEA files 12 | /.idea 13 | 14 | # Ignore all logfiles and tempfiles. 15 | *.log 16 | *.colt 17 | /tmp 18 | /out 19 | 20 | ## Ignore all generated files 21 | /coverage 22 | /rdoc 23 | /wiki 24 | /packaging 25 | npm-debug.log 26 | *.tmproj 27 | azure_error 28 | what 29 | *.sublime-workspace 30 | 31 | # Output folder 32 | /dist 33 | 34 | # Numerous always-ignore extensions 35 | *~ 36 | *.diff 37 | *.patch 38 | *.err 39 | *.orig 40 | *.log 41 | *.rej 42 | *.swo 43 | *.swp 44 | *.vi 45 | *~ 46 | *.sass-cache 47 | 48 | # OS or Editor folders 49 | .DS_Store 50 | .cache 51 | .project 52 | .settings 53 | .tmproj 54 | nbproject 55 | Thumbs.db 56 | 57 | # config files 58 | 59 | /config/*.yml 60 | /config/*.json 61 | 62 | runTestsDebug.sh 63 | .mimosa/require/* 64 | logfile 65 | .vscode 66 | 67 | .nvmrc 68 | .vscode 69 | yarn.lock 70 | package-lock.json -------------------------------------------------------------------------------- /.instanbul.yml: -------------------------------------------------------------------------------- 1 | verbose: false 2 | instrumentation: 3 | root: . 4 | default-excludes: true 5 | excludes: [] 6 | embed-source: false 7 | variable: __coverage__ 8 | compact: true 9 | preserve-comments: false 10 | complete-copy: false 11 | save-baseline: false 12 | baseline-file: ./coverage/coverage-baseline.json 13 | preload-sources: false 14 | reporting: 15 | print: summary 16 | reports: 17 | - lcov 18 | dir: ./coverage 19 | watermarks: 20 | statements: [50, 80] 21 | lines: [50, 80] 22 | functions: [50, 80] 23 | branches: [50, 80] 24 | report-config: 25 | clover: {file: clover.xml} 26 | cobertura: {file: cobertura-coverage.xml} 27 | json: {file: coverage-final.json} 28 | json-summary: {file: coverage-summary.json} 29 | lcovonly: {file: lcov.info} 30 | teamcity: {file: null} 31 | text: {file: null, maxCols: 0} 32 | text-summary: {file: null} 33 | hooks: 34 | hook-run-in-context: false 35 | post-require-hook: null 36 | handle-sigint: false 37 | -------------------------------------------------------------------------------- /.jscsrc: -------------------------------------------------------------------------------- 1 | { 2 | "requireCurlyBraces" : [ 3 | "if", "else", "for", "while", "do", "try", "catch", "case", 4 | "default" 5 | ], 6 | 7 | "requireSpaceAfterKeywords" : [ 8 | "if", "else", "for", "while", "do", "switch", "return", 9 | "try", "catch" 10 | ], 11 | 12 | "requireParenthesesAroundIIFE" : true, 13 | 14 | "requireSpacesInFunctionExpression" : { 15 | "beforeOpeningRoundBrace" : true, 16 | "beforeOpeningCurlyBrace" : true 17 | }, 18 | 19 | "disallowMultipleVarDecl" : true, 20 | "disallowEmptyBlocks" : true, 21 | "requireSpacesInsideObjectBrackets" : "all", 22 | "requireSpacesInsideArrayBrackets" : "all", 23 | "disallowSpacesInsideParentheses" : true, 24 | "disallowDanglingUnderscores" : true, 25 | "requireSpaceAfterObjectKeys" : true, 26 | "requireSpaceBeforeBlockStatements" : true, 27 | "requireCommaBeforeLineBreak" : true, 28 | "requireAlignedObjectValues" : "skipWithLineBreak", 29 | 30 | "requireOperatorBeforeLineBreak" : [ 31 | "?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", 32 | ">=", "<", "<=" 33 | ], 34 | 35 | "disallowSpaceAfterPrefixUnaryOperators" : [ 36 | "++", "--", "+", "-", "~", "!" 37 | ], 38 | 39 | "disallowSpaceBeforePostfixUnaryOperators" : [ "++", "--" ], 40 | 41 | "requireSpaceBeforeBinaryOperators" : [ 42 | "?", "+", "-", "/", "*", "=", "==", "===", "!=", "!==", ">", 43 | ">=", "<", "<=" 44 | ], 45 | 46 | "disallowSpaceBeforeBinaryOperators" : [ "," ], 47 | 48 | "requireSpaceAfterBinaryOperators" : [ 49 | "?", "+", "/", "*", ":", "=", "==", "===", "!=", "!==", ">", 50 | ">=", "<", "<=" 51 | ], 52 | 53 | "disallowImplicitTypeConversion" : [ 54 | "numeric", "boolean", "binary", "string" 55 | ], 56 | 57 | "disallowKeywords" : [ "with" ], 58 | 59 | "disallowMultipleLineStrings" : true, 60 | "disallowMultipleLineBreaks" : true, 61 | "validateLineBreaks" : "LF", 62 | "validateQuoteMarks" : "\"", 63 | "validateIndentation" : "\t", 64 | "disallowMixedSpacesAndTabs" : true, 65 | "disallowTrailingWhitespace" : true, 66 | 67 | "requireKeywordsOnNewLine" : [ "else", "catch", "finally" ], 68 | 69 | "maximumLineLength" : 120, 70 | "requireCapitalizedConstructors" : true, 71 | "safeContextKeyword" : "self", 72 | "requireDotNotation" : true, 73 | 74 | "excludeFiles" : [ "node_modules/**" ] 75 | 76 | } 77 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "bitwise" : true, 3 | "camelcase" : true, 4 | "curly" : true, 5 | "eqeqeq" : true, 6 | "es3" : false, 7 | "forin" : false, 8 | "immed" : true, 9 | "indent" : 4, 10 | "latedef" : true, 11 | "newcap" : true, 12 | "noarg" : true, 13 | "noempty" : true, 14 | "nonew" : true, 15 | "quotmark" : "double", 16 | "undef" : true, 17 | "unused" : true, 18 | "strict" : false, 19 | "trailing" : true, 20 | "maxparams" : 5, 21 | "maxdepth" : 3, 22 | "maxstatements" : false, 23 | "maxlen" : 120, 24 | 25 | "node" : true, 26 | 27 | "proto" : true 28 | } 29 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '8' 4 | - '8.4' 5 | - '6' 6 | - '7' 7 | - '9' 8 | - '10' 9 | - '11' 10 | - '12' 11 | script: npm test 12 | env: 13 | global: 14 | - ENCRYPTION_LABEL: 3985cea5a61f 15 | - COMMIT_AUTHOR_EMAIL: openapi@bandwidth.com 16 | deploy: 17 | provider: npm 18 | email: hi@dtolb.com 19 | api_key: 20 | secure: QsOhkofy49Q2hya3D1QlbGQnFK7eKuBPifygvNgIqN75aJT5mGPUFzLcYyLd+tLtnjIh/fOV+dFI+QAWJjJWa73C7y1pq8y7hD7VPd+jloZPegUOum0fqcM8sHyU5rJ8IIlqxpMHbJBSK4+l3+KmmOoWYcwxsksuD170uDA+Zpg= 21 | on: 22 | tags: true 23 | repo: Bandwidth/node-bandwidth 24 | -------------------------------------------------------------------------------- /COVERAGE.md: -------------------------------------------------------------------------------- 1 | ## Rest API Coverage 2 | ------------ 3 | * [Account](http://ap.bandwidth.com/docs/rest-api/account/) 4 | * [ ] Information 5 | * [ ] Transactions 6 | * [Applications](http://ap.bandwidth.com/docs/rest-api/applications/) 7 | * [ ] List 8 | * [ ] Create 9 | * [ ] Get info 10 | * [ ] Update 11 | * [ ] Delete 12 | * [Available Numbers](http://ap.bandwidth.com/docs/rest-api/available-numbers/) 13 | * [ ] Search Local 14 | * [ ] Buy Local 15 | * [ ] Search Tollfree 16 | * [ ] Buy Tollfree 17 | * [Bridges](http://ap.bandwidth.com/docs/rest-api/bridges/) 18 | * [ ] List 19 | * [ ] Create 20 | * [ ] Get info 21 | * [ ] Update Calls 22 | * [ ] Play Audio 23 | * [ ] Speak Sentence 24 | * [ ] Play Audio File 25 | * [ ] Get Calls 26 | * [Calls](http://ap.bandwidth.com/docs/rest-api/calls/) 27 | * [ ] List all calls 28 | * [ ] Create 29 | * [ ] Get info 30 | * [ ] Update Status 31 | * [ ] Transfer 32 | * [ ] Answer 33 | * [ ] Hangup 34 | * [ ] Reject 35 | * [ ] Play Audio 36 | * [ ] Speak Sentence 37 | * [ ] Play Audio File 38 | * [ ] Send DTMF 39 | * [ ] Events 40 | * [ ] List 41 | * [ ] Get individual info 42 | * [ ] List Recordings 43 | * [ ] List Transactions 44 | * [ ] Gather 45 | * [ ] Create Gather 46 | * [ ] Get Gather info 47 | * [ ] Update Gather 48 | * [Conferences](http://ap.bandwidth.com/docs/rest-api/conferences/) 49 | * [ ] Create conference 50 | * [ ] Get info for single conference 51 | * [ ] Play Audio 52 | * [ ] Speak Sentence 53 | * [ ] Play Audio File 54 | * [ ] Members 55 | * [ ] Add member 56 | * [ ] List members 57 | * [ ] Update members 58 | * [ ] Mute 59 | * [ ] Remove 60 | * [ ] Hold 61 | * [ ] Play Audio to single member 62 | * [ ] Speak Sentence 63 | * [ ] Play Audio File 64 | * [Domains](http://ap.bandwidth.com/docs/rest-api/domains/) 65 | * [ ] List all domains 66 | * [ ] create domain 67 | * [ ] Delete domain 68 | * [Endpoints](http://ap.bandwidth.com/docs/rest-api/endpoints/) 69 | * [ ] List all endpoints 70 | * [ ] Create Endpoint 71 | * [ ] Get Single Endpoint 72 | * [ ] Update Single Endpoint 73 | * [ ] Delete Single Endpoint 74 | * [ ] Create auth token 75 | * [Errors](http://ap.bandwidth.com/docs/rest-api/errors/) 76 | * [ ] Get all errors 77 | * [ ] Get info on Single Error 78 | * [Intelligence Services](http://ap.bandwidth.com/docs/rest-api/intelligenceservices/) 79 | * [ ] Number Intelligence 80 | * [Media](http://ap.bandwidth.com/docs/rest-api/media/) 81 | * [ ] List all media 82 | * [ ] Upload media 83 | * [ ] Download single media file 84 | * [ ] Delete single media 85 | * [Messages](http://ap.bandwidth.com/docs/rest-api/messages/) 86 | * [ ] List all messages 87 | * [ ] Send Message 88 | * [ ] Get single message 89 | * [ ] [Batch Messages](http://ap.bandwidth.com/docs/rest-api/messages/#resourcePOSTv1usersuserIdmessages) (single request, multiple messages) 90 | 91 | * [Number Info](http://ap.bandwidth.com/docs/rest-api/numberinfo/) 92 | * [ ] Get number info 93 | * [Phone Numbers](http://ap.bandwidth.com/docs/rest-api/phonenumbers/) 94 | * [ ] List all phonenumbers 95 | * [ ] Get single phonenumber 96 | * [ ] Order singe number 97 | * [ ] Update single number 98 | * [ ] Delete number 99 | * [Recordings](http://ap.bandwidth.com/docs/rest-api/recordings/) 100 | * [ ] List all recordings 101 | * [ ] Get single recording info 102 | * [Transciptions](http://ap.bandwidth.com/docs/rest-api/recordingsidtranscriptions/) 103 | * [ ] Create 104 | * [ ] Get info for single transcrption 105 | * [ ] Get all transcrptions for a recording 106 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 bandwidthcom 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. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-bandwidth 2 | 3 | > # Deprecation Notice 4 | > This project is deprecated. Please go to https://github.com/bandwidth/node-voice or https://github.com/bandwidth/node-messaging for using Bandwidth's voice and messaging APIs. 5 | 6 | [![npm version](https://badge.fury.io/js/node-bandwidth.svg)](https://badge.fury.io/js/node-bandwidth) 7 | [![Build Status](https://travis-ci.org/bandwidth/node-bandwidth.svg?branch=master)](https://travis-ci.org/bandwidth/node-bandwidth) 8 | [![dependencies](https://david-dm.org/bandwidth/node-bandwidth.svg)](https://david-dm.org/bandwidth/node-bandwidth) 9 | [![Known Vulnerabilities](https://snyk.io/package/npm/node-bandwidth/badge.svg)](https://snyk.io/package/npm/node-bandwidth) 10 | 11 | A Node.js client library for [Bandwidth's Communications Platform](https://app.bandwidth.com/) 12 | 13 | ## API Documentation 14 | 15 | The API documentation is located at [dev.bandwidth.com/ap-docs/](http://dev.bandwidth.com/ap-docs/) 16 | 17 | ## [Full SDK Reference](http://dev.bandwidth.com/node-bandwidth/index.html) 18 | The Full API Reference is available either as an interactive site or as a single Markdown file: 19 | 20 | * [Site](http://dev.bandwidth.com/node-bandwidth/index.html). 21 | * [Single MD file](https://github.com/bandwidth/node-bandwidth/blob/master/docs/api.md) 22 | 23 | ## Installing the SDK 24 | 25 | `node-bandwidth` is available on NPM: 26 | 27 | npm install --save node-bandwidth 28 | 29 | ## Supported Versions 30 | `node-bandwidth` should work on all versions of node newer than `6.0.0`. However, due to the rapid development in the Node and npm environment, we can only provide _support_ on [LTS versions of Node](https://github.com/nodejs/LTS) 31 | 32 | | Version | Support Level | 33 | |:-------------------------------|:-------------------------| 34 | | < 6 | Unsupported 35 | | 6-12 | Supported | 36 | | > 12 | N/A | 37 | 38 | ## Release Notes 39 | | Version | Notes | 40 | |:---|:---| 41 | | 3.0.0 | Dropped support for node versions less than 6 | 42 | | 3.0.2 | Updated the URL used for Bandwidth's V2 Messaging | 43 | 44 | ## Client initialization 45 | 46 | All interaction with the API is done through a `client` Object. The client constructor takes an Object containing configuration options. The following options are supported: 47 | 48 | | Field name | Description | Default value | Required | 49 | |:------------|:-----------------------|:------------------------------------|:---------| 50 | | `userId` | Your Bandwidth user ID | `undefined` | Yes | 51 | | `apiToken` | Your API token | `undefined` | Yes | 52 | | `apiSecret` | Your API secret | `undefined` | Yes | 53 | | `baseUrl` | The Bandwidth API URL | `https://api.catapult.inetwork.com` | No | 54 | 55 | To initialize the client object, provide your API credentials which can be found on your account page in [the portal](https://catapult.inetwork.com/pages/catapult.jsf). 56 | 57 | ```javascript 58 | var Bandwidth = require("node-bandwidth"); 59 | 60 | var client = new Bandwidth({ 61 | userId : "YOUR_USER_ID", // <-- note, this is not the same as the username you used to login to the portal 62 | apiToken : "YOUR_API_TOKEN", 63 | apiSecret : "YOUR_API_SECRET" 64 | }); 65 | ``` 66 | 67 | Your `client` object is now ready to use the API. 68 | 69 | ## Callbacks or Promises 70 | All functions of the client object take an optional Node.js style `(err, result)` callback, and also return a Promise. That way if you want to use Promises in your application, you don't have to wrap the SDK with a Promise library. You can simply do things like this: 71 | 72 | ### Promise style 73 | ```javascript 74 | client.Message.send({ 75 | from : "+12345678901", // This must be a Catapult number on your account 76 | to : "+12345678902", 77 | text : "Hello world." 78 | }) 79 | .then(function(message) { 80 | console.log("Message sent with ID " + message.id); 81 | }) 82 | .catch(function(err) { 83 | console.log(err.message); 84 | }); 85 | ``` 86 | If you're not into that kind of thing you can also do things the "old fashioned" callback way: 87 | 88 | ### Callback style 89 | ```javascript 90 | client.Message.send({ 91 | from : "+12345678901", // This must be a Catapult number on your account 92 | to : "+12345678902", 93 | text : "Hello world." 94 | }, function(err, message) { 95 | if (err) { 96 | console.log(err); 97 | return; 98 | } 99 | console.log("Message sent with ID " + message.id); 100 | }); 101 | ``` 102 | 103 | ## Using Messaging V2 API 104 | 105 | Both callback and promise styles are supported 106 | 107 | ```javascript 108 | // First you should create and application on Bandwidth Dashboard 109 | var dashboardAuth = { 110 | accountId : "accountId", 111 | userName : "userName", 112 | password : "password", 113 | subaccountId : "subaccountId" 114 | }; 115 | 116 | client.v2.Message.createMessagingApplication(dashboardAuth, { 117 | name: "My Messaging App", 118 | callbackUrl: "http://my-callback", 119 | locationName: "My Location", 120 | smsOptions: { 121 | enabled: true, 122 | tollFreeEnabled: true 123 | }, 124 | mmsOptions: { 125 | enabled: true 126 | } 127 | }).then(function (application) { 128 | // application.applicationId contains id of created dashboard application 129 | // application.locationId contains id of location 130 | 131 | // Now you should reserve 1 ore more numbers on Bandwidth Dashboard 132 | return client.v2.Message.searchAndOrderNumbers(dashboardAuth, application, new client.AreaCodeSearchAndOrderNumbersQuery({areaCode: "910", quantity: 1})) 133 | .then(function (numbers) { 134 | // Now you can send messages using these numbers 135 | return client.v2.Message.send({from: numbers[0], to: ["+12345678901", "+12345678902"], text: "Hello", applicationId: application.applicationId}); 136 | }); 137 | }); 138 | ``` 139 | 140 | ## Providing feedback 141 | 142 | For current discussions on 2.0 please see the [2.0 issues section on GitHub](https://github.com/bandwidth/node-bandwidth/labels/2.0). To start a new topic on 2.0, please open an issue and use the `2.0` tag. Your feedback is greatly appreciated! 143 | -------------------------------------------------------------------------------- /conf.json: -------------------------------------------------------------------------------- 1 | { 2 | "tags": { 3 | "allowUnknownTags": true, 4 | "dictionaries": ["jsdoc"] 5 | }, 6 | "source": { 7 | "include": ["lib", "package.json", "README.md"], 8 | "includePattern": ".js$", 9 | "excludePattern": "(node_modules/|docs)" 10 | }, 11 | "plugins": [ 12 | "plugins/markdown" 13 | ], 14 | "templates": { 15 | "cleverLinks": false, 16 | "monospaceLinks": true, 17 | "useLongnameInNav": false 18 | }, 19 | "opts": { 20 | "destination": "./out/", 21 | "encoding": "utf8", 22 | "private": true, 23 | "recurse": true, 24 | "template": "./node_modules/minami" 25 | } 26 | } -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e # Exit with nonzero exit code if anything fails 3 | 4 | SOURCE_BRANCH="master" 5 | TARGET_BRANCH="gh-pages" 6 | 7 | function docGen { 8 | npm run-script docs 9 | mv ./out/node-bandwidth/*/* ./out 10 | } 11 | NODE_VERSION=`node --version` 12 | NODE_VERSION=${NODE_VERSION:1:1} 13 | # Pull requests and commits to other branches shouldn't try to deploy, just build to verify 14 | if [ "$TRAVIS_PULL_REQUEST" != "false" -o "$TRAVIS_BRANCH" != "$SOURCE_BRANCH" -o "$NODE_VERSION" != "5" ]; then 15 | echo "Skipping deploy; just doing a build." 16 | exit 0 17 | fi 18 | 19 | # Save some useful information 20 | REPO=`git config remote.origin.url` 21 | SSH_REPO=${REPO/https:\/\/github.com\//git@github.com:} 22 | SHA=`git rev-parse --verify HEAD` 23 | 24 | # Clone the existing gh-pages for this repo into out/ 25 | # Create a new empty branch if gh-pages doesn't exist yet (should only happen on first deply) 26 | git clone $REPO out 27 | cd out 28 | git checkout $TARGET_BRANCH || git checkout --orphan $TARGET_BRANCH 29 | cd .. 30 | 31 | # Clean out existing contents 32 | rm -rf out/**/* || exit 0 33 | 34 | # Run our compile script 35 | docGen 36 | 37 | # Now let's go have some fun with the cloned repo 38 | cd out 39 | git config user.name "Travis CI" 40 | git config user.email "$COMMIT_AUTHOR_EMAIL" 41 | 42 | # If there are no changes to the compiled out (e.g. this is a README update) then just bail. 43 | if [ -z `git diff --exit-code` ]; then 44 | echo "No changes to the output on this push; exiting." 45 | exit 0 46 | fi 47 | 48 | # Commit the "changes", i.e. the new version. 49 | # The delta will show diffs between new and old versions. 50 | git add . 51 | git commit -m "Deploy to GitHub Pages: ${SHA}" 52 | 53 | # Get the deploy key by using Travis's stored variables to decrypt deploy_key.enc 54 | ENCRYPTED_KEY_VAR="encrypted_${ENCRYPTION_LABEL}_key" 55 | ENCRYPTED_IV_VAR="encrypted_${ENCRYPTION_LABEL}_iv" 56 | ENCRYPTED_KEY=${!ENCRYPTED_KEY_VAR} 57 | ENCRYPTED_IV=${!ENCRYPTED_IV_VAR} 58 | openssl aes-256-cbc -K $ENCRYPTED_KEY -iv $ENCRYPTED_IV -in ../deploy_key.enc -out deploy_key -d 59 | chmod 600 deploy_key 60 | eval `ssh-agent -s` 61 | ssh-add deploy_key 62 | 63 | # Now that we're all set up, we can push. 64 | git push $SSH_REPO $TARGET_BRANCH 65 | -------------------------------------------------------------------------------- /deploy_key.enc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Bandwidth/node-bandwidth/98cb702b9568c4d568959e1b68142c361953bf86/deploy_key.enc -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require("gulp"); 2 | var clean = require("gulp-clean"); 3 | var mocha = require("gulp-mocha"); 4 | var jshint = require("gulp-jshint"); 5 | var istanbul = require("gulp-istanbul"); 6 | var rename = require("gulp-rename"); 7 | var concat = require("gulp-concat") 8 | 9 | gulp.task("jshint", gulp.series(function () { 10 | return gulp.src([ "./lib/*.js", "./test/*.js" ]) 11 | .pipe(jshint()) 12 | .pipe(jshint.reporter("jshint-stylish")) 13 | .pipe(jshint.reporter("fail")); 14 | })); 15 | 16 | gulp.task("styles", gulp.series("jshint")); 17 | 18 | gulp.task("test", gulp.series(function () { 19 | return gulp.src("coverage", { read : false, allowEmpty : true }) 20 | .pipe(clean()) 21 | .on("end", function () { 22 | gulp.src([ "lib/*.js" ]) 23 | .pipe(istanbul()) 24 | .pipe(istanbul.hookRequire()) 25 | .on("finish", function () { 26 | gulp.src([ "test/*.js" ], { read : false }) 27 | .pipe(mocha({ 28 | reporter : "spec", 29 | globals : { 30 | should : require("should") 31 | } 32 | })) 33 | .pipe(istanbul.writeReports()) 34 | .pipe(istanbul.enforceThresholds({ thresholds : { global : 100 } })); 35 | }); 36 | }); 37 | })); 38 | 39 | gulp.task("doc", gulp.series(function () { 40 | return gulp.src([ "lib/*.js" ]) 41 | .pipe(concat("api.md")) 42 | .pipe(rename(function (path) { 43 | path.extname = ".md"; 44 | })) 45 | .pipe(gulp.dest("docs")); 46 | })); 47 | 48 | gulp.task("default", gulp.series("jshint", "test", "doc")); 49 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | module.exports = require("./lib"); 2 | -------------------------------------------------------------------------------- /lib/RateLimitError.js: -------------------------------------------------------------------------------- 1 | var util = require("util"); 2 | 3 | var RateLimitError = function (message, statusCode, limitReset) { 4 | Error.captureStackTrace(this, this.constructor); 5 | this.name = this.constructor.name; 6 | this.message = message; 7 | this.statusCode = statusCode; 8 | this.limitReset = limitReset; 9 | 10 | }; 11 | 12 | util.inherits(RateLimitError, Error); 13 | 14 | module.exports = RateLimitError; 15 | -------------------------------------------------------------------------------- /lib/account.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Account 6 | * @constructor 7 | */ 8 | var Account = function (client) { 9 | 10 | /** 11 | * Gets information about user's account. 12 | * @param {String} accountId The ID of the account to get 13 | * @param {Function} callback A callback with the account information 14 | * @return {AccountResponse} A promise for the account information 15 | * @example 16 | * // Promise 17 | * client.Account.get().then(function(info){}); 18 | * 19 | * // Callback 20 | * client.Account.get(function(err, info){}); 21 | */ 22 | this.get = function (callback) { 23 | return client.makeRequest({ 24 | path : "account", 25 | method : "GET" 26 | }) 27 | .then(function (response) { 28 | return response.body; 29 | }) 30 | .asCallback(callback); 31 | }; 32 | 33 | /** 34 | * Gets a list of transactions from user's account. 35 | * @param {Object} params Query parameters for listing accounts 36 | * @param {Number} [params.size=25] Used for pagination to indicate the size of each page requested 37 | * for querying a list of transactions. If no value is specified the default value is 25 (maximum value 1000). 38 | * @param {Number} [params.maxItems] Limit the number of transactions that will be returned 39 | * @param {String} [params.toDate] Return only transactions that are newer than the parameter. 40 | * @param {String} [params.fromDate] Return only transactions that are older than the parameter. 41 | * @param {String} [params.type] Return only transactions that are this type. 42 | * @param {Function} callback A callback with the list of transactions 43 | * @return {TransactionListResponse} A promise for the list of transactions 44 | * @example 45 | * 46 | * //Promise 47 | * client.Account.getTransactions() 48 | * .then(function (response) { 49 | * console.log(response.transactions); 50 | * if(response.hasNextPage) { 51 | * return response.getNextPage(); 52 | * } 53 | * else { 54 | * return {transactions: []}; 55 | * } 56 | * }) 57 | * .then(function(response) { 58 | * console.log(response.transactions); 59 | * }); 60 | * @example 61 | * //Get transactions filtering by date 62 | * //Promise 63 | * var params = { 64 | * fromDate: "2013-02-21T13:38:00" 65 | * }; 66 | * client.Account.getTransactions(params) 67 | * .then(function (response) { 68 | * console.log(response.transactions); 69 | * if(response.hasNextPage) { 70 | * return response.getNextPage(); 71 | * } 72 | * else { 73 | * return {transactions: []}; 74 | * } 75 | * }) 76 | * .then(function(response) { 77 | * console.log(response.transactions); 78 | * }); 79 | * @example 80 | * //Get transactions filtering by date 81 | * //Promise 82 | * var params = { 83 | * fromDate: "2013-02-21T13:38:00", 84 | * toDate: "2013-02-21T13:40:00" 85 | * }; 86 | * client.Account.getTransactions(params) 87 | * .then(function (response) { 88 | * console.log(response.transactions); 89 | * if(response.hasNextPage) { 90 | * return response.getNextPage(); 91 | * } 92 | * else { 93 | * return {transactions: []}; 94 | * } 95 | * }) 96 | * .then(function(response) { 97 | * console.log(response.transactions); 98 | * }); 99 | * @example 100 | * //Get transactions limiting result 101 | * //Promise 102 | * var params = { 103 | * maxItems: 1 104 | * }; 105 | * client.Account.getTransactions(params) 106 | * .then(function (response) { 107 | * console.log(response.transactions); 108 | * if(response.hasNextPage) { 109 | * return response.getNextPage(); 110 | * } 111 | * else { 112 | * return {transactions: []}; 113 | * } 114 | * }) 115 | * .then(function(response) { 116 | * console.log(response.transactions); 117 | * }); 118 | * 119 | * @example 120 | * //Get transactions of `payment` type 121 | * //Promise 122 | * var params = { 123 | * type: "Payment" 124 | * }; 125 | * client.Account.getTransactions(params) 126 | * .then(function (response) { 127 | * console.log(response.transactions); 128 | * if(response.hasNextPage) { 129 | * return response.getNextPage(); 130 | * } 131 | * else { 132 | * return {transactions: []}; 133 | * } 134 | * }) 135 | * .then(function(response) { 136 | * console.log(response.transactions); 137 | * }); 138 | * 139 | */ 140 | this.getTransactions = function (params, callback) { 141 | var self = this; 142 | return client.makeRequest({ 143 | path : "account/transactions", 144 | method : "GET", 145 | qs : params 146 | }) 147 | .then(function (response) { 148 | var transactionListResponse = { 149 | transactions : response.body, 150 | hasNextPage : false, 151 | getNextPage : function (nextCallback) { 152 | return Promise.reject("Next page does not exist.") 153 | .asCallback(nextCallback); 154 | } 155 | }; 156 | var nextLink = getNextLink(response.headers); 157 | if (nextLink) { 158 | transactionListResponse.hasNextPage = true; 159 | transactionListResponse.getNextPage = function (nextCallback) { 160 | return self.getTransactions(nextLink, nextCallback); 161 | }; 162 | } 163 | return transactionListResponse; 164 | }) 165 | .asCallback(callback); 166 | }; 167 | }; 168 | 169 | module.exports = Account; 170 | 171 | /** 172 | * @class AccountResponse 173 | * @type {Object} 174 | * @property {String} balance User's account balance in dollars, as a string; 175 | * the currency symbol is not included. 176 | * @property {String} type The type of account configured for your user. 177 | */ 178 | 179 | /** 180 | * @class TransactionListResponse 181 | * @type {Object} 182 | * @property {Array.} transactions Array of transactions 183 | * @property {function} getNextPage Calls the next page function 184 | * @property {boolean} hasNextPage True/False flag for next 185 | */ 186 | 187 | /** 188 | * @class TransactionResponse 189 | * @type {Object} 190 | * @property {String} id The unique identifier for the transaction. 191 | * @property {String} time The time the transaction was processed. 192 | * @property {String} amount The transaction amount in dollars, as a string; 193 | * the currency symbol is not included. 194 | * @property {String} type The type of transaction. 195 | * @property {String} units The number of product units the transaction charged or credited. 196 | * @property {String} productType The product the transaction was related to 197 | * @property {String} number The phone number the transaction was related to 198 | */ 199 | -------------------------------------------------------------------------------- /lib/application.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Application 6 | * @constructor 7 | * @param {Object} client Catapult client 8 | */ 9 | 10 | var Application = function (client) { 11 | /** 12 | * List the user's applications 13 | * @param {Object} params Parameters for filtering applications. 14 | * @param {Number} [params.size] The maximum number of applications returned by 15 | * the query per page (Max size: 1000). 16 | * @param {Function} [callback] A callback for the list of applications. 17 | * @return {ApplicationListResponse} A promise for the list of applications, has a getNextPage 18 | * function if the number of applications returned by the query exceeds the page size. 19 | * @example 20 | * //Promise 21 | * client.Application.list() 22 | * .then(function (response) { 23 | * console.log(response.applications); 24 | * if(response.hasNextPage) { 25 | * return response.getNextPage(); 26 | * } 27 | * else { 28 | * return {applications: []}; 29 | * } 30 | * }) 31 | * .then(function(response) { 32 | * console.log(response.applications); 33 | * }); 34 | */ 35 | this.list = function (params, callback) { 36 | var self = this; 37 | return client.makeRequest({ 38 | path : "applications", 39 | method : "GET", 40 | qs : params 41 | }) 42 | .then(function (response) { 43 | var applicationListResponse = { 44 | applications : response.body, 45 | hasNextPage : false, 46 | getNextPage : function (nextCallback) { 47 | return Promise.reject("Next page does not exist.") 48 | .asCallback(nextCallback); 49 | } 50 | }; 51 | var nextLink = getNextLink(response.headers); 52 | if (nextLink) { 53 | applicationListResponse.hasNextPage = true; 54 | applicationListResponse.getNextPage = function (nextCallback) { 55 | return self.list(nextLink, nextCallback); 56 | }; 57 | } 58 | return applicationListResponse; 59 | }) 60 | .asCallback(callback); 61 | }; 62 | 63 | /** 64 | * Create a new application 65 | * @param {Object} params Parameters for creating a new call 66 | * @param {String} params.name A name you choose for this application. 67 | * @param {String} params.incomingCallUrl A URL where call events will be sent for an inbound call. 68 | * This is the endpoint where the Application Platform will send all call events. 69 | * Either incomingCallUrl or incomingMessageUrl is required. 70 | * @param {String} [params.incomingCallUrlCallbackTimeout] Determine how long should the platform wait 71 | * for incomingCallUrl's response before timing out in milliseconds. 72 | * @param {String} [params.incomingCallFallbackUrl] The URL used to send the callback 73 | * event if the request to incomingCallUrl fails. 74 | * @param {String} params.incomingMessageUrl A URL where message events will be sent for an inbound message. 75 | * This is the endpoint where the Application Platform will send all message events. 76 | * Either incomingMessageUrl or incomingCallUrl is required. 77 | * @param {Number} [params.incomingMessageUrlCallbackTimeout] Determine how long should the platform wait for 78 | * incomingMessageUrl's response before timing out in milliseconds. 79 | * @param {String} [params.incomingMessageFallbackUrl] The URL used to send the callback event if 80 | * the request to incomingMessageUrl fails. 81 | * @param {String} [params.callbackHttpMethod] Determine if the callback event should be sent via HTTP GET 82 | * or HTTP POST. Values are "get" or "post", default: "post". 83 | * @param {Boolean} [params.autoAnswer=true] Determines whether or not an incoming call should be 84 | * automatically answered. Default value is 'true'. 85 | * @param {Function} [callback] A callback for the list of applications 86 | * @return {ApplicationResponse} A promise for the newly created application. 87 | * @example 88 | * //Promise 89 | * client.Application.create({ 90 | * name: 'SampleApp', 91 | * incomingCallUrl: 'http://your-server.com/CallCallback', 92 | * incomingMessageUrl: 'http://your-server.com/MsgCallback' 93 | * }) 94 | * .then(function (response) { 95 | * console.log(response); 96 | * }); 97 | * 98 | * //Callback 99 | * client.Application.create({ 100 | * name: 'SampleApp2', 101 | * incomingCallUrl: 'http://your-server.com/CallCallback', 102 | * incomingMessageUrl: 'http://your-server.com/MsgCallback' 103 | * }, function (err, response) { 104 | * if (err) { 105 | * console.log(err); 106 | * } 107 | * else { 108 | * console.log(response) 109 | * } 110 | * }); 111 | */ 112 | this.create = function (params, callback) { 113 | return client.makeRequest({ 114 | path : "applications", 115 | method : "POST", 116 | body : params 117 | }) 118 | .then(function (response) { 119 | var application = params; 120 | var location = response.headers.location; 121 | var applicationId = location.substring(location.lastIndexOf("/") + 1); 122 | application.id = applicationId; 123 | return application; 124 | }) 125 | .asCallback(callback); 126 | }; 127 | 128 | /** 129 | * Get an application. 130 | * @param {String} applicationId The ID of the application to get. 131 | * @param {Function} [callback] A callback for the application. 132 | * @return {ApplicationResponse} A promise for the application. 133 | * @example 134 | * // Promise 135 | * client.Application.get('a-j4f2jz53mq') 136 | * .then(function (response) { 137 | * console.log(response); 138 | * }); 139 | * 140 | * // Callback 141 | * client.Application.get('a-zuwwfzzrbea', 142 | * function (err, response) { 143 | * if (err) { 144 | * console.log(err); 145 | * } 146 | * else { 147 | * console.log(response); 148 | * } 149 | * }); 150 | */ 151 | this.get = function (applicationId, callback) { 152 | return client.makeRequest({ 153 | path : "applications/" + applicationId, 154 | method : "GET" 155 | }) 156 | .then(function (response) { 157 | return response.body; 158 | }) 159 | .asCallback(callback); 160 | }; 161 | 162 | /** 163 | * Make changes to an application. 164 | * @param {String} applicationId The ID of the application to modify. 165 | * @param {Object} params Parameters for creating a new call 166 | * @param {String} [params.name] A name you choose for this application. 167 | * @param {String} [params.incomingCallUrl] A URL where call events will be sent for an inbound call. 168 | * This is the endpoint where the Application Platform will send all call events. 169 | * Either incomingCallUrl or incomingMessageUrl is required. 170 | * @param {String} [params.incomingCallUrlCallbackTimeout] Determine how long should the platform wait 171 | * for incomingCallUrl's response before timing out in milliseconds. 172 | * @param {String} [params.incomingCallFallbackUrl] The URL used to send the callback 173 | * event if the request to incomingCallUrl fails. 174 | * @param {String} [params.incomingMessageUrl] A URL where message events will be sent for an inbound message. 175 | * This is the endpoint where the Application Platform will send all message events. 176 | * Either incomingMessageUrl or incomingCallUrl is required. 177 | * @param {Number} [params.incomingMessageUrlCallbackTimeout] Determine how long should the platform wait for 178 | * incomingMessageUrl's response before timing out in milliseconds. 179 | * @param {String} [params.incomingMessageFallbackUrl] The URL used to send the callback event if 180 | * the request to incomingMessageUrl fails. 181 | * @param {String} [params.callbackHttpMethod] Determine if the callback event should be sent via HTTP GET 182 | * or HTTP POST. Values are "get" or "post", default: "post". 183 | * @param {Boolean} [params.autoAnswer] Determines whether or not an incoming call should be 184 | * automatically answered. Default value is 'true'. 185 | * @param {Function} [callback] A callback for the list of applications 186 | * @example 187 | * // Promise 188 | * client.Application.update('a-j4f2j6vjmqz53mq', { 189 | * name: 'Rename App1', 190 | * autoAnswer: false 191 | * }) 192 | * .then(function (response) { 193 | * console.log(response); 194 | * }); 195 | * 196 | * // Callback 197 | * client.Application.update('a-zudcfzzrbea', 198 | * { 199 | * name: 'Rename App2', 200 | * autoAnswer: false 201 | * }, 202 | * function (err, response) { 203 | * if (err) { 204 | * console.log(err); 205 | * } 206 | * else { 207 | * console.log(response); 208 | * } 209 | * }); 210 | */ 211 | this.update = function (applicationId, params, callback) { 212 | return client.makeRequest({ 213 | path : "applications/" + applicationId, 214 | method : "POST", 215 | body : params 216 | }) 217 | .then(function () { 218 | return; 219 | }) 220 | .asCallback(callback); 221 | }; 222 | 223 | /** 224 | * Delete an application. 225 | * @param {String} applicationId The ID of the application to delete. 226 | * @param {Function} [callback] A callback for the application. 227 | * @example 228 | * // Promise 229 | * client.Application.delete('a-j4f2j6mqz53mq') 230 | * .then(function (response) { 231 | * console.log(response); 232 | * }); 233 | * 234 | * // Callback 235 | * client.Application.delete('a-zuwwzrbea', 236 | * function (err, response) { 237 | * if (err) { 238 | * console.log(err); 239 | * } 240 | * else { 241 | * console.log(response); 242 | * } 243 | * }); 244 | */ 245 | this.delete = function (applicationId, callback) { 246 | return client.makeRequest({ 247 | path : "applications/" + applicationId, 248 | method : "DELETE" 249 | }) 250 | .then(function () { 251 | return; 252 | }) 253 | .asCallback(callback); 254 | }; 255 | 256 | }; 257 | 258 | module.exports = Application; 259 | 260 | /** 261 | * @class ApplicationListResponse 262 | * @type {Object} 263 | * @property {Array.} applications Array of applications 264 | * @property {function} getNextPage Calls the next page function 265 | * @property {boolean} hasNextPage True/False flag for next 266 | */ 267 | 268 | /** 269 | * ApplicationResponse 270 | * @class ApplicationResponse 271 | * @type {Object} 272 | * @property {String} id The unique identifier for the application. 273 | * @property {String} name A name you choose for this application. 274 | * @property {String} incomingCallUrl A URL where call events will be sent for an inbound call. 275 | * This is the endpoint where the Application Platform will send all call events. 276 | * Either incomingCallUrl or incomingMessageUrl is required. 277 | * @property {String} incomingCallUrlCallbackTimeout Determine how long should the platform wait 278 | * for incomingCallUrl's response before timing out in milliseconds. 279 | * @property {String} incomingCallFallbackUrl The URL used to send the callback 280 | * event if the request to incomingCallUrl fails. 281 | * @property {String} callbackHttpMethod Determine if the callback event should be sent via HTTP GET 282 | * or HTTP POST. Values are "get" or "post", default: "post". 283 | * @property {Boolean} autoAnswer Determines whether or not an incoming call should be 284 | * automatically answered. Default value is 'true'. 285 | * @property {String} incomingMessageUrl A URL where message events will be sent for an inbound message. 286 | * This is the endpoint where the Application Platform will send all message events. 287 | * Either incomingMessageUrl or incomingCallUrl is required. 288 | * @property {Number} incomingMessageUrlCallbackTimeout Determine how long should the platform wait for 289 | * incomingMessageUrl's response before timing out in milliseconds. 290 | * @property {String} incomingMessageFallbackUrl The URL used to send the callback event if 291 | * the request to incomingMessageUrl fails. 292 | */ -------------------------------------------------------------------------------- /lib/availableNumber.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Available numbers 3 | * @constructor 4 | */ 5 | var AvailableNumber = function (client) { 6 | /** 7 | * Search for available local or tollFree numbers 8 | * @param {String} type Type of number to search (local or tollFree) 9 | * @param {Object} params Search parameters 10 | * @param {String} [params.city] A city name (only for local numbers) 11 | * @param {String} [params.state] A state name (only for local numbers) 12 | * @param {String} [params.zip] A 5-digit US ZIP code (only for local numbers) 13 | * @param {String} [params.areaCode] A 3-digit telephone area code (only for local numbers) 14 | * @param {String} [params.localNumber] First digits of a telephone number inside an area code 15 | * for filtering the results (only for local numbers) 16 | * @param {String} [params.inLocalCallingArea] Boolean value to indicate that the search for 17 | * available numbers must consider overlayed areas. Only applied for localNumber searching. 18 | * (only for local numbers) 19 | * @param {String} [params.quantity] The maximum number of numbers to return (default 10, maximum 5000) 20 | * @param {String} [params.pattern] A number pattern that may include letters, digits, and the following 21 | * wildcard characters: ? - matches any single digit, * - matches zero or more digits 22 | * @param {Function} callback A callback with the list of available numbers 23 | * @return {Array.} A promise for the list of available numbers 24 | * @example 25 | * // Search 3 available local phone numbers with area code 910 26 | * 27 | * // Promise 28 | * client.AvailableNumber.search("local", { areaCode : "910", quantity : 3 }).then(function (numbers) {}); 29 | * 30 | * // Callback 31 | * client.AvailableNumber.search("local", { areaCode : "910", quantity : 3 }, function (err, numbers) {}); 32 | * @example 33 | * //Promise 34 | * client.AvailableNumber.search("tollFree", { 35 | * quantity : 3 }) 36 | * .then(function (numbers) { 37 | * console.log(numbers) 38 | * }); 39 | * 40 | * // Callback 41 | * client.AvailableNumber.search("tollFree", { 42 | * quantity : 3 }, 43 | * function (err, numbers) { 44 | * if(err) { 45 | * console.log(err); 46 | * } 47 | * else { 48 | * console.log(numbers); 49 | * } 50 | * }); 51 | */ 52 | this.search = function (type, params, callback) { 53 | return client.makeRequest({ 54 | pathWithoutUser : true, 55 | path : "availableNumbers/" + type, 56 | method : "GET", 57 | qs : params 58 | }) 59 | .then(function (response) { 60 | return response.body; 61 | }) 62 | .asCallback(callback); 63 | }; 64 | 65 | /** 66 | * Search for available local or tollFree numbers and order them 67 | * @param {String} type Type of number to search (local or tollFree) 68 | * @param {Object} params Search parameters 69 | * @param {String} [params.city] A city name (only for local numbers) 70 | * @param {String} [params.state] A state name (only for local numbers) 71 | * @param {String} [params.zip] A 5-digit US ZIP code (only for local numbers) 72 | * @param {String} [params.areaCode] A 3-digit telephone area code (only for local numbers) 73 | * @param {String} [params.localNumber] First digits of a telephone number inside an area code for 74 | * filtering the results (only for local numbers) 75 | * @param {String} [params.pattern] A number pattern that may include letters, digits, and the following 76 | * wildcard characters: ? - matches any single digit, * - matches zero or more digits 77 | * @param {String} [params.inLocalCallingArea] Boolean value to indicate that the search for 78 | * available numbers must consider overlayed areas. Only applied for localNumber searching. 79 | * (only for local numbers) 80 | * @param {String} [params.quantity] The maximum number of numbers to return 81 | * (default 10, maximum 5000) 82 | * @param {Function} callback A callback with the list of ordered numbers 83 | * @return {Array.} A promise for the list of ordered numbers 84 | * @example 85 | * // Search 2 available local phone numbers with area code 910 and order them 86 | * 87 | * // Promise 88 | * client.AvailableNumber.searchAndOrder("local", { areaCode : "910", quantity : 2 }).then(function (numbers) {}); 89 | * 90 | * // Callback 91 | * client.AvailableNumber.serchAndOrder("local", { areaCode : "910", quantity : 2 }, function (err, numbers) {}); 92 | * @example 93 | * //Search and order tollfree numbers 94 | * //Promise 95 | * client.AvailableNumber.searchAndOrder("tollFree", { 96 | * quantity : 1 }) 97 | * .then(function (numbers) { 98 | * console.log(numbers) 99 | * }); 100 | * 101 | * // Callback 102 | * client.AvailableNumber.searchAndOrder("tollFree", { 103 | * quantity : 1 }, 104 | * function (err, numbers) { 105 | * if(err) { 106 | * console.log(err); 107 | * } 108 | * else { 109 | * console.log(numbers); 110 | * } 111 | * }); 112 | */ 113 | this.searchAndOrder = function (type, params, callback) { 114 | return client.makeRequest({ 115 | pathWithoutUser : true, 116 | path : "availableNumbers/" + type, 117 | method : "POST", 118 | qs : params 119 | }) 120 | .then(function (response) { 121 | return response.body.map(function (item) { 122 | var location = item.location; 123 | item.id = location.substring(location.lastIndexOf("/") + 1); 124 | return item; 125 | }); 126 | }) 127 | .asCallback(callback); 128 | }; 129 | }; 130 | 131 | module.exports = AvailableNumber; 132 | 133 | /** 134 | * @class AvailableNumberResponse 135 | * @type {Object} 136 | * @property {String} number Phone number. 137 | * @property {String} nationalNumber Phone number in national format. 138 | * @property {String} price Price of this phone number. 139 | * @property {String} city A city name of number (only for local numbers). 140 | * @property {String} rateCenter A rate center (only for local numbers). 141 | * @property {String} state A state of number (only for local numbers). 142 | */ 143 | 144 | /** 145 | * @class OrderedNumberResponse 146 | * @type {Object} 147 | * @property {String} id Id of ordered number. 148 | * @property {String} number Phone number. 149 | * @property {String} nationalNumber Phone number in national format. 150 | * @property {String} price Price of this phone number. 151 | */ 152 | -------------------------------------------------------------------------------- /lib/bridge.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Bridge 6 | * @constructor 7 | */ 8 | var Bridge = function (client) { 9 | /** 10 | * Create a new bridge 11 | * @param {Object} params Parameters for creating a bridge 12 | * @param {Boolean} [params.bridgeAudio=true] Enable/Disable two way audio path. 13 | * @param {Array} [params.callIds] The list of call ids in the bridge. If the list of call ids 14 | * is not provided the bridge is logically created and it can be used to place calls later. 15 | * @param {Function} [callback] Callback with the newly created bridge 16 | * @return {BridgeResponse} A promise for the newly created bridge 17 | * @example 18 | * //Promise 19 | * client.Bridge.create({ 20 | * bridgeAudio: true, 21 | * callIds: ['c-qbs5kwrsyx6wsdi', 'c-zan4g74pprsq'] 22 | * }) 23 | * .then(function (response) { 24 | * console.log(response); 25 | * }); 26 | * 27 | * //Callback 28 | * client.Bridge.create({ 29 | * bridgeAudio: true, 30 | * callIds: ['c-qbsx6wsdi', 'c-zan4g7prsq'] 31 | * }, function (err, response) { 32 | * if(err) { 33 | * console.log(err); 34 | * } 35 | * else { 36 | * console.log(response); 37 | * } 38 | * }); 39 | */ 40 | this.create = function (params, callback) { 41 | return client.makeRequest({ 42 | path : "bridges", 43 | method : "POST", 44 | body : params 45 | }) 46 | .then(function (response) { 47 | var bridge = params; 48 | var location = response.headers.location; 49 | bridge.id = location.substring(location.lastIndexOf("/") + 1); 50 | return bridge; 51 | }) 52 | .asCallback(callback); 53 | }; 54 | 55 | /** 56 | * Gets information about a bridge. 57 | * @param {String} bridgeId The ID of the bridge to get 58 | * @param {Function} callback A callback with the call information 59 | * @return {BridgeResponse} A promise for the call information 60 | * @example 61 | * //Promise 62 | * client.Bridge.get('brg-65dhjwrmbasiei') 63 | * .then(function (response) { 64 | * console.log(response); 65 | * }); 66 | * 67 | * //Callback 68 | * client.Bridge.get('brg-65dhmbasiei', 69 | * function (err, response) { 70 | * if(err) { 71 | * console.log(err); 72 | * } 73 | * else { 74 | * console.log(response); 75 | * } 76 | * }); 77 | */ 78 | this.get = function (bridgeId, callback) { 79 | return client.makeRequest({ 80 | path : "bridges/" + bridgeId, 81 | method : "GET" 82 | }) 83 | .then(function (response) { 84 | return response.body; 85 | }) 86 | .asCallback(callback); 87 | }; 88 | 89 | /** 90 | * Gets a list of bridges. 91 | * @param {Object} params Query parameters for listing bridges 92 | * @param {Number} [params.size=25] Used for pagination to indicate the size of each page requested 93 | * for querying a list of bridges. If no value is specified the default value is 25 (maximum value 1000). 94 | * @param {Function} callback A callback with the list of bridges 95 | * @return {BridgeListResponse} A promise for the list of bridges 96 | * @example 97 | * client.Bridge.list() 98 | * .then(function (response) { 99 | * console.log(response.bridges); 100 | * if(response.hasNextPage) { 101 | * return response.getNextPage(); 102 | * } 103 | * else { 104 | * return {bridges: []}; 105 | * } 106 | * }) 107 | * .then(function(response) { 108 | * console.log(response.bridges); 109 | * }); 110 | */ 111 | this.list = function (params, callback) { 112 | var self = this; 113 | return client.makeRequest({ 114 | path : "bridges", 115 | method : "GET", 116 | qs : params 117 | }) 118 | .then(function (response) { 119 | var bridgeListResponse = { 120 | bridges : response.body, 121 | hasNextPage : false, 122 | getNextPage : function (nextCallback) { 123 | return Promise.reject("Next page does not exist.") 124 | .asCallback(nextCallback); 125 | } 126 | }; 127 | var nextLink = getNextLink(response.headers); 128 | if (nextLink) { 129 | bridgeListResponse.hasNextPage = true; 130 | bridgeListResponse.getNextPage = function (nextCallback) { 131 | return self.list(nextLink, nextCallback); 132 | }; 133 | } 134 | return bridgeListResponse; 135 | }) 136 | .asCallback(callback); 137 | }; 138 | 139 | /** 140 | * Update the bridge 141 | * @param {String} bridgeId The ID of the bridge 142 | * @param {Object} params Changed parameters of the bridge 143 | * @param {Boolean} params.bridgeAudio Enable/Disable two way audio path (default = true). 144 | * @param {Array} params.callIds The list of call ids in the bridge. 145 | * @param {Function} [callback] Callback with the newly created bridge 146 | * @return {BridgeResponse} A promise for the operation 147 | * @example 148 | * //Promise 149 | * client.Bridge.update('brg-65dasiei', { 150 | * bridgeAudio: false 151 | * }) 152 | * .then(function (response) { 153 | * console.log(response); 154 | * }); 155 | * 156 | * //Callback 157 | * client.Bridge.update('brg-65dhjbanasiei', { 158 | * bridgeAudio: false 159 | * }, function (err, response) { 160 | * if(err) { 161 | * console.log(err); 162 | * } 163 | * else { 164 | * console.log(response); 165 | * } 166 | * }); 167 | * 168 | * @example 169 | * // end bridge 170 | * var bridgeOptions = { 171 | * callIds: [] 172 | * }; 173 | * 174 | * client.Bridge.update("{bridgeId}", bridgeOptions) 175 | * .then(function () { 176 | * // continue 177 | * }); 178 | * 179 | * @example 180 | * // Add two calls to bridge then remove one 181 | * var bridgeOptions = { 182 | * bridgeAudio : true, 183 | * callIds: ["{callId1}","{callId2}"] 184 | * }; 185 | * 186 | * client.Bridge.update("{bridgeId}", bridgeOptions) 187 | * .then(function () { 188 | * var callIdsToRemainInBridge = { 189 | * callIds: ["{callId1"] 190 | * }; 191 | * return client.Bridge.update("{bridgeId}", callIdsToRemainInBridge) 192 | * }) 193 | * .then(function () { 194 | * //continue 195 | * }); 196 | */ 197 | this.update = function (bridgeId, params, callback) { 198 | return client.makeRequest({ 199 | path : "bridges/" + bridgeId, 200 | method : "POST", 201 | body : params 202 | }) 203 | .then(function () { 204 | return; 205 | }) 206 | .asCallback(callback); 207 | }; 208 | 209 | function audioApi (bridgeId, params, callback) { 210 | return client.makeRequest({ 211 | path : "bridges/" + bridgeId + "/audio", 212 | method : "POST", 213 | body : params 214 | }) 215 | .then(function (response) { 216 | return response.body; 217 | }) 218 | .asCallback(callback); 219 | } 220 | 221 | /** 222 | * Speak sentence to the bridge using default values 223 | * @param {String} bridgeId The ID of the bridge 224 | * @param {String} sentence A sentence to speak to the bridge. 225 | * @param {Function} [callback] Callback for the operation 226 | * @return {Promise} A promise for the operation 227 | * @example 228 | * //Speak sentence in a bridge 229 | * 230 | * //Promise 231 | * client.Bridge.speakSentence("bridgeID", "Hello From Bandwidth").then(function (res) {}); 232 | * 233 | * //Callback 234 | * client.Bridge.speakSentence("bridgeID", "Hello From Bandwidth", function (err, res) {}); 235 | */ 236 | this.speakSentence = function (bridgeId, sentence, callback) { 237 | return audioApi(bridgeId, { sentence : sentence }).asCallback(callback); 238 | }; 239 | 240 | /** 241 | * This stops any file audio playback on the bridge 242 | * @param {String} bridgeId the Id of the bridge to stop speaking 243 | * @return {Promise} A promise of the operation 244 | * @example 245 | * //Promise 246 | * client.Bridge.stopSpeaking("bridgeId").then(function (res) {}); 247 | */ 248 | this.stopSpeaking = function (bridgeId, callback) { 249 | return this.speakSentence(bridgeId, "").asCallback(callback); 250 | }; 251 | 252 | /** 253 | * Play audio url to the bridge 254 | * @param {String} bridgeId The ID of the bridge 255 | * @param {String} fileUrl The http location of an audio file to play (WAV and MP3 supported). 256 | * @param {Function} [callback] Callback for the operation 257 | * @return {Promise} A promise for the operation 258 | * @example 259 | * //Play Audio file on bridge 260 | * 261 | * //Promise 262 | * client.Bridge.playAudioFile("bridgeID", "http://myurl.com/file.mp3").then(function (res) {}); 263 | * 264 | * //Callback 265 | * client.Bridge.playAudioFile("bridgeID", "http://myurl.com/file.wav", function (err, res) {}); 266 | */ 267 | this.playAudioFile = function (bridgeId, fileUrl, callback) { 268 | return audioApi(bridgeId, { fileUrl : fileUrl }).asCallback(callback); 269 | }; 270 | 271 | /** 272 | * Play audio file or speak sentence in bridge 273 | * @param {String} bridgeId The ID of the bridge 274 | * @param {Object} params Parameters to play audio in bridge. 275 | * @param {String} [params.fileUrl] The http location of an audio file to play (WAV and MP3 supported). 276 | * @param {String} [params.sentence] The sentence to speak. 277 | * @param {String} [params.gender=female] The gender of the voice used to synthesize the sentence. 278 | * It will be considered only if sentence is not null. The female gender will be used by default. 279 | * @param {String=} [params.locale=en_US] The locale used to get the accent of the voice used to 280 | * synthesize the sentence. Check out 281 | * {@link http://ap.bandwidth.com/docs/rest-api/bridges/#resourcePOSTv1usersuserIdbridgesbridgeIdaudio|docs} 282 | * for list of supported locales. 283 | * It will be considered only if sentence is not null/empty. The en_US will be used by default. 284 | * @param {String} [params.voice=Susan] The voice to speak the sentence. Check out 285 | * {@link http://ap.bandwidth.com/docs/rest-api/bridges/#resourcePOSTv1usersuserIdbridgesbridgeIdaudio|docs} 286 | * for list of supported voices 287 | * It will be considered only if sentence is not null/empty. Susan's voice will be used by default. 288 | * @param {Boolean} [params.loopEnabled=false] When value is true, the audio will keep playing in a loop. 289 | * Default: false. 290 | * @param {Function} [callback] Callback for the operation 291 | * @return {Promise} A promise for the operation 292 | * @example 293 | * //Play Audio File on loop 294 | * var options = { 295 | * fileUrl : "http://myurl.com/file.mp3", 296 | * loopEnabled : true 297 | * } 298 | * //Promise 299 | * client.Bridge.playAudioAdvanced("bridgeId", options).then(function (res) {}); 300 | * 301 | * //Callback 302 | * client.Bridge.playAudioAdvanced("bridgeId", options, function (err,res) {}); 303 | * @example 304 | * //Speak sentence with options 305 | * var options = { 306 | * sentence : "hola de Bandwidth", 307 | * gender : "male", 308 | * locale : "es", 309 | * voice : "Jorge" 310 | * } 311 | * //Promise 312 | * client.Bridge.playAudioAdvanced("bridgeId", options).then(function (res) {}); 313 | * 314 | * //Callback 315 | * client.Bridge.playAudioAdvanced("bridgeId", options, function (err,res) {}); 316 | */ 317 | this.playAudioAdvanced = function (bridgeId, params, callback) { 318 | return audioApi(bridgeId, params).asCallback(callback); 319 | }; 320 | 321 | /** 322 | * This stops any file audio playback on the bridge 323 | * @param {String} bridgeId the Id of the bridge to stop file playback 324 | * @return {Promise} A promise of the operation 325 | * @example 326 | * //Promise 327 | * client.Bridge.stopAudioFilePlayback("bridgeId").then(function (res) {}); 328 | */ 329 | this.stopAudioFilePlayback = function (bridgeId, callback) { 330 | return this.playAudioFile(bridgeId, "").asCallback(callback); 331 | }; 332 | 333 | /** 334 | * Gets information about a bridge. 335 | * @param {String} bridgeId The ID of the bridge to get 336 | * @param {Function} callback A callback with the call information 337 | * @return {Promise} A promise for the call information 338 | * @example 339 | * //Promise 340 | * client.Bridge.getCalls('brg-65dhjbiei') 341 | * .then(function (response) { 342 | * console.log(response); 343 | * }); 344 | * 345 | * //Callback 346 | * client.Bridge.getCalls('brg-65dhjrmbasiei', 347 | * function (err, response) { 348 | * if(err) { 349 | * console.log(err); 350 | * } 351 | * else { 352 | * console.log(response); 353 | * } 354 | * }); 355 | */ 356 | this.getCalls = function (bridgeId, callback) { 357 | return client.makeRequest({ 358 | path : "bridges/" + bridgeId + "/calls", 359 | method : "GET" 360 | }) 361 | .then(function (response) { 362 | return response.body; 363 | }) 364 | .asCallback(callback); 365 | }; 366 | }; 367 | 368 | module.exports = Bridge; 369 | 370 | /** 371 | * @class BridgeListResponse 372 | * @type {Object} 373 | * @property {Array.} bridges Array of bridges 374 | * @property {function} getNextPage Calls the next page function 375 | * @property {boolean} hasNextPage True/False flag for next 376 | */ 377 | 378 | /** 379 | * @class BridgeResponse 380 | * @type {Object} 381 | * @property {String} id The unique ID of the bridge. 382 | * @property {String} state Bridge state. Possible state values are described here. 383 | * @property {Array} callIds List of call Ids that will be in the bridge. 384 | * @property {Boolean} bridgeAudio Enable/Disable two way audio path. 385 | * @property {String} completedTime The time when the bridge was completed. 386 | * @property {String} createdTime The time that bridge was created. 387 | * @property {String} activatedTime The time that the bridge got into active state. 388 | */ 389 | -------------------------------------------------------------------------------- /lib/client.js: -------------------------------------------------------------------------------- 1 | var Promise = require("bluebird"); 2 | var request = Promise.promisify(require("request")); 3 | var UnexpectedResponseError = require("./unexpectedResponseError"); 4 | var RateLimitError = require("./RateLimitError"); 5 | var packageInfo = require("./../package.json"); 6 | 7 | var apiVersionPath = "/v1"; 8 | var usersPath = "/users"; 9 | 10 | var Client = function (config) { 11 | // Apply default values if not provided 12 | if (!config.baseUrl) { 13 | config.baseUrl = "https://api.catapult.inetwork.com"; 14 | } 15 | 16 | var handleResponse = function (response) { 17 | if (response.statusCode === 429) { 18 | if (response.headers && response.headers["x-ratelimit-reset"]) { 19 | var limitReset = response.headers["x-ratelimit-reset"]; 20 | throw new RateLimitError(response.body, response.statusCode, limitReset); 21 | } 22 | else { 23 | throw new UnexpectedResponseError(response.body, response.statusCode); 24 | } 25 | } 26 | else if (response.statusCode !== 200 && response.statusCode !== 201 && response.statusCode !== 202) { 27 | var message = ""; 28 | if (response.body) { 29 | message = response.body.message || ""; 30 | } 31 | throw new UnexpectedResponseError(message, response.statusCode); 32 | } 33 | return response; 34 | }; 35 | 36 | function getUserAgentHeader() { 37 | return packageInfo.name + "-v" + packageInfo.version; 38 | } 39 | 40 | function createRequestOptions (params) { 41 | //Added to allow the V1/V2 base url split 42 | //V1 endpoint functions remain unchanged, V2 inclues the new URL as 'apiBaseUrl' param 43 | var apiBaseUrl = params.apiBaseUrl ? params.apiBaseUrl : config.baseUrl; 44 | var baseUrl = apiBaseUrl + (params.apiVersion ? "/" + params.apiVersion : apiVersionPath); 45 | var userPath = params.pathWithoutUser ? "" : (usersPath + "/" + config.userId); 46 | 47 | return { 48 | url : baseUrl + userPath + "/" + params.path, 49 | headers : { 50 | "User-Agent" : getUserAgentHeader() 51 | }, 52 | qs : params.qs, 53 | method : params.method || "GET", 54 | auth : { 55 | user : config.apiToken, 56 | pass : config.apiSecret 57 | }, 58 | json : true, 59 | body : params.body, 60 | rejectUnauthorized : false, // for some reason this is required for bootcamp ssl 61 | encoding : params.encoding || params.encoding === null ? params.encoding : undefined 62 | }; 63 | } 64 | 65 | this.makeRequest = function (params) { 66 | return request(createRequestOptions(params)).then(handleResponse); 67 | }; 68 | 69 | this.createRequestOptions = createRequestOptions; 70 | 71 | this.handleResponse = handleResponse; 72 | 73 | this.getUserAgentHeader = getUserAgentHeader; 74 | }; 75 | 76 | module.exports = Client; 77 | -------------------------------------------------------------------------------- /lib/domain.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | /** 4 | * Domain 5 | * @constructor 6 | */ 7 | var Domain = function (client) { 8 | /** 9 | * Create a domain 10 | * @param {Object} params Parameters for creating a new domain 11 | * @param {String} params.name The name is a unique URI to be used in DNS lookups. 12 | * @param {String} params.description String to describe the domain. 13 | * @param {Function} [callback] Callback with the newly created domain 14 | * @return {DomainResponse} A promise for the newly created domain 15 | */ 16 | this.create = function (params, callback) { 17 | return client.makeRequest({ 18 | path : "domains", 19 | method : "POST", 20 | body : params 21 | }) 22 | .then(function (response) { 23 | var domain = params; 24 | var location = response.headers.location; 25 | var domainId = location.substring(location.lastIndexOf("/") + 1); 26 | domain.id = domainId; 27 | return domain; 28 | }) 29 | .asCallback(callback); 30 | }; 31 | 32 | /** 33 | * Gets a list of all domains. 34 | * @param {Function} callback A callback with the list of calls 35 | * @param {Number} [params.size] the maximum number of domains returned 36 | * by the query per page (Max size: 100). 37 | * @return {Array.} A promise for the list of domains. 38 | */ 39 | this.list = function (params, callback) { 40 | var self = this; 41 | return client.makeRequest({ 42 | path : "domains", 43 | method : "GET", 44 | qs : params 45 | }) 46 | .then(function (response) { 47 | var domainListResponse = { 48 | domains : response.body, 49 | hasNextPage : false, 50 | getNextPage : function (nextCallback) { 51 | return Promise.reject("Next page does not exist.") 52 | .asCallback(nextCallback); 53 | } 54 | }; 55 | var nextLink = getNextLink(response.headers); 56 | if (nextLink) { 57 | domainListResponse.hasNextPage = true; 58 | domainListResponse.getNextPage = function (nextCallback) { 59 | return self.list(nextLink, nextCallback); 60 | }; 61 | } 62 | return domainListResponse; 63 | }) 64 | .asCallback(callback); 65 | }; 66 | 67 | /** 68 | * Delete a domain. 69 | * @param {String} domainId ID of the domain to delete. 70 | * @param {Function} [callback] A callback for the domain. 71 | * @return {Promise} A promise for current operation. 72 | */ 73 | this.delete = function (domainId, callback) { 74 | return client.makeRequest({ 75 | path : "domains/" + domainId, 76 | method : "DELETE" 77 | }) 78 | .then(function () { 79 | return; 80 | }) 81 | .asCallback(callback); 82 | }; 83 | }; 84 | 85 | module.exports = Domain; 86 | 87 | /** 88 | * @class DomainResponse 89 | * @type {Object} 90 | * @property {String} id The unique identifier for the domain. 91 | * @property {String} name A name you choose for this domain. 92 | * @property {String} description A description of this domain. 93 | */ 94 | -------------------------------------------------------------------------------- /lib/endpoint.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Endpoint 6 | * @constructor 7 | */ 8 | var Endpoint = function (client) { 9 | /** 10 | * Create a new endpoint for the domain 11 | * @param {String} domainId Id of domain 12 | * @param {Object} params Parameters for creating a new endpoint 13 | * @param {String} params.name The endpoint's name, which SIP clients use as the "address of record" . 14 | * @param {String} params.description String to describe the endpoint. 15 | * 0param {String} params.applicationId The id of the application associated with this endpoint. 16 | * @param {Boolean} params.enabled Allow or not to receive and make calls. 17 | * @param {Object} params.credentials Auth parameters 18 | * @param {Function} [callback] Callback with the newly created endpoint 19 | * @return {EndpointResponse} A promise for the newly created endpoint 20 | * @example 21 | * // Promise 22 | * client.Endpoint.create("domainId", { name : "my-endpoint", applicationId : "appId", 23 | * credentials : { password : "123456" }}).then(function (endpoint) {}); 24 | * // Callback 25 | * client.Endpoint.create("domainId", { name : "my-endpoint", applicationId : "appId", 26 | * credentials : { password : "123456" }}, function (err, endpoint) {}); 27 | */ 28 | this.create = function (domainId, params, callback) { 29 | params.domainId = domainId; 30 | return client.makeRequest({ 31 | path : "domains/" + domainId + "/endpoints", 32 | method : "POST", 33 | body : params 34 | }) 35 | .then(function (response) { 36 | var enpoint = params; 37 | var location = response.headers.location; 38 | enpoint.id = location.substring(location.lastIndexOf("/") + 1); 39 | return enpoint; 40 | }) 41 | .asCallback(callback); 42 | }; 43 | 44 | /** 45 | * Gets a list of all endpoints for the domain. 46 | * @example 47 | * // Default size (25) using promises 48 | * client.Endpoint.list("domainId") 49 | * .then(function (res) {}); 50 | * @example 51 | * // Default size (25) using callbacks 52 | * client.Endpoint.list("domainId", function (err, res) {}); 53 | * @example 54 | * // Specify number of endpoints using promises 55 | * client.Endpoint.list("domainId", {size: 1000}) 56 | * .then(function (res) {}); 57 | * @example 58 | * // Specify number of endpoints using callbacks 59 | * client.Endpoint.list("domainId" {size: 1000}, function (err, res) {}); 60 | * @param {String} domainId Id of the domain to list the endpoints 61 | * @param {Object} params Parameters for listing endpoints on domain 62 | * @param {Number} [params.size] OPTIONAL The maximum number of endpoints returned by 63 | * the query per page (Max size: 1000). 64 | * @param {Function} [callback] A callback with the list of endpoints 65 | * @return {Array.} A promise for the list of endpoints. 66 | 67 | */ 68 | this.list = function (domainId, params, callback) { 69 | var self = this; 70 | if (typeof params === "function") { 71 | callback = params; 72 | params = {}; 73 | } 74 | return client.makeRequest({ 75 | path : "domains/" + domainId + "/endpoints", 76 | method : "GET", 77 | qs : params 78 | }) 79 | .then(function (response) { 80 | var endpointListResponse = { 81 | endpoints : response.body, 82 | hasNextPage : false, 83 | getNextPage : function (nextCallback) { 84 | return Promise.reject("Next page does not exist.") 85 | .asCallback(nextCallback); 86 | } 87 | }; 88 | var nextLink = getNextLink(response.headers); 89 | if (nextLink) { 90 | endpointListResponse.hasNextPage = true; 91 | endpointListResponse.getNextPage = function (nextCallback) { 92 | return self.list(domainId, nextLink, nextCallback); 93 | }; 94 | } 95 | return endpointListResponse; 96 | }) 97 | .asCallback(callback); 98 | }; 99 | 100 | /** 101 | * Get a single endpoint. 102 | * @param {String} domainId Id of the domain 103 | * @param {String} endpointId Id of the endpoint 104 | * @param {Function} [callback] A callback with the endpoint 105 | * @return {EndpointResponse} A promise for the endpoint. 106 | * @example 107 | * // Promise 108 | * client.Endpoint.get(domainId, endpointId).then(function(endpoint){}); 109 | * 110 | * // Callback 111 | * client.Endpoint.get(domainId, endpointId, function(err, endpoint){}); 112 | */ 113 | this.get = function (domainId, endpointId, callback) { 114 | return client.makeRequest({ 115 | path : "domains/" + domainId + "/endpoints/" + endpointId, 116 | method : "GET" 117 | }) 118 | .then(function (response) { 119 | return response.body; 120 | }) 121 | .asCallback(callback); 122 | }; 123 | 124 | /** 125 | * Delete an endpoint. 126 | * @param {String} domainId Id of domain 127 | * @param {String} endpointId ID of the endpoint to delete. 128 | * @param {Function} [callback] A callback for the operation. 129 | * @return {Promise} A promise for current operation. 130 | * @example 131 | * // Promise 132 | * client.Endpoint.delete("domainId", "endpointId").then(function (endpoint) {}); 133 | * // Callback 134 | * client.Endpoint.delete("domainId", "endpointId", function (err, endpoint) {}); 135 | */ 136 | this.delete = function (domainId, endpointId, callback) { 137 | return client.makeRequest({ 138 | path : "domains/" + domainId + "/endpoints/" + endpointId, 139 | method : "DELETE" 140 | }) 141 | .then(function () { 142 | return; 143 | }) 144 | .asCallback(callback); 145 | }; 146 | 147 | /** 148 | * Update an endpoint. 149 | * @param {String} domainId Id of domain 150 | * @param {String} endpointId ID of the endpoint to update. 151 | * @param {Object} params Changed parameters for the endpoint 152 | * @param {String} params.description String to describe the endpoint. 153 | * 0param {String} params.applicationId The id of the application associated with this endpoint. 154 | * @param {Boolean} params.enabled Allow or not to receive and make calls. 155 | * @param {Object} params.credentials Auth parameters 156 | * @param {Function} [callback] A callback for the operation. 157 | * @return {Promise} A promise for current operation. 158 | * @example 159 | * // Promise 160 | * client.Endpoint.update("domainId", "endpointId", { enabled : true }).then(function (endpoint) {}); 161 | * // Callback 162 | * client.Endpoint.update("domainId", "endpointId", { enabled : true }, function (err, endpoint) {}); 163 | */ 164 | this.update = function (domainId, endpointId, params, callback) { 165 | return client.makeRequest({ 166 | path : "domains/" + domainId + "/endpoints/" + endpointId, 167 | method : "POST", 168 | body : params 169 | }) 170 | .then(function () { 171 | return; 172 | }) 173 | .asCallback(callback); 174 | }; 175 | 176 | /** 177 | * Generate auth token for the endpoint. 178 | * @param {String} domainId Id of domain 179 | * @param {String} endpointId ID of the endpoint to update. 180 | * @param {Object} params parameters of token. 181 | * @param {Number} params.expires Expiration time of token in seconds 182 | * @param {Function} [callback] A callback with token value. 183 | * @return {Promise} A promise with token value. 184 | * @example 185 | * // Promise 186 | * client.Endpoint.createAuthToken("domainId", "endpointId", { expires : 3600 }).then(function (endpoint) {}); 187 | * // Callback 188 | * client.Endpoint.createAuthToken("domainId", "endpointId", { expires : 3600 }, function (err, endpoint) {}); 189 | */ 190 | this.createAuthToken = function (domainId, endpointId, params, callback) { 191 | return client.makeRequest({ 192 | path : "domains/" + domainId + "/endpoints/" + endpointId + "/tokens", 193 | method : "POST", 194 | body : params 195 | }) 196 | .then(function (response) { 197 | return response.body; 198 | }) 199 | .asCallback(callback); 200 | }; 201 | }; 202 | 203 | module.exports = Endpoint; 204 | 205 | /** 206 | * @class EndpointResponse 207 | * @type {Object} 208 | * @property {String} id The unique identifier for the application. 209 | * @param {String} name The endpoint's name, which SIP clients use as the "address of record" . 210 | * @param {String} description String to describe the endpoint. 211 | * 0param {String} applicationId The id of the application associated with this endpoint. 212 | * @param {Boolean} enabled Allow or not to receive and make calls. 213 | * @param {Object} credentials Auth parameters 214 | */ 215 | -------------------------------------------------------------------------------- /lib/error.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Error 6 | * @constructor 7 | */ 8 | var Error = function (client) { 9 | 10 | /** 11 | * Gets information about a error. 12 | * @param {String} errorId The ID of the error to get 13 | * @param {Function} [callback] A callback with the error information 14 | * @return {ErrorResponse} A promise for the error information 15 | * @example 16 | * 17 | * // Promise 18 | * client.Error.get(errorId).then(function(errorInfo){}); 19 | * 20 | * // Callback 21 | * client.Error.get(errorId, function(err, errorInfo){}); 22 | */ 23 | this.get = function (errorId, callback) { 24 | return client.makeRequest({ 25 | path : "errors/" + errorId, 26 | method : "GET" 27 | }) 28 | .then(function (response) { 29 | return response.body; 30 | }) 31 | .asCallback(callback); 32 | }; 33 | 34 | /** 35 | * Gets a list of errors. 36 | * @param {Object} params Query parameters for listing errors 37 | * @param {Number} [params.size=25] Used for pagination to indicate the size of each page requested 38 | * for querying a list of errors. If no value is specified the default value is 25. 39 | * @param {Function} [callback] A callback with the list of errors 40 | * @return {Array.} A promise for the list of errors 41 | * @example 42 | * 43 | * // Promise 44 | * client.Error.list({size: 1000}).then(function(errorResponse){}); 45 | * 46 | * // Callback 47 | * client.Error.list({size: 1000}, function(err, errorResponse){}); 48 | */ 49 | this.list = function (params, callback) { 50 | var self = this; 51 | return client.makeRequest({ 52 | path : "errors", 53 | method : "GET", 54 | qs : params 55 | }) 56 | .then(function (response) { 57 | var errorListResponse = { 58 | errors : response.body, 59 | hasNextPage : false, 60 | getNextPage : function (nextCallback) { 61 | return Promise.reject("Next page does not exist.") 62 | .asCallback(nextCallback); 63 | } 64 | }; 65 | var nextLink = getNextLink(response.headers); 66 | if (nextLink) { 67 | errorListResponse.hasNextPage = true; 68 | errorListResponse.getNextPage = function (nextCallback) { 69 | return self.list(nextLink, nextCallback); 70 | }; 71 | } 72 | return errorListResponse; 73 | }) 74 | .asCallback(callback); 75 | }; 76 | }; 77 | 78 | module.exports = Error; 79 | 80 | /** 81 | * @class ErrorResponse 82 | * @type {Object} 83 | * @property {String} id The unique ID of the error. 84 | * @property {String} time The time the error occurred (UTC). 85 | * @property {String} category The error category. 86 | * @property {String} code A specific error code string that identifies the type of error 87 | * @property {String} message A message that describes the error condition in detail. 88 | * @property {Object} details A list of name/value pairs of additional details. 89 | */ 90 | -------------------------------------------------------------------------------- /lib/headerParsingLib.js: -------------------------------------------------------------------------------- 1 | var parse = require("parse-link-header"); 2 | var _ = require("lodash"); 3 | 4 | /** 5 | * getNextLink 6 | * @function 7 | * @param {Object} response A headers object returned from calling 'client.makeRequest' (response.headers) 8 | * @returns A parsed version of the link to the subsequent page, or null if no such page exists. 9 | */ 10 | var getNextLink = function (headers) { 11 | if (headers.link) { 12 | var parsedHeader = parse(headers.link); 13 | if (parsedHeader.next) { 14 | return _.omit(parsedHeader.next, [ "rel", "url" ]); 15 | } 16 | } 17 | return null; 18 | }; 19 | 20 | module.exports.getNextLink = getNextLink; -------------------------------------------------------------------------------- /lib/index.js: -------------------------------------------------------------------------------- 1 | var Client = require("./client"); 2 | var Account = require("./account"); 3 | var Message = require("./message"); 4 | var Call = require("./call"); 5 | var Conference = require("./conference"); 6 | var Bridge = require("./bridge"); 7 | var Domain = require("./domain"); 8 | var Endpoint = require("./endpoint"); 9 | var ErrorType = require("./error"); 10 | var NumberInfo = require("./numberInfo"); 11 | var Media = require("./media"); 12 | var Application = require("./application"); 13 | var Recording = require("./recording"); 14 | var AvailableNumber = require("./availableNumber"); 15 | var PhoneNumber = require("./phoneNumber"); 16 | var UnexpectedResponseError = require("./unexpectedResponseError"); 17 | var RateLimitError = require("./RateLimitError"); 18 | var BXMLResponse = require("./xml"); 19 | var MessageV2 = require("./v2/message"); 20 | var queries = require("./v2/searchAndOrderNumberQueries"); 21 | 22 | /** 23 | * Catapult API Client 24 | * @constructor 25 | * @param {Object} config - Client configuration parameters 26 | * @param {String} config.userId - Your Catapult user ID 27 | * @param {String} config.apiToken - Your Catapult API token 28 | * @param {String} config.apiSecret - Your Catapult API secret 29 | * @param {String} [config.baseUrl=https://api.catapult.inetwork.com] - The catapult base URL. 30 | * Configurable for using alternative Catapult environments. 31 | */ 32 | var CatapultClient = function (config) { 33 | var client = new Client(config); 34 | this.Account = new Account(client); 35 | this.Media = new Media(client); 36 | this.Message = new Message(client); 37 | this.Call = new Call(client); 38 | this.Conference = new Conference(client); 39 | this.Bridge = new Bridge(client); 40 | this.Domain = new Domain(client); 41 | this.Endpoint = new Endpoint(client); 42 | this.Error = new ErrorType(client); 43 | this.NumberInfo = new NumberInfo(client); 44 | this.Recording = new Recording(client); 45 | this.Application = new Application(client); 46 | this.AvailableNumber = new AvailableNumber(client); 47 | this.PhoneNumber = new PhoneNumber(client); 48 | this.v2 = { 49 | Message : new MessageV2(client) 50 | }; 51 | }; 52 | 53 | CatapultClient.UnexpectedResponseError = UnexpectedResponseError; 54 | CatapultClient.RateLimitError = RateLimitError; 55 | CatapultClient.BXMLResponse = BXMLResponse; 56 | 57 | // Allow modules transformed from ES6 import/export to reference 58 | // this constructor as the default export. 59 | CatapultClient.default = CatapultClient; 60 | 61 | Object.keys(queries).forEach(function (type) { 62 | CatapultClient[type] = queries[type]; 63 | }); 64 | 65 | module.exports = CatapultClient; 66 | -------------------------------------------------------------------------------- /lib/media.js: -------------------------------------------------------------------------------- 1 | var Promise = require("bluebird"); 2 | var stream = require("stream"); 3 | var fs = require("fs"); 4 | var request = require("request"); 5 | 6 | function getReadStreamData(data) { 7 | return new Promise(function (resolve, reject) { 8 | var s; 9 | if (data instanceof Buffer) { 10 | s = new stream.Readable(); 11 | s.push(data); 12 | s.push(null); 13 | return resolve({ stream : s, size : data.length }); 14 | } 15 | if (typeof data === "string") { 16 | return fs.stat(data, function (err, stat) { 17 | if (err) { 18 | return reject(err); 19 | } 20 | resolve({ stream : fs.createReadStream(data), size : stat.size }); 21 | }); 22 | } 23 | if (data instanceof stream.Readable) { 24 | // we have to detect stream size first 25 | var size = 0; 26 | s = new stream.Readable(); // new stream in memory to store data from original stream 27 | data.on("data", function (buffer) { 28 | s.push(buffer); 29 | size += buffer.length; 30 | }); 31 | data.on("end", function () { 32 | s.push(null); 33 | resolve({ stream : s, size : size }); 34 | }); 35 | data.resume(); 36 | return; 37 | } 38 | reject(new Error("data should be string, Buffer or readable stream")); 39 | }); 40 | } 41 | 42 | /** 43 | * Media 44 | * @constructor 45 | */ 46 | var Media = function (client) { 47 | /** 48 | * Upload a media file 49 | * @param {String} name The name of uploaded file. 50 | * @param {String|Buffer|Readable} data Data to upload. If data is string it should be path to file to upload. 51 | * @param {String} contentType Optional MIME type of uploaded data (default: application/octet-stream). 52 | * @param {Function} [callback] Callback for the operation 53 | * @return {Promise} A promise for the operation 54 | */ 55 | this.upload = function (name, data, contentType, callback) { 56 | if (!callback && typeof contentType === "function") { 57 | callback = contentType; 58 | contentType = null; 59 | } 60 | return getReadStreamData(data) 61 | .then(function (streamData) { 62 | return new Promise(function (resolve, reject) { 63 | var req = request( 64 | client.createRequestOptions({ 65 | path : encodeURI("media/" + name), 66 | method : "PUT" 67 | }) 68 | ); 69 | req.headers["Content-Type"] = 70 | contentType || "application/octet-stream"; 71 | req.headers["Content-Length"] = streamData.size; 72 | req.on("error", reject); 73 | req.on("response", resolve); 74 | streamData.stream.pipe(req); 75 | }); 76 | }) 77 | .then(client.handleResponse) 78 | .asCallback(callback); 79 | }; 80 | 81 | /** 82 | * Download a media file 83 | * @param {String} name The name of downloaded file. 84 | * @param {String/null/Function} [encoding='binary'] The encoding that will be passed onto makeRequest, 85 | if null content will be a Buffer. If function is passed, it will be the callback 86 | * @param {Function} [callback] Callback for the operation 87 | * @return {DownloadMediaFileResponse} A promise for the operation 88 | */ 89 | this.download = function (name, encoding, callback) { 90 | 91 | if(typeof encoding === "function") { 92 | callback = encoding; 93 | encoding = "binary"; 94 | } 95 | 96 | return client.makeRequest({ 97 | path : encodeURI("media/" + name), 98 | method : "GET", 99 | encoding : encoding 100 | }) 101 | .then(function (response) { 102 | return { 103 | contentType : response.headers["content-type"], 104 | content : response.body 105 | }; 106 | }) 107 | .asCallback(callback); 108 | }; 109 | 110 | /** 111 | * Gets a list of your media files. 112 | * @param {Function} [callback] Callback for the operation 113 | * @return {Array} A promise for the operation 114 | */ 115 | this.list = function (callback) { 116 | return client 117 | .makeRequest({ 118 | path : "media", 119 | method : "GET" 120 | }) 121 | .then(function (response) { 122 | return response.body; 123 | }) 124 | .asCallback(callback); 125 | }; 126 | 127 | /** 128 | * Remove a media file 129 | * @param {String} name The name of file to remove. 130 | * @param {Function} [callback] Callback for the operation 131 | * @return {Promise} A promise for the operation 132 | */ 133 | this.delete = function (name, callback) { 134 | return client 135 | .makeRequest({ 136 | path : encodeURI("media/" + name), 137 | method : "DELETE" 138 | }) 139 | .asCallback(callback); 140 | }; 141 | }; 142 | 143 | module.exports = Media; 144 | /** 145 | * @class DownloadMediaFileResponse 146 | * @type {Object} 147 | * @property {String} contentType MIME type of downloaded file. 148 | * @property {String|Buffer|Readable} content Content of file. 149 | */ 150 | 151 | /** 152 | * @class MediaFileResponse 153 | * @type {Object} 154 | * @property {String} mediaName name of media file. 155 | * @property {Number} contentLength Length of media file. 156 | */ 157 | -------------------------------------------------------------------------------- /lib/numberInfo.js: -------------------------------------------------------------------------------- 1 | /** 2 | * NumberInfo 3 | * @constructor 4 | */ 5 | var NumberInfo = function (client) { 6 | /** 7 | * Gets information about a number. 8 | * @param {String} number The ID of the numberInfo to get 9 | * @param {Function} [callback] A callback with the number information 10 | * @return {NumberInfoResponse} A promise for the number information 11 | * @example 12 | * // Promise 13 | * client.NumberInfo.get("+1234567890").then(function(info){}); 14 | * 15 | * // Callback 16 | * client.NumberInfo.get("+1234567890", function(err, info){}); 17 | */ 18 | this.get = function (number, callback) { 19 | return client.makeRequest({ 20 | pathWithoutUser : true, 21 | path : "phoneNumbers/numberInfo/" + encodeURIComponent(number), 22 | method : "GET" 23 | }) 24 | .then(function (response) { 25 | return response.body; 26 | }) 27 | .asCallback(callback); 28 | }; 29 | }; 30 | 31 | module.exports = NumberInfo; 32 | 33 | /** 34 | * @class NumberInfoResponse 35 | * @type {Object} 36 | * @property {String} name The Caller ID name information. 37 | * @property {String} number Phone number in E164 format. 38 | * @property {String} created The time this Caller ID information was first queried (UTC). 39 | * @property {String} updated The time this Caller ID information was last updated (UTC). 40 | */ 41 | -------------------------------------------------------------------------------- /lib/phoneNumber.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("./headerParsingLib").getNextLink; 2 | var Promise = require("bluebird"); 3 | 4 | /** 5 | * Phone numbers 6 | * @constructor 7 | */ 8 | var PhoneNumber = function (client) { 9 | /** 10 | * Allocates a number 11 | * @param {Object} params Parameters for allocating a number 12 | * @param {String} params.number A number to allocate. 13 | * @param {String} [params.name] A name you choose for this number. 14 | * @param {String} [params.applicationId] The unique id of an Application you want 15 | * to associate with this number. 16 | * @param {String} [params.fallbackNumber] Number to transfer an incoming call when 17 | * the callback/fallback events can't be delivered. 18 | * @param {Function} [callback] Callback with the newly created number 19 | * @return {PhoneNumberResponse} A promise for the newly created number 20 | * @example 21 | * 22 | * //Allocate number +1234567980 23 | * 24 | * // Promise 25 | * client.PhoneNumber.create({ number : "+1234567890" }).then(function(number){}); 26 | * 27 | * // Callback 28 | * client.PhoneNumber.create({ number : "+1234567890" }, function(err, number){}); 29 | */ 30 | this.create = function (params, callback) { 31 | return client.makeRequest({ 32 | path : "phoneNumbers", 33 | method : "POST", 34 | body : params 35 | }) 36 | .then(function (response) { 37 | var phoneNumber = params; 38 | var location = response.headers.location; 39 | phoneNumber.id = location.substring(location.lastIndexOf("/") + 1); 40 | return phoneNumber; 41 | }) 42 | .asCallback(callback); 43 | }; 44 | 45 | /** 46 | * Gets information about a phoneNumber. 47 | * @param {String} phoneNumberOrId The ID of the number or number in format E.164 48 | * (like +1234567980) to get 49 | * @param {Function} callback A callback with the call information 50 | * @return {PhoneNumberResponse} A promise for the call information 51 | * @example 52 | * // Promise 53 | * client.PhoneNumber.get(numberId).then(function(number){}); 54 | * // or 55 | * client.PhoneNumber.get("+1234567890").then(function(number){}); 56 | * 57 | * // Callback 58 | * client.PhoneNumber.get(numberId, function(err, number){}); 59 | * // or 60 | * client.PhoneNumber.get("+1234567890", function(err, number){}); 61 | * */ 62 | this.get = function (phoneNumberOrId, callback) { 63 | return client.makeRequest({ 64 | path : "phoneNumbers/" + encodeURIComponent(phoneNumberOrId), 65 | method : "GET" 66 | }) 67 | .then(function (response) { 68 | return response.body; 69 | }) 70 | .asCallback(callback); 71 | }; 72 | 73 | /** 74 | * Gets a list of allocated numbers. 75 | * @param {Object} params Query parameters for listing numbers 76 | * @param {Number} [params.size=25] Used for pagination to indicate the size of each page requested 77 | * for querying a list numbers. If no value is specified the default value is 25 (maximum value 1000). 78 | * @param {String} [params.applicationId] Used to filter the retrieved list of numbers by 79 | * an associated application ID 80 | * @param {String} [params.state] Used to filter the retrieved list of numbers by 81 | * a US state. 82 | * @param {String} [params.name] Used to filter the retrieved list of numbers by name 83 | * @param {String} [params.city] Used to filter the retrieved list of numbers by city name 84 | * @param {String} [params.numberState] Used to filter the retrieved list of numbers by number state 85 | * @param {Function} callback A callback with the list of numbers 86 | * @return {Array.} A promise for the list of phone numbers 87 | * @example 88 | * // Promise 89 | * client.PhoneNumber.list({size: 1000}).then(function(numbersResponse){}); 90 | * 91 | * // Callback 92 | * client.PhoneNumber.list({size: 1000}, function(err, numbersResponse){}); 93 | */ 94 | this.list = function (params, callback) { 95 | var self = this; 96 | return client.makeRequest({ 97 | path : "phoneNumbers", 98 | method : "GET", 99 | qs : params 100 | }) 101 | .then(function (response) { 102 | var phoneNumberListResponse = { 103 | phoneNumbers : response.body, 104 | hasNextPage : false, 105 | getNextPage : function (nextCallback) { 106 | return Promise.reject("Next page does not exist.") 107 | .asCallback(nextCallback); 108 | } 109 | }; 110 | var nextLink = getNextLink(response.headers); 111 | if (nextLink) { 112 | phoneNumberListResponse.hasNextPage = true; 113 | phoneNumberListResponse.getNextPage = function (nextCallback) { 114 | return self.list(nextLink, nextCallback); 115 | }; 116 | } 117 | return phoneNumberListResponse; 118 | }) 119 | .asCallback(callback); 120 | }; 121 | 122 | /** 123 | * Update the number 124 | * @param {String} phoneNumberId The ID of the number 125 | * @param {Object} params Changed parameters of the number 126 | * @param {String} params.applicationId The unique id of an Application 127 | * resource you want to associate with this number for incoming calls and messages. 128 | * @param {String} params.name A name you choose for this number. 129 | * @param {String} params.fallbackNumber Number to transfer an incoming call when the 130 | * callback/fallback events can't be delivered. 131 | * @param {Function} [callback] Callback for the operation 132 | * @return {Promise} A promise for the operation 133 | * @example 134 | * // Promise 135 | * client.PhoneNumber.update(numberId, {name: "Another Name"}).then(function(){}); 136 | * 137 | * // Callback 138 | * client.PhoneNumber.update(numberId, {name: "Another Name"}, function(err){}); 139 | */ 140 | this.update = function (phoneNumberId, params, callback) { 141 | return client.makeRequest({ 142 | path : "phoneNumbers/" + phoneNumberId, 143 | method : "POST", 144 | body : params 145 | }) 146 | .then(function () { 147 | return; 148 | }) 149 | .asCallback(callback); 150 | }; 151 | 152 | /** 153 | * Remove the number 154 | * @param {String} phoneNumberId The ID of the number 155 | * @param {Function} [callback] Callback for the operation 156 | * @return {Promise} A promise for the operation 157 | * @example 158 | * // Promise 159 | * client.PhoneNumber.delete(numberId).then(function(){}); 160 | * 161 | * // Callback 162 | * client.PhoneNumber.delete(numberId, function(err){}); 163 | */ 164 | this.delete = function (phoneNumberId, callback) { 165 | return client.makeRequest({ 166 | path : "phoneNumbers/" + phoneNumberId, 167 | method : "DELETE" 168 | }) 169 | .then(function () { 170 | return; 171 | }) 172 | .asCallback(callback); 173 | }; 174 | }; 175 | 176 | module.exports = PhoneNumber; 177 | 178 | /** 179 | * @class PhoneNumberResponse 180 | * @type {Object} 181 | * @property {String} id The unique ID of the number. 182 | * @property {String} state Number state 183 | * @property {String} name Number name 184 | * @property {String} number Number in E.164 format. 185 | * @property {String} nationalNumber Number in natinal friendly format (like (555) 5555-5555). 186 | * @property {String} city Number city. 187 | * @property {String} state Number state. 188 | * @property {String} applicationId The unique id of an linked Application. 189 | * @property {String} fallbackNumber Number to transfer an incoming call 190 | * when the callback/fallback events can't be delivered. 191 | * @property {String} price The monthly price for this number. 192 | * @property {String} numberState The phone number state, values are `enabled` or `released` 193 | * @property {String} createdTime Date when the number was created. 194 | */ 195 | -------------------------------------------------------------------------------- /lib/recording.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Retrieve information about call recordings 3 | * @constructor 4 | */ 5 | var Recording = function (client) { 6 | 7 | /** 8 | * Get a recording 9 | * @param {String} recordingId The ID of the recording to retrieve 10 | * @param {Function} [callback] Callback with the recording object 11 | * @return {RecordingResponse} A promise for the recording object 12 | */ 13 | this.get = function (recordingId, callback) { 14 | return client.makeRequest({ 15 | path : "recordings/" + recordingId, 16 | method : "GET" 17 | }) 18 | .then(function (response) { 19 | return response.body; 20 | }) 21 | .asCallback(callback); 22 | }; 23 | 24 | /** 25 | * Get a list of recordings 26 | * @param {Object} params [description] 27 | * @param {Function} [callback] Callback with the recording objects 28 | * @return {RecordingResponse} A promise for the recording objects 29 | */ 30 | this.list = function (params, callback) { 31 | return client.makeRequest({ 32 | path : "recordings", 33 | method : "GET", 34 | qs : params 35 | }) 36 | .then(function (response) { 37 | return response.body; 38 | }) 39 | .asCallback(callback); 40 | }; 41 | 42 | /** 43 | * Create a transcription 44 | * @param {String} recordingId The ID of the recording 45 | * @param {Function} [callback] Callback with the create transcription 46 | * @return {TranscriptionResponse} A promise for the created transcription 47 | * @example 48 | * 49 | * // Promise 50 | * client.Recording.createTranscription(recordingId).then(function(transcription){}); 51 | * 52 | * // Callback 53 | * client.Recording.createTranscription(recordingId, function(err, transcription){}); 54 | */ 55 | this.createTranscription = function (recordingId, callback) { 56 | return client.makeRequest({ 57 | path : "recordings/" + recordingId + "/transcriptions", 58 | method : "POST", 59 | body : {} 60 | }) 61 | .then(function (response) { 62 | var location = response.headers.location; 63 | return { id : location.substring(location.lastIndexOf("/") + 1) }; 64 | }) 65 | .asCallback(callback); 66 | }; 67 | 68 | /** 69 | * Get information about the transcription 70 | * @param {String} recordingId The ID of the recording 71 | * @param {String} transcriptionId The ID of the transcription 72 | * @param {Function} [callback] Callback with the transcription 73 | * @return {TranscriptionResponse} A promise for the transcription 74 | * @example 75 | * 76 | * // Promise 77 | * client.Recording.getTranscription(recordingId, transcriptionId).then(function(transcription){}); 78 | * 79 | * // Callback 80 | * client.Recording.getTranscription(recordingId, transcriptionId, function(err, transcription){}); 81 | */ 82 | this.getTranscription = function (recordingId, transcriptionId, callback) { 83 | return client.makeRequest({ 84 | path : "recordings/" + recordingId + "/transcriptions/" + transcriptionId, 85 | method : "GET" 86 | }) 87 | .then(function (response) { 88 | return response.body; 89 | }) 90 | .asCallback(callback); 91 | }; 92 | 93 | /** 94 | * Get list of all transcriptions for recording 95 | * @param {String} recordingId The ID of the recording 96 | * @param {Function} [callback] Callback with the transcriptions 97 | * @return {TranscriptionResponse} A promise for the transcriptions 98 | * @example 99 | * 100 | * // Promise 101 | * client.Recording.getTranscriptions(recordingId).then(function(transcriptions){}); 102 | * 103 | * // Callback 104 | * client.Recording.getTranscriptions(recordingId, function(err, transcriptions){}); 105 | */ 106 | this.getTranscriptions = function (recordingId, callback) { 107 | return client.makeRequest({ 108 | path : "recordings/" + recordingId + "/transcriptions", 109 | method : "GET" 110 | }) 111 | .then(function (response) { 112 | return response.body; 113 | }) 114 | .asCallback(callback); 115 | }; 116 | }; 117 | 118 | module.exports = Recording; 119 | /** 120 | * @class RecordingResponse 121 | * @type {Object} 122 | * @property {String} id The unique ID of the recording. 123 | * @property {String} startTime Date/time when the recording started. 124 | * @property {String} endTime Date/time when the recording ended. 125 | * @property {String} media The complete URL to the media resource this 126 | * recording is associated with. 127 | * @property {String} call The complete URL to the call resource 128 | * this recording is associated with. 129 | * @property {String} state The state of the recording, 130 | */ 131 | /** 132 | * @class TranscriptionResponse 133 | * @type {Object} 134 | * @property {String} id The unique ID of the transcription. 135 | * @property {String} text The transcribed text (only first 1000 characters). 136 | * @property {Number} chargeableDuration The seconds between activeTime and endTime 137 | * for the recording; this is the time that is going to be used to charge the resource. 138 | * @property {Number} textSize The size of the transcribed text. 139 | * @property {String} state The state of the transcription, 140 | * @property {String} textUrl A url to the full text, 141 | */ 142 | -------------------------------------------------------------------------------- /lib/unexpectedResponseError.js: -------------------------------------------------------------------------------- 1 | var util = require("util"); 2 | 3 | var UnexpectedResponseError = function (message, statusCode) { 4 | Error.captureStackTrace(this, this.constructor); 5 | this.name = this.constructor.name; 6 | this.message = message; 7 | this.statusCode = statusCode; 8 | }; 9 | 10 | util.inherits(UnexpectedResponseError, Error); 11 | 12 | module.exports = UnexpectedResponseError; 13 | -------------------------------------------------------------------------------- /lib/v2/searchAndOrderNumberQueries.js: -------------------------------------------------------------------------------- 1 | /** AreaCodeSearchAndOrderNumbersQuery */ 2 | function AreaCodeSearchAndOrderNumbersQuery(query) { 3 | this.toXml = function () { 4 | return { 5 | "AreaCodeSearchAndOrderType": { 6 | "AreaCode": {_text: query.areaCode}, 7 | "Quantity": {_text: query.quantity || 1} 8 | } 9 | }; 10 | }; 11 | } 12 | 13 | /** RateCenterSearchAndOrdeNumbersQuery */ 14 | function RateCenterSearchAndOrdeNumbersQuery(query) { 15 | this.toXml = function () { 16 | return { 17 | "RateCenterSearchAndOrderType": { 18 | "RateCenter": {_text: query.rateCenter}, 19 | "State": {_text: query.state}, 20 | "Quantity": {_text: query.quantity || 1} 21 | } 22 | }; 23 | }; 24 | } 25 | 26 | /** NpaNxxSearchAndOrderNumbersQuery */ 27 | function NpaNxxSearchAndOrderNumbersQuery(query) { 28 | this.toXml = function () { 29 | return { 30 | "NPANXXSearchAndOrderType": { 31 | "NpaNxx": {_text: query.npaNxx}, 32 | "EnableTNDetail": {_text: query.enableTnDetail || query.enableTNDetail}, 33 | "EnableLCA": {_text: query.enableLca || query.enableLCA}, 34 | "Quantity": {_text: query.quantity || 1} 35 | } 36 | }; 37 | }; 38 | } 39 | 40 | /** TollFreeVanitySearchAndOrderNumbersQuery */ 41 | function TollFreeVanitySearchAndOrderNumbersQuery(query) { 42 | this.toXml = function () { 43 | return { 44 | "TollFreeVanitySearchAndOrderType": { 45 | "TollFreeVanity": {_text: query.tollFreeVanity}, 46 | "Quantity": {_text: query.quantity || 1} 47 | } 48 | }; 49 | }; 50 | } 51 | 52 | /** TollFreeWildCharSearchAndOrderNumbersQuery */ 53 | function TollFreeWildCharSearchAndOrderNumbersQuery(query) { 54 | this.toXml = function () { 55 | return { 56 | "TollFreeWildCharSearchAndOrderType": { 57 | "TollFreeWildCardPattern": {_text: query.tollFreeWildCardPattern}, 58 | "Quantity": {_text: query.quantity || 1} 59 | } 60 | }; 61 | }; 62 | } 63 | 64 | /** StateSearchAndOrderNumbersQuery */ 65 | function StateSearchAndOrderNumbersQuery(query) { 66 | this.toXml = function () { 67 | return { 68 | "StateSearchAndOrderType": { 69 | "State": {_text: query.state}, 70 | "Quantity": {_text: query.quantity || 1} 71 | } 72 | }; 73 | }; 74 | } 75 | 76 | /** CitySearchAndOrderNumbersQuery */ 77 | function CitySearchAndOrderNumbersQuery(query) { 78 | this.toXml = function () { 79 | return { 80 | "CitySearchAndOrderType": { 81 | "State": {_text: query.state}, 82 | "City": {_text: query.city}, 83 | "Quantity": {_text: query.quantity || 1} 84 | } 85 | }; 86 | }; 87 | } 88 | 89 | /** ZipSearchAndOrderNumbersQuery */ 90 | function ZipSearchAndOrderNumbersQuery(query) { 91 | this.toXml = function () { 92 | return { 93 | "ZIPSearchAndOrderType": { 94 | "Zip": {_text: query.zip}, 95 | "Quantity": {_text: query.quantity || 1} 96 | } 97 | }; 98 | }; 99 | } 100 | 101 | /** LataSearchAndOrderNumbersQuery */ 102 | function LataSearchAndOrderNumbersQuery(query) { 103 | this.toXml = function () { 104 | return { 105 | "LATASearchAndOrderType": { 106 | "Lata": {_text: query.lata}, 107 | "Quantity": {_text: query.quantity || 1} 108 | } 109 | }; 110 | }; 111 | } 112 | 113 | /** CombinedSearchAndOrderNumbersQuery */ 114 | function CombinedSearchAndOrderNumbersQuery(query) { 115 | this.toXml = function () { 116 | return { 117 | "CombinedSearchAndOrderType": { 118 | "Quantity": {_text: query.quantity || 1}, 119 | "AreaCode": {_text: query.areaCode}, 120 | "RateCenter": {_text: query.rateCenter}, 121 | "NpaNxx": {_text: query.npaNxx}, 122 | "EnableTNDetail": {_text: query.enableTnDetail || query.enableTNDetail}, 123 | "EnableLCA": {_text: query.enableLca || query.enableLCA}, 124 | "TollFreeVanity": {_text: query.tollFreeVanity}, 125 | "TollFreeWildCardPattern": {_text: query.tollFreeWildCardPattern}, 126 | "State": {_text: query.state}, 127 | "City": {_text: query.city}, 128 | "Zip": {_text: query.zip}, 129 | "Lata": {_text: query.lata} 130 | } 131 | }; 132 | }; 133 | } 134 | 135 | module.exports = { 136 | AreaCodeSearchAndOrderNumbersQuery, 137 | RateCenterSearchAndOrdeNumbersQuery, 138 | NpaNxxSearchAndOrderNumbersQuery, 139 | TollFreeVanitySearchAndOrderNumbersQuery, 140 | TollFreeWildCharSearchAndOrderNumbersQuery, 141 | StateSearchAndOrderNumbersQuery, 142 | CitySearchAndOrderNumbersQuery, 143 | ZipSearchAndOrderNumbersQuery, 144 | LataSearchAndOrderNumbersQuery, 145 | CombinedSearchAndOrderNumbersQuery 146 | }; 147 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-bandwidth", 3 | "version": "4.0.0", 4 | "description": "NodeJS Client library for Bandwidth API", 5 | "main": "index.js", 6 | "types": "types/index.d.ts", 7 | "scripts": { 8 | "test": "cross-env NODE_ENV=test gulp", 9 | "docs": "./node_modules/.bin/jsdoc --configure conf.json" 10 | }, 11 | "repository": { 12 | "type": "git", 13 | "url": "https://github.com/bandwidth/node-bandwidth.git" 14 | }, 15 | "keywords": [ 16 | "bandwidth", 17 | "catapult", 18 | "cpaas", 19 | "voice", 20 | "messaging" 21 | ], 22 | "author": "bandwidth", 23 | "license": "MIT", 24 | "bugs": { 25 | "url": "https://github.com/bandwidth/node-bandwidth/issues" 26 | }, 27 | "homepage": "https://github.com/bandwidth/node-bandwidth", 28 | "dependencies": { 29 | "bluebird": "^3.5.1", 30 | "gulp": "^4.0.0", 31 | "lodash": "^4.17.4", 32 | "parse-link-header": "^1.0.1", 33 | "qs": "^6.5.1", 34 | "request": "^2.83.0", 35 | "xml-js": "^1.5.1", 36 | "xmlbuilder": "^9.0.4" 37 | }, 38 | "devDependencies": { 39 | "cross-env": "2.0.0", 40 | "gulp-clean": "^0.3.1", 41 | "gulp-concat": "^2.6.0", 42 | "gulp-istanbul": "^1.1.3", 43 | "gulp-jshint": "^2.1.0", 44 | "gulp-mocha": "^6.0.0", 45 | "gulp-rename": "^1.2.2", 46 | "jsdoc": "^3.4.0", 47 | "jshint": "^2.10.2", 48 | "jshint-stylish": "^2.1.0", 49 | "minami": "^1.1.1", 50 | "nock": "^10.0.6", 51 | "should": "^11.2.1", 52 | "sinon": "1.17.4" 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /test/.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "expr": true, 4 | "globals": { 5 | "describe": false, 6 | "it": false, 7 | "before": false, 8 | "beforeEach": false, 9 | "after": false, 10 | "afterEach": false 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/account-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Account API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var testAccount = { 16 | "balance" : "100", 17 | "type" : "pre-paid" 18 | }; 19 | 20 | var transactionList = [ 21 | { 22 | "id" : "{transactionId1}", 23 | "time" : "2013-02-21T13:39:09.122Z", 24 | "amount" : "0.00750", 25 | "type" : "charge", 26 | "units" : "1", 27 | "productType" : "sms-out", 28 | "number" : "{number}" 29 | }, 30 | { 31 | "id" : "{transactionId2}", 32 | "time" : "2013-02-21T13:37:42.079Z", 33 | "amount" : "0.00750", 34 | "type" : "charge", 35 | "units" : "1", 36 | "productType" : "sms-out", 37 | "number" : "{number}" 38 | } 39 | ]; 40 | 41 | before(function () { 42 | client = new CatapultClient({ 43 | userId : userId, 44 | apiToken : apiToken, 45 | apiSecret : apiSecret 46 | }); 47 | nock.disableNetConnect(); 48 | 49 | nock("https://api.catapult.inetwork.com") 50 | .persist() 51 | .get("/v1/users/" + userId + "/account") 52 | .reply(200, testAccount) 53 | .get("/v1/users/" + userId + "/account/transactions") 54 | .reply(200, transactionList); 55 | }); 56 | 57 | after(function () { 58 | nock.cleanAll(); 59 | nock.enableNetConnect(); 60 | }); 61 | 62 | it("should get a account info, promise style", function () { 63 | return client.Account.get() 64 | .then(function (account) { 65 | account.should.eql(testAccount); 66 | }); 67 | }); 68 | 69 | it("should get a list of transactions, promise style", function () { 70 | return client.Account.getTransactions({ }) 71 | .then(function (response) { 72 | response.transactions.should.eql(transactionList); 73 | }); 74 | }); 75 | 76 | it("those transactions should not have more pages", function () { 77 | return client.Account.getTransactions({}) 78 | .then(function (response) { 79 | response.hasNextPage.should.be.false; 80 | return response.getNextPage() 81 | .catch(function (err) { 82 | err.should.equal("Next page does not exist."); 83 | }); 84 | }); 85 | }); 86 | 87 | describe("pagination tests", function () { 88 | 89 | before(function () { 90 | nock("https://api.catapult.inetwork.com") 91 | .persist() 92 | .get("/v1/users/" + userId + "/account/transactions?size=25") 93 | .reply(200, transactionList, 94 | { 95 | "link" : "; rel=\"first\"," + 97 | "; rel=\"next\"" 98 | }); 99 | }); 100 | 101 | after(function () { 102 | nock.cleanAll(); 103 | nock.enableNetConnect(); 104 | }); 105 | 106 | it("should return a list of accounts with a page to the next link", function () { 107 | return client.Account.getTransactions({ size : 25 }) 108 | .then(function (response) { 109 | response.transactions.should.eql(transactionList); 110 | return response.getNextPage(); 111 | }) 112 | .then(function (moreTransactions) { 113 | moreTransactions.transactions.should.eql(transactionList); 114 | }); 115 | }); 116 | }); 117 | }); 118 | }); 119 | -------------------------------------------------------------------------------- /test/application-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Application API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | var requestSpy; 11 | var updateNock; 12 | var deleteNock; 13 | 14 | var userId = "fakeUserId"; 15 | var apiToken = "fakeApiToken"; 16 | var apiSecret = "fakeapiSecret"; 17 | 18 | var page = 1; 19 | var size = 1; 20 | 21 | var applicationsList = [ 22 | { 23 | "id" : "fakeApplicationId", 24 | "name" : "fakeApp", 25 | "incomingCallUrl" : "http://example.com/calls.php", 26 | "incomingMessageUrl" : "http://example.com/messages.php", 27 | "autoAnswer" : true 28 | }, 29 | { 30 | "id" : "fakeApplicationId2", 31 | "name" : "fakeApp2", 32 | "incomingCallUrl" : "http://example.com/calls2.php", 33 | "incomingMessageUrl" : "http://example.com/messages2.php", 34 | "autoAnswer" : true 35 | }, 36 | ]; 37 | 38 | var newApplication = { 39 | "name" : "NewApplication", 40 | "incomingCallUrl" : "http://example.com/calls3.php", 41 | "incomingMessageUrl" : "http://example.com/messages3.php", 42 | "autoAnswer" : true 43 | }; 44 | 45 | var testApplication = { 46 | "id" : "fakeTestApplicationId", 47 | "name" : "NewApplication", 48 | "incomingCallUrl" : "http://example.com/calls3.php", 49 | "incomingMessageUrl" : "http://example.com/messages3.php", 50 | "autoAnswer" : true 51 | }; 52 | 53 | before(function () { 54 | client = new CatapultClient({ 55 | userId : userId, 56 | apiToken : apiToken, 57 | apiSecret : apiSecret 58 | }); 59 | nock.disableNetConnect(); 60 | 61 | nock("https://api.catapult.inetwork.com") 62 | .persist() 63 | .get("/v1/users/" + userId + "/applications") 64 | .reply(200, applicationsList, 65 | { 66 | "link" : "; rel='first'" 67 | }) 68 | .post("/v1/users/" + userId + "/applications") 69 | .reply(201, 70 | {}, 71 | { 72 | "location" : "/v1/users/" + userId + "/messages/fakeApplicationId3" 73 | }) 74 | .get("/v1/users/" + userId + "/applications/" + testApplication.id) 75 | .reply(200, testApplication) 76 | .get("/v1/users/" + userId + "/applications?page=" + page + "&size=" + size) 77 | .reply(200, applicationsList); 78 | }); 79 | 80 | after(function () { 81 | nock.cleanAll(); 82 | nock.enableNetConnect(); 83 | }); 84 | 85 | it("should get a list of applications, promise style", function () { 86 | return client.Application.list({}) 87 | .then(function (applicationsResponse) { 88 | applicationsResponse.applications.should.eql(applicationsList); 89 | }); 90 | }); 91 | 92 | it("should get a list of applications, callback style", function () { 93 | client.Application.list({}, function (err, applicationsResponse) { 94 | if (err) { 95 | throw err; 96 | } 97 | applicationsResponse.applications.should.eql(applicationsList); 98 | }); 99 | }); 100 | 101 | it("those applications should not have more pages", function () { 102 | return client.Application.list({}) 103 | .then(function (applicationsResponse) { 104 | applicationsResponse.hasNextPage.should.be.false; 105 | return applicationsResponse.getNextPage() 106 | .catch(function (err) { 107 | err.should.equal("Next page does not exist."); 108 | }); 109 | }); 110 | }); 111 | 112 | it("should create an application, promise style", function () { 113 | return client.Application.create(newApplication) 114 | .then(function (applicationResponse) { 115 | applicationResponse.id.should.equal("fakeApplicationId3"); 116 | applicationResponse.name.should.equal(newApplication.name); 117 | applicationResponse.incomingCallUrl.should.equal(newApplication.incomingCallUrl); 118 | applicationResponse.incomingMessageUrl.should.equal(newApplication.incomingMessageUrl); 119 | applicationResponse.autoAnswer.should.equal(newApplication.autoAnswer); 120 | }); 121 | }); 122 | 123 | it("should create an application, callback style", function () { 124 | client.Application.create(newApplication, function (err, applicationResponse) { 125 | if (err) { 126 | throw err; 127 | } 128 | applicationResponse.id.should.equal("fakeApplicationId3"); 129 | applicationResponse.name.should.equal(newApplication.name); 130 | applicationResponse.incomingCallUrl.should.equal(newApplication.incomingCallUrl); 131 | applicationResponse.incomingMessageUrl.should.equal(newApplication.incomingMessageUrl); 132 | applicationResponse.autoAnswer.should.equal(newApplication.autoAnswer); 133 | }); 134 | }); 135 | 136 | it("should get an application, promise style", function () { 137 | return client.Application.get(testApplication.id) 138 | .then(function (applicationResponse) { 139 | applicationResponse.should.eql(testApplication); 140 | }); 141 | }); 142 | 143 | it("should get an application, callback style", function () { 144 | client.Application.get(testApplication.id, function (err, applicationResponse) { 145 | if (err) { 146 | throw err; 147 | } 148 | applicationResponse.should.eql(testApplication); 149 | }); 150 | }); 151 | 152 | describe("testing global void methods", function () { 153 | 154 | describe("updating applications", function () { 155 | 156 | beforeEach(function () { 157 | updateNock = nock("https://api.catapult.inetwork.com") 158 | .persist() 159 | .post("/v1/users/" + userId + "/applications/" + testApplication.id) 160 | .reply(200, {}); 161 | }); 162 | 163 | afterEach(function () { 164 | nock.cleanAll(); 165 | }); 166 | 167 | it("should update an application, promise style", function () { 168 | return client.Application.update(testApplication.id, { name : "newTestApplication" }) 169 | .then(function () { 170 | updateNock.isDone().should.equal(true); 171 | }); 172 | }); 173 | 174 | it("should update an application, callback style", function () { 175 | client.Application.update(testApplication.id, { name : "anotherNewTestApplication" }, function (err, response) { 176 | if (err) { 177 | throw err; 178 | } 179 | updateNock.isDone().should.equal(true); 180 | }); 181 | }); 182 | }); 183 | 184 | describe("deleting applications", function () { 185 | 186 | beforeEach(function () { 187 | deleteNock = nock("https://api.catapult.inetwork.com") 188 | .persist() 189 | .delete("/v1/users/" + userId + "/applications/" + testApplication.id) 190 | .reply(200, {}); 191 | }); 192 | 193 | afterEach(function () { 194 | nock.cleanAll(); 195 | }); 196 | 197 | it("should delete an application, promise style", function () { 198 | return client.Application.delete(testApplication.id) 199 | .then(function () { 200 | deleteNock.isDone().should.equal(true); 201 | }); 202 | }); 203 | 204 | it("should delete an application, callback style", function () { 205 | client.Application.delete(testApplication.id, function (err, response) { 206 | if (err) { 207 | throw err; 208 | } 209 | deleteNock.isDone().should.equal(true); 210 | }); 211 | }); 212 | }); 213 | }); 214 | 215 | describe("pagination tests", function () { 216 | 217 | before(function () { 218 | nock("https://api.catapult.inetwork.com") 219 | .persist() 220 | .get("/v1/users/" + userId + "/applications") 221 | .reply(200, applicationsList, 222 | { 223 | "link" : "; rel=\"first\"," + 225 | "; rel=\"next\"" 226 | }); 227 | }); 228 | 229 | after(function () { 230 | nock.cleanAll(); 231 | nock.enableNetConnect(); 232 | }); 233 | 234 | it("should return a list of applications with a page to the next link", function () { 235 | return client.Application.list({}) 236 | .then(function (applicationsResponse) { 237 | applicationsResponse.applications.should.eql(applicationsList); 238 | return applicationsResponse.getNextPage(); 239 | }) 240 | .then(function (moreApplications) { 241 | moreApplications.applications.should.eql(applicationsList); 242 | }); 243 | }); 244 | }); 245 | }); 246 | }); -------------------------------------------------------------------------------- /test/availableNumber-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("AvailableNumber API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var query = { areaCode : "910" }; 16 | 17 | var foundNumberList = [ { 18 | "number" : "{number1}", 19 | "nationalNumber" : "{national_number1}", 20 | "patternMatch" : " 2 9 ", 21 | "city" : "CARY", 22 | "lata" : "426", 23 | "rateCenter" : "CARY", 24 | "state" : "NC", 25 | "price" : "0.60" 26 | } ]; 27 | 28 | var orderedNumberList = [ { 29 | "number" : "{number1}", 30 | "nationalNumber" : "{national_number1}", 31 | "price" : "0.60", 32 | "location" : "https://.../v1/users/.../phoneNumbers/numberId1" 33 | } ]; 34 | 35 | var orderedNumber = { 36 | "id" : "numberId1", 37 | "number" : "{number1}", 38 | "nationalNumber" : "{national_number1}", 39 | "price" : "0.60", 40 | "location" : "https://.../v1/users/.../phoneNumbers/numberId1" 41 | }; 42 | 43 | before(function () { 44 | client = new CatapultClient({ 45 | userId : userId, 46 | apiToken : apiToken, 47 | apiSecret : apiSecret 48 | }); 49 | nock.disableNetConnect(); 50 | 51 | nock("https://api.catapult.inetwork.com") 52 | .persist() 53 | .get("/v1/availableNumbers/local?areaCode=910") 54 | .reply(200, foundNumberList) 55 | .post("/v1/availableNumbers/local?areaCode=910") 56 | .reply(200, orderedNumberList); 57 | }); 58 | 59 | after(function () { 60 | nock.cleanAll(); 61 | nock.enableNetConnect(); 62 | }); 63 | 64 | it("should search available numbers", function () { 65 | return client.AvailableNumber.search("local", { areaCode : "910" }) 66 | .then(function (numbers) { 67 | numbers[0].should.eql(foundNumberList[0]); 68 | }); 69 | }); 70 | 71 | it("should search available numbers and order them", function () { 72 | return client.AvailableNumber.searchAndOrder("local", { areaCode : "910" }) 73 | .then(function (numbers) { 74 | numbers[0].should.eql(orderedNumber); 75 | }); 76 | }); 77 | }); 78 | }); 79 | -------------------------------------------------------------------------------- /test/bridge-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Bridge API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var newTestBridge = { 16 | bridgeAudio : true, 17 | callIds : [ "callId" ] 18 | }; 19 | 20 | var changes = { 21 | bridgeAudio : true, 22 | callIds : [ "callId1" ] 23 | }; 24 | 25 | var testBridge = { 26 | "id" : "bridgeId", 27 | "state" : "completed", 28 | "bridgeAudio" : "true", 29 | "calls" :"https://.../v1/users/{userId}/bridges/{bridgeId}/calls", 30 | "createdTime" : "2013-04-22T13:55:30.279Z", 31 | "activatedTime" : "2013-04-22T13:55:30.280Z", 32 | "completedTime" : "2013-04-22T13:59:30.122Z" 33 | }; 34 | 35 | var bridgesList = [ testBridge ]; 36 | 37 | var callsList = [ 38 | { 39 | "id" : "fakeCallId1", 40 | "direction" : "out", 41 | "from" : "{fromNumber}", 42 | "to" : "{toNumber1}", 43 | "recordingEnabled" : false, 44 | "callbackUrl" : "", 45 | "state" : "completed", 46 | "startTime" : "2013-02-08T13:15:47.587Z", 47 | "activeTime" : "2013-02-08T13:15:52.347Z", 48 | "endTime" : "2013-02-08T13:15:55.887Z", 49 | "chargeableDuration" : 60, 50 | "events" : "https://.../calls/fakeCallId1/events" 51 | }, 52 | { 53 | "id" : "fakeCallId2", 54 | "direction" : "out", 55 | "from" : "{fromNumber}", 56 | "to" : "{toNumber2}", 57 | "recordingEnabled" : false, 58 | "callbackUrl" : "", 59 | "state" : "active", 60 | "startTime" : "2013-02-08T13:15:47.587Z", 61 | "activeTime" : "2013-02-08T13:15:52.347Z", 62 | "events" : "https://.../calls/fakeCallId2/events" 63 | } 64 | ]; 65 | 66 | var tag = "tag"; 67 | var sampleSentence = "Hello world"; 68 | var speakSentencePayload = { 69 | sentence : sampleSentence 70 | }; 71 | 72 | var speakSentencePayloadWithTag = { 73 | sentence : sampleSentence, 74 | tag : tag 75 | }; 76 | 77 | var audioUrl = "http://somewhere/something.mp3"; 78 | var playAudioPayload = { 79 | fileUrl : audioUrl 80 | }; 81 | 82 | var playAudioPayloadWithTag = { 83 | fileUrl : audioUrl, 84 | tag : tag 85 | }; 86 | 87 | var stopFilePlaybackPayload = { 88 | fileUrl : "" 89 | }; 90 | 91 | var stopSpeakingPayload = { 92 | sentence : "" 93 | }; 94 | 95 | before(function () { 96 | client = new CatapultClient({ 97 | userId : userId, 98 | apiToken : apiToken, 99 | apiSecret : apiSecret 100 | }); 101 | nock.disableNetConnect(); 102 | 103 | nock("https://api.catapult.inetwork.com") 104 | .persist() 105 | .post("/v1/users/" + userId + "/bridges", newTestBridge) 106 | .reply(201, 107 | {}, 108 | { 109 | "Location" : "/v1/users/" + userId + "/bridges/fakeBridgeId" 110 | }) 111 | .get("/v1/users/" + userId + "/bridges/" + testBridge.id) 112 | .reply(200, testBridge) 113 | .get("/v1/users/" + userId + "/bridges") 114 | .reply(200, bridgesList) 115 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", speakSentencePayload) 116 | .reply(200) 117 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", stopSpeakingPayload) 118 | .reply(200) 119 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", playAudioPayload) 120 | .reply(200) 121 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", speakSentencePayloadWithTag) 122 | .reply(200) 123 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", playAudioPayloadWithTag) 124 | .reply(200) 125 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id + "/audio", stopFilePlaybackPayload) 126 | .reply(200) 127 | .post("/v1/users/" + userId + "/bridges/" + testBridge.id, changes) 128 | .reply(200) 129 | .get("/v1/users/" + userId + "/bridges/" + testBridge.id + "/calls") 130 | .reply(200, callsList); 131 | }); 132 | 133 | after(function () { 134 | nock.cleanAll(); 135 | nock.enableNetConnect(); 136 | }); 137 | 138 | it("should create a bridge, promise style", function () { 139 | return client.Bridge.create(newTestBridge) 140 | .then(function (bridge) { 141 | bridge.should.eql(newTestBridge); 142 | }); 143 | }); 144 | 145 | it("should create a bridge, callback style", function (done) { 146 | client.Bridge.create(newTestBridge, function (err, call) { 147 | if (err) { 148 | throw err; 149 | } 150 | call.should.eql(newTestBridge); 151 | done(); 152 | }); 153 | }); 154 | 155 | it("should get a bridge, promise style", function () { 156 | return client.Bridge.get(testBridge.id) 157 | .then(function (bridge) { 158 | bridge.should.eql(testBridge); 159 | }); 160 | }); 161 | 162 | it("should get a list of bridges, promise style", function () { 163 | return client.Bridge.list({ }) 164 | .then(function (bridgesResponse) { 165 | bridgesResponse.bridges[0].should.eql(bridgesList[0]); 166 | }); 167 | }); 168 | 169 | it("should get a list of bridges, callback style", function (done) { 170 | client.Bridge.list({ }, function (err, bridgesResponse) { 171 | if (err) { 172 | throw err; 173 | } 174 | bridgesResponse.bridges[0].should.eql(bridgesList[0]); 175 | done(); 176 | }); 177 | }); 178 | 179 | it("those bridges should not have more pages", function () { 180 | return client.Bridge.list({}) 181 | .then(function (bridgesResponse) { 182 | bridgesResponse.hasNextPage.should.be.false; 183 | return bridgesResponse.getNextPage() 184 | .catch(function (err) { 185 | err.should.equal("Next page does not exist."); 186 | }); 187 | }); 188 | }); 189 | 190 | it("should speak a sentence to the bridge, promise style", function () { 191 | return client.Bridge.speakSentence(testBridge.id, sampleSentence); 192 | }); 193 | 194 | it("should speak a sentence to the bridge, callback style", function (done) { 195 | client.Bridge.speakSentence(testBridge.id, sampleSentence, done); 196 | }); 197 | 198 | it("should stop a sentence from speaking, promise style", function () { 199 | return client.Bridge.stopSpeaking(testBridge.id); 200 | }); 201 | 202 | it("should stop a sentence from speaking, callback style", function (done) { 203 | client.Bridge.stopSpeaking(testBridge.id, done); 204 | }); 205 | 206 | it("should play an audio file on sentence to the bridge, promise style", function () { 207 | return client.Bridge.playAudioFile(testBridge.id, audioUrl); 208 | }); 209 | 210 | it("should play an audio file on sentence to the bridge, callback style", function (done) { 211 | client.Bridge.playAudioFile(testBridge.id, audioUrl, done); 212 | }); 213 | 214 | it("should play an audio with custom params to the bridge, promise style", function () { 215 | return client.Bridge.playAudioAdvanced(testBridge.id, { fileUrl : audioUrl }); 216 | }); 217 | 218 | it("should play an audio with custom params to the bridge, callback style", function (done) { 219 | client.Bridge.playAudioAdvanced(testBridge.id, { fileUrl : audioUrl }, done); 220 | }); 221 | 222 | it("should stop an audio file playback, promise style", function () { 223 | return client.Bridge.stopAudioFilePlayback(testBridge.id); 224 | }); 225 | 226 | it("should stop an audio file playback, callback style", function (done) { 227 | client.Bridge.stopAudioFilePlayback(testBridge.id, done); 228 | }); 229 | 230 | it("should update the bridge, promise style", function () { 231 | return client.Bridge.update(testBridge.id, changes); 232 | }); 233 | 234 | it("should get a list of calls for the bridge, promise style", function () { 235 | return client.Bridge.getCalls(testBridge.id) 236 | .then(function (calls) { 237 | calls[0].should.eql(callsList[0]); 238 | calls[1].should.eql(callsList[1]); 239 | }); 240 | }); 241 | 242 | describe("pagination tests", function () { 243 | 244 | before(function () { 245 | nock("https://api.catapult.inetwork.com") 246 | .persist() 247 | .get("/v1/users/" + userId + "/bridges?size=25") 248 | .reply(200, bridgesList, 249 | { 250 | "link" : "; rel=\"first\"," + 252 | "; rel=\"next\"" 253 | }); 254 | }); 255 | 256 | after(function () { 257 | nock.cleanAll(); 258 | nock.enableNetConnect(); 259 | }); 260 | 261 | it("should return a list of bridges with a page to the next link", function () { 262 | return client.Bridge.list({ size : 25 }) 263 | .then(function (bridgesResponse) { 264 | bridgesResponse.bridges.should.eql(bridgesList); 265 | return bridgesResponse.getNextPage(); 266 | }) 267 | .then(function (moreBridges) { 268 | moreBridges.bridges.should.eql(bridgesList); 269 | }); 270 | }); 271 | }); 272 | }); 273 | }); 274 | -------------------------------------------------------------------------------- /test/bxml-responses/call.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/chaining.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hi! My name is: 4 | What? My name is: 5 | -------------------------------------------------------------------------------- /test/bxml-responses/conference.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/gather.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/hangup.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/multiTransfer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Your call is somewhat important to us. 4 | Please wait while it is being transferred. 5 | 6 | transferOne 7 | transferTwo 8 | transferThree 9 | A call is being transferred to you from Customer Service. 10 | 11 | -------------------------------------------------------------------------------- /test/bxml-responses/nesting.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Press some numbers! 5 | 6 | -------------------------------------------------------------------------------- /test/bxml-responses/pause.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /test/bxml-responses/playAudio.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | http://www.example.com/example.mp3 4 | -------------------------------------------------------------------------------- /test/bxml-responses/record.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/redirect.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/bxml-responses/sendDtmf.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 4 | 5 | -------------------------------------------------------------------------------- /test/bxml-responses/sendMessage.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Where are you? 4 | -------------------------------------------------------------------------------- /test/bxml-responses/speakSentence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Thank you for calling ACME Technical Support. 4 | -------------------------------------------------------------------------------- /test/bxml-responses/transfer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /test/client-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var Client = require("../lib/client"); 3 | var RateLimitError = require("../lib/RateLimitError"); 4 | var UnexpectedResponseError = require("../lib/unexpectedResponseError"); 5 | 6 | var baseUrl = "https://api.catapult.inetwork.com"; 7 | 8 | describe("Client", function () { 9 | 10 | var accountResponse = { 11 | balance : "20.00", 12 | accountType : "pre-pay" 13 | }; 14 | 15 | before(function () { 16 | nock.disableNetConnect(); 17 | }); 18 | 19 | after(function () { 20 | nock.enableNetConnect(); 21 | }); 22 | 23 | describe("using default options", function () { 24 | var client; 25 | 26 | before(function () { 27 | client = new Client({ 28 | userId : "fakeUserId", 29 | apiToken : "fakeApiToken", 30 | apiKey : "fakeApiKey" 31 | }); 32 | 33 | nock(baseUrl) 34 | .persist() 35 | .get("/v1/users/fakeUserId/account") 36 | .reply(200, accountResponse) 37 | .post("/v1/users/fakeUserId/201endpoint") 38 | .reply(201,{},{}) 39 | .post("/v1/users/fakeUserId/202endpoint") 40 | .reply(202,{},{}); 41 | }); 42 | 43 | after(function () { 44 | nock.cleanAll(); 45 | }); 46 | 47 | it("should make requests to the default baseUrl", function () { 48 | return client.makeRequest({ 49 | path : "account" 50 | }).then(function (res) { 51 | res.body.should.eql(accountResponse); 52 | }); 53 | }); 54 | 55 | it("should not error on 200 responses", function () { 56 | return client.makeRequest({ 57 | path : "account" 58 | }).then(function (res) { 59 | res.statusCode.should.eql(200); 60 | }); 61 | }); 62 | 63 | it("should not error on 201 responses", function () { 64 | return client.makeRequest({ 65 | path : "201endpoint", 66 | method : "POST" 67 | }).then(function (res) { 68 | res.statusCode.should.eql(201); 69 | }); 70 | }); 71 | 72 | it("should not error on 202 responses", function () { 73 | return client.makeRequest({ 74 | path : "202endpoint", 75 | method : "POST" 76 | }).then(function (res) { 77 | res.statusCode.should.eql(202); 78 | }); 79 | }); 80 | }); 81 | 82 | describe("using custom options", function () { 83 | var client; 84 | var oldBaseUrl; 85 | 86 | before(function () { 87 | oldBaseUrl = baseUrl; 88 | baseUrl = "https://stage.catapult.inetwork.com"; 89 | client = new Client({ 90 | userId : "fakeUserId", 91 | apiToken : "fakeApiToken", 92 | apiKey : "fakeApiKey", 93 | baseUrl : baseUrl 94 | }); 95 | }); 96 | 97 | after(function () { 98 | nock.cleanAll(); 99 | baseUrl = oldBaseUrl; 100 | }); 101 | 102 | it("should make requests to the custom baseUrl", function () { 103 | var accountResponse = { 104 | balance : "20.00", 105 | accountType : "pre-pay" 106 | }; 107 | 108 | nock(baseUrl).get("/v1/users/fakeUserId/account").reply(200, accountResponse); 109 | return client.makeRequest({ 110 | path : "account" 111 | }).then(function (res) { 112 | res.body.should.eql(accountResponse); 113 | }); 114 | }); 115 | 116 | }); 117 | 118 | describe("using path without user", function () { 119 | var client; 120 | var oldBaseUrl; 121 | 122 | before(function () { 123 | client = new Client({ 124 | userId : "fakeUserId", 125 | apiToken : "fakeApiToken", 126 | apiKey : "fakeApiKey" 127 | }); 128 | }); 129 | 130 | after(function () { 131 | nock.cleanAll(); 132 | }); 133 | 134 | it("should make requests without user data in the path", function () { 135 | var numbersResponse = []; 136 | nock(baseUrl).get("/v1/availableNumbers").reply(200, numbersResponse); 137 | return client.makeRequest({ 138 | path : "availableNumbers", 139 | pathWithoutUser : true 140 | }).then(function (res) { 141 | res.body.should.eql(numbersResponse); 142 | }); 143 | }); 144 | 145 | }); 146 | 147 | describe("in error cases", function () { 148 | var client; 149 | var limitReset = 1501782812222; 150 | 151 | var rateLimitBody = { 152 | "category" : "too-many-requests", 153 | "code" : "rate-limit-reached", 154 | "details" : [ 155 | { 156 | "name" : "requestPath", 157 | "value" : "availableNumbers/local" 158 | }, 159 | { 160 | "name" : "remoteAddress", 161 | "value" : "107.197.154.30" 162 | }, 163 | { 164 | "name" : "rateLimitResetTime", 165 | "value" : "1501782812222" 166 | }, 167 | { 168 | "name" : "requestMethod", 169 | "value" : "GET" 170 | } 171 | ] 172 | }; 173 | 174 | before(function () { 175 | client = new Client({ 176 | userId : "fakeUserId", 177 | apiToken : "fakeApiToken", 178 | apiKey : "fakeApiKey" 179 | }); 180 | 181 | nock(baseUrl) 182 | .persist() 183 | .get("/v1/users/fakeUserId/account") 184 | .reply(401, { message : "Something bad happened..." }) 185 | .get("/v1/users/fakeUserId/unknown") 186 | .reply(404) 187 | .get("/v1/users/fakeUserId/RateLimit") 188 | .reply(429, rateLimitBody, { "X-RateLimit-Reset" : limitReset }) 189 | .get("/v1/users/fakeUserId/RateLimitError") 190 | .reply(429, rateLimitBody) 191 | .get("/v1/users/fakeUserId/unknown2") 192 | .reply(404, {}); 193 | }); 194 | 195 | after(function () { 196 | nock.cleanAll(); 197 | }); 198 | 199 | it("should throw exceptions on unexpected HTTP responses", function () { 200 | return client.makeRequest({ 201 | path : "account" 202 | }).then(function (res) { 203 | throw new Error("It should have thrown an exception!"); 204 | }).catch(function (err) { 205 | err.statusCode.should.equal(401); 206 | err.message.should.equal("Something bad happened..."); 207 | }); 208 | }); 209 | 210 | it("should throw exceptions on unexpected HTTP responses with no response body", function () { 211 | return client.makeRequest({ 212 | path : "unknown" 213 | }).then(function (res) { 214 | throw new Error("It should have thrown an exception!"); 215 | }).catch(function (err) { 216 | err.statusCode.should.equal(404); 217 | err.message.should.equal(""); 218 | }); 219 | }); 220 | 221 | it("should throw exceptions on unexpected HTTP responses with an empty response body", function () { 222 | return client.makeRequest({ 223 | path : "unknown2" 224 | }).then(function (res) { 225 | throw new Error("It should have thrown an exception!"); 226 | }).catch(function (err) { 227 | err.statusCode.should.equal(404); 228 | err.message.should.equal(""); 229 | }); 230 | }); 231 | 232 | it("should return RateLimit Error on 429", function () { 233 | return client.makeRequest({ 234 | path : "RateLimit" 235 | }) 236 | .then(function (res) { 237 | throw new Error("It should have been an exception"); 238 | }) 239 | .catch(function (err) { 240 | err.statusCode.should.equal(429); 241 | err.limitReset.should.equal(limitReset); 242 | err.message.should.deepEqual(rateLimitBody); 243 | err.should.be.instanceOf(RateLimitError); 244 | }); 245 | }); 246 | 247 | it("should return UnexpectedResponseError Error on 429 when X-RateLimit-Reset is not present", function () { 248 | return client.makeRequest({ 249 | path : "RateLimitError" 250 | }) 251 | .then(function (res) { 252 | throw new Error("It should have been an exception"); 253 | }) 254 | .catch(function (err) { 255 | err.statusCode.should.equal(429); 256 | err.should.be.instanceOf(UnexpectedResponseError); 257 | }); 258 | }); 259 | }); 260 | }); 261 | -------------------------------------------------------------------------------- /test/conference-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Conference API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var newTestConference = { 16 | from : "+1234567890" 17 | }; 18 | 19 | var changes = { 20 | state : "completed" 21 | }; 22 | 23 | var testConference = { 24 | "id" : "conferenceId", 25 | "state" : "completed", 26 | "from" : "+1234567890" 27 | }; 28 | 29 | var conferencesList = [ testConference ]; 30 | 31 | var newTestMember = { 32 | callId : "callId" 33 | }; 34 | 35 | var testMember = { 36 | "id" : "memberId", 37 | "state" : "active", 38 | "call" : "http://.../callId" 39 | }; 40 | 41 | var memberList = [ testMember ]; 42 | 43 | var tag = "tag"; 44 | var sampleSentence = "Hello world"; 45 | var speakSentencePayload = { 46 | sentence : sampleSentence 47 | }; 48 | 49 | var speakSentencePayloadWithTag = { 50 | sentence : sampleSentence, 51 | tag : tag 52 | }; 53 | 54 | var audioUrl = "http://somewhere/something.mp3"; 55 | var playAudioPayload = { 56 | fileUrl : audioUrl 57 | }; 58 | 59 | var playAudioPayloadWithTag = { 60 | fileUrl : audioUrl, 61 | tag : tag 62 | }; 63 | 64 | var stopFilePlaybackPayload = { 65 | fileUrl : "" 66 | }; 67 | 68 | var stopSpeakingPayload = { 69 | sentence : "" 70 | }; 71 | 72 | before(function () { 73 | client = new CatapultClient({ 74 | userId : userId, 75 | apiToken : apiToken, 76 | apiSecret : apiSecret 77 | }); 78 | nock.disableNetConnect(); 79 | 80 | nock("https://api.catapult.inetwork.com") 81 | .persist() 82 | .post("/v1/users/" + userId + "/conferences", newTestConference) 83 | .reply(201, 84 | {}, 85 | { 86 | "Location" : "/v1/users/" + userId + "/conferences/fakeConferenceId" 87 | }) 88 | .get("/v1/users/" + userId + "/conferences/" + testConference.id) 89 | .reply(200, testConference) 90 | .post("/v1/users/" + userId + "/conferences/" + testConference.id, changes) 91 | .reply(200) 92 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", speakSentencePayload) 93 | .reply(200) 94 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", playAudioPayload) 95 | .reply(200) 96 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", speakSentencePayloadWithTag) 97 | .reply(200) 98 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", stopSpeakingPayload) 99 | .reply(200) 100 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", playAudioPayloadWithTag) 101 | .reply(200) 102 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/audio", stopFilePlaybackPayload) 103 | .reply(200) 104 | .get("/v1/users/" + userId + "/conferences/" + testConference.id + "/members") 105 | .reply(200, memberList) 106 | .get("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + testMember.id) 107 | .reply(200, testMember) 108 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members", newTestMember) 109 | .reply(201, 110 | {}, 111 | { 112 | "Location" : "/v1/users/" + userId + "/conferences/fakeConferenceId/members/" + testMember.id 113 | }) 114 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + testMember.id, changes) 115 | .reply(200) 116 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + 117 | testMember.id + "/audio", speakSentencePayload) 118 | .reply(200) 119 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + 120 | testMember.id + "/audio", playAudioPayload) 121 | .reply(200) 122 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + 123 | testMember.id + "/audio", speakSentencePayloadWithTag) 124 | .reply(200) 125 | .post("/v1/users/" + userId + "/conferences/" + testConference.id + "/members/" + 126 | testMember.id + "/audio", playAudioPayloadWithTag) 127 | .reply(200); 128 | }); 129 | 130 | after(function () { 131 | nock.cleanAll(); 132 | nock.enableNetConnect(); 133 | }); 134 | 135 | it("should create a conference, promise style", function () { 136 | return client.Conference.create(newTestConference) 137 | .then(function (conference) { 138 | conference.should.eql(newTestConference); 139 | }); 140 | }); 141 | 142 | it("should get a conference, promise style", function () { 143 | return client.Conference.get(testConference.id) 144 | .then(function (conference) { 145 | conference.should.eql(testConference); 146 | }); 147 | }); 148 | 149 | it("should update a conference, promise style", function () { 150 | return client.Conference.update(testConference.id, changes); 151 | }); 152 | 153 | it("should remove a conference, promise style", function () { 154 | return client.Conference.remove(testConference.id); 155 | }); 156 | 157 | it("should speak a sentence to the conference, promise style", function () { 158 | return client.Conference.speakSentence(testConference.id, sampleSentence); 159 | }); 160 | 161 | it("should stop a sentence from speaking, promise style", function () { 162 | return client.Conference.stopSpeaking(testConference.id); 163 | }); 164 | 165 | it("should play an audio file on sentence to the conference, promise style", function () { 166 | return client.Conference.playAudioFile(testConference.id, audioUrl); 167 | }); 168 | 169 | it("should play an audio with custom params to the conference, promise style", function () { 170 | return client.Conference.playAudioAdvanced(testConference.id, { fileUrl : audioUrl }); 171 | }); 172 | 173 | it("should stop an audio file playback, promise style", function () { 174 | return client.Conference.stopAudioFilePlayback(testConference.id); 175 | }); 176 | 177 | it("should get a list of members, promise style", function () { 178 | return client.Conference.getMembers(testConference.id) 179 | .then(function (members) { 180 | members.should.eql(memberList); 181 | }); 182 | }); 183 | 184 | it("should get a member, promise style", function () { 185 | return client.Conference.getMember(testConference.id, testMember.id) 186 | .then(function (member) { 187 | member.should.eql(member); 188 | }); 189 | }); 190 | 191 | it("should add a member, promise style", function () { 192 | return client.Conference.createMember(testConference.id, newTestMember) 193 | .then(function (member) { 194 | member.should.eql(newTestMember); 195 | }); 196 | }); 197 | 198 | it("should update a member, promise style", function () { 199 | return client.Conference.updateMember(testConference.id, testMember.id, changes); 200 | }); 201 | 202 | it("should remove a member, promise style", function () { 203 | return client.Conference.removeMember(testConference.id, testMember.id); 204 | }); 205 | 206 | it("should speak a sentence to the member, promise style", function () { 207 | return client.Conference.speakSentenceToMember(testConference.id, testMember.id, sampleSentence); 208 | }); 209 | 210 | it("should play an audio file on sentence to the member, promise style", function () { 211 | return client.Conference.playAudioFileToMember(testConference.id, testMember.id, audioUrl); 212 | }); 213 | 214 | it("should play an audio with custom params to the member, promise style", function () { 215 | return client.Conference.playAudioAdvancedToMember(testConference.id, testMember.id, { fileUrl : audioUrl }); 216 | }); 217 | }); 218 | }); 219 | -------------------------------------------------------------------------------- /test/domain-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Domain API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var newTestDomain = { 16 | name : "domain1", 17 | description : "New domain", 18 | }; 19 | 20 | var testDomain = { 21 | "id" : "fakeDomainId", 22 | "name" : "domain11", 23 | "description" : "New domain", 24 | "endpoints" : "https://.../domains/fakeDomainId/endpoints" 25 | }; 26 | 27 | var domainsList = [ 28 | { 29 | "id" : "fakeDomainId1", 30 | "name" : "domain11", 31 | "description" : "New domain1", 32 | "endpoints" : "https://.../domains/fakeDomainId1/endpoints" 33 | }, 34 | { 35 | "id" : "fakeDomainId2", 36 | "name" : "domain12", 37 | "description" : "New domain2", 38 | "endpoints" : "https://.../domains/fakeDomainId2/endpoints" 39 | } 40 | ]; 41 | 42 | before(function () { 43 | client = new CatapultClient({ 44 | userId : userId, 45 | apiToken : apiToken, 46 | apiSecret : apiSecret 47 | }); 48 | nock.disableNetConnect(); 49 | 50 | nock("https://api.catapult.inetwork.com") 51 | .persist() 52 | .post("/v1/users/" + userId + "/domains", newTestDomain) 53 | .reply(201, 54 | {}, 55 | { 56 | "Location" : "/v1/users/" + userId + "/domains/fakeDomainId" 57 | }) 58 | .get("/v1/users/" + userId + "/domains") 59 | .reply(200, domainsList) 60 | .delete("/v1/users/" + userId + "/domains/" + testDomain.id) 61 | .reply(200); 62 | }); 63 | 64 | after(function () { 65 | nock.cleanAll(); 66 | nock.enableNetConnect(); 67 | }); 68 | 69 | it("should create a domain", function () { 70 | return client.Domain.create(newTestDomain) 71 | .then(function (domain) { 72 | domain.should.eql(newTestDomain); 73 | }); 74 | }); 75 | 76 | it("should return domain list", function () { 77 | return client.Domain.list({}) 78 | .then(function (domainsResponse) { 79 | domainsResponse.domains.should.eql(domainsList); 80 | }); 81 | }); 82 | 83 | it("those domains should not have more pages", function () { 84 | return client.Domain.list({}) 85 | .then(function (domainsResponse) { 86 | domainsResponse.hasNextPage.should.be.false; 87 | return domainsResponse.getNextPage() 88 | .catch(function (err) { 89 | err.should.equal("Next page does not exist."); 90 | }); 91 | }); 92 | }); 93 | 94 | it("should remove the domain", function () { 95 | return client.Domain.delete(testDomain.id); 96 | }); 97 | 98 | describe("pagination tests", function () { 99 | 100 | before(function () { 101 | nock("https://api.catapult.inetwork.com") 102 | .persist() 103 | .get("/v1/users/" + userId + "/domains?size=25") 104 | .reply(200, domainsList, 105 | { 106 | "link" : "; rel=\"first\"," + 108 | "; rel=\"next\"" 109 | }); 110 | }); 111 | 112 | after(function () { 113 | nock.cleanAll(); 114 | nock.enableNetConnect(); 115 | }); 116 | 117 | it("should return a list of applications with a page to the next link", function () { 118 | return client.Domain.list({ size : 25 }) 119 | .then(function (domainsResponse) { 120 | domainsResponse.domains.should.eql(domainsList); 121 | return domainsResponse.getNextPage(); 122 | }) 123 | .then(function (moreDomains) { 124 | moreDomains.domains.should.eql(domainsList); 125 | }); 126 | }); 127 | }); 128 | }); 129 | }); 130 | -------------------------------------------------------------------------------- /test/endpoint-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Endpoint API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var domainId = "domainId"; 16 | 17 | var newTestEndpoint = { 18 | name : "endpoint1", 19 | description : "New endpoint", 20 | domainId : domainId, 21 | credentials : { "password" : "123456" } 22 | }; 23 | 24 | var testEndpoint = { 25 | id : "endpointId1", 26 | name : "endpoint1", 27 | description : "New endpoint", 28 | sipUri : "endpoint1@doname.bwapp.bwsipp.io", 29 | credentials : { 30 | realm : "doname.bwapp.bwsipp.io", 31 | username : "jsmith-mobile" 32 | } 33 | }; 34 | 35 | var endpointList = [ 36 | { 37 | id : "endpointId1", 38 | name : "endpoint1", 39 | description : "New endpoint", 40 | sipUri : "endpoint1@doname.bwapp.bwsipp.io", 41 | credentials : { 42 | realm : "doname.bwapp.bwsipp.io", 43 | username : "jsmith-mobile" 44 | } 45 | }, 46 | { 47 | id : "endpointId2", 48 | name : "endpoint2", 49 | description : "New endpoint", 50 | sipUri : "endpoint2@doname.bwapp.bwsipp.io", 51 | credentials : { 52 | realm : "doname.bwapp.bwsipp.io", 53 | username : "jsmith-mobile2" 54 | } 55 | } 56 | ]; 57 | 58 | var changes = { enabled : false }; 59 | 60 | var tokenValue = { token : "token" }; 61 | 62 | var authTokenParams = { expires : 3600 }; 63 | 64 | before(function () { 65 | client = new CatapultClient({ 66 | userId : userId, 67 | apiToken : apiToken, 68 | apiSecret : apiSecret 69 | }); 70 | nock.disableNetConnect(); 71 | 72 | nock("https://api.catapult.inetwork.com") 73 | .persist() 74 | .post("/v1/users/" + userId + "/domains/" + domainId + "/endpoints", newTestEndpoint) 75 | .reply(201, 76 | {}, 77 | { 78 | "Location" : "/v1/users/" + userId + "/domains/" + domainId + "/endpoints/fakeEndpointId" 79 | }) 80 | .get("/v1/users/" + userId + "/domains/" + domainId + "/endpoints") 81 | .reply(200, endpointList) 82 | .delete("/v1/users/" + userId + "/domains/" + domainId + "/endpoints/fakeEndpointId") 83 | .reply(200) 84 | .post("/v1/users/" + userId + "/domains/" + domainId + "/endpoints/fakeEndpointId", changes) 85 | .reply(200) 86 | .get("/v1/users/" + userId + "/domains/" + domainId + "/endpoints/fakeEndpointId") 87 | .reply(200, testEndpoint) 88 | .post("/v1/users/" + userId + "/domains/" + domainId + "/endpoints/fakeEndpointId/tokens", authTokenParams) 89 | .reply(201, tokenValue); 90 | }); 91 | 92 | after(function () { 93 | nock.cleanAll(); 94 | nock.enableNetConnect(); 95 | }); 96 | 97 | it("should create an endpoint", function () { 98 | return client.Endpoint.create(domainId, newTestEndpoint) 99 | .then(function (endpoint) { 100 | endpoint.should.eql(newTestEndpoint); 101 | }); 102 | }); 103 | 104 | it("should remove the endpoint", function () { 105 | return client.Endpoint.delete(domainId, "fakeEndpointId"); 106 | }); 107 | 108 | it("should update the endpoint", function () { 109 | return client.Endpoint.update(domainId, "fakeEndpointId", changes); 110 | }); 111 | 112 | it("should create auth token for the endpoint", function () { 113 | return client.Endpoint.createAuthToken(domainId, "fakeEndpointId", authTokenParams) 114 | .then(function (token) { 115 | token.should.eql(tokenValue); 116 | }); 117 | }); 118 | 119 | it("should return a single endpoint", function () { 120 | return client.Endpoint.get(domainId, "fakeEndpointId").then(function (endpoint) { 121 | endpoint.should.eql(testEndpoint); 122 | }); 123 | }); 124 | 125 | it("should get a list of endpoints, Promise", function () { 126 | return client.Endpoint.list(domainId) 127 | .then(function (response) { 128 | response.endpoints.should.eql(endpointList); 129 | }); 130 | }); 131 | 132 | it("should get a list of endpoints, callback", function (done) { 133 | client.Endpoint.list(domainId, function (err, response) { 134 | if (err) { 135 | return done(err); 136 | } 137 | response.endpoints.should.eql(endpointList); 138 | done(); 139 | }); 140 | }); 141 | 142 | it("those endpoints should not have more pages", function () { 143 | return client.Endpoint.list(domainId) 144 | .then(function (response) { 145 | response.hasNextPage.should.be.false; 146 | return response.getNextPage() 147 | .catch(function (err) { 148 | err.should.equal("Next page does not exist."); 149 | }); 150 | }); 151 | }); 152 | 153 | describe("pagination tests", function () { 154 | 155 | before(function () { 156 | nock("https://api.catapult.inetwork.com") 157 | .persist() 158 | .get("/v1/users/" + userId + "/domains/" + domainId + 159 | "/endpoints?size=25") 160 | .reply(200, endpointList, 161 | { 162 | "link" : "; rel=\"first\"," + 164 | "; rel=\"next\"" 165 | }); 166 | }); 167 | 168 | after(function () { 169 | nock.cleanAll(); 170 | nock.enableNetConnect(); 171 | }); 172 | 173 | it("should return a list of endpoints with a page to the next link", function () { 174 | return client.Endpoint.list(domainId, { size : 25 }) 175 | .then(function (response) { 176 | response.endpoints.should.eql(endpointList); 177 | return response.getNextPage(); 178 | }) 179 | .then(function (more) { 180 | more.endpoints.should.eql(endpointList); 181 | }); 182 | }); 183 | }); 184 | 185 | }); 186 | }); 187 | -------------------------------------------------------------------------------- /test/error-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Error API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var testError = { 16 | "time" : "2012-11-15T01:29:24.512Z", 17 | "category" : "unavailable", 18 | "id" : "userErrorId", 19 | "message" : "No application is configured for number +19195556666", 20 | "code" : "no-application-for-number" 21 | }; 22 | 23 | var errorsList = [ testError ]; 24 | 25 | before(function () { 26 | client = new CatapultClient({ 27 | userId : userId, 28 | apiToken : apiToken, 29 | apiSecret : apiSecret 30 | }); 31 | nock.disableNetConnect(); 32 | 33 | nock("https://api.catapult.inetwork.com") 34 | .persist() 35 | .get("/v1/users/" + userId + "/errors/" + testError.id) 36 | .reply(200, testError) 37 | .get("/v1/users/" + userId + "/errors") 38 | .reply(200, errorsList); 39 | }); 40 | 41 | after(function () { 42 | nock.cleanAll(); 43 | nock.enableNetConnect(); 44 | }); 45 | 46 | it("should get a error, promise style", function () { 47 | return client.Error.get(testError.id) 48 | .then(function (error) { 49 | error.should.eql(testError); 50 | }); 51 | }); 52 | 53 | it("should get a list of errors, promise style", function () { 54 | return client.Error.list({ }) 55 | .then(function (errorsResponse) { 56 | errorsResponse.errors[0].should.eql(errorsList[0]); 57 | }); 58 | }); 59 | 60 | it("should get a list of errors, callback style", function (done) { 61 | client.Error.list({ }, function (err, errorsResponse) { 62 | if (err) { 63 | throw err; 64 | } 65 | errorsResponse.errors[0].should.eql(errorsList[0]); 66 | done(); 67 | }); 68 | }); 69 | 70 | it("those errors should not have more pages", function () { 71 | return client.Error.list({}) 72 | .then(function (errorsResponse) { 73 | errorsResponse.hasNextPage.should.be.false; 74 | return errorsResponse.getNextPage() 75 | .catch(function (err) { 76 | err.should.equal("Next page does not exist."); 77 | }); 78 | }); 79 | }); 80 | 81 | describe("pagination tests", function () { 82 | 83 | before(function () { 84 | nock("https://api.catapult.inetwork.com") 85 | .persist() 86 | .get("/v1/users/" + userId + "/errors?size=25") 87 | .reply(200, errorsList, 88 | { 89 | "link" : "; rel=\"first\"," + 91 | "; rel=\"next\"" 92 | }); 93 | }); 94 | 95 | after(function () { 96 | nock.cleanAll(); 97 | nock.enableNetConnect(); 98 | }); 99 | 100 | it("should return a list of errors with a page to the next link", function () { 101 | return client.Error.list({ size : 25 }) 102 | .then(function (errorsResponse) { 103 | errorsResponse.errors.should.eql(errorsList); 104 | return errorsResponse.getNextPage(); 105 | }) 106 | .then(function (moreErrors) { 107 | moreErrors.errors.should.eql(errorsList); 108 | }); 109 | }); 110 | }); 111 | }); 112 | }); 113 | -------------------------------------------------------------------------------- /test/headerparsinglib-test.js: -------------------------------------------------------------------------------- 1 | var getNextLink = require("../lib/headerParsingLib").getNextLink; 2 | 3 | describe("Utility Library", function () { 4 | 5 | describe("getNextLink works as intended if the response has a next link", function () { 6 | 7 | var response; 8 | 9 | before (function () { 10 | response = { 11 | "headers" : { 12 | "link" : "; rel=\"first\"," + 13 | "; rel=\"next\"" 14 | } 15 | }; 16 | }); 17 | 18 | it("returns a link", function () { 19 | getNextLink(response.headers).should.be.ok; 20 | }); 21 | }); 22 | 23 | describe("getNextLink works as intended if the response does not have a next link", function () { 24 | 25 | var response; 26 | 27 | before(function () { 28 | response = { 29 | "headers" : { 30 | "link" : "; rel=\"first\"" 31 | } 32 | }; 33 | }); 34 | 35 | it("returns null", function () { 36 | (getNextLink(response.headers) === null).should.be.true; 37 | }); 38 | }); 39 | 40 | describe("getNextLink works as intended if the response does not have any links", function () { 41 | 42 | var response; 43 | 44 | before(function () { 45 | response = { 46 | "headers" : {} 47 | }; 48 | }); 49 | 50 | it("returns null", function () { 51 | (getNextLink(response.headers) === null).should.be.true; 52 | }); 53 | }); 54 | }); -------------------------------------------------------------------------------- /test/media-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var stream = require("stream"); 3 | var fs = require("fs"); 4 | var path = require("path"); 5 | var os = require("os"); 6 | var sinon = require("sinon"); 7 | var CatapultClient = require("../index"); 8 | 9 | var baseUrl = "https://api.catapult.inetwork.com"; 10 | 11 | describe("Media API", function () { 12 | 13 | describe("global methods", function () { 14 | var client; 15 | 16 | var userId = "fakeUserId"; 17 | var apiToken = "fakeApiToken"; 18 | var apiSecret = "fakeapiSecret"; 19 | 20 | var mediaName1 = "file1"; 21 | var mediaName2 = "file2"; 22 | var mediaContent = "1234567890"; 23 | 24 | var getMediaContentAsStream = function () { 25 | var s = new stream.Readable(); 26 | s.push(mediaContent); 27 | s.push(null); 28 | return s; 29 | }; 30 | 31 | var mediaFileList = [ 32 | { 33 | "contentLength" : 561276, 34 | "mediaName" : "{mediaName1}", 35 | "content" : "api.catapult.inetwork.com/.../media/{mediaName1}" 36 | } 37 | ]; 38 | 39 | var mediaContentFile = path.join(os.tmpdir(), "node-bandwidth-media-file.txt"); 40 | 41 | before(function () { 42 | fs.writeFileSync(mediaContentFile, mediaContent); 43 | client = new CatapultClient({ 44 | userId : userId, 45 | apiToken : apiToken, 46 | apiSecret : apiSecret 47 | 48 | }); 49 | nock.disableNetConnect(); 50 | 51 | nock("https://api.catapult.inetwork.com", { 52 | reqheaders : { 53 | "Content-Type" : "application/octet-stream" 54 | } 55 | }) 56 | .persist() 57 | .put("/v1/users/" + userId + "/media/" + mediaName1) 58 | .reply(200); 59 | nock("https://api.catapult.inetwork.com", { 60 | reqheaders : { 61 | "Content-Type" : "text/plain" 62 | } 63 | }) 64 | .persist() 65 | .put("/v1/users/" + userId + "/media/" + mediaName2, mediaContent) 66 | .reply(200); 67 | nock("https://api.catapult.inetwork.com") 68 | .persist() 69 | .get("/v1/users/" + userId + "/media/" + mediaName1) 70 | .reply(200, mediaContent, { "Content-Type" : "text/plain" }) 71 | .get("/v1/users/" + userId + "/media") 72 | .reply(200, mediaFileList) 73 | .delete("/v1/users/" + userId + "/media/" + mediaName1) 74 | .reply(200); 75 | }); 76 | 77 | after(function () { 78 | nock.cleanAll(); 79 | nock.enableNetConnect(); 80 | fs.unlinkSync(mediaContentFile); 81 | }); 82 | 83 | it("should upload a media file (Buffer), Promise", function () { 84 | return client.Media.upload(mediaName1, new Buffer(mediaContent)); 85 | }); 86 | 87 | it("should upload a media file (Buffer) with content type, Promise", function () { 88 | return client.Media.upload(mediaName2, new Buffer(mediaContent), "text/plain"); 89 | }); 90 | 91 | it("should upload a media file (Buffer), callback", function (done) { 92 | client.Media.upload(mediaName1, new Buffer(mediaContent), done); 93 | }); 94 | 95 | it("should upload a media file (Buffer) with content type, callback", function (done) { 96 | client.Media.upload(mediaName2, new Buffer(mediaContent), "text/plain", done); 97 | }); 98 | 99 | it("should upload a media file (stream), Promise", function () { 100 | return client.Media.upload(mediaName1, getMediaContentAsStream()); 101 | }); 102 | 103 | it("should upload a media file (stream) with content type, Promise", function () { 104 | return client.Media.upload(mediaName2, getMediaContentAsStream(), "text/plain"); 105 | }); 106 | 107 | it("should upload a media file (file), Promise", function () { 108 | return client.Media.upload(mediaName1, mediaContentFile); 109 | }); 110 | 111 | it("should upload a media file (file) with content type, Promise", function () { 112 | return client.Media.upload(mediaName2, mediaContentFile, "text/plain"); 113 | }); 114 | 115 | it("should throw error if uploaded data is invalid", function (done) { 116 | new Promise(function (resolve) { 117 | return client.Media.upload(mediaName1, {}, function (err) { 118 | err.should.be.ok; 119 | done(); 120 | }); 121 | }); 122 | }); 123 | 124 | it("should throw error if fs.stat failed", function (done) { 125 | new Promise(function (resolve) { 126 | var stub = sinon.stub(fs, "stat").callsArgWith(1, new Error()); 127 | return client.Media.upload(mediaName1, mediaContent, function (err) { 128 | err.should.be.ok; 129 | stub.restore(); 130 | done(); 131 | }); 132 | }); 133 | }); 134 | 135 | it("should download a media file", function () { 136 | return client.Media.download(mediaName1) 137 | .then(function (result) { 138 | result.contentType.should.eql("text/plain"); 139 | result.content.toString().should.eql(mediaContent); 140 | }); 141 | }); 142 | 143 | it("should list media files", function () { 144 | return client.Media.list() 145 | .then(function (files) { 146 | files[0].should.eql(mediaFileList[0]); 147 | }); 148 | }); 149 | 150 | it("should remove a media file", function () { 151 | return client.Media.delete(mediaName1); 152 | }); 153 | }); 154 | }); 155 | -------------------------------------------------------------------------------- /test/message-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | var baseUrl = "https://api.catapult.inetwork.com"; 4 | 5 | describe("Message API", function () { 6 | 7 | var client; 8 | 9 | var userId = "fakeUserId"; 10 | var apiToken = "fakeApiToken"; 11 | var apiSecret = "fakeapiSecret"; 12 | 13 | var newTestMessage = { 14 | from : "+12345678901", 15 | to : "+12345678902", 16 | text : "Hello world." 17 | }; 18 | 19 | var otherTestMessage = { 20 | from : "+12345678902", 21 | text : "Hello world." 22 | }; 23 | 24 | var testMessage = { 25 | "id" : "fakeMessageId", 26 | "messageId" : "fakeMessageId", 27 | "from" : "+12345678901", 28 | "to" : "+12345678902", 29 | "text" : "Good morning, this is a test message", 30 | "time" : "2012-10-05T20:37:38.048Z", 31 | "direction" : "out", 32 | "state" : "sent", 33 | "media" : [] 34 | }; 35 | 36 | var someOtherTestMessage = { 37 | "id" : "fakeMessageId2", 38 | "messageId" : "fakeMessageId2", 39 | "from" : "+12345678902", 40 | "to" : "+12345678901", 41 | "text" : "I received your test message", 42 | "time" : "2012-10-05T20:38:11.023Z", 43 | "direction" : "in", 44 | "state" : "received", 45 | "media" : [] 46 | }; 47 | 48 | var messagesList = [ testMessage, someOtherTestMessage ]; 49 | 50 | var fromDateTime = "2012-10-04"; 51 | var toDateTime = "2012-10-06"; 52 | 53 | describe("global methods using single page response", function () { 54 | 55 | before(function () { 56 | client = new CatapultClient({ 57 | userId : userId, 58 | apiToken : apiToken, 59 | apiSecret : apiSecret 60 | }); 61 | nock.disableNetConnect(); 62 | 63 | nock("https://api.catapult.inetwork.com") 64 | .persist() 65 | .post("/v1/users/" + userId + "/messages", newTestMessage) 66 | .reply(201, 67 | {}, 68 | { 69 | "Location" : "/v1/users/" + userId + "/messages/fakeMessageId" 70 | }) 71 | .post("/v1/users/" + userId + "/messages", [ newTestMessage, otherTestMessage ]) 72 | .reply(202, 73 | [ 74 | { 75 | result : "accepted", 76 | location : "https://api.catapult.inetwork.com/v1/users/" + userId + 77 | "/messages/fakeMessageId" 78 | }, 79 | { 80 | result : "error", 81 | error : { 82 | category : "bad-request", 83 | code : "blank-property", 84 | message : "The 'message' resource property 'to' must contain at least" + 85 | " one non-whitespace character", 86 | details : [] 87 | } 88 | } 89 | ] 90 | ) 91 | .get("/v1/users/" + userId + "/messages/" + testMessage.id) 92 | .reply(200, testMessage) 93 | .get("/v1/users/" + userId + "/messages?fromDateTime=" + fromDateTime + "&" + "toDateTime=" + toDateTime) 94 | .reply(200, messagesList) 95 | .patch("/v1/users/" + userId + "/messages/" + testMessage.id, { text : "" }) 96 | .reply(200); 97 | }); 98 | 99 | after(function () { 100 | nock.cleanAll(); 101 | nock.enableNetConnect(); 102 | }); 103 | 104 | it("should send a message, promise style", function () { 105 | return client.Message.send(newTestMessage) 106 | .then(function (message) { 107 | message.should.eql(newTestMessage); 108 | }); 109 | }); 110 | 111 | it("should send a message, callback style", function (done) { 112 | new Promise(function (resolve) { 113 | client.Message.send(newTestMessage, function (err, message) { 114 | if (err) { 115 | throw err; 116 | } 117 | message.should.eql(newTestMessage); 118 | done(); 119 | }); 120 | }); 121 | }); 122 | 123 | it("should send multiple messages", function () { 124 | return client.Message.sendMultiple([ newTestMessage, otherTestMessage ]) 125 | .then(function (messages) { 126 | messages[0].message.should.eql(newTestMessage); 127 | messages[1].error.should.eql({ 128 | category : "bad-request", 129 | code : "blank-property", 130 | message : "The 'message' resource property 'to' must contain at " + 131 | "least one non-whitespace character", 132 | details : [] 133 | }); 134 | }); 135 | }); 136 | 137 | it("should get a message, promise style", function () { 138 | return client.Message.get(testMessage.id) 139 | .then(function (message) { 140 | message.should.eql(testMessage); 141 | }); 142 | }); 143 | 144 | it("should get a list of messages, promise style", function () { 145 | return client.Message.list({ 146 | fromDateTime : fromDateTime, 147 | toDateTime : toDateTime 148 | }) 149 | .then(function (messageResponse) { 150 | var messages = messageResponse.messages; 151 | messages.should.eql(messagesList); 152 | }); 153 | }); 154 | 155 | it("should contain the nextLink in response", function () { 156 | return client.Message.list({ 157 | fromDateTime : fromDateTime, 158 | toDateTime : toDateTime 159 | }) 160 | .then(function (messageResponse) { 161 | var nextLink = messageResponse.nextLink; 162 | nextLink.should.eql({}); 163 | }); 164 | }); 165 | 166 | it("should get a list of messages, callback style", function (done) { 167 | new Promise(function (resolve) { 168 | client.Message.list({ 169 | fromDateTime : fromDateTime, 170 | toDateTime : toDateTime 171 | }, function (err, messageResponse) { 172 | if (err) { 173 | throw err; 174 | } 175 | var messages = messageResponse.messages; 176 | messages.should.eql(messagesList); 177 | done(); 178 | }); 179 | }); 180 | }); 181 | 182 | it("should patch a message, promise style", function () { 183 | return client.Message.patch(testMessage.id, { text : "" }); 184 | }); 185 | 186 | it("should patch a message, callback style", function (done) { 187 | client.Message.patch(testMessage.id, { text : "" }, done); 188 | }); 189 | }); 190 | 191 | describe("list function with a multiple page response", function () { 192 | 193 | before(function () { 194 | nock.disableNetConnect(); 195 | 196 | nock("https://api.catapult.inetwork.com") 197 | .persist() 198 | .get("/v1/users/" + userId + "/messages") 199 | .reply(200, messagesList, { 200 | "link" : "; rel=\"next\"" 202 | }) 203 | .get("/v1/users/" + userId + "/messages?sortKeyLT=1") 204 | .reply(200, []); 205 | }); 206 | 207 | after(function () { 208 | nock.cleanAll(); 209 | nock.enableNetConnect(); 210 | }); 211 | 212 | it("should get the next page of messages (if it exists)", function () { 213 | //Simulating a response which has 1 page of messages 214 | return client.Message.list() 215 | .then(function (messageResponse) { 216 | 217 | var messages = messageResponse.messages; 218 | 219 | messages[0].should.eql(messagesList[0]); 220 | messages[1].should.eql(messagesList[1]); 221 | 222 | return messageResponse.getNextPage(); 223 | }) 224 | .then(function (otherMessageResponse) { 225 | 226 | messages = otherMessageResponse.messages; 227 | 228 | (messages[0] === undefined).should.be.true; 229 | 230 | return otherMessageResponse.getNextPage(); 231 | }) 232 | .catch(function (err) { 233 | err.should.eql("Next page does not exist."); 234 | }); 235 | }); 236 | 237 | it("should return the nextLink header", function () { 238 | //Simulating a response which has 1 page of messages 239 | return client.Message.list() 240 | .then(function (messageResponse) { 241 | 242 | var nextLink = messageResponse.nextLink; 243 | nextLink.should.eql({ sortKeyLT : "1" }); 244 | }); 245 | }); 246 | }); 247 | 248 | describe("list function with no messages available", function () { 249 | 250 | before(function () { 251 | nock.disableNetConnect(); 252 | 253 | nock("https://api.catapult.inetwork.com") 254 | .persist() 255 | .get("/v1/users/" + userId + "/messages") 256 | .reply(200, []); 257 | }); 258 | 259 | after(function () { 260 | nock.cleanAll(); 261 | nock.enableNetConnect(); 262 | }); 263 | 264 | it("should not get the next page of messages", function () { 265 | //Simulating a response which has 0 pages of messages 266 | return client.Message.list() 267 | .then(function (messageResponse) { 268 | 269 | var messages = messageResponse.messages; 270 | (messages[0] === undefined).should.be.true; 271 | 272 | return messageResponse.getNextPage(); 273 | }) 274 | .catch(function (err) { 275 | err.should.eql("Next page does not exist."); 276 | }); 277 | }); 278 | }); 279 | }); 280 | -------------------------------------------------------------------------------- /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require should 2 | --reporter dot 3 | --recursive 4 | --timeout 10s 5 | -------------------------------------------------------------------------------- /test/numberInfo-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("NumberInfo API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var number = "234567890"; 16 | 17 | var testNumberInfo = { 18 | "created" : "2013-09-23T16:31:15Z", 19 | "name" : "Name", 20 | "number" : "{number}", 21 | "updated" : "2013-09-23T16:42:18Z" 22 | }; 23 | 24 | before(function () { 25 | client = new CatapultClient({ 26 | userId : userId, 27 | apiToken : apiToken, 28 | apiSecret : apiSecret 29 | }); 30 | nock.disableNetConnect(); 31 | 32 | nock("https://api.catapult.inetwork.com") 33 | .persist() 34 | .get("/v1/phoneNumbers/numberInfo/" + number) 35 | .reply(200, testNumberInfo); 36 | }); 37 | 38 | after(function () { 39 | nock.cleanAll(); 40 | nock.enableNetConnect(); 41 | }); 42 | 43 | it("should get a number info, promise style", function () { 44 | return client.NumberInfo.get(number) 45 | .then(function (numberInfo) { 46 | numberInfo.should.eql(testNumberInfo); 47 | }); 48 | }); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /test/phoneNumber-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("PhoneNumber API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var newTestPhoneNumber = { 16 | number : "+1234567890", 17 | name : "my number" 18 | }; 19 | 20 | var changes = { 21 | name : "main" 22 | }; 23 | 24 | var testPhoneNumber = { 25 | "id" : "phoneNumberId", 26 | "number" : "+1234567890", 27 | "nationalNumber" : "(234) 567-890" 28 | }; 29 | 30 | var phoneNumbersList = [ testPhoneNumber ]; 31 | 32 | before(function () { 33 | client = new CatapultClient({ 34 | userId : userId, 35 | apiToken : apiToken, 36 | apiSecret : apiSecret 37 | }); 38 | nock.disableNetConnect(); 39 | 40 | nock("https://api.catapult.inetwork.com") 41 | .persist() 42 | .post("/v1/users/" + userId + "/phoneNumbers", newTestPhoneNumber) 43 | .reply(201, 44 | {}, 45 | { 46 | "Location" : "/v1/users/" + userId + "/phoneNumbers/fakePhoneNumberId" 47 | }) 48 | .get("/v1/users/" + userId + "/phoneNumbers/" + testPhoneNumber.id) 49 | .reply(200, testPhoneNumber) 50 | .get("/v1/users/" + userId + "/phoneNumbers") 51 | .reply(200, phoneNumbersList) 52 | .post("/v1/users/" + userId + "/phoneNumbers/" + testPhoneNumber.id, changes) 53 | .reply(200) 54 | .delete("/v1/users/" + userId + "/phoneNumbers/" + testPhoneNumber.id) 55 | .reply(200); 56 | }); 57 | 58 | after(function () { 59 | nock.cleanAll(); 60 | nock.enableNetConnect(); 61 | }); 62 | 63 | it("should create a phoneNumber, promise style", function () { 64 | return client.PhoneNumber.create(newTestPhoneNumber) 65 | .then(function (phoneNumber) { 66 | phoneNumber.should.eql(newTestPhoneNumber); 67 | }); 68 | }); 69 | 70 | it("should create a phoneNumber, callback style", function (done) { 71 | client.PhoneNumber.create(newTestPhoneNumber, function (err, phoneNumber) { 72 | if (err) { 73 | throw err; 74 | } 75 | phoneNumber.should.eql(newTestPhoneNumber); 76 | done(); 77 | }); 78 | }); 79 | 80 | it("should get a phoneNumber, promise style", function () { 81 | return client.PhoneNumber.get(testPhoneNumber.id) 82 | .then(function (phoneNumber) { 83 | phoneNumber.should.eql(testPhoneNumber); 84 | }); 85 | }); 86 | 87 | it("should get a list of phoneNumbers, promise style", function () { 88 | return client.PhoneNumber.list({ }) 89 | .then(function (phoneNumbersResponse) { 90 | phoneNumbersResponse.phoneNumbers[0].should.eql(phoneNumbersList[0]); 91 | }); 92 | }); 93 | 94 | it("should get a list of phoneNumbers, callback style", function (done) { 95 | client.PhoneNumber.list({ }, function (err, phoneNumbersResponse) { 96 | if (err) { 97 | throw err; 98 | } 99 | phoneNumbersResponse.phoneNumbers[0].should.eql(phoneNumbersList[0]); 100 | done(); 101 | }); 102 | }); 103 | 104 | it("those phoneNumbers should not have more pages", function () { 105 | return client.PhoneNumber.list({}) 106 | .then(function (phoneNumbersResponse) { 107 | phoneNumbersResponse.hasNextPage.should.be.false; 108 | return phoneNumbersResponse.getNextPage() 109 | .catch(function (err) { 110 | err.should.equal("Next page does not exist."); 111 | }); 112 | }); 113 | }); 114 | 115 | it("should remove the phoneNumber, promise style", function () { 116 | return client.PhoneNumber.delete(testPhoneNumber.id); 117 | }); 118 | 119 | it("should update the phoneNumber, promise style", function () { 120 | return client.PhoneNumber.update(testPhoneNumber.id, changes); 121 | }); 122 | 123 | describe("pagination tests", function () { 124 | 125 | before(function () { 126 | nock("https://api.catapult.inetwork.com") 127 | .persist() 128 | .get("/v1/users/" + userId + "/phoneNumbers?size=25") 129 | .reply(200, phoneNumbersList, 130 | { 131 | "link" : "; rel=\"first\"," + 133 | "; rel=\"next\"" 134 | }); 135 | }); 136 | 137 | after(function () { 138 | nock.cleanAll(); 139 | nock.enableNetConnect(); 140 | }); 141 | 142 | it("should return a list of phoneNumbers with a page to the next link", function () { 143 | return client.PhoneNumber.list({ size : 25 }) 144 | .then(function (phoneNumbersResponse) { 145 | phoneNumbersResponse.phoneNumbers.should.eql(phoneNumbersList); 146 | return phoneNumbersResponse.getNextPage(); 147 | }) 148 | .then(function (morePhoneNumbers) { 149 | morePhoneNumbers.phoneNumbers.should.eql(phoneNumbersList); 150 | }); 151 | }); 152 | }); 153 | }); 154 | }); 155 | -------------------------------------------------------------------------------- /test/recording-test.js: -------------------------------------------------------------------------------- 1 | var nock = require("nock"); 2 | var CatapultClient = require("../index"); 3 | 4 | var baseUrl = "https://api.catapult.inetwork.com"; 5 | 6 | describe("Recording API", function () { 7 | 8 | describe("global methods", function () { 9 | var client; 10 | 11 | var userId = "fakeUserId"; 12 | var apiToken = "fakeApiToken"; 13 | var apiSecret = "fakeapiSecret"; 14 | 15 | var newTestMessage = { 16 | from : "+12345678901", 17 | to : "+12345678902", 18 | text : "Hello world." 19 | }; 20 | 21 | var testRecording = { 22 | "endTime" : "2013-02-08T13:17:12.181Z", 23 | "id" : "fakeRecordingId", 24 | "media" : "https://.../v1/users/.../media/c-bonay3r4mtwbplurq4nkt7q-1.wav", 25 | "call" : "https://.../v1/users/.../calls/{callId}", 26 | "startTime" : "2013-02-08T13:15:47.587Z", 27 | "state" : "complete" 28 | }; 29 | 30 | var recordingList = [ 31 | { 32 | "endTime" : "2013-02-08T13:17:12.181Z", 33 | "id" : "fakeRecordingId1", 34 | "media" : "https://.../v1/users/.../media/c-bonay3r4mtwbplurq4nkt7q-1.wav", 35 | "call" : "https://.../v1/users/.../calls/{callId}", 36 | "startTime" : "2013-02-08T13:15:47.587Z", 37 | "state" : "complete" 38 | }, 39 | { 40 | "endTime" : "2013-02-08T13:17:12.181Z", 41 | "id" : "fakeRecordingId2", 42 | "media" : "https://.../v1/users/.../media/c-bonay3r4mtwbplurq4nkt7q-1.wav", 43 | "call" : "https://.../v1/users/.../calls/{callId}", 44 | "startTime" : "2013-02-08T13:15:47.587Z", 45 | "state" : "complete" 46 | }, 47 | ]; 48 | 49 | var testTranscription = { 50 | "chargeableDuration" : 11, 51 | "id" : "transcriptionId", 52 | "state" : "completed", 53 | "text" : "Hey there, I was calling to talk about plans for this saturday. ", 54 | "textSize" : 63, 55 | "textUrl" : "https://api.catapult.inetwork.com/.../media/{transcriptionId}", 56 | "time" : "2014-12-23T23:08:59Z" 57 | }; 58 | 59 | var transcriptionList = [ testTranscription ]; 60 | 61 | before(function () { 62 | client = new CatapultClient({ 63 | userId : userId, 64 | apiToken : apiToken, 65 | apiSecret : apiSecret 66 | }); 67 | nock.disableNetConnect(); 68 | 69 | nock("https://api.catapult.inetwork.com") 70 | .persist() 71 | .get("/v1/users/" + userId + "/recordings/" + testRecording.id) 72 | .reply(200, testRecording) 73 | .get("/v1/users/" + userId + "/recordings") 74 | .reply(200, recordingList) 75 | .get("/v1/users/" + userId + "/recordings/" + testRecording.id + "/transcriptions") 76 | .reply(200, transcriptionList) 77 | .get("/v1/users/" + userId + "/recordings/" + testRecording.id + "/transcriptions/" + testTranscription.id) 78 | .reply(200, testTranscription) 79 | .post("/v1/users/" + userId + "/recordings/" + testRecording.id + "/transcriptions") 80 | .reply(201, {}, { 81 | "Location" : "/v1/users/" + userId + "/recordings/" + testRecording.id + "/transcriptions/" + testTranscription.id 82 | }); 83 | }); 84 | 85 | after(function () { 86 | nock.cleanAll(); 87 | nock.enableNetConnect(); 88 | }); 89 | 90 | it("should get a recording", function () { 91 | return client.Recording.get(testRecording.id) 92 | .then(function (recording) { 93 | recording.should.eql(testRecording); 94 | }); 95 | }); 96 | 97 | it("should get a list of recordings, promise style", function () { 98 | return client.Recording.list() 99 | .then(function (recordings) { 100 | recordings.should.eql(recordingList); 101 | }); 102 | }); 103 | 104 | it("should get a list of transcriptions, promise style", function () { 105 | return client.Recording.getTranscriptions(testRecording.id) 106 | .then(function (transcriptions) { 107 | transcriptions.should.eql(transcriptionList); 108 | }); 109 | }); 110 | 111 | it("should get a transcriptions, promise style", function () { 112 | return client.Recording.getTranscription(testRecording.id, testTranscription.id) 113 | .then(function (transcription) { 114 | transcription.should.eql(testTranscription); 115 | }); 116 | }); 117 | 118 | it("should create a transcriptions, promise style", function () { 119 | return client.Recording.createTranscription(testRecording.id) 120 | .then(function (transcription) { 121 | transcription.id.should.eql(testTranscription.id); 122 | }); 123 | }); 124 | 125 | }); 126 | }); 127 | -------------------------------------------------------------------------------- /test/searchAndOrderNumberQueries-test.js: -------------------------------------------------------------------------------- 1 | var assert = require("assert"); 2 | var client = require("../lib/index"); 3 | 4 | // jscs:disable disallowDanglingUnderscores 5 | 6 | describe("searchAndOrderNumberQueries", function () { 7 | describe("AreaCodeSearchAndOrderNumbersQuery", function () { 8 | it("should build right XML", function () { 9 | (new client.AreaCodeSearchAndOrderNumbersQuery({ areaCode : "910" })).toXml().should.containDeep({ 10 | "AreaCodeSearchAndOrderType" : { 11 | "AreaCode" : { _text : "910" }, 12 | "Quantity" : { _text : 1 } 13 | } 14 | }); 15 | }); 16 | }); 17 | describe("RateCenterSearchAndOrdeNumbersQuery", function () { 18 | it("should build right XML", function () { 19 | (new client.RateCenterSearchAndOrdeNumbersQuery({ rateCenter : "NC", state : "NC" })).toXml().should.containDeep({ 20 | "RateCenterSearchAndOrderType" : { 21 | "RateCenter" : { _text : "NC" }, 22 | "State" : { _text : "NC" }, 23 | "Quantity" : { _text : 1 } 24 | } 25 | }); 26 | }); 27 | }); 28 | describe("NpaNxxSearchAndOrderNumbersQuery", function () { 29 | it("should build right XML", function () { 30 | (new client.NpaNxxSearchAndOrderNumbersQuery({ npaNxx : "num", enableTnDetail : true, enableLca : true })) 31 | .toXml().should.containDeep({ 32 | "NPANXXSearchAndOrderType" : { 33 | "NpaNxx" : { _text : "num" }, 34 | "EnableTNDetail" : { _text : true }, 35 | "EnableLCA" : { _text : true }, 36 | "Quantity" : { _text : 1 } 37 | } 38 | }); 39 | }); 40 | }); 41 | describe("TollFreeVanitySearchAndOrderNumbersQuery", function () { 42 | it("should build right XML", function () { 43 | (new client.TollFreeVanitySearchAndOrderNumbersQuery({ tollFreeVanity : "value" })) 44 | .toXml().should.containDeep({ 45 | "TollFreeVanitySearchAndOrderType" : { 46 | "TollFreeVanity" : { _text : "value" }, 47 | "Quantity" : { _text : 1 } 48 | } 49 | }); 50 | }); 51 | }); 52 | describe("TollFreeWildCharSearchAndOrderNumbersQuery", function () { 53 | it("should build right XML", function () { 54 | (new client.TollFreeWildCharSearchAndOrderNumbersQuery({ tollFreeWildCardPattern : "value" })) 55 | .toXml().should.containDeep({ 56 | "TollFreeWildCharSearchAndOrderType" : { 57 | "TollFreeWildCardPattern" : { _text : "value" }, 58 | "Quantity" : { _text : 1 } 59 | } 60 | }); 61 | }); 62 | }); 63 | describe("StateSearchAndOrderNumbersQuery", function () { 64 | it("should build right XML", function () { 65 | (new client.StateSearchAndOrderNumbersQuery({ state : "value" })).toXml().should.containDeep({ 66 | "StateSearchAndOrderType" : { 67 | "State" : { _text : "value" }, 68 | "Quantity" : { _text : 1 } 69 | } 70 | }); 71 | }); 72 | }); 73 | describe("CitySearchAndOrderNumbersQuery", function () { 74 | it("should build right XML", function () { 75 | (new client.CitySearchAndOrderNumbersQuery({ state : "NC", city : "Cary" })) 76 | .toXml().should.containDeep({ 77 | "CitySearchAndOrderType" : { 78 | "State" : { _text : "NC" }, 79 | "City" : { _text : "Cary" }, 80 | "Quantity" : { _text : 1 } 81 | } 82 | }); 83 | }); 84 | }); 85 | describe("ZipSearchAndOrderNumbersQuery", function () { 86 | it("should build right XML", function () { 87 | (new client.ZipSearchAndOrderNumbersQuery({ zip : "zip" })).toXml().should.containDeep({ 88 | "ZIPSearchAndOrderType" : { 89 | "Zip" : { _text : "zip" }, 90 | "Quantity" : { _text : 1 } 91 | } 92 | }); 93 | }); 94 | }); 95 | describe("LataSearchAndOrderNumbersQuery", function () { 96 | it("should build right XML", function () { 97 | (new client.LataSearchAndOrderNumbersQuery({ lata : "lata" })) 98 | .toXml().should.containDeep({ 99 | "LATASearchAndOrderType" : { 100 | "Lata" : { _text : "lata" }, 101 | "Quantity" : { _text : 1 } 102 | } 103 | }); 104 | }); 105 | }); 106 | describe("CombinedSearchAndOrderNumbersQuery", function () { 107 | it("should build right XML", function () { 108 | (new client.CombinedSearchAndOrderNumbersQuery({ lata : "lata" })) 109 | .toXml().should.containDeep({ 110 | "CombinedSearchAndOrderType" : { 111 | "Quantity" : { _text : 1 }, 112 | "Lata" : { _text : "lata" } 113 | } 114 | }); 115 | }); 116 | }); 117 | }); 118 | -------------------------------------------------------------------------------- /test/templates.json: -------------------------------------------------------------------------------- 1 | { 2 | "irisError1": "CodeDescription", 3 | "irisError2": "CodeDescription", 4 | "irisError3": "CodeDescription", 5 | "irisError4": "CodeDescription", 6 | "createApplicationRequest": "App1url", 7 | "createApplicationResponse": "ApplicationIdMessaging-V2Demo Serverhttps://requestb.in/1m009f61", 8 | "createLocationRequest": "Location1false", 9 | "enableSmsRequest": "truefalseHTTPtruefalsefalsefalsefalse", 10 | "enableMmsRequest": "HTTP", 11 | "assignApplicationToLocationRequest": "applicationId", 12 | "createOrderRequest": "1sublocationId", 13 | "createOrderResponse": "2017-09-18T17:36:57.274Z{{location}}falseOrderId9101true{{subaccount}}RECEIVED", 14 | "orderResponseSuccess": "1lorem2017-09-18T17:36:57.411Z2017-09-18T17:36:57.410Z2017-09-18T17:36:57.274Z{{location}}false9101true{{subaccount}}COMPLETE910239876691023987671 number ordered in (910)0", 15 | "orderResponseFail": "1lorem2017-09-18T17:36:57.411Z2017-09-18T17:36:57.410Z2017-09-18T17:36:57.274Z{{location}}false9101true{{subaccount}}FAILED1", 16 | "orderResponseWait": "1lorem2017-09-18T17:36:57.411Z2017-09-18T17:36:57.410Z2017-09-18T17:36:57.274Z{{location}}false9101true{{subaccount}}WAIT" 17 | } 18 | -------------------------------------------------------------------------------- /test/xml-test.js: -------------------------------------------------------------------------------- 1 | var BXMLResponse = require("../lib/xml.js"); 2 | var fs = require("fs"); 3 | var speakSentenceOnlyResponse = fs.readFileSync("./test/bxml-responses/speakSentence.xml", "utf8"); 4 | var gatherOnlyResponse = fs.readFileSync("./test/bxml-responses/gather.xml", "utf8"); 5 | var callOnlyResponse = fs.readFileSync("./test/bxml-responses/call.xml", "utf8"); 6 | var conferenceOnlyResponse = fs.readFileSync("./test/bxml-responses/conference.xml", "utf8"); 7 | var hangupOnlyResponse = fs.readFileSync("./test/bxml-responses/hangup.xml", "utf8"); 8 | var audioOnlyResponse = fs.readFileSync("./test/bxml-responses/playAudio.xml", "utf8"); 9 | var recordOnlyResponse = fs.readFileSync("./test/bxml-responses/record.xml", "utf8"); 10 | var redirectOnlyResponse = fs.readFileSync("./test/bxml-responses/redirect.xml", "utf8"); 11 | var sendMessageOnlyResponse = fs.readFileSync("./test/bxml-responses/sendMessage.xml", "utf8"); 12 | var transferOnlyResponse = fs.readFileSync("./test/bxml-responses/transfer.xml", "utf8"); 13 | var nestingResponse = fs.readFileSync("./test/bxml-responses/nesting.xml", "utf8"); 14 | var chainingResponse = fs.readFileSync("./test/bxml-responses/chaining.xml", "utf8"); 15 | var multiTransferResponse = fs.readFileSync("./test/bxml-responses/multiTransfer.xml", "utf8"); 16 | var pauseResponse = fs.readFileSync("./test/bxml-responses/pause.xml", "utf8"); 17 | var dtmfResponse = fs.readFileSync("./test/bxml-responses/sendDtmf.xml", "utf8"); 18 | 19 | describe("Builder", function () { 20 | 21 | describe("Individual verb - speakSentence", function () { 22 | var myApp; 23 | before(function () { 24 | myApp = new BXMLResponse(); 25 | myApp.speakSentence("Thank you for calling ACME Technical Support."); 26 | }); 27 | it("Should generate correct BXML", function () { 28 | myApp.toString().should.equal(speakSentenceOnlyResponse); 29 | }); 30 | }); 31 | describe("Individual verb - gather", function () { 32 | var myApp; 33 | before(function () { 34 | myApp = new BXMLResponse(); 35 | myApp.gather({ 36 | requestUrl : "http://www.example.com/" 37 | }); 38 | }); 39 | it("Should generate correct BXML", function () { 40 | myApp.toString().should.equal(gatherOnlyResponse); 41 | }); 42 | }); 43 | describe("Individual verb - call", function () { 44 | var myApp; 45 | before(function () { 46 | myApp = new BXMLResponse(); 47 | myApp.call({ 48 | from : "+19195551212", 49 | to : "+19195551213" 50 | }); 51 | }); 52 | it("Should generate correct BXML", function () { 53 | myApp.toString().should.equal(callOnlyResponse); 54 | }); 55 | }); 56 | describe("Individual verb - conference", function () { 57 | var myApp; 58 | before(function () { 59 | myApp = new BXMLResponse(); 60 | myApp.conference({ 61 | from : "+19195551212" 62 | }); 63 | }); 64 | it("Should generate correct BXML", function () { 65 | myApp.toString().should.equal(conferenceOnlyResponse); 66 | }); 67 | }); 68 | describe("Individual verb - hangup", function () { 69 | var myApp; 70 | before(function () { 71 | myApp = new BXMLResponse(); 72 | myApp.hangup({ }); 73 | }); 74 | it("Should generate correct BXML", function () { 75 | myApp.toString().should.equal(hangupOnlyResponse); 76 | }); 77 | }); 78 | describe("Individual verb - playAudio", function () { 79 | var myApp; 80 | before(function () { 81 | myApp = new BXMLResponse(); 82 | myApp.playAudio("http://www.example.com/example.mp3"); 83 | }); 84 | it("Should generate correct BXML", function () { 85 | myApp.toString().should.equal(audioOnlyResponse); 86 | }); 87 | }); 88 | describe("Individual verb - record", function () { 89 | var myApp; 90 | before(function () { 91 | myApp = new BXMLResponse(); 92 | myApp.record({ 93 | requestUrl : "http://www.example.com", 94 | requestUrlTimeout : 12345 95 | }); 96 | }); 97 | it("Should generate correct BXML", function () { 98 | myApp.toString().should.equal(recordOnlyResponse); 99 | }); 100 | }); 101 | describe("Individual verb - redirect", function () { 102 | var myApp; 103 | before(function () { 104 | myApp = new BXMLResponse(); 105 | myApp.redirect({ 106 | requestUrl : "http://www.example.com", 107 | requestUrlTimeout : 12345 108 | }); 109 | }); 110 | it("Should generate correct BXML", function () { 111 | myApp.toString().should.equal(redirectOnlyResponse); 112 | }); 113 | }); 114 | describe("Individual verb - sendMessage", function () { 115 | var myApp; 116 | before(function () { 117 | myApp = new BXMLResponse(); 118 | myApp.sendMessage("Where are you?", { 119 | from : "+19195551212", 120 | to : "+19195551213" 121 | }); 122 | }); 123 | it("Should generate correct BXML", function () { 124 | myApp.toString().should.equal(sendMessageOnlyResponse); 125 | }); 126 | }); 127 | describe("Individual verb - transfer", function () { 128 | var myApp; 129 | before(function () { 130 | myApp = new BXMLResponse(); 131 | myApp.transfer({ 132 | transferTo : "+19195551212" 133 | }); 134 | }); 135 | it("Should generate correct BXML", function () { 136 | myApp.toString().should.equal(transferOnlyResponse); 137 | }); 138 | }); 139 | describe("Individual verb - pause", function () { 140 | var myApp; 141 | before(function () { 142 | myApp = new BXMLResponse(); 143 | myApp.pause({ 144 | length : 5 145 | }); 146 | }); 147 | it("Should generate correct BXML", function () { 148 | myApp.toString().should.equal(pauseResponse.trim()); 149 | }); 150 | }); 151 | describe("Individual verb - sendDtmf", function () { 152 | var myApp; 153 | before(function () { 154 | myApp = new BXMLResponse(); 155 | myApp.sendDtmf("5"); 156 | }); 157 | it("Should generate correct BXML", function () { 158 | myApp.toString().should.equal(dtmfResponse.trim()); 159 | }); 160 | }); 161 | describe("Nesting", function () { 162 | var myApp; 163 | before(function () { 164 | myApp = new BXMLResponse(); 165 | myApp.gather({ 166 | requestUrl : "http://www.example.com/" 167 | }, function () { 168 | this.speakSentence("Press some numbers!"); 169 | }); 170 | }); 171 | it("Should generate correct BXML", function () { 172 | myApp.toString().should.equal(nestingResponse); 173 | }); 174 | }); 175 | describe("Chaining", function () { 176 | var myApp; 177 | before(function () { 178 | myApp = new BXMLResponse(); 179 | myApp.speakSentence("Hi! My name is:") 180 | .speakSentence("What? My name is:"); 181 | }); 182 | it("Should generate correct BXML", function () { 183 | myApp.toString().should.equal(chainingResponse); 184 | }); 185 | }); 186 | describe("Multiple Transfer with Speak Sentence", function () { 187 | var myApp; 188 | before(function () { 189 | myApp = new BXMLResponse(); 190 | myApp.speakSentence("Your call is somewhat important to us.") 191 | .speakSentence("Please wait while it is being transferred.") 192 | .transfer({}, function () { 193 | this.phoneNumber("transferOne"); 194 | this.phoneNumber("transferTwo"); 195 | this.phoneNumber("transferThree"); 196 | this.speakSentence("A call is being transferred to you from Customer Service."); 197 | }); 198 | }); 199 | it("Should generate correct BXML", function () { 200 | myApp.toString().should.equal(multiTransferResponse); 201 | }); 202 | }); 203 | }); 204 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | import { V2MessageAPI } from './v2'; 2 | import { 3 | AreaCodeSearchAndOrderNumbersQuery, 4 | RateCenterSearchAndOrderNumbersQuery, 5 | NpaNxxSearchAndOrderNumbersQuery, 6 | TollFreeVanitySearchAndOrderNumbersQuery, 7 | TollFreeWildCharSearchAndOrderNumbersQuery, 8 | StateSearchAndOrderNumbersQuery, 9 | CitySearchAndOrderNumbersQuery, 10 | ZipSearchAndOrderNumbersQuery, 11 | LataSearchAndOrderNumbersQuery, 12 | CombinedSearchAndOrderNumbersQuery, 13 | } from './v2/searchAndOrderNumberQueries'; 14 | 15 | export interface BandwidthOptions { 16 | userId : string; 17 | apiToken : string; 18 | apiSecret: string; 19 | baseUrl?: string; 20 | } 21 | 22 | export interface v2 { 23 | Message: V2MessageAPI; 24 | } 25 | 26 | export default class Bandwidth { 27 | constructor(options: BandwidthOptions); 28 | public v2: v2; 29 | public static AreaCodeSearchAndOrderNumbersQuery: typeof AreaCodeSearchAndOrderNumbersQuery; 30 | public static RateCenterSearchAndOrderNumbersQuery: typeof RateCenterSearchAndOrderNumbersQuery; 31 | public static NpaNxxSearchAndOrderNumbersQuery: typeof NpaNxxSearchAndOrderNumbersQuery; 32 | public static TollFreeVanitySearchAndOrderNumbersQuery: typeof TollFreeVanitySearchAndOrderNumbersQuery; 33 | public static TollFreeWildCharSearchAndOrderNumbersQuery: typeof TollFreeWildCharSearchAndOrderNumbersQuery; 34 | public static StateSearchAndOrderNumbersQuery: typeof StateSearchAndOrderNumbersQuery; 35 | public static CitySearchAndOrderNumbersQuery: typeof CitySearchAndOrderNumbersQuery; 36 | public static ZipSearchAndOrderNumbersQuery: typeof ZipSearchAndOrderNumbersQuery; 37 | public static LataSearchAndOrderNumbersQuery: typeof LataSearchAndOrderNumbersQuery; 38 | public static CombinedSearchAndOrderNumbersQuery: typeof CombinedSearchAndOrderNumbersQuery; 39 | } 40 | -------------------------------------------------------------------------------- /types/v2/index.d.ts: -------------------------------------------------------------------------------- 1 | import { NumbersQuery } from './v2/searchAndOrderNumberQueries'; 2 | 3 | export type MessageDirection = "out" | "in"; 4 | 5 | export interface V2MessageResponse { 6 | id: string; 7 | time: string; 8 | to: string[]; 9 | from: string; 10 | text: string; 11 | applicationId: string; 12 | tag: string; 13 | owner: string; 14 | direction: MessageDirection; 15 | segmentCount: number; 16 | } 17 | 18 | export interface V2ApplicationResponse { 19 | applicationId: string; 20 | locationId: string; 21 | } 22 | 23 | export interface V2SendOptions { 24 | applicationId: string; 25 | from: string; 26 | to: string | string[]; 27 | text: string; 28 | media?: string[]; 29 | tag?: string; 30 | } 31 | 32 | export interface V2SMSOptions { 33 | enabled: boolean; 34 | tollFreeEnabled: boolean; 35 | shortCodeEnabled: boolean; 36 | } 37 | 38 | export interface V2MMSOptions { 39 | enabled: boolean; 40 | } 41 | 42 | export interface V2CallbackAuthData { 43 | userName: string; 44 | password: string; 45 | } 46 | 47 | export interface V2CreateMessagingApplicationOptions { 48 | name: string; 49 | callbackUrl: string; 50 | callbackAuthData: V2CallbackAuthData; 51 | locationName: string; 52 | isDefaultLocation: boolean; 53 | smsOptions: V2SMSOptions; 54 | mmsOptions: V2MMSOptions; 55 | } 56 | 57 | export interface V2SearchAndOrderNumbersOptions { 58 | 59 | } 60 | 61 | export interface V2AuthData { 62 | accountId: string; 63 | userName: string; 64 | password: string; 65 | subaccountId: string; 66 | } 67 | 68 | export interface V2MessageAPI { 69 | createMessagingApplication: (auth: V2AuthData, opts: V2CreateMessagingApplicationOptions) => Promise 70 | searchAndOrderNumbers: (auth: V2AuthData, app: V2ApplciationResponse, opts: NumbersQuery) => Promise; 71 | send: (opts: V2SendOptions) => Promise; 72 | } 73 | -------------------------------------------------------------------------------- /types/v2/searchAndOrderNumberQueries.d.ts: -------------------------------------------------------------------------------- 1 | 2 | export interface IAreaCodeSearchAndOrderNumbersQuery { 3 | areaCode: string; 4 | quantity: number; 5 | } 6 | 7 | export class AreaCodeSearchAndOrderNumbersQuery { 8 | constructor(options: IAreaCodeSearchAndOrderNumbersQuery); 9 | toXml(): object; 10 | } 11 | 12 | export interface IRateCenterSearchAndOrderNumbersQuery { 13 | rateCenter: string; 14 | state: string; 15 | quantity: number 16 | } 17 | 18 | export class RateCenterSearchAndOrderNumbersQuery { 19 | constructor(options: IRateCenterSearchAndOrderNumbersQuery); 20 | toXml(): object; 21 | } 22 | 23 | export interface INpaNxxSearchAndOrderNumbersQuery { 24 | npaNxx: string; 25 | enableTnDetail: boolean; 26 | enableLca: boolean; 27 | quantity: number; 28 | } 29 | 30 | export class NpaNxxSearchAndOrderNumbersQuery { 31 | constructor(options: INpaNxxSearchAndOrderNumbersQuery); 32 | toXml(): object; 33 | } 34 | 35 | export interface ITollFreeVanitySearchAndOrderNumbersQuery { 36 | tollFreeVanity: string; 37 | quantity: number; 38 | } 39 | 40 | export class TollFreeVanitySearchAndOrderNumbersQuery { 41 | constructor(options: ITollFreeVanitySearchAndOrderNumbersQuery); 42 | toXml(): object; 43 | } 44 | 45 | export interface ITollFreeWildCharSearchAndOrderNumbersQuery { 46 | tollFreeWildCardPattern: string; 47 | quantity: number 48 | } 49 | 50 | export class TollFreeWildCharSearchAndOrderNumbersQuery { 51 | constructor(options: ITollFreeWildCharSearchAndOrderNumbersQuery); 52 | toXml(): object; 53 | } 54 | 55 | export interface IStateSearchAndOrderNumbersQuery { 56 | state: string; 57 | quantity: number; 58 | } 59 | 60 | export class StateSearchAndOrderNumbersQuery { 61 | constructor(options: IStateSearchAndOrderNumbersQuery); 62 | toXml(): object; 63 | } 64 | 65 | export interface ICitySearchAndOrderNumbersQuery { 66 | state: string; 67 | city: string; 68 | quantity: number; 69 | } 70 | 71 | export class CitySearchAndOrderNumbersQuery { 72 | constructor(options: ICitySearchAndOrderNumbersQuery); 73 | toXml(): object; 74 | } 75 | 76 | export interface IZipSearchAndOrderNumbersQuery { 77 | zip: string; 78 | quantity: number; 79 | } 80 | 81 | export class ZipSearchAndOrderNumbersQuery { 82 | constructor(options: IZipSearchAndOrderNumbersQuery); 83 | toXml(): object; 84 | } 85 | 86 | export interface ILataSearchAndOrderNumbersQuery { 87 | lata: string; 88 | quantity: number; 89 | } 90 | 91 | export class LataSearchAndOrderNumbersQuery { 92 | constructor(options: ILataSearchAndOrderNumbersQuery); 93 | toXml(): object; 94 | } 95 | 96 | export interface ICombinedSearchAndOrderNumbersQuery { 97 | quantity: number; 98 | areaCode: string; 99 | rateCenter: string; 100 | npaNxx: string; 101 | enableTnDetail: boolean; 102 | enableLca: boolean; 103 | tollFreeVanity: string; 104 | tollFreeWildCardPattern: string; 105 | state: string; 106 | city: string; 107 | zip: string; 108 | lata: string; 109 | } 110 | 111 | export class CombinedSearchAndOrderNumbersQuery { 112 | constructor(options: ICombinedSearchAndOrderNumbersQuery); 113 | toXml(): object; 114 | } 115 | 116 | export type NumbersQuery = AreaCodeSearchAndOrderNumbersQuery | RateCenterSearchAndOrderNumbersQuery | NpaNxxSearchAndOrderNumbersQuery | TollFreeVanitySearchAndOrderNumbersQuery | TollFreeWildCharSearchAndOrderNumbersQuery | StateSearchAndOrderNumbersQuery | CitySearchAndOrderNumbersQuery | ZipSearchAndOrderNumbersQuery | LataSearchAndOrderNumbersQuery | CombinedSearchAndOrderNumbersQuery; 117 | --------------------------------------------------------------------------------