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

@jeonghwanko/onesub-sdk

v0.6.7

Published

React Native SDK for in-app subscriptions. useOneSub() hook + Paywall component. Built on react-native-iap.

Downloads

3,155

Readme

@jeonghwanko/onesub-sdk

React Native SDK for onesub — drop-in useOneSub() hook + <Paywall /> component built on react-native-iap v15.

npm install @jeonghwanko/onesub-sdk react-native-iap

Usage

import { OneSubProvider, useOneSub } from '@jeonghwanko/onesub-sdk';

// Wrap your app
<OneSubProvider config={{ serverUrl: 'https://api.yourapp.com', productId: 'pro_monthly' }} userId={userId}>
  <App />
</OneSubProvider>

// In any component
function PaywallScreen() {
  const { isActive, subscribe, restore, purchaseProduct, restoreProduct } = useOneSub();

  // Subscriptions
  if (!isActive) return <Button onPress={subscribe} title="Subscribe" />;

  // One-time products
  const result = await purchaseProduct('credits_100', 'consumable');
  // result: null on cancel, (PurchaseInfo & { action?: 'new' | 'restored' }) on success

  // Restore a non-consumable
  const restored = await restoreProduct('premium_unlock', 'non_consumable');
}

Config options

| Option | Purpose | |--------|---------| | serverUrl | Base URL of your @onesub/server backend | | productId | Default subscription product ID | | appleProductId / googleProductId | Platform-specific overrides (optional) | | mockMode | Return synthetic success without calling react-native-iap or the server. For Expo Go / simulator UI testing. Never enable in production. | | debug | When true, emit verbose [onesub] traces at every step (IAP connection, listener events, in-flight matches, server validations, finishTransaction, drain transitions). Recommended when diagnosing an integration. | | logger | Custom log sink ({ info, warn, error }). Defaults to console. Works with pino / winston / any compatible logger. |

Debug mode

Set debug: true to see what the SDK is actually doing:

<OneSubProvider
  config={{ serverUrl, productId, debug: __DEV__ }}
  userId={userId}
>
  <App />
</OneSubProvider>

Sample output when a user subscribes:

[onesub] provider mount { serverUrl: ..., userId: 'user_1', mockMode: false }
[onesub] initConnection start
[onesub] initConnection ok
[onesub] listeners attached; drain window open { drainMs: 2500 }
[onesub] drain released { reason: 'timeout', waiters: 0 }
[onesub] subscribe() called { productId: 'pro_monthly', drainReady: true }
[onesub] event received { productId: 'pro_monthly', transactionId: 'tx_42', productType: 'subs', hasInFlight: true, matchingAllowed: true, matched: true }
[onesub] validating { productId: 'pro_monthly', platform: 'apple', kind: 'subscription' }
[onesub] subscription validated { productId: 'pro_monthly', action: 'new', active: true }

If something goes wrong, trace shows exactly where: the matched flag distinguishes in-flight matches from orphan replays, matchingAllowed reveals drain-window state, and action: 'restored' vs 'new' tells you whether the server treated the receipt as a first-time purchase.

Structured errors

Every Error thrown by the SDK is a OneSubError with a machine-readable code:

import { OneSubError, ONESUB_ERROR_CODE } from '@jeonghwanko/onesub-sdk';

try {
  await purchaseProduct('premium', 'non_consumable');
} catch (err) {
  if (err instanceof OneSubError) {
    switch (err.code) {
      case ONESUB_ERROR_CODE.USER_CANCELLED: return;
      case ONESUB_ERROR_CODE.NON_CONSUMABLE_ALREADY_OWNED:
        return Alert.alert('이미 구매한 상품입니다.');
      case ONESUB_ERROR_CODE.PURCHASE_TIMEOUT:
      case ONESUB_ERROR_CODE.NETWORK_ERROR:
        return Alert.alert('네트워크 상태를 확인해주세요.');
      default:
        return Alert.alert('결제 실패', err.message);
    }
  }
  throw err;
}

Requirements

  • react-native-iap v15+ (event-based purchase flow)
  • React Native 0.71+
  • @onesub/server running somewhere reachable

Links

MIT © onesub contributors.