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

@redclover/koru-react-sdk

v1.0.2

Published

Lightweight React SDK for Koru platform authorization and integration

Downloads

8

Readme

@redclover/koru-react-sdk

Lightweight React SDK for Koru platform authorization and integration

npm version Bundle Size License

A modern, lightweight React SDK for seamless integration with the Koru platform. Provides hooks, components, and utilities for authorization, configuration management, and protected routes.

✨ Features

  • 🪝 React Hooks - useKoruAuth, useKoruConfig for easy state access
  • 🔐 Authorization - Automatic authorization with Koru platform
  • 💾 Smart Caching - Configurable localStorage caching with TTL
  • 🔄 Retry Logic - Exponential backoff retry for failed requests
  • 🛡️ Protected Routes - KoruProtected component for auth-gated content
  • 📦 Tiny Bundle - < 5KB gzipped
  • 🎯 TypeScript - Full TypeScript support with type definitions
  • ⚛️ React 16.8+ - Works with React 16.8+ (hooks support)
  • 🚀 Zero Dependencies - No runtime dependencies except React

📦 Installation

npm install @redclover/koru-react-sdk
yarn add @redclover/koru-react-sdk
pnpm add @redclover/koru-react-sdk

🚀 Quick Start

1. Wrap your app with KoruProvider

import { KoruProvider } from '@redclover/koru-react-sdk';

function App() {
  return (
    <KoruProvider
      websiteId="your-website-id"
      appId="your-app-id"
      koruUrl="https://app.koru.com"
      options={{ cache: true, debug: true }}
    >
      <YourApp />
    </KoruProvider>
  );
}

2. Use hooks to access auth state

import { useKoruAuth } from '@redclover/koru-react-sdk';

function MyComponent() {
  const { isAuthorized, loading, error, config, token, reload } = useKoruAuth();

  if (loading) return <div>Loading...</div>;
  if (error) return <div>Error: {error.message}</div>;
  if (!isAuthorized) return <div>Not authorized</div>;

  return (
    <div>
      <h1>Welcome!</h1>
      <pre>{JSON.stringify(config, null, 2)}</pre>
      <button onClick={reload}>Refresh Auth</button>
    </div>
  );
}

3. Protect components with KoruProtected

import { KoruProtected } from '@redclover/koru-react-sdk';

function App() {
  return (
    <KoruProtected
      loading={<div>Checking authorization...</div>}
      fallback={<div>Access denied</div>}
    >
      <ProtectedContent />
    </KoruProtected>
  );
}

📚 API Reference

<KoruProvider>

Context provider that wraps your app to provide Koru authorization.

Props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | websiteId | string | ✅ | Unique website identifier from Koru | | appId | string | ✅ | Unique app identifier from Koru | | koruUrl | string | ✅ | Base URL of Koru platform | | options | KoruOptions | ❌ | Configuration options | | children | ReactNode | ✅ | Child components |

Options:

interface KoruOptions {
  cache?: boolean;          // Enable caching (default: true)
  cacheDuration?: number;   // Cache TTL in seconds (default: 3600)
  retryAttempts?: number;   // Retry attempts (default: 3)
  retryDelay?: number;      // Retry delay in ms (default: 1000)
  debug?: boolean;          // Enable debug logging (default: false)
}

useKoruAuth()

Hook to access Koru authorization state and data.

Returns:

{
  isAuthorized: boolean;     // Whether app is authorized
  loading: boolean;          // Whether authorization is in progress
  error: Error | null;       // Error if authorization failed
  authData: AuthResponse | null;  // Full auth response
  token: string | null;      // Auth token for API calls
  config: KoruConfig | null; // App configuration
  reload: () => Promise<void>;    // Refresh authorization
}

Example:

function Dashboard() {
  const { isAuthorized, config, token, reload } = useKoruAuth();

  const fetchData = async () => {
    const response = await fetch('/api/data', {
      headers: { Authorization: `Bearer ${token}` }
    });
    return response.json();
  };

  return (
    <div>
      <h1>{config.title}</h1>
      <button onClick={reload}>Refresh</button>
    </div>
  );
}

useKoruConfig()

Convenience hook to access only the configuration object.

Returns:

{
  config: KoruConfig | null;  // App configuration
  loading: boolean;           // Whether loading
  error: Error | null;        // Error if any
}

Example:

function Settings() {
  const { config, loading } = useKoruConfig();

  if (loading) return <div>Loading...</div>;

  return (
    <div>
      <h1>Settings</h1>
      <p>API URL: {config.apiUrl}</p>
      <p>Theme: {config.theme}</p>
    </div>
  );
}

<KoruProtected>

Component that wraps content requiring authorization.

Props:

| Prop | Type | Required | Description | |------|------|----------|-------------| | fallback | ReactNode | ❌ | UI to show when not authorized | | loading | ReactNode | ❌ | UI to show while loading | | children | ReactNode | ✅ | Protected content |

Example:

<KoruProtected
  loading={<Spinner />}
  fallback={<AccessDenied />}
>
  <AdminPanel />
</KoruProtected>

🎯 Usage Examples

Basic Usage

import { KoruProvider, useKoruAuth } from '@redclover/koru-react-sdk';

function App() {
  return (
    <KoruProvider
      websiteId="ws_123"
      appId="app_456"
      koruUrl="https://app.koru.com"
    >
      <Dashboard />
    </KoruProvider>
  );
}

function Dashboard() {
  const { isAuthorized, loading, config } = useKoruAuth();

  if (loading) return <div>Loading...</div>;
  if (!isAuthorized) return <div>Not authorized</div>;

  return <div>Welcome to {config.appName}</div>;
}

With Custom Options

<KoruProvider
  websiteId="ws_123"
  appId="app_456"
  koruUrl="https://app.koru.com"
  options={{
    cache: true,
    cacheDuration: 7200,  // 2 hours
    retryAttempts: 5,
    retryDelay: 2000,
    debug: process.env.NODE_ENV === 'development'
  }}
>
  <App />
</KoruProvider>

Protected Routes

import { BrowserRouter, Routes, Route } from 'react-router-dom';
import { KoruProtected } from '@redclover/koru-react-sdk';

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route
          path="/dashboard"
          element={
            <KoruProtected fallback={<Navigate to="/login" />}>
              <Dashboard />
            </KoruProtected>
          }
        />
      </Routes>
    </BrowserRouter>
  );
}

Using Auth Token for API Calls

function DataFetcher() {
  const { token, isAuthorized } = useKoruAuth();
  const [data, setData] = useState(null);

  useEffect(() => {
    if (isAuthorized && token) {
      fetch('https://api.example.com/data', {
        headers: {
          'Authorization': `Bearer ${token}`,
          'Content-Type': 'application/json'
        }
      })
        .then(res => res.json())
        .then(setData);
    }
  }, [isAuthorized, token]);

  return <div>{JSON.stringify(data)}</div>;
}

Manual Reload

function RefreshButton() {
  const { reload, loading } = useKoruAuth();

  return (
    <button onClick={reload} disabled={loading}>
      {loading ? 'Refreshing...' : 'Refresh Authorization'}
    </button>
  );
}

🔧 Advanced Usage

Environment Variables

# .env
REACT_APP_KORU_WEBSITE_ID=ws_123
REACT_APP_KORU_APP_ID=app_456
REACT_APP_KORU_URL=https://app.koru.com
<KoruProvider
  websiteId={process.env.REACT_APP_KORU_WEBSITE_ID}
  appId={process.env.REACT_APP_KORU_APP_ID}
  koruUrl={process.env.REACT_APP_KORU_URL}
>
  <App />
</KoruProvider>

Next.js Usage

// pages/_app.tsx
import { KoruProvider } from '@redclover/koru-react-sdk';

function MyApp({ Component, pageProps }) {
  return (
    <KoruProvider
      websiteId={process.env.NEXT_PUBLIC_KORU_WEBSITE_ID}
      appId={process.env.NEXT_PUBLIC_KORU_APP_ID}
      koruUrl={process.env.NEXT_PUBLIC_KORU_URL}
    >
      <Component {...pageProps} />
    </KoruProvider>
  );
}

export default MyApp;

Error Handling

function ErrorBoundary() {
  const { error, isAuthorized, reload } = useKoruAuth();

  if (error) {
    return (
      <div>
        <h1>Authorization Error</h1>
        <p>{error.message}</p>
        <button onClick={reload}>Retry</button>
      </div>
    );
  }

  return <YourApp />;
}

🧪 TypeScript Support

Full TypeScript support with comprehensive type definitions:

import type {
  KoruConfig,
  AuthResponse,
  KoruOptions,
  UseKoruAuthReturn,
  UseKoruConfigReturn,
} from '@redclover/koru-react-sdk';

// Custom config type
interface MyAppConfig extends KoruConfig {
  apiUrl: string;
  theme: 'light' | 'dark';
  features: string[];
}

function MyComponent() {
  const { config } = useKoruAuth();
  const typedConfig = config as MyAppConfig;
  
  return <div>{typedConfig.apiUrl}</div>;
}

📊 Bundle Size

The SDK is optimized for minimal bundle size:

  • Minified: ~8KB
  • Minified + Gzipped: ~3KB
  • Zero runtime dependencies (except React)

🤝 Contributing

Contributions are welcome! Please read our Contributing Guide for details.

📄 License

UNLICENSED - © Red Clover

🔗 Links

💬 Support

For support, email [email protected] or open an issue on GitHub.