ibm-cloud-sdk-core
Advanced tools
Comparing version 0.0.2 to 0.0.3
@@ -0,1 +1,16 @@ | ||
/** | ||
* Copyright 2015 IBM Corp. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
export declare type Options = { | ||
@@ -62,3 +77,3 @@ iamApikey?: string; | ||
*/ | ||
private requestToken(cb); | ||
private requestToken; | ||
/** | ||
@@ -70,3 +85,3 @@ * Refresh an IAM token using a refresh token. | ||
*/ | ||
private refreshToken(cb); | ||
private refreshToken; | ||
/** | ||
@@ -83,3 +98,3 @@ * Check if currently stored token is expired. | ||
*/ | ||
private isTokenExpired(); | ||
private isTokenExpired; | ||
/** | ||
@@ -94,3 +109,3 @@ * Used as a fail-safe to prevent the condition of a refresh token expiring, | ||
*/ | ||
private isRefreshTokenExpired(); | ||
private isRefreshTokenExpired; | ||
/** | ||
@@ -103,3 +118,3 @@ * Save the response from the IAM service request to the object's state. | ||
*/ | ||
private saveTokenInfo(tokenResponse); | ||
private saveTokenInfo; | ||
} |
@@ -20,2 +20,3 @@ /** | ||
export { BaseService } from './lib/base_service'; | ||
export { IamTokenManagerV1 } from './iam-token-manager/v1'; | ||
export * from './lib/helper'; | ||
@@ -22,0 +23,0 @@ export { default as qs } from './lib/querystring'; |
@@ -26,2 +26,4 @@ "use strict"; | ||
exports.BaseService = base_service_1.BaseService; | ||
var v1_1 = require("./iam-token-manager/v1"); | ||
exports.IamTokenManagerV1 = v1_1.IamTokenManagerV1; | ||
__export(require("./lib/helper")); | ||
@@ -28,0 +30,0 @@ var querystring_1 = require("./lib/querystring"); |
@@ -0,1 +1,17 @@ | ||
/** | ||
* Copyright 2014 IBM Corp. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
import request = require('request'); | ||
export interface HeaderOptions { | ||
@@ -10,2 +26,3 @@ 'X-Watson-Learning-Opt-Out'?: boolean; | ||
password?: string; | ||
api_key?: string; | ||
apikey?: string; | ||
@@ -23,2 +40,3 @@ use_unauthenticated?: boolean; | ||
url: string; | ||
jar?: request.CookieJar; | ||
qs: any; | ||
@@ -30,2 +48,3 @@ rejectUnauthorized?: boolean; | ||
password?: string; | ||
api_key?: string; | ||
url?: string; | ||
@@ -66,3 +85,3 @@ iam_access_token?: string; | ||
*/ | ||
getServiceCredentials(): Credentials; | ||
getCredentials(): Credentials; | ||
/** | ||
@@ -106,3 +125,3 @@ * Set an IAM access token to use when authenticating with the service. | ||
*/ | ||
private initCredentials(options); | ||
private initCredentials; | ||
/** | ||
@@ -120,3 +139,3 @@ * Pulls credentials from env properties | ||
*/ | ||
private getCredentialsFromEnvironment(envObj, name); | ||
private getCredentialsFromEnvironment; | ||
/** | ||
@@ -128,3 +147,3 @@ * Pulls credentials from VCAP_SERVICES env property that bluemix sets | ||
*/ | ||
private getCredentialsFromBluemix(vcapServicesName); | ||
private getCredentialsFromBluemix; | ||
} |
@@ -22,2 +22,3 @@ "use strict"; | ||
var extend = require("extend"); | ||
var request = require("request"); | ||
var semver = require("semver"); | ||
@@ -32,2 +33,3 @@ var vcapServices = require("vcap_services"); | ||
((obj.username && obj.password) || | ||
obj.api_key || | ||
obj.iam_access_token || | ||
@@ -101,2 +103,7 @@ obj.iam_apikey)); | ||
var _options = this.initCredentials(options); | ||
// If url is not specified, visual recognition requires gateway-a for CF instances | ||
// https://github.ibm.com/Watson/developer-experience/issues/4589 | ||
if (_options && this.name === 'watson_vision_combined' && !_options.url && _options.api_key && !_options.iam_apikey) { | ||
_options.url = 'https://gateway-a.watsonplatform.net/visual-recognition/api'; | ||
} | ||
if (options.url) { | ||
@@ -134,3 +141,3 @@ _options.url = helper_1.stripTrailingSlash(options.url); | ||
*/ | ||
BaseService.prototype.getServiceCredentials = function () { | ||
BaseService.prototype.getCredentials = function () { | ||
var credentials = {}; | ||
@@ -143,2 +150,5 @@ if (this._options.username) { | ||
} | ||
if (this._options.api_key) { | ||
credentials.api_key = this._options.api_key; | ||
} | ||
if (this._options.url) { | ||
@@ -239,2 +249,6 @@ credentials.url = this._options.url; | ||
} | ||
if (options.api_key || options.apikey) { | ||
_options.api_key = options.api_key || options.apikey; | ||
} | ||
_options.jar = request.jar(); | ||
// Get credentials from environment properties or Bluemix, | ||
@@ -247,4 +261,4 @@ // but prefer credentials provided programatically | ||
'constructor argument. Refer to the documentation for the ' + | ||
'required parameters. Common examples are username/password and ' + | ||
'iam_access_token.'; | ||
'required parameters. Common examples are username/password, ' + | ||
'api_key, and iam_access_token.'; | ||
throw new Error(errorMessage); | ||
@@ -267,2 +281,5 @@ } | ||
} | ||
else { | ||
_options.qs = extend({ api_key: _options.api_key }, _options.qs); | ||
} | ||
} | ||
@@ -310,2 +327,3 @@ } | ||
password: password, | ||
api_key: apiKey, | ||
url: url, | ||
@@ -312,0 +330,0 @@ iam_access_token: iamAccessToken, |
@@ -0,1 +1,16 @@ | ||
/** | ||
* Copyright 2014 IBM Corp. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
/// <reference types="node" /> | ||
@@ -40,3 +55,3 @@ export interface FileObject { | ||
[key: string]: any; | ||
}, requires: string[]): string[] | Error; | ||
}, requires: string[]): null | Error; | ||
/** | ||
@@ -43,0 +58,0 @@ * Return true if 'text' is html |
@@ -206,6 +206,6 @@ "use strict"; | ||
_obj = extend.apply(void 0, [{}].concat(Object.keys(obj).map(function (key) { | ||
var _a; | ||
return (_a = {}, | ||
_a[key.toLowerCase()] = obj[key], | ||
_a); | ||
var _a; | ||
}))); | ||
@@ -212,0 +212,0 @@ } |
/** | ||
* Format error returned by axios | ||
* Copyright 2014 IBM Corp. All Rights Reserved. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* http://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
import request = require('request'); | ||
/** | ||
* Check if the service/request have error and try to format them. | ||
* @param {Function} cb the request callback | ||
@@ -7,3 +23,3 @@ * @private | ||
*/ | ||
export declare function formatError(axiosError: any): any; | ||
export declare function formatErrorIfExists(cb: Function): request.RequestCallback; | ||
/** | ||
@@ -19,2 +35,2 @@ * Creates the request. | ||
*/ | ||
export declare function sendRequest(parameters: any, _callback: any): void; | ||
export declare function sendRequest(parameters: any, _callback: any): any; |
@@ -18,7 +18,5 @@ "use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var axios_1 = require("axios"); | ||
var extend = require("extend"); | ||
var FormData = require("form-data"); | ||
var https = require("https"); | ||
var querystring = require("querystring"); | ||
var request = require("request"); | ||
var stream_1 = require("stream"); | ||
var helper_1 = require("./helper"); | ||
@@ -45,22 +43,3 @@ // tslint:disable-next-line:no-var-requires | ||
/** | ||
* Determine if the error is due to bad credentials | ||
* @private | ||
* @param {Object} error - error object returned from axios | ||
* @returns {boolean} true if error is due to authentication | ||
*/ | ||
function isAuthenticationError(error) { | ||
var isAuthErr = false; | ||
var code = error.status; | ||
var body = error.data; | ||
// handle specific error from iam service, should be relevant across platforms | ||
var isIamServiceError = body.context && | ||
body.context.url && | ||
body.context.url.indexOf('iam') > -1; | ||
if (code === 401 || code === 403 || isIamServiceError) { | ||
isAuthErr = true; | ||
} | ||
return isAuthErr; | ||
} | ||
/** | ||
* Format error returned by axios | ||
* Check if the service/request have error and try to format them. | ||
* @param {Function} cb the request callback | ||
@@ -70,52 +49,85 @@ * @private | ||
*/ | ||
function formatError(axiosError) { | ||
// return an actual error object, | ||
// but make it flexible so we can add properties like 'body' | ||
var error = new Error(); | ||
// axios specific handling | ||
if (axiosError.response) { | ||
axiosError = axiosError.response; | ||
// The request was made and the server responded with a status code | ||
// that falls out of the range of 2xx | ||
delete axiosError.config; | ||
delete axiosError.request; | ||
error.name = axiosError.statusText; | ||
error.code = axiosError.status; | ||
error.message = axiosError.data.error && typeof axiosError.data.error === 'string' | ||
? axiosError.data.error | ||
: axiosError.statusText; | ||
// some services bury the useful error message within 'data' | ||
// adding it to the error under the key 'body' as a string or object | ||
var errorBody = void 0; | ||
function formatErrorIfExists(cb) { | ||
return function (error, response, body) { | ||
// eslint-disable-line complexity | ||
// If we have an error return it. | ||
if (error) { | ||
// first ensure that it's an instanceof Error | ||
if (!(error instanceof Error)) { | ||
body = error; | ||
error = new Error(error.message || error.error || error); | ||
error.body = body; | ||
} | ||
if (response && response.headers) { | ||
error[globalTransactionId] = response.headers[globalTransactionId]; | ||
} | ||
cb(error, body, response); | ||
return; | ||
} | ||
try { | ||
// try/catch to handle objects with circular references | ||
errorBody = JSON.stringify(axiosError.data); | ||
// in most cases, request will have already parsed the body as JSON | ||
body = JSON.parse(body); | ||
} | ||
catch (e) { | ||
// ignore the error, use the object, and tack on a warning | ||
errorBody = axiosError.data; | ||
errorBody.warning = 'body contains circular reference'; | ||
// if it fails, just return the body as-is | ||
} | ||
error.body = errorBody; | ||
// attach headers to error object | ||
error.headers = axiosError.headers; | ||
// print a more descriptive error message for auth issues | ||
if (isAuthenticationError(axiosError)) { | ||
error.message = 'Access is denied due to invalid credentials.'; | ||
// for api-key services | ||
if (response.statusMessage === 'invalid-api-key') { | ||
var error_1 = { | ||
error: response.statusMessage, | ||
code: response.statusMessage === 'invalid-api-key' ? 401 : 400, | ||
}; | ||
if (response.headers) { | ||
error_1[globalTransactionId] = response.headers[globalTransactionId]; | ||
} | ||
cb(error_1, null); | ||
return; | ||
} | ||
} | ||
else if (axiosError.request) { | ||
// The request was made but no response was received | ||
// `error.request` is an instance of XMLHttpRequest in the browser and an instance of | ||
// http.ClientRequest in node.js | ||
error.message = 'Response not received. Body of error is HTTP ClientRequest object'; | ||
error.body = axiosError.request; | ||
} | ||
else { | ||
// Something happened in setting up the request that triggered an Error | ||
error.message = axiosError.message; | ||
} | ||
return error; | ||
// If we have a response and it contains an error | ||
if (body && (body.error || body.error_code)) { | ||
// visual recognition sets body.error to a json object with code/description/error_id instead of putting them top-left | ||
if (typeof body.error === 'object' && body.error.description) { | ||
var errObj = body.error; // just in case there's a body.error.error... | ||
Object.keys(body.error).forEach(function (key) { | ||
body[key] = body.error[key]; | ||
}); | ||
Object.keys(body.error).forEach(function (key) { | ||
body[key] = body.error[key]; | ||
}); | ||
body.error = errObj.description; | ||
} | ||
else if (typeof body.error === 'object' && typeof body.error.error === 'object') { | ||
// this can happen with, for example, the conversation createSynonym() API | ||
body.rawError = body.error; | ||
body.error = JSON.stringify(body.error.error); // | ||
} | ||
// language translaton returns json with error_code and error_message | ||
error = new Error(body.error || body.error_message || 'Error Code: ' + body.error_code); | ||
error.code = body.error_code; | ||
Object.keys(body).forEach(function (key) { | ||
error[key] = body[key]; | ||
}); | ||
body = null; | ||
} | ||
// If we still don't have an error and there was an error... | ||
if (!error && (response.statusCode < 200 || response.statusCode >= 300)) { | ||
// The JSON stringify for the error below is for the Dialog service | ||
// It stringifies "[object Object]" into the correct error (PR #445) | ||
error = new Error(typeof body === 'object' ? JSON.stringify(body) : body); | ||
error.code = response.statusCode; | ||
body = null; | ||
} | ||
// ensure a more descriptive error message | ||
if (error && (error.code === 401 || error.code === 403)) { | ||
error.body = error.message; | ||
error.message = 'Unauthorized: Access is denied due to invalid credentials.'; | ||
} | ||
if (error && response && response.headers) { | ||
error[globalTransactionId] = response.headers[globalTransactionId]; | ||
} | ||
cb(error, body, response); | ||
return; | ||
}; | ||
} | ||
exports.formatError = formatError; | ||
exports.formatErrorIfExists = formatErrorIfExists; | ||
/** | ||
@@ -132,6 +144,23 @@ * Creates the request. | ||
function sendRequest(parameters, _callback) { | ||
var missingParams = null; | ||
var options = extend(true, {}, parameters.defaultOptions, parameters.options); | ||
var path = options.path, body = options.body, form = options.form, formData = options.formData, qs = options.qs, method = options.method, rejectUnauthorized = options.rejectUnauthorized; | ||
var url = options.url, headers = options.headers; | ||
var multipartForm = new FormData(); | ||
var path = options.path, body = options.body, form = options.form, formData = options.formData, qs = options.qs; | ||
// Missing parameters | ||
if (parameters.options.requiredParams) { | ||
// eslint-disable-next-line no-console | ||
console.warn(new Error('requiredParams set on parameters.options - it should be set directly on parameters')); | ||
} | ||
missingParams = helper_1.getMissingParams(parameters.originalParams || extend({}, qs, body, form, formData, path), parameters.requiredParams); | ||
if (missingParams) { | ||
if (typeof _callback === 'function') { | ||
return _callback(missingParams); | ||
} | ||
else { | ||
var errorStream_1 = new stream_1.PassThrough(); | ||
setTimeout(function () { | ||
errorStream_1.emit('error', missingParams); | ||
}, 0); | ||
return errorStream_1; | ||
} | ||
} | ||
// Form params | ||
@@ -144,86 +173,42 @@ if (formData) { | ||
Object.keys(formData).forEach(function (key) { | ||
if (formData[key] == null || | ||
// tslint:disable-next-line:no-unused-expression | ||
(formData[key] == null || | ||
helper_1.isEmptyObject(formData[key]) || | ||
(formData[key].hasOwnProperty('contentType') && !formData[key].hasOwnProperty('data'))) { | ||
(formData[key].hasOwnProperty('contentType') && !formData[key].hasOwnProperty('data'))) && | ||
delete formData[key]; | ||
} | ||
}); | ||
// Convert file form parameters to request-style objects | ||
Object.keys(formData).forEach(function (key) { | ||
if (formData[key].data != null) { | ||
formData[key] = helper_1.buildRequestFileObject(formData[key]); | ||
} | ||
}); | ||
Object.keys(formData).forEach(function (key) { return formData[key].data != null && (formData[key] = helper_1.buildRequestFileObject(formData[key])); }); | ||
// Stringify arrays | ||
Object.keys(formData).forEach(function (key) { | ||
if (Array.isArray(formData[key])) { | ||
formData[key] = formData[key].join(','); | ||
} | ||
}); | ||
Object.keys(formData).forEach(function (key) { return Array.isArray(formData[key]) && (formData[key] = formData[key].join(',')); }); | ||
// Convert non-file form parameters to strings | ||
Object.keys(formData).forEach(function (key) { | ||
if (!helper_1.isFileParam(formData[key]) && | ||
return !helper_1.isFileParam(formData[key]) && | ||
!Array.isArray(formData[key]) && | ||
typeof formData[key] === 'object') { | ||
typeof formData[key] === 'object' && | ||
(formData[key] = JSON.stringify(formData[key])); | ||
} | ||
}); | ||
// build multipart form data | ||
Object.keys(formData).forEach(function (key) { | ||
// handle files differently to maintain options | ||
if (formData[key].value) { | ||
multipartForm.append(key, formData[key].value, formData[key].options); | ||
} | ||
else { | ||
multipartForm.append(key, formData[key]); | ||
} | ||
}); | ||
} | ||
// Path params | ||
url = parsePath(url, path); | ||
options.url = parsePath(options.url, path); | ||
delete options.path; | ||
// Headers | ||
options.headers = extend({}, options.headers); | ||
// Convert array-valued query params to strings | ||
if (qs && Object.keys(qs).length > 0) { | ||
Object.keys(qs).forEach(function (key) { return Array.isArray(qs[key]) && (qs[key] = qs[key].join(',')); }); | ||
// Query params | ||
if (options.qs && Object.keys(options.qs).length > 0) { | ||
// dialog doesn't like qs params joined with a `,` | ||
if (!parameters.defaultOptions.url.match(/dialog\/api/)) { | ||
Object.keys(options.qs).forEach(function (key) { return Array.isArray(options.qs[key]) && (options.qs[key] = options.qs[key].join(',')); }); | ||
} | ||
options.useQuerystring = true; | ||
} | ||
// Add service default endpoint if options.url start with / | ||
if (url && url.charAt(0) === '/') { | ||
url = parameters.defaultOptions.url + url; | ||
if (options.url.charAt(0) === '/') { | ||
options.url = parameters.defaultOptions.url + options.url; | ||
} | ||
var data = body; | ||
if (form) { | ||
data = querystring.stringify(form); | ||
headers['Content-type'] = 'application/x-www-form-urlencoded'; | ||
} | ||
if (formData) { | ||
data = multipartForm; | ||
// form-data generates headers that MUST be included or the request will fail | ||
headers = extend(true, {}, headers, multipartForm.getHeaders()); | ||
} | ||
// accept gzip encoded responses if Accept-Encoding is not already set | ||
headers['Accept-Encoding'] = headers['Accept-Encoding'] || 'gzip'; | ||
var requestParams = { | ||
url: url, | ||
method: method, | ||
headers: headers, | ||
params: qs, | ||
data: data, | ||
responseType: options.responseType || 'json', | ||
paramsSerializer: function (params) { | ||
return querystring.stringify(params); | ||
}, | ||
// a custom httpsAgent is needed to support ICP | ||
httpsAgent: new https.Agent({ rejectUnauthorized: rejectUnauthorized }), | ||
}; | ||
axios_1.default(requestParams) | ||
.then(function (res) { | ||
// the other sdks use the interface `result` for the body | ||
_callback(null, res.data, res); | ||
}) | ||
.catch(function (error) { | ||
_callback(formatError(error)); | ||
}); | ||
// Compression support | ||
options.gzip = true; | ||
return request(options, formatErrorIfExists(_callback)); | ||
} | ||
exports.sendRequest = sendRequest; | ||
//# sourceMappingURL=requestwrapper.js.map |
{ | ||
"name": "ibm-cloud-sdk-core", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "Core functionality to support SDKs generated with IBM's OpenAPI 3 SDK Generator.", | ||
@@ -80,3 +80,4 @@ "main": "./index", | ||
"test-travis": "jest --silent --runInBand test/unit/", | ||
"report-coverage": "codecov" | ||
"report-coverage": "codecov", | ||
"prepare": "tsc" | ||
}, | ||
@@ -83,0 +84,0 @@ "jest": { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
110560
1648
0