feat(host): Add DockerHost version & image-prune APIs, extend network creation options, return exec inspect info, and improve image import/store and streaming

This commit is contained in:
2025-11-25 05:18:48 +00:00
parent 889b017d4f
commit b86601c939
10 changed files with 670 additions and 18 deletions

View File

@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@apiclient.xyz/docker',
version: '5.0.2',
version: '5.1.0',
description: 'Provides easy communication with Docker remote API from Node.js, with TypeScript support.'
}

View File

@@ -329,6 +329,7 @@ export class DockerContainer extends DockerResource {
): Promise<{
stream: plugins.smartstream.stream.Duplex;
close: () => Promise<void>;
inspect: () => Promise<interfaces.IExecInspectInfo>;
}> {
// Step 1: Create exec instance
const createResponse = await this.dockerHost.request('POST', `/containers/${this.Id}/exec`, {
@@ -386,9 +387,15 @@ export class DockerContainer extends DockerResource {
}
};
const inspect = async (): Promise<interfaces.IExecInspectInfo> => {
const inspectResponse = await this.dockerHost.request('GET', `/exec/${execId}/json`);
return inspectResponse.body;
};
return {
stream: duplexStream,
close,
inspect,
};
}
}

View File

@@ -88,6 +88,25 @@ export class DockerHost {
}
}
/**
* Get Docker daemon version information
* @returns Version info including Docker version, API version, OS, architecture, etc.
*/
public async getVersion(): Promise<{
Version: string;
ApiVersion: string;
MinAPIVersion?: string;
GitCommit: string;
GoVersion: string;
Os: string;
Arch: string;
KernelVersion: string;
BuildTime?: string;
}> {
const response = await this.request('GET', '/version');
return response.body;
}
/**
* authenticate against a registry
* @param userArg
@@ -248,6 +267,35 @@ export class DockerHost {
});
}
/**
* Prune unused images
* @param options Optional filters (dangling, until, label)
* @returns Object with deleted images and space reclaimed
*/
public async pruneImages(options?: {
dangling?: boolean;
filters?: Record<string, string[]>;
}): Promise<{
ImagesDeleted: Array<{ Untagged?: string; Deleted?: string }>;
SpaceReclaimed: number;
}> {
const filters: Record<string, string[]> = options?.filters || {};
// Add dangling filter if specified
if (options?.dangling !== undefined) {
filters.dangling = [options.dangling.toString()];
}
let route = '/images/prune';
if (filters && Object.keys(filters).length > 0) {
route += `?filters=${encodeURIComponent(JSON.stringify(filters))}`;
}
const response = await this.request('POST', route);
return response.body;
}
/**
* Builds an image from a Dockerfile
*/

View File

@@ -51,20 +51,12 @@ export class DockerNetwork extends DockerResource {
const response = await dockerHost.request('POST', '/networks/create', {
Name: networkCreationDescriptor.Name,
CheckDuplicate: true,
Driver: 'overlay',
EnableIPv6: false,
/* IPAM: {
Driver: 'default',
Config: [
{
Subnet: `172.20.${networkCreationDescriptor.NetworkNumber}.0/16`,
IPRange: `172.20.${networkCreationDescriptor.NetworkNumber}.0/24`,
Gateway: `172.20.${networkCreationDescriptor.NetworkNumber}.11`
}
]
}, */
Internal: false,
Attachable: true,
Driver: networkCreationDescriptor.Driver || 'overlay',
EnableIPv6: networkCreationDescriptor.EnableIPv6 || false,
IPAM: networkCreationDescriptor.IPAM,
Internal: networkCreationDescriptor.Internal || false,
Attachable: networkCreationDescriptor.Attachable !== undefined ? networkCreationDescriptor.Attachable : true,
Labels: networkCreationDescriptor.Labels,
Ingress: false,
});
if (response.statusCode < 300) {

View File

@@ -10,3 +10,41 @@ export interface IContainerCreationDescriptor {
/** Network names (strings) or DockerNetwork instances */
networks?: (string | DockerNetwork)[];
}
/**
* Information about an exec instance, including exit code and running state.
* Retrieved via container.exec().inspect()
*/
export interface IExecInspectInfo {
/** Exit code of the exec command (0 = success) */
ExitCode: number;
/** Whether the exec is currently running */
Running: boolean;
/** Process ID */
Pid: number;
/** Container ID where exec runs */
ContainerID: string;
/** Exec instance ID */
ID: string;
/** Whether stderr is open */
OpenStderr: boolean;
/** Whether stdin is open */
OpenStdin: boolean;
/** Whether stdout is open */
OpenStdout: boolean;
/** Whether exec can be removed */
CanRemove: boolean;
/** Detach keys */
DetachKeys: string;
/** Process configuration */
ProcessConfig: {
/** Whether TTY is allocated */
tty: boolean;
/** Entrypoint */
entrypoint: string;
/** Command arguments */
arguments: string[];
/** Whether running in privileged mode */
privileged: boolean;
};
}

View File

@@ -3,4 +3,18 @@
*/
export interface INetworkCreationDescriptor {
Name: string;
Driver?: 'bridge' | 'overlay' | 'host' | 'none' | 'macvlan';
Attachable?: boolean;
Labels?: Record<string, string>;
IPAM?: {
Driver?: string;
Config?: Array<{
Subnet?: string;
Gateway?: string;
IPRange?: string;
AuxiliaryAddresses?: Record<string, string>;
}>;
};
Internal?: boolean;
EnableIPv6?: boolean;
}