-
Notifications
You must be signed in to change notification settings - Fork 8
Feat/mothership v2 #1551
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Feat/mothership v2 #1551
Conversation
WalkthroughThis pull request introduces a major refactor of the Unraid Connect plugin’s backend, shifting from a GraphQL-over-HTTP approach to a WebSocket-based architecture for mothership communication. It adds a new WebSocket client, updates environment/configuration handling, removes obsolete GraphQL code generation, and extensively revises the GraphQL schema and related services. Changes
Sequence Diagram(s)WebSocket-based Mothership Communication FlowsequenceDiagram
participant Plugin as Unraid Connect Plugin
participant UnraidServerClient as WebSocket Client
participant Mothership as Mothership Server
participant LocalExecutor as LocalGraphQLExecutor
Plugin->>UnraidServerClient: initializeClient(apiKey, mothershipUrl)
UnraidServerClient->>Mothership: Open WebSocket connection
Mothership-->>UnraidServerClient: Sends GraphQL request (JSON)
UnraidServerClient->>LocalExecutor: execute({query, variables, ...})
LocalExecutor-->>UnraidServerClient: GraphQL response
UnraidServerClient->>Mothership: Send response (JSON)
loop Every 30s
UnraidServerClient->>Mothership: Send plaintext ping
Mothership-->>UnraidServerClient: pong
end
Plugin->>UnraidServerClient: disconnect()
UnraidServerClient->>Mothership: Close WebSocket
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested reviewers
Poem
📜 Recent review detailsConfiguration used: CodeRabbit UI ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (6)
✅ Files skipped from review due to trivial changes (1)
🚧 Files skipped from review as they are similar to previous changes (3)
🧰 Additional context used📓 Path-based instructions (2)api/**/*📄 CodeRabbit Inference Engine (.cursor/rules/api-rules.mdc)
Files:
api/src/unraid-api/**/*📄 CodeRabbit Inference Engine (.cursor/rules/api-rules.mdc)
Files:
🧠 Learnings (17)📓 Common learnings
📚 Learning: the unraidfilemodifierservice in the unraid api provides comprehensive error handling for all filemo...
Applied to files:
📚 Learning: the unraidfilemodifierservice in the unraid api provides comprehensive error handling for all filemo...
Applied to files:
📚 Learning: in the unraid api, filemodification implementations (like logrotatemodification) don't need to handl...
Applied to files:
📚 Learning: in the unraid api, filemodification implementations (apply/rollback methods) don't need to implement...
Applied to files:
📚 Learning: applies to api/src/unraid-api/**/* : prefer adding new files to the nestjs repository located at api...
Applied to files:
📚 Learning: applies to api/src/unraid-api/**/* : prefer adding new files to the nestjs repo located at api/src/u...
Applied to files:
📚 Learning: when modifying `apikey.roles` in `removerolefromapikey` and `addroletoapikey` within `api/src/unraid...
Applied to files:
📚 Learning: when reviewing typescript files containing php code snippets intended for file modifications (like i...
Applied to files:
📚 Learning: the build script in web/package.json should include type-check command (`npm run type-check`) even w...
Applied to files:
📚 Learning: in dockereventservice, the chokidar file watcher is configured with `ignoreinitial: false` to ensure...
Applied to files:
📚 Learning: the project uses a custom or extended implementation of nestjs configservice that includes a `set()`...
Applied to files:
📚 Learning: the project uses a custom configservice implementation that includes a `set()` method for runtime co...
Applied to files:
📚 Learning: this codebase uses esm (ecmascript modules) and requires .js extensions in import statements, even w...
Applied to files:
📚 Learning: in the filemodification class's patch handling: - `results === false` indicates patch application fa...
Applied to files:
📚 Learning: the base `filemodification` class's `shouldapply` method should include validation for file existenc...
Applied to files:
📚 Learning: for critical components in the unraid api, such as retrieving version information from package.json,...
Applied to files:
🪛 GitHub Actions: CI - Main (API)api/src/unraid-api/unraid-file-modifier/file-modification.ts[error] 114-153: Failed to apply patch due to invalid patch format: No hunks found for /usr/local/emhttp/plugins/dynamix/include/DefaultPageLayout.php. [error] 114-153: Failed to apply patch due to invalid patch format: No hunks found for /usr/local/emhttp/plugins/dynamix/Notifications.page. [error] Failed to check if files should be applied due to missing 'constants' export on 'node:fs' mock in vitest tests. 🔇 Additional comments (4)
✨ Finishing Touches
🧪 Generate unit tests
🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. 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)
Other keywords and placeholders
CodeRabbit Configuration File (
|
…ient - Updated package.json scripts to remove MOTHERSHIP_GRAPHQL_LINK environment variable. - Changed MOTHERSHIP_GRAPHQL_LINK to MOTHERSHIP_BASE_URL in environment.ts. - Removed GraphQL code generation for Mothership types in codegen.ts. - Updated connection status services to use MOTHERSHIP_BASE_URL. - Refactored MothershipSubscriptionHandler to utilize UnraidServerClient instead of GraphQL client. - Implemented UnraidServerClient for WebSocket communication with Mothership. - Enhanced MothershipController to manage UnraidServerClient lifecycle. - Added reconnection logic and ping/pong handling in UnraidServerClient. - Simplified GraphQL execution logic in UnraidServerClient.
9ab5977
to
5caeb09
Compare
Claude finished @elibosley's task —— View job PR Review: Mothership v2I've completed a comprehensive review of this PR. Here's my detailed feedback: Review Tasks
🔍 Code Quality & ArchitectureStrengths:
Areas for Improvement: 1. Error Handling & Logging 🚨
2. Hardcoded Values & Magic Numbers
3. Code Duplication
🔒 Security Concerns1. API Key Exposure
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 5
🧹 Nitpick comments (5)
api/.env.development (1)
20-20
: LGTM: New environment variable supports centralized configuration.The addition of
PATHS_CONNECT_STATUS
aligns with the shift toward centralized configuration management viaConfigService
.Consider adding quotes around the value to match the project's .env formatting conventions:
-PATHS_CONNECT_STATUS=./dev/states/connectStatus.json # Connect status file for development +PATHS_CONNECT_STATUS="./dev/states/connectStatus.json" # Connect status file for developmentpackages/unraid-api-plugin-connect/src/mothership-proxy/mothership.controller.ts (1)
39-41
: Simplify the disconnect logic.The null check is redundant since the optional chaining operator already handles null/undefined cases safely.
- if (this.clientService.getClient()) { - this.clientService.getClient()?.disconnect(); - } + this.clientService.getClient()?.disconnect();packages/unraid-api-plugin-connect/src/mothership-proxy/local-graphql-executor.service.ts (2)
125-150
: Consider making field name mappings configurable.The hardcoded field name mappings in
transformRemoteFieldName
could become a maintenance burden as the API evolves. Consider extracting these mappings to a configuration object.+private readonly fieldNameMappings: Record<string, string> = { + 'remoteGetDockerInfo': 'docker', + 'remoteGetVms': 'vms', + 'remoteGetSystemInfo': 'system', +}; + private transformRemoteFieldName(fieldName: string): string { - // Handle common patterns - if (fieldName === 'remoteGetDockerInfo') { - return 'docker'; - } - if (fieldName === 'remoteGetVms') { - return 'vms'; - } - if (fieldName === 'remoteGetSystemInfo') { - return 'system'; - } + // Check configured mappings first + if (this.fieldNameMappings[fieldName]) { + return this.fieldNameMappings[fieldName]; + } // Generic transformation: remove "remoteGet" and convert to camelCase if (fieldName.startsWith('remoteGet')) {
152-155
: Implement the stopSubscription method.The
stopSubscription
method is currently just a stub. This could lead to memory leaks if subscriptions are not properly cleaned up.Do you want me to help implement the subscription cleanup logic or open an issue to track this task?
packages/unraid-api-plugin-connect/src/mothership-proxy/unraid-server-client.service.ts (1)
56-56
: Validate WebSocket URL construction.The WebSocket URL is constructed by appending to the base URL. Ensure the base URL doesn't already end with a slash to avoid double slashes.
- const wsUrl = `${this.mothershipUrl}/ws/server` + const wsUrl = `${this.mothershipUrl.replace(/\/$/, '')}/ws/server`
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
api/.env.development
(1 hunks)api/dev/configs/api.json
(1 hunks)api/dev/configs/connect.json
(1 hunks)api/dev/keys/7789353b-40f4-4f3b-a230-b1f22909abff.json
(1 hunks)api/dev/keys/b5b4aa3d-8e40-4c92-bc40-d50182071886.json
(0 hunks)api/generated-schema.graphql
(5 hunks)api/src/environment.ts
(1 hunks)packages/unraid-api-plugin-connect/codegen.ts
(1 hunks)packages/unraid-api-plugin-connect/package.json
(1 hunks)packages/unraid-api-plugin-connect/src/connection-status/cloud.service.ts
(2 hunks)packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts
(3 hunks)packages/unraid-api-plugin-connect/src/mothership-proxy/local-graphql-executor.service.ts
(1 hunks)packages/unraid-api-plugin-connect/src/mothership-proxy/mothership-subscription.handler.ts
(1 hunks)packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.controller.ts
(4 hunks)packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.module.ts
(1 hunks)packages/unraid-api-plugin-connect/src/mothership-proxy/unraid-server-client.service.ts
(1 hunks)
💤 Files with no reviewable changes (1)
- api/dev/keys/b5b4aa3d-8e40-4c92-bc40-d50182071886.json
🧰 Additional context used
📓 Path-based instructions (1)
api/**/*
📄 CodeRabbit Inference Engine (.cursor/rules/api-rules.mdc)
api/**/*
: Use pnpm as the only package manager
Always run scripts from api/package.json unless specifically requested otherwise
Files:
api/dev/configs/api.json
api/dev/keys/7789353b-40f4-4f3b-a230-b1f22909abff.json
api/dev/configs/connect.json
api/src/environment.ts
api/generated-schema.graphql
🧠 Learnings (15)
📓 Common learnings
Learnt from: mdatelle
PR: unraid/api#1106
File: unraid-ui/src/components/index.ts:2-2
Timestamp: 2025-02-04T17:21:39.710Z
Learning: The unraid-ui package is undergoing a major refactoring process, and breaking changes are expected during this transition period.
Learnt from: pujitm
PR: unraid/api#1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: elibosley
PR: unraid/api#969
File: web/justfile:7-9
Timestamp: 2024-11-27T15:30:02.252Z
Learning: In the Unraid Connect project, the different implementations of the `setup` commands in `web/justfile` and `api/justfile` are intentional and correct behavior.
Learnt from: elibosley
PR: unraid/api#1101
File: api/src/unraid-api/unraid-file-modifier/modifications/patches/default-page-layout.patch:24-27
Timestamp: 2025-01-31T22:01:22.708Z
Learning: The Unraid UI uses a modern notification system with a custom `unraid-toaster` component replacing the legacy jGrowl notifications. The system is backed by a comprehensive GraphQL API with real-time subscription support for notification updates.
Learnt from: pujitm
PR: unraid/api#1415
File: plugin/plugins/dynamix.unraid.net.plg:234-236
Timestamp: 2025-06-11T14:14:30.348Z
Learning: For the Unraid Connect plugin, the script `/etc/rc.d/rc.unraid-api` is bundled with the plugin package itself, so its presence on the target system is guaranteed during installation.
Learnt from: mdatelle
PR: unraid/api#942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in `api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts`, methods like `removeRoleFromApiKey` rely on service-level error handling.
Learnt from: elibosley
PR: unraid/api#1101
File: api/src/unraid-api/unraid-file-modifier/modifications/__test__/snapshots/DefaultPageLayout.php.modified.snapshot.php:203-207
Timestamp: 2025-02-03T17:21:26.738Z
Learning: The project uses patches to override existing Unraid pages rather than modifying them directly.
api/dev/keys/7789353b-40f4-4f3b-a230-b1f22909abff.json (3)
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/auth/auth.service.ts:0-0
Timestamp: 2024-11-04T20:41:22.303Z
Learning: In api/src/unraid-api/auth/auth.service.ts
, the addRoleToApiKey
function operates on API keys stored as JSON files in a directory, not a database, so concurrency is not a concern for modifying apiKey.roles
.
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/auth/auth.service.ts:0-0
Timestamp: 2024-11-04T20:44:46.432Z
Learning: When modifying apiKey.roles
in removeRoleFromApiKey
and addRoleToApiKey
within api/src/unraid-api/auth/auth.service.ts
, concurrency issues are not a concern because the keys are stored in the file system.
Learnt from: elibosley
PR: #1425
File: api/dev/configs/connect.json:5-13
Timestamp: 2025-06-20T20:50:14.050Z
Learning: Connect configuration files like api/dev/configs/connect.json use their own naming conventions (e.g., apikey, accesstoken, idtoken, refreshtoken) as implementation details, and these should not be changed to follow general camelCase patterns.
api/dev/configs/connect.json (2)
Learnt from: elibosley
PR: #1425
File: api/dev/configs/connect.json:5-13
Timestamp: 2025-06-20T20:50:14.050Z
Learning: Connect configuration files like api/dev/configs/connect.json use their own naming conventions (e.g., apikey, accesstoken, idtoken, refreshtoken) as implementation details, and these should not be changed to follow general camelCase patterns.
Learnt from: pujitm
PR: #1211
File: web/codegen.ts:14-14
Timestamp: 2025-03-12T13:35:43.900Z
Learning: The JSON scalar type in web/codegen.ts was temporarily changed from 'string' to 'any' for compatibility with JsonForms integration. This change facilitates the implementation of the Connect settings web component.
packages/unraid-api-plugin-connect/src/connection-status/cloud.service.ts (6)
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: pujitm
PR: #1211
File: api/src/graphql/schema/types/connect/connect.graphql:142-146
Timestamp: 2025-03-14T16:10:38.562Z
Learning: The updateApiSettings mutation in api/src/unraid-api/graph/connect/connect.resolver.ts is protected with the @UsePermissions decorator that requires UPDATE permission on the CONFIG resource.
Learnt from: pujitm
PR: #1211
File: web/codegen.ts:14-14
Timestamp: 2025-03-12T13:35:43.900Z
Learning: The JSON scalar type in web/codegen.ts was temporarily changed from 'string' to 'any' for compatibility with JsonForms integration. This change facilitates the implementation of the Connect settings web component.
Learnt from: elibosley
PR: #1381
File: plugin/source/dynamix.unraid.net/usr/local/share/dynamix.unraid.net/install/scripts/verify_install.sh:11-16
Timestamp: 2025-05-08T19:31:52.417Z
Learning: The dynamix.my.servers
namespace is still valid and should not be changed to dynamix.unraid.net
in file paths, as both namespaces coexist in the codebase.
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.module.ts (9)
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: mdatelle
PR: #1106
File: unraid-ui/src/components/index.ts:2-2
Timestamp: 2025-02-04T17:21:39.710Z
Learning: The unraid-ui package is undergoing a major refactoring process, and breaking changes are expected during this transition period.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/api-rules.mdc:0-0
Timestamp: 2025-07-21T14:00:06.258Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repository located at api/src/unraid-api/ instead of the legacy code
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repo located at api/src/unraid-api/ instead of the legacy code
Learnt from: elibosley
PR: #1408
File: web/components/ApiKey/PermissionCounter.vue:6-6
Timestamp: 2025-05-23T21:59:29.632Z
Learning: This codebase uses ESM (ECMAScript Modules) and requires .js extensions in import statements, even when importing from TypeScript files, as the imports refer to the compiled JavaScript output.
Learnt from: elibosley
PR: #1308
File: unraid-ui/src/components/common/loading/Error.vue:2-2
Timestamp: 2025-04-02T21:21:29.168Z
Learning: Components in the unraid-ui folder require explicit imports and are not autoloaded, unlike other parts of the project that may use Nuxt.js autoloading features.
Learnt from: elibosley
PR: #1211
File: api/src/unraid-api/graph/connect/connect-settings.service.ts:48-53
Timestamp: 2025-03-13T16:17:55.820Z
Learning: In NestJS services, dynamic imports should be wrapped in try/catch blocks with proper error logging and fallback handling to prevent unhandled rejections from crashing the application.
packages/unraid-api-plugin-connect/package.json (14)
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run pnpm codegen for GraphQL code generation in the web directory
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Always run pnpm codegen
for GraphQL code generation in the web directory
Learnt from: pujitm
PR: #1211
File: web/codegen.ts:14-14
Timestamp: 2025-03-12T13:35:43.900Z
Learning: The JSON scalar type in web/codegen.ts was temporarily changed from 'string' to 'any' for compatibility with JsonForms integration. This change facilitates the implementation of the Connect settings web component.
Learnt from: mdatelle
PR: #1122
File: web/package.json:16-16
Timestamp: 2025-02-06T17:25:45.397Z
Learning: The build script in web/package.json should include type-check command (npm run type-check
) even when NODE_ENV is production, as it provides value for local builds by catching type errors before pushing to CI/CD.
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run scripts from api/package.json unless requested
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/api-rules.mdc:0-0
Timestamp: 2025-07-21T14:00:06.258Z
Learning: Applies to api/**/* : Always run scripts from api/package.json unless specifically requested otherwise
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: pujitm
PR: #1211
File: api/src/graphql/schema/types/connect/connect.graphql:142-146
Timestamp: 2025-03-14T16:10:38.562Z
Learning: The updateApiSettings mutation in api/src/unraid-api/graph/connect/connect.resolver.ts is protected with the @UsePermissions decorator that requires UPDATE permission on the CONFIG resource.
Learnt from: pujitm
PR: #1415
File: plugin/plugins/dynamix.unraid.net.plg:234-236
Timestamp: 2025-06-11T14:14:30.348Z
Learning: For the Unraid Connect plugin, the script /etc/rc.d/rc.unraid-api
is bundled with the plugin package itself, so its presence on the target system is guaranteed during installation.
Learnt from: elibosley
PR: #1120
File: plugin/package.json:0-0
Timestamp: 2025-02-05T14:43:48.568Z
Learning: In Node.js projects, npm scripts should be organized with clear namespacing (e.g., build:, docker:, env:*) and include proper environment validation and error handling. Each script should follow the single responsibility principle.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/
must follow this naming convention
Learnt from: elibosley
PR: #1408
File: web/components/ApiKey/PermissionCounter.vue:6-6
Timestamp: 2025-05-23T21:59:29.632Z
Learning: This codebase uses ESM (ECMAScript Modules) and requires .js extensions in import statements, even when importing from TypeScript files, as the imports refer to the compiled JavaScript output.
Learnt from: elibosley
PR: #1120
File: plugin/Dockerfile:1-3
Timestamp: 2025-02-05T14:25:37.316Z
Learning: The Dockerfile in the plugin directory is specifically for building artifacts during CI and is not used for production deployments. It creates a build environment with Node.js and necessary dependencies to generate plugin files.
packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts (12)
Learnt from: elibosley
PR: #1151
File: plugin/builder/utils/consts.ts:6-6
Timestamp: 2025-03-04T14:55:00.903Z
Learning: The startingDir constant in plugin/builder/utils/consts.ts is defined using process.cwd(), which can cause issues if directory changes occur after importing this constant. Using __dirname.split('/builder')[0] would make it more reliable by making it relative to the file location rather than the current working directory.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/api-rules.mdc:0-0
Timestamp: 2025-07-21T14:00:06.258Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repository located at api/src/unraid-api/ instead of the legacy code
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repo located at api/src/unraid-api/ instead of the legacy code
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/auth/auth.service.ts:0-0
Timestamp: 2024-11-04T20:44:46.432Z
Learning: When modifying apiKey.roles
in removeRoleFromApiKey
and addRoleToApiKey
within api/src/unraid-api/auth/auth.service.ts
, concurrency issues are not a concern because the keys are stored in the file system.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: pujitm
PR: #1211
File: api/src/graphql/schema/types/connect/connect.graphql:142-146
Timestamp: 2025-03-14T16:10:38.562Z
Learning: The updateApiSettings mutation in api/src/unraid-api/graph/connect/connect.resolver.ts is protected with the @UsePermissions decorator that requires UPDATE permission on the CONFIG resource.
Learnt from: pujitm
PR: #1367
File: packages/unraid-api-plugin-connect/src/pubsub/user.service.ts:44-52
Timestamp: 2025-04-23T20:19:42.542Z
Learning: The project uses a custom or extended implementation of NestJS ConfigService that includes a set()
method for runtime configuration mutation, unlike the standard @nestjs/config package which only provides getter methods.
Learnt from: pujitm
PR: #1367
File: packages/unraid-api-plugin-connect/src/pubsub/user.service.ts:44-52
Timestamp: 2025-04-23T20:19:42.542Z
Learning: The project uses a custom ConfigService implementation that includes a set()
method for runtime configuration mutation, unlike the standard @nestjs/config package which only provides getter methods.
Learnt from: pujitm
PR: #1367
File: packages/unraid-api-plugin-connect/src/event-handler/mothership.handler.ts:50-57
Timestamp: 2025-06-05T14:27:57.441Z
Learning: For NestJS applications with async event handlers using @onevent decorator, implement generic error handling using a custom decorator or base class rather than individual try-catch blocks in each handler method to avoid application crashes from unhandled promise rejections.
Learnt from: pujitm
PR: #1367
File: packages/unraid-api-plugin-connect/src/event-handler/mothership.handler.ts:50-57
Timestamp: 2025-06-05T14:27:57.441Z
Learning: NestJS async event handlers using @onevent decorator can crash the entire application if exceptions are not caught. Industry best practices recommend generic error handling approaches like custom decorators, Sentry's automatic wrapping, or global event exception services rather than individual try-catch blocks in each handler.
Learnt from: elibosley
PR: #1211
File: api/src/unraid-api/graph/connect/connect-settings.service.ts:48-53
Timestamp: 2025-03-13T16:17:55.820Z
Learning: In NestJS services, dynamic imports should be wrapped in try/catch blocks with proper error logging and fallback handling to prevent unhandled rejections from crashing the application.
Learnt from: elibosley
PR: #1352
File: packages/unraid-api-plugin-connect/src/config.persistence.ts:0-0
Timestamp: 2025-04-21T18:44:39.643Z
Learning: Use Promise-based file writing instead of callback-based approaches for better error handling and to allow proper propagation of success/failure states to callers.
api/.env.development (5)
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run pnpm codegen for GraphQL code generation in the web directory
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Always run pnpm codegen
for GraphQL code generation in the web directory
Learnt from: pujitm
PR: #1047
File: api/src/unraid-api/graph/sandbox-plugin.ts:57-57
Timestamp: 2025-01-15T21:34:00.006Z
Learning: In the GraphQL sandbox (api/src/unraid-api/graph/sandbox-plugin.ts), CSRF token validation should fail silently with a fallback value to maintain sandbox accessibility, as it's a development tool where strict security measures aren't required.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: elibosley
PR: #1063
File: web/_data/serverState.ts:137-147
Timestamp: 2025-01-27T14:57:46.617Z
Learning: The values in web/_data/serverState.ts
are used for testing purposes and should remain as hardcoded mock data to facilitate testing different scenarios.
api/src/environment.ts (11)
Learnt from: elibosley
PR: #1381
File: plugin/builder/cli/common-environment.ts:18-22
Timestamp: 2025-05-08T19:28:37.034Z
Learning: In plugin/builder/cli/common-environment.ts, the getDefaultBaseUrl() function intentionally returns an invalid URL when running in CI environments to force explicit specification of the base URL parameter rather than relying on defaults.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/
must follow this naming convention
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.mutation.ts : GraphQL mutations must be placed in .mutation.ts
files
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/ must follow this naming convention (.query.ts for queries, .mutation.ts for mutations)
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.mutation.ts : GraphQL mutations must be placed in .mutation.ts files under web/
Learnt from: elibosley
PR: #1063
File: web/_data/serverState.ts:137-147
Timestamp: 2025-01-27T14:57:46.617Z
Learning: The values in web/_data/serverState.ts
are used for testing purposes and should remain as hardcoded mock data to facilitate testing different scenarios.
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run pnpm codegen for GraphQL code generation in the web directory
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Always run pnpm codegen
for GraphQL code generation in the web directory
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run scripts from api/package.json unless requested
Learnt from: elibosley
PR: #1408
File: web/components/ApiKey/PermissionCounter.vue:6-6
Timestamp: 2025-05-23T21:59:29.632Z
Learning: This codebase uses ESM (ECMAScript Modules) and requires .js extensions in import statements, even when importing from TypeScript files, as the imports refer to the compiled JavaScript output.
packages/unraid-api-plugin-connect/codegen.ts (13)
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:41-47
Timestamp: 2024-11-05T14:48:56.949Z
Learning: Input types for GraphQL mutations can be pulled from the GraphQL codegen types, as they are generated into the API files. Therefore, explicit typing in the resolver files may be unnecessary.
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Always run pnpm codegen for GraphQL code generation in the web directory
Learnt from: pujitm
PR: #1211
File: web/codegen.ts:14-14
Timestamp: 2025-03-12T13:35:43.900Z
Learning: The JSON scalar type in web/codegen.ts was temporarily changed from 'string' to 'any' for compatibility with JsonForms integration. This change facilitates the implementation of the Connect settings web component.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Always run pnpm codegen
for GraphQL code generation in the web directory
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: pujitm
PR: #1047
File: api/src/unraid-api/graph/sandbox-plugin.ts:57-57
Timestamp: 2025-01-15T21:34:00.006Z
Learning: In the GraphQL sandbox (api/src/unraid-api/graph/sandbox-plugin.ts), CSRF token validation should fail silently with a fallback value to maintain sandbox accessibility, as it's a development tool where strict security measures aren't required.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/
must follow this naming convention
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/ must follow this naming convention (.query.ts for queries, .mutation.ts for mutations)
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.query.ts : GraphQL queries must be placed in .query.ts
files
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.query.ts : GraphQL queries must be placed in .query.ts files under web/
Learnt from: elibosley
PR: #1408
File: web/components/ApiKey/PermissionCounter.vue:6-6
Timestamp: 2025-05-23T21:59:29.632Z
Learning: This codebase uses ESM (ECMAScript Modules) and requires .js extensions in import statements, even when importing from TypeScript files, as the imports refer to the compiled JavaScript output.
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.mutation.ts : GraphQL mutations must be placed in .mutation.ts files under web/
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.controller.ts (5)
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: mdatelle
PR: #1106
File: unraid-ui/src/components/index.ts:2-2
Timestamp: 2025-02-04T17:21:39.710Z
Learning: The unraid-ui package is undergoing a major refactoring process, and breaking changes are expected during this transition period.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: pujitm
PR: #1211
File: api/src/graphql/schema/types/connect/connect.graphql:142-146
Timestamp: 2025-03-14T16:10:38.562Z
Learning: The updateApiSettings mutation in api/src/unraid-api/graph/connect/connect.resolver.ts is protected with the @UsePermissions decorator that requires UPDATE permission on the CONFIG resource.
packages/unraid-api-plugin-connect/src/mothership-proxy/local-graphql-executor.service.ts (7)
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/
must follow this naming convention
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.{query,mutation}.ts : All GraphQL under web/ must follow this naming convention (.query.ts for queries, .mutation.ts for mutations)
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/web-graphql.mdc:0-0
Timestamp: 2025-07-21T14:00:25.140Z
Learning: Applies to web/**/*.query.ts : GraphQL queries must be placed in .query.ts
files
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to web/**/*.query.ts : GraphQL queries must be placed in .query.ts files under web/
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership-subscription.handler.ts (9)
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: pujitm
PR: #1075
File: web/components/Notifications/Sidebar.vue:52-57
Timestamp: 2025-01-30T19:56:42.055Z
Learning: Notification links in the Unraid API are validated at creation time on the server side, making additional client-side validation unnecessary when receiving notifications through GraphQL subscriptions.
Learnt from: elibosley
PR: #1526
File: api/src/unraid-api/graph/resolvers/ups/ups.resolver.ts:82-85
Timestamp: 2025-07-22T13:29:32.175Z
Learning: In GraphQL subscriptions using the graphql-subscriptions PubSub, the correct method is asyncIterableIterator()
, not asyncIterator()
. The asyncIterableIterator
method returns an AsyncIterableIterator
that conforms to both AsyncIterable
and AsyncIterator
interfaces, which is required for GraphQL subscription resolvers. Using asyncIterator()
would cause TypeScript type errors as it only returns an AsyncIterator
that doesn't satisfy the AsyncIterable
interface requirement.
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: elibosley
PR: #1222
File: api/src/unraid-api/graph/resolvers/logs/logs.resolver.ts:37-65
Timestamp: 2025-03-17T13:41:52.496Z
Learning: The LogsService in Unraid API uses a reference counting mechanism to track log file subscriptions, ensuring file watchers remain active until all subscribers have unsubscribed.
Learnt from: pujitm
PR: #978
File: web/helpers/apollo-cache/index.ts:133-157
Timestamp: 2024-12-11T17:20:09.604Z
Learning: In web/helpers/apollo-cache/index.ts
, when updating the cache in the cache.updateQuery
function, it's sufficient to check if data
is present, as type checking inside data
is handled at the GraphQL layer.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: pujitm
PR: #1148
File: web/composables/gql/graphql.ts:1812-1821
Timestamp: 2025-02-19T17:30:55.418Z
Learning: When using Apollo Vue's subscribeToMore, throttling can be implemented by wrapping the update function with lodash's throttle or using RxJS's throttleTime operator to prevent flooding the client with updates.
Learnt from: elibosley
PR: #1526
File: api/src/unraid-api/graph/resolvers/ups/ups.resolver.ts:82-85
Timestamp: 2025-07-22T13:29:32.175Z
Learning: In GraphQL subscriptions using the graphql-subscriptions PubSub, the correct method to create an async iterator is asyncIterableIterator()
, not asyncIterator()
. This is the modern/current method used in the graphql-subscriptions library.
packages/unraid-api-plugin-connect/src/mothership-proxy/unraid-server-client.service.ts (7)
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/auth/api-key.service.ts:62-70
Timestamp: 2024-11-05T14:49:07.308Z
Learning: In api/src/unraid-api/auth/api-key.service.ts
, when handling read errors in the findById
method, throw a GraphQLError
instead of an InternalServerErrorException
.
Learnt from: mdatelle
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:111-113
Timestamp: 2024-11-06T20:59:25.809Z
Learning: In the Unraid API project, error handling for mutations is handled at the service level rather than in the GraphQL resolvers. Specifically, in api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts
, methods like removeRoleFromApiKey
rely on service-level error handling.
Learnt from: pujitm
PR: #1211
File: web/composables/gql/gql.ts:17-18
Timestamp: 2025-03-12T13:48:14.850Z
Learning: In the Unraid API project, the duplicate GraphQL query and mutation strings in gql.ts files are intentionally generated by GraphQL CodeGen tool and are necessary for the type system to function properly.
Learnt from: CR
PR: unraid/api#0
File: .cursor/rules/api-rules.mdc:0-0
Timestamp: 2025-07-21T14:00:06.258Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repository located at api/src/unraid-api/ instead of the legacy code
Learnt from: CR
PR: unraid/api#0
File: CLAUDE.md:0-0
Timestamp: 2025-07-28T15:34:24.715Z
Learning: Applies to api/src/unraid-api/**/* : Prefer adding new files to the NestJS repo located at api/src/unraid-api/ instead of the legacy code
Learnt from: mdatelle
PR: #1106
File: unraid-ui/src/components/index.ts:2-2
Timestamp: 2025-02-04T17:21:39.710Z
Learning: The unraid-ui package is undergoing a major refactoring process, and breaking changes are expected during this transition period.
Learnt from: pujitm
PR: #1367
File: packages/unraid-api-plugin-connect/src/pubsub/user.service.ts:44-52
Timestamp: 2025-04-23T20:19:42.542Z
Learning: The project uses a custom or extended implementation of NestJS ConfigService that includes a set()
method for runtime configuration mutation, unlike the standard @nestjs/config package which only provides getter methods.
api/generated-schema.graphql (1)
Learnt from: elibosley
PR: #942
File: api/src/unraid-api/graph/resolvers/auth/auth.resolver.ts:41-47
Timestamp: 2024-11-05T14:48:56.949Z
Learning: Input types for GraphQL mutations can be pulled from the GraphQL codegen types, as they are generated into the API files. Therefore, explicit typing in the resolver files may be unnecessary.
🪛 Gitleaks (8.27.2)
api/dev/keys/7789353b-40f4-4f3b-a230-b1f22909abff.json
5-5: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.
(generic-api-key)
🪛 GitHub Actions: CI - Main (API)
packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts
[error] 64-64: TypeError: The "path" argument must be of type string. Received an instance of Object. This error occurs multiple times during writeStatus calls.
🪛 dotenv-linter (3.3.0)
api/.env.development
[warning] 20-20: [UnorderedKey] The PATHS_CONNECT_STATUS key should go before the PATHS_CONNECT_STATUS_FILE_PATH key
[warning] 20-20: [ValueWithoutQuotes] This value needs to be surrounded in quotes
[warning] 21-21: [QuoteCharacter] The value has quote characters (', ")
[warning] 21-21: [UnorderedKey] The ENVIRONMENT key should go before the PATHS_ACTIVATION_BASE key
[warning] 22-22: [QuoteCharacter] The value has quote characters (', ")
[warning] 22-22: [UnorderedKey] The NODE_ENV key should go before the PATHS_ACTIVATION_BASE key
[warning] 23-23: [QuoteCharacter] The value has quote characters (', ")
[warning] 24-24: [UnorderedKey] The PLAYGROUND key should go before the PORT key
[warning] 25-25: [UnorderedKey] The INTROSPECTION key should go before the NODE_ENV key
[warning] 26-26: [QuoteCharacter] The value has quote characters (', ")
[warning] 26-26: [UnorderedKey] The MOTHERSHIP_BASE_URL key should go before the NODE_ENV key
🔇 Additional comments (20)
api/src/environment.ts (1)
96-100
: LGTM! Clean environment variable refactor.The renaming from
MOTHERSHIP_GRAPHQL_LINK
toMOTHERSHIP_BASE_URL
and removal of the/ws
suffix aligns well with the architectural shift from GraphQL-over-HTTP to WebSocket-based communication. The conditional logic and fallback behavior are preserved correctly.api/dev/configs/api.json (1)
2-2
: Appropriate version bump for the architectural changes.The minor version increment from "4.11.0" to "4.12.0" correctly reflects the introduction of new WebSocket-based mothership communication features while maintaining backward compatibility.
packages/unraid-api-plugin-connect/src/connection-status/cloud.service.ts (2)
96-96
: LGTM! Consistent environment variable update.The change from
MOTHERSHIP_GRAPHQL_LINK
toMOTHERSHIP_BASE_URL
aligns with the environment configuration updates and maintains the existing connectivity check functionality.
207-207
: LGTM! Consistent environment variable update.The change from
MOTHERSHIP_GRAPHQL_LINK
toMOTHERSHIP_BASE_URL
aligns with the environment configuration updates and maintains the existing DNS check functionality.api/dev/keys/7789353b-40f4-4f3b-a230-b1f22909abff.json (1)
1-11
: Development API key correctly scoped to development environmentNo references to this key or its secret were found in production code. Keeping the JSON file under
api/dev/keys/
is appropriate for development/testing purposes.packages/unraid-api-plugin-connect/package.json (1)
16-16
: LGTM! Script cleanup aligns with architectural changes.Removing the inline
MOTHERSHIP_GRAPHQL_LINK
environment variable from the codegen script is consistent with the transition to WebSocket-based communication and the renaming of environment variables throughout the codebase.packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.module.ts (2)
11-11
: LGTM: Clean architectural transition to WebSocket-based services.The addition of
LocalGraphQLExecutor
andUnraidServerClientService
imports aligns well with the broader shift from HTTP GraphQL to WebSocket-based mothership communication.Also applies to: 15-15
23-25
: LGTM: Provider registration looks correct.The replacement of
MothershipGraphqlClientService
withUnraidServerClientService
andLocalGraphQLExecutor
in the providers array is properly structured and consistent with the architectural changes.api/.env.development (1)
26-26
: LGTM: URL change supports WebSocket architecture transition.The change from
MOTHERSHIP_GRAPHQL_LINK
toMOTHERSHIP_BASE_URL
with the new localhost URL correctly supports the shift to WebSocket-based communication.api/dev/configs/connect.json (1)
11-18
: LGTM: Configuration additions support enhanced connect functionality.The new fields (
version
,extraOrigins
,sandbox
, and token fields) provide necessary configuration placeholders for the updated connect architecture. The JSON structure remains valid and maintains backward compatibility.packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts (2)
4-5
: LGTM: Proper imports for directory handling.The addition of
mkdir
anddirname
imports supports the enhanced directory creation functionality.
63-66
: LGTM: Enhanced robustness with directory creation.The addition of directory creation before writing the status file improves robustness by ensuring the target directory exists.
packages/unraid-api-plugin-connect/codegen.ts (1)
29-31
: LGTM: GraphQL codegen removal aligns with WebSocket architecture.Removing the mothership GraphQL type generation is the correct approach since the new
UnraidServerClientService
handles GraphQL operations dynamically over WebSocket connections rather than using pre-generated static types.packages/unraid-api-plugin-connect/src/mothership-proxy/mothership.controller.ts (2)
5-19
: LGTM! Clean transition to WebSocket-based architecture.The migration from
MothershipGraphqlClientService
toUnraidServerClientService
is well-implemented, with appropriate updates to comments and dependency injection.
51-57
: Good defensive programming with proper validation.The addition of the
apiKey
check alongsideisLoaded
ensures the mothership connection is only established when proper credentials are available.packages/unraid-api-plugin-connect/src/mothership-proxy/local-graphql-executor.service.ts (1)
24-24
: LocalGraphQLExecutor correctly injects InternalClientService
- The constructor’s dependency on InternalClientService is intentional and matches its use elsewhere (e.g., in MothershipSubscriptionHandler). No change to use UnraidServerClientService is needed.
- Remaining suggestions for this new executor:
- Implement stopSubscription (around line 154) or document its intended behavior.
- Externalize the hard-coded field-name mappings (currently in lines 68–109 and 125–150) into a configuration or constants file for easier maintenance.
[fix_required]packages/unraid-api-plugin-connect/src/mothership-proxy/unraid-server-client.service.ts (2)
402-418
: LGTM! Proper cleanup in disconnect method.The disconnect method correctly:
- Disables reconnection
- Clears ping interval
- Clears reconnection timeout
- Closes the WebSocket connection
This prevents memory leaks and ensures clean shutdown.
210-248
: Excellent reconnection implementation with exponential backoff.The reconnection logic is well-implemented with:
- Exponential backoff starting at 1 second
- Maximum delay cap of 30 minutes
- Clear logging of reconnection attempts
- Proper cleanup of existing timeouts
api/generated-schema.graphql (2)
1-3
: Auto-generated file - changes look appropriate.This schema file is automatically generated and reflects the architectural changes in the PR. The removal of remote access/cloud types and addition of comprehensive UPS management features align with the WebSocket-based mothership communication refactor.
1398-1526
: Well-documented UPS types with clear field descriptions.The new UPS-related types are thoroughly documented with units, examples, and clear explanations. This will greatly help API consumers understand the data structure.
// Use environment variable if set, otherwise default to /var/local/emhttp/connectStatus.json | ||
return this.configService.get('PATHS_CONNECT_STATUS') || '/var/local/emhttp/connectStatus.json'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Verification agent
🧩 Analysis chain
Fix critical path handling issue causing pipeline failures.
The pipeline failures indicate that configService.get('PATHS_CONNECT_STATUS')
is returning an object instead of a string, causing a TypeError when passed to dirname()
.
The issue is likely that the configuration value is not being properly typed or retrieved. Apply this fix:
get statusFilePath() {
- // Use environment variable if set, otherwise default to /var/local/emhttp/connectStatus.json
- return this.configService.get('PATHS_CONNECT_STATUS') || '/var/local/emhttp/connectStatus.json';
+ // Use environment variable if set, otherwise default to /var/local/emhttp/connectStatus.json
+ return this.configService.get<string>('PATHS_CONNECT_STATUS') || '/var/local/emhttp/connectStatus.json';
}
Run this script to verify the configuration service implementation:
🏁 Script executed:
#!/bin/bash
# Description: Check how PATHS_CONNECT_STATUS is configured in the environment and config service
# Find configuration files that might define PATHS_CONNECT_STATUS
rg -n "PATHS_CONNECT_STATUS" --type json --type ts
# Look for ConfigService usage patterns
ast-grep --pattern 'configService.get($$$)'
Length of output: 428
Enforce string type and validate PATHS_CONNECT_STATUS to prevent TypeError
Ensure the config value is both statically typed and runtime-validated in connect-status-writer.service.ts
so that a non-string never reaches dirname()
.
• File: packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts
Method: statusFilePath
get statusFilePath(): string {
- // Use environment variable if set, otherwise default to /var/local/emhttp/connectStatus.json
- return this.configService.get('PATHS_CONNECT_STATUS') || '/var/local/emhttp/connectStatus.json';
+ // Use environment variable if set, otherwise default to /var/local/emhttp/connectStatus.json
+ const rawPath = this.configService.get<string>('PATHS_CONNECT_STATUS');
+ if (typeof rawPath !== 'string') {
+ throw new TypeError(
+ `Invalid config "PATHS_CONNECT_STATUS": expected string, received ${typeof rawPath}`
+ );
+ }
+ return rawPath || '/var/local/emhttp/connectStatus.json';
}
Also verify in your configuration files (JSON, .env
or TS) that PATHS_CONNECT_STATUS
is defined as a string.
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In
packages/unraid-api-plugin-connect/src/connection-status/connect-status-writer.service.ts
around lines 17 to 19, the config value for PATHS_CONNECT_STATUS should be
explicitly checked to ensure it is a string before returning it. Update the
statusFilePath method to validate the type of the config value at runtime,
returning the default path only if the config value is either undefined or not a
string. Also, verify that PATHS_CONNECT_STATUS is defined as a string in all
configuration files such as JSON, .env, or TypeScript files.
const client = this.mothershipClient.getClient(); | ||
if (client && subscription.operationId) { | ||
// Note: We can't directly call stopSubscription on the client since it's private | ||
// This would need to be exposed or handled differently in a real implementation | ||
this.logger.debug(`Should stop subscription with operationId: ${subscription.operationId}`); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Address the architectural limitation with stopSubscription.
The comment indicates that stopSubscription
cannot be called on the client because it's private. This is an architectural issue that should be resolved by exposing the necessary methods on the UnraidServerClient
.
Consider exposing a public method on UnraidServerClient
to stop subscriptions:
// In UnraidServerClient class
public async stopSubscription(operationId: string): Promise<void> {
if (this.executor.stopSubscription) {
await this.executor.stopSubscription(operationId);
}
// Send subscription_stop message to mothership
this.sendResponse({
operationId,
event: 'query_response',
type: 'complete',
payload: { data: null },
});
}
🤖 Prompt for AI Agents
In
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership-subscription.handler.ts
around lines 32 to 37, the code cannot call stopSubscription on the client
because it is private. To fix this, add a public async method
stopSubscription(operationId: string) to the UnraidServerClient class that
internally calls the private executor.stopSubscription if available and sends
the appropriate subscription_stop message to mothership. Then update this
handler to call the new public stopSubscription method on the client instead of
accessing the private method directly.
stopMothershipSubscription() { | ||
this.logger.verbose('Stopping mothership subscription (not implemented yet)'); | ||
} | ||
|
||
async handleRemoteGraphQLEvent(event: RemoteGraphQlEventFragmentFragment) { | ||
const { body, type, sha256 } = event.remoteGraphQLEventData; | ||
switch (type) { | ||
case RemoteGraphQlEventType.REMOTE_QUERY_EVENT: | ||
return this.safeExecuteQuery(sha256, body); | ||
case RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT: | ||
return this.addSubscription(event.remoteGraphQLEventData); | ||
case RemoteGraphQlEventType.REMOTE_SUBSCRIPTION_EVENT_PING: | ||
return this.pingSubscription(sha256); | ||
default: | ||
return; | ||
async subscribeToMothershipEvents() { | ||
this.logger.log('Subscribing to mothership events via UnraidServerClient'); | ||
|
||
// For now, just log that we're connected | ||
// The UnraidServerClient handles the WebSocket connection automatically | ||
const client = this.mothershipClient.getClient(); | ||
if (client) { | ||
this.logger.log('UnraidServerClient is connected and handling mothership communication'); | ||
} else { | ||
this.logger.warn('UnraidServerClient is not available'); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement proper mothership event subscription.
The current implementation only logs connection status. This should set up actual event subscriptions through the WebSocket client.
The method needs to:
- Subscribe to mothership events via the WebSocket client
- Handle incoming events and route them appropriately
- Manage subscription lifecycle
🤖 Prompt for AI Agents
In
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership-subscription.handler.ts
around lines 104 to 119, the subscribeToMothershipEvents method currently only
logs connection status without setting up real event subscriptions. Update this
method to use the WebSocket client from mothershipClient to subscribe to actual
mothership events, add event listeners to handle incoming events and route them
properly, and implement logic to manage the subscription lifecycle including
cleanup or reconnection as needed.
async executeQuery(sha256: string, body: string) { | ||
this.logger.debug(`Request to execute query ${sha256}: ${body} (simplified implementation)`); | ||
|
||
try { | ||
// For now, just return a success response | ||
// TODO: Implement actual query execution via the UnraidServerClient | ||
return { | ||
data: { | ||
message: 'Query executed successfully (simplified)', | ||
sha256, | ||
} | ||
}, | ||
}); | ||
}; | ||
} catch (error: any) { | ||
this.logger.error(`Error executing query ${sha256}:`, error); | ||
return { | ||
errors: [ | ||
{ | ||
message: `Query execution failed: ${error?.message || 'Unknown error'}`, | ||
extensions: { code: 'EXECUTION_ERROR' }, | ||
}, | ||
], | ||
}; | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Complete the executeQuery implementation.
The method currently returns mock data with a TODO comment. This needs to be implemented to execute actual queries via the UnraidServerClient.
This method should execute queries through the WebSocket client. Do you want me to help implement the proper query execution logic?
🤖 Prompt for AI Agents
In
packages/unraid-api-plugin-connect/src/mothership-proxy/mothership-subscription.handler.ts
between lines 121 and 144, the executeQuery method currently returns mock data
and has a TODO to implement actual query execution. Replace the mock response by
invoking the appropriate method on the UnraidServerClient WebSocket client to
execute the query using the provided sha256 and body parameters. Handle the
response and errors properly, returning the actual query result or formatted
error information as needed.
interface GraphQLExecutor { | ||
execute(params: { | ||
query: string | ||
variables?: Record<string, any> | ||
operationName?: string | ||
operationType?: 'query' | 'mutation' | 'subscription' | ||
}): Promise<any> | ||
stopSubscription?(operationId: string): Promise<void> | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove duplicate GraphQLExecutor interface.
This interface is already defined in local-graphql-executor.service.ts
. Import it instead of duplicating the definition.
+import { GraphQLExecutor } from './local-graphql-executor.service.js';
+
-interface GraphQLExecutor {
- execute(params: {
- query: string
- variables?: Record<string, any>
- operationName?: string
- operationType?: 'query' | 'mutation' | 'subscription'
- }): Promise<any>
- stopSubscription?(operationId: string): Promise<void>
-}
🤖 Prompt for AI Agents
In
packages/unraid-api-plugin-connect/src/mothership-proxy/unraid-server-client.service.ts
around lines 25 to 33, the GraphQLExecutor interface is duplicated but already
exists in local-graphql-executor.service.ts. Remove this local interface
definition and import the GraphQLExecutor interface from
local-graphql-executor.service.ts to avoid duplication and maintain consistency.
- Introduced new types and enums for managing remote access configurations, including AccessUrl, RemoteAccess, and Connect settings. - Added mutations for updating API settings and managing remote access. - Updated the API configuration to include the new connect plugin. - Enhanced the pnpm lock file with the addition of the pify package. - Implemented logic to skip file modifications in development mode.
Claude finished @elibosley's task —— View job PR Review: Mothership v2I've completed a comprehensive review of this PR. Here's my detailed feedback: Review Tasks
🔍 Code Quality & ArchitectureStrengths:
Areas for Improvement: 1. Error Handling & Logging 🚨
2. Hardcoded Values & Magic Numbers
3. Code Duplication
🔒 Security Concerns1. API Key Exposure
|
Summary by CodeRabbit
New Features
Refactor
Chores