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/ng-revenue

v0.2.0

Published

Angular library for RevenueCat subscription and entitlement management. Protects premium routes via a backend-verified guard, exposes subscription status, and wraps the RevenueCat SDK for purchase flows on both web and native (Capacitor) platforms.

Readme

@sftech/ng-revenue

Angular library for RevenueCat subscription and entitlement management. Protects premium routes via a backend-verified guard, exposes subscription status, and wraps the RevenueCat SDK for purchase flows on both web and native (Capacitor) platforms.

Installation

npm install @sftech/ng-revenue

Optional: Purchase flows (P2)

Install the RevenueCat SDK that matches your deployment target. Neither package is required for route protection or status checks.

# Web (browser)
npm install @revenuecat/purchases-js

# Native (iOS / Android via Capacitor)
npm install @revenuecat/purchases-capacitor @capacitor/core

Configuration

1. Add config keys to your environment config

// environment.ts or config loaded via APP_INITIALIZER
export const appConfig = {
    apiUrl: 'https://api.example.com/api',
    REVENUECAT_PUBLIC_KEY: 'appl_xxxxxxxxxxxxxxxx',
    // Optional overrides (defaults shown):
    SUBSCRIPTION_API_URL: 'https://api.example.com/api/subscription', // defaults to apiUrl + '/subscription'
    REVENUECAT_ENTITLEMENT_ID: 'premium',                              // defaults to 'premium'
    REVENUECAT_UPGRADE_REDIRECT: '/upgrade',                           // defaults to '/upgrade'
};

REVENUECAT_PUBLIC_KEY is the only required key. The mapper throws a descriptive error if it is missing.

2. Register the module in app.config.ts

import { ApplicationConfig, importProvidersFrom } from '@angular/core';
import { RevenueModule, RevenueConfigMapper } from '@sftech/ng-revenue';

export function appConfig(config: Record<string, unknown>): ApplicationConfig {
    return {
        providers: [
            // ...other providers
            importProvidersFrom(
                RevenueModule.forRoot(RevenueConfigMapper.map(config)),
            ),
        ],
    };
}

RevenueConfigMapper.map() validates the config and applies defaults. Pass its return value directly to RevenueModule.forRoot().

Features

Route Protection with entitlementGuard

Protects routes from users without an active subscription. The guard queries the backend on every navigation attempt and is fail-closed: any HTTP error redirects to the upgrade path instead of granting access.

import { Routes } from '@angular/router';
import { entitlementGuard } from '@sftech/ng-revenue';

export const routes: Routes = [
    {
        path: 'premium-feature',
        loadComponent: () => import('./premium/premium.component').then((m) => m.PremiumComponent),
        canActivate: [entitlementGuard],
    },
];

The redirect target is IRevenueConfig.upgradeRedirectPath (mapped from REVENUECAT_UPGRADE_REDIRECT, default '/upgrade').

Subscription Status Checking with SubscriptionApiService

Query the backend subscription status directly in any component or service. Useful for conditional UI rendering without gating an entire route.

import { Component, inject } from '@angular/core';
import { SubscriptionApiService, SubscriberStatus } from '@sftech/ng-revenue';

@Component({
    selector: 'app-profile',
    standalone: true,
    template: `<p>Premium: {{ status?.isPremium }}</p>`,
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class ProfileComponent {
    private subscriptionApi = inject(SubscriptionApiService);

    status: SubscriberStatus | null = null;

    ngOnInit(): void {
        this.subscriptionApi.getEntitlementStatus().subscribe({
            next: (status) => {
                this.status = status;
                console.log('Premium:', status.isPremium);
                console.log('Expires:', status.expiresAt);
                console.log('Active subscriptions:', status.activeSubscriptions);
            },
        });
    }
}

getEntitlementStatus() never throws. When the backend is unreachable it returns SubscriberStatus.free() (all fields set to their zero/null values).

Purchase Flows with RevenueService (optional SDK)

RevenueService wraps the RevenueCat SDK with automatic platform detection. It uses the Capacitor plugin on native platforms and the web SDK in a browser. Both paths share the same method signatures.

Requires one of the optional SDK packages listed in the Installation section.

import { Component, inject } from '@angular/core';
import { RevenueService, Offering, Package } from '@sftech/ng-revenue';

@Component({
    selector: 'app-upgrade',
    standalone: true,
    changeDetection: ChangeDetectionStrategy.OnPush,
})
export class UpgradeComponent {
    private revenueService = inject(RevenueService);

    offerings: Offering[] = [];

    async ngOnInit(): Promise<void> {
        // Call initialize() once per session, passing the current user's ID
        await this.revenueService.initialize('user-123');
        this.offerings = await this.revenueService.getOfferings();
    }

    async purchase(pkg: Package): Promise<void> {
        const success = await this.revenueService.purchasePackage(pkg);
        if (success) {
            // Navigate to premium content
        }
    }

    async restore(): Promise<void> {
        await this.revenueService.restorePurchases();
    }

    async signOut(): Promise<void> {
        await this.revenueService.logout();
    }
}

isInitialized is a signal you can read to disable purchase buttons before initialize() completes:

readonly isInitialized = this.revenueService.isInitialized;

purchasePackage() returns false (not throws) when the user cancels the purchase dialog.

API Reference

Services

| Symbol | Description | |--------|-------------| | SubscriptionApiService | Calls GET {apiUrl}/status and returns Observable<SubscriberStatus>. Returns SubscriberStatus.free() on error. | | RevenueService | Wraps the RevenueCat SDK (web + native). Methods: initialize(userId), getOfferings(), purchasePackage(pkg), restorePurchases(), logout(). Signal: isInitialized. |

Guards

| Symbol | Description | |--------|-------------| | entitlementGuard | CanActivateFn — allows navigation when isPremium === true, redirects to upgradeRedirectPath otherwise. Fail-closed. |

Models

| Symbol | Description | |--------|-------------| | SubscriberStatus | User subscription state. Fields: isPremium, entitlement, expiresAt (Date \| null), activeSubscriptions. Factories: fromDto(), free(). | | Offering | RevenueCat offering. Fields: identifier, serverDescription, availablePackages. Factory: fromSdkOffering(). | | Package | RevenueCat package within an offering. Fields: identifier, packageType, product, rcBillingProduct. Factory: fromSdkPackage(). | | Product | RevenueCat product. Fields: identifier, title, description, priceString, price, currencyCode. Factory: fromSdkProduct(). |

Enums

| Symbol | Values | Description | |--------|--------|-------------| | ERevenuePlatform | IOS, ANDROID, STRIPE, AMAZON, MACOS, PLAY_STORE | Platform identifiers used by RevenueCat. | | ESubscriptionApiEndpoint | STATUS = '/status' | Backend endpoint paths appended to apiUrl. |

Configuration

| Symbol | Description | |--------|-------------| | IRevenueConfig | Config interface: publicKey, apiUrl, entitlementId, upgradeRedirectPath. | | RevenueConfigMapper | Maps flat app-config keys to IRevenueConfig. Required key: REVENUECAT_PUBLIC_KEY. | | REVENUE_CONFIGURATION | InjectionToken<IRevenueConfig> — inject to access config in custom services. |

DTOs

| Symbol | Description | |--------|-------------| | IApiResponse<TDto> | Generic backend response wrapper: status, messages?, data?. | | ISubscriberStatusResponseDto | Raw backend DTO: isPremium, entitlement, expiresAt, activeSubscriptions. |

Module

| Symbol | Description | |--------|-------------| | RevenueModule | NgModule with forRoot(config: IRevenueConfig): ModuleWithProviders<RevenueModule>. Registers all services. |

Peer Dependencies

| Package | Version | Required | |---------|---------|----------| | @angular/common | >=20.0.0 | Yes | | @angular/core | >=20.0.0 | Yes | | @angular/router | >=20.0.0 | Yes | | @revenuecat/purchases-js | >=1.0.0 | No (web purchase flows only) | | @revenuecat/purchases-capacitor | >=12.0.0 | No (native purchase flows only) | | @capacitor/core | >=6.0.0 | No (required alongside purchases-capacitor) |

The three RevenueCat/Capacitor packages are optional. Route protection and status checks work without them.

Backend Requirements

This library connects to a backend that implements the @sftech/nestjs-revenue API.

Required Endpoint:

  • GET /subscription/status — Returns the current user's subscription state.

Response Format:

{
    status: number;
    messages?: string[];
    data?: {
        isPremium: boolean;
        entitlement: string | null;
        expiresAt: string | null;       // ISO 8601 date string
        activeSubscriptions: string[];
    };
}

The endpoint is expected to be secured (authentication required). Token handling is delegated to @sftech/ng-auth — its authenticationInterceptor attaches the Bearer token to outgoing requests automatically.

Changelog

See CHANGELOG.md for a full history of changes.