fix(cliproxy): exclude colocated tests from tsconfig and eslint

- Add src/**/__tests__/** to tsconfig.json exclude list
- Add ignores pattern for __tests__ in eslint.config.mjs
- Fix ui/src/lib/api-client.ts import path for provider-entitlement-types
- Remove stale build artifacts from ui/src/lib/ and tests/mocks/
This commit is contained in:
Tam Nhu Tran
2026-04-29 17:18:23 -04:00
parent 273214d166
commit c3c8cb7a82
57 changed files with 251 additions and 214 deletions
+1
View File
@@ -5,6 +5,7 @@ import prettier from 'eslint-config-prettier';
export default [
{
files: ['src/**/*.ts'],
ignores: ['src/**/__tests__/**'],
languageOptions: {
parser: tsparser,
parserOptions: {
@@ -16,7 +16,8 @@ function writeCliproxyConfig(homeDir: string, value: Record<string, unknown>): v
function readCliproxyConfig(homeDir: string): Record<string, any> {
return (
(yaml.load(fs.readFileSync(getCliproxyConfigPath(homeDir), 'utf8')) as Record<string, any>) || {}
(yaml.load(fs.readFileSync(getCliproxyConfigPath(homeDir), 'utf8')) as Record<string, any>) ||
{}
);
}
@@ -62,7 +63,9 @@ describe('ai-provider service stable ids', () => {
expect(family?.entries[1]?.id).toBeTruthy();
expect(family?.entries[0]?.id).not.toBe(family?.entries[1]?.id);
const persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<Record<string, unknown>>;
const persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<
Record<string, unknown>
>;
expect(persisted[0]?.id).toBe(family?.entries[0]?.id);
expect(persisted[1]?.id).toBe(family?.entries[1]?.id);
});
@@ -82,7 +85,9 @@ describe('ai-provider service stable ids', () => {
baseUrl: 'https://example.test/gemini',
});
let persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<Record<string, unknown>>;
let persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<
Record<string, unknown>
>;
expect(persisted[0]?.id).toBe('gemini-a');
expect(persisted[0]?.['api-key']).toBe('gamma');
expect(persisted[0]?.['base-url']).toBe('https://example.test/gemini');
@@ -105,7 +110,9 @@ describe('ai-provider service stable ids', () => {
apiKey: 'legacy-index-update',
});
const persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<Record<string, unknown>>;
const persisted = readCliproxyConfig(tempHome)['gemini-api-key'] as Array<
Record<string, unknown>
>;
expect(persisted[0]?.id).toBe('gemini-a');
expect(persisted[0]?.['api-key']).toBe('legacy-index-update');
});
@@ -140,9 +147,9 @@ describe('ai-provider service stable ids', () => {
>;
expect(persisted[0]?.id).toBe(connectorId);
expect(persisted[0]?.['base-url']).toBe('https://router.example/v1');
expect((persisted[0]?.['api-key-entries'] as Array<Record<string, unknown>>)[0]?.['api-key']).toBe(
'sk-openrouter'
);
expect(
(persisted[0]?.['api-key-entries'] as Array<Record<string, unknown>>)[0]?.['api-key']
).toBe('sk-openrouter');
});
it('normalizes plain openai-compatible model rules without aliases', async () => {
@@ -1,10 +1,6 @@
import { describe, it, expect } from 'bun:test';
import { findModel, supportsThinking } from '../model-catalog';
import {
PROVIDER_TO_CHANNEL,
SYNCABLE_PROVIDERS,
mergeCatalog,
} from '../services/catalog-cache';
import { PROVIDER_TO_CHANNEL, SYNCABLE_PROVIDERS, mergeCatalog } from '../services/catalog-cache';
describe('model-catalog compatibility lookups', () => {
it('finds agy Claude models using dotted major.minor IDs', () => {
+1 -4
View File
@@ -118,10 +118,7 @@ describe('Model Config', () => {
assert(parsed.env, 'Should have env object');
assert(parsed.env.ANTHROPIC_MODEL, 'Should have ANTHROPIC_MODEL');
assert.strictEqual(
parsed.env.ANTHROPIC_MODEL,
'claude-opus-4-5-thinking'
);
assert.strictEqual(parsed.env.ANTHROPIC_MODEL, 'claude-opus-4-5-thinking');
});
it('all env values should be strings (PowerShell safety)', () => {
@@ -167,9 +167,13 @@ describe('provider-capabilities', () => {
expect(getKiroCLIAuthFlag('aws-authcode')).toBe('--kiro-aws-authcode');
expect(getKiroCLIAuthFlag('google')).toBe('--kiro-google-login');
expect(getKiroCLIAuthFlag('idc')).toBe('--kiro-idc-login');
expect(getKiroCLIAuthArgs('idc', { idcStartUrl: 'https://d-123.awsapps.com/start' })).toEqual(
['--kiro-idc-login', '--kiro-idc-start-url', 'https://d-123.awsapps.com/start', '--kiro-idc-flow', 'authcode']
);
expect(getKiroCLIAuthArgs('idc', { idcStartUrl: 'https://d-123.awsapps.com/start' })).toEqual([
'--kiro-idc-login',
'--kiro-idc-start-url',
'https://d-123.awsapps.com/start',
'--kiro-idc-flow',
'authcode',
]);
expect(getKiroCallbackPort('aws')).toBeNull();
expect(getKiroCallbackPort('google')).toBe(9876);
@@ -11,7 +11,10 @@ const path = require('path');
const os = require('os');
// Set test isolation environment before importing
const testHome = path.join(os.tmpdir(), `ccs-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
const testHome = path.join(
os.tmpdir(),
`ccs-test-${Date.now()}-${Math.random().toString(36).slice(2)}`
);
const originalCcsHome = process.env.CCS_HOME;
const originalCcsDir = process.env.CCS_DIR;
process.env.CCS_HOME = testHome;
@@ -183,7 +183,11 @@ describe('Account Manager - discoverExistingAccounts', () => {
const accountIds = Object.keys(accounts.providers.kiro.accounts);
// For kiro/ghcp without email, generates unique ID like "kiro-1"
assert.strictEqual(accountIds[0], 'kiro-1', 'Should generate unique ID for kiro without email');
assert.strictEqual(
accountIds[0],
'kiro-1',
'Should generate unique ID for kiro without email'
);
});
it('handles dots in email local part', () => {
@@ -21,7 +21,9 @@ async function loadAccountManager() {
return import(`../account-manager?account-registry-integrity=${Date.now()}`);
}
async function captureConsoleError<T>(fn: () => Promise<T> | T): Promise<{ result: T; messages: string[] }> {
async function captureConsoleError<T>(
fn: () => Promise<T> | T
): Promise<{ result: T; messages: string[] }> {
const originalError = console.error;
const messages: string[] = [];
@@ -351,7 +353,9 @@ describe('account registry integrity', () => {
fs.writeFileSync(registryPath, '{"providers":', 'utf8');
const { loadAccountsRegistry } = await loadRegistryModule();
const { result: registry, messages } = await captureConsoleError(() => loadAccountsRegistry());
const { result: registry, messages } = await captureConsoleError(() =>
loadAccountsRegistry()
);
expect(registry).toEqual({
version: 1,
@@ -121,7 +121,8 @@ describe('registerAccount optional nickname flow', () => {
const result = await withIsolatedHome(async (homeDir) => {
writeTokenFile(homeDir, 'codex-04a0f049-kaidu.kd@gmail.com-team.json');
writeTokenFile(homeDir, 'codex-kaidu.kd@gmail.com-free.json');
const { registerAccount, getProviderAccounts, findAccountByQuery } = await loadAccountManager();
const { registerAccount, getProviderAccounts, findAccountByQuery } =
await loadAccountManager();
const team = registerAccount(
'codex',
'codex-04a0f049-kaidu.kd@gmail.com-team.json',
@@ -342,16 +342,12 @@ describe('Quota Exhaustion Handlers', () => {
}) as typeof fetch;
const result = await handleQuotaExhaustion('claude', 'exhausted@example.com', 10);
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedTo).toBe('fallback@example.com');
expect(getDefaultAccount('claude')?.id).toBe('fallback@example.com');
expect(getAccount('claude', 'exhausted@example.com')?.paused).not.toBe(true);
expect(fs.existsSync(path.join(tmpDir, '.ccs', 'cliproxy', 'quota-paused.json'))).toBe(
false
);
expect(fs.existsSync(path.join(tmpDir, '.ccs', 'cliproxy', 'quota-paused.json'))).toBe(false);
expect(
fs.existsSync(
path.join(
@@ -429,9 +425,7 @@ describe('Quota Exhaustion Handlers', () => {
}) as typeof fetch;
const result = await handleQuotaExhaustion('codex', 'exhausted@example.com', 10);
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedTo).toBe('fallback@example.com');
expect(getDefaultAccount('codex')?.id).toBe('fallback@example.com');
@@ -569,9 +563,7 @@ describe('Quota Exhaustion Handlers', () => {
const { preflightCheck } = await import('../../quota/quota-manager');
const result = await preflightCheck('codex');
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedFrom).toBe('preflight-exhausted@example.com');
expect(result.accountId).toBe('preflight-fallback@example.com');
@@ -649,16 +641,12 @@ describe('Quota Exhaustion Handlers', () => {
const { preflightCheck } = await import('../../quota/quota-manager');
const result = await preflightCheck('codex');
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedFrom).toBe('preflight-unknown-exhausted@example.com');
expect(result.accountId).toBe('preflight-unknown-fallback@example.com');
expect(getDefaultAccount('codex')?.id).toBe('preflight-unknown-fallback@example.com');
expect(getAccount('codex', 'preflight-unknown-exhausted@example.com')?.paused).not.toBe(
true
);
expect(getAccount('codex', 'preflight-unknown-exhausted@example.com')?.paused).not.toBe(true);
expect(
fs.existsSync(
path.join(tmpDir, '.ccs', 'cliproxy', 'auth', 'codex-preflight-unknown-exhausted.json')
@@ -675,9 +663,7 @@ describe('Quota Exhaustion Handlers', () => {
)
)
).toBe(false);
expect(fs.existsSync(path.join(tmpDir, '.ccs', 'cliproxy', 'quota-paused.json'))).toBe(
false
);
expect(fs.existsSync(path.join(tmpDir, '.ccs', 'cliproxy', 'quota-paused.json'))).toBe(false);
});
it('should self-pause exhausted Gemini accounts when a healthy fallback exists', async () => {
@@ -736,9 +722,7 @@ describe('Quota Exhaustion Handlers', () => {
}) as typeof fetch;
const result = await handleQuotaExhaustion('gemini', 'gemini-exhausted@example.com', 10);
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedTo).toBe('gemini-fallback@example.com');
expect(getDefaultAccount('gemini')?.id).toBe('gemini-fallback@example.com');
@@ -804,9 +788,7 @@ describe('Quota Exhaustion Handlers', () => {
}) as typeof fetch;
const result = await handleQuotaExhaustion('ghcp', 'ghcp-exhausted', 10);
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedTo).toBe('ghcp-fallback');
expect(getDefaultAccount('ghcp')?.id).toBe('ghcp-fallback');
@@ -868,9 +850,7 @@ describe('Quota Exhaustion Handlers', () => {
}) as typeof fetch;
const result = await handleQuotaExhaustion('ghcp', 'ghcp-partial-exhausted', 10);
const { getAccount, getDefaultAccount } = await import(
'../account-manager'
);
const { getAccount, getDefaultAccount } = await import('../account-manager');
expect(result.switchedTo).toBe('ghcp-partial-fallback');
expect(getDefaultAccount('ghcp')?.id).toBe('ghcp-partial-fallback');
@@ -153,7 +153,10 @@ describe('Codex Reasoning Proxy', () => {
});
it('preserves query strings after stripping', () => {
const result = stripPathPrefix('/api/provider/codex/v1/messages?stream=true', '/api/provider/codex');
const result = stripPathPrefix(
'/api/provider/codex/v1/messages?stream=true',
'/api/provider/codex'
);
assert.strictEqual(result, '/v1/messages?stream=true');
});
@@ -56,8 +56,15 @@ describe('openai-compat manager', () => {
});
const afterWrite = fs.readFileSync(configPath, 'utf8');
assert.strictEqual(afterWrite.split('\n')[0], initialHeader, 'Should preserve the generated header');
assert(afterWrite.includes('openai-compatibility:'), 'Should write the openai-compatibility section');
assert.strictEqual(
afterWrite.split('\n')[0],
initialHeader,
'Should preserve the generated header'
);
assert(
afterWrite.includes('openai-compatibility:'),
'Should write the openai-compatibility section'
);
assert.strictEqual(
configGenerator.configNeedsRegeneration(),
false,
@@ -67,7 +74,10 @@ describe('openai-compat manager', () => {
configGenerator.regenerateConfig();
const afterRegen = fs.readFileSync(configPath, 'utf8');
assert(afterRegen.includes('openai-compatibility:'), 'Connector section should survive regeneration');
assert(
afterRegen.includes('openai-compatibility:'),
'Connector section should survive regeneration'
);
assert(afterRegen.includes('name: mimo'), 'Connector name should survive regeneration');
assert(
afterRegen.includes('base-url: https://api.xiaomimimo.com/v1'),
@@ -71,11 +71,7 @@ describe('Tool Name Mapper', () => {
it('handles mixed valid and invalid names', () => {
const mapper = new ToolNameMapper();
const tools = [
{ name: 'valid_tool' },
{ name: 'foo__bar__bar' },
{ name: 'another_valid' },
];
const tools = [{ name: 'valid_tool' }, { name: 'foo__bar__bar' }, { name: 'another_valid' }];
const result = mapper.registerTools(tools);
@@ -92,9 +88,7 @@ describe('Tool Name Mapper', () => {
const mapper = new ToolNameMapper();
mapper.registerTools([{ name: 'foo__bar__bar' }]);
const content = [
{ type: 'tool_use', id: 'call_1', name: 'foo__bar', input: {} },
];
const content = [{ type: 'tool_use', id: 'call_1', name: 'foo__bar', input: {} }];
const result = mapper.restoreToolUse(content);
@@ -121,9 +115,7 @@ describe('Tool Name Mapper', () => {
const mapper = new ToolNameMapper();
mapper.registerTools([{ name: 'foo__bar__bar' }]);
const content = [
{ type: 'tool_use', id: 'call_1', name: 'unknown_tool', input: {} },
];
const content = [{ type: 'tool_use', id: 'call_1', name: 'unknown_tool', input: {} }];
const result = mapper.restoreToolUse(content);
@@ -196,10 +188,7 @@ describe('Tool Name Mapper', () => {
it('returns list of all changes', () => {
const mapper = new ToolNameMapper();
mapper.registerTools([
{ name: 'foo__bar__bar' },
{ name: 'baz__qux__qux' },
]);
mapper.registerTools([{ name: 'foo__bar__bar' }, { name: 'baz__qux__qux' }]);
const changes = mapper.getChanges();
@@ -1,5 +1,9 @@
import { getManagedModelPrefix } from '../../shared/cliproxy-model-routing';
import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver';
import {
buildManagementHeaders,
buildProxyUrl,
getProxyTarget,
} from '../proxy/proxy-target-resolver';
import { mapExternalProviderName } from '../provider-capabilities';
import type { CLIProxyProvider } from '../types';
@@ -5,11 +5,7 @@
*/
import { describe, it, expect } from 'bun:test';
import {
getTokenExpiryTimestamp,
isTokenExpired,
sanitizeEmail,
} from '../../auth/auth-utils';
import { getTokenExpiryTimestamp, isTokenExpired, sanitizeEmail } from '../../auth/auth-utils';
describe('Auth Utilities', () => {
describe('sanitizeEmail', () => {
@@ -148,11 +148,9 @@ describe('findNewTokenSnapshotForManualAuth', () => {
const newFile = path.join(tokenDir, 'kiro-new.json');
fs.writeFileSync(newFile, JSON.stringify({ type: 'kiro', email: 'new@example.com' }));
const snapshot = findNewTokenSnapshotForManualAuth(
'kiro',
tokenDir,
[{ file: 'kiro-existing.json', mtimeMs: existingMtimeMs }]
);
const snapshot = findNewTokenSnapshotForManualAuth('kiro', tokenDir, [
{ file: 'kiro-existing.json', mtimeMs: existingMtimeMs },
]);
expect(snapshot?.file).toBe('kiro-new.json');
fs.rmSync(tokenDir, { recursive: true, force: true });
@@ -168,7 +166,10 @@ describe('findNewTokenSnapshotForManualAuth', () => {
`../oauth-handler?manual-auth-updated-token=${Date.now()}`
);
fs.writeFileSync(tokenFile, JSON.stringify({ type: 'kiro', email: 'existing@example.com', refreshed: true }));
fs.writeFileSync(
tokenFile,
JSON.stringify({ type: 'kiro', email: 'existing@example.com', refreshed: true })
);
const bumpedTime = new Date(existingMtimeMs + 10_000);
fs.utimesSync(tokenFile, bumpedTime, bumpedTime);
@@ -231,7 +232,9 @@ describe('getCliAuthNicknameError', () => {
];
expect(getCliAuthNicknameError('kiro', 'work', existingAccounts, 'github-ABC123')).toBeNull();
expect(getCliAuthNicknameError('kiro', 'github-ABC123', existingAccounts, 'github-ABC123')).toBeNull();
expect(
getCliAuthNicknameError('kiro', 'github-ABC123', existingAccounts, 'github-ABC123')
).toBeNull();
});
});
+1 -6
View File
@@ -43,12 +43,7 @@ export {
} from '.';
// Re-export environment detection functions
export {
isHeadlessEnvironment,
killProcessOnPort,
getTimeoutTroubleshooting,
showStep,
} from '.';
export { isHeadlessEnvironment, killProcessOnPort, getTimeoutTroubleshooting, showStep } from '.';
// Re-export OAuth handling functions
export { triggerOAuth, ensureAuth } from '.';
@@ -48,8 +48,7 @@ describe('deleteBinary ETXTBSY guard', () => {
// We can't reliably trigger ETXTBSY in tests (need a running Go binary),
// so we verify the code structure matches the expected behavior.
const err = Object.assign(new Error('ETXTBSY: text file busy'), { code: 'ETXTBSY' });
const code =
err instanceof Error && 'code' in err ? (err as { code: string }).code : '';
const code = err instanceof Error && 'code' in err ? (err as { code: string }).code : '';
expect(code).toBe('ETXTBSY');
// The guard only catches ETXTBSY, not EBUSY
expect(code === 'ETXTBSY').toBe(true);
@@ -59,8 +58,7 @@ describe('deleteBinary ETXTBSY guard', () => {
it('EBUSY is not treated as "binary in use"', () => {
// Verify that EBUSY (Windows mount/directory) is distinguished from ETXTBSY
const err = Object.assign(new Error('EBUSY: resource busy'), { code: 'EBUSY' });
const code =
err instanceof Error && 'code' in err ? (err as { code: string }).code : '';
const code = err instanceof Error && 'code' in err ? (err as { code: string }).code : '';
expect(code).toBe('EBUSY');
expect(code === 'ETXTBSY').toBe(false);
});
@@ -52,9 +52,7 @@ describe('installCliproxyVersion', () => {
});
it('returns plus and emits an informational notice when plus backend is resolved locally', async () => {
const binaryManager = await import(
`../../binary-manager?binary-manager-warning=${Date.now()}`
);
const binaryManager = await import(`../../binary-manager?binary-manager-warning=${Date.now()}`);
const writes: string[] = [];
const originalWrite = process.stderr.write.bind(process.stderr);
@@ -146,9 +144,7 @@ describe('installCliproxyVersion', () => {
ensureBinary: 0,
};
const binaryManager = await import(
`../../binary-manager?binary-manager-install=${Date.now()}`
);
const binaryManager = await import(`../../binary-manager?binary-manager-install=${Date.now()}`);
await binaryManager.installCliproxyVersion('6.7.1', false, 'plus', {
createManager: () => ({
@@ -181,9 +177,7 @@ describe('installCliproxyVersion', () => {
});
it('fails fast when runtime startup forbids installing a missing binary', async () => {
const binaryManager = await import(
`../../binary-manager?binary-manager-runtime=${Date.now()}`
);
const binaryManager = await import(`../../binary-manager?binary-manager-runtime=${Date.now()}`);
await expect(
binaryManager.ensureCLIProxyBinary(false, {
@@ -28,10 +28,7 @@ describe('version-checker stale cache fallback', () => {
});
it('uses a stale latest-version cache when GitHub lookup fails', async () => {
const {
getVersionCachePath,
writeInstalledVersion,
} = await import('../version-cache');
const { getVersionCachePath, writeInstalledVersion } = await import('../version-cache');
const { VERSION_CACHE_DURATION_MS } = await import('../types');
const { checkForUpdates } = await import('../version-checker');
const plusBinDir = path.join(tempHome, '.ccs', 'cliproxy', 'bin', 'plus');
+5 -1
View File
@@ -6,7 +6,11 @@
import * as fs from 'fs';
import * as path from 'path';
import * as zlib from 'zlib';
import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../binary/platform-detector';
import {
getExecutableName,
getArchiveBinaryName,
DEFAULT_BACKEND,
} from '../binary/platform-detector';
import type { CLIProxyBackend } from '../types';
/**
+5 -1
View File
@@ -6,7 +6,11 @@
import * as fs from 'fs';
import * as path from 'path';
import * as zlib from 'zlib';
import { getExecutableName, getArchiveBinaryName, DEFAULT_BACKEND } from '../binary/platform-detector';
import {
getExecutableName,
getArchiveBinaryName,
DEFAULT_BACKEND,
} from '../binary/platform-detector';
import type { CLIProxyBackend } from '../types';
/**
@@ -44,7 +44,9 @@ describe('Default Port Sync', () => {
});
test('Device code providers are synced between backend and UI', () => {
expect(sorted(UI_DEVICE_CODE_PROVIDERS)).toEqual(sorted(getProvidersByOAuthFlow('device_code')));
expect(sorted(UI_DEVICE_CODE_PROVIDERS)).toEqual(
sorted(getProvidersByOAuthFlow('device_code'))
);
});
test('plus-extra providers are synced between backend and UI', () => {
@@ -60,13 +62,17 @@ describe('Default Port Sync', () => {
test('Provider display names are synced between backend and UI', () => {
for (const provider of BACKEND_CLIPROXY_PROVIDER_IDS) {
expect(UI_PROVIDER_METADATA[provider].displayName).toBe(getBackendProviderDisplayName(provider));
expect(UI_PROVIDER_METADATA[provider].displayName).toBe(
getBackendProviderDisplayName(provider)
);
}
});
test('Provider descriptions are synced between backend and UI', () => {
for (const provider of BACKEND_CLIPROXY_PROVIDER_IDS) {
expect(UI_PROVIDER_METADATA[provider].description).toBe(getBackendProviderDescription(provider));
expect(UI_PROVIDER_METADATA[provider].description).toBe(
getBackendProviderDescription(provider)
);
}
});
});
@@ -77,8 +77,15 @@ describe('Config Generator Port', function () {
it('returns config.yaml for default port (8317)', function () {
const configPath = getConfigPathForPort(CLIPROXY_DEFAULT_PORT);
const filename = path.basename(configPath);
assert.ok(configPath.endsWith('config.yaml'), `Expected path to end with config.yaml but got: ${configPath}`);
assert.strictEqual(filename, 'config.yaml', `Expected filename to be config.yaml but got: ${filename}`);
assert.ok(
configPath.endsWith('config.yaml'),
`Expected path to end with config.yaml but got: ${configPath}`
);
assert.strictEqual(
filename,
'config.yaml',
`Expected filename to be config.yaml but got: ${filename}`
);
});
it('returns config-{port}.yaml for variant ports', function () {
@@ -473,7 +473,10 @@ openai-compatibility:
const newConfig = fs.readFileSync(path.join(cliproxyDir, 'config.yaml'), 'utf-8');
assert(newConfig.includes('openai-compatibility:'), 'Should preserve openai-compatibility');
assert(newConfig.includes('name: mimo'), 'Should preserve connector name');
assert(newConfig.includes('base-url: https://api.xiaomimimo.com/v1'), 'Should preserve base URL');
assert(
newConfig.includes('base-url: https://api.xiaomimimo.com/v1'),
'Should preserve base URL'
);
assert(newConfig.includes('alias: mimo-v2-flash'), 'Should preserve model aliases');
});
@@ -2,10 +2,7 @@ import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import {
ensureProviderSettings,
getEffectiveEnvVars,
} from '../env-builder';
import { ensureProviderSettings, getEffectiveEnvVars } from '../env-builder';
interface EnvSettings {
ANTHROPIC_BASE_URL: string;
@@ -5,11 +5,7 @@
*/
import { describe, it, expect } from 'bun:test';
import {
isProviderError,
detectFailedTier,
PROVIDER_ERROR_PATTERNS,
} from '../retry-handler';
import { isProviderError, detectFailedTier, PROVIDER_ERROR_PATTERNS } from '../retry-handler';
import { applyFallback } from '../env-resolver';
import { CompositeTierConfig } from '../../../config/unified-config-types';
@@ -6,10 +6,7 @@ import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import {
createCompositeVariant,
updateCompositeVariant,
} from '../../services/variant-service';
import { createCompositeVariant, updateCompositeVariant } from '../../services/variant-service';
import {
saveCompositeVariantUnified,
listVariantsFromConfig,
@@ -2,10 +2,7 @@ import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { afterEach, describe, expect, it } from 'bun:test';
import {
buildClaudeEnvironment,
resolveCliproxyImageAnalysisEnv,
} from '../env-resolver';
import { buildClaudeEnvironment, resolveCliproxyImageAnalysisEnv } from '../env-resolver';
import type { ImageAnalysisStatus } from '../../../utils/hooks';
const tempDirs: string[] = [];
@@ -2,15 +2,16 @@ import { afterEach, beforeEach, describe, expect, it, jest } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import {
execClaudeWithCLIProxy,
hasGitLabTokenLoginFlag,
readOptionValue,
} from '../index';
import { execClaudeWithCLIProxy, hasGitLabTokenLoginFlag, readOptionValue } from '../index';
describe('readOptionValue', () => {
it('parses split-token option values', () => {
expect(readOptionValue(['--kiro-idc-start-url', 'https://d-123.awsapps.com/start'], '--kiro-idc-start-url')).toEqual({
expect(
readOptionValue(
['--kiro-idc-start-url', 'https://d-123.awsapps.com/start'],
'--kiro-idc-start-url'
)
).toEqual({
present: true,
value: 'https://d-123.awsapps.com/start',
missingValue: false,
@@ -78,7 +79,9 @@ describe('execClaudeWithCLIProxy browser flag validation', () => {
await execClaudeWithCLIProxy(fakeClaudePath, 'gemini', ['--browser', '--no-browser'], {});
expect(exitSpy).toHaveBeenCalledWith(1);
expect(errorSpy).toHaveBeenCalledWith('[X] Use either `--browser` or `--no-browser`, not both.');
expect(errorSpy).toHaveBeenCalledWith(
'[X] Use either `--browser` or `--no-browser`, not both.'
);
} finally {
exitSpy.mockRestore();
errorSpy.mockRestore();
@@ -164,10 +164,7 @@ describe('Variant Port Allocation', function () {
assert.fail('Should have thrown error');
} catch (err) {
assert.ok(err.message.includes('100/100'), 'Should include variant count');
assert.ok(
err.message.includes('ccs cliproxy remove'),
'Should include recovery hint'
);
assert.ok(err.message.includes('ccs cliproxy remove'), 'Should include recovery hint');
}
});
});
+4 -1
View File
@@ -32,7 +32,10 @@ import { stripBrowserEnv, stripClaudeCodeEnv } from '../../utils/shell-executor'
import { CodexReasoningProxy } from '../ai-providers/codex-reasoning-proxy';
import { ToolSanitizationProxy } from '../proxy/tool-sanitization-proxy';
import { HttpsTunnelProxy } from '../proxy/https-tunnel-proxy';
import { MODEL_ENV_VAR_KEYS, normalizeModelIdForProvider } from '../ai-providers/model-id-normalizer';
import {
MODEL_ENV_VAR_KEYS,
normalizeModelIdForProvider,
} from '../ai-providers/model-id-normalizer';
import type { ProxyTarget } from '../proxy/proxy-target-resolver';
import { getEffectiveApiKey } from '../auth/auth-token-manager';
import { isSettings, type Settings } from '../../types/config';
+5 -1
View File
@@ -18,7 +18,11 @@ import {
unregisterSession,
stopProxy,
} from '../session-tracker';
import { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from '../proxy/proxy-detector';
import {
detectRunningProxy,
waitForProxyHealthy,
reclaimOrphanedProxy,
} from '../proxy/proxy-detector';
import { withStartupLock } from '../services/startup-lock';
import { killProcessOnPort } from '../../utils/platform-commands';
import { stopQuotaMonitor } from '../quota/quota-manager';
+16 -3
View File
@@ -108,7 +108,11 @@ export {
} from './ai-providers/codex-plan-compatibility';
// Executor
export { execClaudeWithCLIProxy, isPortAvailable, findAvailablePort } from './executor/cliproxy-executor';
export {
execClaudeWithCLIProxy,
isPortAvailable,
findAvailablePort,
} from './executor/cliproxy-executor';
// Authentication
export type { AuthStatus } from './auth/auth-handler';
@@ -167,7 +171,11 @@ export { ensureCliproxyService, stopCliproxyService, getServiceStatus } from './
// Proxy detector (unified detection with multiple fallbacks)
export type { ProxyStatus, DetectionMethod } from './proxy/proxy-detector';
export { detectRunningProxy, waitForProxyHealthy, reclaimOrphanedProxy } from './proxy/proxy-detector';
export {
detectRunningProxy,
waitForProxyHealthy,
reclaimOrphanedProxy,
} from './proxy/proxy-detector';
// Startup lock (prevents race conditions between CCS processes)
export type { LockResult } from './services/startup-lock';
@@ -246,7 +254,12 @@ export {
GEMINI_MAX_TOOL_NAME_LENGTH,
} from './ai-providers/tool-name-sanitizer';
export type { Tool, ToolUseBlock, ContentBlock, SanitizationChange } from './ai-providers/tool-name-mapper';
export type {
Tool,
ToolUseBlock,
ContentBlock,
SanitizationChange,
} from './ai-providers/tool-name-mapper';
export { ToolNameMapper } from './ai-providers/tool-name-mapper';
export type { ToolSanitizationProxyConfig } from './proxy/tool-sanitization-proxy';
@@ -32,9 +32,7 @@ describe('Antigravity quota failure metadata', () => {
it('preserves entitlement evidence when project lookup fails before quota fetch', async () => {
const moduleId = Date.now() + Math.random();
const { fetchAccountQuota } = await import(`../../quota-fetcher?agy-early=${moduleId}`);
const { getProviderAuthDir } = await import(
`../../config-generator?agy-config=${moduleId}`
);
const { getProviderAuthDir } = await import(`../../config-generator?agy-config=${moduleId}`);
const fs = await import('node:fs');
const os = await import('node:os');
const path = await import('node:path');
@@ -88,9 +86,7 @@ describe('Antigravity quota failure metadata', () => {
const { fetchAccountQuota } = await import(
`../../quota-fetcher?agy-invalid-project=${moduleId}`
);
const { getProviderAuthDir } = await import(
`../../config-generator?agy-config=${moduleId}`
);
const { getProviderAuthDir } = await import(`../../config-generator?agy-config=${moduleId}`);
const fs = await import('node:fs');
const os = await import('node:os');
const path = await import('node:path');
@@ -144,9 +140,7 @@ describe('Antigravity quota failure metadata', () => {
const { fetchAccountQuota } = await import(
`../../quota-fetcher?agy-invalid-models=${moduleId}`
);
const { getProviderAuthDir } = await import(
`../../config-generator?agy-config=${moduleId}`
);
const { getProviderAuthDir } = await import(`../../config-generator?agy-config=${moduleId}`);
const fs = await import('node:fs');
const os = await import('node:os');
const path = await import('node:path');
@@ -516,13 +516,17 @@ describe('Codex Quota Fetcher', () => {
accountId = `workspace-${email}`,
tokenFile?: string
): void {
createCodexAccount(email, {
access_token: 'test-token',
account_id: accountId,
expired: '2099-01-01T00:00:00.000Z',
createCodexAccount(
email,
type: 'codex',
}, tokenFile);
{
access_token: 'test-token',
account_id: accountId,
expired: '2099-01-01T00:00:00.000Z',
email,
type: 'codex',
},
tokenFile
);
}
it('maps deactivated workspace 402 responses to structured metadata', async () => {
@@ -573,11 +577,7 @@ describe('Codex Quota Fetcher', () => {
'codex-kaidu.kd@gmail.com-free.json'
);
registerAccount(
'codex',
'codex-04a0f049-kaidu.kd@gmail.com-team.json',
'kaidu.kd@gmail.com'
);
registerAccount('codex', 'codex-04a0f049-kaidu.kd@gmail.com-team.json', 'kaidu.kd@gmail.com');
const freeAccount = registerAccount(
'codex',
'codex-kaidu.kd@gmail.com-free.json',
@@ -611,16 +611,8 @@ describe('Codex Quota Fetcher', () => {
});
it('does not guess a duplicate-email Codex auth file when the registry entry is missing', async () => {
createValidCodexAccount(
'kaidu.kd@gmail.com',
'workspace-team',
'codex-legacy-slot-a.json'
);
createValidCodexAccount(
'kaidu.kd@gmail.com',
'workspace-free',
'codex-legacy-slot-b.json'
);
createValidCodexAccount('kaidu.kd@gmail.com', 'workspace-team', 'codex-legacy-slot-a.json');
createValidCodexAccount('kaidu.kd@gmail.com', 'workspace-free', 'codex-legacy-slot-b.json');
const fetchSpy = mock(() =>
Promise.resolve(
@@ -66,9 +66,7 @@ describe('Gemini CLI Quota Fetcher', () => {
fetchGeminiCliQuota,
resolveGeminiCliProjectId,
__testExports: geminiTestExports,
} = await import(
`../quota-fetcher-gemini-cli?gemini-quota-fetcher=${moduleVersion}`
));
} = await import(`../quota-fetcher-gemini-cli?gemini-quota-fetcher=${moduleVersion}`));
({ getProviderAuthDir } = configGenerator);
});
@@ -1000,5 +998,4 @@ describe('Gemini CLI Quota Fetcher', () => {
).toContain('project');
});
});
});
@@ -11,11 +11,7 @@ import { describe, it, expect, beforeEach, afterEach } from 'bun:test';
import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import {
startQuotaMonitor,
stopQuotaMonitor,
clearQuotaCache,
} from '../quota-manager';
import { startQuotaMonitor, stopQuotaMonitor, clearQuotaCache } from '../quota-manager';
import { __testExports as executorTestExports } from '../../executor';
// Setup test isolation
@@ -15,7 +15,11 @@ import {
type GeminiCliParsedBucket,
} from './gemini-cli-quota-normalizer';
import { mapExternalProviderName } from '../provider-capabilities';
import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver';
import {
buildManagementHeaders,
buildProxyUrl,
getProxyTarget,
} from '../proxy/proxy-target-resolver';
import type { GeminiCliQuotaResult, GeminiCliBucket } from './quota-types';
import {
buildProviderEntitlementEvidence,
+5 -1
View File
@@ -23,7 +23,11 @@ import {
normalizeProviderTierId,
} from '../auth/provider-entitlement-evidence';
import type { ProviderEntitlementEvidence } from '../auth/provider-entitlement-types';
import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver';
import {
buildManagementHeaders,
buildProxyUrl,
getProxyTarget,
} from '../proxy/proxy-target-resolver';
/** Individual model quota info */
export interface ModelQuota {
@@ -2,9 +2,9 @@ import { describe, expect, it } from 'bun:test';
import type { ProxyTarget } from '../../proxy/proxy-target-resolver';
async function loadRoutingHttpModule() {
return import(
`../routing-strategy-http?test=${Date.now()}-${Math.random()}`
) as Promise<typeof import('../routing-strategy-http')>;
return import(`../routing-strategy-http?test=${Date.now()}-${Math.random()}`) as Promise<
typeof import('../routing-strategy-http')
>;
}
describe('routing-strategy-http', () => {
@@ -23,9 +23,7 @@ function createDetail(overrides: Partial<CliproxyRequestDetail> = {}): CliproxyR
};
}
function createInternallyBucketedUsage(
details: CliproxyRequestDetail[]
): CliproxyUsageApiResponse {
function createInternallyBucketedUsage(details: CliproxyRequestDetail[]): CliproxyUsageApiResponse {
return {
usage: {
total_requests: details.length,
@@ -225,7 +223,9 @@ describe('buildCliproxyStatsFromUsageResponse', () => {
{ label: 'empty authFiles', authFiles: [] },
{
label: 'missing auth_index match',
authFiles: [{ auth_index: 'other-auth-index', provider: 'codex', email: 'shared@example.com' }],
authFiles: [
{ auth_index: 'other-auth-index', provider: 'codex', email: 'shared@example.com' },
],
},
{
label: 'matching auth_index without provider metadata',
@@ -236,7 +236,10 @@ describe('buildCliproxyStatsFromUsageResponse', () => {
for (const scenario of scenarios) {
const stats = buildCliproxyStatsFromUsageResponse(usage, { authFiles: scenario.authFiles });
expect(stats.accountStats['ccs-internal-managed:shared@example.com'], scenario.label).toMatchObject({
expect(
stats.accountStats['ccs-internal-managed:shared@example.com'],
scenario.label
).toMatchObject({
provider: 'ccs-internal-managed',
source: 'shared@example.com',
successCount: 1,
@@ -280,7 +283,9 @@ describe('buildCliproxyStatsFromUsageResponse', () => {
successCount: 1,
failureCount: 0,
});
expect(stats.accountStats['ccs-internal-managed:providerless-fallback@example.com']).toMatchObject({
expect(
stats.accountStats['ccs-internal-managed:providerless-fallback@example.com']
).toMatchObject({
provider: 'ccs-internal-managed',
source: 'providerless-fallback@example.com',
successCount: 0,
@@ -6,10 +6,7 @@ import * as fs from 'fs';
import * as os from 'os';
import * as path from 'path';
import { afterEach, beforeEach, describe, expect, it } from 'bun:test';
import {
updateVariant,
validateProviderBackend,
} from '../variant-service';
import { updateVariant, validateProviderBackend } from '../variant-service';
import { loadOrCreateUnifiedConfig } from '../../../config/unified-config-loader';
describe('updateVariant - provider/model consistency', () => {
@@ -84,7 +81,10 @@ cliproxy:
function setConfiguredBackend(backend: 'original' | 'plus'): void {
const configPath = path.join(tmpDir, 'config.yaml');
const current = fs.readFileSync(configPath, 'utf-8');
fs.writeFileSync(configPath, current.replace(/backend: (original|plus)/, `backend: ${backend}`));
fs.writeFileSync(
configPath,
current.replace(/backend: (original|plus)/, `backend: ${backend}`)
);
}
it('rejects provider change without model update', () => {
+5 -1
View File
@@ -10,7 +10,11 @@ import type {
RemoteThinkingSupport,
} from '../management/management-api-types';
import { getDeniedModelIdReasonForProvider } from '../ai-providers/model-id-normalizer';
import { buildManagementHeaders, buildProxyUrl, getProxyTarget } from '../proxy/proxy-target-resolver';
import {
buildManagementHeaders,
buildProxyUrl,
getProxyTarget,
} from '../proxy/proxy-target-resolver';
const CACHE_FILE_NAME = 'model-catalog-cache.json';
const CACHE_TTL_MS = 24 * 60 * 60 * 1000; // 24 hours
@@ -48,9 +48,14 @@ describe('types.ts backward compatibility', () => {
it('exports all binary types', () => {
const cfg: BinaryManagerConfig = {
version: '1.0.0', releaseUrl: '', binPath: '/tmp',
maxRetries: 3, verbose: false, forceVersion: false,
skipAutoUpdate: false, allowInstall: true,
version: '1.0.0',
releaseUrl: '',
binPath: '/tmp',
maxRetries: 3,
verbose: false,
forceVersion: false,
skipAutoUpdate: false,
allowInstall: true,
};
expect(cfg.version).toBe('1.0.0');
const progress: DownloadProgress = { total: 100, downloaded: 50, percentage: 50 };
@@ -1,10 +1,17 @@
import { getAuthStatus, initializeAccounts, type AuthStatus } from '../../cliproxy/auth/auth-handler';
import {
getAuthStatus,
initializeAccounts,
type AuthStatus,
} from '../../cliproxy/auth/auth-handler';
import {
checkRemoteProxy,
type RemoteProxyClientConfig,
type RemoteProxyStatus,
} from '../../cliproxy/services/remote-proxy-client';
import { fetchRemoteAuthStatus, type RemoteAuthStatus } from '../../cliproxy/services/remote-auth-fetcher';
import {
fetchRemoteAuthStatus,
type RemoteAuthStatus,
} from '../../cliproxy/services/remote-auth-fetcher';
import { getProxyTarget, type ProxyTarget } from '../../cliproxy/proxy/proxy-target-resolver';
import { getProviderDisplayName, isCLIProxyProvider } from '../../cliproxy/provider-capabilities';
import { isCliproxyRunning } from '../../cliproxy/services/stats-fetcher';
@@ -5,7 +5,10 @@
* types compatible with the CCS analytics dashboard.
*/
import type { CliproxyUsageApiResponse, CliproxyRequestDetail } from '../../cliproxy/services/stats-fetcher';
import type {
CliproxyUsageApiResponse,
CliproxyRequestDetail,
} from '../../cliproxy/services/stats-fetcher';
import { calculateCost } from '../model-pricing';
import type { ModelBreakdown, DailyUsage, HourlyUsage, MonthlyUsage } from './types';
import { getModelsUsed, normalizeUsageProvider } from './model-identity';
+2 -1
View File
@@ -56,6 +56,7 @@
"tests",
"lib",
"scripts",
"ui"
"ui",
"src/**/__tests__/**"
]
}
+1 -1
View File
@@ -9,7 +9,7 @@ import type {
ListAiProvidersResult,
UpsertAiProviderEntryInput,
} from '../../../src/cliproxy/ai-providers';
import type { ProviderEntitlementEvidence } from '../../../src/cliproxy/provider-entitlement-types';
import type { ProviderEntitlementEvidence } from '../../../src/cliproxy/auth/provider-entitlement-types';
import type { BrowserRuntimeEnv } from '../../../src/utils/browser/chrome-reuse';
export const API_BASE_URL = '/api';
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"default-ports.d.ts","sourceRoot":"","sources":["default-ports.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,qBAAqB,OAAO,CAAC;AAC1C,eAAO,MAAM,mBAAmB,QAAQ,CAAC"}
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"default-ports.js","sourceRoot":"","sources":["default-ports.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,qBAAqB,GAAG,IAAI,CAAC;AAC7B,QAAA,mBAAmB,GAAG,KAAK,CAAC"}
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"i18n.d.ts","sourceRoot":"","sources":["i18n.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,SAAS,CAAC;AA29T3B,eAAe,IAAI,CAAC"}
File diff suppressed because one or more lines are too long
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["locales.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,kBAAkB,kBAAkB,CAAC;AAElD,eAAO,MAAM,iBAAiB,sCAAuC,CAAC;AAEtE,MAAM,MAAM,SAAS,GAAG,CAAC,OAAO,iBAAiB,CAAC,CAAC,MAAM,CAAC,CAAC;AAE3D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,IAAI,SAAS,CAErE;AAED,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAM5E;AAED,wBAAgB,eAAe,IAAI,SAAS,GAAG,IAAI,CAQlD;AAED,wBAAgB,gBAAgB,IAAI,SAAS,CAK5C;AAED,wBAAgB,mBAAmB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAM3D;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAUvD"}
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"locales.js","sourceRoot":"","sources":["locales.ts"],"names":[],"mappings":";;;AAAa,QAAA,kBAAkB,GAAG,eAAe,CAAC;AAErC,QAAA,iBAAiB,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAU,CAAC;AAItE,SAAgB,iBAAiB,CAAC,MAAc;IAC9C,OAAO,yBAAiB,CAAC,QAAQ,CAAC,MAAmB,CAAC,CAAC;AACzD,CAAC;AAFD,8CAEC;AAED,SAAgB,eAAe,CAAC,MAAiC;IAC/D,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,OAAO,CAAC;IAC1D,IAAI,MAAM,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IACvD,OAAO,IAAI,CAAC;AACd,CAAC;AAND,0CAMC;AAED,SAAgB,eAAe;IAC7B,IAAI,OAAO,MAAM,KAAK,WAAW;QAAE,OAAO,IAAI,CAAC;IAC/C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,0BAAkB,CAAC,CAAC;QAC5D,OAAO,GAAG,CAAC,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AARD,0CAQC;AAED,SAAgB,gBAAgB;IAC9B,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AALD,4CAKC;AAED,SAAgB,mBAAmB,CAAC,MAAe;IACjD,IAAI,MAAM;QAAE,OAAO,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,eAAe,EAAE,CAAC;IACjC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,OAAO,SAAS,KAAK,WAAW;QAAE,OAAO,eAAe,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;IACjF,OAAO,IAAI,CAAC;AACd,CAAC;AAND,kDAMC;AAED,SAAgB,aAAa,CAAC,MAAc;IAC1C,MAAM,UAAU,GAAG,eAAe,CAAC,MAAM,CAAC,CAAC;IAC3C,IAAI,OAAO,MAAM,KAAK,WAAW,EAAE,CAAC;QAClC,IAAI,CAAC;YACH,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,0BAAkB,EAAE,UAAU,CAAC,CAAC;QAC9D,CAAC;QAAC,MAAM,CAAC;YACP,sDAAsD;QACxD,CAAC;IACH,CAAC;IACD,OAAO,UAAU,CAAC;AACpB,CAAC;AAVD,sCAUC"}
+1
View File
@@ -0,0 +1 @@
{"version":3,"file":"provider-config.d.ts","sourceRoot":"","sources":["provider-config.ts"],"names":[],"mappings":"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"}
File diff suppressed because one or more lines are too long