Skip to content

Commit f5d9619

Browse files
committed
fix: validate usePluginData return type against default value shape
The Go backend returns `any` from the data store, and the TypeScript generic cast (`result as T`) provides no runtime safety. When stored data has a different JSON type than expected (e.g. object instead of array), callers crash with confusing errors like "favorites.includes is not a function". Add a `matchesShape` check that validates the structural type (array, object, primitive) matches the default value before accepting the stored result. Falls back to the default with a console warning on mismatch.
1 parent dd2bd55 commit f5d9619

1 file changed

Lines changed: 22 additions & 0 deletions

File tree

packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,20 @@ type UsePluginDataResult<T> = {
88
isLoading: boolean;
99
};
1010

11+
/**
12+
* Check whether a value from the data store structurally matches the expected
13+
* type indicated by the default value. This catches cases where the Go backend
14+
* returns a JSON type that doesn't match the TypeScript generic (e.g. an object
15+
* was stored but the caller expects an array).
16+
*/
17+
function matchesShape<T>(value: unknown, defaultValue: T): value is T {
18+
if (Array.isArray(defaultValue)) return Array.isArray(value);
19+
if (defaultValue !== null && typeof defaultValue === 'object') {
20+
return typeof value === 'object' && value !== null && !Array.isArray(value);
21+
}
22+
return typeof value === typeof defaultValue;
23+
}
24+
1125
/**
1226
* Generic hook for reading/writing plugin data from the Plugin Data Store.
1327
* Uses React Query for caching and optimistic updates.
@@ -28,6 +42,14 @@ export function usePluginData<T>(
2842
if (result === null || result === undefined) {
2943
return defaultValue;
3044
}
45+
if (!matchesShape(result, defaultValue)) {
46+
console.warn(
47+
`[usePluginData] stored value for "${key}" has unexpected type ` +
48+
`(expected ${Array.isArray(defaultValue) ? 'array' : typeof defaultValue}, ` +
49+
`got ${Array.isArray(result) ? 'array' : typeof result}). Using default.`,
50+
);
51+
return defaultValue;
52+
}
3153
return result as T;
3254
},
3355
});

0 commit comments

Comments
 (0)