补齐runtime story到STDB的兼容桥
This commit is contained in:
@@ -10,10 +10,16 @@ vi.mock('./apiClient', async () => {
|
||||
return {
|
||||
...actual,
|
||||
requestJson: requestJsonMock,
|
||||
getStoredAccessToken: vi.fn(() => ''),
|
||||
getStoredSpacetimeToken: vi.fn(() => ''),
|
||||
};
|
||||
});
|
||||
|
||||
import { AnimationState } from '../types';
|
||||
import {
|
||||
getStoredAccessToken,
|
||||
getStoredSpacetimeToken,
|
||||
} from './apiClient';
|
||||
import {
|
||||
buildStoryMomentFromRuntimeOptions,
|
||||
getRuntimeClientVersion,
|
||||
@@ -32,6 +38,8 @@ describe('runtimeStoryService', () => {
|
||||
beforeEach(() => {
|
||||
requestJsonMock.mockReset();
|
||||
resetRuntimeStoryTransport();
|
||||
vi.mocked(getStoredAccessToken).mockReturnValue('');
|
||||
vi.mocked(getStoredSpacetimeToken).mockReturnValue('');
|
||||
});
|
||||
|
||||
function createMockRuntimeResponse(overrides: Record<string, unknown> = {}) {
|
||||
@@ -110,7 +118,33 @@ describe('runtimeStoryService', () => {
|
||||
}),
|
||||
}),
|
||||
'执行运行时动作失败',
|
||||
expect.any(Object),
|
||||
expect.objectContaining({
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('prefers spacetime token auth headers for runtime story compatibility bridge', async () => {
|
||||
vi.mocked(getStoredAccessToken).mockReturnValue('legacy-http-token');
|
||||
vi.mocked(getStoredSpacetimeToken).mockReturnValue('stdb-token');
|
||||
requestJsonMock.mockResolvedValue(createMockRuntimeResponse());
|
||||
|
||||
await getRuntimeStoryState('runtime-main');
|
||||
|
||||
expect(requestJsonMock).toHaveBeenCalledWith(
|
||||
'/api/runtime/story/state/runtime-main',
|
||||
expect.objectContaining({
|
||||
headers: expect.objectContaining({
|
||||
Authorization: 'Bearer stdb-token',
|
||||
'x-genarrative-runtime-story-auth': 'spacetime-token',
|
||||
}),
|
||||
}),
|
||||
'读取运行时故事状态失败',
|
||||
expect.objectContaining({
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -16,7 +16,12 @@ import type {
|
||||
} from '../persistence/runtimeSnapshotTypes';
|
||||
import type { GameState, StoryMoment, StoryOption } from '../types';
|
||||
import { AnimationState } from '../types';
|
||||
import { type ApiRetryOptions, requestJson } from './apiClient';
|
||||
import {
|
||||
getStoredAccessToken,
|
||||
getStoredSpacetimeToken,
|
||||
type ApiRetryOptions,
|
||||
requestJson,
|
||||
} from './apiClient';
|
||||
|
||||
const RUNTIME_STORY_API_BASE = '/api/runtime/story';
|
||||
const DEFAULT_SESSION_ID = 'runtime-main';
|
||||
@@ -33,6 +38,7 @@ const TASK5_RUNTIME_FUNCTION_ID_SET = new Set<string>(
|
||||
const SERVER_RUNTIME_FUNCTION_ID_SET = new Set<string>([
|
||||
...SERVER_RUNTIME_FUNCTION_IDS,
|
||||
]);
|
||||
const RUNTIME_STORY_STDB_AUTH_HEADER = 'x-genarrative-runtime-story-auth';
|
||||
|
||||
export type RuntimeStoryServiceOptions = {
|
||||
signal?: AbortSignal;
|
||||
@@ -64,6 +70,29 @@ export type RuntimeStoryTransport = {
|
||||
) => Promise<RuntimeStoryResponse>;
|
||||
};
|
||||
|
||||
function withRuntimeStoryAuthHeaders(headers?: HeadersInit) {
|
||||
const nextHeaders =
|
||||
headers instanceof Headers
|
||||
? Object.fromEntries(headers.entries())
|
||||
: Array.isArray(headers)
|
||||
? Object.fromEntries(headers)
|
||||
: { ...(headers ?? {}) };
|
||||
const httpAccessToken = getStoredAccessToken();
|
||||
const spacetimeToken = getStoredSpacetimeToken();
|
||||
const bearerToken = spacetimeToken || httpAccessToken;
|
||||
|
||||
if (bearerToken) {
|
||||
nextHeaders.Authorization = `Bearer ${bearerToken}`;
|
||||
}
|
||||
if (spacetimeToken) {
|
||||
nextHeaders[RUNTIME_STORY_STDB_AUTH_HEADER] = 'spacetime-token';
|
||||
} else if (httpAccessToken) {
|
||||
nextHeaders[RUNTIME_STORY_STDB_AUTH_HEADER] = 'http-access-token';
|
||||
}
|
||||
|
||||
return nextHeaders;
|
||||
}
|
||||
|
||||
function requestRuntimeStoryJson<T>(
|
||||
path: string,
|
||||
init: RequestInit,
|
||||
@@ -75,9 +104,14 @@ function requestRuntimeStoryJson<T>(
|
||||
{
|
||||
...init,
|
||||
signal: options.signal,
|
||||
headers: withRuntimeStoryAuthHeaders(init.headers),
|
||||
},
|
||||
fallbackMessage,
|
||||
{ retry: options.retry ?? RUNTIME_STORY_RETRY },
|
||||
{
|
||||
retry: options.retry ?? RUNTIME_STORY_RETRY,
|
||||
skipAuth: true,
|
||||
skipRefresh: true,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user