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

@qasimha/react-native-sdk

v0.1.1

Published

React Native checkout module for Qasimha: presents a hosted checkout session in the system browser sheet, reports the outcome, and offers an instalment promo component.

Readme

@qasimha/react-native-sdk presents the Qasimha hosted checkout in the system browser sheet, detects the return to your app and resolves a typed result. Your server creates the session and hands the app a paymentUrl. The module also ships QasimhaPromo, an instalment summary for product, cart and checkout screens. No secret key lives on the device.

Requirements

| Item | Requirement | | :--- | :--- | | React Native | 0.72 or later | | React | 18 or 19 | | Android | minSdk 24, AndroidX, Kotlin 1.9+, a browser with Custom Tabs (falls back to the default browser) | | iOS | 13.4 or later, Swift 5.9. ASWebAuthenticationSession with an https return URL needs iOS 17.4. | | Optional | react-native-svg 13+ for the riyal symbol and logo in QasimhaPromo | | Server | A Qasimha server SDK that creates the checkout session. See Checkout flows. |

Install

npm install @qasimha/react-native-sdk
cd ios && pod install

Autolinking registers the native module on both platforms. Under the New Architecture it runs through the interop layer (enabled by default from React Native 0.74).

Set up the return into your app

App Links and Universal Links (https) are the secure choice. Custom schemes are simpler but can be claimed by other apps.

  1. Declare the return scheme in android/app/build.gradle. The build fails without it; set any unused value if you only use App Links.
android {
  defaultConfig {
    manifestPlaceholders = [qasimhaReturnScheme: "myshop"]
  }
}

myshop://qasimha/return then reaches your app.

  1. For App Links, add a verified intent filter to your main activity and publish /.well-known/assetlinks.json on that host:
<intent-filter android:autoVerify="true">
  <action android:name="android.intent.action.VIEW" />
  <category android:name="android.intent.category.DEFAULT" />
  <category android:name="android.intent.category.BROWSABLE" />
  <data android:scheme="https" android:host="shop.example" android:pathPrefix="/qasimha/return" />
</intent-filter>
  1. Keep android:launchMode="singleTask" on the main activity (the React Native template default). The return arrives through onNewIntent, which also closes the Custom Tab.
  1. Custom scheme: add it to Info.plist.
<key>CFBundleURLTypes</key>
<array>
  <dict>
    <key>CFBundleURLSchemes</key>
    <array><string>myshop</string></array>
  </dict>
</array>
  1. Universal Links: add the Associated Domains capability (applinks:shop.example) and publish /.well-known/apple-app-site-association on that host.

  2. Forward links to React Native's Linking in AppDelegate:

import React

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey: Any] = [:]) -> Bool {
  return RCTLinkingManager.application(app, open: url, options: options)
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity,
                 restorationHandler: @escaping ([UIUserActivityRestoring]?) -> Void) -> Bool {
  return RCTLinkingManager.application(application, continue: userActivity, restorationHandler: restorationHandler)
}

SFSafariViewController opens a Universal Link into your app only from a user tap. The hosted checkout shows a "Return to store" button on every final screen, so the shopper's tap brings the result back. Custom-scheme URLs and presentation: 'webAuthenticationSession' return without a tap.

Then pass every incoming link to handleReturn:

import { useEffect } from 'react';
import { Linking } from 'react-native';
import { handleReturn } from '@qasimha/react-native-sdk';

function useQasimhaReturn() {
  useEffect(() => {
    const subscription = Linking.addEventListener('url', ({ url }) => handleReturn(url));
    Linking.getInitialURL().then((url) => url && handleReturn(url));
    return () => subscription.remove();
  }, []);
}

handleReturn(url) returns true when the URL matched the pending checkout (the checkout resolves and the sheet closes), and false otherwise. Keep your own deep-link handling for the false case.

Start a checkout

Get paymentUrl from your server and pass the same three return URLs your server sent to POST /api/v1/pay/session/create.

import { startCheckout } from '@qasimha/react-native-sdk';

async function pay(paymentUrl: string) {
  const result = await startCheckout({
    paymentUrl,
    merchantUrl: {
      success: 'https://shop.example/qasimha/return?order=1001',
      failure: 'https://shop.example/qasimha/return?order=1001',
      cancel: 'https://shop.example/cart',
    },
    language: 'ar',
  });

  switch (result.type) {
    case 'success':
      await confirmOnServer(result.orderId);
      break;
    case 'failure':
      showDeclined(result.status);
      break;
    case 'cancelled':
      break;
  }
}

Options

| Option | Notes | | :--- | :--- | | paymentUrl | Required. The paymentUrl from session creation; https only. | | merchantUrl | Required: success, failure, cancel. Each absolute, at most 1024 characters, no fragment; https, http on localhost / 127.0.0.1, or a custom app scheme of at least 3 characters (javascript, data, file, blob, vbscript refused). | | presentation | systemBrowser (default: Android Custom Tabs, iOS SFSafariViewController) or webAuthenticationSession (iOS only; ephemeral, no shared cookies, needs no Linking wiring; the three URLs must share one custom scheme, or one https host and path on iOS 17.4+). | | language | ar or en. Sent as Accept-Language to the Custom Tab. The hosted checkout follows the shopper's browser language and offers an in-page toggle; this hint does not override it today. |

Give the cancel URL a dedicated path. Matching is a prefix on the path at a segment boundary, so a root-path return URL matches every link on that host.

There is no embedded WebView mode in this module. Use the native Android or iOS SDK if you need one.

Handle the result and confirm on your server

type CheckoutResult =
  | { type: 'success'; orderId: string; orderReferenceId?: string }
  | { type: 'failure'; status: string; orderId?: string; orderReferenceId?: string }
  | { type: 'cancelled' };
  • success: status=confirmed with an orderId.
  • failure: declined, expired or failed; unknown when the return URL matched but had no usable status, or confirmed without an orderId.
  • cancelled: status=cancelled, the cancel URL without a status, or the shopper dismissed the sheet. A dismissed sheet resolves after a 300 ms grace period so a return URL still in flight through Linking wins.

A return URL is navigation, not proof. Before showing "paid" or fulfilling, your server reads the order with its secret key (orders.get in the server SDKs, GET /api/v1/merchant/orders/{orderId}) and acts on the status it returns. Your server also receives the webhook, the durable record. Never change an order from the return URL parameters alone.

Rejections are QasimhaCheckoutError with a code: INVALID_OPTIONS (with field), IN_PROGRESS, NATIVE_MODULE_MISSING, NO_ACTIVITY, NO_VIEW_CONTROLLER, NO_BROWSER, UNSUPPORTED, PRESENTATION_FAILED, HOST_DESTROYED, INVALID_URL, NATIVE_ERROR.

Promo component

import { QasimhaPromo } from '@qasimha/react-native-sdk';

<QasimhaPromo amount={1200} publicKey="pk_test_..." lang="ar" textStyle={{ fontSize: 16, color: '#1f2937' }} />

| Prop | Notes | | :--- | :--- | | amount | Required. Positive, at most two decimals. | | publicKey | Required. pk_test_... or pk_live_.... | | lang | ar (default) or en. | | apiBaseUrl | Defaults by key prefix (pk_test_ to UAT, pk_live_ to production). https; http for localhost only. | | renderSymbol | Your own riyal symbol node. | | showLogo | Default true. | | onLearnMore | Adds a "Learn more" link that opens your own explainer. | | onPlan | Called with the headline plan, or null when nothing renders. Use it to hide a surrounding card. |

  • Calls GET /api/v1/widget/plans with X-Public-Key, a 5-second timeout, no cookies, no storage.
  • Fails closed: renders nothing, never a computed number, on invalid input, a failed request or an out-of-range amount.
  • Place it on product, cart and checkout screens, not in every list row: each mounted instance makes one request.

Release builds

  • Android: consumer R8 rules are shipped; nothing to add.
  • iOS: symbols are stripped in your release build with the rest of the app. The iOS module ships a privacy manifest declaring no tracking.
  • Metro and react-native-svg: the module loads react-native-svg with an optional require. Metro's resolver.allowOptionalDependencies is false by default, so an app without react-native-svg may fail to bundle. Install react-native-svg or set that option to true.

Security

  • No secret on the device. The only credential in the app is the publishable key for the promo, which the API scopes to reading plans.
  • TLS validation is the platform's; no option to disable it and no certificate pinning.
  • No storage, analytics or fingerprinting. Nothing is written to logs.
  • PCI DSS: card entry happens on the hosted checkout and the payment provider. You stay in SAQ-A scope.
  • App hardening: root/jailbreak detection, anti-tamper and runtime protection are recommended for apps that present payments. Use a RASP product or the platform's integrity APIs; the module does not perform them.

Troubleshooting

Add manifestPlaceholders = [qasimhaReturnScheme: "..."] to defaultConfig in android/app/build.gradle, even if you only use App Links.

Install react-native-svg 13+, or set Metro's resolver.allowOptionalDependencies to true. Without it, use renderSymbol to draw the riyal symbol.

The return link did not reach handleReturn. Check the Linking listener and getInitialURL() call, the AppDelegate forwarding on iOS, and singleTask on Android. On iOS with Universal Links, the shopper must tap "Return to store". Confirm the order on your server anyway.

A checkout is already open. Only one can run at a time.

Read field on the error. Usually a return URL has a fragment, uses http outside localhost, or uses a refused scheme.

The native module is not linked. Rebuild the app after install, and run pod install in ios/.

Expected today. The hosted checkout follows the shopper's browser language and offers an in-page toggle.

Related