npm package: @saivarunvaidya/recaptcha-universal-sdk
Description: Framework-agnostic reCAPTCHA v2 SDK with adapters for React, Angular, Vue, and vanilla JS
Author: Your Name
Latest version: 1.0.1

# @recaptcha/universal-sdk

> Framework-agnostic reCAPTCHA v2 SDK with adapters for React, Angular, Vue, and vanilla JavaScript

[![npm version](https://badge.fury.io/js/%40recaptcha%2Funiversal-sdk.svg)](https://www.npmjs.com/package/@recaptcha/universal-sdk)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

## 🎯 Features

- ✅ **Framework-Agnostic Core** - Pure TypeScript, zero dependencies
- ✅ **Multiple Framework Adapters** - React, Vue, Angular, Vanilla JS
- ✅ **TypeScript First** - Full type definitions included
- ✅ **SSR Safe** - Works with server-side rendering
- ✅ **Tree-Shakeable** - Only import what you need
- ✅ **Production Ready** - Comprehensive testing and error handling
- ✅ **Backend Integration** - Built-in verification service support
- ✅ **reCAPTCHA v2** - Support for Checkbox and Invisible variants

## 📦 Installation

```bash
npm install @recaptcha/universal-sdk
```

Or with yarn:

```bash
yarn add @recaptcha/universal-sdk
```

## 🚀 Quick Start

### React

```tsx
import { useRecaptcha } from '@recaptcha/universal-sdk/react';

function MyForm() {
  const { containerRef, token, isReady, verify } = useRecaptcha({
    siteKey: 'your-site-key',
    clientId: 'react-app',
    verifyUrl: 'https://api.example.com/captcha/verify',
    options: {
      size: 'normal',
      theme: 'light',
      callback: (token) => console.log('Token:', token)
    }
  });

  const handleSubmit = async () => {
    if (token) {
      const result = await verify();
      console.log('Verified:', result.success);
    }
  };

  return (
    <div>
      <div ref={containerRef}></div>
      <button onClick={handleSubmit} disabled={!token}>
        Submit
      </button>
    </div>
  );
}
```

### Vue 3

```vue
<script setup>
import { useRecaptcha } from '@recaptcha/universal-sdk/vue';

const { containerRef, token, isReady, verify } = useRecaptcha({
  siteKey: 'your-site-key',
  clientId: 'vue-app',
  verifyUrl: 'https://api.example.com/captcha/verify',
  options: {
    size: 'normal'
  }
});

const handleSubmit = async () => {
  if (token.value) {
    const result = await verify();
    console.log('Verified:', result.success);
  }
};
</script>

<template>
  <div>
    <div ref="containerRef"></div>
    <button @click="handleSubmit" :disabled="!token">Submit</button>
  </div>
</template>
```

### Angular

```typescript
import { Component, OnInit, AfterViewInit, ViewChild, ElementRef } from '@angular/core';
import { RecaptchaService } from '@recaptcha/universal-sdk/angular';

@Component({
  selector: 'app-form',
  template: `
    <div #recaptchaContainer></div>
    <button (click)="handleSubmit()" [disabled]="!(token$ | async)">
      Submit
    </button>
  `
})
export class FormComponent implements OnInit, AfterViewInit {
  @ViewChild('recaptchaContainer', { static: false }) container!: ElementRef;
  
  token$ = this.recaptchaService.token$;
  
  constructor(private recaptchaService: RecaptchaService) {}
  
  async ngOnInit() {
    await this.recaptchaService.init({
      siteKey: 'your-site-key',
      clientId: 'angular-app',
      verifyUrl: 'https://api.example.com/captcha/verify'
    });
  }
  
  ngAfterViewInit() {
    this.recaptchaService.render(this.container.nativeElement);
  }
  
  async handleSubmit() {
    const result = await this.recaptchaService.verify();
    console.log('Verified:', result.success);
  }
}
```

### Vanilla JavaScript

```javascript
import { VanillaRecaptcha } from '@recaptcha/universal-sdk/vanilla';

const recaptcha = new VanillaRecaptcha({
  siteKey: 'your-site-key',
  clientId: 'vanilla-app',
  verifyUrl: 'https://api.example.com/captcha/verify',
  options: {
    size: 'normal',
    callback: (token) => {
      console.log('Token received:', token);
      handleToken(token);
    }
  }
});

// Initialize
await recaptcha.init();

// Render
const container = document.getElementById('recaptcha-container');
recaptcha.render(container);

// Verify
async function handleToken(token) {
  const result = await recaptcha.verify(token);
  console.log('Verified:', result.success);
}
```

## 📚 API Documentation

### Core Configuration

```typescript
interface RecaptchaConfig {
  siteKey: string;              // Your reCAPTCHA site key
  clientId?: string;            // Client ID for backend verification
  verifyUrl?: string;           // Backend verification endpoint
  language?: string;            // Language code (e.g., 'en', 'es')
  options?: {
    size?: 'normal' | 'compact' | 'invisible';
    theme?: 'light' | 'dark';
    badge?: 'bottomright' | 'bottomleft' | 'inline';
    tabindex?: number;
    callback?: (token: string) => void;
    'expired-callback'?: () => void;
    'error-callback'?: () => void;
  };
}
```

### React Hook API

```typescript
const {
  containerRef,     // Ref for the container element
  execute,          // Execute invisible reCAPTCHA
  reset,            // Reset the widget
  getResponse,      // Get current token
  verify,           // Verify token with backend
  token,            // Current token (reactive)
  isReady,          // Is reCAPTCHA loaded
  isLoading,        // Is loading
  error,            // Error message
  widgetId          // Widget ID
} = useRecaptcha(config);
```

### Vue Composable API

```typescript
const {
  containerRef,     // Template ref for container
  execute,          // Execute invisible reCAPTCHA
  reset,            // Reset the widget
  getResponse,      // Get current token
  verify,           // Verify token with backend
  token,            // Current token (ref)
  isReady,          // Is reCAPTCHA loaded (ref)
  isLoading,        // Is loading (ref)
  error,            // Error message (ref)
  widgetId          // Widget ID (ref)
} = useRecaptcha(config);
```

### Angular Service API

```typescript
class RecaptchaService {
  token$: Observable<string | null>;
  isReady$: Observable<boolean>;
  isLoading$: Observable<boolean>;
  error$: Observable<string | null>;
  
  async init(config: RecaptchaConfig): Promise<void>;
  render(container: HTMLElement, config?: RecaptchaConfig): number;
  execute(): void;
  reset(): void;
  getResponse(): string;
  async verify(): Promise<VerifyResponse>;
}
```

### Vanilla Class API

```typescript
class VanillaRecaptcha {
  constructor(config: RecaptchaConfig);
  
  async init(): Promise<void>;
  render(container: HTMLElement | string): number;
  execute(): void;
  reset(): void;
  getResponse(): string;
  async verify(token?: string): Promise<VerifyResponse>;
  getToken(): string | null;
  isReady(): boolean;
  isLoading(): boolean;
  getError(): string | null;
}
```

## 🔒 Backend Integration

This SDK is designed to work with a centralized backend verification service:

### Verification Request

```json
POST https://api.example.com/captcha/verify

{
  "token": "03AGdBq27...",
  "clientId": "react-app"
}
```

### Verification Response

```json
{
  "success": true,
  "timestamp": "2024-01-01T12:00:00Z",
  "challengeTs": "2024-01-01T11:59:55Z",
  "hostname": "example.com"
}
```

See the [backend service documentation](../../backend/captcha-service/README.md) for implementation details.

## 🎨 Invisible reCAPTCHA

For invisible reCAPTCHA (no visible widget):

### React

```tsx
const { containerRef, execute, token } = useInvisibleRecaptcha({
  siteKey: 'your-site-key',
  clientId: 'react-app',
  verifyUrl: 'https://api.example.com/captcha/verify'
});

const handleSubmit = () => {
  execute(); // Triggers the challenge
};

useEffect(() => {
  if (token) {
    // Token received, submit form
  }
}, [token]);
```

### Vue

```vue
<script setup>
const { containerRef, execute, token } = useInvisibleRecaptcha({
  siteKey: 'your-site-key',
  clientId: 'vue-app',
  verifyUrl: 'https://api.example.com/captcha/verify'
});

const handleSubmit = () => {
  execute();
};

watch(token, (newToken) => {
  if (newToken) {
    // Token received, submit form
  }
});
</script>
```

## 🧪 Testing

The SDK includes comprehensive unit tests:

```bash
# Run tests
npm test

# Run tests with coverage
npm run test:coverage

# Watch mode
npm run test:watch
```

## 🔧 Advanced Usage

### Custom Script Loading

```typescript
import { loadRecaptchaScript, renderRecaptcha } from '@recaptcha/universal-sdk';

// Load script with custom language
await loadRecaptchaScript('es');

// Render widget
const container = document.getElementById('recaptcha');
const widgetId = renderRecaptcha(container, {
  siteKey: 'your-site-key',
  options: { theme: 'dark' }
});
```

### Manual Verification

```typescript
import { verifyRecaptchaToken } from '@recaptcha/universal-sdk';

const result = await verifyRecaptchaToken('token', {
  siteKey: 'your-site-key',
  verifyUrl: 'https://api.example.com/captcha/verify',
  clientId: 'my-app'
});

if (result.success) {
  console.log('Verification successful');
}
```

## 🌍 SSR Support

The SDK is SSR-safe and will gracefully handle server-side environments:

```typescript
// Next.js example
'use client';

import { useRecaptcha } from '@recaptcha/universal-sdk/react';

export default function ContactForm() {
  const { containerRef, token } = useRecaptcha({
    siteKey: process.env.NEXT_PUBLIC_RECAPTCHA_SITE_KEY!,
    clientId: 'nextjs-app',
    verifyUrl: '/api/captcha/verify'
  });

  // Component implementation
}
```

## 🤝 Contributing

Contributions are welcome! Please see [CONTRIBUTING.md](../../CONTRIBUTING.md) for guidelines.

## 📝 License

MIT License - see [LICENSE](../../LICENSE) for details.

## 🔗 Links

- [Backend Service](../../backend/captcha-service/README.md)
- [Examples](../../examples/)
- [Architecture Documentation](../../docs/architecture.md)
- [Security Best Practices](../../docs/security.md)

## 💡 Support

- 📫 [GitHub Issues](https://github.com/your-org/recaptcha-production/issues)
- 📖 [Documentation](https://github.com/your-org/recaptcha-production/docs)
- 💬 [Discussions](https://github.com/your-org/recaptcha-production/discussions)

---

**Built with ❤️ for production use**