import axios, { AxiosInstance } from 'axios';
export interface DockerHubAuthResponse {
token: string;
access_token?: string;
}
export interface DockerHubRepository {
name: string;
namespace: string;
repository_type: string;
status: number;
description: string;
is_private: boolean;
is_automated: boolean;
star_count: number;
pull_count: number;
last_updated: string;
}
export interface DockerHubSearchResponse {
count: number;
next?: string;
previous?: string;
results: DockerHubRepository[];
}
export interface DockerHubTag {
name: string;
full_size: number;
id: number;
repository: number;
creator: number;
image_id: number | null;
v2: boolean;
last_updated: string;
last_updater: number;
last_updater_username: string;
images: Array<{
size: number;
architecture: string;
variant: string | null;
features: string | null;
digest: string;
os: string;
os_version: string | null;
os_features: string | null;
}>;
}
export interface DockerHubTagsResponse {
count: number;
next?: string;
previous?: string;
results: DockerHubTag[];
}
export class DockerHubClient {
private baseURL = 'https://hub.docker.com/v2';
private api: AxiosInstance;
private authToken?: string;
constructor() {
this.api = axios.create({
baseURL: this.baseURL,
headers: {
'Content-Type': 'application/json',
},
});
}
async authenticate(username: string, password: string): Promise<string> {
try {
const response = await axios.post<DockerHubAuthResponse>(
'https://hub.docker.com/v2/users/login',
{
username,
password,
}
);
this.authToken = response.data.token || response.data.access_token;
return this.authToken!;
} catch (error: any) {
throw new Error(`Docker Hub authentication failed: ${error.response?.data?.detail || error.message}`);
}
}
getAuthToken(): string | undefined {
return this.authToken;
}
async searchRepositories(query: string, limit: number = 25, page: number = 1): Promise<DockerHubSearchResponse> {
try {
const response = await this.api.get<DockerHubSearchResponse>('/search/repositories', {
params: {
q: query,
page,
page_size: limit,
},
});
return response.data;
} catch (error: any) {
throw new Error(`Docker Hub search failed: ${error.response?.data?.detail || error.message}`);
}
}
async getRepositoryTags(namespace: string, repository: string, page: number = 1, pageSize: number = 100): Promise<DockerHubTagsResponse> {
try {
const response = await this.api.get<DockerHubTagsResponse>(
`/repositories/${namespace}/${repository}/tags`,
{
params: {
page,
page_size: pageSize,
},
...(this.authToken && {
headers: {
Authorization: `Bearer ${this.authToken}`,
},
}),
}
);
return response.data;
} catch (error: any) {
throw new Error(`Failed to get repository tags: ${error.response?.data?.detail || error.message}`);
}
}
async getRepositoryInfo(namespace: string, repository: string): Promise<DockerHubRepository> {
try {
const response = await this.api.get<DockerHubRepository>(
`/repositories/${namespace}/${repository}`,
{
...(this.authToken && {
headers: {
Authorization: `Bearer ${this.authToken}`,
},
}),
}
);
return response.data;
} catch (error: any) {
throw new Error(`Failed to get repository info: ${error.response?.data?.detail || error.message}`);
}
}
}