Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
1 change: 0 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ Enables GraphQL playground at `http://tower.local/graphql`

- We are using tailwind v4 we do not need a tailwind config anymore
- always search the internet for tailwind v4 documentation when making tailwind related style changes
- never run or restart the API server or web server. I will handle the lifecycle, simply wait and ask me to do this for you
- Never use the `any` type. Always prefer proper typing
- Avoid using casting whenever possible, prefer proper typing from the start
- **IMPORTANT:** cache-manager v7 expects TTL values in **milliseconds**, not seconds. Always use milliseconds when setting cache TTL (e.g., 600000 for 10 minutes, not 600)
56 changes: 28 additions & 28 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@
},
"dependencies": {
"@apollo/client": "3.14.0",
"@apollo/server": "4.12.2",
"@as-integrations/fastify": "2.1.1",
"@apollo/server": "5.5.1",
"@as-integrations/fastify": "3.1.0",
"@fastify/cookie": "11.0.2",
"@fastify/helmet": "13.0.1",
"@graphql-codegen/client-preset": "5.0.0",
Expand All @@ -67,15 +67,15 @@
"@graphql-tools/schema": "10.0.25",
"@graphql-tools/utils": "10.9.1",
"@jsonforms/core": "3.6.0",
"@nestjs/apollo": "13.1.0",
"@nestjs/apollo": "13.4.2",
"@nestjs/cache-manager": "3.0.1",
"@nestjs/common": "11.1.6",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/core": "11.1.26",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/graphql": "13.4.2",
"@nestjs/passport": "11.0.5",
"@nestjs/platform-fastify": "11.1.6",
"@nestjs/platform-fastify": "11.1.26",
"@nestjs/schedule": "6.0.0",
"@nestjs/throttler": "6.4.0",
"@reduxjs/toolkit": "2.8.2",
Expand All @@ -90,28 +90,28 @@
"cache-manager": "7.2.0",
"cacheable-lookup": "7.0.0",
"camelcase-keys": "10.0.0",
"casbin": "5.38.0",
"casbin": "5.50.0",
"change-case": "5.4.4",
"chokidar": "4.0.3",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"class-validator": "0.15.1",
"cli-table": "0.3.11",
"command-exists": "1.2.9",
"convert": "5.12.0",
"cookie": "1.0.2",
"cron": "4.3.0",
"cross-fetch": "4.1.0",
"diff": "8.0.2",
"dockerode": "4.0.7",
"diff": "8.0.4",
"dockerode": "4.0.12",
"dotenv": "17.2.1",
"escape-html": "1.0.3",
"execa": "9.6.0",
"exit-hook": "4.0.0",
"fast-xml-parser": "5.3.0",
"fastify": "5.5.0",
"fast-xml-parser": "5.8.0",
"fastify": "5.8.5",
"filenamify": "7.0.0",
"fs-extra": "11.3.1",
"glob": "11.0.3",
"glob": "11.1.0",
"global-agent": "3.0.0",
"got": "14.4.7",
"graphql": "16.11.0",
Expand All @@ -125,7 +125,7 @@
"ip": "2.0.1",
"jose": "6.0.13",
"json-bigint-patch": "0.0.8",
"lodash-es": "4.17.21",
"lodash-es": "4.18.1",
"multi-ini": "2.3.2",
"mustache": "4.2.0",
"nest-authz": "2.17.0",
Expand All @@ -141,15 +141,15 @@
"pino": "9.9.0",
"pino-http": "10.5.0",
"pino-pretty": "13.1.1",
"pm2": "6.0.8",
"pm2": "7.0.1",
"reflect-metadata": "^0.1.14",
"rxjs": "7.8.2",
"semver": "7.7.2",
"strftime": "0.10.3",
"systeminformation": "5.27.8",
"undici": "7.15.0",
"uuid": "13.0.0",
"ws": "8.18.3",
"systeminformation": "5.31.7",
"undici": "7.27.2",
"uuid": "13.0.2",
"ws": "8.21.0",
"zen-observable-ts": "1.1.0",
"zod": "3.25.76"
},
Expand All @@ -173,7 +173,7 @@
"@graphql-codegen/typescript-resolvers": "5.0.0",
"@graphql-typed-document-node/core": "3.2.0",
"@ianvs/prettier-plugin-sort-imports": "4.6.3",
"@nestjs/testing": "11.1.6",
"@nestjs/testing": "11.1.26",
"@originjs/vite-plugin-commonjs": "1.0.3",
"@rollup/plugin-node-resolve": "16.0.1",
"@swc/core": "1.13.5",
Expand All @@ -200,13 +200,13 @@
"@types/uuid": "11.0.0",
"@types/ws": "8.18.1",
"@types/wtfnode": "0.10.0",
"@vitest/coverage-v8": "3.2.4",
"@vitest/ui": "3.2.4",
"@vitest/coverage-v8": "3.2.6",
"@vitest/ui": "3.2.6",
"eslint": "9.34.0",
"eslint-plugin-import": "2.32.0",
"eslint-plugin-no-relative-import-paths": "1.6.1",
"eslint-plugin-prettier": "5.5.4",
"jiti": "2.5.1",
"jiti": "2.7.0",
"nodemon": "3.1.10",
"prettier": "3.6.2",
"rollup-plugin-node-externals": "8.1.0",
Expand All @@ -216,15 +216,15 @@
"typescript": "5.9.2",
"typescript-eslint": "8.41.0",
"unplugin-swc": "1.5.7",
"vite": "7.1.3",
"vite": "7.3.5",
"vite-plugin-node": "7.0.0",
"vite-tsconfig-paths": "5.1.4",
"vitest": "3.2.4",
"zx": "8.8.1"
"vitest": "3.2.6",
"zx": "8.8.5"
},
"overrides": {
"eslint": {
"jiti": "2.5.1"
"jiti": "2.7.0"
},
"@as-integrations/fastify": {
"fastify": "$fastify"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -165,14 +165,19 @@ describe('UnraidPluginsService', () => {
});

it('listInstalledPlugins returns empty array when plugin directory is missing', async () => {
const configService = {
get: vi.fn().mockReturnValue({
'dynamix-base': '/tmp/definitely-missing-dynamix-base',
}),
} as unknown as ConfigService;
const configuredService = new UnraidPluginsService(configService);
const tempDir = await mkdtemp(join(tmpdir(), 'unraid-plugins-missing-test-'));
try {
const configService = {
get: vi.fn().mockReturnValue({
'dynamix-base': join(tempDir, 'missing', 'dynamix-base'),
}),
} as unknown as ConfigService;
const configuredService = new UnraidPluginsService(configService);
Comment on lines +170 to +175

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.

🛠️ Refactor suggestion | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
rg -nP "as\\s+unknown\\s+as\\s+ConfigService|\\bas\\s+any\\b" api/src/unraid-api/graph/resolvers/unraid-plugins/unraid-plugins.service.spec.ts

Repository: unraid/api

Length of output: 286


🏁 Script executed:

# Get the full context around lines 170-175 and examine surrounding test structure
sed -n '150,180p' api/src/unraid-api/graph/resolvers/unraid-plugins/unraid-plugins.service.spec.ts | cat -n

Repository: unraid/api

Length of output: 1650


🏁 Script executed:

# Check the imports and ConfigService definition in this test file
head -40 api/src/unraid-api/graph/resolvers/unraid-plugins/unraid-plugins.service.spec.ts | cat -n

Repository: unraid/api

Length of output: 1690


🏁 Script executed:

# Verify all instances of casting pattern and understand test structure
grep -n -B2 -A2 "as unknown as" api/src/unraid-api/graph/resolvers/unraid-plugins/unraid-plugins.service.spec.ts

Repository: unraid/api

Length of output: 1024


🏁 Script executed:

# Check ConfigService definition and whether it can be instantiated directly
fd -t f ConfigService.ts$ | head -5 | xargs cat -n 2>/dev/null | head -80

Repository: unraid/api

Length of output: 36


Remove unnecessary casting of mock ConfigService

The as unknown as ConfigService pattern bypasses type safety and violates the coding guideline to avoid casting. Use direct instantiation with vi.spyOn() instead, as demonstrated by the existing test setup at line 34.

This casting pattern appears at multiple locations in the test file (lines 157, 174, 193) and should be addressed consistently.

Example fix
-            const configService = {
-                get: vi.fn().mockReturnValue({
-                    'dynamix-base': join(tempDir, 'missing', 'dynamix-base'),
-                }),
-            } as unknown as ConfigService;
+            const configService = new ConfigService();
+            vi.spyOn(configService, 'get').mockReturnValue({
+                'dynamix-base': join(tempDir, 'missing', 'dynamix-base'),
+            });
             const configuredService = new UnraidPluginsService(configService);
📝 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 configService = {
get: vi.fn().mockReturnValue({
'dynamix-base': join(tempDir, 'missing', 'dynamix-base'),
}),
} as unknown as ConfigService;
const configuredService = new UnraidPluginsService(configService);
const configService: Partial<ConfigService> = {
get: vi.fn().mockReturnValue({
'dynamix-base': join(tempDir, 'missing', 'dynamix-base'),
}),
};
const configuredService = new UnraidPluginsService(configService as ConfigService);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@api/src/unraid-api/graph/resolvers/unraid-plugins/unraid-plugins.service.spec.ts`
around lines 170 - 175, Replace the mock ConfigService object creation that uses
the `as unknown as ConfigService` casting pattern with the `vi.spyOn()` approach
to maintain type safety and avoid unsafe casting. The current pattern at the
configService initialization violates type safety guidelines. Instead of
creating a mock object and casting it, use the spy approach demonstrated in the
existing test setup to properly mock the ConfigService without bypassing
TypeScript's type checking. Apply this fix consistently wherever this pattern
appears in the test file.

Source: Coding guidelines


await expect(configuredService.listInstalledPlugins()).resolves.toEqual([]);
await expect(configuredService.listInstalledPlugins()).resolves.toEqual([]);
} finally {
await rm(tempDir, { recursive: true, force: true });
}
});

it('removes completed operations after retention ttl', async () => {
Expand Down
46 changes: 44 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"private": true,
"version": "4.35.0",
"scripts": {
"audit": "node scripts/pnpm-audit.mjs",
"build": "pnpm -r build",
"build:watch": "pnpm -r --parallel --filter '!@unraid/ui' build:watch",
"codegen": "pnpm -r codegen",
Expand All @@ -23,7 +24,48 @@
"pnpm": {
"overrides": {
"graphql": "16.11.0",
"@graphql-tools/utils": "10.9.1"
"@graphql-tools/utils": "10.9.1",
"ajv@<6.14.0": "6.15.0",
"ajv@>=7.0.0-alpha.0 <8.18.0": "8.20.0",
"axios": "1.17.0",
"brace-expansion@<1.1.13": "1.1.13",
"brace-expansion@>=4.0.0 <5.0.5": "5.0.6",
"brace-expansion@>=5.0.0 <5.0.5": "5.0.5",
"defu": "6.1.7",
"esbuild": "0.28.1",
"fast-uri": "3.1.2",
"fast-xml-parser": "5.8.0",
"file-type": "22.0.1",
"flatted": "3.4.2",
"follow-redirects": "1.16.0",
"glob@>=11.0.0 <11.1.0": "11.1.0",
"handlebars": "4.7.9",
"immutable": "3.8.3",
"js-beautify": "1.15.4",
"js-cookie": "3.0.8",
"jiti": "2.7.0",
"js-yaml": "4.2.0",
"lodash": "4.18.1",
"minimatch@<3.1.5": "3.1.5",
"minimatch@>=9.0.0 <9.0.9": "9.0.9",
"nuxt": "4.4.8",
"picomatch@<2.3.2": "2.3.2",
"picomatch@>=4.0.0 <4.0.4": "4.0.4",
"postcss": "8.5.15",
"qs": "6.15.2",
"shell-quote": "1.8.4",
"tar": "7.5.16",
"tmp": "0.2.7",
"uuid@>=8.0.0 <11.1.1": "11.1.1",
"uuid@>=11.0.0 <11.1.1": "11.1.1",
"vue-eslint-parser": "10.4.1",
"ws": "8.21.0",
"yaml": "2.9.0"
},
"auditConfig": {
"ignoreCves": [
"CVE-2024-29415"
]
},
"peerDependencyRules": {
"allowAny": [
Expand Down Expand Up @@ -54,7 +96,7 @@
"dependencies": {
"@manypkg/cli": "0.25.0",
"chalk": "5.6.0",
"diff": "8.0.2",
"diff": "8.0.4",
"ignore": "7.0.5"
},
"devDependencies": {
Expand Down
36 changes: 18 additions & 18 deletions packages/unraid-api-plugin-connect/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,14 +30,14 @@
"@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/apollo": "13.4.2",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/core": "11.1.26",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/graphql": "13.4.2",
"@nestjs/schedule": "6.0.0",
"@nestjs/testing": "11.1.6",
"@nestjs/testing": "11.1.26",
"@runonflux/nat-upnp": "1.0.2",
"@types/ini": "4.1.1",
"@types/ip": "1.1.3",
Expand All @@ -46,7 +46,7 @@
"@types/ws": "8.18.1",
"camelcase-keys": "10.0.0",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"class-validator": "0.15.1",
"execa": "9.6.0",
"fast-check": "4.2.0",
"got": "14.4.7",
Expand All @@ -56,16 +56,16 @@
"graphql-ws": "6.0.6",
"ini": "5.0.0",
"jose": "6.0.13",
"lodash-es": "4.17.21",
"lodash-es": "4.18.1",
"nest-authz": "2.17.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",
"undici": "7.27.2",
"vitest": "3.2.6",
"ws": "8.21.0",
"zen-observable-ts": "1.1.0"
},
"dependencies": {
Expand All @@ -77,17 +77,17 @@
"@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/apollo": "13.4.2",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/core": "11.1.26",
"@nestjs/event-emitter": "3.0.1",
"@nestjs/graphql": "13.1.0",
"@nestjs/graphql": "13.4.2",
"@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",
"class-validator": "0.15.1",
"execa": "9.6.0",
"got": "14.4.7",
"graphql": "16.11.0",
Expand All @@ -96,11 +96,11 @@
"graphql-ws": "6.0.6",
"ini": "5.0.0",
"jose": "6.0.13",
"lodash-es": "4.17.21",
"lodash-es": "4.18.1",
"nest-authz": "2.17.0",
"rxjs": "7.8.2",
"undici": "7.15.0",
"ws": "8.18.3",
"undici": "7.27.2",
"ws": "8.21.0",
"zen-observable-ts": "1.1.0"
}
}
8 changes: 4 additions & 4 deletions packages/unraid-api-plugin-generator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,16 +19,16 @@
"validate-npm-package-name": "6.0.2"
},
"devDependencies": {
"@nestjs/common": "11.1.6",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/graphql": "13.1.0",
"@nestjs/core": "11.1.26",
"@nestjs/graphql": "13.4.2",
"@types/fs-extra": "11.0.4",
"@types/inquirer": "9.0.9",
"@types/node": "22.18.0",
"@types/validate-npm-package-name": "4.0.2",
"class-transformer": "0.5.1",
"class-validator": "0.14.2",
"class-validator": "0.15.1",
"typescript": "5.9.2"
}
}
16 changes: 8 additions & 8 deletions packages/unraid-api-plugin-health/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 +16,19 @@
"license": "GPL-2.0-or-later",
"description": "Example Health plugin for Unraid API",
"devDependencies": {
"@nestjs/common": "11.1.6",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/graphql": "13.1.0",
"@nestjs/core": "11.1.26",
"@nestjs/graphql": "13.4.2",
"nest-authz": "2.17.0",
"typescript": "5.9.2",
"pify": "6.1.0"
"pify": "6.1.0",
"typescript": "5.9.2"
},
"peerDependencies": {
"@nestjs/common": "11.1.6",
"@nestjs/common": "11.1.26",
"@nestjs/config": "4.0.2",
"@nestjs/core": "11.1.6",
"@nestjs/graphql": "13.1.0",
"@nestjs/core": "11.1.26",
"@nestjs/graphql": "13.4.2",
"nest-authz": "2.17.0"
}
}
Loading
Loading