diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 687789b0..cb3274f5 100755 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ Instructions for contributing to [plaid-node][1]. A node.js client library for t cp .env.example .env ``` -2. Go to the [Plaid Dashboard](https://dashboard.plaid.com/) and copy and paste your `client_id`, `public_key`, and sandbox `secret` +2. Go to the [Plaid Dashboard](https://dashboard.plaid.com/) and copy and paste your `client_id` and sandbox `secret` into `.env` using a text editor of your choice. 3. Install the necessary dependencies. @@ -24,14 +24,12 @@ Instructions for contributing to [plaid-node][1]. A node.js client library for t ```console $ SECRET=$PLAID_SECRET \ CLIENT_ID=$PLAID_CLIENT_ID \ -PUBLIC_KEY=$PLAID_PUBLIC_KEY \ make test # Running specific tests $ GREP='constructor|item|assets' \ SECRET=$PLAID_SECRET \ CLIENT_ID=$PLAID_CLIENT_ID \ -PUBLIC_KEY=$PLAID_PUBLIC_KEY \ make test ``` diff --git a/README.md b/README.md index 3a926a8d..20e0771b 100755 --- a/README.md +++ b/README.md @@ -28,13 +28,14 @@ $ npm install plaid You can specify the Plaid API version you wish to use when initializing `plaid-node`. Releases prior to `2.6.x` do not support versioning. ```javascript -const plaidClient = new plaid.Client( - process.env.PLAID_CLIENT_ID, - process.env.PLAID_SECRET, - process.env.PUBLIC_KEY, - plaid.environments.sandbox, - {version: '2019-05-29'} // '2019-05-29' | '2018-05-22' | '2017-03-08' -); +const plaidClient = new plaid.Client({ + clientID: process.env.PLAID_CLIENT_ID, + secret: process.env.PLAID_SECRET, + env: plaid.environments.sandbox, + options: { + version: '2019-05-29', // '2019-05-29' | '2018-05-22' | '2017-03-08' + }, +}); ``` For information about what has changed between versions and how to update your integration, head to the [API upgrade guide][api-upgrades]. @@ -45,13 +46,17 @@ For information about what has changed between versions and how to update your i The module supports all Plaid API endpoints. For complete information about the API, head to the [docs][2]. -All endpoints require a valid `client_id`, `secret`, and `public_key` to +All endpoints require a valid `client_id` and `secret` to access and are accessible from a valid instance of a Plaid `Client`: ```javascript const plaid = require('plaid'); -const plaidClient = new plaid.Client(client_id, secret, public_key, plaid_env, {version: '2019-05-29'}); +const plaidClient = new plaid.Client({ + clientID: client_id, + secret: secret, + env: plaid_env, +}); ``` The `plaid_env` parameter dictates which Plaid API environment you will access. Values are: @@ -59,12 +64,17 @@ The `plaid_env` parameter dictates which Plaid API environment you will access. - `plaid.environments.development` - use for integration development and testing, creates `Item`s on https://development.plaid.com - `plaid.environments.sandbox` - quickly build out your integration with stateful test data, creates `Item`s on https://sandbox.plaid.com -The `options` parameter is optional and allows for clients to override the default options used to make requests. e.g. +The `options` field is optional and allows for clients to override the default options used to make requests. e.g. ```javascript -const patientClient = new plaid.Client(client_id, secret, public_key, plaid_env, { - timeout: 30 * 60 * 1000, // 30 minutes - agent: 'Patient Agent' +const patientClient = new plaid.Client({ + clientID: client_id, + secret: secret, + env: plaid_env, + options: { + timeout: 30 * 60 * 1000, // 30 minutes + version: '2019-05-29', + } }); ``` @@ -78,7 +88,14 @@ Once an instance of the client has been created you use the following methods: const plaid = require('plaid'); // Initialize client -const plaidClient = new plaid.Client(client_id, secret, public_key, plaid_env, {version: '2018-05-22'}); +const plaidClient = new plaid.Client({ + clientID: client_id, + secret: secret, + env: plaid_env, + options: { + version: '2019-05-29', + }, +}); // createPublicToken(String, Function) plaidClient.createPublicToken(access_token, cb); @@ -264,13 +281,14 @@ const bodyParser = require('body-parser'); const express = require('express'); const plaid = require('plaid'); -const plaidClient = new plaid.Client( - process.env.PLAID_CLIENT_ID, - process.env.PLAID_SECRET, - process.env.PUBLIC_KEY, - plaid.environments.sandbox, - {version: '2018-05-22'} -); +const plaidClient = new plaid.Client({ + clientID: process.env.PLAID_CLIENT_ID, + secret: process.env.PLAID_SECRET, + env: plaid.environments.sandbox, + options: { + version: '2018-05-22', + }, +}); const app = express(); const port = process.env.PORT || 3000; diff --git a/index.d.ts b/index.d.ts index d0159d15..dec6bcd6 100644 --- a/index.d.ts +++ b/index.d.ts @@ -717,9 +717,17 @@ declare module 'plaid' { interface SandboxItemSetVerificationStatusResponse extends BaseResponse {} - interface ClientOptions extends AxiosRequestConfig { + interface ClientOptions { version?: '2019-05-29' | '2018-05-22' | '2017-03-08'; clientApp?: string; + timeout?: number; + } + + interface ClientConfigs extends AxiosRequestConfig { + clientID: string; + secret: string; + env: string, + options: ClientOptions, } type IdentityFieldBase = { @@ -749,13 +757,7 @@ declare module 'plaid' { } class Client { - constructor( - clientId: string, - secret: string, - publicKey: string, - env: string, - options?: ClientOptions, - ); + constructor(configs: ClientConfigs); exchangePublicToken(publicToken: string): Promise; exchangePublicToken( diff --git a/lib/PlaidClient.js b/lib/PlaidClient.js index 8590b963..ad41311a 100755 --- a/lib/PlaidClient.js +++ b/lib/PlaidClient.js @@ -12,35 +12,42 @@ var helpers = require('./_helpers'); const DEFAULT_VERSION = '2019-05-29'; // Client(String, String, String, String, Object?) -function Client(client_id, secret, public_key, env, options) { - if (R.isNil(client_id)) { +function Client(configs) { + if (!R.is(Object, configs)) { + throw new Error('Unexpected parameter type. ' + + 'Refer to https://github.com/plaid/plaid-node ' + + 'for how to create a Plaid client.'); + } + + if (R.isNil(configs.clientID)) { throw new Error('Missing Plaid "client_id"'); } - if (R.isNil(secret)) { + if (R.isNil(configs.secret)) { throw new Error('Missing Plaid "secret"'); } - if (R.isNil(public_key)) { - throw new Error('Missing Plaid "public_key"'); + if (!R.any(R.equals(configs.env), R.values(plaidEnvironments))) { + throw new Error('Invalid Plaid environment'); } - if (!R.any(R.equals(env), R.values(plaidEnvironments))) { - throw new Error('Invalid Plaid environment'); + if (arguments.length > 1) { + throw new Error('Too many arguments to constructor'); } - this.client_id = client_id; - this.secret = secret; - this.env = env; - this.public_key = public_key; + this.client_id = configs.clientID; + this.secret = configs.secret; + this.env = configs.env; - if (options == null) { - options = {}; + if (configs.options == null) { + configs.options = {}; } - if (options.version == null) { - options.version = DEFAULT_VERSION; + + if (configs.options.version == null) { + configs.options.version = DEFAULT_VERSION; } - this.client_request_opts = options; + + this.client_request_opts = configs.options; } // Private @@ -56,7 +63,7 @@ var requestWithAccessToken = function(path) { }; Client.prototype._authenticatedRequest = - function _authenticatedRequest(requestSpec, options, cb, withPublicKey) { + function _authenticatedRequest(requestSpec, options, cb) { // juggle arguments if (typeof options === 'function') { cb = options; @@ -65,13 +72,10 @@ Client.prototype._authenticatedRequest = requestSpec.body.options = options; } - var context = R.merge({env: this.env}, withPublicKey ? { - public_key: this.public_key, - } : { + var context = R.merge({env: this.env}, { client_id: this.client_id, secret: this.secret, - } - ); + }); return plaidRequest(context, requestSpec, this.client_request_opts, cb); }; @@ -514,7 +518,7 @@ Client.prototype.getInstitutionById = body: { institution_id: institution_id, } - }, options, cb, true); + }, options, cb); }; // searchInstitutionsByName(String, [String], Object?, Function) @@ -526,7 +530,7 @@ Client.prototype.searchInstitutionsByName = query: query, products: products, } - }, options, cb, true); + }, options, cb); }; // getCategories(Function) @@ -563,7 +567,7 @@ function(institution_id, initial_products, options, cb) { institution_id: institution_id, initial_products: initial_products, }, - }, options, cb, true); + }, options, cb); }; // sandboxItemFireWebhook(String, String, Function) - sandbox only diff --git a/package-lock.json b/package-lock.json index 4b10f870..0c1ba2c5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "plaid", - "version": "4.11.0", + "version": "5.1.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/test/PlaidClientTest.js b/test/PlaidClientTest.js index 80a4b57b..ebf7fa2b 100755 --- a/test/PlaidClientTest.js +++ b/test/PlaidClientTest.js @@ -14,25 +14,42 @@ const plaid = require('../'); const testConstants = require('./testConstants.js'); dotenv.config(); -const {SECRET, PUBLIC_KEY, CLIENT_ID} = process.env; +const {SECRET, CLIENT_ID} = process.env; describe('plaid.Client', () => { + const configs = { + clientID: CLIENT_ID, + secret: SECRET, + env: plaid.environments.sandbox, + options: { + version: '2019-05-29', + }, + }; let pCl; beforeEach(() => { - pCl = new plaid.Client( - CLIENT_ID, - SECRET, - PUBLIC_KEY, - plaid.environments.sandbox, - {version: '2019-05-29'} - ); + pCl = new plaid.Client(configs); }); describe('constructor', () => { + it('throws for invalid parameter', () => { + expect(() => { + plaid.Client('client_id'); + }).to.throwException(e => { + expect(e).to.be.ok(); + expect(e.message).to.equal( + 'Unexpected parameter type. Refer to ' + + 'https://github.com/plaid/plaid-node ' + + 'for how to create a Plaid client.' + ); + }); + }); + it('throws for missing client_id', () => { expect(() => { - plaid.Client(null, SECRET, PUBLIC_KEY, plaid.environments.sandbox); + plaid.Client(R.merge(configs, { + clientID: null, + })); }).to.throwException(e => { expect(e).to.be.ok(); expect(e.message).to.equal('Missing Plaid "client_id"'); @@ -41,35 +58,52 @@ describe('plaid.Client', () => { it('throws for missing secret', () => { expect(() => { - plaid.Client(CLIENT_ID, null, PUBLIC_KEY, plaid.environments.sandbox); + plaid.Client(R.merge(configs, { + secret: null, + })); }).to.throwException(e => { expect(e).to.be.ok(); expect(e.message).to.equal('Missing Plaid "secret"'); }); }); - it('throws for missing public_key', () => { + it('throws for invalid environment', () => { expect(() => { - plaid.Client(CLIENT_ID, SECRET, null, plaid.environments.sandbox); + plaid.Client(R.merge(configs, { + env: 'gingham', + })); }).to.throwException(e => { expect(e).to.be.ok(); - expect(e.message).to.equal('Missing Plaid "public_key"'); + expect(e.message).to.equal('Invalid Plaid environment'); }); }); - it('throws for invalid environment', () => { + it('throws for too many arguments', () => { expect(() => { - plaid.Client(CLIENT_ID, SECRET, PUBLIC_KEY, 'gingham'); + plaid.Client(configs, 'extra arg'); }).to.throwException(e => { expect(e).to.be.ok(); - expect(e.message).to.equal('Invalid Plaid environment'); + expect(e.message).to.equal('Too many arguments to constructor'); }); }); it('succeeds with all arguments', () => { expect(() => { R.forEachObjIndexed(env => { - plaid.Client(CLIENT_ID, SECRET, PUBLIC_KEY, env); + plaid.Client(R.merge(configs, { + env: env, + })); + }, plaid.environments); + }).not.to.throwException(); + }); + + it('succeeds without any options', () => { + expect(() => { + R.forEachObjIndexed(env => { + plaid.Client(R.merge(configs, { + options: null, + env: env, + })); }, plaid.environments); }).not.to.throwException(); }); diff --git a/test/mocks/api-invalid-json.nb b/test/mocks/api-invalid-json.nb index 22f0230b..523a5259 100644 --- a/test/mocks/api-invalid-json.nb +++ b/test/mocks/api-invalid-json.nb @@ -1,5 +1,5 @@ >> POST /institutions/get_by_id ->> ={"public_key":"xxx","institution_id":"ins_3"} +>> ={"client_id":"xxx","secret":"yyy","institution_id":"ins_3"} << 400 << content-type: application/json; charset=utf-8 << =invalidJsonIsTheWorst diff --git a/test/mocks/api-valid-json.nb b/test/mocks/api-valid-json.nb index de20090c..3ed0114d 100644 --- a/test/mocks/api-valid-json.nb +++ b/test/mocks/api-valid-json.nb @@ -1,5 +1,5 @@ >> POST /institutions/get_by_id ->> ={"public_key":"yyy","institution_id":"ins_1"} +>> ={"client_id":"www","secret":"vvv","institution_id":"ins_1"} << 200 << plaid-request-id: 1234abcd << content-type: application/json; charset=utf-8 diff --git a/test/plaidRequest.js b/test/plaidRequest.js index 21543604..76887bbc 100644 --- a/test/plaidRequest.js +++ b/test/plaidRequest.js @@ -22,7 +22,8 @@ describe('plaid.plaidRequest', () => { plaidRequest({ env: plaid.environments.sandbox, - public_key: 'xxx', + client_id: 'xxx', + secret: 'yyy', }, { path: '/institutions/get_by_id', body: {institution_id: 'ins_3'}, @@ -50,7 +51,8 @@ describe('plaid.plaidRequest', () => { plaidRequest({ env: plaid.environments.sandbox, - public_key: 'yyy', + client_id: 'www', + secret: 'vvv', }, { path: '/institutions/get_by_id', body: {institution_id: 'ins_1'},