diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..8056443 --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "plugins": [ "add-module-exports" ], + "presets": [ "es2015" ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..e717f5e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,13 @@ +# http://editorconfig.org +root = true + +[*] +indent_style = space +indent_size = 2 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true +insert_final_newline = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd071a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,31 @@ +# Logs +logs +*.log + +# Runtime data +pids +*.pid +*.seed + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage + +# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +# Commenting this out is preferred by some people, see +# https://www.npmjs.org/doc/misc/npm-faq.html#should-i-check-my-node_modules-folder-into-git- +node_modules + +# Users Environment Variables +.lock-wscript + +# The compiled/babelified modules +lib/ diff --git a/.jshintrc b/.jshintrc new file mode 100644 index 0000000..741f1e4 --- /dev/null +++ b/.jshintrc @@ -0,0 +1,30 @@ +{ + "node": true, + "esnext": true, + "bitwise": true, + "camelcase": true, + "curly": true, + "eqeqeq": true, + "immed": true, + "indent": 2, + "latedef": "nofunc", + "newcap": false, + "noarg": true, + "quotmark": "single", + "regexp": true, + "undef": true, + "unused": true, + "strict": false, + "trailing": true, + "smarttabs": true, + "white": false, + "node": true, + "globals": { + "it": true, + "describe": true, + "before": true, + "beforeEach": true, + "after": true, + "afterEach": true + } +} diff --git a/.npmignore b/.npmignore new file mode 100644 index 0000000..1c22293 --- /dev/null +++ b/.npmignore @@ -0,0 +1,8 @@ +.editorconfig +.jshintrc +.travis.yml +.babelrc +.idea/ +src/ +test/ +!lib/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b7b1e28 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,4 @@ +language: node_js +node_js: + - 'node' + - 'iojs' diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..40b7881 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +The MIT License (MIT) + +Copyright (c) 2015 Feathers + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + diff --git a/README.md b/README.md new file mode 100644 index 0000000..4fb427e --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# feathers-stripe + +[![Build Status](https://travis-ci.org/feathersjs/feathers-stripe.png?branch=master)](https://travis-ci.org/feathersjs/feathers-stripe) + +> A Feathers service for Stripe + +## About + + +## Changelog + +__0.1.0__ + +- Initial release + +## License + +Copyright (c) 2015 + +Licensed under the [MIT license](LICENSE). diff --git a/package.json b/package.json new file mode 100644 index 0000000..d0977d1 --- /dev/null +++ b/package.json @@ -0,0 +1,55 @@ +{ + "name": "feathers-stripe", + "description": "A Feathers service for Stripe", + "version": "0.0.0", + "homepage": "https://github.com/feathersjs/feathers-stripe", + "main": "lib/", + "keywords": [ + "feathers", + "feathers-plugin" + ], + "license": "MIT", + "repository": { + "type": "git", + "url": "git://github.com/feathersjs/feathers-stripe.git" + }, + "author": { + "name": "Feathers contributors", + "email": "hello@feathersjs.com", + "url": "https://feathersjs.com" + }, + "contributors": [], + "bugs": { + "url": "https://github.com/feathersjs/feathers-stripe/issues" + }, + "engines": { + "node": ">= 0.12.0" + }, + "scripts": { + "prepublish": "npm run compile", + "publish": "git push origin && git push origin --tags", + "release:patch": "npm version patch && npm publish", + "release:minor": "npm version minor && npm publish", + "release:major": "npm version major && npm publish", + "compile": "rm -rf lib/ && babel -d lib/ src/", + "watch": "babel --watch -d lib/ src/", + "jshint": "jshint src/. test/. --config", + "mocha": "mocha test/ --compilers js:babel-core/register", + "test": "npm run compile && npm run jshint && npm run mocha" + }, + "directories": { + "lib": "lib" + }, + "dependencies": { + "debug": "^2.2.0" + }, + "devDependencies": { + "babel-cli": "^6.5.1", + "babel-core": "^6.5.2", + "babel-plugin-add-module-exports": "^0.1.2", + "babel-preset-es2015": "^6.5.0", + "feathers": "^2.0.0", + "jshint": "^2.9.1", + "mocha": "^2.4.5" + } +} diff --git a/src/error-handler.js b/src/error-handler.js new file mode 100644 index 0000000..7e6c74e --- /dev/null +++ b/src/error-handler.js @@ -0,0 +1,35 @@ +import errors from 'feathers-errors'; + +export default function errorHandler(error) { + let feathersError = error; + + if (error.type) { + switch(error.type) { + case 'StripeCardError': + // A declined card error + feathersError = new errors.PaymentError(error); + break; + case 'StripeInvalidRequestError': + case 'StripeInvalidRequest': + // Invalid parameters were supplied to Stripe's API + feathersError = new errors.BadRequest(error); + break; + case 'StripeAPIError': + // An error occurred internally with Stripe's API + feathersError = new errors.Unavailable(error); + break; + case 'StripeConnectionError': + // Some kind of error occurred during the HTTPS communication + feathersError = new errors.Unavailable(error); + break; + case 'StripeAuthenticationError': + // You probably used an incorrect API key + feathersError = new errors.NotAuthenticated(error); + break; + default: + feathersError = new errors.GeneralError('Unknown Payment Gateway Error', error); + } + } + + return Promise.reject(feathersError); +} diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..0c738ce --- /dev/null +++ b/src/index.js @@ -0,0 +1,8 @@ +if (!global._babelPolyfill) { require('babel-polyfill'); } + +import card from './services/card'; +import charge from './services/charge'; +import customer from './services/customer'; +import plan from './services/plan'; + +export default { card, charge, customer, plan }; \ No newline at end of file diff --git a/src/services/card.js b/src/services/card.js new file mode 100644 index 0000000..f175147 --- /dev/null +++ b/src/services/card.js @@ -0,0 +1,50 @@ +import errorHandler from '../error-handler'; +import makeDebug from 'debug'; +import Stripe from 'stripe'; + +const debug = makeDebug('feathers-stripe:card'); + +class Service { + constructor(options = {}) { + + if (!options.apiKey) { + throw new Error('Stripe `apiKey` needs to be provided'); + } + + this.stripe = Stripe(options.apiKey); + this.paginate = options.paginate = {}; + } + + find(params) { + // TODO (EK): Handle pagination + return this.stripe.cards.list(params).catch(errorHandler); + } + + get(id) { + return this.stripe.cards.retrieve(id).catch(errorHandler); + } + + create(data) { + return this.stripe.cards.create(data).catch(errorHandler); + } + + patch(... args) { + return this.update(...args); + } + + update(id, data) { + return this.stripe.cards.update(id, data).catch(errorHandler); + } + + remove(id) { + return this.stripe.cards.del(id).catch(errorHandler); + } +} + +export default function init(options) { + debug('Initializing feathers-stripe:card plugin'); + + return new Service(options); +} + +init.Service = Service; diff --git a/src/services/charge.js b/src/services/charge.js new file mode 100644 index 0000000..cf2ecc8 --- /dev/null +++ b/src/services/charge.js @@ -0,0 +1,50 @@ +import errorHandler from '../error-handler'; +import makeDebug from 'debug'; +import Stripe from 'stripe'; + +const debug = makeDebug('feathers-stripe:charge'); + +class Service { + constructor(options = {}) { + + if (!options.apiKey) { + throw new Error('Stripe `apiKey` needs to be provided'); + } + + this.stripe = Stripe(options.apiKey); + this.paginate = options.paginate = {}; + } + + find(params) { + // TODO (EK): Handle pagination + return this.stripe.charges.list(params).catch(errorHandler); + } + + get(id) { + return this.stripe.charges.retrieve(id).catch(errorHandler); + } + + create(data) { + return this.stripe.charges.create(data).catch(errorHandler); + } + + patch(... args) { + return this.update(...args); + } + + update(id, data) { + return this.stripe.charges.update(id, data).catch(errorHandler); + } + + remove(id) { + return this.stripe.charges.del(id).catch(errorHandler); + } +} + +export default function init(options) { + debug('Initializing feathers-stripe:charge plugin'); + + return new Service(options); +} + +init.Service = Service; diff --git a/src/services/customer.js b/src/services/customer.js new file mode 100644 index 0000000..32550bc --- /dev/null +++ b/src/services/customer.js @@ -0,0 +1,50 @@ +import errorHandler from '../error-handler'; +import makeDebug from 'debug'; +import Stripe from 'stripe'; + +const debug = makeDebug('feathers-stripe:customer'); + +class Service { + constructor(options = {}) { + + if (!options.apiKey) { + throw new Error('Stripe `apiKey` needs to be provided'); + } + + this.stripe = Stripe(options.apiKey); + this.paginate = options.paginate = {}; + } + + find(params) { + // TODO (EK): Handle pagination + return this.stripe.customers.list(params).catch(errorHandler); + } + + get(id) { + return this.stripe.customers.retrieve(id).catch(errorHandler); + } + + create(data) { + return this.stripe.customers.create(data).catch(errorHandler); + } + + patch(... args) { + return this.update(...args); + } + + update(id, data) { + return this.stripe.customers.update(id, data).catch(errorHandler); + } + + remove(id) { + return this.stripe.customers.del(id).catch(errorHandler); + } +} + +export default function init(options) { + debug('Initializing feathers-stripe:customer plugin'); + + return new Service(options); +} + +init.Service = Service; diff --git a/src/services/plan.js b/src/services/plan.js new file mode 100644 index 0000000..2c45ed4 --- /dev/null +++ b/src/services/plan.js @@ -0,0 +1,50 @@ +import errorHandler from '../error-handler'; +import makeDebug from 'debug'; +import Stripe from 'stripe'; + +const debug = makeDebug('feathers-stripe:plan'); + +class Service { + constructor(options = {}) { + + if (!options.apiKey) { + throw new Error('Stripe `apiKey` needs to be provided'); + } + + this.stripe = Stripe(options.apiKey); + this.paginate = options.paginate = {}; + } + + find(params) { + // TODO (EK): Handle pagination + return this.stripe.plans.list(params).catch(errorHandler); + } + + get(id) { + return this.stripe.plans.retrieve(id).catch(errorHandler); + } + + create(data) { + return this.stripe.plans.create(data).catch(errorHandler); + } + + patch(... args) { + return this.update(...args); + } + + update(id, data) { + return this.stripe.plans.update(id, data).catch(errorHandler); + } + + remove(id) { + return this.stripe.plans.del(id).catch(errorHandler); + } +} + +export default function init(options) { + debug('Initializing feathers-stripe:plan plugin'); + + return new Service(options); +} + +init.Service = Service; diff --git a/test/index.test.js b/test/index.test.js new file mode 100644 index 0000000..c057155 --- /dev/null +++ b/test/index.test.js @@ -0,0 +1,13 @@ +import assert from 'assert'; +import plugin from '../src'; + +describe('feathers-stripe', () => { + it('is CommonJS compatible', () => { + assert.equal(typeof require('../lib'), 'function'); + }); + + it('basic functionality', done => { + assert.equal(typeof plugin, 'function', 'It worked'); + done(); + }); +});