npm package: @progalaxyelabs/stonescriptphp-ts-client
Description: Framework-agnostic TypeScript client for StoneScriptPHP backend
Author: Progalaxy E-Labs
Latest version: 1.0.0

# StoneScriptPHP TypeScript Client

[![npm version](https://img.shields.io/npm/v/@progalaxyelabs/stonescriptphp-ts-client.svg)](https://www.npmjs.com/package/@progalaxyelabs/stonescriptphp-ts-client)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)

A framework-agnostic TypeScript HTTP client for StoneScriptPHP backend applications. Works seamlessly with React, Vue, Angular, vanilla JavaScript, and any other frontend framework.

## Features

- **Framework Agnostic**: Works with any JavaScript framework or vanilla JS
- **Multiple Authentication Modes**: Cookie-based and body-based authentication
- **Automatic Token Refresh**: Built-in JWT token refresh with retry logic
- **CSRF Protection**: Configurable CSRF token handling for cookie-based auth
- **TypeScript Support**: Full TypeScript definitions included
- **Error Handling**: Comprehensive error classes for different scenarios
- **Flexible Storage**: Browser localStorage, sessionStorage, or memory storage
- **Type-Safe API**: Generic type support for request/response data

## Installation

```bash
npm install @progalaxyelabs/stonescriptphp-ts-client
```

or

```bash
yarn add @progalaxyelabs/stonescriptphp-ts-client
```

or

```bash
pnpm add @progalaxyelabs/stonescriptphp-ts-client
```

## Quick Start

### Basic Usage

```typescript
import { StoneScriptClient } from '@progalaxyelabs/stonescriptphp-ts-client';

// Initialize the client
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: {
    mode: 'cookie', // or 'body' or 'none'
    refreshEndpoint: '/auth/refresh',
    useCsrf: true
  }
});

// Make API requests
async function fetchUsers() {
  try {
    const users = await client.get<User[]>('/users');
    console.log(users);
  } catch (error) {
    console.error('Failed to fetch users:', error);
  }
}
```

### Authentication

#### Login

```typescript
// Login with credentials
await client.login('/auth/login', {
  email: 'user@example.com',
  password: 'password123'
});

// Check authentication status
if (client.isAuthenticated()) {
  console.log('User is authenticated');
}
```

#### Logout

```typescript
// Logout and optionally call logout endpoint
await client.logout('/auth/logout');
```

#### Auth State Monitoring

```typescript
// Subscribe to authentication state changes
const unsubscribe = client.onAuthChange((isAuthenticated) => {
  console.log('Auth state changed:', isAuthenticated);
});

// Clean up when needed
unsubscribe();
```

## Configuration

### Client Configuration

```typescript
interface ClientConfig {
  baseUrl: string;                          // API base URL (required)
  auth?: AuthConfig;                        // Authentication configuration
  timeout?: number;                         // Request timeout in ms (default: 30000)
  defaultHeaders?: Record<string, string>;  // Default headers for all requests
  debug?: boolean;                          // Enable debug logging (default: false)
}
```

### Authentication Configuration

```typescript
interface AuthConfig {
  mode: 'cookie' | 'body' | 'none';        // Authentication mode (required)
  refreshEndpoint?: string;                 // Token refresh endpoint (default: '/auth/refresh')
  useCsrf?: boolean;                        // Enable CSRF protection (default: true for cookie mode)
  refreshTokenCookieName?: string;          // Refresh token cookie name (default: 'refresh_token')
  csrfTokenCookieName?: string;             // CSRF token cookie name (default: 'csrf_token')
  csrfHeaderName?: string;                  // CSRF header name (default: 'X-CSRF-Token')
}
```

## Authentication Modes

### Cookie-Based Authentication (Recommended for web apps)

Best for web applications where you want the browser to handle cookie storage automatically.

```typescript
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: {
    mode: 'cookie',
    refreshEndpoint: '/auth/refresh',
    useCsrf: true,
    csrfTokenCookieName: 'csrf_token',
    csrfHeaderName: 'X-CSRF-Token'
  }
});
```

Features:
- Access token stored in localStorage/sessionStorage
- Refresh token stored in HTTP-only cookie
- Automatic CSRF token handling
- Credentials automatically included in requests

### Body-Based Authentication

Best for mobile apps or when you need full control over token storage.

```typescript
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: {
    mode: 'body',
    refreshEndpoint: '/auth/refresh'
  }
});
```

Features:
- Both access and refresh tokens stored in localStorage/sessionStorage
- Tokens sent in request body for refresh
- No cookie dependencies

### No Authentication

For public APIs or when authentication is handled externally.

```typescript
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: {
    mode: 'none'
  }
});
```

## API Methods

### HTTP Methods

All methods support generic typing for type-safe responses:

```typescript
// GET request
const users = await client.get<User[]>('/users');

// POST request
const newUser = await client.post<User>('/users', {
  name: 'John Doe',
  email: 'john@example.com'
});

// PUT request
const updatedUser = await client.put<User>('/users/123', {
  name: 'Jane Doe'
});

// PATCH request
const patchedUser = await client.patch<User>('/users/123', {
  email: 'jane@example.com'
});

// DELETE request
await client.delete('/users/123');
```

### Request Options

All HTTP methods accept optional request options:

```typescript
interface RequestOptions {
  params?: Record<string, any>;             // Query parameters
  headers?: Record<string, string>;         // Additional headers
  timeout?: number;                         // Override default timeout
  skipAuth?: boolean;                       // Skip authentication for this request
  skipRefresh?: boolean;                    // Skip token refresh on 401
  credentials?: RequestCredentials;         // Fetch credentials option
}
```

Example:

```typescript
// GET with query parameters and custom headers
const users = await client.get<User[]>('/users', {
  params: { page: 1, limit: 10 },
  headers: { 'X-Custom-Header': 'value' }
});

// POST without authentication
const data = await client.post('/public/newsletter',
  { email: 'user@example.com' },
  { skipAuth: true }
);
```

## Error Handling

The client provides specific error classes for different scenarios:

```typescript
import {
  ApiError,
  AuthError,
  ValidationError,
  NetworkError
} from '@progalaxyelabs/stonescriptphp-ts-client';

try {
  const user = await client.get<User>('/users/123');
} catch (error) {
  if (error instanceof AuthError) {
    console.error('Authentication failed:', error.message);
    // Redirect to login
  } else if (error instanceof ValidationError) {
    console.error('Validation errors:', error.errors);
    // Display field-specific errors
  } else if (error instanceof NetworkError) {
    console.error('Network error:', error.message);
    // Show offline message
  } else if (error instanceof ApiError) {
    console.error('API error:', error.message, error.statusCode);
    // Handle general API errors
  }
}
```

### Error Types

- **ApiError**: General API errors with status code
- **AuthError**: Authentication/authorization failures (401, 403)
- **ValidationError**: Validation failures (422) with field-specific errors
- **NetworkError**: Network connectivity issues

## Storage Options

By default, the client uses browser localStorage for token storage. You can customize this:

```typescript
import { BrowserStorage, MemoryStorage } from '@progalaxyelabs/stonescriptphp-ts-client';

// Use sessionStorage instead of localStorage
const sessionStore = new BrowserStorage('session');

// Use in-memory storage (tokens lost on page refresh)
const memoryStore = new MemoryStorage();

// Custom storage implementation
class CustomStorage implements TokenStorage {
  getItem(key: string): string | null {
    // Your implementation
  }
  setItem(key: string, value: string): void {
    // Your implementation
  }
  removeItem(key: string): void {
    // Your implementation
  }
}
```

## Framework Examples

### React

```typescript
import { StoneScriptClient } from '@progalaxyelabs/stonescriptphp-ts-client';
import { useEffect, useState } from 'react';

const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: { mode: 'cookie' }
});

function App() {
  const [isAuthenticated, setIsAuthenticated] = useState(client.isAuthenticated());

  useEffect(() => {
    const unsubscribe = client.onAuthChange(setIsAuthenticated);
    return unsubscribe;
  }, []);

  const handleLogin = async () => {
    await client.login('/auth/login', { email, password });
  };

  return <div>{isAuthenticated ? 'Logged in' : 'Logged out'}</div>;
}
```

### Vue 3

```typescript
import { StoneScriptClient } from '@progalaxyelabs/stonescriptphp-ts-client';
import { ref, onMounted, onUnmounted } from 'vue';

const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: { mode: 'cookie' }
});

export default {
  setup() {
    const isAuthenticated = ref(client.isAuthenticated());
    let unsubscribe: (() => void) | null = null;

    onMounted(() => {
      unsubscribe = client.onAuthChange((auth) => {
        isAuthenticated.value = auth;
      });
    });

    onUnmounted(() => {
      unsubscribe?.();
    });

    const login = async (email: string, password: string) => {
      await client.login('/auth/login', { email, password });
    };

    return { isAuthenticated, login };
  }
};
```

### Vanilla JavaScript

```javascript
import { StoneScriptClient } from '@progalaxyelabs/stonescriptphp-ts-client';

const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  auth: { mode: 'cookie' }
});

// Login
document.getElementById('loginBtn').addEventListener('click', async () => {
  const email = document.getElementById('email').value;
  const password = document.getElementById('password').value;

  try {
    await client.login('/auth/login', { email, password });
    console.log('Login successful');
  } catch (error) {
    console.error('Login failed:', error);
  }
});

// Fetch data
async function loadUsers() {
  try {
    const users = await client.get('/users');
    // Render users
  } catch (error) {
    console.error('Failed to load users:', error);
  }
}
```

## Advanced Usage

### Custom Headers

```typescript
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  defaultHeaders: {
    'X-API-Version': '1.0',
    'X-Client-App': 'MyApp'
  }
});
```

### Request Timeout

```typescript
// Global timeout
const client = new StoneScriptClient({
  baseUrl: 'https://api.example.com',
  timeout: 10000 // 10 seconds
});

// Per-request timeout
await client.get('/users', { timeout: 5000 });
```

### Manual Token Management

```typescript
// Get current access token
const token = client.getAccessToken();

// Check if user is authenticated
if (client.isAuthenticated()) {
  // Make authenticated requests
}
```

## API Response Format

The client expects StoneScriptPHP-compatible API responses:

```typescript
interface ApiResponse<T> {
  status: 'ok' | 'error';
  message?: string;
  data?: T;
  errors?: Record<string, string[]>;
}
```

Success response:
```json
{
  "status": "ok",
  "data": { "id": 1, "name": "John" }
}
```

Error response:
```json
{
  "status": "error",
  "message": "Validation failed",
  "errors": {
    "email": ["Email is required"],
    "password": ["Password must be at least 8 characters"]
  }
}
```

## Building and Development

```bash
# Install dependencies
npm install

# Build the library
npm run build

# Run tests
npm test

# Development mode with watch
npm run dev

# Lint code
npm run lint
```

## Browser Support

- Chrome (latest)
- Firefox (latest)
- Safari (latest)
- Edge (latest)

Requires ES2015+ environment with Fetch API support.

## TypeScript

This library is written in TypeScript and includes type definitions. No additional @types packages needed.

## License

MIT License - see LICENSE file for details.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## Support

For issues and questions, please use the [GitHub Issues](https://github.com/progalaxyelabs/stonescriptphp-ts-client/issues) page.

## Author

Progalaxy E-Labs

## Related Projects

- [StoneScriptPHP](https://github.com/progalaxyelabs/stonescriptphp) - The backend framework this client is designed for