refactor: remove deprecated apiKey from site management and update related functionality
- Removed apiKey from SiteRow type and related forms in Sites component. - Updated site saving logic to handle site creation without apiKey. - Adjusted tests to ensure apiKey is not included in site editor state. - Refactored Tokens component to support embedded mode and redirect logic. - Added migration tests for site apiKey to account migration service. - Implemented siteApiKeyMigrationService to handle migration of apiKey to account tokens. - Enhanced tests for segmented connections in Accounts and redirect logic for Tokens.
This commit is contained in:
1 parent
a98a6f2c18
commit
c31bbcbb51
30 files changed
+1960
-592
No files matched your search
@@ -0,0 +1,131 @@
|
||||
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
||||
|
||||
const { fetchMock, fetchJsonWithShieldCookieRetryMock } = vi.hoisted(() => ({
|
||||
fetchMock: vi.fn(),
|
||||
fetchJsonWithShieldCookieRetryMock: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock('undici', () => ({
|
||||
fetch: (...args: unknown[]) => fetchMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock('./platforms/newApiShield.js', () => ({
|
||||
buildNewApiCookieCandidates: () => [],
|
||||
fetchJsonWithShieldCookieRetry: (...args: unknown[]) => fetchJsonWithShieldCookieRetryMock(...args),
|
||||
}));
|
||||
|
||||
vi.mock('./siteProxy.js', () => ({
|
||||
withExplicitProxyRequestInit: (_proxyUrl: string | null | undefined, init: RequestInit) => init,
|
||||
}));
|
||||
|
||||
import {
|
||||
resolveProxyUsageWithSelfLogFallback,
|
||||
shouldLookupSelfLog,
|
||||
} from './proxyUsageFallbackService.js';
|
||||
|
||||
describe('proxyUsageFallbackService sub2api', () => {
|
||||
beforeEach(() => {
|
||||
fetchMock.mockReset();
|
||||
fetchJsonWithShieldCookieRetryMock.mockReset();
|
||||
fetchJsonWithShieldCookieRetryMock.mockResolvedValue({ data: null });
|
||||
});
|
||||
|
||||
it('always enables usage lookup for sub2api to recover exact billing cost', () => {
|
||||
expect(shouldLookupSelfLog('sub2api', {
|
||||
promptTokens: 70354,
|
||||
completionTokens: 1148,
|
||||
totalTokens: 71502,
|
||||
})).toBe(true);
|
||||
});
|
||||
|
||||
it('recovers exact cost from sub2api /api/v1/usage and matches by api key value', async () => {
|
||||
fetchMock.mockResolvedValue(new Response(JSON.stringify({
|
||||
code: 0,
|
||||
message: 'success',
|
||||
data: {
|
||||
items: [
|
||||
{
|
||||
id: 1001,
|
||||
model: 'gpt-5.4',
|
||||
input_tokens: 512,
|
||||
output_tokens: 32,
|
||||
cache_creation_tokens: 0,
|
||||
cache_read_tokens: 0,
|
||||
total_cost: 0.001088,
|
||||
actual_cost: 0.001088,
|
||||
duration_ms: 23000,
|
||||
created_at: '2026-03-07T06:12:30.000Z',
|
||||
api_key: {
|
||||
id: 91,
|
||||
key: 'sk-wrong',
|
||||
name: 'wrong-key',
|
||||
},
|
||||
},
|
||||
{
|
||||
id: 1002,
|
||||
model: 'gpt-5.4',
|
||||
input_tokens: 70354,
|
||||
output_tokens: 1148,
|
||||
cache_creation_tokens: 0,
|
||||
cache_read_tokens: 0,
|
||||
total_cost: 0.143004,
|
||||
actual_cost: 0.143004,
|
||||
duration_ms: 23000,
|
||||
created_at: '2026-03-07T06:12:29.000Z',
|
||||
api_key: {
|
||||
id: 92,
|
||||
key: 'sk-route',
|
||||
name: 'upstream-key-name',
|
||||
},
|
||||
},
|
||||
],
|
||||
total: 2,
|
||||
page: 1,
|
||||
page_size: 20,
|
||||
pages: 1,
|
||||
},
|
||||
}), {
|
||||
status: 200,
|
||||
headers: { 'content-type': 'application/json' },
|
||||
}));
|
||||
|
||||
const result = await resolveProxyUsageWithSelfLogFallback({
|
||||
site: {
|
||||
url: 'https://sub2api.example.com',
|
||||
platform: 'sub2api',
|
||||
},
|
||||
account: {
|
||||
accessToken: 'jwt-access-token',
|
||||
apiToken: 'sk-account-level',
|
||||
},
|
||||
tokenValue: 'sk-route',
|
||||
tokenName: 'local-token-name',
|
||||
modelName: 'gpt-5.4',
|
||||
requestStartedAtMs: Date.parse('2026-03-07T06:12:07.000Z'),
|
||||
requestEndedAtMs: Date.parse('2026-03-07T06:12:30.000Z'),
|
||||
localLatencyMs: 23000,
|
||||
usage: {
|
||||
promptTokens: 0,
|
||||
completionTokens: 0,
|
||||
totalTokens: 0,
|
||||
},
|
||||
});
|
||||
|
||||
expect(fetchMock).toHaveBeenCalledTimes(1);
|
||||
expect(String(fetchMock.mock.calls[0]?.[0] || '')).toContain('/api/v1/usage?');
|
||||
expect(String(fetchMock.mock.calls[0]?.[0] || '')).toContain('model=gpt-5.4');
|
||||
expect(fetchMock.mock.calls[0]?.[1]).toMatchObject({
|
||||
method: 'GET',
|
||||
headers: {
|
||||
Authorization: 'Bearer jwt-access-token',
|
||||
},
|
||||
});
|
||||
expect(result).toMatchObject({
|
||||
promptTokens: 70354,
|
||||
completionTokens: 1148,
|
||||
totalTokens: 71502,
|
||||
recoveredFromSelfLog: true,
|
||||
estimatedCostFromQuota: 0.143004,
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user