New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

subscription

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

subscription - npm Package Compare versions

Comparing version 0.0.0 to 0.0.1

Devfile

5

index.js

@@ -21,3 +21,6 @@ var level = require("level-json");

return {
define: require("./lib/define"),
balance: require('./lib/balance'),
cancel: require('./lib/cancel'),
charges: require('./lib/charges'),
service: require("./lib/service"),
priceOf: require('./lib/price-of'),

@@ -24,0 +27,0 @@ purchase: require('./lib/purchase'),

97

lib/charges.js

@@ -5,2 +5,3 @@ var debug = require("local-debug")('charges');

var fatal = require("./fatal");
var newError = require("new-error");

@@ -10,15 +11,17 @@ module.exports = {

active: active,
available: available,
create: create,
last: last
lastUnexpired: lastUnexpired,
markAsCancelled: markAsCancelled,
notExpired: notExpired,
read: read
};
function active (customer, subscription, callback) {
function active (customer, service, callback) {
var now = Date.now();
read(customer, subscription, function (error, all) {
read(customer, service, function (error, all) {
if (error) return callback(error);
callback(undefined, all.filter(function (charge) {
return charge.start_ts <= now && charge.expire_ts > now;
return !charge.cancelled && charge.start_ts <= now && charge.expire_ts > now;
}));

@@ -29,3 +32,3 @@ });

function add (charge, callback) {
var key = keyOf({ customer: charge.customer, charges: charge.subscription });
var key = keyOf({ customer: charge.customer, service: charge.service });

@@ -47,16 +50,4 @@ debug('Adding the charge %s into %s', charge.amount + charge.currency, key);

function available (customer, subscription, callback) {
var now = Date.now();
read(customer, subscription, function (error, all) {
if (error) return callback(error);
callback(undefined, all.filter(function (charge) {
return charge.expire_ts > now;
}));
});
}
function create (charge, callback) {
var key = keyOf({ customer: charge.customer, charges: charge.subscription });
var key = keyOf({ customer: charge.customer, service: charge.service });
var charges = [charge];

@@ -80,26 +71,70 @@

function read (customer, subscription, callback) {
var key = keyOf({ customer: customer, charges: subscription });
function markAsCancelled (customer, service, callback) {
debug('Marking all unexpired charges by %s to "%s" as cancelled', customer, service);
var now = Date.now();
read(customer, service, function (error, charges) {
if (error) return callback(error);
var save = charges.map(function (charge) {
if (charge.expire_ts < now) return charge;
debug('Cancelling %s%s made by %s for "%s', charge.amount, charge.currency, customer, service);
charge.cancelled = Date.now();
return charge;
});
var key = keyOf({ customer: customer, service: service });
io.set(key, save, callback);
});
}
function read (customer, service, callback) {
var key = keyOf({ customer: customer, service: service });
debug('Reading %s', key);
io.get(key, callback);
io.get(key, function (error, result) {
if (error) {
return callback(newError('{0} has no charge records for "{1}"', customer, service));
};
callback(undefined, result);
});
}
function last (customer, subscription, callback) {
recent(customer, subscription, function (error, recent) {
function lastUnexpired (customer, service, callback) {
recent(customer, service, function (error, recent) {
if(error) return callback(error);
callback(undefined, recent[0]);
callback(undefined, recent[recent.length - 1]);
});
}
function recent (customer, subscription, callback) {
read(customer, subscription, function (error, all) {
function recent (customer, service, callback) {
read(customer, service, function (error, all) {
if (error) return callback(error);
callback(undefined, all.sort(function (a, b) {
if (a.expire_ts > b.expire_ts) return 1;
if (a.expire_ts < b.expire_ts) return -1;
return 0;
callback(undefined, all
.filter(function (charge) {
return !charge.cancelled;
})
.sort(function (a, b) {
if (a.expire_ts > b.expire_ts) return 1;
if (a.expire_ts < b.expire_ts) return -1;
return 0;
}));
});
}
function notExpired (customer, service, callback) {
var now = Date.now();
read(customer, service, function (error, all) {
if (error) return callback(error);
callback(undefined, all.filter(function (charge) {
return !charge.cancelled && charge.expire_ts > now;
}));
});
}

@@ -0,10 +1,16 @@

var prefix = 'subscription/';
module.exports = keyOf;
function keyOf (options) {
if (options.customer && options.charges)
return options.customer + '/charges/' + options.charges;
if (options.customer && options.service)
return prefix + options.customer + '/charges/' + options.service;
if (options.subscription) return 'subscriptions/' + options.subscription;
if (options.service) return prefix + 'services/' + options.service;
if (options.subscriptions) return options.subscriptions + '/subscriptions';
if (options.services) return prefix + 'services';
if (options.subscriptionsOf) return prefix + options.subscriptionsOf + '/subscriptions';
if (options.balance) return prefix + options.balance + '/balance';
}

@@ -5,7 +5,8 @@ var englishTime = require("english-time");

function priceOf (subscription, englishLength) {
var length = englishTime(englishLength);
var amount = Math.floor(length / subscription.period);
function priceOf (service, length) {
typeof length == 'string' && ( length = englishTime(length) );
return subscription.price * amount;
var amount = Math.floor(length / service.period);
return service.price * amount;
}
var debug = require("local-debug")('purchase');
var getSubscription = require("./define").read;
var newError = require("new-error");
var getService = require("./service").get;
var stripe = require("./stripe-sdk")();

@@ -9,31 +10,66 @@ var priceOf = require("./price-of");

var fatal = require("./fatal");
var remaining = require("./remaining");
var cancel = require("./cancel");
var balance = require("./balance");
module.exports = subscription;
module.exports.extension = extension;
module.exports.upgrade = upgrade;
function extension (subscriptionName, options, callback) {
charges.last(options.customer, subscriptionName, function (error, lastCharge) {
if (error) return callback(error);
function extension (serviceName, options, callback) {
charges.lastUnexpired(options.customer, serviceName, function (error, lastCharge) {
if (error) {
return callback(newError('Oops, unable to extend. {0} doesn\'t have any active subscription to "{1}".', options.customer, serviceName));
}
options.startTS = lastCharge.expire_ts;
subscription(subscriptionName, options, callback);
subscription(serviceName, options, callback);
});
}
function subscription (subscriptionName, options, callback) {
debug('%s is purchasing %s subscription for %s', options.customer, subscriptionName, options.length);
function upgrade (options, callback) {
debug('%s is upgrading from %s to %s', options.customer, options.from, options.to);
getSubscription(subscriptionName, function (error, subscription) {
cancel(options.customer, options.from, function (error, result) {
if (error) return callback(error);
charge(subscription, options, function (error, stripeCharge) {
if (error) return callback(error);
debug('Cancelled %s\'s subscription to %s. Now purchasing %s, for %s', options.customer, options.from, options.to, result.remainingTime);
charges.add(stripeCharge, function (error, chargeRecord) {
subscriptions.add(options.customer, subscriptionName, function (error) {
if(error) return callback(error);
callback(undefined, chargeRecord);
subscription(options.to, { token: options.token, customer: options.customer, length: result.remainingTime }, callback);
});
}
function subscription (serviceName, options, callback) {
debug('%s is purchasing %s subscription for %s', options.customer, serviceName, options.length);
options.startTS || (options.startTS = Date.now());
charges.lastUnexpired(options.customer, serviceName, function (error, lastCharge) {
getService(serviceName, function (error, service) {
if (error) {
return callback(error);
}
if (lastCharge && lastCharge.expire_ts > options.startTS) {
return callback(newError('You ({0}) already paid "{1}". Use the "extend" option to extend your subscription.', options.customer, serviceName));
}
charge(service, options, function (error, stripeCharge) {
if (error) return callback(error);
charges.add(stripeCharge, function (error, chargeRecord) {
if (error) {
fatal(error.message);
fatal(error.stack);
}
subscriptions.add(options.customer, serviceName, function (error) {
if(error) return callback(error);
callback(undefined, chargeRecord);
});
});
});
});

@@ -45,30 +81,56 @@

function charge (subscription, options, callback) {
function charge (service, options, callback) {
if (!service.price) {
return callback(undefined, {
customer: options.customer,
service: service.name,
create_ts: Date.now(),
start_ts: options.startTS
});
}
if (!options.card && !options.token) {
return callback(newError('Either card info or a valid Stripe token has to be provided for purchasing a subscription.'));
}
var totalPrice = priceOf(service, options.length);
var stripeOptions = {
amount: priceOf(subscription, options.length),
currency: subscription.currency,
amount: totalPrice,
currency: service.currency,
card: options.token,
description: 'Subscribe "' + subscription.name + '" for ' + options.length
description: 'Subscribe "' + service.name + '" for ' + options.length
};
stripe.charges.create(stripeOptions, function (error, charge) {
if (error) return callback(error);
balance.charge(options.customer, stripeOptions.amount, function (error, restMoney, usedBalance) {
if (error) {
fatal('Unable to charge existing balance of %s', options.customer);
fatal(error.message);
fatal(error.stack);
};
debug('%s%s was paid by %s for %s. (ID: %s)', charge.amount, charge.currency, charge.customer, charge.description, charge.id);
if (restMoney != stripeOptions.amount) {
debug('%s used %s%s from his/her balance to pay %s', options.customer, usedBalance, stripeOptions.currency, stripeOptions.amount);
stripeOptions.amount = restMoney;
}
var startTS = options.startTS || Date.now();
stripe.charges.create(stripeOptions, function (error, charge) {
if (error) return callback(error);
callback(undefined, {
id: charge.id,
customer: options.customer,
subscription: subscription.name,
amount: charge.amount,
currency: charge.currency,
description: charge.description,
create_ts: Date.now(),
start_ts: startTS,
expire_ts: (charge.amount / subscription.price) * subscription.period + startTS
debug('%s%s was paid by %s for "%s". (ID: %s)', charge.amount, charge.currency, options.customer, charge.description, charge.id);
callback(undefined, {
id: charge.id,
customer: options.customer,
service: service.name,
amount: charge.amount,
currency: charge.currency,
description: charge.description,
create_ts: Date.now(),
start_ts: options.startTS,
expire_ts: (totalPrice / service.price) * service.period + options.startTS
});
});
});
}
var debug = require("local-debug")('remaining');
var newError = require("new-error");
var charges = require("./charges");

@@ -7,14 +8,24 @@ var fatal = require("./fatal");

function remaining (customer, subscription, callback) {
debug('Calculating the remaining time of %s\'s subscription to %s.', customer, subscription);
function remaining (customer, service, callback) {
debug('Calculating the remaining time of %s\'s subscription to %s.', customer, service);
charges.last(customer, subscription, function (error, charge) {
charges.lastUnexpired(customer, service, function (error, charge) {
if (error) {
fatal(error.message);
fatal(error.stack);
return callback(error);
}
callback(undefined, charge.expire_ts - Date.now());
if (!charge) {
return callback(undefined, 0);
}
var now = Date.now();
if (charge.expire_ts <= now) {
return callback(newError('{0} doesn\'t have any active subscription to {1}', customer, service));
}
debug('Remaining time of %s\'s subscription to %s is %d', customer, service, charge.expire_ts - now);
callback(undefined, charge.expire_ts - now);
});
}
var debug = require("local-debug")('subscriptions');
var newError = require("new-error");
var io = require("./io")();
var charges = require("./charges");
var keyOf = require("./key-of");
var fatal = require("./fatal");

@@ -9,18 +11,19 @@ module.exports = {

has: has,
read: read
read: read,
remove: remove
};
function add (customer, subscription, callback) {
var key = keyOf({ subscriptions: customer });
function add (customer, serviceName, callback) {
var key = keyOf({ subscriptionsOf: customer });
debug('Adding %s into %s', subscription, key);
debug('Adding %s into %s', serviceName, key);
io.get(key, function (error, subscriptions) {
if (error) return create(customer, subscription, callback);
if (error) return create(customer, serviceName, callback);
if (subscriptions.indexOf(subscription) > -1) {
if (subscriptions.indexOf(serviceName) > -1) {
return callback();
}
subscriptions.push(subscription);
subscriptions.push(serviceName);

@@ -31,5 +34,5 @@ io.set(key, subscriptions, callback);

function create (customer, subscription, callback) {
var key = keyOf({ subscriptions: customer });
var subs = [subscription];
function create (customer, serviceName, callback) {
var key = keyOf({ subscriptionsOf: customer });
var subs = [serviceName];

@@ -43,4 +46,28 @@ io.set(key, subs, function (error) {

function remove (customer, serviceName, callback) {
var key = keyOf({ subscriptionsOf: customer });
debug('Removing %s from %s', serviceName, key);
io.get(key, function (error, subscriptions) {
if (error) {
fatal(error);
return callback(error);
}
var index = subscriptions.indexOf(serviceName);
if (index == -1) {
return callback(newError('{0} already doesn\'t have any subscription to {1}', customer, serviceName));
}
subscriptions.splice(index, 1);
io.set(key, subscriptions, callback);
});
}
function read (customer, callback) {
var key = keyOf({ subscriptions: customer });
var key = keyOf({ subscriptionsOf: customer });

@@ -50,8 +77,8 @@ io.get(key, callback);

function has (customer, subscription, callback) {
function has (customer, serviceName, callback) {
read(customer, function (error, all) {
if (error) return callback();
callback(all.indexOf(subscription) > -1);
callback(all.indexOf(serviceName) > -1);
});
}
{
"name": "subscription",
"version": "0.0.0",
"version": "0.0.1",
"description": "Library to store and manage paid subscriptions via Stripe and LevelDB",

@@ -14,7 +14,10 @@ "main": "index.js",

"english-time": "0.0.8",
"local-debug": "0.0.0"
"local-debug": "0.0.0",
"new-error": "0.0.0"
},
"devDependencies": {
"fox": "*",
"call-all": "*"
"call-all": "*",
"map": "*",
"iter": "*"
},

@@ -21,0 +24,0 @@ "keywords": [

@@ -18,3 +18,3 @@ ## subscription

subscription.define('atlas magazine', { 'price': 1000, period: '1 month', currency: 'usd' }, function (error, atlas) {
subscription.service.define('atlas magazine', { 'price': 1000, period: '1 month', currency: 'usd' }, function (error, atlas) {

@@ -24,3 +24,3 @@ subscription.priceOf(atlas, '1 month')

subscription.priceOf(atlas, '1 year')
subscription.priceOf(atlas, '1 year')
// => 12000 (One Twenty Dollars)

@@ -37,3 +37,3 @@

length: '1 year',
token: 'tok_2oWvm6yRBFSMSh' // obtained with Stripe.js
token: 'tok_2oWvm6yRBFSMSh' // obtain it with Stripe.js
}

@@ -63,25 +63,33 @@

subscription.remaining('azer@kodfabrik.com', 'atlas magazine', function (error, remaining) {
remaining
// => 8035200000 (3 months)
})
```
List all subscriptions of a user:
List subscriptions of a user:
```js
subscription.subscriptionsOf('azer@kodfabrik.com', function (error, subs) {
subs
// => ['atlas magazine']
})
```
## More Docs
Extend a subscription:
* `test.js`
* [english-time](http://github.com/azer/english-time): The library used for parsing time inputs.
```js
subscription.purchase.extension('atlas magazine', { customer: 'azer@kodfabrik.com', length: '2 years', token: token }, function (error, purchase) {
purchase.amount
// => 24000
});
```
Upgrade a subscription:
```js
subscription.purchase.upgrade({ customer: 'hi@ada.io', from: 'cheaper', to: 'more expensive service', token: token }, function (error, purchase) {
if (error) return callback(error);
});
```
## Debugging

@@ -106,1 +114,6 @@

```
## More Docs
* `test.js`
* [english-time](http://github.com/azer/english-time): The library used for parsing time inputs.

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc