@saas-experts/subscrio
v0.1.16
Published
TypeScript subscription management library with feature flags, billing cycles, and Stripe integration
Maintainers
Readme
@saas-experts/subscrio
A comprehensive TypeScript library for subscription management, feature flags, billing cycles, and Stripe integration.
Features
- 🎯 Feature Flags & Entitlements - Granular feature control with subscription-based access
- 💳 Billing Management - Flexible billing cycles, plans, and pricing models
- 🔄 Subscription Lifecycle - Complete subscription management from trial to renewal
- 🏷️ Stripe Integration - Seamless payment processing and webhook handling
- 🗄️ PostgreSQL Ready - Built on Drizzle ORM with full type safety
- 📊 Feature Resolution - Smart hierarchy: subscription overrides → plan values → defaults
- ⚡ TypeScript First - Full type safety and excellent developer experience
Installation
npm install @saas-experts/subscrioPrerequisites:
- Node.js 18+
- PostgreSQL database
Quick Start
import { Subscrio } from '@saas-experts/subscrio';
// Initialize the library
const subscrio = new Subscrio({
database: {
connectionString: 'postgresql://user:password@localhost:5432/mydb'
}
});
// Install database schema (first time only)
await subscrio.installSchema();
// Create a product
const product = await subscrio.products.createProduct({
key: 'my-saas',
displayName: 'My SaaS Product'
});
// Create a feature
const feature = await subscrio.features.createFeature({
key: 'max-users',
displayName: 'Maximum Users',
valueType: 'numeric',
defaultValue: '10'
});
// Associate feature with product (using keys, not IDs)
await subscrio.products.associateFeature(product.key, feature.key);
// Create a plan (using productKey, not productId)
const plan = await subscrio.plans.createPlan({
productKey: product.key,
key: 'pro-plan',
displayName: 'Pro Plan'
});
// Set feature value on plan (using keys, not IDs)
await subscrio.plans.setFeatureValue(plan.key, feature.key, '100');
// Create a billing cycle for the plan (required for subscriptions)
const billingCycle = await subscrio.billingCycles.createBillingCycle({
planKey: plan.key,
key: 'monthly',
displayName: 'Monthly',
durationValue: 1,
durationUnit: 'months'
});
// Create a customer (using key, not externalId)
const customer = await subscrio.customers.createCustomer({
key: 'customer-123',
displayName: 'Acme Corp'
});
// Create a subscription (using keys and billingCycleKey, not IDs)
const subscription = await subscrio.subscriptions.createSubscription({
key: 'sub-001',
customerKey: customer.key,
billingCycleKey: billingCycle.key
});
// Check feature access (requires customerKey, productKey, and featureKey)
const maxUsers = await subscrio.featureChecker.getValueForCustomer(
customer.key,
product.key,
'max-users'
);
console.log(`Customer can have ${maxUsers} users`); // "100"API Reference
Core Services
subscrio.products- Product managementsubscrio.features- Feature flag managementsubscrio.plans- Subscription plan managementsubscrio.billingCycles- Billing cycle managementsubscrio.customers- Customer managementsubscrio.subscriptions- Subscription lifecyclesubscrio.featureChecker- Feature access checkingsubscrio.stripe- Stripe integration
Instance Methods
installSchema(adminPassphrase?)- Install database schemaverifySchema()- Check if schema is installeddropSchema()- Drop all database tables (destructive)close()- Close database connections
Configuration
import { Subscrio } from '@saas-experts/subscrio';
const subscrio = new Subscrio({
database: {
connectionString: process.env.DATABASE_URL,
ssl: process.env.DATABASE_SSL === 'true', // Optional
poolSize: parseInt(process.env.DATABASE_POOL_SIZE || '10') // Optional
},
adminPassphrase: process.env.ADMIN_PASSPHRASE, // Optional, min 8 chars
stripe: {
secretKey: process.env.STRIPE_SECRET_KEY // Optional
},
logging: {
level: (process.env.LOG_LEVEL as 'debug' | 'info' | 'warn' | 'error') || 'info' // Optional
}
});Feature Resolution Hierarchy
Subscrio uses a smart hierarchy for feature values:
- Subscription Override (highest priority)
- Plan Value
- Feature Default (fallback)
// Check if feature is enabled for a customer in a product
const isEnabled = await subscrio.featureChecker.isEnabledForCustomer(
'customer-123', // customerKey
'my-saas', // productKey
'advanced-analytics' // featureKey
);
// Get feature value for a customer in a product
const maxProjects = await subscrio.featureChecker.getValueForCustomer(
'customer-123', // customerKey
'my-saas', // productKey
'max-projects' // featureKey
);
// Get feature value for a specific subscription
const value = await subscrio.featureChecker.getValueForSubscription(
'sub-001', // subscriptionKey
'max-projects' // featureKey
);Stripe Integration
// Process Stripe webhooks (implementor handles verification)
app.post('/webhooks/stripe', express.raw({type: 'application/json'}), async (req, res) => {
const event = stripe.webhooks.constructEvent(req.body, sig, webhookSecret);
await subscrio.stripe.processStripeEvent(event);
res.json({received: true});
});TypeScript Support
Full TypeScript support with comprehensive type definitions:
import {
Subscrio,
SubscrioConfig,
CreateProductDto,
ProductDto,
CreateFeatureDto,
FeatureDto,
CreatePlanDto,
PlanDto,
CreateBillingCycleDto,
BillingCycleDto,
CreateCustomerDto,
CustomerDto,
CreateSubscriptionDto,
SubscriptionDto
} from '@saas-experts/subscrio';
// All APIs are fully typed
const product: ProductDto = await subscrio.products.createProduct({
key: 'my-product',
displayName: 'My Product'
});Key Concepts
Keys vs IDs: All public APIs use keys (string identifiers like 'my-product') rather than internal IDs. Keys are:
- Human-readable and memorable
- Globally unique within their scope
- Immutable once created
- Used in all method calls and references
DTOs: All create/update operations use DTOs (Data Transfer Objects) with Zod validation:
CreateProductDto,CreateFeatureDto,CreatePlanDto, etc.- All fields are validated before processing
- Type-safe with full TypeScript inference
License
MIT License - see LICENSE file for details.
Contributing
Contributions are welcome! Please see our Contributing Guide for details.
