npm package: @nixxie-international/s3-service
Description: A comprehensive AWS S3 service wrapper with TypeScript support
Author: Sher Ghan
Latest version: 1.0.4

# S3 Service

A comprehensive AWS S3 service wrapper with TypeScript support, designed for easy file management and operations.

## Features

- 🚀 **Easy to use** - Simple API for common S3 operations
- 📁 **File Management** - Upload, download, delete, and list files
- 🔒 **Access Control** - Support for public and private files
- 🔗 **Signed URLs** - Generate secure, time-limited access URLs
- 📝 **TypeScript** - Full TypeScript support with type definitions
- 🏗️ **Flexible** - Singleton pattern with support for multiple instances
- 📊 **Logging** - Configurable logging support
- ✅ **Well Tested** - Comprehensive test coverage

## Installation

```bash
npm install @nixxie-international/s3-service
```

## Quick Start

```typescript
import { S3Service } from '@nixxie-international/s3-service';

// Create service instance
const s3Service = S3Service.getInstance({
  bucket: 'your-bucket-name',
  region: 'us-east-1',
  accessKeyId: 'your-access-key',
  secretAccessKey: 'your-secret-key'
});

// Initialize the service
await s3Service.initialize();

// Upload a file
const fileBuffer = Buffer.from('Hello, World!');
const fileKey = await s3Service.uploadFile(fileBuffer, {
  filename: 'hello',
  extension: 'txt',
  folder: 'documents'
});

console.log('File uploaded:', fileKey);
```

## Configuration

### Basic Configuration

```typescript
import { S3Service, S3ServiceConfig } from '@nixxie-international/s3-service';

const config: S3ServiceConfig = {
  bucket: 'your-bucket-name',
  region: 'us-east-1', // Optional, defaults to us-east-1
  accessKeyId: 'your-access-key', // Optional, uses env var AWS_ACCESS_KEY_ID
  secretAccessKey: 'your-secret-key', // Optional, uses env var AWS_SECRET_ACCESS_KEY
  publicFolder: 'public', // Optional, defaults to 'public'
  logger: customLogger // Optional, uses console logger by default
};

const s3Service = S3Service.getInstance(config);
```

### Environment Variables

You can also configure using environment variables:

```bash
AWS_ACCESS_KEY_ID=your-access-key
AWS_SECRET_ACCESS_KEY=your-secret-key
AWS_REGION=us-east-1
```

## API Reference

### File Upload

#### `uploadFile(fileBuffer, options)`

Upload a file to S3.

```typescript
const fileKey = await s3Service.uploadFile(fileBuffer, {
  contentType: 'image/jpeg',
  folder: 'images',
  filename: 'profile-pic',
  extension: 'jpg',
  metadata: { userId: '123' },
  isPublic: true
});
```

#### `uploadPublicFile(fileBuffer, options)`

Upload a file to the public folder.

```typescript
const fileKey = await s3Service.uploadPublicFile(fileBuffer, {
  filename: 'avatar',
  extension: 'png'
});
```

### File Retrieval

#### `getFile(key)`

Retrieve a file from S3.

```typescript
const { buffer, contentType } = await s3Service.getFile('documents/hello.txt');
```

#### `fileExists(key)`

Check if a file exists.

```typescript
const exists = await s3Service.fileExists('documents/hello.txt');
```

#### `getFileMetadata(key)`

Get file metadata.

```typescript
const metadata = await s3Service.getFileMetadata('documents/hello.txt');
console.log(metadata.ContentLength, metadata.LastModified);
```

### File Management

#### `deleteFile(key)`

Delete a single file.

```typescript
await s3Service.deleteFile('documents/old-file.txt');
```

#### `deleteFiles(keys)`

Delete multiple files.

```typescript
await s3Service.deleteFiles([
  'documents/file1.txt',
  'documents/file2.txt'
]);
```

#### `copyFile(sourceKey, destinationKey, options)`

Copy a file within S3.

```typescript
await s3Service.copyFile(
  'documents/original.txt',
  'backup/original-backup.txt',
  { isPublic: true }
);
```

#### `listFiles(prefix, maxKeys)`

List files in a folder.

```typescript
const files = await s3Service.listFiles('documents/', 100);
files.forEach(file => {
  console.log(file.Key, file.Size, file.LastModified);
});
```

### Access Control

#### `makeFilePublic(key)`

Make an existing file public.

```typescript
await s3Service.makeFilePublic('documents/public-doc.pdf');
```

#### `makeFilePrivate(key)`

Make an existing file private.

```typescript
await s3Service.makeFilePrivate('documents/private-doc.pdf');
```

#### `isPublicFile(key)`

Check if a file is in the public folder.

```typescript
const isPublic = s3Service.isPublicFile('public/images/logo.png'); // true
```

### URL Generation

#### `getPublicUrl(key)`

Get the public URL for a file.

```typescript
const url = s3Service.getPublicUrl('public/images/logo.png');
// Returns: https://your-bucket.s3.us-east-1.amazonaws.com/public/images/logo.png
```

#### `getSignedUrl(key, options)`

Generate a signed URL for secure access.

```typescript
// Default: 1 hour expiration for getObject
const url = await s3Service.getSignedUrl('private/document.pdf');

// Custom expiration and operation
const uploadUrl = await s3Service.getSignedUrl('uploads/new-file.jpg', {
  expiresIn: 3600, // 1 hour
  operation: 'putObject'
});
```

## Advanced Usage

### Multiple Instances

You can create multiple S3Service instances for different buckets:

```typescript
const productionS3 = S3Service.getInstance({
  bucket: 'production-bucket'
}, 'production');

const stagingS3 = S3Service.getInstance({
  bucket: 'staging-bucket'
}, 'staging');
```

### Custom Logger

Implement your own logger:

```typescript
import { Logger } from '@nixxie-international/s3-service';

class CustomLogger implements Logger {
  info(message: string, meta?: any): void {
    // Your custom logging logic
  }

  error(message: string, meta?: any): void {
    // Your custom error logging
  }

  warn(message: string, meta?: any): void {
    // Your custom warning logging
  }

  debug(message: string, meta?: any): void {
    // Your custom debug logging
  }
}

const s3Service = S3Service.getInstance({
  bucket: 'your-bucket',
  logger: new CustomLogger()
});
```

### File Upload with Progress

For large files, you might want to use multipart uploads:

```typescript
// For large files, consider using AWS SDK directly for multipart uploads
// This service is optimized for smaller files and standard uploads
```

## Error Handling

The service throws descriptive errors for various scenarios:

```typescript
try {
  await s3Service.uploadFile(fileBuffer, options);
} catch (error) {
  if (error.message === 'Failed to upload file to S3') {
    // Handle upload failure
  }
}
```

Common error scenarios:
- **Initialization failed**: Invalid credentials or bucket doesn't exist
- **Upload failed**: Network issues, insufficient permissions, or invalid file
- **File not found**: Trying to access a non-existent file
- **Access denied**: Insufficient permissions for the operation

## TypeScript Support

Full TypeScript support with comprehensive type definitions:

```typescript
import { S3Service, S3ServiceConfig, UploadOptions, FileResult } from '@nixxie-international/s3-service';

const config: S3ServiceConfig = {
  bucket: 'my-bucket',
  region: 'us-west-2'
};

const options: UploadOptions = {
  contentType: 'application/pdf',
  isPublic: false,
  metadata: {
    uploadedBy: 'user123'
  }
};

const result: FileResult = await s3Service.getFile('document.pdf');
```

## Best Practices

### 1. Initialize Once

```typescript
// Good: Initialize once at application startup
const s3Service = S3Service.getInstance(config);
await s3Service.initialize();

// Use throughout your application
export { s3Service };
```

### 2. Use Appropriate Folders

```typescript
// Organize files in logical folders
await s3Service.uploadFile(profilePic, {
  folder: 'users/avatars',
  isPublic: true
});

await s3Service.uploadFile(document, {
  folder: 'users/documents',
  isPublic: false
});
```

### 3. Handle Errors Gracefully

```typescript
try {
  const fileKey = await s3Service.uploadFile(buffer, options);
  return { success: true, fileKey };
} catch (error) {
  logger.error('File upload failed', { error, options });
  return { success: false, error: error.message };
}
```

### 4. Use Signed URLs for Private Files

```typescript
// Instead of making files public, use signed URLs
const signedUrl = await s3Service.getSignedUrl(privateFileKey, {
  expiresIn: 3600 // 1 hour
});
```

## Contributing

1. Fork the repository
2. Create your feature branch (`git checkout -b feature/amazing-feature`)
3. Commit your changes (`git commit -m 'Add some amazing feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`)
5. Open a Pull Request



## License

This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.

## Changelog

### 1.0.0
- Initial release
- Basic S3 operations (upload, download, delete)
- Public/private file management
- Signed URL generation
- TypeScript support
- Comprehensive test coverage