dracopay
v0.0.2
Published
DracoPay uses revenuecat to process payments
Maintainers
Readme
DracoPay
A TypeScript package that provides a clean interface for interacting with the RevenueCat v2 API for subscription management and entitlement verification.
Features
- Get customer subscription information from RevenueCat
- Check if a customer has active subscriptions
- Check if a customer has specific entitlements
- Get subscription expiration dates
- Get all active entitlements for a customer
- Maps raw RevenueCat API responses to user-friendly DracoPay models
- NestJS integration support
Installation
npm install dracopayConfiguration
Create a DracoPayConfig object with your RevenueCat API key and project ID:
import { DracoPayService, DracoPayConfig } from 'dracopay';
const config: DracoPayConfig = {
apiKey: 'YOUR_REVENUECAT_API_KEY',
projectId: 'YOUR_REVENUECAT_PROJECT_ID',
baseUrl: 'https://api.revenuecat.com/v2' // Optional, defaults to RevenueCat v2 API
};
const dracoPayService = new DracoPayService(config);Usage
Get Customer Information
const customerId = 'customer-123';
const customer = await dracoPayService.getCustomer(customerId);
console.log(customer.id); // customer-123
console.log(customer.hasActiveSubscription); // true/false
console.log(customer.subscriptions); // Array of DracoPaySubscription objects
console.log(customer.entitlements); // Array of DracoPayEntitlement objectsCheck for Active Subscriptions
const customerId = 'customer-123';
const hasActive = await dracoPayService.hasActiveSubscription(customerId);
if (hasActive) {
console.log('Customer has at least one active subscription');
} else {
console.log('Customer has no active subscriptions');
}Get Subscription Expiration Date
const customerId = 'customer-123';
const expirationDate = await dracoPayService.getSubscriptionExpirationDate(customerId);
if (expirationDate) {
console.log(`Subscription expires on: ${expirationDate.toLocaleDateString()}`);
} else {
console.log('No active subscription found');
}Check for Specific Entitlement
const customerId = 'customer-123';
const entitlementId = 'premium_access';
const hasEntitlement = await dracoPayService.hasEntitlement(customerId, entitlementId);
if (hasEntitlement) {
console.log('Customer has the premium_access entitlement');
} else {
console.log('Customer does not have the premium_access entitlement');
}Get All Active Entitlements
const customerId = 'customer-123';
const activeEntitlements = await dracoPayService.getActiveEntitlements(customerId);
console.log('Active entitlements:', activeEntitlements); // Array of entitlement IDsGet All Subscriptions
const customerId = 'customer-123';
const subscriptions = await dracoPayService.getSubscriptions(customerId);
subscriptions.forEach(sub => {
console.log(`Subscription ID: ${sub.id}`);
console.log(`Product: ${sub.productName || sub.productId}`);
console.log(`Status: ${sub.status}`);
console.log(`Expiration: ${sub.expirationDate.toLocaleDateString()}`);
console.log(`Auto-renew: ${sub.autoRenewStatus}`);
console.log(`Store: ${sub.store}`);
});Get All Entitlements
const customerId = 'customer-123';
const entitlements = await dracoPayService.getEntitlements(customerId);
entitlements.forEach(ent => {
console.log(`Entitlement ID: ${ent.id}`);
console.log(`Display Name: ${ent.displayName || 'N/A'}`);
console.log(`Is Active: ${ent.isActive ? 'Yes' : 'No'}`);
console.log(`Expires: ${ent.expirationDate.toLocaleDateString()}`);
});Models
The service maps RevenueCat API responses to these DracoPay model types:
DracoPayCustomer
interface DracoPayCustomer {
id: string;
firstSeen: Date | null;
lastSeen: Date | null;
subscriptions: DracoPaySubscription[];
entitlements: DracoPayEntitlement[];
hasActiveSubscription: boolean;
attributes?: Record<string, string>;
country?: string;
}DracoPaySubscription
interface DracoPaySubscription {
id: string;
productId: string;
productName?: string;
purchaseDate: Date;
expirationDate: Date;
startDate: Date;
currentPeriodStartDate: Date;
currentPeriodEndDate: Date;
status: DracoPaySubscriptionStatus;
store: string;
storeIdentifier: string;
givesAccess: boolean;
autoRenewStatus: string;
offeringId?: string;
environment: string;
country?: string;
managementUrl?: string;
isInGracePeriod: boolean;
hasBillingIssues: boolean;
isRefunded: boolean;
isPendingPayment: boolean;
isActive: boolean;
}DracoPayEntitlement
interface DracoPayEntitlement {
id: string;
lookupKey?: string;
displayName?: string;
expirationDate: Date;
isActive: boolean;
productIds?: string[];
}DracoPaySubscriptionStatus
enum DracoPaySubscriptionStatus {
ACTIVE = 'active',
CANCELLED = 'cancelled',
CANCELLING = 'cancelling',
EXPIRED = 'expired',
GRACE_PERIOD = 'grace_period',
TRIALING = 'trialing',
REFUNDED = 'refunded',
BILLING_ISSUE = 'billing_issue',
UNKNOWN = 'unknown'
}Using in a NestJS Application
DracoPay includes a NestJS module that can be configured in different ways to integrate with your NestJS application.
Static Configuration
The simplest way to use the module is with static configuration:
import { Module } from '@nestjs/common';
import { DracoPayModule } from 'dracopay';
@Module({
imports: [
DracoPayModule.register({
apiKey: 'your-revenue-cat-api-key',
baseUrl: 'https://api.revenuecat.com/v2',
projectId: 'your-revenue-cat-project-id',
}),
],
})
export class AppModule {}Async Configuration
For more flexibility, you can use async configuration with environment variables:
import { Module } from '@nestjs/common';
import { ConfigModule, ConfigService } from '@nestjs/config';
import { DracoPayModule } from 'dracopay';
@Module({
imports: [
ConfigModule.forRoot(),
DracoPayModule.registerAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
apiKey: configService.get<string>('REVENUECAT_API_KEY'),
baseUrl: 'https://api.revenuecat.com/v2',
projectId: configService.get<string>('REVENUECAT_PROJECT_ID'),
}),
inject: [ConfigService],
}),
],
})
export class AppModule {}Module Configuration Details
The DracoPayModule exports these configuration methods:
register(config: DracoPayConfig)
For static configuration with a direct config object:
DracoPayModule.register({
apiKey: 'your-api-key', // RevenueCat API key (required)
projectId: 'your-project-id', // RevenueCat project ID (required)
baseUrl: 'https://api.revenuecat.com/v2', // API base URL (optional)
});registerAsync(asyncConfig: DracoPayAsyncConfig)
For dynamic configuration, such as loading from environment variables:
DracoPayModule.registerAsync({
imports: [ConfigModule], // Optional: Import modules needed for configuration
useFactory: (configService: ConfigService) => ({
// Factory function that returns a DracoPayConfig object
apiKey: configService.get<string>('REVENUECAT_API_KEY'),
projectId: configService.get<string>('REVENUECAT_PROJECT_ID'),
baseUrl: configService.get<string>('REVENUECAT_BASE_URL'),
}),
inject: [ConfigService], // Dependencies to inject into the factory function
});The module automatically provides the DracoPayService which can be injected into your controllers and services:
@Injectable()
export class YourService {
constructor(private readonly dracoPayService: DracoPayService) {}
async checkSubscription(userId: string): Promise<boolean> {
return this.dracoPayService.hasActiveSubscription(userId);
}
}Using in Controllers or Services
Once the module is imported, you can inject the DracoPayService into your controllers or services:
import { Controller, Get, Param } from '@nestjs/common';
import { DracoPayService } from 'dracopay';
@Controller('subscriptions')
export class SubscriptionsController {
constructor(private readonly dracoPayService: DracoPayService) {}
@Get(':customerId')
async getSubscription(@Param('customerId') customerId: string) {
const hasActiveSubscription = await this.dracoPayService.hasActiveSubscription(customerId);
if (hasActiveSubscription) {
return { status: 'active', message: 'User has an active subscription' };
}
return { status: 'inactive', message: 'User does not have an active subscription' };
}
@Get(':customerId/entitlements')
async getEntitlements(@Param('customerId') customerId: string) {
const entitlements = await this.dracoPayService.getEntitlements(customerId);
return { entitlements };
}
}Testing
For testing the DracoPayService, we recommend setting up environment variables:
Setting up environment variables
Create a .env file in your project root:
REVENUECAT_API_KEY=your_api_key
REVENUECAT_PROJECT_ID=your_project_id
TEST_CUSTOMER_ID=test_customer_idManual testing
For manual testing, you can create a simple test file:
import { DracoPayService, DracoPayConfig } from 'dracopay';
import dotenv from 'dotenv';
dotenv.config();
const config: DracoPayConfig = {
apiKey: process.env.REVENUECAT_API_KEY!,
projectId: process.env.REVENUECAT_PROJECT_ID!,
};
const dracoPayService = new DracoPayService(config);
const customerId = process.env.TEST_CUSTOMER_ID!;
async function test() {
try {
const customer = await dracoPayService.getCustomer(customerId);
console.log(JSON.stringify(customer, null, 2));
} catch (error) {
console.error('Error testing DracoPayService:', error);
}
}
test();Error Handling
All service methods will throw exceptions if there's an error communicating with the RevenueCat API. Make sure to add proper error handling in your application.
Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
License
MIT
