# Docker Module - Development Hints ## OOP Refactoring - Clean Architecture (2025-11-24) ### Architecture Changes The module has been restructured to follow a clean OOP Facade pattern: - **DockerHost** is now the single entry point for all Docker operations - All resource classes extend abstract `DockerResource` base class - Static methods are prefixed with `_` to indicate internal use - Public API is exclusively through DockerHost methods ### Key Changes **1. Factory Pattern** - All resource creation/retrieval goes through DockerHost: ```typescript // Old (deprecated): const container = await DockerContainer.getContainers(dockerHost); const network = await DockerNetwork.createNetwork(dockerHost, descriptor); // New (clean API): const containers = await dockerHost.getContainers(); const network = await dockerHost.createNetwork(descriptor); ``` **2. Container Management Methods Added** The DockerContainer class now has full CRUD and streaming operations: **Lifecycle:** - `container.start()` - Start container - `container.stop(options?)` - Stop container - `container.remove(options?)` - Remove container - `container.refresh()` - Reload state **Information:** - `container.inspect()` - Get detailed info - `container.logs(options)` - Get logs as string (one-shot) - `container.stats(options)` - Get stats **Streaming & Interactive:** - `container.streamLogs(options)` - Stream logs continuously (follow mode) - `container.attach(options)` - Attach to main process (PID 1) with bidirectional stream - `container.exec(command, options)` - Execute commands in container interactively **Example - Stream Logs:** ```typescript const container = await dockerHost.getContainerById('abc123'); const logStream = await container.streamLogs({ timestamps: true }); logStream.on('data', (chunk) => { console.log(chunk.toString()); }); ``` **Example - Attach to Container:** ```typescript const { stream, close } = await container.attach({ stdin: true, stdout: true, stderr: true }); // Pipe to/from process process.stdin.pipe(stream); stream.pipe(process.stdout); // Later: detach await close(); ``` **Example - Execute Command:** ```typescript const { stream, close } = await container.exec('ls -la /app', { tty: true }); stream.on('data', (chunk) => { console.log(chunk.toString()); }); stream.on('end', async () => { await close(); }); ``` **3. DockerResource Base Class** All resource classes now extend `DockerResource`: - Consistent `dockerHost` property (not `dockerHostRef`) - Required `refresh()` method - Standardized constructor pattern **4. ImageStore Encapsulation** - `dockerHost.imageStore` is now private - Use `dockerHost.storeImage(name, stream)` instead - Use `dockerHost.retrieveImage(name)` instead **5. Creation Descriptors Support Both Primitives and Instances** Interfaces now accept both strings and class instances: ```typescript // Both work: await dockerHost.createService({ image: 'nginx:latest', // String networks: ['my-network'], // String array secrets: ['my-secret'] // String array }); await dockerHost.createService({ image: imageInstance, // DockerImage instance networks: [networkInstance], // DockerNetwork array secrets: [secretInstance] // DockerSecret array }); ``` ### Migration Guide Replace all static method calls with dockerHost methods: - `DockerContainer.getContainers(host)` → `dockerHost.getContainers()` - `DockerImage.createFromRegistry(host, opts)` → `dockerHost.createImageFromRegistry(opts)` - `DockerService.createService(host, desc)` → `dockerHost.createService(desc)` - `dockerHost.imageStore.storeImage(...)` → `dockerHost.storeImage(...)` ## smartrequest v5+ Migration (2025-11-17) ### Breaking Change smartrequest v5.0.0+ returns web `ReadableStream` objects (Web Streams API) instead of Node.js streams. ### Solution Implemented All streaming methods now convert web ReadableStreams to Node.js streams using: ```typescript plugins.smartstream.nodewebhelpers.convertWebReadableToNodeReadable(webStream) ``` ### Files Modified - `ts/classes.host.ts`: - `requestStreaming()` - Converts web stream to Node.js stream before returning - `getEventObservable()` - Works with converted Node.js stream - `ts/classes.image.ts`: - `createFromTarStream()` - Uses converted Node.js stream for event handling - `exportToTarStream()` - Uses converted Node.js stream for backpressure management ### Testing - Build:  All 11 type errors resolved - Tests:  Node.js tests pass (DockerHost, DockerContainer, DockerImage, DockerImageStore) ### Notes - The conversion maintains backward compatibility with existing code expecting Node.js stream methods (`.on()`, `.emit()`, `.pause()`, `.resume()`) - smartstream's `nodewebhelpers` module provides bidirectional conversion utilities between web and Node.js streams