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

@cardql/react-native

v1.0.1

Published

CardQL SDK for React Native applications with mobile-optimized features

Readme

@cardql/react-native

CardQL SDK for React Native applications with mobile-optimized features including offline support, secure storage, and native UI components.

Installation

npm install @cardql/react-native
# or
yarn add @cardql/react-native
# or
pnpm add @cardql/react-native

Additional Dependencies

For full functionality, you may want to install these optional dependencies:

# For secure storage (recommended)
npm install react-native-keychain
# or for Expo
npm install expo-secure-store

# For network status monitoring (recommended)
npm install @react-native-community/netinfo

# For persistent storage
npm install @react-native-async-storage/async-storage

Quick Start

1. Setup Provider

Wrap your app with the CardQL provider:

import React from "react";
import { CardQLProvider } from "@cardql/react-native";

function App() {
  return (
    <CardQLProvider
      config={{
        apiKey: "your-api-key",
        endpoint: "https://api.cardql.com/graphql",
      }}
      enableOfflineMode={true}
      enableSecureStorage={true}>
      <YourApp />
    </CardQLProvider>
  );
}

2. Use Hooks

Use CardQL hooks in your components:

import React from "react";
import { View, Text, TouchableOpacity, FlatList } from "react-native";
import { usePayments, useCreatePayment } from "@cardql/react-native";

function PaymentScreen() {
  const { data: paymentsData, loading, error } = usePayments();
  const createPayment = useCreatePayment({
    onSuccess: (data) => {
      console.log("Payment created:", data.createPayment);
    },
  });

  const handleCreatePayment = async () => {
    await createPayment.mutateAsync({
      amount: "10.00",
      currency: "USD",
      merchantID: "merchant_123",
      userID: "user_456",
    });
  };

  if (loading) return <Text>Loading...</Text>;
  if (error) return <Text>Error: {error.message}</Text>;

  return (
    <View>
      <TouchableOpacity
        onPress={handleCreatePayment}
        disabled={createPayment.loading}>
        <Text>{createPayment.loading ? "Creating..." : "Create Payment"}</Text>
      </TouchableOpacity>

      <FlatList
        data={paymentsData?.payments}
        keyExtractor={(item) => item.id}
        renderItem={({ item }) => (
          <Text>
            {item.amount} {item.currency} - {item.status}
          </Text>
        )}
      />
    </View>
  );
}

3. Use Payment Sheet

Use the pre-built payment sheet:

import React, { useState } from "react";
import { View, TouchableOpacity, Text } from "react-native";
import { PaymentSheet } from "@cardql/react-native";

function CheckoutScreen() {
  const [showPaymentSheet, setShowPaymentSheet] = useState(false);

  return (
    <View>
      <TouchableOpacity onPress={() => setShowPaymentSheet(true)}>
        <Text>Pay Now</Text>
      </TouchableOpacity>

      <PaymentSheet
        visible={showPaymentSheet}
        onClose={() => setShowPaymentSheet(false)}
        merchantID="merchant_123"
        userID="user_456"
        onSuccess={(payment) => {
          console.log("Payment successful:", payment);
          // Navigate to success screen
        }}
        onError={(error) => {
          console.error("Payment failed:", error);
        }}
      />
    </View>
  );
}

Mobile-Specific Features

Offline Support

The React Native SDK includes built-in offline support:

import React from "react";
import { useOfflineQueue, useIsOnline } from "@cardql/react-native";

function OfflineAwareComponent() {
  const isOnline = useIsOnline();
  const { queue, addToQueue, processQueue } = useOfflineQueue();

  const handleOfflinePayment = async () => {
    if (!isOnline) {
      // Add to offline queue
      await addToQueue(CREATE_PAYMENT, {
        amount: "25.99",
        currency: "USD",
        merchantID: "merchant_123",
        userID: "user_456",
      });
    }
  };

  return (
    <View>
      <Text>Status: {isOnline ? "Online" : "Offline"}</Text>
      <Text>Queued Operations: {queue.length}</Text>
      {!isOnline && (
        <TouchableOpacity onPress={handleOfflinePayment}>
          <Text>Create Payment (Offline)</Text>
        </TouchableOpacity>
      )}
    </View>
  );
}

Secure Storage

API keys and sensitive data are automatically stored securely:

import React from "react";
import { useCardQL } from "@cardql/react-native";

function AuthComponent() {
  const { updateApiKey, clearStoredData } = useCardQL();

  const handleLogin = async (apiKey: string) => {
    // API key will be securely stored
    await updateApiKey(apiKey);
  };

  const handleLogout = async () => {
    // Clear all stored data
    await clearStoredData();
  };

  return (
    <View>
      <TouchableOpacity onPress={() => handleLogin("new-api-key")}>
        <Text>Login</Text>
      </TouchableOpacity>
      <TouchableOpacity onPress={handleLogout}>
        <Text>Logout</Text>
      </TouchableOpacity>
    </View>
  );
}

Network Status Monitoring

Monitor network connectivity:

import React from "react";
import {
  useNetworkStatus,
  useIsOnline,
  useIsOffline,
  useNetworkType,
} from "@cardql/react-native";

function NetworkStatusComponent() {
  const networkStatus = useNetworkStatus();
  const isOnline = useIsOnline();
  const isOffline = useIsOffline();
  const networkType = useNetworkType();

  return (
    <View>
      <Text>Connected: {isOnline ? "Yes" : "No"}</Text>
      <Text>Network Type: {networkType || "Unknown"}</Text>
      <Text>WiFi Enabled: {networkStatus.isWifiEnabled ? "Yes" : "No"}</Text>
    </View>
  );
}

API Reference

Provider Props

interface CardQLProviderProps {
  config: CardQLConfig;
  children: ReactNode;
  enableOfflineMode?: boolean; // Default: false
  enableSecureStorage?: boolean; // Default: true
  apiKeyStorageKey?: string; // Default: 'cardql_api_key'
}

Context Value

interface CardQLContextValue {
  cardql: CardQL;
  config: CardQLConfig;
  isOnline: boolean;
  enableOfflineMode: boolean;
  updateApiKey: (apiKey: string) => Promise<void>;
  clearStoredData: () => Promise<void>;
}

Offline Queue

const {
  queue, // Array of queued operations
  addToQueue, // Add operation to queue
  processQueue, // Process all queued operations
  clearQueue, // Clear the queue
  removeFromQueue, // Remove specific operation
  isProcessing, // Whether queue is being processed
} = useOfflineQueue({
  maxRetries: 3, // Maximum retry attempts
  retryDelay: 1000, // Delay between retries (ms)
  storageKey: "custom_queue_key",
});

Payment Sheet

<PaymentSheet
  visible={boolean}
  onClose={() => void}
  merchantID={string}
  userID={string}
  onSuccess={(payment) => void}
  onError={(error) => void}
  defaultAmount="10.00"
  defaultCurrency="USD"
  defaultDescription="Payment"
  // Styling props
  style={ViewStyle}
  headerStyle={ViewStyle}
  inputStyle={TextStyle}
  buttonStyle={ViewStyle}
  buttonTextStyle={TextStyle}
/>

Advanced Usage

Custom Storage Implementation

Replace the default storage with your own:

import { Storage } from "@cardql/react-native";
import AsyncStorage from "@react-native-async-storage/async-storage";
import * as Keychain from "react-native-keychain";

class CustomSecureStorage implements Storage {
  async getItem(key: string): Promise<string | null> {
    try {
      const credentials = await Keychain.getInternetCredentials(key);
      return credentials ? credentials.password : null;
    } catch {
      return null;
    }
  }

  async setItem(key: string, value: string): Promise<void> {
    await Keychain.setInternetCredentials(key, key, value);
  }

  async removeItem(key: string): Promise<void> {
    await Keychain.resetInternetCredentials(key);
  }

  async clear(): Promise<void> {
    await Keychain.resetGenericPassword();
  }
}

// Use custom storage
export const customStorage = new CustomSecureStorage();

Offline-First Architecture

Build an offline-first app:

import React, { useEffect } from "react";
import {
  useOfflineQueue,
  useIsOnline,
  usePayments,
} from "@cardql/react-native";

function OfflineFirstComponent() {
  const isOnline = useIsOnline();
  const { queue, processQueue } = useOfflineQueue();
  const { data: payments, refetch } = usePayments({
    enabled: isOnline, // Only fetch when online
  });

  // Auto-sync when coming back online
  useEffect(() => {
    if (isOnline) {
      processQueue();
      refetch();
    }
  }, [isOnline, processQueue, refetch]);

  return (
    <View>
      {!isOnline && (
        <Text style={{ color: "orange" }}>
          Offline mode - {queue.length} operations queued
        </Text>
      )}
      {/* Your UI */}
    </View>
  );
}

Background Sync

Handle background synchronization:

import { useEffect } from "react";
import { AppState } from "react-native";
import { useOfflineQueue } from "@cardql/react-native";

function BackgroundSyncHandler() {
  const { processQueue } = useOfflineQueue();

  useEffect(() => {
    const handleAppStateChange = (nextAppState: string) => {
      if (nextAppState === "active") {
        // App came to foreground, process queue
        processQueue();
      }
    };

    const subscription = AppState.addEventListener(
      "change",
      handleAppStateChange
    );
    return () => subscription?.remove();
  }, [processQueue]);

  return null;
}

Error Handling

Handle mobile-specific errors:

import { Alert } from "react-native";
import { useCreatePayment } from "@cardql/react-native";

function PaymentWithErrorHandling() {
  const createPayment = useCreatePayment({
    onError: (error, variables) => {
      // Handle different error types
      if (error.code === "NETWORK_ERROR") {
        Alert.alert(
          "Network Error",
          "Please check your internet connection and try again.",
          [{ text: "OK" }]
        );
      } else if (error.code === "VALIDATION_ERROR") {
        Alert.alert("Invalid Payment", "Please check your payment details.", [
          { text: "OK" },
        ]);
      } else {
        Alert.alert(
          "Payment Failed",
          "An unexpected error occurred. Please try again.",
          [{ text: "OK" }]
        );
      }
    },
  });

  // Component implementation...
}

Styling

The PaymentSheet component can be fully customized:

const customStyles = {
  container: {
    backgroundColor: "#f5f5f5",
  },
  header: {
    backgroundColor: "#007bff",
    paddingVertical: 20,
  },
  title: {
    color: "#fff",
    fontSize: 20,
    fontWeight: "bold",
  },
  input: {
    borderRadius: 12,
    paddingHorizontal: 20,
    paddingVertical: 15,
    fontSize: 16,
    backgroundColor: "#fff",
    shadowColor: "#000",
    shadowOffset: { width: 0, height: 2 },
    shadowOpacity: 0.1,
    shadowRadius: 4,
    elevation: 3,
  },
  button: {
    backgroundColor: "#28a745",
    paddingVertical: 18,
    borderRadius: 12,
  },
  buttonText: {
    fontSize: 18,
    fontWeight: "bold",
  },
};

<PaymentSheet
  style={customStyles.container}
  headerStyle={customStyles.header}
  inputStyle={customStyles.input}
  buttonStyle={customStyles.button}
  buttonTextStyle={customStyles.buttonText}
  // ... other props
/>;

Best Practices

1. Always Handle Offline States

// ✅ Good - Handle offline gracefully
function PaymentButton() {
  const isOnline = useIsOnline();
  const { addToQueue } = useOfflineQueue();
  const createPayment = useCreatePayment();

  const handlePayment = async (paymentData) => {
    if (isOnline) {
      await createPayment.mutateAsync(paymentData);
    } else {
      await addToQueue(CREATE_PAYMENT, paymentData);
      Alert.alert("Offline", "Payment queued for when you're back online");
    }
  };

  return (
    <TouchableOpacity onPress={() => handlePayment(data)}>
      <Text>{isOnline ? "Pay Now" : "Queue Payment"}</Text>
    </TouchableOpacity>
  );
}

2. Secure Storage for Sensitive Data

// ✅ Good - Use secure storage for API keys
<CardQLProvider
  config={{ endpoint: 'https://api.cardql.com/graphql' }}
  enableSecureStorage={true}
  apiKeyStorageKey="my_app_cardql_key"
>
  <App />
</CardQLProvider>

// ❌ Avoid - Don't hardcode API keys
<CardQLProvider
  config={{
    apiKey: 'hardcoded-key',  // Don't do this
    endpoint: 'https://api.cardql.com/graphql'
  }}
>
  <App />
</CardQLProvider>

3. Provide Feedback for Long Operations

function PaymentForm() {
  const createPayment = useCreatePayment();

  return (
    <View>
      <TouchableOpacity
        onPress={handleSubmit}
        disabled={createPayment.loading}
        style={[styles.button, createPayment.loading && styles.buttonDisabled]}>
        {createPayment.loading ? (
          <ActivityIndicator color="#fff" />
        ) : (
          <Text>Create Payment</Text>
        )}
      </TouchableOpacity>
    </View>
  );
}

Platform-Specific Considerations

iOS

  • Ensure you have the Keychain sharing capability enabled for secure storage
  • Test with different network conditions using Network Link Conditioner

Android

  • Add INTERNET permission in AndroidManifest.xml
  • Consider Android's battery optimization settings for background sync

License

MIT

Support

For support, please contact the CardQL team or visit our documentation.