refactor(new merge) (#369)

Co-authored-by: paisley <8197966+su8su@users.noreply.github.com>
Co-authored-by: zuolingxuan <zuolingxuan@bytedance.com>
This commit is contained in:
Lingxuan Zuo
2026-03-09 20:18:25 +08:00
committed by GitHub
Unverified
parent e28eba01e1
commit 3d664c017a
18 changed files with 514 additions and 390 deletions

View File

@@ -21,6 +21,9 @@ import { validateApiKeyWithProvider } from '../../services/providers/provider-va
import { getProviderService } from '../../services/providers/provider-service';
import { providerAccountToConfig } from '../../services/providers/provider-store';
import type { ProviderAccount } from '../../shared/providers/types';
import { logger } from '../../utils/logger';
const legacyProviderRoutesWarned = new Set<string>();
export async function handleProviderRoutes(
req: IncomingMessage,
@@ -29,6 +32,13 @@ export async function handleProviderRoutes(
ctx: HostApiContext,
): Promise<boolean> {
const providerService = getProviderService();
const logLegacyProviderRoute = (route: string): void => {
if (legacyProviderRoutesWarned.has(route)) return;
legacyProviderRoutesWarned.add(route);
logger.warn(
`[provider-migration] Legacy HTTP route "${route}" is deprecated. Prefer /api/provider-accounts endpoints.`,
);
};
if (url.pathname === '/api/provider-vendors' && req.method === 'GET') {
sendJson(res, 200, await providerService.listVendors());
@@ -125,16 +135,19 @@ export async function handleProviderRoutes(
}
if (url.pathname === '/api/providers' && req.method === 'GET') {
logLegacyProviderRoute('GET /api/providers');
sendJson(res, 200, await providerService.listLegacyProvidersWithKeyInfo());
return true;
}
if (url.pathname === '/api/providers/default' && req.method === 'GET') {
logLegacyProviderRoute('GET /api/providers/default');
sendJson(res, 200, { providerId: await providerService.getDefaultLegacyProvider() ?? null });
return true;
}
if (url.pathname === '/api/providers/default' && req.method === 'PUT') {
logLegacyProviderRoute('PUT /api/providers/default');
try {
const body = await parseJsonBody<{ providerId: string }>(req);
await providerService.setDefaultLegacyProvider(body.providerId);
@@ -147,6 +160,7 @@ export async function handleProviderRoutes(
}
if (url.pathname === '/api/providers/validate' && req.method === 'POST') {
logLegacyProviderRoute('POST /api/providers/validate');
try {
const body = await parseJsonBody<{ providerId: string; apiKey: string; options?: { baseUrl?: string } }>(req);
const provider = await providerService.getLegacyProvider(body.providerId);
@@ -161,6 +175,7 @@ export async function handleProviderRoutes(
}
if (url.pathname === '/api/providers/oauth/start' && req.method === 'POST') {
logLegacyProviderRoute('POST /api/providers/oauth/start');
try {
const body = await parseJsonBody<{
provider: OAuthProviderType | BrowserOAuthProviderType;
@@ -187,6 +202,7 @@ export async function handleProviderRoutes(
}
if (url.pathname === '/api/providers/oauth/cancel' && req.method === 'POST') {
logLegacyProviderRoute('POST /api/providers/oauth/cancel');
try {
await deviceOAuthManager.stopFlow();
await browserOAuthManager.stopFlow();
@@ -198,6 +214,7 @@ export async function handleProviderRoutes(
}
if (url.pathname === '/api/providers' && req.method === 'POST') {
logLegacyProviderRoute('POST /api/providers');
try {
const body = await parseJsonBody<{ config: ProviderConfig; apiKey?: string }>(req);
const config = body.config;
@@ -218,6 +235,7 @@ export async function handleProviderRoutes(
}
if (url.pathname.startsWith('/api/providers/') && req.method === 'GET') {
logLegacyProviderRoute('GET /api/providers/:id');
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
if (providerId.endsWith('/api-key')) {
const actualId = providerId.slice(0, -('/api-key'.length));
@@ -234,6 +252,7 @@ export async function handleProviderRoutes(
}
if (url.pathname.startsWith('/api/providers/') && req.method === 'PUT') {
logLegacyProviderRoute('PUT /api/providers/:id');
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
try {
const body = await parseJsonBody<{ updates: Partial<ProviderConfig>; apiKey?: string }>(req);
@@ -263,6 +282,7 @@ export async function handleProviderRoutes(
}
if (url.pathname.startsWith('/api/providers/') && req.method === 'DELETE') {
logLegacyProviderRoute('DELETE /api/providers/:id');
const providerId = decodeURIComponent(url.pathname.slice('/api/providers/'.length));
try {
const existing = await providerService.getLegacyProvider(providerId);

View File

@@ -10,8 +10,14 @@ export async function handleUsageRoutes(
_ctx: HostApiContext,
): Promise<boolean> {
if (url.pathname === '/api/usage/recent-token-history' && req.method === 'GET') {
const parsedLimit = Number(url.searchParams.get('limit') || '');
const limit = Number.isFinite(parsedLimit) ? Math.max(Math.floor(parsedLimit), 1) : undefined;
const rawLimit = url.searchParams.get('limit');
let limit: number | undefined;
if (rawLimit != null && rawLimit.trim() !== '') {
const parsedLimit = Number(rawLimit);
if (Number.isFinite(parsedLimit)) {
limit = Math.max(Math.floor(parsedLimit), 1);
}
}
sendJson(res, 200, await getRecentTokenUsageHistory(limit));
return true;
}

View File

@@ -1652,6 +1652,14 @@ function registerDeviceOAuthHandlers(mainWindow: BrowserWindow): void {
*/
function registerProviderHandlers(gatewayManager: GatewayManager): void {
const providerService = getProviderService();
const legacyProviderChannelsWarned = new Set<string>();
const logLegacyProviderChannel = (channel: string): void => {
if (legacyProviderChannelsWarned.has(channel)) return;
legacyProviderChannelsWarned.add(channel);
logger.warn(
`[provider-migration] Legacy IPC channel "${channel}" is deprecated. Prefer app:request provider actions and account APIs.`,
);
};
// Listen for OAuth success to automatically restart the Gateway with new tokens/configs.
// Use a longer debounce (8s) so that provider:setDefault — which writes the full config
@@ -1669,6 +1677,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Get all providers with key info
ipcMain.handle('provider:list', async () => {
logLegacyProviderChannel('provider:list');
return await providerService.listLegacyProvidersWithKeyInfo();
});
@@ -1687,11 +1696,13 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Get a specific provider
ipcMain.handle('provider:get', async (_, providerId: string) => {
logLegacyProviderChannel('provider:get');
return await providerService.getLegacyProvider(providerId);
});
// Save a provider configuration
ipcMain.handle('provider:save', async (_, config: ProviderConfig, apiKey?: string) => {
logLegacyProviderChannel('provider:save');
try {
// Save the provider config
await providerService.saveLegacyProvider(config);
@@ -1726,6 +1737,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Delete a provider
ipcMain.handle('provider:delete', async (_, providerId: string) => {
logLegacyProviderChannel('provider:delete');
try {
const existing = await providerService.getLegacyProvider(providerId);
await providerService.deleteLegacyProvider(providerId);
@@ -1747,6 +1759,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Update API key for a provider
ipcMain.handle('provider:setApiKey', async (_, providerId: string, apiKey: string) => {
logLegacyProviderChannel('provider:setApiKey');
try {
await providerService.setLegacyProviderApiKey(providerId, apiKey);
@@ -1774,6 +1787,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
updates: Partial<ProviderConfig>,
apiKey?: string
) => {
logLegacyProviderChannel('provider:updateWithKey');
const existing = await providerService.getLegacyProvider(providerId);
if (!existing) {
return { success: false, error: 'Provider not found' };
@@ -1834,6 +1848,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Delete API key for a provider
ipcMain.handle('provider:deleteApiKey', async (_, providerId: string) => {
logLegacyProviderChannel('provider:deleteApiKey');
try {
await providerService.deleteLegacyProviderApiKey(providerId);
@@ -1853,16 +1868,19 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Check if a provider has an API key
ipcMain.handle('provider:hasApiKey', async (_, providerId: string) => {
logLegacyProviderChannel('provider:hasApiKey');
return await providerService.hasLegacyProviderApiKey(providerId);
});
// Get the actual API key (for internal use only - be careful!)
ipcMain.handle('provider:getApiKey', async (_, providerId: string) => {
logLegacyProviderChannel('provider:getApiKey');
return await providerService.getLegacyProviderApiKey(providerId);
});
// Set default provider and update OpenClaw default model
ipcMain.handle('provider:setDefault', async (_, providerId: string) => {
logLegacyProviderChannel('provider:setDefault');
try {
await providerService.setDefaultLegacyProvider(providerId);
@@ -1883,6 +1901,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
// Get default provider
ipcMain.handle('provider:getDefault', async () => {
logLegacyProviderChannel('provider:getDefault');
return await providerService.getDefaultLegacyProvider();
});
@@ -1896,6 +1915,7 @@ function registerProviderHandlers(gatewayManager: GatewayManager): void {
apiKey: string,
options?: { baseUrl?: string }
) => {
logLegacyProviderChannel('provider:validateKey');
try {
// First try to get existing provider
const provider = await providerService.getLegacyProvider(providerId);

View File

@@ -27,6 +27,7 @@ import {
storeApiKey,
} from '../../utils/secure-storage';
import type { ProviderWithKeyInfo } from '../../shared/providers/types';
import { logger } from '../../utils/logger';
function maskApiKey(apiKey: string | null): string | null {
if (!apiKey) return null;
@@ -36,6 +37,18 @@ function maskApiKey(apiKey: string | null): string | null {
return '*'.repeat(apiKey.length);
}
const legacyProviderApiWarned = new Set<string>();
function logLegacyProviderApiUsage(method: string, replacement: string): void {
if (legacyProviderApiWarned.has(method)) {
return;
}
legacyProviderApiWarned.add(method);
logger.warn(
`[provider-migration] Legacy provider API "${method}" is deprecated. Migrate to "${replacement}".`,
);
}
export class ProviderService {
async listVendors(): Promise<ProviderDefinition[]> {
return PROVIDER_DEFINITIONS;
@@ -103,20 +116,21 @@ export class ProviderService {
return deleteProvider(accountId);
}
async syncLegacyProvider(config: ProviderConfig, options?: { isDefault?: boolean }): Promise<ProviderAccount> {
await ensureProviderStoreMigrated();
const account = providerConfigToAccount(config, options);
await saveProviderAccount(account);
return account;
}
/**
* @deprecated Use listAccounts() and map account data in callers.
*/
async listLegacyProviders(): Promise<ProviderConfig[]> {
logLegacyProviderApiUsage('listLegacyProviders', 'listAccounts');
await ensureProviderStoreMigrated();
const accounts = await listProviderAccounts();
return accounts.map(providerAccountToConfig);
}
/**
* @deprecated Use listAccounts() + secret-store based key summary.
*/
async listLegacyProvidersWithKeyInfo(): Promise<ProviderWithKeyInfo[]> {
logLegacyProviderApiUsage('listLegacyProvidersWithKeyInfo', 'listAccounts');
const providers = await this.listLegacyProviders();
const results: ProviderWithKeyInfo[] = [];
for (const provider of providers) {
@@ -130,13 +144,21 @@ export class ProviderService {
return results;
}
/**
* @deprecated Use getAccount(accountId).
*/
async getLegacyProvider(providerId: string): Promise<ProviderConfig | null> {
logLegacyProviderApiUsage('getLegacyProvider', 'getAccount');
await ensureProviderStoreMigrated();
const account = await getProviderAccount(providerId);
return account ? providerAccountToConfig(account) : null;
}
/**
* @deprecated Use createAccount()/updateAccount().
*/
async saveLegacyProvider(config: ProviderConfig): Promise<void> {
logLegacyProviderApiUsage('saveLegacyProvider', 'createAccount/updateAccount');
await ensureProviderStoreMigrated();
const account = providerConfigToAccount(config);
const existing = await getProviderAccount(config.id);
@@ -147,33 +169,61 @@ export class ProviderService {
await this.createAccount(account);
}
/**
* @deprecated Use deleteAccount(accountId).
*/
async deleteLegacyProvider(providerId: string): Promise<boolean> {
logLegacyProviderApiUsage('deleteLegacyProvider', 'deleteAccount');
await ensureProviderStoreMigrated();
await this.deleteAccount(providerId);
return true;
}
/**
* @deprecated Use setDefaultAccount(accountId).
*/
async setDefaultLegacyProvider(providerId: string): Promise<void> {
logLegacyProviderApiUsage('setDefaultLegacyProvider', 'setDefaultAccount');
await this.setDefaultAccount(providerId);
}
/**
* @deprecated Use getDefaultAccountId().
*/
async getDefaultLegacyProvider(): Promise<string | undefined> {
logLegacyProviderApiUsage('getDefaultLegacyProvider', 'getDefaultAccountId');
return this.getDefaultAccountId();
}
/**
* @deprecated Use secret-store APIs by accountId.
*/
async setLegacyProviderApiKey(providerId: string, apiKey: string): Promise<boolean> {
logLegacyProviderApiUsage('setLegacyProviderApiKey', 'setProviderSecret(accountId, api_key)');
return storeApiKey(providerId, apiKey);
}
/**
* @deprecated Use secret-store APIs by accountId.
*/
async getLegacyProviderApiKey(providerId: string): Promise<string | null> {
logLegacyProviderApiUsage('getLegacyProviderApiKey', 'getProviderSecret(accountId)');
return getApiKey(providerId);
}
/**
* @deprecated Use secret-store APIs by accountId.
*/
async deleteLegacyProviderApiKey(providerId: string): Promise<boolean> {
logLegacyProviderApiUsage('deleteLegacyProviderApiKey', 'deleteProviderSecret(accountId)');
return deleteApiKey(providerId);
}
/**
* @deprecated Use secret-store APIs by accountId.
*/
async hasLegacyProviderApiKey(providerId: string): Promise<boolean> {
logLegacyProviderApiUsage('hasLegacyProviderApiKey', 'getProviderSecret(accountId)');
return hasApiKey(providerId);
}