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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sftech/nestjs-revenue

v0.1.0

Published

RevenueCat subscription management for NestJS applications. Provides entitlement-based access control, a subscription status endpoint, and a guard/decorator pair for protecting routes behind an active subscription check.

Downloads

96

Readme

@sftech/nestjs-revenue

RevenueCat subscription management for NestJS applications. Provides entitlement-based access control, a subscription status endpoint, and a guard/decorator pair for protecting routes behind an active subscription check.

Installation

pnpm add @sftech/nestjs-revenue

Peer Dependencies

| Package | Required Version | |---|---| | @nestjs/common | ^10.0.0 \|\| ^11.0.0 | | @nestjs/core | ^10.0.0 \|\| ^11.0.0 | | @nestjs/axios | >=4.0.1 | | @sftech/nestjs-core | >=1.0.3 | | @sftech/nestjs-auth | >=1.5.0 | | rxjs | ^7.0.0 |

Note: @sftech/nestjs-auth must be registered in the consuming application. NestjsRevenueModule relies on @sftech/nestjs-auth for the @CurrentUser() decorator and IS_PUBLIC_KEY reflection metadata used by EntitlementGuard.

Module Registration

Pass your application configuration object directly to NestjsRevenueModule.register(). The module reads the RevenueCat keys from the configuration and validates required keys at startup.

import { Module } from '@nestjs/common';
import { NestjsAuthModule } from '@sftech/nestjs-auth';
import { NestjsRevenueModule } from '@sftech/nestjs-revenue';
import { Configuration } from '@sftech/nestjs-core';

@Module({
    imports: [
        NestjsAuthModule.register(Configuration.getConfig()),
        NestjsRevenueModule.register(Configuration.getConfig()),
    ],
})
export class AppModule {}

The module is decorated with @Global(), so RevenueService and EntitlementGuard are available application-wide once registered.

Configuration Keys

| Key | Required | Default | Description | |---|---|---|---| | REVENUECAT_SECRET_KEY | Yes | - | RevenueCat secret API key (e.g. sk_live_...) | | REVENUECAT_ENTITLEMENT_ID | Yes | - | Entitlement identifier to check (e.g. premium) | | REVENUECAT_API_URL | No | https://api.revenuecat.com | RevenueCat REST API base URL | | REVENUECAT_PLATFORM | No | (none) | Platform sent in X-Platform header (see ERevenuePlatform). When not set, the X-Platform header is omitted entirely. Leave unconfigured when serving multiple platforms (web, Android, iOS) from a single backend — RevenueCat resolves subscribers cross-platform via the app_user_id alone. |

If REVENUECAT_SECRET_KEY or REVENUECAT_ENTITLEMENT_ID is missing, NestjsRevenueModule.register() throws a BaseApplicationException at startup with a descriptive message.

API Reference

Interfaces

| Interface | Description | |---|---| | IRevenueConfig | Internal configuration shape used by the module after mapping | | IRevenuePort | Port interface for the RevenueCat adapter (getSubscriber(appUserId)) | | ISubscriberStatus | Shape returned by RevenueService and the status endpoint |

IRevenueConfig

interface IRevenueConfig {
    secretKey: string;
    apiUrl: string;
    entitlementId: string;
    platform?: ERevenuePlatform;
}

IRevenuePort

interface IRevenuePort {
    getSubscriber(appUserId: string): Promise<ISubscriberStatus>;
}

ISubscriberStatus

interface ISubscriberStatus {
    isPremium: boolean;
    entitlement: string | null;
    expiresAt: Date | null;
    activeSubscriptions: string[];
}

Enums

ERevenuePlatform

| Member | Value | |---|---| | IOS | 'ios' | | ANDROID | 'android' | | STRIPE | 'stripe' | | AMAZON | 'amazon' | | MACOS | 'macos' | | PLAY_STORE | 'play_store' |

ERevenueConfigKeys

| Member | Value | |---|---| | SECRET_KEY | 'REVENUECAT_SECRET_KEY' | | API_URL | 'REVENUECAT_API_URL' | | ENTITLEMENT_ID | 'REVENUECAT_ENTITLEMENT_ID' | | PLATFORM | 'REVENUECAT_PLATFORM' |

Classes

| Class | Layer | Description | |---|---|---| | RevenueService | Application | Facade service; inject this to query subscription status | | RevenueConfigMapper | Infrastructure | Static mapper that transforms raw config into IRevenueConfig | | EntitlementGuard | Presentation | NestJS guard that blocks non-premium users with 403 Forbidden | | SubscriptionController | Presentation | Registers GET /subscription/status endpoint automatically |

Decorator

| Decorator | Description | |---|---| | @RequireEntitlement() | Shorthand for @UseGuards(EntitlementGuard) |

REST Endpoint

GET /subscription/status

Returns the authenticated user's subscription status. Authentication is required and handled by @sftech/nestjs-auth. The endpoint is registered automatically when NestjsRevenueModule is imported.

Response (200 OK, active subscription):

{
    "isPremium": true,
    "entitlement": "premium",
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "activeSubscriptions": ["monthly_premium"]
}

Response (200 OK, no active subscription):

{
    "isPremium": false,
    "entitlement": null,
    "expiresAt": null,
    "activeSubscriptions": []
}

Response (200 OK, lifetime subscription):

{
    "isPremium": true,
    "entitlement": "premium",
    "expiresAt": null,
    "activeSubscriptions": ["lifetime_premium"]
}

Error responses:

| Status | Condition | |---|---| | 401 Unauthorized | User is not authenticated (handled by @sftech/nestjs-auth) |

Usage Examples

Protecting a Route with EntitlementGuard

import { Controller, Get, UseGuards } from '@nestjs/common';
import { JwtAuthGuard } from '@sftech/nestjs-auth';
import { EntitlementGuard } from '@sftech/nestjs-revenue';

@Controller('premium-content')
@UseGuards(JwtAuthGuard, EntitlementGuard)
export class PremiumContentController {
    @Get()
    getContent() {
        return { data: 'This is premium content' };
    }
}

Non-premium users receive 403 Forbidden with the message "Active entitlement required".

Using the @RequireEntitlement() Decorator

@RequireEntitlement() is a convenience wrapper for @UseGuards(EntitlementGuard) and behaves identically:

import { Controller, Get } from '@nestjs/common';
import { JwtAuthGuard, Public } from '@sftech/nestjs-auth';
import { RequireEntitlement } from '@sftech/nestjs-revenue';

@Controller('premium-content')
export class PremiumContentController {
    @Get('protected')
    @RequireEntitlement()
    getProtected() {
        return { data: 'Premium only' };
    }

    @Get('free')
    @Public()
    getFree() {
        return { data: 'Free for everyone' };
    }
}

Routes decorated with @Public() from @sftech/nestjs-auth bypass EntitlementGuard entirely.

Injecting RevenueService

Use RevenueService directly when you need programmatic access to subscription status:

import { Injectable } from '@nestjs/common';
import { RevenueService, ISubscriberStatus } from '@sftech/nestjs-revenue';

@Injectable()
export class MyFeatureService {
    constructor(private readonly revenueService: RevenueService) {}

    async getFeatureAccess(userId: string): Promise<ISubscriberStatus> {
        return this.revenueService.getSubscriberStatus(userId);
    }

    async canAccessPremiumFeature(userId: string): Promise<boolean> {
        return this.revenueService.hasActiveEntitlement(userId);
    }
}

Edge Case Behavior

Fail-Open on API Errors

If the RevenueCat API is unreachable, returns a non-200 status, or the response cannot be parsed, the adapter logs a warning and returns a safe non-premium status:

{
    "isPremium": false,
    "entitlement": null,
    "expiresAt": null,
    "activeSubscriptions": []
}

This means API errors do not cause 500 responses or surface to the end user. The endpoint always returns 200 OK.

Lifetime Subscriptions

When RevenueCat reports expires_date: null for an entitlement or subscription, it indicates a lifetime (non-expiring) purchase. The adapter treats these as always active:

  • isPremium is true
  • expiresAt is null (no expiry date)
  • The subscription key appears in activeSubscriptions