Enterprise-grade TypeScript client for OpenAI's Sora AI Video Generation API. Built with best practices, featuring comprehensive error handling, logging, validation, and retry mechanisms.
✨ Enterprise-Ready Architecture
- Clean Architecture with separation of concerns
- Domain-Driven Design (DDD) principles
- Repository Pattern for data access
- Service Layer for business logic
- Dependency Injection support
🛡️ Robust Error Handling
- Custom exception hierarchy
- Automatic retry with exponential backoff
- Rate limit handling
- Timeout management
- Network error recovery
📝 Comprehensive Logging
- Winston-based logging system
- Multiple log levels (debug, info, warn, error)
- File and console transports
- Structured logging with metadata
✅ Validation
- Zod-based schema validation
- Input sanitization
- Type-safe operations
🔄 Advanced Features
- Progress tracking callbacks
- Batch processing support
- Video download with/without watermark
- Polling with configurable intervals
- Circuit breaker pattern
npm install- Copy the environment example file:
cp .env.example .env- Configure your
.envfile:
SORA_BASE_URL=https://sora.chatgpt.com
SORA_AUTH_TOKEN=your_bearer_token_here
SORA_DEVICE_ID=your_device_id_here
SORA_COOKIES=cookie1=value1,cookie2=value2
# Optional configurations
API_TIMEOUT=30000
MAX_RETRIES=3
RETRY_DELAY=2000
POLL_INTERVAL=5000
MAX_POLL_ATTEMPTS=120
LOG_LEVEL=info
LOG_DIR=logsimport { SoraClient, VideoOrientation } from './src';
const client = new SoraClient();
// Create and wait for video
const draft = await client.createAndWaitForVideo(
'A futuristic cityscape at sunset',
{ orientation: VideoOrientation.PORTRAIT }
);
console.log('Video URL:', draft.downloadableUrl);
// Download video
await client.downloadVideo(draft, './my-video.mp4');const taskId = await client.createVideo('A serene mountain landscape');
const draft = await client.waitForVideoCompletion(
taskId,
(progress, task) => {
console.log(`Progress: ${progress}% - Status: ${task.status}`);
}
);src/
├── domain/ # Domain layer (business logic)
│ ├── models/ # Domain models & entities
│ │ ├── VideoTask.ts
│ │ ├── VideoDraft.ts
│ │ ├── VideoCreateOptions.ts
│ │ └── RateLimit.ts
│ ├── interfaces/ # Domain interfaces
│ │ ├── ISoraRepository.ts
│ │ ├── IVideoService.ts
│ │ ├── ILogger.ts
│ │ └── IHttpClient.ts
│ └── exceptions/ # Custom exceptions
│ └── SoraException.ts
│
├── application/ # Application layer (use cases)
│ ├── services/ # Application services
│ │ └── VideoService.ts
│ └── validators/ # Input validation
│ └── VideoValidator.ts
│
├── infrastructure/ # Infrastructure layer
│ ├── config/ # Configuration management
│ │ └── Config.ts
│ ├── logging/ # Logging implementation
│ │ └── Logger.ts
│ ├── http/ # HTTP client with retry
│ │ └── HttpClient.ts
│ └── repositories/ # Repository implementations
│ └── SoraRepository.ts
│
├── SoraClient.ts # Main client facade
└── index.ts # Public API exports
examples/ # Usage examples
├── basic-usage.ts
├── advanced-usage.ts
├── batch-processing.ts
├── error-handling.ts
└── check-status.ts
Main client class providing all functionality.
Creates a video and waits for completion.
Parameters:
prompt(string): Video generation promptoptions(VideoCreateOptions): Optional configuration
Returns: Promise<VideoDraft>
Example:
const draft = await client.createAndWaitForVideo(
'A beautiful sunset over the ocean',
{
orientation: VideoOrientation.LANDSCAPE,
nFrames: 400,
size: VideoSize.LARGE
}
);Creates a video task without waiting.
Returns: Promise<string> - Task ID
Monitors a task until completion.
Parameters:
taskId(string): Task ID to monitoronProgress(callback): Optional progress callback
Returns: Promise<VideoDraft>
Retrieves all pending video tasks.
Returns: Promise<VideoTask[]>
Retrieves completed video drafts.
Parameters:
limit(number): Maximum drafts to retrieve (1-100, default: 15)
Returns: Promise<VideoDraft[]>
Downloads a video to local filesystem.
Parameters:
draft(VideoDraft): Video draft to downloadoutputPath(string): Local file pathwithWatermark(boolean): Include watermark (default: false)
Returns: Promise<string> - File path
interface VideoCreateOptions {
title?: string;
orientation?: VideoOrientation; // PORTRAIT, LANDSCAPE, SQUARE
size?: VideoSize; // SMALL, LARGE
nFrames?: number; // 60-600
model?: string; // Default: 'sy_8'
// ... other options
}The client provides specific exception types:
import {
ValidationException,
RateLimitException,
VideoProcessingException,
TimeoutException,
AuthenticationException,
ApiException,
NetworkException
} from './src';
try {
await client.createVideo('My prompt');
} catch (error) {
if (error instanceof RateLimitException) {
console.log(`Rate limited. Retry after: ${error.retryAfter}s`);
} else if (error instanceof ValidationException) {
console.log('Validation errors:', error.errors);
} else if (error instanceof VideoProcessingException) {
console.log(`Processing failed for task: ${error.taskId}`);
}
}const prompts = [
'A red sports car',
'A mountain landscape',
'A chef cooking'
];
const taskIds = await Promise.all(
prompts.map(prompt => client.createVideo(prompt))
);
const drafts = await Promise.all(
taskIds.map(id => client.waitForVideoCompletion(id))
);// Check pending tasks
const pending = await client.getPendingTasks();
console.log(`${pending.length} tasks pending`);
// Get recent drafts
const drafts = await client.getDrafts(10);
drafts.forEach(draft => {
console.log(`${draft.prompt}: ${draft.downloadableUrl}`);
});npm run buildnpm run dev examples/basic-usage.tsnpm run lint
npm run lint:fixnpm run format- Domain Layer: Business logic and entities
- Application Layer: Use cases and orchestration
- Infrastructure Layer: External services and frameworks
- Single Responsibility: Each class has one reason to change
- Open/Closed: Open for extension, closed for modification
- Liskov Substitution: Interfaces are substitutable
- Interface Segregation: Focused, specific interfaces
- Dependency Inversion: Depend on abstractions, not concretions
- Repository Pattern: Data access abstraction
- Factory Pattern: Object creation
- Singleton Pattern: Configuration and logging
- Strategy Pattern: Retry and error handling
- Facade Pattern: Simplified client interface
The architecture supports easy testing through dependency injection:
import { SoraClient } from './src';
// Mock dependencies for testing
const mockLogger = { /* ... */ };
const mockRepository = { /* ... */ };
const client = new SoraClient({
logger: mockLogger,
repository: mockRepository
});⚠️ Important Security Considerations:
- Never commit your
.envfile - Rotate your authentication tokens regularly
- Use environment variables in production
- Implement proper access controls
- Monitor API usage and costs
- Retry Logic: Exponential backoff (configurable)
- Timeout Handling: Configurable timeouts
- Connection Pooling: Reuses HTTP connections
- Efficient Polling: Adjustable poll intervals
- Maximum prompt length: 2000 characters
- Maximum frame count: 600
- Maximum drafts per request: 100
- Default timeout: 30 seconds (configurable)
- Fork the repository
- Create a feature branch
- Follow the existing code style
- Add tests for new features
- Submit a pull request
MIT License - see LICENSE file for details
For issues and questions:
- GitHub Issues: [Create an issue]
- Documentation: See
/examplesdirectory
- Initial release
- Complete TypeScript rewrite
- Enterprise architecture implementation
- Comprehensive error handling
- Logging and monitoring
- Validation layer
- Retry mechanisms
- Progress tracking
- Batch processing support
Built with ❤️ using TypeScript, following enterprise best practices and SOLID principles.