@musallam/firefly-services-clients
v2.4.0
Published
TypeScript client library for Adobe Firefly Services API
Maintainers
Readme
@musallam/firefly-services-clients
TypeScript client library for Adobe Firefly Services API
Auto-generated clients powered by Orval from official Adobe Firefly OpenAPI specifications.
Features
- 🔥 Full TypeScript support with complete type definitions
- 🤖 Auto-generated clients from OpenAPI specs using Orval
- 🎨 Complete API coverage for all Firefly operations:
- Text to Image generation
- Image expansion
- Generative fill
- Similar image generation
- Object composite generation
- Video generation
- Custom models
- Image upload
- 🏷️ Namespaced exports to avoid type conflicts between clients
- ⚡ Type-safe job polling with progress tracking and error handling
- 🎯 Full type inference for polling results and progress callbacks
- 🔐 Fetch-based with flexible authentication
- 📦 ESM and CommonJS support
- 🚀 Modern async/await API
Installation
npm install @musallam/firefly-services-clientsQuick Start
Note: All clients are exported under namespaces to avoid type conflicts. See docs/USAGE_EXAMPLES.md for detailed examples.
Generate Images
import { ImageGenerationClient } from '@musallam/firefly-services-clients';
const authOptions = {
headers: {
Authorization: `Bearer YOUR_ACCESS_TOKEN`,
'x-api-key': 'YOUR_CLIENT_ID',
},
};
// Start image generation job
const job = await ImageGenerationClient.generateImagesV3Async(
{
prompt: 'A futuristic city at sunset',
numVariations: 2,
size: { width: 2048, height: 2048 },
contentClass: ImageGenerationClient.ContentClassV3.photo,
},
authOptions
);
console.log('Job started:', job.jobId);
console.log('Status URL:', job.statusUrl);Poll Until Complete
Use the built-in polling utility to automatically wait for job completion with full type safety:
import { ImageGenerationClient, pollJob } from '@musallam/firefly-services-clients';
// Start the job
const job = await ImageGenerationClient.generateImagesV3Async(
{
prompt: 'A futuristic city at sunset',
size: { width: 2048, height: 2048 },
},
authOptions
);
// Poll until complete with explicit result type for full type safety
const result = await pollJob<ImageGenerationClient.GenerateImagesResponseV3>(job, {
fetchOptions: authOptions,
intervalMs: 2000, // Check every 2 seconds
onProgress: (status) => {
console.log(`Status: ${status.status}, Progress: ${status.progress}%`);
if (status.result) {
// status.result is properly typed!
console.log(`Generated ${status.result.outputs.length} images so far`);
}
},
});
// result is typed as GenerateImagesResponseV3
console.log('Generated images:', result.outputs);
result.outputs.forEach((output) => {
console.log(`Image URL: ${output.image.url}`);
});Available Clients
All clients are exported under their own namespace to prevent type conflicts:
| Client | Description | Source |
| ------------------------------- | ----------------------------------- | ------------------------------------------- |
| ImageGenerationClient | Text-to-image generation | image-generation-async-v3-client |
| GenerateSimilarClient | Generate similar image variations | generate-similar-async-v3-client |
| GenerateObjectCompositeClient | Composite objects into images | generate-object-composite-async-v3-client |
| GenerativeExpandClient | Expand images with AI | generative-expand-async-v3-client |
| GenerativeFillClient | Generative fill/remove objects | generative-fill-async-v3-client |
| GenerateVideoClient | Generate videos from images/prompts | generate-video-api-client |
| UploadImageClient | Upload images to Firefly storage | upload-image-client |
| CustomModelsClient | List and manage custom models | custom-models-listing-client |
Usage Pattern
import {
ImageGenerationClient,
GenerateSimilarClient,
UploadImageClient,
} from '@musallam/firefly-services-clients';
// Each client has its own types - no conflicts!
const alignment1: ImageGenerationClient.AlignmentHorizontal = 'center';
const alignment2: GenerateSimilarClient.AlignmentHorizontal = 'left';
// Use client functions
const result = await ImageGenerationClient.generateImagesV3Async(request, authOptions);Authentication
All Firefly API calls require authentication headers with an access token and API key.
Built-in IMS Client
This library includes an IMSClient that handles OAuth 2.0 Client Credentials flow automatically:
import { IMSClient, ImageGenerationClient } from '@musallam/firefly-services-clients';
// Create IMS client
const imsClient = new IMSClient({
clientId: 'YOUR_CLIENT_ID',
clientSecret: 'YOUR_CLIENT_SECRET',
scopes: ['openid', 'AdobeID', 'firefly_api', 'ff_apis'],
});
// Get auth headers (handles token fetching and caching)
const authHeaders = await imsClient.getAuthHeaders();
// Use with any client
const job = await ImageGenerationClient.generateImagesV3Async(request, {
headers: authHeaders,
});Features:
- ✅ Automatic token fetching and caching
- ✅ Token expiration handling with 60s buffer
- ✅ OAuth 2.0 Client Credentials flow
- ✅ Returns properly formatted headers (
Authorization,x-api-key)
Manual Authentication
If you already have an access token, pass it directly:
const authOptions = {
headers: {
Authorization: `Bearer YOUR_ACCESS_TOKEN`,
'x-api-key': 'YOUR_CLIENT_ID',
},
};
const job = await ImageGenerationClient.generateImagesV3Async(request, authOptions);Custom IMS Client
You can implement your own authentication strategy by implementing the IIMSClient interface:
import { IIMSClient } from '@musallam/firefly-services-clients';
class MyCustomIMSClient implements IIMSClient {
async getAccessToken(): Promise<string> {
// Your custom token fetching logic
// e.g., fetch from cache, service account, etc.
return 'your_access_token';
}
async getAuthHeaders(): Promise<Record<string, string>> {
const token = await this.getAccessToken();
return {
Authorization: `Bearer ${token}`,
'x-api-key': 'YOUR_CLIENT_ID',
};
}
}
// Use your custom client
const myClient = new MyCustomIMSClient();
const authHeaders = await myClient.getAuthHeaders();Use cases for custom clients:
- Token caching in Redis or external cache
- Service account authentication
- Integration with existing auth systems
- Custom token refresh logic
- Multi-tenant authentication
Token-only IMS Client
For scenarios where you already have a long-lived access token:
import { TokenIMSClient } from '@musallam/firefly-services-clients';
const tokenClient = new TokenIMSClient({
accessToken: 'YOUR_EXISTING_TOKEN',
clientId: 'YOUR_CLIENT_ID',
});
const authHeaders = await tokenClient.getAuthHeaders();For more details on obtaining credentials, see the Adobe Firefly Services Authentication Guide.
Custom Axios Configuration
All API clients use a shared axios instance internally, which is exported as AXIOS_INSTANCE. You can customize this instance to configure global behavior for all API calls, such as timeouts, interceptors, custom headers, or retry logic.
since this mutates AXIOS_INSTANCE, it would need to be executed before any of the client calls.
import { AXIOS_INSTANCE } from '@musallam/firefly-services-clients';
// Add request interceptor
AXIOS_INSTANCE.interceptors.request.use((config) => {
console.log('Making request to:', config.url);
return config;
});
// Add response interceptor
AXIOS_INSTANCE.interceptors.response.use(
(response) => {
console.log('Response received:', response.status);
return response;
},
(error) => {
console.error('Request failed:', error.message);
return Promise.reject(error);
}
);
// Override base URL (e.g., for proxy or different environment)
AXIOS_INSTANCE.defaults.baseURL = 'https://your-proxy-server.com';
// Set global timeout
AXIOS_INSTANCE.defaults.timeout = 30000; // 30 seconds
// Add custom headers for all requests
AXIOS_INSTANCE.defaults.headers.common['X-Custom-Header'] = 'value';Common use cases:
- Setting global timeouts for all API calls
- Adding request/response logging
- Implementing retry logic with interceptors
- Adding custom headers to all requests
- Overriding the base URL (for proxies or different environments)
- Monitoring API performance
- Handling errors globally
For a complete list of available configuration options and interceptor capabilities, see the Axios documentation.
Image Upload
For uploading images to Firefly storage (for use with operations like generate similar, expand, fill), use the uploadImage utility:
import { uploadImage } from '@musallam/firefly-services-clients';
// Read your image file
const imageBuffer = readFileSync('./my-image.jpg');
const imageBlob = new Blob([imageBuffer], { type: 'image/jpeg' });
// Upload to Firefly storage
const uploadResult = await uploadImage(imageBlob, {
headers: authHeaders,
});
const uploadId = uploadResult.images[0].id;
// Use the uploadId in other operations
const job = await GenerateSimilarClient.generateSimilarImagesV3Async(
{
image: {
source: { uploadId },
},
numVariations: 3,
},
{ headers: authHeaders }
);Note: Use uploadImage instead of UploadImageClient.storageImageV2 as it properly handles binary data uploads. The generated client has a limitation with Blob serialization that this utility addresses.
Job Polling
All async operations return { jobId, statusUrl, cancelUrl }. Use the polling utilities to wait for completion:
pollJob<TResult>(jobResult, options)
Polls a single job until completion with full TypeScript type safety. Specify the result type explicitly for the best developer experience:
import { ImageGenerationClient, pollJob } from '@musallam/firefly-services-clients';
// Recommended: Specify the result type for full type safety
const result = await pollJob<ImageGenerationClient.GenerateImagesResponseV3>(job, {
fetchOptions: authOptions,
intervalMs: 2000, // Poll every 2 seconds (default)
maxAttempts: 60, // Max 60 attempts (default: 120 seconds)
timeoutMs: 300000, // Or set explicit 5-minute timeout
onProgress: (status) => {
console.log(`Status: ${status.status}`);
console.log(`Progress: ${status.progress}%`);
// status.result is properly typed as GenerateImagesResponseV3 | undefined
if (status.result) {
console.log(`Generated ${status.result.outputs.length} images`);
}
},
});
// result is typed as GenerateImagesResponseV3
console.log(`Image URL: ${result.outputs[0].image.url}`);Available Result Types:
ImageGenerationClient.GenerateImagesResponseV3GenerativeExpandClient.ExpandImageResponseV3GenerativeFillClient.FillImageResponseV3GenerateSimilarClient.GenerateSimilarImagesResponseV3GenerateObjectCompositeClient.GenerateObjectCompositeResponseV3GenerateVideoClient.AsyncResult
See docs/TYPE_INFERENCE_GUIDE.md for detailed examples.
Polling Multiple Jobs
You can poll multiple jobs in parallel using Promise.all:
import { pollJob, ImageGenerationClient } from '@musallam/firefly-services-clients';
const jobs = [job1, job2, job3];
const results = await Promise.all(
jobs.map((job) =>
pollJob<ImageGenerationClient.GenerateImagesResponseV3>(job, {
fetchOptions: authOptions,
})
)
);
// results is an array of GenerateImagesResponseV3
results.forEach((result, index) => {
console.log(`Job ${index + 1} generated ${result.outputs.length} images`);
});Error Handling
import {
ImageGenerationClient,
pollJob,
PollingError,
PollingTimeoutError,
} from '@musallam/firefly-services-clients';
try {
const result = await pollJob<ImageGenerationClient.GenerateImagesResponseV3>(job, {
fetchOptions: authOptions,
maxAttempts: 30,
});
console.log(`Success! Generated ${result.outputs.length} images`);
} catch (error) {
if (error instanceof PollingTimeoutError) {
console.error('Job timed out after maximum attempts');
} else if (error instanceof PollingError) {
console.error('Job failed:', error.message);
console.log('Job status:', error.status);
}
}Architecture
This package uses Orval to auto-generate TypeScript clients from OpenAPI specifications:
build-scripts/
├── fetch-spec.ts # Downloads OpenAPI specs
└── spec-urls.ts # Configuration for spec URLs
src/
├── spec/ # OpenAPI spec files (JSON)
├── generated/ # Auto-generated clients (DO NOT EDIT)
│ ├── image-generation-async-v3-client/
│ ├── generate-similar-async-v3-client/
│ └── ...
├── extension/ # Custom extensions
│ └── job-polling-extension.ts
├── mutator/ # Custom fetch client
└── index.ts # Main entry (namespaced exports)
orval.config.ts # Orval configurationCode Generation Workflow
Fetch specs: Download OpenAPI specs from Adobe
npm run fetch-specGenerate clients: Generate TypeScript clients using Orval
npm run orvalBuild: Bundle the library
npm run build
Namespaced Exports
To avoid type name conflicts (e.g., multiple clients exporting AlignmentHorizontal), all clients are imported and re-exported under namespaces in src/index.ts:
// src/index.ts
import * as ImageGenerationClient from './generated/image-generation-async-v3-client/index.js';
import * as GenerateSimilarClient from './generated/generate-similar-async-v3-client/index.js';
export {
ImageGenerationClient,
GenerateSimilarClient,
// ...
};This allows consumers to use:
const type1: ImageGenerationClient.AlignmentHorizontal = 'center';
const type2: GenerateSimilarClient.AlignmentHorizontal = 'left';
// No conflicts!More Examples
See USAGE_EXAMPLES.md for comprehensive examples including:
- All client types with usage examples
- Polling patterns and error handling
- Batch processing multiple jobs
- Working with different content types
Also check the Adobe Firefly Services documentation for API details and guides.
Development
Setup
# Install dependencies
npm install
# Download OpenAPI specs
npm run fetch-spec
# Generate clients from specs
npm run orvalCommon Commands
# Type check
npm run type-check
# Lint
npm run lint
# Format code
npm run format
# Build library
npm run build
# Run all checks
npm run type-check && npm run lintRegenerating Clients
When Adobe updates their OpenAPI specs:
# 1. Download latest specs
npm run fetch-spec
# 2. Regenerate clients
npm run orval
# 3. Verify everything works
npm run type-check
npm run buildProject Structure
src/generated/- Auto-generated code (never edit manually)src/extension/- Custom utilities and extensionssrc/mutator/- Custom fetch implementationorval.config.ts- Orval configuration for code generationbuild-scripts/- Scripts for fetching specs and automation
Contributing
This project uses:
- Orval - OpenAPI to TypeScript code generation
- Conventional Commits for commit messages
- ESLint + Prettier for code quality
- Husky for git hooks
- Semantic Release for automated versioning
Contributing Guidelines
- Never edit files in
src/generated/directly - they are auto-generated - Use conventional commits format:
feat:,fix:,docs:, etc. - Run linter and type-check before committing
- Extensions and utilities go in
src/extension/
License
MIT
Built with Orval | API by Adobe Firefly Services
