- 
                Notifications
    You must be signed in to change notification settings 
- Fork 11
fix: no sizeRootFs unless queried #1710
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
Changes from all commits
270c1f6
              b13aa72
              d0246af
              f32ed7f
              a3168b5
              c1812f7
              File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | 
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| { | ||
| "version": "4.22.1", | ||
| "version": "4.22.2", | ||
| "extraOrigins": [], | ||
| "sandbox": true, | ||
| "ssoSubIds": [], | ||
|  | ||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,7 +1,7 @@ | ||||||||||||||||||||||
| import { Field, ID, Int, ObjectType, registerEnumType } from '@nestjs/graphql'; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| import { Node } from '@unraid/shared/graphql.model.js'; | ||||||||||||||||||||||
| import { GraphQLJSON, GraphQLPort } from 'graphql-scalars'; | ||||||||||||||||||||||
| import { GraphQLBigInt, GraphQLJSON, GraphQLPort } from 'graphql-scalars'; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| export enum ContainerPortType { | ||||||||||||||||||||||
| TCP = 'TCP', | ||||||||||||||||||||||
|  | @@ -89,7 +89,10 @@ export class DockerContainer extends Node { | |||||||||||||||||||||
| @Field(() => [ContainerPort]) | ||||||||||||||||||||||
| ports!: ContainerPort[]; | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| @Field(() => Int, { nullable: true, description: 'Total size of all the files in the container' }) | ||||||||||||||||||||||
| @Field(() => GraphQLBigInt, { | ||||||||||||||||||||||
| nullable: true, | ||||||||||||||||||||||
| description: 'Total size of all files in the container (in bytes)', | ||||||||||||||||||||||
| }) | ||||||||||||||||||||||
| sizeRootFs?: number; | ||||||||||||||||||||||
| 
      Comment on lines
    
      +92
     to 
      96
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Align TS type with GraphQLBigInt (use bigint, not number). GraphQLBigInt uses JS BigInt at runtime. Keeping the property typed as number risks precision loss and serialization mismatches for large values. Apply this minimal change: -    })
-    sizeRootFs?: number;
+    })
+    sizeRootFs?: bigint;Follow‑up: ensure the resolver populates this field with a BigInt, not a number (see service comment). 📝 Committable suggestion
 
        Suggested change
       
 🤖 Prompt for AI Agents | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| @Field(() => GraphQLJSON, { nullable: true }) | ||||||||||||||||||||||
|  | ||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|  | @@ -31,6 +31,7 @@ export class DockerService { | |||||||||
| private readonly logger = new Logger(DockerService.name); | ||||||||||
|  | ||||||||||
| public static readonly CONTAINER_CACHE_KEY = 'docker_containers'; | ||||||||||
| public static readonly CONTAINER_WITH_SIZE_CACHE_KEY = 'docker_containers_with_size'; | ||||||||||
| public static readonly NETWORK_CACHE_KEY = 'docker_networks'; | ||||||||||
| public static readonly CACHE_TTL_SECONDS = 60; // Cache for 60 seconds | ||||||||||
|  | ||||||||||
|  | @@ -71,6 +72,8 @@ export class DockerService { | |||||||||
| } | ||||||||||
|  | ||||||||||
| public transformContainer(container: Docker.ContainerInfo): DockerContainer { | ||||||||||
| const sizeValue = (container as Docker.ContainerInfo & { SizeRootFs?: number }).SizeRootFs; | ||||||||||
|  | ||||||||||
| 
      Comment on lines
    
      +75
     to 
      +76
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Avoid cast and prepare value for BigInt. Current cast to add SizeRootFs is brittle. Prefer a small helper type or a type guard, and coerce to BigInt at the source. Option A (local helper type): +type ContainerInfoMaybeSized = Docker.ContainerInfo & { SizeRootFs?: number };
-const sizeValue = (container as Docker.ContainerInfo & { SizeRootFs?: number }).SizeRootFs;
+const sizeValue = (container as ContainerInfoMaybeSized).SizeRootFs;Then set the field as BigInt (see next comment). 📝 Committable suggestion
 
        Suggested change
       
 🤖 Prompt for AI Agents | ||||||||||
| const transformed: DockerContainer = { | ||||||||||
| id: container.Id, | ||||||||||
| names: container.Names, | ||||||||||
|  | @@ -86,7 +89,7 @@ export class DockerService { | |||||||||
| ContainerPortType[port.Type.toUpperCase() as keyof typeof ContainerPortType] || | ||||||||||
| ContainerPortType.TCP, | ||||||||||
| })), | ||||||||||
| sizeRootFs: undefined, | ||||||||||
| sizeRootFs: sizeValue, | ||||||||||
| labels: container.Labels ?? {}, | ||||||||||
| 
      Comment on lines
    
      +92
     to 
      93
    
   There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Populate GraphQLBigInt with a JS BigInt. Return a BigInt to match the scalar and avoid precision issues. Apply this change: -            sizeRootFs: sizeValue,
+            sizeRootFs: sizeValue !== undefined ? BigInt(sizeValue) : undefined,Reference: GraphQLBigInt expects native BigInt. (the-guild.dev) 📝 Committable suggestion
 
        Suggested change
       
 🤖 Prompt for AI Agents | ||||||||||
| state: | ||||||||||
| typeof container.State === 'string' | ||||||||||
|  | @@ -109,21 +112,23 @@ export class DockerService { | |||||||||
| { | ||||||||||
| skipCache = false, | ||||||||||
| all = true, | ||||||||||
| size = true, | ||||||||||
| size = false, | ||||||||||
| ...listOptions | ||||||||||
| }: Partial<ContainerListingOptions> = { skipCache: false } | ||||||||||
| ): Promise<DockerContainer[]> { | ||||||||||
| const cacheKey = size | ||||||||||
| ? DockerService.CONTAINER_WITH_SIZE_CACHE_KEY | ||||||||||
| : DockerService.CONTAINER_CACHE_KEY; | ||||||||||
|  | ||||||||||
| if (!skipCache) { | ||||||||||
| const cachedContainers = await this.cacheManager.get<DockerContainer[]>( | ||||||||||
| DockerService.CONTAINER_CACHE_KEY | ||||||||||
| ); | ||||||||||
| const cachedContainers = await this.cacheManager.get<DockerContainer[]>(cacheKey); | ||||||||||
| if (cachedContainers) { | ||||||||||
| this.logger.debug('Using docker container cache'); | ||||||||||
| this.logger.debug(`Using docker container cache (${size ? 'with' : 'without'} size)`); | ||||||||||
| return cachedContainers; | ||||||||||
| } | ||||||||||
| } | ||||||||||
|  | ||||||||||
| this.logger.debug('Updating docker container cache'); | ||||||||||
| this.logger.debug(`Updating docker container cache (${size ? 'with' : 'without'} size)`); | ||||||||||
| const rawContainers = | ||||||||||
| (await this.client | ||||||||||
| .listContainers({ | ||||||||||
|  | @@ -136,11 +141,7 @@ export class DockerService { | |||||||||
| this.autoStarts = await this.getAutoStarts(); | ||||||||||
| const containers = rawContainers.map((container) => this.transformContainer(container)); | ||||||||||
|  | ||||||||||
| await this.cacheManager.set( | ||||||||||
| DockerService.CONTAINER_CACHE_KEY, | ||||||||||
| containers, | ||||||||||
| DockerService.CACHE_TTL_SECONDS * 1000 | ||||||||||
| ); | ||||||||||
| await this.cacheManager.set(cacheKey, containers, DockerService.CACHE_TTL_SECONDS * 1000); | ||||||||||
| return containers; | ||||||||||
| } | ||||||||||
|  | ||||||||||
|  | @@ -191,15 +192,18 @@ export class DockerService { | |||||||||
| } | ||||||||||
|  | ||||||||||
| public async clearContainerCache(): Promise<void> { | ||||||||||
| await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY); | ||||||||||
| this.logger.debug('Invalidated container cache due to external event.'); | ||||||||||
| await Promise.all([ | ||||||||||
| this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY), | ||||||||||
| this.cacheManager.del(DockerService.CONTAINER_WITH_SIZE_CACHE_KEY), | ||||||||||
| ]); | ||||||||||
| this.logger.debug('Invalidated container caches due to external event.'); | ||||||||||
| } | ||||||||||
|  | ||||||||||
| public async start(id: string): Promise<DockerContainer> { | ||||||||||
| const container = this.client.getContainer(id); | ||||||||||
| await container.start(); | ||||||||||
| await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY); | ||||||||||
| this.logger.debug(`Invalidated container cache after starting ${id}`); | ||||||||||
| await this.clearContainerCache(); | ||||||||||
| this.logger.debug(`Invalidated container caches after starting ${id}`); | ||||||||||
| const containers = await this.getContainers({ skipCache: true }); | ||||||||||
| const updatedContainer = containers.find((c) => c.id === id); | ||||||||||
| if (!updatedContainer) { | ||||||||||
|  | @@ -213,8 +217,8 @@ export class DockerService { | |||||||||
| public async stop(id: string): Promise<DockerContainer> { | ||||||||||
| const container = this.client.getContainer(id); | ||||||||||
| await container.stop({ t: 10 }); | ||||||||||
| await this.cacheManager.del(DockerService.CONTAINER_CACHE_KEY); | ||||||||||
| this.logger.debug(`Invalidated container cache after stopping ${id}`); | ||||||||||
| await this.clearContainerCache(); | ||||||||||
| this.logger.debug(`Invalidated container caches after stopping ${id}`); | ||||||||||
|  | ||||||||||
| let containers = await this.getContainers({ skipCache: true }); | ||||||||||
| let updatedContainer: DockerContainer | undefined; | ||||||||||
|  | ||||||||||
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
Schema change to BigInt matches the model.
Alignment with the model is correct. Ensure client codegen maps BigInt consistently (string or bigint) to prevent runtime mismatches.
Run this to sanity-check mappings and usages:
🏁 Script executed:
Length of output: 430
🏁 Script executed:
Length of output: 61970
Add explicit BigInt scalar mapping and regenerate client types
🤖 Prompt for AI Agents