Skip to content
Merged
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
23 changes: 23 additions & 0 deletions packages/omniviewdev-runtime/src/hooks/data/usePluginData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,21 @@ type UsePluginDataResult<T> = {
isLoading: boolean;
};

/**
* Check whether a value from the data store structurally matches the expected
* type indicated by the default value. This catches cases where the Go backend
* returns a JSON type that doesn't match the TypeScript generic (e.g. an object
* was stored but the caller expects an array).
*/
function matchesShape<T>(value: unknown, defaultValue: T): value is T {
if (defaultValue === null) return value === null;
if (Array.isArray(defaultValue)) return Array.isArray(value);
if (typeof defaultValue === 'object') {
return typeof value === 'object' && value !== null && !Array.isArray(value);
}
return typeof value === typeof defaultValue;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* Generic hook for reading/writing plugin data from the Plugin Data Store.
* Uses React Query for caching and optimistic updates.
Expand All @@ -28,6 +43,14 @@ export function usePluginData<T>(
if (result === null || result === undefined) {
return defaultValue;
}
if (!matchesShape(result, defaultValue)) {
console.warn(
`[usePluginData] stored value for "${key}" has unexpected type ` +
`(expected ${Array.isArray(defaultValue) ? 'array' : typeof defaultValue}, ` +
`got ${Array.isArray(result) ? 'array' : typeof result}). Using default.`,
);
return defaultValue;
}
return result as T;
},
});
Expand Down
Loading