# Softypy Media Service

A robust TypeScript/JavaScript package for seamless media file management through a RESTful API. Handle uploads, transformations, thumbnails, and more with ease.

## Features

- File uploads with optional transformations and metadata
- File retrieval with on-the-fly transformations
- Automatic thumbnail generation
- Custom file transformations (resize, format conversion, quality adjustment)
- Secure file deletion
- Built-in TypeScript support
- Comprehensive error handling

## Installation

Install using npm:

```bash
npm install softypy-media-service
```

Or using yarn:

```bash
yarn add softypy-media-service
```

## Quick Start

```typescript
import { configureMediaService, getMediaService } from 'softypy-media-service';

// Configure the service (do this once at app initialization)
configureMediaService({
  baseUrl: 'https://api.example.com/media',
  apiKey: 'your-api-key'
});

// Get the configured service instance
const mediaService = getMediaService();

// Upload a file
const uploadFile = async () => {
  const file = new File(['content'], 'example.jpg', { type: 'image/jpeg' });
  try {
    const response = await mediaService.uploadFile(file, {
      transform: {
        width: 800,
        height: 600,
        format: 'webp',
        quality: 85
      },
      metadata: {
        description: 'Product image'
      }
    });
    console.log('File uploaded:', response.publicId);
  } catch (error) {
    console.error('Upload failed:', error);
  }
};
```

## API Reference

### Configuration

```typescript
// Configure once at application startup
configureMediaService({
  baseUrl: 'https://api.example.com/media',
  apiKey: 'your-api-key',
  timeout: 60000, // optional, default is 30000ms
  retryAttempts: 3 // optional
});

// Get the configured service instance anywhere in your app
const mediaService = getMediaService();
```

### MediaService Methods

#### Upload File

```typescript
uploadFile(
  file: File,
  options?: {
    transform?: TransformOptions;
    metadata?: Record<string, any>;
  }
): Promise<UploadResponse>
```

#### Get File

```typescript
getFile(
  publicId: string,
  transform?: TransformOptions
): Promise<FileResponse>
```

#### Get Thumbnail

```typescript
getThumbnail(
  publicId: string
): Promise<FileResponse>
```

#### Transform File

```typescript
getTransformedFile(
  publicId: string,
  transform: TransformOptions
): Promise<FileResponse>
```

#### Delete File

```typescript
deleteFile(
  publicId: string
): Promise<DeleteResponse>
```

### Interfaces

#### MediaServiceConfig

```typescript
interface MediaServiceConfig {
  baseUrl: string;
  apiKey: string;
  timeout?: number;
  retryAttempts?: number;
}
```

#### TransformOptions

```typescript
interface TransformOptions {
  width?: number;
  height?: number;
  format?: 'jpeg' | 'png' | 'webp' | 'avif';
  quality?: number;
  fit?: 'cover' | 'contain' | 'fill';
}
```

#### UploadResponse

```typescript
interface UploadResponse {
  _id: string;
  filename: string;
  originalname: string;
  mimetype: string;
  size: number;
  path: string;
  thumbnailPath?: string;
  url: string;
  thumbnailUrl?: string;
  publicId: string;
  userId: string;
  versions: TransformationRecord[];
  createdAt: Date;
  updatedAt: Date;
}
```

#### FileResponse

```typescript
interface FileResponse {
  url: string;
  publicId: string;
  metadata: FileMetadata;
  mimetype: string;
  size: number;
}
```

#### DeleteResponse

```typescript
interface DeleteResponse {
  success: boolean;
  message: string;
}
```

## Examples

### File Upload with Transformation

```typescript
const uploadImage = async () => {
  const file = new File(['content'], 'product.jpg', { type: 'image/jpeg' });

  try {
    const response = await mediaService.uploadFile(file, {
      transform: {
        width: 1200,
        height: 800,
        format: 'webp',
        quality: 85,
        fit: 'cover'
      },
      metadata: {
        productId: '12345',
        category: 'electronics'
      }
    });

    console.log('Upload successful:', response.url);
  } catch (error) {
    console.error('Upload failed:', error);
  }
};
```

### Retrieve and Transform

```typescript
const getTransformedImage = async (publicId) => {
  try {
    const response = await mediaService.getFile(publicId, {
      width: 300,
      height: 300,
      format: 'webp',
      quality: 75,
      fit: 'contain'
    });

    console.log('Transformed image URL:', response.url);
    return response;
  } catch (error) {
    console.error('Transformation failed:', error);
    throw error;
  }
};
```

### Generate Thumbnail

```typescript
const getThumbnail = async (publicId) => {
  try {
    const thumbnail = await mediaService.getThumbnail(publicId);
    console.log('Thumbnail URL:', thumbnail.url);
    return thumbnail;
  } catch (error) {
    console.error('Failed to get thumbnail:', error);
    throw error;
  }
};
```

### Delete a File

```typescript
const removeFile = async (publicId) => {
  try {
    const result = await mediaService.deleteFile(publicId);
    console.log('File deleted:', result.message);
    return result.success;
  } catch (error) {
    console.error('Delete failed:', error);
    return false;
  }
};
```

## Error Handling

The service provides detailed error information through the ErrorResponse interface:

```typescript
interface ErrorResponse {
  message: string;
  code: string;
  status: number;
}
```

Example error handling:

```typescript
try {
  await mediaService.uploadFile(file);
} catch (error) {
  console.error(`Error (${error.code}): ${error.message}`);

  // Handle different error status codes
  switch (error.status) {
    case 400:
      console.error('Bad request - check your input parameters');
      break;
    case 401:
      console.error('Authentication failed - check your API key');
      break;
    case 413:
      console.error('File too large');
      break;
    case 500:
      console.error('Server error');
      break;
    default:
      console.error('Unknown error occurred');
  }
}
```

## Best Practices

1. **Configure once at startup**: Call `configureMediaService()` once during application initialization.

2. **Validate inputs**: Although the library validates inputs, it's good practice to validate parameters before making API calls.

3. **Error handling**: Always wrap API calls in try/catch blocks to gracefully handle errors.

4. **Optimize transformations**: Use the smallest dimensions and quality settings that meet your needs to reduce bandwidth.

5. **Cache results**: Consider caching transformed images and thumbnails to reduce API calls.

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

## License

MIT License - feel free to use this package in your projects.

## Support

For issues and feature requests, please use the GitHub issue tracker.
