Files
OmniRoute/open-sse/utils/kieTask.ts
backryun 13e15e9cfe refactor(sse): guard the KIE task-id and callback-url reads at their source (#8661)
`kieExecutor.createTask()` returns `JsonObject` (`Record<string, unknown>`), so
`createData.data` is `unknown` and the `createData?.data?.taskId` read that
image, video and music generation each duplicated could not compile. The same
three-line expression appeared verbatim in all three handlers.

`open-sse/utils/kieTask.ts` already holds two helpers with exactly this shape —
`normalizeKieTaskState()` and `parseKieResultJson()` both take `unknown`, guard
with `isJsonObject()` and return a declared type. `getKieTaskId()` follows them,
so the three handlers now share one guarded read instead of three unguarded ones.

`getKieCallbackUrl()` took `KieCallbackBody`, a weak type (all properties
optional). Passing a request body whose declared keys are `prompt` /
`timeout_ms` / `poll_interval_ms` tripped TS2559 "no properties in common" at
both music call sites. It receives arbitrary upstream request bodies, so it now
takes `unknown` and guards the same way its neighbours do; `KieCallbackBody`
had no other reference and is gone.

Behaviour is unchanged. `isJsonObject()` rejects arrays and null exactly where
optional chaining already yielded `undefined`, and the callers' `String(taskId)`
coercion moved inside the helper, so a numeric id still reaches `pollTask()` as
a string and a falsy id still takes the 502 branch.

Fixes 5 of the 208 `tsc -p open-sse/tsconfig.json` diagnostics with no new ones:
3 x TS2339 `taskId` on `unknown`, 2 x TS2559 on `KieCallbackBody`.

Refs #8484
2026-07-27 17:24:09 -03:00

130 lines
3.7 KiB
TypeScript

export type JsonObject = Record<string, unknown>;
export type KieTaskState = "success" | "failed" | "pending";
const FALLBACK_KIE_CALLBACK_URL = "https://omniroute.local/api/kie/callback";
export function isJsonObject(value: unknown): value is JsonObject {
return typeof value === "object" && value !== null && !Array.isArray(value);
}
function callbackUrlFromBaseUrl(baseUrl: string | undefined): string | null {
if (!baseUrl || baseUrl.trim().length === 0) return null;
try {
const url = new URL(baseUrl);
url.pathname = "/api/kie/callback";
url.search = "";
url.hash = "";
return url.toString();
} catch {
return null;
}
}
function getConfiguredKieCallbackUrl(): string {
const explicit =
process.env.KIE_CALLBACK_URL?.trim() || process.env.OMNIROUTE_KIE_CALLBACK_URL?.trim();
if (explicit) return explicit;
return (
callbackUrlFromBaseUrl(process.env.OMNIROUTE_PUBLIC_URL) ||
callbackUrlFromBaseUrl(process.env.NEXT_PUBLIC_APP_URL) ||
callbackUrlFromBaseUrl(process.env.APP_URL) ||
callbackUrlFromBaseUrl(process.env.PUBLIC_URL) ||
FALLBACK_KIE_CALLBACK_URL
);
}
export function getKieCallbackUrl(body: unknown = {}): string {
const record = isJsonObject(body) ? body : {};
const callbackUrl = record.callBackUrl ?? record.callback_url ?? record.callbackUrl;
return typeof callbackUrl === "string" && callbackUrl.trim().length > 0
? callbackUrl
: getConfiguredKieCallbackUrl();
}
export function parseKieResultJson(recordData: unknown): JsonObject {
const data = isJsonObject(recordData) && isJsonObject(recordData.data) ? recordData.data : {};
const resultJson = data.resultJson;
if (typeof resultJson === "string") {
try {
const parsed = JSON.parse(resultJson) as unknown;
return isJsonObject(parsed) ? parsed : {};
} catch {
return {};
}
}
return isJsonObject(resultJson) ? resultJson : {};
}
export function getKieTaskId(createData: unknown): string | null {
const record = isJsonObject(createData) ? createData : {};
const data = isJsonObject(record.data) ? record.data : {};
const taskId = data.taskId || record.taskId;
return taskId ? String(taskId) : null;
}
export function normalizeKieTaskState(recordData: unknown): KieTaskState {
const record = isJsonObject(recordData) ? recordData : {};
const data = isJsonObject(record.data) ? record.data : {};
const state = String(
data.status ?? data.state ?? data.successFlag ?? record.msg ?? "PENDING"
).toUpperCase();
if (
state === "SUCCESS" ||
state === "1" ||
state === "FINISHED" ||
state === "COMPLETE" ||
state === "COMPLETED" ||
state === "FIRST_SUCCESS" ||
state === "ALL_SUCCESS" ||
state.includes("SUCCESS")
) {
return "success";
}
if (
state === "FAIL" ||
state === "FAILED" ||
state === "ERROR" ||
state === "2" ||
state === "3" ||
state.includes("FAIL") ||
state.includes("ERROR") ||
state === "CREATE_TASK_FAILED" ||
state === "GENERATE_FAILED" ||
state === "GENERATE_AUDIO_FAILED"
) {
return "failed";
}
return "pending";
}
export function getKieErrorStatus(error: unknown, fallback = 502): number {
if (isJsonObject(error)) {
const status = Number(error.status);
if (Number.isFinite(status) && status > 0) {
return status;
}
}
return fallback;
}
export function getKieErrorMessage(error: unknown, fallback: string): string {
if (error instanceof Error && error.message) {
return error.message;
}
if (isJsonObject(error) && typeof error.message === "string" && error.message.length > 0) {
return error.message;
}
return typeof error === "string" && error.length > 0 ? error : fallback;
}