From 742bde1d272354cd353392779799d02015cf8ec7 Mon Sep 17 00:00:00 2001 From: Sven Date: Tue, 11 Aug 2026 10:59:28 +0200 Subject: [PATCH] fix(synology): support vol_info in storage_v2 responses (#6554) --- .../src/synology/synology-client.ts | 5 ++ .../src/synology/synology-types.ts | 1 + .../test/synology-integration.spec.ts | 54 +++++++++++++++++++ 3 files changed, 60 insertions(+) diff --git a/packages/integrations/src/synology/synology-client.ts b/packages/integrations/src/synology/synology-client.ts index cc853e2c9..87450cc2f 100644 --- a/packages/integrations/src/synology/synology-client.ts +++ b/packages/integrations/src/synology/synology-client.ts @@ -85,6 +85,11 @@ export class SynologyClient { if (volumesFromV2.length > 0) { return volumesFromV2; } + + const legacyVolumesFromV2 = this.mapLegacyVolumes(storageV2.vol_info); + if (legacyVolumesFromV2.length > 0) { + return legacyVolumesFromV2; + } } catch (error) { logger.debug("storage_v2 unavailable, falling back to legacy storage info", { integrationId: this.integrationId, diff --git a/packages/integrations/src/synology/synology-types.ts b/packages/integrations/src/synology/synology-types.ts index c1f73b52e..0d3a13163 100644 --- a/packages/integrations/src/synology/synology-types.ts +++ b/packages/integrations/src/synology/synology-types.ts @@ -78,6 +78,7 @@ export const synologyStorageV2VolumeSchema = z export const synologyStorageV2DataSchema = z.object({ volumes: z.array(synologyStorageV2VolumeSchema).optional(), + vol_info: z.array(synologyVolumeInfoSchema).optional(), }); export const synologyUtilizationCpuSchema = z.object({ diff --git a/packages/integrations/src/synology/test/synology-integration.spec.ts b/packages/integrations/src/synology/test/synology-integration.spec.ts index e8a13f015..60e334fe4 100644 --- a/packages/integrations/src/synology/test/synology-integration.spec.ts +++ b/packages/integrations/src/synology/test/synology-integration.spec.ts @@ -426,6 +426,60 @@ describe("SynologyIntegration.getSystemInfoAsync", () => { expect(result.fileSystem[0]?.deviceName).toBe("volume_1"); }); + test("uses vol_info from storage_v2 without falling back to legacy storage", async () => { + mockSuccessfulFlow({ + storageV2: { + success: true, + data: { + vol_info: [ + { + name: "volume_1", + used_size: "4000000000", + total_size: "10000000000", + status: "normal", + }, + { + name: "volume_2", + used_size: "5000000000", + total_size: "20000000000", + status: "attention", + }, + ], + }, + }, + }); + + const integration = createIntegration(); + const result = await integration.getSystemInfoAsync(); + + expect(result.fileSystem).toEqual([ + { + deviceName: "volume_1", + used: "4000000000", + available: "6000000000", + percentage: 40, + }, + { + deviceName: "volume_2", + used: "5000000000", + available: "15000000000", + percentage: 25, + }, + ]); + + const legacyStorageRequests = mockFetch.mock.calls.filter(([url]) => { + const urlString = toUrlString(url); + + return ( + getApiFromUrl(urlString) === "SYNO.Core.System" && + getMethodFromUrl(urlString) === "info" && + getTypeFromUrl(urlString) === "storage" + ); + }); + + expect(legacyStorageRequests).toHaveLength(0); + }); + test("continues when optional tier-2 calls fail", async () => { mockSuccessfulFlow({ skipOptional: true }); const integration = createIntegration();