Skip to content

refactor: reorganize services and types#71

Merged
kmendell merged 26 commits intomainfrom
refactor/reorganize-services
Apr 26, 2025
Merged

refactor: reorganize services and types#71
kmendell merged 26 commits intomainfrom
refactor/reorganize-services

Conversation

@kmendell
Copy link
Member

@kmendell kmendell commented Apr 26, 2025

Fixes: #27

Summary by CodeRabbit

  • New Features

    • Added dedicated modules for managing Docker containers, images, networks, volumes, and stacks, enabling more granular control and improved error handling.
    • Introduced new type definitions for Docker resources, providing clearer and more structured data throughout the application.
    • Added a full stack redeploy operation for Docker Compose stacks.
  • Refactor

    • Modularized Docker-related services, splitting them into resource-specific modules for better maintainability and clarity.
    • Updated import paths across the application to use the new modular service and type structure.
    • Enhanced code documentation and validation for stack operations.
  • Chores

    • Updated code formatting configuration to reduce maximum line length for improved readability.
  • Style

    • Improved code comments and logging for better operational transparency.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 26, 2025

Walkthrough

This change refactors the Docker service layer by splitting the monolithic docker-service.ts into multiple focused modules: container-service.ts, image-service.ts, network-service.ts, volume-service.ts, image-service.ts, core.ts, and stack-service.ts. Corresponding Docker-related types are reorganized into dedicated files under src/lib/types/docker/, with a new barrel file for easier imports. All imports throughout the codebase are updated to reference these new modules and type paths. No logic or control flow is changed outside of this modularization, and additional JSDoc comments and error handling improvements are added in the stack service.

Changes

Files/Groups Change Summary
src/lib/services/docker-service.ts, src/lib/types/image.ts Deleted monolithic Docker service and an image type file.
src/lib/services/docker/ (container-service.ts, core.ts, image-service.ts, network-service.ts, stack-service.ts, volume-service.ts) Added new modules, each handling a specific Docker resource or concern (containers, images, networks, volumes, core connection, stacks). Functions are split and refactored for modularity, with improved error handling, logging, and JSDoc comments. Stack service adds new validation and a redeploy function.
src/lib/types/docker/ (all files), src/lib/types/docker/index.ts Added/updated type definitions for Docker resources (containers, images, networks, volumes, connection options) and created a barrel export file for consolidated imports. Types are reorganized and expanded for clarity and structure.
All src/routes/ server and utility files Updated import paths to use new modular service and type files. No logic changes; only import sources are refactored.
.prettierrc Reduced printWidth from 600 to 450.

Sequence Diagram(s)

sequenceDiagram
    participant App as Application Layer
    participant Core as docker/core.ts
    participant Container as container-service.ts
    participant Image as image-service.ts
    participant Network as network-service.ts
    participant Volume as volume-service.ts
    participant Stack as stack-service.ts

    App->>Core: getDockerClient(), initializeDocker(), etc.
    App->>Container: listContainers(), createContainer(), etc.
    App->>Image: listImages(), pullImage(), etc.
    App->>Network: listNetworks(), createNetwork(), etc.
    App->>Volume: listVolumes(), createVolume(), etc.
    App->>Stack: loadComposeStacks(), createStack(), etc.
    Container->>Core: getDockerClient()
    Image->>Core: getDockerClient()
    Network->>Core: getDockerClient()
    Volume->>Core: getDockerClient()
    Stack->>Core: getDockerClient()
Loading

Assessment against linked issues

Objective Addressed Explanation
Refactor: Make Better Types / Services for Docker Connections (#27)

Possibly related PRs

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

src/lib/services/docker/core.ts

Oops! Something went wrong! :(

ESLint: 9.25.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@sveltejs/adapter-node' imported from /svelte.config.js
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
(node:9674) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use node --trace-warnings ... to show where the warning was created)

src/lib/services/docker/volume-service.ts

Oops! Something went wrong! :(

ESLint: 9.25.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@sveltejs/adapter-node' imported from /svelte.config.js
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
(node:9696) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use node --trace-warnings ... to show where the warning was created)

src/lib/services/docker/stack-service.ts

Oops! Something went wrong! :(

ESLint: 9.25.1

Error [ERR_MODULE_NOT_FOUND]: Cannot find package '@sveltejs/adapter-node' imported from /svelte.config.js
at packageResolve (node:internal/modules/esm/resolve:839:9)
at moduleResolve (node:internal/modules/esm/resolve:908:18)
at defaultResolve (node:internal/modules/esm/resolve:1038:11)
at ModuleLoader.defaultResolve (node:internal/modules/esm/loader:557:12)
at ModuleLoader.resolve (node:internal/modules/esm/loader:525:25)
at ModuleLoader.getModuleJob (node:internal/modules/esm/loader:246:38)
at ModuleJob._link (node:internal/modules/esm/module_job:126:49)
(node:9694) ExperimentalWarning: Importing JSON modules is an experimental feature and might change at any time
(Use node --trace-warnings ... to show where the warning was created)

  • 6 others
✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 21

🔭 Outside diff range comments (1)
src/routes/api/docker/test-connection/+server.ts (1)

18-18: 💡 Verification agent

🧩 Analysis chain

Critical: Pass hostToTest into getDockerInfo
You retrieve hostToTest from the query but invoke getDockerInfo() without it. This will ignore the specified host. Update the call to:

-		await getDockerInfo();
+		await getDockerInfo(hostToTest);

Confirm that getDockerInfo accepts a host parameter and adjust its signature if necessary.


🏁 Script executed:

#!/bin/bash
set -e

echo "🔍 Searching for all occurrences of getDockerInfo in the repo"
rg -n "getDockerInfo" .

echo
echo "📄 Displaying definitions or exports of getDockerInfo for context"
rg -n "export function getDockerInfo" -A3 -B1 .
rg -n "export const getDockerInfo" -A3 -B1 .
rg -n "function getDockerInfo" -A3 -B1 .

Length of output: 1288


🏁 Script executed:

#!/bin/bash
set -e

echo "🔍 Displaying the signature of getDockerInfo in core.ts"
rg -n "export async function getDockerInfo" -A5 -B2 src/lib/services/docker/core.ts

Length of output: 424


🏁 Script executed:

#!/bin/bash
set -e

echo "🔍 Context around hostToTest in test-connection route:"
rg -n "hostToTest" -A3 -B3 src/routes/api/docker/test-connection/+server.ts || true

echo
echo "🔍 Context around getDockerInfo call in test-connection route:"
rg -n "getDockerInfo" -A3 -B3 src/routes/api/docker/test-connection/+server.ts

Length of output: 1688


Critical: Pass hostToTest into getDockerInfo and update its signature

The GET handler in src/routes/api/docker/test-connection/+server.ts extracts hostToTest but never passes it along—so you’re still connecting to the default Docker target. You need to:

• In src/routes/api/docker/test-connection/+server.ts, change at line 18:

-    await getDockerInfo();
+    await getDockerInfo(hostToTest);

• In src/lib/services/docker/core.ts, update the getDockerInfo signature to accept an optional host and forward it to the client:

-export async function getDockerInfo() {
+export async function getDockerInfo(host?: string) {
     const docker = getDockerClient(host);
     return await docker.info();
 }

• If getDockerClient doesn’t yet accept a host parameter, adjust its signature and implementation to use the passed-in host (e.g. TCP socket or environment override).

This ensures the route actually tests the specified Docker endpoint.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 99d3f76 and 34182e0.

📒 Files selected for processing (47)
  • src/hooks.server.ts (1 hunks)
  • src/lib/services/compose.ts (0 hunks)
  • src/lib/services/docker-service.ts (0 hunks)
  • src/lib/services/docker/container-service.ts (1 hunks)
  • src/lib/services/docker/core.ts (1 hunks)
  • src/lib/services/docker/image-service.ts (1 hunks)
  • src/lib/services/docker/network-service.ts (1 hunks)
  • src/lib/services/docker/stack-service.ts (1 hunks)
  • src/lib/services/docker/volume-service.ts (1 hunks)
  • src/lib/types/docker/connection.type.ts (1 hunks)
  • src/lib/types/docker/container.type.ts (2 hunks)
  • src/lib/types/docker/image.type.ts (1 hunks)
  • src/lib/types/docker/index.ts (1 hunks)
  • src/lib/types/docker/network.type.ts (1 hunks)
  • src/lib/types/docker/volume.type.ts (1 hunks)
  • src/lib/types/image.ts (0 hunks)
  • src/routes/+page.server.ts (1 hunks)
  • src/routes/+page.svelte (0 hunks)
  • src/routes/api/containers/+server.ts (1 hunks)
  • src/routes/api/docker/containers/+server.ts (1 hunks)
  • src/routes/api/docker/test-connection/+server.ts (1 hunks)
  • src/routes/api/images/[id]/+server.ts (1 hunks)
  • src/routes/api/images/prune/+server.ts (1 hunks)
  • src/routes/api/images/pull-stream/[...name]/+server.ts (1 hunks)
  • src/routes/api/images/pull/[...name]/+server.ts (1 hunks)
  • src/routes/api/networks/[id]/+server.ts (1 hunks)
  • src/routes/api/networks/create/+server.ts (1 hunks)
  • src/routes/api/stacks/create/+server.ts (1 hunks)
  • src/routes/api/stacks/import/+server.ts (1 hunks)
  • src/routes/api/volumes/+server.ts (1 hunks)
  • src/routes/api/volumes/[name]/+server.ts (1 hunks)
  • src/routes/columns.ts (1 hunks)
  • src/routes/containers/+page.server.ts (1 hunks)
  • src/routes/containers/+page.svelte (2 hunks)
  • src/routes/containers/[id]/+page.server.ts (1 hunks)
  • src/routes/containers/columns.ts (1 hunks)
  • src/routes/containers/create-container-dialog.svelte (1 hunks)
  • src/routes/images/+page.server.ts (1 hunks)
  • src/routes/images/+page.svelte (1 hunks)
  • src/routes/images/columns.ts (1 hunks)
  • src/routes/networks/+page.server.ts (1 hunks)
  • src/routes/networks/columns.ts (1 hunks)
  • src/routes/stacks/+page.server.ts (1 hunks)
  • src/routes/stacks/[stackId]/+page.server.ts (1 hunks)
  • src/routes/stacks/columns.ts (1 hunks)
  • src/routes/volumes/+page.server.ts (1 hunks)
  • src/routes/volumes/columns.ts (1 hunks)
💤 Files with no reviewable changes (4)
  • src/routes/+page.svelte
  • src/lib/types/image.ts
  • src/lib/services/compose.ts
  • src/lib/services/docker-service.ts
🧰 Additional context used
🧬 Code Graph Analysis (4)
src/lib/services/docker/core.ts (1)
src/lib/types/docker/connection.type.ts (1)
  • DockerConnectionOptions (1-8)
src/lib/services/docker/volume-service.ts (2)
src/lib/types/docker/volume.type.ts (1)
  • ServiceVolume (1-7)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-49)
  • dockerHost (5-5)
src/lib/services/docker/image-service.ts (2)
src/lib/types/docker/image.type.ts (1)
  • ServiceImage (1-11)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-49)
  • dockerHost (5-5)
src/lib/services/docker/stack-service.ts (3)
src/lib/services/settings-service.ts (2)
  • getSettings (128-181)
  • ensureStacksDirectory (65-83)
src/lib/services/docker/core.ts (1)
  • getDockerClient (24-49)
src/lib/types/docker/stack.type.ts (4)
  • StackService (7-16)
  • Stack (18-30)
  • StackMeta (1-5)
  • StackUpdate (32-35)
🪛 Biome (1.9.4)
src/lib/services/docker/core.ts

[error] 5-5: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)


[error] 26-26: This let declares a variable that is only assigned once.

'connectionOpts' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 34-34: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 38-38: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 61-61: This let declares a variable that is only assigned once.

'connectionOpts' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 100-100: This let declares a variable that is only assigned once.

'connectionOpts' is never reassigned.

Safe fix: Use const instead.

(lint/style/useConst)


[error] 110-110: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)


[error] 115-115: Use Number.parseInt instead of the equivalent global.

ES2015 moved some globals into the Number namespace for consistency.
Safe fix: Use Number.parseInt instead.

(lint/style/useNumberNamespace)

src/lib/services/docker/volume-service.ts

[error] 125-125: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/lib/services/docker/image-service.ts

[error] 61-61: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/lib/services/docker/stack-service.ts

[error] 1-1: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 2-2: A Node.js builtin module should be imported with the node: protocol.

Using the node: protocol is more explicit and signals that the imported module belongs to Node.js.
Unsafe fix: Add the node: protocol.

(lint/style/useNodejsImportProtocol)


[error] 351-351: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/lib/services/docker/container-service.ts

[error] 264-264: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)


[error] 265-265: Forbidden non-null assertion.

(lint/style/noNonNullAssertion)


[error] 265-265: Forbidden non-null assertion.

Unsafe fix: Replace with optional chain operator ?. This operator includes runtime checks, so it is safer than the compile-only non-null assertion operator

(lint/style/noNonNullAssertion)


[error] 293-293: Avoid the delete operator which can impact performance.

Unsafe fix: Use an undefined assignment instead.

(lint/performance/noDelete)


[error] 313-313: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 317-317: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 320-320: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

🔇 Additional comments (39)
src/lib/types/docker/network.type.ts (1)

1-9: Well-defined ServiceNetwork type
The new ServiceNetwork alias cleanly models Docker network entities with required and nullable fields, improving type safety and consistency.

src/lib/types/docker/volume.type.ts (1)

1-7: Clear ServiceVolume definition
The ServiceVolume type accurately represents Docker volumes, and the explicit labels: { [label: string]: string } | null aligns with expected metadata usage.

src/routes/images/+page.svelte (1)

3-3: Use centralized Docker types barrel
Switching to import EnhancedImageInfo from $lib/types/docker simplifies and standardizes type imports across the application.

src/routes/containers/create-container-dialog.svelte (1)

3-3: Updated ContainerConfig import path
Importing ContainerConfig from the specific container.type module aligns with the new, more granular Docker type organization.

src/routes/stacks/columns.ts (1)

1-1: Adjusted Stack type import
Importing the Stack type from $lib/types/docker/stack.type reflects the refactored types directory structure for Docker stacks.

src/routes/api/images/pull/[...name]/+server.ts (1)

3-3: Import path updated to new image service module
Importing pullImage from $lib/services/docker/image-service correctly reflects the refactored service structure and replaces the deprecated monolithic service.

src/routes/api/images/pull-stream/[...name]/+server.ts (1)

2-2: Import path updated to Docker core module
Switching to getDockerClient from $lib/services/docker/core aligns with the new modular client management and replaces the old monolithic service.

src/routes/api/volumes/+server.ts (1)

3-3: Import path updated to new volume service module
Using createVolume from $lib/services/docker/volume-service matches the reorganized Docker services and removes the outdated unified service.

src/routes/images/columns.ts (1)

1-1: Type import updated to centralized Docker types
Importing ServiceImage from the $lib/types/docker barrel ensures consistency with the new consolidated type definitions.

src/routes/volumes/columns.ts (1)

5-5: Type import updated to centralized Docker types
Switching to ServiceVolume from the $lib/types/docker barrel aligns with the refactored type modules and maintains consistency across UI columns.

src/routes/api/containers/+server.ts (1)

3-3: Modular import path updated correctly
Importing createContainer from docker/container-service aligns with the refactor. Ensure that this service exports the expected function and that there are no lingering references to the old docker-service module in this route.

src/routes/api/images/prune/+server.ts (1)

3-3: Image pruning import path is correct
The pruneImages import from the new docker/image-service module matches the intended modularization. No further action required here.

src/routes/api/stacks/create/+server.ts (1)

3-3: Stack creation import path is accurate
Switching to createStack from docker/stack-service correctly reflects the split of compose logic into its own module.

src/routes/api/networks/create/+server.ts (1)

3-3: Network creation import path is accurate
The createNetwork import from docker/network-service is consistent with the new modular architecture.

src/routes/containers/columns.ts (1)

1-1: Import path updated to new centralized Docker types
The ServiceContainer type import has been updated to point at the new $lib/types/docker module, reflecting the migration from the monolithic service module to a dedicated types directory.

src/routes/api/images/[id]/+server.ts (1)

3-3: Use new dedicated image-service module
The removeImage import has been switched to $lib/services/docker/image-service, aligning this API route with the new modular service structure for Docker images.

src/routes/api/volumes/[name]/+server.ts (1)

3-3: Use new dedicated volume-service module
The removeVolume import now references $lib/services/docker/volume-service, consistent with the refactoring of Docker services into resource-specific modules.

src/routes/api/stacks/import/+server.ts (1)

3-3: Use new dedicated stack-service module
The importExternalStack import path has been updated to $lib/services/docker/stack-service, matching the consolidation of stack-related operations into the new stack service.

src/routes/api/networks/[id]/+server.ts (1)

3-3: Use new dedicated network-service module
The removeNetwork import has been migrated to $lib/services/docker/network-service, ensuring this API handler uses the new modular network service.

src/routes/columns.ts (1)

2-2: Update type imports to centralized Docker types.
Importing ServiceContainer and ServiceImage from the new $lib/types/docker barrel aligns perfectly with the refactored type organization and ensures consistency across the codebase.

src/hooks.server.ts (1)

1-1: Import service initialization from the new stack-service module.
Switching the initComposeService import to $lib/services/docker/stack-service correctly reflects the relocation of Docker Compose initialization logic into its dedicated module.

src/routes/stacks/+page.server.ts (1)

2-2: Redirect stack-load functions to the new stack-service.
Updating loadComposeStacks and discoverExternalStacks imports to $lib/services/docker/stack-service is consistent with the modularization of stack management.

src/routes/api/docker/containers/+server.ts (1)

3-3: Point container listing to the dedicated container-service.
Changing the import of listContainers to $lib/services/docker/container-service correctly reflects the split of the monolithic Docker service into granular modules.

src/routes/stacks/[stackId]/+page.server.ts (1)

1-2: Update stack-related imports and remove unused redirect.
Removing the unused redirect import and switching all stack operations (getStack, updateStack, startStack, stopStack, restartStack, removeStack) to $lib/services/docker/stack-service aligns this route with the new service structure.

src/routes/images/+page.server.ts (1)

2-3: Imports Updated to Dedicated Service and Type Modules

The import paths for listImages and isImageInUse have been correctly updated to $lib/services/docker/image-service, and EnhancedImageInfo now comes from the centralized $lib/types/docker barrel. These changes align with the modularization refactor and maintain consistency throughout the codebase.

src/routes/volumes/+page.server.ts (1)

2-3: Imports Updated to Dedicated Volume Service and Type Modules

The listVolumes and isVolumeInUse functions have been correctly imported from $lib/services/docker/volume-service, and ServiceVolume now comes from the centralized $lib/types/docker barrel. This aligns with the new modular structure and ensures consistency.

src/routes/containers/[id]/+page.server.ts (1)

2-2: Import Path Updated to Container Service

The Docker container management functions are now imported from the specialized $lib/services/docker/container-service module, reflecting the refactor. This maintains functionality and improves modularity.

src/routes/networks/columns.ts (1)

5-5: Import Type from Centralized Docker Types Module

The ServiceNetwork type import has been updated to $lib/types/docker, consolidating Docker-related type definitions. This change aligns with the broader modularization of types.

src/routes/networks/+page.server.ts (1)

2-3: Imports Refactored to Network Service and Type Modules

The listNetworks function is now correctly imported from $lib/services/docker/network-service, and ServiceNetwork is pulled from the centralized $lib/types/docker barrel. This matches the modular structure and improves maintainability.

src/routes/containers/+page.server.ts (1)

1-5: Great refactoring of imports for better modularity

The changes to import from granular service modules rather than a monolithic docker service improves code organization and maintainability. This aligns well with the separation of concerns principle.

src/routes/containers/+page.svelte (1)

10-10: Import path correctly updated to reflect new type organization

The updated import path aligns with the modular structure created in this refactoring effort.

src/lib/types/docker/index.ts (1)

1-7: Good use of barrel file for simplifying imports

Creating a barrel file to re-export all Docker-related types is a good practice that will simplify imports throughout the codebase.

src/lib/types/docker/connection.type.ts (1)

1-8: Well-structured interface for Docker connection options

The DockerConnectionOptions interface is well-defined with appropriate optional fields for Docker connection configuration. This supports the modular service architecture by centralizing connection types.

src/routes/+page.server.ts (1)

2-5: Import paths updated correctly to reflect new modular structure

The import statements have been properly updated to use the new specialized service modules and type imports, which aligns with the modular architecture refactoring. This separation of concerns improves maintainability by making it clearer which specific Docker service each function belongs to.

src/lib/types/docker/image.type.ts (2)

1-11: Well-structured type definition for Docker images

The ServiceImage type provides a comprehensive representation of Docker image metadata with proper typing for all properties. This type centralization in a dedicated file follows TypeScript best practices and will make maintenance easier.


13-15: Good extension pattern for enhanced image information

Using the intersection type pattern to extend ServiceImage with additional properties is a clean approach. The inUse flag will be useful for UI components that need to display whether an image is currently being used by containers.

src/lib/types/docker/container.type.ts (2)

1-15: Improved container type definition with proper Docker.Port typing

The ServiceContainer type definition is well-structured with appropriate typing for all properties. The use of Docker.Port[] from dockerode is a good practice as it leverages the library's type definitions rather than recreating them.


67-109: Well-documented container configuration interfaces

The container-related interfaces are clearly structured and adequately documented with comments. These types provide a comprehensive representation of the data needed for container operations, which will improve type safety throughout the application.

src/lib/services/docker/core.ts (1)

137-146: Good error handling in connection test

The implementation of testDockerConnection is well done with proper error handling and logging. This will be helpful for diagnosing Docker connection issues.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

🔭 Outside diff range comments (1)
src/lib/services/docker/core.ts (1)

142-147: 🧹 Nitpick (assertive)

Consider simplifying default export documentation.

The current comment on the default export is quite verbose. Consider simplifying it to be more concise while still explaining its purpose.

-/* The statement `export default getDockerClient;` is exporting the `getDockerClient` function as the
-default export of the module. This means that when another module imports from this module without
-specifying a particular named export, it will receive the `getDockerClient` function as the default
-export. */
+/**
+ * Export getDockerClient as the default for convenient importing
+ */
export default getDockerClient;
♻️ Duplicate comments (7)
src/routes/containers/+page.svelte (1)

22-23: Improved type safety by replacing 'any' with specific type.

Replacing the any type with the proper ServiceContainer type in the derived filter methods enhances type safety and catches potential errors at compile time rather than runtime.

src/lib/types/docker/index.ts (1)

1-6: 🧹 Nitpick (assertive)

Effective use of barrel file for centralized type exports.

Creating a barrel file to centralize and re-export Docker-related types is a good practice that simplifies imports across the codebase. This aligns well with the PR's goal of reorganizing services and types.

However, add a semicolon at the end of line 6 for consistency with the other export statements:

-export * from './connection.type'
+export * from './connection.type';
src/lib/services/docker/core.ts (1)

1-5: 🧹 Nitpick (assertive)

Good module structure with clear imports and defaults.

The module properly imports the Docker client and the connection options type. Setting a default Docker host is a good practice.

However, the type annotation for dockerHost can be omitted as the type is inferred from the initial value:

-export let dockerHost = 'unix:///var/run/docker.sock';
+export let dockerHost = 'unix:///var/run/docker.sock';
src/lib/services/docker/volume-service.ts (1)

49-55: Previous note about sequential inspect still applies

The container-by-container await loop is O(N) sequential and slows down hosts with many containers. Parallelising (or early-return on first hit) would cut latency.

src/lib/services/docker/network-service.ts (1)

48-56: Protect against default networks when caller passes an ID, not just a name

Earlier feedback suggested inspecting the network to compare details.Name as well as the supplied identifier. The current implementation still only checks the raw networkId, letting Docker’s builtin networks slip through when the caller passes their ID.

-		if (DEFAULT_NETWORK_NAMES.has(networkId)) {
-			throw new Error(`Network "${networkId}" is managed by Docker and cannot be removed.`);
-		}
-		const docker = getDockerClient();
-		const network = docker.getNetwork(networkId);
+		const docker = getDockerClient();
+		const network = docker.getNetwork(networkId);
+		const details = await network.inspect();
+		if (DEFAULT_NETWORK_NAMES.has(networkId) || DEFAULT_NETWORK_NAMES.has(details.Name)) {
+			throw new Error(`Network "${details.Name}" is managed by Docker and cannot be removed.`);
+		}
src/lib/services/docker/container-service.ts (2)

50-74: 🛠️ Refactor suggestion

Add a specific return type to getContainer to improve type safety.

The function lacks an explicit return type, which weakens TypeScript's type checking and makes it harder for consumers to understand the function's contract.

-export async function getContainer(containerId: string) {
+export async function getContainer(containerId: string): Promise<ContainerDetails | null> {

You'll need to import the ContainerDetails type from your Docker types module and ensure it matches the structure of the object being returned.


174-194: ⚠️ Potential issue

Fix handling of stream when follow === true to prevent runtime errors.

When follow is set to true, dockerode returns a ReadableStream instead of a Buffer, causing the .toString() call to throw a TypeError.

-const logsBuffer = options.follow === true ? await container.logs({ ...logOptions, follow: true }) : await container.logs({ ...logOptions, follow: false });
-let logString = logsBuffer.toString();
+const raw = await container.logs({ ...logOptions, follow: !!options.follow });
+
+// Handle both Buffer and Stream return types
+const logsBuffer: Buffer = Buffer.isBuffer(raw)
+  ? raw
+  : await new Promise<Buffer>((resolve, reject) => {
+      const chunks: Buffer[] = [];
+      raw.on('data', (chunk: Buffer) => chunks.push(chunk));
+      raw.on('end', () => resolve(Buffer.concat(chunks)));
+      raw.on('error', reject);
+    });
+
+let logString = logsBuffer.toString();

This change correctly handles both return types from the dockerode logs method.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: ASSERTIVE
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 34182e0 and 6f44d4b.

📒 Files selected for processing (10)
  • .prettierrc (1 hunks)
  • src/lib/services/docker/container-service.ts (1 hunks)
  • src/lib/services/docker/core.ts (1 hunks)
  • src/lib/services/docker/image-service.ts (1 hunks)
  • src/lib/services/docker/network-service.ts (1 hunks)
  • src/lib/services/docker/stack-service.ts (17 hunks)
  • src/lib/services/docker/volume-service.ts (1 hunks)
  • src/lib/types/docker/container.type.ts (2 hunks)
  • src/lib/types/docker/index.ts (1 hunks)
  • src/routes/containers/+page.svelte (2 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (6)
src/lib/services/docker/image-service.ts (2)
src/lib/types/docker/image.type.ts (1)
  • ServiceImage (1-11)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-32)
  • dockerHost (5-5)
src/lib/services/docker/core.ts (1)
src/lib/types/docker/connection.type.ts (1)
  • DockerConnectionOptions (1-8)
src/lib/services/docker/network-service.ts (2)
src/lib/types/docker/network.type.ts (1)
  • ServiceNetwork (1-9)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-32)
  • dockerHost (5-5)
src/lib/services/docker/volume-service.ts (2)
src/lib/types/docker/volume.type.ts (1)
  • ServiceVolume (1-7)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-32)
  • dockerHost (5-5)
src/lib/services/docker/container-service.ts (2)
src/lib/types/docker/container.type.ts (3)
  • ServiceContainer (4-15)
  • ContainerConfig (73-101)
  • ContainerCreate (68-70)
src/lib/services/docker/core.ts (2)
  • getDockerClient (24-32)
  • dockerHost (5-5)
src/lib/services/docker/stack-service.ts (1)
src/lib/types/docker/stack.type.ts (1)
  • Stack (18-30)
🪛 Biome (1.9.4)
src/lib/services/docker/image-service.ts

[error] 64-64: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/lib/services/docker/volume-service.ts

[error] 117-117: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

src/lib/services/docker/container-service.ts

[error] 314-314: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 318-318: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 321-321: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 256-256: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

🔇 Additional comments (10)
src/routes/containers/+page.svelte (1)

10-10: Good use of specific type imports.

Importing both ServiceContainer and ContainerConfig types directly from the container type file improves type safety and aligns with the refactoring goals of the PR.

src/lib/types/docker/container.type.ts (2)

1-15: Well-structured type definition for container data.

Creating a dedicated ServiceContainer type that maps to the Docker container data structure improves type safety when working with containers. The type includes all essential container properties and properly uses the Docker types from dockerode.


66-109: Good organization of container-related interfaces.

Moving the interfaces for container creation and configuration to a logical location in the file improves readability. The types are well-documented with comments that explain their purpose.

src/lib/services/docker/core.ts (6)

7-16: Well-documented getDockerInfo function.

The getDockerInfo function includes comprehensive JSDoc comments that explain its purpose and return value. The implementation is clean and straightforward.


18-32: Improved Docker client initialization.

The getDockerClient function now uses the extracted createConnectionOptions helper function, which reduces code duplication and improves maintainability.


34-64: Well-structured Docker initialization function.

The initializeDocker function properly handles different connection types and TLS options. Using Record<string, any> instead of just any provides better type safety while maintaining flexibility.


66-91: Good error handling in updateDockerConnection.

The function includes proper error handling with try/catch and logs helpful information both for successful connections and errors. Good validation to check for empty host strings.


93-109: Useful Docker connection testing function.

The testDockerConnection function provides a convenient way to validate whether the Docker connection is working properly. The error handling is appropriate and the return type is clearly defined.


111-140: Well-implemented connection options helper function.

The createConnectionOptions function effectively centralizes the logic for parsing different types of Docker connection strings. It handles Unix sockets, TCP, and HTTPS connections with appropriate defaults for ports.

src/lib/services/docker/volume-service.ts (1)

80-92: ⚠️ Potential issue

createVolume returns undefined fields – inspect after creation

docker.createVolume() yields a Volume handle, not an inspected object. Properties such as Name, Driver, etc. are therefore undefined, which breaks callers relying on ServiceVolume.

-		const volume = await docker.createVolume(options);
-		// Return the creation response which contains basic info
-		return {
-			name: volume.Name,
-			driver: volume.Driver,
-			mountpoint: volume.Mountpoint,
-			labels: volume.Labels || {},
-			scope: volume.Scope || 'local'
-		};
+		const volumeHandle = await docker.createVolume(options);
+		const inspectInfo = await volumeHandle.inspect();
+
+		return {
+			name: inspectInfo.Name,
+			driver: inspectInfo.Driver,
+			mountpoint: inspectInfo.Mountpoint,
+			labels: inspectInfo.Labels || {},
+			scope: inspectInfo.Scope || 'local'
+		};

Likely an incorrect or invalid review comment.

"singleQuote": true,
"trailingComma": "none",
"printWidth": 600,
"printWidth": 450,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Reduced printWidth to 450 for improved readability
Lowering the maximum line length helps enforce clearer formatting across the newly modularized services.
Consider verifying that no existing lines exceed this new threshold to avoid unexpected formatting diffs.

Run the following script to detect any lines longer than 450 characters:


🏁 Script executed:

#!/bin/bash
# Verify no lines exceed the new printWidth of 450
rg -n '.{451}' .

Length of output: 4742


Lines exceeding the new printWidth of 450 detected
Lowering printWidth to 450 helps enforce clearer formatting, but the following lines will be reformatted unexpectedly unless addressed. Please break these up (or extract long class strings into variables) or reconsider the threshold.

• src/routes/+page.svelte:307
• src/lib/components/ui/checkbox/checkbox.svelte:10
• src/lib/components/ui/tabs/tabs-trigger.svelte:8
• src/lib/components/ui/select/select-content.svelte:24
• src/lib/components/ui/dialog/dialog-content.svelte:22
• src/lib/components/ui/dropdown-menu/dropdown-menu-content.svelte:17
• src/lib/components/ui/switch/switch.svelte:8
• src/lib/components/ui/input/input.svelte:14

Suggested actions:

  • Break long attribute strings across multiple lines.
  • Extract large class={…} values into constants.
  • Or, if these patterns are unavoidable, consider increasing printWidth.

const stoppedContainers = $derived(containers?.filter((c: ServiceContainer) => c.state === 'exited').length || 0);

// Calculate total containers
const totalContainers = $derived(containers?.length || 0);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Consider adding type annotation to totalContainers for consistency.

While you've updated the type annotations for runningContainers and stoppedContainers, the totalContainers derived store remains untyped. For consistency, consider adding the same type annotation here.

-const totalContainers = $derived(containers?.length || 0);
+const totalContainers = $derived(containers?.length || 0);

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +64 to +69
export async function removeImage(imageId: string, force: boolean = false): Promise<void> {
try {
const docker = getDockerClient();
const image = docker.getImage(imageId);
await image.remove({ force });
console.log(`Docker Service: Image "${imageId}" removed successfully.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Remove the redundant type annotation on force & satisfy Biome

Biome flags force: boolean = false as a “trivially inferred” type. Dropping the explicit type keeps the signature shorter and makes the linter happy.

-export async function removeImage(imageId: string, force: boolean = false): Promise<void> {
+export async function removeImage(imageId: string, force = false): Promise<void> {
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
export async function removeImage(imageId: string, force: boolean = false): Promise<void> {
try {
const docker = getDockerClient();
const image = docker.getImage(imageId);
await image.remove({ force });
console.log(`Docker Service: Image "${imageId}" removed successfully.`);
export async function removeImage(imageId: string, force = false): Promise<void> {
try {
const docker = getDockerClient();
const image = docker.getImage(imageId);
await image.remove({ force });
console.log(`Docker Service: Image "${imageId}" removed successfully.`);
🧰 Tools
🪛 Biome (1.9.4)

[error] 64-64: This type annotation is trivially inferred from its initialization.

Safe fix: Remove the type annotation.

(lint/style/noInferrableTypes)

Comment on lines +18 to +32
const parseRepoTag = (tag: string | undefined): { repo: string; tag: string } => {
if (!tag || tag === '<none>:<none>') {
return { repo: '<none>', tag: '<none>' };
}
const withoutDigest = tag.split('@')[0];
const lastSlash = withoutDigest.lastIndexOf('/');
const lastColon = withoutDigest.lastIndexOf(':');
if (lastColon === -1 || lastColon < lastSlash) {
return { repo: withoutDigest, tag: 'latest' };
}
return {
repo: withoutDigest.substring(0, lastColon),
tag: withoutDigest.substring(lastColon + 1)
};
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Extract parseRepoTag into a shared util to avoid re-allocation on every call

parseRepoTag is re-created each time listImages runs. Hoisting it (or moving it to a small util module) removes the per-call allocation and makes it re-usable from other services that need the same parsing logic.

-		const parseRepoTag = (tag: string | undefined): { repo: string; tag: string } => {
+function parseRepoTag(tag: string | undefined): { repo: string; tag: string } {

Committable suggestion skipped: line range outside the PR's diff.

Comment on lines +161 to +166
const pullTimeout = 10 * 60 * 1000; // 10 min

// Wait for the pull to complete by consuming the stream with 10 minute timeout
const result = await Promise.race([new Promise((resolve, reject) => docker.modem.followProgress(stream, (err, out) => (err ? reject(err) : resolve(out)))), new Promise((_, reject) => setTimeout(() => reject(new Error(`Pull timed-out after ${pullTimeout} ms`)), pullTimeout))]);

console.log(`Docker Service: Image "${imageRef}" pulled successfully.`);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

result is unused – drop the binding or expose pull feedback

The value returned from Promise.race is stored in result but never referenced. Either propagate the data to the caller or simply await the promise to avoid the unused-variable overhead.

-		const result = await Promise.race([
+		await Promise.race([
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const pullTimeout = 10 * 60 * 1000; // 10 min
// Wait for the pull to complete by consuming the stream with 10 minute timeout
const result = await Promise.race([new Promise((resolve, reject) => docker.modem.followProgress(stream, (err, out) => (err ? reject(err) : resolve(out)))), new Promise((_, reject) => setTimeout(() => reject(new Error(`Pull timed-out after ${pullTimeout} ms`)), pullTimeout))]);
console.log(`Docker Service: Image "${imageRef}" pulled successfully.`);
const pullTimeout = 10 * 60 * 1000; // 10 min
// Wait for the pull to complete by consuming the stream with 10 minute timeout
await Promise.race([
new Promise((resolve, reject) =>
docker.modem.followProgress(
stream,
(err, out) => (err ? reject(err) : resolve(out))
)
),
new Promise((_, reject) =>
setTimeout(
() =>
reject(
new Error(`Pull timed-out after ${pullTimeout} ms`)
),
pullTimeout
)
)
]);
console.log(`Docker Service: Image "${imageRef}" pulled successfully.`);

Comment on lines +255 to +268
if (config.ports?.length) {
const exposedPorts: Record<string, {}> = {};
const portBindings: Record<string, Array<{ HostPort: string }>> = {};
for (const p of config.ports) {
const key = `${p.containerPort}/tcp`;
exposedPorts[key] = {};
portBindings[key] = [{ HostPort: p.hostPort }];
}
containerOptions.ExposedPorts = exposedPorts;
containerOptions.HostConfig = {
...(containerOptions.HostConfig ?? {}),
PortBindings: portBindings
};
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Remove empty object type {} in Record to improve type safety.

Using {} as a type is discouraged as it can accept more values than intended. Biome flagged this as a violation of the lint/complexity/noBannedTypes rule.

-    const exposedPorts: Record<string, {}> = {};
+    const exposedPorts: Record<string, object> = {};

Alternatively, you could be even more explicit with:

const exposedPorts: Record<string, Record<string, never>> = {};
🧰 Tools
🪛 Biome (1.9.4)

[error] 256-256: Don't use '{}' as a type.

Prefer explicitly define the object shape. '{}' means "any non-nullable value".

(lint/complexity/noBannedTypes)

Comment on lines +314 to +316
if (error.message && error.message.includes('IPAMConfig')) {
throw new Error(`Failed to create container: Invalid IP address configuration for network "${config.network}". ${error.message}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use optional chaining when checking error messages.

The current approach using the logical AND operator works but is less concise than using optional chaining. This was flagged by the static analyzer.

-if (error.message && error.message.includes('IPAMConfig')) {
+if (error.message?.includes('IPAMConfig')) {
    throw new Error(`Failed to create container: Invalid IP address configuration for network "${config.network}". ${error.message}`);
}

Apply the same change to similar error handling patterns on lines 318 and 321.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (error.message && error.message.includes('IPAMConfig')) {
throw new Error(`Failed to create container: Invalid IP address configuration for network "${config.network}". ${error.message}`);
}
if (error.message?.includes('IPAMConfig')) {
throw new Error(`Failed to create container: Invalid IP address configuration for network "${config.network}". ${error.message}`);
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 314-314: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Comment on lines +270 to +274
// Set up volume mounts if provided
if (config.volumes && config.volumes.length > 0) {
containerOptions.HostConfig = containerOptions.HostConfig || {};
containerOptions.HostConfig.Binds = config.volumes.map((vol) => `${vol.source}:${vol.target}${vol.readOnly ? ':ro' : ''}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Remove redundant null check with nullish coalescing operator.

The current implementation has a conditional assignment followed by potential use, which could be simplified.

if (config.volumes && config.volumes.length > 0) {
-    containerOptions.HostConfig = containerOptions.HostConfig || {};
+    containerOptions.HostConfig = containerOptions.HostConfig ?? {};
    containerOptions.HostConfig.Binds = config.volumes.map((vol) => `${vol.source}:${vol.target}${vol.readOnly ? ':ro' : ''}`);
}

This matches the pattern used for port bindings and is more consistent with modern TypeScript patterns.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// Set up volume mounts if provided
if (config.volumes && config.volumes.length > 0) {
containerOptions.HostConfig = containerOptions.HostConfig || {};
containerOptions.HostConfig.Binds = config.volumes.map((vol) => `${vol.source}:${vol.target}${vol.readOnly ? ':ro' : ''}`);
}
// Set up volume mounts if provided
if (config.volumes && config.volumes.length > 0) {
containerOptions.HostConfig = containerOptions.HostConfig ?? {};
containerOptions.HostConfig.Binds = config.volumes.map((vol) => `${vol.source}:${vol.target}${vol.readOnly ? ':ro' : ''}`);
}

Comment on lines +318 to +323
if (error.message && error.message.includes('NanoCpus')) {
throw new Error(`Invalid CPU limit specified: ${error.message}`);
}
if (error.message && error.message.includes('Memory')) {
throw new Error(`Invalid Memory limit specified: ${error.message}`);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use optional chaining consistently in error handling.

Similar to the previous comment, apply optional chaining to the remaining error checks.

-if (error.message && error.message.includes('NanoCpus')) {
+if (error.message?.includes('NanoCpus')) {
    throw new Error(`Invalid CPU limit specified: ${error.message}`);
}
-if (error.message && error.message.includes('Memory')) {
+if (error.message?.includes('Memory')) {
    throw new Error(`Invalid Memory limit specified: ${error.message}`);
}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (error.message && error.message.includes('NanoCpus')) {
throw new Error(`Invalid CPU limit specified: ${error.message}`);
}
if (error.message && error.message.includes('Memory')) {
throw new Error(`Invalid Memory limit specified: ${error.message}`);
}
if (error.message?.includes('NanoCpus')) {
throw new Error(`Invalid CPU limit specified: ${error.message}`);
}
if (error.message?.includes('Memory')) {
throw new Error(`Invalid Memory limit specified: ${error.message}`);
}
🧰 Tools
🪛 Biome (1.9.4)

[error] 318-318: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)


[error] 321-321: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

Comment on lines +278 to +281
containerOptions.HostConfig = containerOptions.HostConfig || {};
if (!containerOptions.NetworkingConfig) {
containerOptions.HostConfig.NetworkMode = config.network;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick (assertive)

Use nullish coalescing for HostConfig assignment.

Similar to the volumes section, this should use the nullish coalescing operator for consistency.

if (config.network) {
-    containerOptions.HostConfig = containerOptions.HostConfig || {};
+    containerOptions.HostConfig = containerOptions.HostConfig ?? {};
    if (!containerOptions.NetworkingConfig) {
        containerOptions.HostConfig.NetworkMode = config.network;
    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
containerOptions.HostConfig = containerOptions.HostConfig || {};
if (!containerOptions.NetworkingConfig) {
containerOptions.HostConfig.NetworkMode = config.network;
}
if (config.network) {
containerOptions.HostConfig = containerOptions.HostConfig ?? {};
if (!containerOptions.NetworkingConfig) {
containerOptions.HostConfig.NetworkMode = config.network;
}
}

@kmendell kmendell merged commit 7079dc1 into main Apr 26, 2025
1 check passed
@kmendell kmendell deleted the refactor/reorganize-services branch April 26, 2025 19:05
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor: Make Better Types / Services for Docker Connections

1 participant