npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

dracopay

v0.0.2

Published

DracoPay uses revenuecat to process payments

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 dracopay

Configuration

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 objects

Check 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 IDs

Get 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_id

Manual 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