feat: add official game audio generation client

This commit is contained in:
2026-09-21 12:17:32 +08:00
parent d222d17500
commit 09e0ce5cf3
28 changed files with 1835 additions and 31 deletions

View File

@@ -4,6 +4,7 @@ import { CodingProjectServiceError } from '../../coding-projects/project-service
import type { HostApiContext } from '../context';
import { parseJsonBody, sendJson } from '../route-utils';
import { CodingProjectPluginServiceError } from '../coding-product-services';
import { GameAudioClientError } from '../../services/game-audio-client';
const PLUGIN_ROUTE = /^\/api\/coding\/plugins\/([^/]+)$/u;
const PLUGIN_ID_PATTERN = /^[a-z][a-z0-9.-]{0,127}$/u;
@@ -96,6 +97,20 @@ export async function handleCodingPluginRoutes(
url: URL,
ctx: HostApiContext,
): Promise<boolean> {
const savedAudio = /^\/api\/coding\/game-audio\/([0-9a-f-]{36})\/outputs\/([0-9])$/u.exec(url.pathname);
if (savedAudio && req.method === 'GET') {
try {
const delivery = ctx.codingProducts?.gameAudio;
if (!delivery) throw new CodingPluginRouteError(503, 'game_audio_unavailable', 'Audio delivery is unavailable');
if (url.search) requestError('Saved audio lookup does not accept query parameters');
sendJson(res, 200, await delivery.readSavedOutput(savedAudio[1], Number(savedAudio[2])));
} catch (error) {
if (error instanceof GameAudioClientError) {
sendJson(res, error.status, { code: error.code, error: error.message });
} else sendError(res, error);
}
return true;
}
if (url.pathname !== '/api/coding/plugins' && !PLUGIN_ROUTE.test(url.pathname)) return false;
const plugins = ctx.codingProducts?.plugins;
if (!plugins) {