From a4e1e5beb009f6c67b37bfc281f3e7a0d962f91c Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 8 Oct 2025 16:16:06 +0200 Subject: [PATCH 1/2] Always prefer async functions Signed-off-by: Nicolas De Loof --- lib/docker-client.ts | 203 ++++++++++++++++++++----------------------- lib/ssh.ts | 19 ++-- lib/tls.ts | 24 +++-- 3 files changed, 121 insertions(+), 125 deletions(-) diff --git a/lib/docker-client.ts b/lib/docker-client.ts index 744ca18..c295b98 100644 --- a/lib/docker-client.ts +++ b/lib/docker-client.ts @@ -1,5 +1,5 @@ import * as net from 'net'; -import * as fs from 'fs'; +import { promises as fsPromises } from 'fs'; import * as path from 'path'; import * as os from 'os'; import * as http from 'http'; @@ -34,88 +34,76 @@ export class DockerClient { * @param certificates Optional path to directory containing TLS certificates (ca.pem, cert.pem, key.pem) for TCP connections * @returns Promise that resolves to a connected DockerClient instance */ - static fromDockerHost( + static async fromDockerHost( dockerHost: string, certificates?: string | SecureContextOptions, userAgent?: string, ): Promise { - return new Promise((resolve, reject) => { - if (dockerHost.startsWith('unix:')) { - // Unix socket connection - use SocketAgent with socket creation function - const socketPath = dockerHost.substring(5); // Remove "unix:" prefix + if (dockerHost.startsWith('unix:')) { + // Unix socket connection - use SocketAgent with socket creation function + const socketPath = dockerHost.substring(5); // Remove "unix:" prefix - try { - const agent = new SocketAgent(() => - net.createConnection(socketPath), - ); - resolve(new DockerClient(agent, userAgent)); - } catch (error) { - reject( - new Error( - `Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`, - ), - ); - } - } else if (dockerHost.startsWith('tcp:')) { - // TCP connection - use SocketAgent with TCP socket creation function - const defaultPort = certificates ? 2376 : 2375; // Default ports: 2376 for TLS, 2375 for plain - const { host, port } = parseDockerHost(dockerHost, defaultPort); - - try { - let agent: SocketAgent; - - if (certificates) { - if (typeof certificates === 'string') { - // Use SocketAgent with TLS socket creation function - const tlsOptions = - TLS.loadCertificates(certificates); - agent = new SocketAgent(() => - tls.connect({ host, port, ...tlsOptions }), - ); - } else { - // certificates is a SecureContextOptions type - agent = new SocketAgent(() => - tls.connect({ host, port, ...certificates }), - ); - } + try { + const agent = new SocketAgent(() => + net.createConnection(socketPath), + ); + return new DockerClient(agent, userAgent); + } catch (error) { + throw new Error( + `Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`, + ); + } + } else if (dockerHost.startsWith('tcp:')) { + // TCP connection - use SocketAgent with TCP socket creation function + const defaultPort = certificates ? 2376 : 2375; // Default ports: 2376 for TLS, 2375 for plain + const { host, port } = parseDockerHost(dockerHost, defaultPort); + + try { + let agent: SocketAgent; + + if (certificates) { + if (typeof certificates === 'string') { + // Use SocketAgent with TLS socket creation function + const tlsOptions = + await TLS.loadCertificates(certificates); + agent = new SocketAgent(() => + tls.connect({ host, port, ...tlsOptions }), + ); } else { - // Use SocketAgent with plain TCP socket creation function + // certificates is a SecureContextOptions type agent = new SocketAgent(() => - net.createConnection({ host, port }), + tls.connect({ host, port, ...certificates }), ); } - - resolve(new DockerClient(agent, userAgent)); - } catch (error) { - reject( - new Error( - `Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`, - ), - ); - } - } else if (dockerHost.startsWith('ssh:')) { - // SSH connection - use SocketAgent with SSH socket creation function - try { - const agent = new SocketAgent( - SSH.createSocketFactory(dockerHost), - ); - resolve(new DockerClient(agent, userAgent)); - } catch (error) { - reject( - new Error( - `Failed to create SSH Docker client for ${dockerHost}: ${getErrorMessage(error)}`, - ), + } else { + // Use SocketAgent with plain TCP socket creation function + agent = new SocketAgent(() => + net.createConnection({ host, port }), ); } - } else { - reject( - new Error( - `Unsupported Docker host format: ${dockerHost}. Must start with "unix:", "tcp:", or "ssh:"`, - ), + + return new DockerClient(agent, userAgent); + } catch (error) { + throw new Error( + `Failed to create Docker client for ${dockerHost}: ${getErrorMessage(error)}`, ); - return; } - }); + } else if (dockerHost.startsWith('ssh:')) { + // SSH connection - use SocketAgent with SSH socket creation function + try { + const socketFactory = await SSH.createSocketFactory(dockerHost); + const agent = new SocketAgent(socketFactory); + return new DockerClient(agent, userAgent); + } catch (error) { + throw new Error( + `Failed to create SSH Docker client for ${dockerHost}: ${getErrorMessage(error)}`, + ); + } + } else { + throw new Error( + `Unsupported Docker host format: ${dockerHost}. Must start with "unix:", "tcp:", or "ssh:"`, + ); + } } /** @@ -142,8 +130,10 @@ export class DockerClient { try { // Read all directories in the contexts meta directory - const contextDirs = fs - .readdirSync(contextsDir, { withFileTypes: true }) + const contextEntries = await fsPromises.readdir(contextsDir, { + withFileTypes: true, + }); + const contextDirs = contextEntries .filter((dirent) => dirent.isDirectory()) .map((dirent) => dirent.name); @@ -155,41 +145,41 @@ export class DockerClient { ); try { - if (fs.existsSync(metaJsonPath)) { - const metaContent = fs.readFileSync( - metaJsonPath, - 'utf8', - ); - const meta = JSON.parse(metaContent); - - if (meta.Name === targetContext) { - // Found matching context, extract endpoint - if ( - meta.Endpoints && - meta.Endpoints.docker && - meta.Endpoints.docker.Host - ) { - const dockerHost = meta.Endpoints.docker.Host; - let certificates: string | undefined = - undefined; - const tls = path.join(tlsDir, contextDir); - if (fs.existsSync(tls)) { - certificates = tls; - } - return DockerClient.fromDockerHost( - dockerHost, - certificates, - userAgent, - ); - } else { - throw new Error( - `Docker context '${targetContext}' found but has no valid Docker endpoint`, - ); + const metaContent = await fsPromises.readFile( + metaJsonPath, + 'utf8', + ); + const meta = JSON.parse(metaContent); + + if (meta.Name === targetContext) { + // Found matching context, extract endpoint + if ( + meta.Endpoints && + meta.Endpoints.docker && + meta.Endpoints.docker.Host + ) { + const dockerHost = meta.Endpoints.docker.Host; + let certificates: string | undefined = undefined; + const tls = path.join(tlsDir, contextDir); + try { + await fsPromises.access(tls); + certificates = tls; + } catch { + // TLS directory doesn't exist, certificates remain undefined } + return DockerClient.fromDockerHost( + dockerHost, + certificates, + userAgent, + ); + } else { + throw new Error( + `Docker context '${targetContext}' found but has no valid Docker endpoint`, + ); } } } catch (parseError) { - // Skip invalid meta.json files + // Skip invalid meta.json files or files that don't exist } } @@ -224,12 +214,7 @@ export class DockerClient { path.join(os.homedir(), '.docker', 'config.json'); try { - if (!fs.existsSync(configPath)) { - // If no config file exists, use default context (usually unix socket) - return DockerClient.fromDockerHost('unix:/var/run/docker.sock'); - } - - const configContent = fs.readFileSync(configPath, 'utf8'); + const configContent = await fsPromises.readFile(configPath, 'utf8'); const config = JSON.parse(configContent); if (config.currentContext) { diff --git a/lib/ssh.ts b/lib/ssh.ts index 770c1ba..3fcfcdf 100644 --- a/lib/ssh.ts +++ b/lib/ssh.ts @@ -1,5 +1,5 @@ import * as net from 'net'; -import * as fs from 'fs'; +import { promises as fsPromises } from 'fs'; import * as path from 'path'; import * as os from 'os'; import { Client } from 'ssh2'; @@ -12,7 +12,7 @@ export class SSH { * Get SSH private key from common locations * @returns SSH private key buffer or undefined */ - private static getPrivateKey(): Buffer | undefined { + private static async getPrivateKey(): Promise { const keyPaths = [ path.join(os.homedir(), '.ssh', 'id_rsa'), path.join(os.homedir(), '.ssh', 'id_ed25519'), @@ -21,9 +21,7 @@ export class SSH { for (const keyPath of keyPaths) { try { - if (fs.existsSync(keyPath)) { - return fs.readFileSync(keyPath); - } + return await fsPromises.readFile(keyPath); } catch (err) { // Continue to next key } @@ -37,7 +35,12 @@ export class SSH { * @param sshHost SSH host string (e.g., "ssh://user@host:22/var/run/docker.sock") * @returns Function that creates new SSH socket connections */ - static createSocketFactory(sshHost: string): () => net.Socket { + static async createSocketFactory( + sshHost: string, + ): Promise<() => net.Socket> { + // Preload the private key asynchronously + const privateKey = await SSH.getPrivateKey(); + // Parse SSH connection parameters once const sshUrl = sshHost.substring(6); // Remove "ssh://" prefix @@ -121,12 +124,12 @@ export class SSH { ); }); - // Connect using SSH key authentication (looks for default keys) + // Connect using SSH key authentication (preloaded key) conn.connect({ host, port, username: user, - privateKey: SSH.getPrivateKey(), + privateKey: privateKey, tryKeyboard: true, }); diff --git a/lib/tls.ts b/lib/tls.ts index 0478e5c..122ec1c 100644 --- a/lib/tls.ts +++ b/lib/tls.ts @@ -1,4 +1,4 @@ -import * as fs from 'fs'; +import { promises as fsPromises } from 'fs'; import * as path from 'path'; import { getErrorMessage } from './util.js'; import type { SecureContextOptions } from 'tls'; @@ -12,26 +12,34 @@ export class TLS { * @param certPath Path to directory containing ca.pem, cert.pem, and key.pem files * @returns TLS options object for HTTPS agent */ - static loadCertificates(certPath: string): SecureContextOptions { + static async loadCertificates( + certPath: string, + ): Promise { const tlsOptions: SecureContextOptions = {}; try { // Load CA certificate const caPath = path.join(certPath, 'ca.pem'); - if (fs.existsSync(caPath)) { - tlsOptions.ca = fs.readFileSync(caPath); + try { + tlsOptions.ca = await fsPromises.readFile(caPath); + } catch { + // CA certificate is optional } // Load client certificate const certPemPath = path.join(certPath, 'cert.pem'); - if (fs.existsSync(certPemPath)) { - tlsOptions.cert = fs.readFileSync(certPemPath); + try { + tlsOptions.cert = await fsPromises.readFile(certPemPath); + } catch { + // Client certificate is optional } // Load client private key const keyPath = path.join(certPath, 'key.pem'); - if (fs.existsSync(keyPath)) { - tlsOptions.key = fs.readFileSync(keyPath); + try { + tlsOptions.key = await fsPromises.readFile(keyPath); + } catch { + // Private key is optional } return tlsOptions; From 0a53cfcd616574109f414b51a0f9a5a995bb3013 Mon Sep 17 00:00:00 2001 From: Nicolas De Loof Date: Wed, 8 Oct 2025 20:51:52 +0200 Subject: [PATCH 2/2] prefer 'node:' imports for built-in node modules. Also only import the types/functions needed Signed-off-by: Nicolas De Loof --- lib/docker-client.ts | 40 +++++++++++++++------------------ lib/http.ts | 25 +++++++++++---------- lib/socket.ts | 18 +++++++-------- lib/ssh.ts | 20 ++++++++--------- lib/tls.ts | 12 +++++----- main.ts | 4 ++-- test/build.test.ts | 4 ++-- test/container.test.ts | 2 +- test/image.test.ts | 3 +-- test/multiplexed-stream.test.ts | 2 +- 10 files changed, 62 insertions(+), 68 deletions(-) diff --git a/lib/docker-client.ts b/lib/docker-client.ts index c295b98..5a868d9 100644 --- a/lib/docker-client.ts +++ b/lib/docker-client.ts @@ -1,9 +1,9 @@ -import * as net from 'net'; -import { promises as fsPromises } from 'fs'; -import * as path from 'path'; -import * as os from 'os'; -import * as http from 'http'; -import * as tls from 'tls'; +import { createConnection } from 'node:net'; +import { promises as fsPromises } from 'node:fs'; +import { join, resolve } from 'node:path'; +import { homedir } from 'node:os'; +import type { Agent } from 'node:http'; +import { connect as tlsConnect } from 'node:tls'; import * as types from './types/index.js'; import { HTTPClient } from './http.js'; import { SocketAgent } from './socket.js'; @@ -18,13 +18,13 @@ import { parseDockerHost, } from './util.js'; import type { AuthConfig, Platform } from './types/index.js'; -import type { SecureContextOptions } from 'tls'; +import type { SecureContextOptions } from 'node:tls'; // noinspection JSUnusedGlobalSymbols export class DockerClient { private api: HTTPClient; - constructor(agent: http.Agent, userAgent: string = 'docker/node-sdk') { + constructor(agent: Agent, userAgent: string = 'docker/node-sdk') { this.api = new HTTPClient(agent, userAgent); } @@ -45,7 +45,7 @@ export class DockerClient { try { const agent = new SocketAgent(() => - net.createConnection(socketPath), + createConnection(socketPath), ); return new DockerClient(agent, userAgent); } catch (error) { @@ -67,18 +67,18 @@ export class DockerClient { const tlsOptions = await TLS.loadCertificates(certificates); agent = new SocketAgent(() => - tls.connect({ host, port, ...tlsOptions }), + tlsConnect({ host, port, ...tlsOptions }), ); } else { // certificates is a SecureContextOptions type agent = new SocketAgent(() => - tls.connect({ host, port, ...certificates }), + tlsConnect({ host, port, ...certificates }), ); } } else { // Use SocketAgent with plain TCP socket creation function agent = new SocketAgent(() => - net.createConnection({ host, port }), + createConnection({ host, port }), ); } @@ -124,9 +124,9 @@ export class DockerClient { ); } - const configDir = process.env.DOCKER_CONFIG || os.homedir(); - const contextsDir = path.join(configDir, '.docker', 'contexts', 'meta'); - const tlsDir = path.join(configDir, '.docker', 'contexts', 'tls'); + const configDir = process.env.DOCKER_CONFIG || homedir(); + const contextsDir = join(configDir, '.docker', 'contexts', 'meta'); + const tlsDir = join(configDir, '.docker', 'contexts', 'tls'); try { // Read all directories in the contexts meta directory @@ -138,11 +138,7 @@ export class DockerClient { .map((dirent) => dirent.name); for (const contextDir of contextDirs) { - const metaJsonPath = path.join( - contextsDir, - contextDir, - 'meta.json', - ); + const metaJsonPath = join(contextsDir, contextDir, 'meta.json'); try { const metaContent = await fsPromises.readFile( @@ -160,7 +156,7 @@ export class DockerClient { ) { const dockerHost = meta.Endpoints.docker.Host; let certificates: string | undefined = undefined; - const tls = path.join(tlsDir, contextDir); + const tls = join(tlsDir, contextDir); try { await fsPromises.access(tls); certificates = tls; @@ -211,7 +207,7 @@ export class DockerClient { // Check for DOCKER_CONFIG environment variable, otherwise use default path const configPath = process.env.DOCKER_CONFIG || - path.join(os.homedir(), '.docker', 'config.json'); + join(homedir(), '.docker', 'config.json'); try { const configContent = await fsPromises.readFile(configPath, 'utf8'); diff --git a/lib/http.ts b/lib/http.ts index 011f7ff..89bb2e9 100644 --- a/lib/http.ts +++ b/lib/http.ts @@ -1,5 +1,6 @@ -import * as http from 'http'; -import * as stream from 'stream'; +import type { Agent, IncomingMessage, RequestOptions } from 'node:http'; +import { request } from 'node:http'; +import type { Readable, Writable, Duplex } from 'node:stream'; import { getErrorMessage } from './util.js'; // Docker stream content type constants @@ -56,7 +57,7 @@ function parseContentType(contentType?: string): { // Function to extract error message from response body function getErrorMessageFromResp( - res: http.IncomingMessage, + res: IncomingMessage, body: string | undefined, ): string | undefined { const contentType = res.headers['content-type']?.toLowerCase(); @@ -75,7 +76,7 @@ export interface HTTPResponse { statusCode?: number; headers: { [key: string]: string }; body?: string; - sock?: stream.Duplex; + sock?: Duplex; } /** @@ -84,10 +85,10 @@ export interface HTTPResponse { * Handles chunked transfer encoding and provides streaming response callbacks. */ export class HTTPClient { - private agent: http.Agent; + private agent: Agent; private userAgent: string; - constructor(agent: http.Agent, userAgent: string) { + constructor(agent: Agent, userAgent: string) { this.agent = agent; this.userAgent = userAgent; } @@ -130,7 +131,7 @@ export class HTTPClient { }; // Prepare body data and headers - let body: string | NodeJS.ReadableStream | undefined; + let body: string | Readable | undefined; if (data) { // Check if body is a stream if ( @@ -139,7 +140,7 @@ export class HTTPClient { typeof (data as any).read === 'function' ) { // Use chunked transfer encoding for streams - body = data as stream.Readable; + body = data as Readable; requestHeaders['Transfer-Encoding'] = 'chunked'; } else { // Convert to JSON string for objects @@ -150,7 +151,7 @@ export class HTTPClient { } // Create HTTP request options using our instance agent - const requestOptions: http.RequestOptions = { + const requestOptions: RequestOptions = { method, host: 'dockerhost', path, @@ -160,7 +161,7 @@ export class HTTPClient { // Helper function to create response object const createResponse = ( - res: http.IncomingMessage, + res: IncomingMessage, body?: string, ): HTTPResponse => { const responseHeaders: { [key: string]: string } = {}; @@ -179,7 +180,7 @@ export class HTTPClient { }; }; - const req = http.request(requestOptions, (res) => { + const req = request(requestOptions, (res) => { let responseBody = ''; // Helper function to handle response completion @@ -272,7 +273,7 @@ export class HTTPClient { req.write(body); req.end(); } else { - const input = body as stream.Readable; + const input = body as Readable; input.pipe(req); } } else { diff --git a/lib/socket.ts b/lib/socket.ts index c943d6d..7ec4bc3 100644 --- a/lib/socket.ts +++ b/lib/socket.ts @@ -1,16 +1,16 @@ -import * as net from 'net'; -import type { ClientRequestArgs } from 'http'; -import * as http from 'http'; -import * as stream from 'stream'; +import type { Socket } from 'node:net'; +import type { ClientRequestArgs } from 'node:http'; +import { Agent } from 'node:http'; +import type { Duplex } from 'node:stream'; /** * HTTP Agent that creates socket connections using a provided factory function. * This allows flexible socket creation strategies while supporting connection pooling. */ -export class SocketAgent extends http.Agent { - private socketFactory: () => net.Socket; +export class SocketAgent extends Agent { + private socketFactory: () => Socket; - constructor(createSocketFn: () => net.Socket) { + constructor(createSocketFn: () => Socket) { super({ keepAlive: true, keepAliveMsecs: 30000, @@ -26,8 +26,8 @@ export class SocketAgent extends http.Agent { // Override createConnection to use our socket factory this.createConnection = ( options: ClientRequestArgs, - callback?: (err: Error | null, socket: stream.Duplex) => void, - ): stream.Duplex => { + callback?: (err: Error | null, socket: Duplex) => void, + ): Duplex => { const socket = this.socketFactory(); socket.setNoDelay(true); socket.setKeepAlive(true, 30000); diff --git a/lib/ssh.ts b/lib/ssh.ts index 3fcfcdf..ecb50c2 100644 --- a/lib/ssh.ts +++ b/lib/ssh.ts @@ -1,7 +1,7 @@ -import * as net from 'net'; -import { promises as fsPromises } from 'fs'; -import * as path from 'path'; -import * as os from 'os'; +import { Socket } from 'node:net'; +import { promises as fsPromises } from 'node:fs'; +import { join } from 'node:path'; +import { homedir } from 'node:os'; import { Client } from 'ssh2'; /** @@ -14,9 +14,9 @@ export class SSH { */ private static async getPrivateKey(): Promise { const keyPaths = [ - path.join(os.homedir(), '.ssh', 'id_rsa'), - path.join(os.homedir(), '.ssh', 'id_ed25519'), - path.join(os.homedir(), '.ssh', 'id_ecdsa'), + join(homedir(), '.ssh', 'id_rsa'), + join(homedir(), '.ssh', 'id_ed25519'), + join(homedir(), '.ssh', 'id_ecdsa'), ]; for (const keyPath of keyPaths) { @@ -35,9 +35,7 @@ export class SSH { * @param sshHost SSH host string (e.g., "ssh://user@host:22/var/run/docker.sock") * @returns Function that creates new SSH socket connections */ - static async createSocketFactory( - sshHost: string, - ): Promise<() => net.Socket> { + static async createSocketFactory(sshHost: string): Promise<() => Socket> { // Preload the private key asynchronously const privateKey = await SSH.getPrivateKey(); @@ -83,7 +81,7 @@ export class SSH { // Return factory function that creates new SSH connections return () => { const conn = new Client(); - const sshStream = new net.Socket(); + const sshStream = new Socket(); conn.on('ready', () => { // Create a Unix socket connection through SSH diff --git a/lib/tls.ts b/lib/tls.ts index 122ec1c..a995618 100644 --- a/lib/tls.ts +++ b/lib/tls.ts @@ -1,7 +1,7 @@ -import { promises as fsPromises } from 'fs'; -import * as path from 'path'; +import { promises as fsPromises } from 'node:fs'; +import { join } from 'node:path'; import { getErrorMessage } from './util.js'; -import type { SecureContextOptions } from 'tls'; +import type { SecureContextOptions } from 'node:tls'; /** * TLS certificate utilities for secure Docker connections @@ -19,7 +19,7 @@ export class TLS { try { // Load CA certificate - const caPath = path.join(certPath, 'ca.pem'); + const caPath = join(certPath, 'ca.pem'); try { tlsOptions.ca = await fsPromises.readFile(caPath); } catch { @@ -27,7 +27,7 @@ export class TLS { } // Load client certificate - const certPemPath = path.join(certPath, 'cert.pem'); + const certPemPath = join(certPath, 'cert.pem'); try { tlsOptions.cert = await fsPromises.readFile(certPemPath); } catch { @@ -35,7 +35,7 @@ export class TLS { } // Load client private key - const keyPath = path.join(certPath, 'key.pem'); + const keyPath = join(certPath, 'key.pem'); try { tlsOptions.key = await fsPromises.readFile(keyPath); } catch { diff --git a/main.ts b/main.ts index 9f603a7..3c79d25 100644 --- a/main.ts +++ b/main.ts @@ -1,5 +1,5 @@ import { DockerClient } from './lib/docker-client.js'; -import * as fs from 'node:fs'; +import { createWriteStream } from 'node:fs'; try { const docker = await DockerClient.fromDockerConfig(); @@ -18,7 +18,7 @@ try { return value.Id; }); - const out = fs.createWriteStream('/tmp/test.tar'); + const out = createWriteStream('/tmp/test.tar'); await docker.containerExport(ctr, out); docker.close(); diff --git a/test/build.test.ts b/test/build.test.ts index 1945d3e..a1297e7 100644 --- a/test/build.test.ts +++ b/test/build.test.ts @@ -1,6 +1,6 @@ import { expect, test } from 'vitest'; import { DockerClient } from '../lib/docker-client.js'; -import * as tar from 'tar-stream'; +import { pack as createTarPack } from 'tar-stream'; import { fail } from 'node:assert'; test('imageBuild: build image from Dockerfile with tar-stream context', async () => { @@ -9,7 +9,7 @@ test('imageBuild: build image from Dockerfile with tar-stream context', async () const testTag = 'latest'; try { - const pack = tar.pack(); + const pack = createTarPack(); pack.entry( { name: 'Dockerfile' }, `FROM scratch diff --git a/test/container.test.ts b/test/container.test.ts index f5a62b2..f3f5934 100644 --- a/test/container.test.ts +++ b/test/container.test.ts @@ -1,7 +1,7 @@ import { assert, test } from 'vitest'; import { DockerClient } from '../lib/docker-client.js'; import { Filter } from '../lib/filter.js'; -import { Writable } from 'stream'; +import { Writable } from 'node:stream'; // Test Docker Container API functionality diff --git a/test/image.test.ts b/test/image.test.ts index 098a756..bf1f70f 100644 --- a/test/image.test.ts +++ b/test/image.test.ts @@ -1,8 +1,7 @@ import { assert, expect, test } from 'vitest'; import { DockerClient } from '../lib/docker-client.js'; import { Filter } from '../lib/filter.js'; -import { Writable } from 'stream'; -import { Readable } from 'node:stream'; +import { Writable, Readable } from 'node:stream'; import type { NotFoundError } from '../lib/http.js'; test('image lifecycle: create container, commit image, export/import, inspect, and prune', async () => { diff --git a/test/multiplexed-stream.test.ts b/test/multiplexed-stream.test.ts index cb4e724..f8f8129 100644 --- a/test/multiplexed-stream.test.ts +++ b/test/multiplexed-stream.test.ts @@ -1,6 +1,6 @@ import { assert, test } from 'vitest'; import { demultiplexStream } from '../lib/multiplexed-stream.js'; -import { Writable } from 'stream'; +import { Writable } from 'node:stream'; function createMockStream(): { stream: Writable; data: Buffer[] } { const data: Buffer[] = [];