Remove deeplink replace and default actions

This commit is contained in:
musi 2026-06-23 07:37:57 +08:00
parent 9119cd8567
commit 0243b408a1
5 changed files with 10 additions and 51 deletions

View file

@ -20,7 +20,7 @@ The wrapper reads `~/.claude-code-router/config.json`, preserves the old CCR `Pr
Supplier websites can open CCR and import a model provider with a custom protocol link:
```text
ccr://provider?name=Example%20AI&base_url=https%3A%2F%2Fapi.example.com%2Fv1&api_key=sk-example&models=example-chat%2Cexample-coder&protocol=openai_chat_completions&set_default=1
ccr://provider?name=Example%20AI&base_url=https%3A%2F%2Fapi.example.com%2Fv1&api_key=sk-example&models=example-chat%2Cexample-coder&protocol=openai_chat_completions
```
Supported query parameters:
@ -30,8 +30,6 @@ Supported query parameters:
- `api_key`: optional provider API key. Aliases: `apiKey`, `apikey`, `key`, `token`.
- `models`: comma-separated or newline-separated model list. You can also repeat `model=...`.
- `protocol`: one of `openai_chat_completions`, `openai_responses`, `anthropic_messages`, or `gemini_generate_content`. Aliases such as `openai`, `responses`, `anthropic`, and `gemini` are accepted.
- `set_default=1`: make the imported provider the preferred provider.
- `replace=1`: replace an existing provider with the same name or normalized base URL.
For larger payloads, pass `payload` as URL-encoded JSON or base64url JSON with the same fields:
@ -41,8 +39,7 @@ For larger payloads, pass `payload` as URL-encoded JSON or base64url JSON with t
"baseUrl": "https://api.example.com/v1",
"apiKey": "sk-example",
"models": ["example-chat", "example-coder"],
"protocol": "openai_chat_completions",
"setDefault": true
"protocol": "openai_chat_completions"
}
```

View file

@ -11,7 +11,7 @@ import {
enforceSingleEnabledGlobalProfilePerAgent,
ExtensionConfigTarget, ExtensionDeleteTarget, ExtensionInstallDraft, ExtensionSource, fallbackAgentAnalysis, fallbackConfig,
fallbackGatewayStatus, fallbackInfo, fallbackProxyCertificateStatus, fallbackProxyNetworkSnapshot, fallbackProxyStatus, fallbackRequestLogPage,
fallbackUpdateStatus, fallbackUsageStats, findProviderDeepLinkReplacementIndex, formatJson, formatProxyCertificateInstallMessage, GatewayProviderConfig,
fallbackUpdateStatus, fallbackUsageStats, formatJson, formatProxyCertificateInstallMessage, GatewayProviderConfig,
fusionCustomMcpServerFromDraft, fusionCustomToolConfigFromProfile,
GatewayProviderProbeResult, gatewayServiceMessage, GatewayStatus, getDefaultOnboardingStep, isClaudeDesignPluginConfig, isClaudeDesignRoutingDraftValid,
isCursorProxyPluginConfig, isMacPlatform, isPlainRecord, isProfileDraftSubmittable, isProviderNameDuplicate, isProviderProbeCandidateReady,
@ -1231,17 +1231,10 @@ function App() {
const probe = await probeProviderDeepLinkPayload(payload);
let importedProviderName = payload.name?.trim() || "";
const next = buildConfigUpdate((config) => {
const replaceIndex = payload.replaceExisting
? findProviderDeepLinkReplacementIndex(config.Providers, payload, probe?.normalizedBaseUrl || payload.baseUrl)
: -1;
const provider = createProviderConfigFromDeepLink(payload, config.Providers, probe, replaceIndex);
const provider = createProviderConfigFromDeepLink(payload, config.Providers, probe);
importedProviderName = provider.name;
if (replaceIndex >= 0) {
config.Providers[replaceIndex] = provider;
} else {
config.Providers.push(provider);
}
if (payload.setDefault || !config.preferredProvider) {
config.Providers.push(provider);
if (!config.preferredProvider) {
config.preferredProvider = provider.name;
}
return config;

View file

@ -790,8 +790,7 @@ export async function resolveProviderDeepLinkIcon(payload: ProviderDeepLinkPaylo
export function createProviderConfigFromDeepLink(
payload: ProviderDeepLinkPayload,
providers: GatewayProviderConfig[],
probe: GatewayProviderProbeResult | undefined,
replaceIndex: number
probe: GatewayProviderProbeResult | undefined
): GatewayProviderConfig {
const protocol = probe?.detectedProtocol ?? payload.protocol ?? "openai_chat_completions";
const baseUrl = probe?.normalizedBaseUrl || payload.baseUrl;
@ -802,9 +801,8 @@ export function createProviderConfigFromDeepLink(
throw new Error("Models are required. Ask the provider to include models=... in the link.");
}
const existingName = replaceIndex >= 0 ? providers[replaceIndex]?.name : undefined;
const baseName = payload.name?.trim() || existingName || inferProviderNameFromBaseUrl(baseUrl);
const name = replaceIndex >= 0 ? baseName : uniqueProviderName(providers, baseName);
const baseName = payload.name?.trim() || inferProviderNameFromBaseUrl(baseUrl);
const name = uniqueProviderName(providers, baseName);
const keySafetyIssue = providerApiKeySafetyIssue({ apiKey: payload.apiKey, baseUrl, name });
if (keySafetyIssue) {
throw new Error(keySafetyIssue.message);
@ -839,23 +837,6 @@ export function createProviderConfigFromDeepLink(
};
}
export function findProviderDeepLinkReplacementIndex(
providers: GatewayProviderConfig[],
payload: ProviderDeepLinkPayload,
baseUrl: string
): number {
const name = payload.name?.trim();
if (name) {
const namedIndex = providers.findIndex((provider) => provider.name === name);
if (namedIndex >= 0) {
return namedIndex;
}
}
const normalizedBaseUrl = normalizeProviderBaseUrl(baseUrl).toLowerCase();
return providers.findIndex((provider) => normalizeProviderBaseUrl(providerBaseUrl(provider)).toLowerCase() === normalizedBaseUrl);
}
export function inferProviderNameFromBaseUrl(baseUrl: string): string {
try {
const url = new URL(providerUrlWithDefaultScheme(baseUrl));
@ -1445,9 +1426,7 @@ export function createProviderInstallLinkFromDraft(draft: AddProviderDraft, prob
...(draft.icon.trim() ? { icon: draft.icon.trim() } : {}),
models,
name: providerName,
protocol,
replaceExisting: false,
setDefault: false
protocol
};
return `ccr://provider?payload=${base64UrlEncodeText(JSON.stringify(payload))}`;
}

View file

@ -215,8 +215,6 @@ export type ProviderDeepLinkPayload = {
models: string[];
name?: string;
protocol?: GatewayProviderProtocol;
replaceExisting: boolean;
setDefault: boolean;
source?: string;
};

View file

@ -160,8 +160,6 @@ export function parseProviderDeepLinkPayload(rawUrl: string): ProviderDeepLinkPa
firstStringParam(params, ["protocol", "type"]) ?? firstPayloadString(payload, ["protocol", "type"])
);
const models = readDeepLinkModels(params, payload);
const setDefault = readDeepLinkBoolean(params, payload, ["set_default", "setDefault", "default", "preferred"]);
const replaceExisting = readDeepLinkBoolean(params, payload, ["replace", "replace_existing", "replaceExisting", "update"]);
const account = readDeepLinkAccount(params, payload);
const source = boundedString(
firstStringParam(params, ["source", "source_url", "sourceUrl"]) ??
@ -176,8 +174,6 @@ export function parseProviderDeepLinkPayload(rawUrl: string): ProviderDeepLinkPa
models,
...(name ? { name } : {}),
...(protocol ? { protocol } : {}),
replaceExisting,
setDefault,
...(source ? { source } : {})
};
}
@ -232,8 +228,6 @@ function parseProviderPayloadFields(
firstStringParam(params, ["protocol", "type"]) ?? firstPayloadString(payload, ["protocol", "type"])
);
const models = readDeepLinkModels(params, payload);
const setDefault = readDeepLinkBoolean(params, payload, ["set_default", "setDefault", "default", "preferred"]);
const replaceExisting = readDeepLinkBoolean(params, payload, ["replace", "replace_existing", "replaceExisting", "update"]);
const account = readDeepLinkAccount(params, payload);
const source = boundedString(
firstStringParam(params, ["source", "source_url", "sourceUrl"]) ??
@ -251,8 +245,6 @@ function parseProviderPayloadFields(
models,
...(name ? { name } : {}),
...(protocol ? { protocol } : {}),
replaceExisting,
setDefault,
...(source ? { source } : {})
};
}