Skip to content
Draft
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion api/.env.development
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,14 @@ PATHS_LOGS_FILE=./dev/log/graphql-api.log
PATHS_CONNECT_STATUS_FILE_PATH=./dev/connectStatus.json # Connect plugin status file
PATHS_OIDC_JSON=./dev/configs/oidc.local.json
PATHS_LOCAL_SESSION_FILE=./dev/local-session
PATHS_CONNECT_STATUS=./dev/states/connectStatus.json # Connect status file for development
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Add quotes around the value on line 22.

The .env file format requires quoted values for consistent parsing by dotenv libraries.

Apply this fix:

-PATHS_CONNECT_STATUS=./dev/states/connectStatus.json # Connect status file for development
+PATHS_CONNECT_STATUS="./dev/states/connectStatus.json" # Connect status file for development
📝 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
PATHS_CONNECT_STATUS=./dev/states/connectStatus.json # Connect status file for development
PATHS_CONNECT_STATUS="./dev/states/connectStatus.json" # Connect status file for development
🧰 Tools
🪛 dotenv-linter (4.0.0)

[warning] 22-22: [UnorderedKey] The PATHS_CONNECT_STATUS key should go before the PATHS_CONNECT_STATUS_FILE_PATH key

(UnorderedKey)


[warning] 22-22: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🤖 Prompt for AI Agents
In api/.env.development around line 22, the PATHS_CONNECT_STATUS value is
unquoted; update the line to wrap the value in quotes so dotenv parsers handle
it consistently (e.g., change
PATHS_CONNECT_STATUS=./dev/states/connectStatus.json to
PATHS_CONNECT_STATUS="./dev/states/connectStatus.json").

ENVIRONMENT="development"
NODE_ENV="development"
PORT="3001"
PLAYGROUND=true
INTROSPECTION=true
MOTHERSHIP_GRAPHQL_LINK="http://authenticator:3000/graphql"
MOTHERSHIP_GRAPHQL_LINK="wss://preview.mothership2.unraid.net"
MOTHERSHIP_BASE_URL="https://preview.mothership2.unraid.net"
NODE_TLS_REJECT_UNAUTHORIZED=0
BYPASS_PERMISSION_CHECKS=false
BYPASS_CORS_CHECKS=true
Expand Down
2 changes: 1 addition & 1 deletion api/dev/configs/api.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"version": "4.25.3",
"version": "4.27.2",
"extraOrigins": [],
"sandbox": true,
"ssoSubIds": [],
Expand Down
2 changes: 1 addition & 1 deletion api/dev/configs/connect.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"wanaccess": true,
"wanport": 8443,
"upnpEnabled": false,
"apikey": "",
"apikey": "_______________________LOCAL_API_KEY_HERE_________________________",
"localApiKey": "_______________________LOCAL_API_KEY_HERE_________________________",
"email": "test@example.com",
"username": "zspearmint",
Expand Down
7 changes: 7 additions & 0 deletions api/dev/states/connectStatus.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"connectionStatus": "PRE_INIT",
"error": null,
"lastPing": null,
"allowedOrigins": "",
"timestamp": 1764472463288
}
4 changes: 2 additions & 2 deletions api/docs/developer/api-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ Add your workspace package to the vendoring configuration in `api/scripts/build.
```typescript
const WORKSPACE_PACKAGES_TO_VENDOR = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect-2',
'your-plugin-name': 'packages/your-plugin-path', // Add your plugin here
} as const;
```
Expand All @@ -31,7 +31,7 @@ Add your workspace package to the Vite configuration in `api/vite.config.ts`:
```typescript
const workspaceDependencies = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect-2',
'your-plugin-name': 'packages/your-plugin-path', // Add your plugin here
};
```
Expand Down
4 changes: 2 additions & 2 deletions api/scripts/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { exit } from 'process';
import type { PackageJson } from 'type-fest';
import { $, cd } from 'zx';

import { getDeploymentVersion } from './get-deployment-version.js';
import { getDeploymentVersion } from '@app/../scripts/get-deployment-version.js';

type ApiPackageJson = PackageJson & {
version: string;
Expand All @@ -21,7 +21,7 @@ type ApiPackageJson = PackageJson & {
*/
const WORKSPACE_PACKAGES_TO_VENDOR = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect-2',
} as const;

/**
Expand Down
9 changes: 9 additions & 0 deletions api/src/unraid-api/unraid-file-modifier/file-modification.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { applyPatch, createPatch, parsePatch, reversePatch } from 'diff';
import { coerce, compare, gte, lte } from 'semver';

import { getUnraidVersion } from '@app/common/dashboard/get-unraid-version.js';
import { NODE_ENV } from '@app/environment.js';

export type ModificationEffect = 'nginx:reload';

Expand Down Expand Up @@ -225,6 +226,14 @@ export abstract class FileModification {
throw new Error('Invalid file modification configuration');
}

// Skip file modifications in development mode
if (NODE_ENV === 'development') {
return {
shouldApply: false,
reason: 'File modifications are disabled in development mode',
};
}

const fileExists = await access(this.filePath, constants.R_OK | constants.W_OK)
.then(() => true)
.catch(() => false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { ConfigService } from '@nestjs/config';

import type { ModificationEffect } from '@app/unraid-api/unraid-file-modifier/file-modification.js';
import { NODE_ENV } from '@app/environment.js';
import { FileModificationEffectService } from '@app/unraid-api/unraid-file-modifier/file-modification-effect.service.js';
import { FileModification } from '@app/unraid-api/unraid-file-modifier/file-modification.js';

Expand All @@ -29,6 +30,11 @@ export class UnraidFileModificationService
*/
async onModuleInit() {
try {
if (NODE_ENV === 'development') {
this.logger.log('Skipping file modifications in development mode');
return;
}

this.logger.log('Loading file modifications...');
const mods = await this.loadModifications();
await this.applyModifications(mods);
Expand Down
2 changes: 1 addition & 1 deletion api/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import { defineConfig } from 'vitest/config';
*/
const workspaceDependencies = {
'@unraid/shared': 'packages/unraid-shared',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect',
'unraid-api-plugin-connect': 'packages/unraid-api-plugin-connect-2',
};

export default defineConfig(({ mode }): ViteUserConfig => {
Expand Down
38 changes: 38 additions & 0 deletions packages/unraid-api-plugin-connect-2/.prettierrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/**
* @see https://prettier.io/docs/en/configuration.html
* @type {import("prettier").Config}
*/
module.exports = {
trailingComma: 'es5',
tabWidth: 4,
semi: true,
singleQuote: true,
printWidth: 105,
plugins: ['@ianvs/prettier-plugin-sort-imports'],
// decorators-legacy lets the import sorter transform files with decorators
importOrderParserPlugins: ['typescript', 'decorators-legacy'],
importOrder: [
/**----------------------
* Nest.js & node.js imports
*------------------------**/
'<TYPES>^@nestjs(/.*)?$',
'^@nestjs(/.*)?$', // matches imports starting with @nestjs
'<TYPES>^(node:)',
'<BUILTIN_MODULES>', // Node.js built-in modules
'',
/**----------------------
* Third party packages
*------------------------**/
'<TYPES>',
'<THIRD_PARTY_MODULES>', // Imports not matched by other special words or groups.
'',
/**----------------------
* Application Code
*------------------------**/
'<TYPES>^@app(/.*)?$', // matches type imports starting with @app
'^@app(/.*)?$',
'',
'<TYPES>^[.]',
'^[.]', // relative imports
],
};
36 changes: 36 additions & 0 deletions packages/unraid-api-plugin-connect-2/codegen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import type { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
overwrite: true,
emitLegacyCommonJSImports: false,
verbose: true,
config: {
namingConvention: {
enumValues: 'change-case-all#upperCase',
transformUnderscore: true,
useTypeImports: true,
},
scalars: {
DateTime: 'string',
Long: 'number',
JSON: 'Record<string, any>',
URL: 'URL',
Port: 'number',
UUID: 'string',
BigInt: 'number',
},
scalarSchemas: {
URL: 'z.instanceof(URL)',
Long: 'z.number()',
JSON: 'z.record(z.string(), z.any())',
Port: 'z.number()',
UUID: 'z.string()',
BigInt: 'z.number()',
},
},
generates: {
// No longer generating mothership GraphQL types since we switched to WebSocket-based UnraidServerClient
},
};

export default config;
39 changes: 39 additions & 0 deletions packages/unraid-api-plugin-connect-2/justfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Justfile for unraid-api-plugin-connect

# Default recipe to run when just is called without arguments
default:
@just --list

# Watch for changes in src files and run clean + build
watch:
watchexec -r -e ts,tsx -w src -- pnpm build

# Count TypeScript lines in src directory, excluding test and generated files
count-lines:
#!/usr/bin/env bash
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color

echo -e "${BLUE}Counting TypeScript lines in src/ (excluding test/ and graphql/generated/)...${NC}"
echo
echo -e "${GREEN}Lines by directory:${NC}"
cd src
# First pass to get total lines
total=$(find . -type f -name "*.ts" -not -path "*/test/*" -not -path "*/graphql/generated/*" | xargs wc -l | tail -n 1 | awk '{print $1}')

# Second pass to show directory breakdown with percentages
for dir in $(find . -type d -not -path "*/test/*" -not -path "*/graphql/generated/*" -not -path "." -not -path "./test" | sort); do
lines=$(find "$dir" -type f -name "*.ts" -not -path "*/graphql/generated/*" | xargs wc -l 2>/dev/null | tail -n 1 | awk '{print $1}')
if [ ! -z "$lines" ]; then
percentage=$(echo "scale=1; $lines * 100 / $total" | bc)
printf "%-30s %6d lines (%5.1f%%)\n" "$dir" "$lines" "$percentage"
fi
done
echo
echo -e "${GREEN}Top 10 largest files:${NC}"
find . -type f -name "*.ts" -not -path "*/test/*" -not -path "*/graphql/generated/*" | xargs wc -l | sort -nr | head -n 11
echo
echo -e "${GREEN}Total TypeScript lines:${NC} $total"
106 changes: 106 additions & 0 deletions packages/unraid-api-plugin-connect-2/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
{
"name": "unraid-api-plugin-connect",
"version": "4.25.3",
"main": "dist/index.js",
"type": "module",
"files": [
"dist",
"readme.md"
],
"scripts": {
"test": "vitest",
"clean": "rimraf dist",
"build": "tsc",
"prepare": "npm run build",
"format": "prettier --write \"src/**/*.{ts,js,json}\"",
"codegen": "graphql-codegen --config codegen.ts"
},
"keywords": [
"unraid",
"connect",
"unraid plugin"
],
"author": "Lime Technology, Inc. <unraid.net>",
"license": "GPL-2.0-or-later",
"description": "Unraid Connect plugin for Unraid API",
"devDependencies": {
"@apollo/client": "3.14.0",
"@faker-js/faker": "10.0.0",
"@graphql-codegen/cli": "6.0.0",
"@graphql-typed-document-node/core": "3.2.0",
"@ianvs/prettier-plugin-sort-imports": "4.6.3",
"@jsonforms/core": "3.6.0",
"@nestjs/apollo": "13.1.0",
"@nestjs/common": "11.1.6",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/schedule": "6.0.0",
"@runonflux/nat-upnp": "1.0.2",
"@types/ini": "4.1.1",
"@types/ip": "1.1.3",
"@types/lodash-es": "4.17.12",
"@types/node": "22.18.0",
"@types/ws": "8.18.1",
"camelcase-keys": "10.0.0",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"execa": "9.6.0",
"fast-check": "4.2.0",
"got": "14.4.7",
"graphql": "16.11.0",
"graphql-scalars": "1.24.2",
"graphql-subscriptions": "3.0.0",
"graphql-ws": "6.0.6",
"ini": "5.0.0",
"jose": "6.0.13",
"lodash-es": "4.17.21",
"nest-authz": "2.17.0",
"pify": "^6.1.0",
"prettier": "3.6.2",
"rimraf": "6.0.1",
"rxjs": "7.8.2",
"type-fest": "5.0.0",
"typescript": "5.9.2",
"undici": "7.15.0",
"vitest": "3.2.4",
"ws": "8.18.3",
"zen-observable-ts": "1.1.0"
},
"dependencies": {
"@unraid/shared": "workspace:*",
"ip": "2.0.1",
"node-cache": "5.1.2"
},
"peerDependencies": {
"@apollo/client": "3.14.0",
"@graphql-typed-document-node/core": "3.2.0",
"@jsonforms/core": "3.6.0",
"@nestjs/apollo": "13.1.0",
"@nestjs/common": "11.1.6",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/schedule": "6.0.0",
"@runonflux/nat-upnp": "1.0.2",
"camelcase-keys": "10.0.0",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"execa": "9.6.0",
"got": "14.4.7",
"graphql": "16.11.0",
"graphql-scalars": "1.24.2",
"graphql-subscriptions": "3.0.0",
"graphql-ws": "6.0.6",
"ini": "5.0.0",
"jose": "6.0.13",
"lodash-es": "4.17.21",
"nest-authz": "2.17.0",
"rxjs": "7.8.2",
"undici": "7.15.0",
"ws": "8.18.3",
"zen-observable-ts": "1.1.0"
}
}
Loading
Loading