mirror of
https://github.com/router-for-me/Cli-Proxy-API-Management-Center.git
synced 2026-06-16 21:03:58 +08:00
refactor(utils): share isRecord and getErrorMessage helpers
isRecord was declared locally in 15 modules (with two divergent shapes) and getErrorMessage in 7. Move a single canonical pair into utils/helpers and import it everywhere. The shared isRecord excludes arrays; the call sites that previously allowed them only read named properties, so behavior is unchanged.
This commit is contained in:
@@ -5,6 +5,7 @@ import { EmptyState } from '@/components/ui/EmptyState';
|
||||
import { useHeaderRefresh } from '@/hooks/useHeaderRefresh';
|
||||
import { pluginsApi } from '@/services/api';
|
||||
import { useAuthStore } from '@/stores';
|
||||
import { getErrorMessage, isRecord } from '@/utils/helpers';
|
||||
import type { PluginListResponse } from '@/types';
|
||||
import {
|
||||
collectPluginResourceEntries,
|
||||
@@ -12,15 +13,9 @@ import {
|
||||
} from './pluginResources';
|
||||
import styles from './PluginResourcePage.module.scss';
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
|
||||
const hasStatus = (error: unknown, status: number) =>
|
||||
isRecord(error) && error.status === status;
|
||||
|
||||
const getErrorMessage = (error: unknown, fallback: string) =>
|
||||
error instanceof Error ? error.message : typeof error === 'string' ? error : fallback;
|
||||
|
||||
const safeDecodeURIComponent = (value = '') => {
|
||||
try {
|
||||
return decodeURIComponent(value);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
import { useHeaderRefresh } from '@/hooks/useHeaderRefresh';
|
||||
import { pluginStoreApi } from '@/services/api';
|
||||
import { useAuthStore, useConfigStore, useNotificationStore } from '@/stores';
|
||||
import { getErrorMessage, isRecord } from '@/utils/helpers';
|
||||
import type { PluginStoreEntry, PluginStoreResponse } from '@/types';
|
||||
import { buildRepositoryURL, resolvePluginAssetURL } from './pluginResources';
|
||||
import styles from './PluginStorePage.module.scss';
|
||||
@@ -27,12 +28,6 @@ interface StoreLoadError {
|
||||
message: string;
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
|
||||
const getErrorMessage = (error: unknown, fallback: string) =>
|
||||
error instanceof Error ? error.message : typeof error === 'string' ? error : fallback;
|
||||
|
||||
const getErrorStatus = (error: unknown): number | undefined =>
|
||||
isRecord(error) && typeof error.status === 'number' ? error.status : undefined;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
import { useHeaderRefresh } from '@/hooks/useHeaderRefresh';
|
||||
import { pluginsApi } from '@/services/api';
|
||||
import { useAuthStore, useConfigStore, useNotificationStore } from '@/stores';
|
||||
import { getErrorMessage, isRecord } from '@/utils/helpers';
|
||||
import type { PluginConfigField, PluginListEntry, PluginListResponse } from '@/types';
|
||||
import { getPluginTitle, resolvePluginAssetURL } from './pluginResources';
|
||||
import styles from './PluginsPage.module.scss';
|
||||
@@ -44,15 +45,9 @@ function PluginCardLogo({ src }: { src: string }) {
|
||||
);
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
value !== null && typeof value === 'object' && !Array.isArray(value);
|
||||
|
||||
const cloneRecord = (value: unknown): Record<string, unknown> =>
|
||||
isRecord(value) ? { ...value } : {};
|
||||
|
||||
const getErrorMessage = (error: unknown, fallback: string) =>
|
||||
error instanceof Error ? error.message : typeof error === 'string' ? error : fallback;
|
||||
|
||||
const hasStatus = (error: unknown, status: number) =>
|
||||
isRecord(error) && error.status === status;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import {
|
||||
type ProviderRecentUsageMap,
|
||||
} from '@/components/providers/utils';
|
||||
import type { OpenAIProviderConfig } from '@/types';
|
||||
import { isRecord } from '@/utils/helpers';
|
||||
import { ProviderHeaderCard } from './components/ProviderHeaderCard';
|
||||
import { ProviderCategoryList } from './components/ProviderCategoryList';
|
||||
import { ProviderResourcePanel } from './components/ProviderResourcePanel';
|
||||
@@ -66,9 +67,6 @@ const matchesFilter = (r: ProviderResource, normalized: string): boolean => {
|
||||
return haystack.some((v) => v.includes(normalized));
|
||||
};
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
||||
|
||||
const getResourceModels = (resource: ProviderResource): string[] => {
|
||||
if (!isRecord(resource.raw)) return [];
|
||||
if (resource.brand === 'ampcode') {
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
buildOpenAIChatCompletionsEndpoint,
|
||||
} from '@/components/providers/utils';
|
||||
import { buildHeaderObject, hasHeader } from '@/utils/headers';
|
||||
import { getErrorMessage } from '@/utils/helpers';
|
||||
import type { ApiKeyEntryInput, ModelEntryInput, ProviderBrand } from '../../types';
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 30_000;
|
||||
@@ -20,14 +21,8 @@ export interface ConnectivityStatus {
|
||||
|
||||
const IDLE: ConnectivityStatus = { state: 'idle', message: '' };
|
||||
|
||||
const errorMessage = (err: unknown): string => {
|
||||
if (err instanceof Error) return err.message;
|
||||
if (typeof err === 'string') return err;
|
||||
return '';
|
||||
};
|
||||
|
||||
const requestFailureMessage = (err: unknown, messages: ConnectivityErrorMessages): string => {
|
||||
const raw = errorMessage(err);
|
||||
const raw = getErrorMessage(err);
|
||||
const isTimeout =
|
||||
(typeof err === 'object' &&
|
||||
err !== null &&
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { modelsApi } from '@/services/api';
|
||||
import { buildHeaderObject } from '@/utils/headers';
|
||||
import { getErrorMessage } from '@/utils/helpers';
|
||||
import type { ModelInfo } from '@/utils/models';
|
||||
import type { ApiKeyEntryInput, ProviderBrand } from '../../types';
|
||||
|
||||
@@ -14,12 +15,6 @@ export const MODEL_DISCOVERY_BRANDS: ReadonlyArray<ProviderBrand> = [
|
||||
export const isModelDiscoveryBrand = (brand: ProviderBrand): boolean =>
|
||||
MODEL_DISCOVERY_BRANDS.includes(brand);
|
||||
|
||||
const toErrorMessage = (err: unknown): string => {
|
||||
if (err instanceof Error) return err.message;
|
||||
if (typeof err === 'string') return err;
|
||||
return '';
|
||||
};
|
||||
|
||||
export interface UseModelDiscoveryArgs {
|
||||
brand: ProviderBrand;
|
||||
baseUrl: string;
|
||||
@@ -111,7 +106,7 @@ export function useModelDiscovery(args: UseModelDiscoveryArgs): UseModelDiscover
|
||||
setHasFetched(true);
|
||||
} catch (err) {
|
||||
setModels([]);
|
||||
setError(toErrorMessage(err) || 'Failed to fetch models');
|
||||
setError(getErrorMessage(err) || 'Failed to fetch models');
|
||||
setHasFetched(true);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isRecord } from '@/utils/helpers';
|
||||
import { PROVIDER_BRAND_ORDER } from './descriptors';
|
||||
import {
|
||||
PROVIDER_SORT_BY_VALUES,
|
||||
@@ -32,9 +33,6 @@ export interface ProvidersWorkbenchUiState {
|
||||
filtersByBrand: Partial<Record<ProviderBrand, ProviderFilterState>>;
|
||||
}
|
||||
|
||||
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
||||
Boolean(value && typeof value === 'object' && !Array.isArray(value));
|
||||
|
||||
const isProviderBrand = (value: unknown): value is ProviderBrand =>
|
||||
typeof value === 'string' && PROVIDER_BRAND_SET.has(value as ProviderBrand);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||
import { ampcodeApi, providersApi } from '@/services/api';
|
||||
import { getErrorMessage } from '@/utils/helpers';
|
||||
import { useAuthStore, useConfigStore } from '@/stores';
|
||||
import {
|
||||
withDisableAllModelsRule,
|
||||
@@ -28,12 +29,6 @@ import type {
|
||||
ProviderSnapshot,
|
||||
} from './types';
|
||||
|
||||
const getErrorMessage = (err: unknown): string => {
|
||||
if (err instanceof Error) return err.message;
|
||||
if (typeof err === 'string') return err;
|
||||
return '';
|
||||
};
|
||||
|
||||
export interface UseProviderWorkbenchResult {
|
||||
connected: boolean;
|
||||
isPending: boolean;
|
||||
|
||||
Reference in New Issue
Block a user