Socket
Socket
Sign inDemoInstall

leankit-client

Package Overview
Dependencies
47
Maintainers
1
Versions
29
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 2.0.2 to 2.1.0

repl.js

3

.eslintrc.js
module.exports = {
extends: [ "leankit", "leankit/es6" ],
parserOptions: {
ecmaVersion: 2017
},
rules: {

@@ -4,0 +7,0 @@ "no-unused-expressions": 2,

3

package.json

@@ -17,3 +17,3 @@ {

"license": "SEE LICENSE IN https://github.com/LeanKit/leankit-node-client/blob/master/LICENSE",
"version": "2.0.2",
"version": "2.1.0",
"homepage": "https://github.com/LeanKit/leankit-node-client/",

@@ -53,2 +53,3 @@ "bugs": {

"test": "mocha -r ./spec/setup --reporter spec ./spec/*.spec.js",
"test:watch": "npm run test -- -w",
"scratch-tests": "npm run lint && node ./scratch"

@@ -55,0 +56,0 @@ },

@@ -26,3 +26,3 @@ ## LeanKit API Client for Node.js

account: "account-name", // change these properties to match your account
email: "your@email.com",
email: "your@email.com", // for token auth, see below
password: "your-p@ssw0rd"

@@ -39,2 +39,19 @@ };

### Authentication
The LeanKit API Client supports both "Basic" and "Bearer" authentication.
* provide a valid email and password for basic authentication
* provide a valid token to use bearer authentication
For most production uses, it's recommended that you use token authentication so that you don't need to worry about protecting your password. See the API section [Auth Tokens](#auth-tokens) for information on how to create and manage auth tokens.
Using a token is simple:
```javascript
const auth = {
account: "account-name",
token: "2a0ec41e4fca6a10727a33je4f409545870c0ce199fd8cde287a027acdf671d73da3f5af1ee983441d1993dc3a2181302690885c0b46692e39b6c9e29bd132eb"
}
const client = LeanKitClient( auth );
```
### Support for JavaScript Promises, and `async`/`await`

@@ -41,0 +58,0 @@

const utils = require( "../src/utils" );
describe( "utils tests", () => {
it( "should turn an account name into a LeanKit URL", done => {
const url = utils.buildUrl( "test" );
url.should.equal( "https://test.leankit.com/" );
done();
} );
describe( "buildUrl", () => {
it( "should turn an account name into a LeanKit URL", done => {
const url = utils.buildUrl( "test" );
url.should.equal( "https://test.leankit.com/" );
done();
} );
it( "should preserve given URL", done => {
const url = utils.buildUrl( "http://test.com" );
url.should.equal( "http://test.com/" );
done();
it( "should preserve given URL", done => {
const url = utils.buildUrl( "http://test.com" );
url.should.equal( "http://test.com/" );
done();
} );
});
describe( "buildDefaultConfig", ()=> {
let result;
describe( "when providing account and token", ()=> {
before(() => {
result = utils.buildDefaultConfig( "bob", "1234" );
});
it( "should have expanded url", ()=> {
result.baseUrl.should.equal( "https://bob.leankit.com/" );
} );
it( "should use bearer token auth with specified token", ()=> {
result.auth.should.eql( { bearer: "1234" } );
} );
it( "should have default headers", ()=> {
result.headers.should.eql({
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": utils.getUserAgent()
} );
} );
} );
describe( "when providing email and password", () => {
before(() => {
result = utils.buildDefaultConfig( "bob", null, "wcoyote@acme.com", "rr!#@" );
});
it( "should use provided credentials", ()=> {
result.auth.should.eql({
username: "wcoyote@acme.com",
password: "rr!#@"
});
} );
})
describe( "when providing token plus email and password", () => {
before(() => {
result = utils.buildDefaultConfig( "bob", "1234", "wcoyote@acme.com", "rr!#@" );
});
it( "should use bearer token auth with specified token", ()=> {
result.auth.should.eql( { bearer: "1234" } );
} );
})
describe( "when providing header values in config", ()=> {
it( "should force values for Accept, Content-Type, and User-Agent", ()=> {
let invalidHeaders = {
Accept: "anything",
"Content-Type": "text/css",
"User-Agent": "Mozilla/5.0"
}
result = utils.buildDefaultConfig( "bob", "1234", null, null, { config: { headers: invalidHeaders } } );
result.headers.should.eql({
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": utils.getUserAgent()
} );
} );
} );
describe( "when providing other header values in config", ()=> {
it( "should include the header values", ()=> {
let headers = {
CustomHeader:"beardzrock"
};
result = utils.buildDefaultConfig( "bob", "1234", null, null, { headers } );
result.headers.should.eql({
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": utils.getUserAgent(),
CustomHeader: "beardzrock"
} );
} );
} );
describe( "when providing a proxy value", ()=> {
it( "should include the proxy", ()=> {
let config = {
proxy:{
}
}
result = utils.buildDefaultConfig( "bob", "1234", null, null, config );
result.proxy.should.eql({});
} );
} );
} );
} );

@@ -6,76 +6,33 @@ /* eslint-disable max-lines */

const v1ApiFactory = require( "./api.v1" );
const STATUS_200 = 200;
const STATUS_201 = 201;
const legacy = require( "./legacy" );
const buildDefaultConfig = ( account, email, password, config ) => {
config = config || { headers: {} };
if ( !config.headers ) {
config.headers = {};
const rejectError = ( err, res, body, reject ) => {
const message = res ? res.statusMessage : err.message;
const reqErr = new Error( message );
if ( err ) {
reqErr.stack = err.stack;
}
const userAgent = utils.getPropertyValue( config.headers, "User-Agent", utils.getUserAgent() );
utils.removeProperties( config.headers, [ "User-Agent", "Content-Type", "Accept" ] );
const proxy = config.proxy || null;
const defaultHeaders = {
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": userAgent
};
const headers = Object.assign( {}, config.headers, defaultHeaders );
const defaults = {
auth: {
username: email,
password
},
baseUrl: utils.buildUrl( account ),
headers
};
if ( proxy ) {
defaults.proxy = proxy;
if ( res ) {
reqErr.status = res.statusCode;
reqErr.statusText = res.statusMessage;
}
return defaults;
if ( body ) {
try {
reqErr.data = JSON.parse( body );
} catch ( e ) {
reqErr.data = body;
}
}
return reject( reqErr );
};
const Client = ( { account, email, password, config } ) => {
const defaults = buildDefaultConfig( account, email, password, config );
const Client = ( { account, token, email, password, config } ) => {
const defaults = utils.buildDefaultConfig( account, token, email, password, config );
const legacyHandler = legacy( req, defaults );
const streamResponse = ( request, cfg, stream ) => {
return new Promise( ( resolve, reject ) => {
const response = {};
request( cfg )
.on( "error", err => {
return reject( err );
} )
.on( "response", res => {
response.status = res.statusCode;
response.statusText = res.statusMessage;
response.data = "";
} )
.on( "end", () => {
if ( response.status < 200 || response.status >= 300 ) { // eslint-disable-line no-magic-numbers
return reject( response );
}
return resolve( response );
} )
.pipe( stream );
} );
};
const request = ( options, stream = null ) => {
if ( options.headers ) {
options.headers.Accept = defaults.headers.Accept;
options.headers[ "User-Agent" ] = defaults.headers[ "User-Agent" ];
}
const cfg = Object.assign( {}, defaults, options );
if ( cfg.data ) {
if ( cfg.headers[ "Content-Type" ] === "application/json" ) {
cfg.body = JSON.stringify( cfg.data );
} else {
cfg.body = cfg.data;
}
delete cfg.data;
}
const cfg = utils.mergeOptions( options, defaults );
if ( stream ) {
return streamResponse( req, cfg, stream );
return utils.streamResponse( req, cfg, stream );
}

@@ -85,21 +42,4 @@

req( cfg, ( err, res, body ) => {
if ( err || res.statusCode < 200 || res.statusCode >= 300 ) { // eslint-disable-line no-magic-numbers
const message = res ? res.statusMessage : err.message;
const reqErr = new Error( message );
if ( err ) {
reqErr.stack = err.stack;
}
if ( res ) {
reqErr.status = res.statusCode;
reqErr.statusText = res.statusMessage;
// reqErr.headers = res.headers;
}
if ( body ) {
try {
reqErr.data = JSON.parse( body );
} catch ( e ) {
reqErr.data = body;
}
}
return reject( reqErr );
if ( err || res.statusCode < utils.status.status200 || res.statusCode >= utils.status.status300 ) {
return rejectError( err, res, body, reject );
}

@@ -124,72 +64,5 @@

const parseReplyData = ( error, response, body, resolve, reject ) => { // eslint-disable-line max-statements
const parsed = utils.parseBody( body );
if ( error ) {
const message = response ? response.statusMessage : error.message;
const reqErr = new Error( message );
reqErr.stack = error.stack;
if ( response ) {
reqErr.status = response.statusCode;
reqErr.statusText = response.statusMessage;
}
reqErr.data = parsed;
return reject( reqErr );
}
if ( response.statusCode !== STATUS_200 ) {
const err = new Error( response.statusText );
err.name = "clientRequestError";
err.replyCode = response.statusCode;
err.data = parsed;
return reject( err );
}
if ( parsed && parsed.ReplyCode && parsed.ReplyCode >= 300 ) { // eslint-disable-line no-magic-numbers
const err = new Error( parsed.ReplyText || "apiError" );
err.name = "apiError";
err.httpStatusCode = parsed.ReplyCode;
err.replyCode = parsed.ReplyCode;
err.replyText = parsed.ReplyText;
err.replyData = parsed.ReplyData;
return reject( err );
}
if ( parsed && parsed.ReplyCode && parsed.ReplyCode !== STATUS_200 && parsed.ReplyCode !== STATUS_201 ) {
return resolve( parsed );
}
if ( parsed.ReplyData && parsed.ReplyData.length > 0 ) {
return resolve( {
status: parsed.ReplyCode,
statusText: parsed.ReplyText,
data: parsed.ReplyData[ 0 ]
} );
}
return resolve( parsed );
};
const legacyRequest = ( options, stream = null ) => {
options.url = utils.checkLegacyPath( options.url );
if ( options.headers ) {
options.headers.Accept = defaults.headers.Accept;
options.headers[ "User-Agent" ] = defaults.headers[ "User-Agent" ];
}
const cfg = Object.assign( {}, defaults, options );
if ( cfg.data ) {
if ( cfg.headers[ "Content-Type" ] === "application/json" ) {
cfg.body = JSON.stringify( cfg.data );
} else {
cfg.body = cfg.data;
}
delete cfg.data;
}
if ( stream ) {
return streamResponse( req, cfg, stream );
}
return new Promise( ( resolve, reject ) => {
req( cfg, ( err, res, body ) => {
return parseReplyData( err, res, body, resolve, reject );
} );
} );
};
const api = {};
apiFactory( api, request, { accountName: account, email, password } );
v1ApiFactory( api, legacyRequest, { accountName: account, email, password } );
v1ApiFactory( api, legacyHandler.request, { accountName: account, email, password } );
return api;

@@ -196,0 +69,0 @@ };

@@ -1,3 +0,3 @@

const fs = require( "fs" );
const path = require( "path" );
/* eslint-disable max-lines */
const pkg = require( "../package.json" );

@@ -22,11 +22,5 @@ const buildUrl = account => {

const getUserAgent = () => {
const pkgfilepath = path.resolve( __dirname, "../", "package.json" );
if ( fs.existsSync( pkgfilepath ) ) {
const pkg = JSON.parse( fs.readFileSync( pkgfilepath, "utf-8" ) );
return `leankit-node-client/${ pkg.version }`;
}
return "leankit-node-client/2.0.0";
return `leankit-node-client/${ pkg.version }`;
};
const getPropertyValue = ( obj, prop, def = null ) => {

@@ -41,2 +35,3 @@ for ( const k in obj ) {

const removeProperties = ( obj, props ) => {

@@ -52,2 +47,29 @@ for ( let i = 0; i < props.length; i++ ) {

const buildDefaultConfig = ( account, token, email, password, config ) => {
config = config || { headers: {} };
if ( !config.headers ) {
config.headers = {};
}
const userAgent = getPropertyValue( config.headers, "User-Agent", getUserAgent() );
removeProperties( config.headers, [ "User-Agent", "Content-Type", "Accept" ] );
const proxy = config.proxy || null;
const defaultHeaders = {
Accept: "application/json",
"Content-Type": "application/json",
"User-Agent": userAgent
};
const headers = Object.assign( {}, config.headers, defaultHeaders );
const auth = token ? { bearer: token } : { username: email, password };
const defaults = {
auth,
baseUrl: buildUrl( account ),
headers
};
if ( proxy ) {
defaults.proxy = proxy;
}
return defaults;
};
const checkLegacyPath = urlPath => {

@@ -57,2 +79,19 @@ return ( urlPath.startsWith( "api/" ) ) ? urlPath : `kanban/api/${ urlPath }`;

const mergeOptions = ( options, defaults ) => {
if ( options.headers ) {
options.headers.Accept = defaults.headers.Accept;
options.headers[ "User-Agent" ] = defaults.headers[ "User-Agent" ];
}
const config = Object.assign( {}, defaults, options );
if ( config.data ) {
if ( config.headers[ "Content-Type" ] === "application/json" ) {
config.body = JSON.stringify( config.data );
} else {
config.body = config.data;
}
delete config.data;
}
return config;
};
const parseBody = body => {

@@ -72,4 +111,33 @@ let parsed;

const streamResponse = ( request, cfg, stream ) => {
return new Promise( ( resolve, reject ) => {
const response = {};
request( cfg )
.on( "error", err => {
return reject( err );
} )
.on( "response", res => {
response.status = res.statusCode;
response.statusText = res.statusMessage;
response.data = "";
} )
.on( "end", () => {
if ( response.status < 200 || response.status >= 300 ) { // eslint-disable-line no-magic-numbers
return reject( response );
}
return resolve( response );
} )
.pipe( stream );
} );
};
const status = {
status200: 200,
status201: 201,
status300: 300
};
module.exports = {
buildUrl,
buildDefaultConfig,
getUserAgent,

@@ -79,3 +147,6 @@ getPropertyValue,

checkLegacyPath,
parseBody
parseBody,
streamResponse,
mergeOptions,
status
};
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc