Enrich external API failure audit metadata
This commit is contained in:
@@ -3,6 +3,7 @@ import {
|
||||
postApiJson,
|
||||
} from '../../editor/shared/editorApiClient';
|
||||
import {
|
||||
appendApiErrorRequestId,
|
||||
fetchJson,
|
||||
parseApiErrorMessage,
|
||||
} from '../../editor/shared/jsonClient';
|
||||
@@ -265,7 +266,10 @@ export async function putCharacterRoleAssetWorkflow(
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
parseApiErrorMessage(responseText, '保存角色资产工坊缓存失败'),
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(responseText, '保存角色资产工坊缓存失败'),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
import { fetchJson, parseApiErrorMessage, saveJsonObject } from './jsonClient';
|
||||
import {
|
||||
appendApiErrorRequestId,
|
||||
fetchJson,
|
||||
parseApiErrorMessage,
|
||||
saveJsonObject,
|
||||
} from './jsonClient';
|
||||
|
||||
export const EDITOR_API_BASE_PATH = '/api/editor';
|
||||
export const ASSETS_API_BASE_PATH = '/api/assets';
|
||||
@@ -69,7 +74,7 @@ export async function postApiJson<T>(
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(appendApiErrorRequestId(parseApiErrorMessage(responseText, fallbackMessage), response.headers.get('x-request-id')));
|
||||
}
|
||||
|
||||
return responseText ? (JSON.parse(responseText) as T) : ({} as T);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
API_RESPONSE_ENVELOPE_HEADER,
|
||||
API_RESPONSE_ENVELOPE_VERSION,
|
||||
appendApiErrorRequestId,
|
||||
parseApiErrorMessage,
|
||||
unwrapApiResponse,
|
||||
} from '../../../packages/shared/src/http';
|
||||
@@ -17,7 +18,15 @@ export async function fetchJson<T>(
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(parseApiErrorMessage(responseText, `${fallbackMessage}: ${response.status}`));
|
||||
throw new Error(
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(
|
||||
responseText,
|
||||
`${fallbackMessage}: ${response.status}`,
|
||||
),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
return responseText
|
||||
@@ -41,8 +50,13 @@ export async function saveJsonObject(
|
||||
const responseText = await response.text();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(responseText, fallbackMessage),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export { parseApiErrorMessage };
|
||||
export { appendApiErrorRequestId, parseApiErrorMessage };
|
||||
|
||||
@@ -14,7 +14,10 @@ import type {
|
||||
GenerateCustomWorldProfileInput,
|
||||
GenerateCustomWorldProfileOptions,
|
||||
} from '../../packages/shared/src/contracts/runtime';
|
||||
import { parseApiErrorMessage } from '../../packages/shared/src/http';
|
||||
import {
|
||||
appendApiErrorRequestId,
|
||||
parseApiErrorMessage,
|
||||
} from '../../packages/shared/src/http';
|
||||
import type {
|
||||
AIResponse,
|
||||
Character,
|
||||
@@ -93,7 +96,12 @@ async function requestPlainTextStream(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, '流式请求失败'));
|
||||
throw new Error(
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(responseText, '流式请求失败'),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
@@ -488,7 +496,12 @@ export async function streamNpcChatTurn(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, 'NPC 聊天续写失败'));
|
||||
throw new Error(
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(responseText, 'NPC 聊天续写失败'),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
|
||||
@@ -547,6 +547,7 @@ describe('apiClient', () => {
|
||||
routeVersion: 'runtime.v2',
|
||||
},
|
||||
});
|
||||
expect((capturedError as Error).message).toContain('requestId: req-body');
|
||||
});
|
||||
|
||||
it('uses api error details.message as ApiClientError message', async () => {
|
||||
|
||||
@@ -671,9 +671,14 @@ async function buildApiClientError(
|
||||
) {
|
||||
const responseText = await response.text();
|
||||
const parsedError = parseApiErrorShape(responseText);
|
||||
const requestId =
|
||||
parsedError?.meta.requestId ??
|
||||
response.headers.get(REQUEST_ID_HEADER) ??
|
||||
undefined;
|
||||
const baseMessage = parseApiErrorMessage(responseText, fallbackMessage);
|
||||
|
||||
return new ApiClientError({
|
||||
message: parseApiErrorMessage(responseText, fallbackMessage),
|
||||
message: requestId ? `${baseMessage}(requestId: ${requestId})` : baseMessage,
|
||||
status: response.status,
|
||||
code: parsedError?.code ?? `HTTP_${response.status || 0}`,
|
||||
details: parsedError?.details ?? null,
|
||||
@@ -682,10 +687,7 @@ async function buildApiClientError(
|
||||
parsedError?.meta.apiVersion ??
|
||||
response.headers.get(API_VERSION_HEADER) ??
|
||||
API_VERSION,
|
||||
requestId:
|
||||
parsedError?.meta.requestId ??
|
||||
response.headers.get(REQUEST_ID_HEADER) ??
|
||||
undefined,
|
||||
requestId,
|
||||
routeVersion:
|
||||
parsedError?.meta.routeVersion ??
|
||||
response.headers.get(ROUTE_VERSION_HEADER) ??
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import { parseApiErrorMessage } from '../../packages/shared/src/http';
|
||||
import {
|
||||
appendApiErrorRequestId,
|
||||
parseApiErrorMessage,
|
||||
} from '../../packages/shared/src/http';
|
||||
import {
|
||||
ApiClientError,
|
||||
BACKGROUND_AUTH_REQUEST_OPTIONS,
|
||||
@@ -338,7 +341,12 @@ export async function readAssetBytes(
|
||||
if (!response.ok) {
|
||||
const message = await response
|
||||
.text()
|
||||
.then((text) => parseApiErrorMessage(text, '读取资源内容失败'))
|
||||
.then((text) =>
|
||||
appendApiErrorRequestId(
|
||||
parseApiErrorMessage(text, '读取资源内容失败'),
|
||||
response.headers.get('x-request-id'),
|
||||
),
|
||||
)
|
||||
.catch(() => '');
|
||||
throw new Error(message || '读取资源内容失败');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import { appendApiErrorRequestId, parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import type { TextStreamOptions } from '../aiTypes';
|
||||
import {
|
||||
type ApiRetryOptions,
|
||||
@@ -64,7 +64,7 @@ async function openCreationAgentSsePost(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(appendApiErrorRequestId(parseApiErrorMessage(responseText, fallbackMessage), response.headers.get('x-request-id')));
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
|
||||
@@ -7,7 +7,7 @@ import type {
|
||||
CreativeDraftEditStreamRequest,
|
||||
StreamCreativeAgentMessageRequest,
|
||||
} from '../../../packages/shared/src/contracts/creativeAgent';
|
||||
import { parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import { appendApiErrorRequestId, parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import type { TextStreamOptions } from '../aiTypes';
|
||||
import { fetchWithApiAuth, requestJson } from '../apiClient';
|
||||
import {
|
||||
@@ -42,7 +42,7 @@ async function openCreativeAgentSsePost(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(appendApiErrorRequestId(parseApiErrorMessage(responseText, fallbackMessage), response.headers.get('x-request-id')));
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import { appendApiErrorRequestId, parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import { fetchWithApiAuth, requestJson } from '../apiClient';
|
||||
|
||||
export async function requestRpgCreationPostJson<T>(
|
||||
@@ -32,7 +32,7 @@ export async function openRpgCreationSsePost(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(appendApiErrorRequestId(parseApiErrorMessage(responseText, fallbackMessage), response.headers.get('x-request-id')));
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
|
||||
@@ -16,7 +16,7 @@ import type {
|
||||
VisualNovelStartRunRequest,
|
||||
VisualNovelWorksResponse,
|
||||
} from '../../../packages/shared/src/contracts/visualNovel';
|
||||
import { parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import { appendApiErrorRequestId, parseApiErrorMessage } from '../../../packages/shared/src/http';
|
||||
import type { TextStreamOptions } from '../aiTypes';
|
||||
import {
|
||||
type ApiRetryOptions,
|
||||
@@ -100,7 +100,7 @@ async function openVisualNovelRuntimeSsePost(
|
||||
|
||||
if (!response.ok) {
|
||||
const responseText = await response.text();
|
||||
throw new Error(parseApiErrorMessage(responseText, fallbackMessage));
|
||||
throw new Error(appendApiErrorRequestId(parseApiErrorMessage(responseText, fallbackMessage), response.headers.get('x-request-id')));
|
||||
}
|
||||
|
||||
if (!response.body) {
|
||||
|
||||
Reference in New Issue
Block a user