feat(dashboard): derive media serviceKinds from registries (surface MiniMax + media catalog) (#4212)

Integrated into release/v3.8.29 (round 7). Media serviceKinds derived from backend registries (single source of truth) unioned with declared kinds; listing + detail pages use the same resolver (no 'listed but 404'). Surfaces MiniMax (tts/video/music) + ~48 previously-invisible media providers. Validated locally: 6/6 tests + typecheck:core clean.
This commit is contained in:
Diego Rodrigues de Sa e Souza
2026-06-18 20:19:00 -03:00
committed by GitHub
parent 12124aaad8
commit cfc2bc707b
4 changed files with 181 additions and 6 deletions

View File

@@ -1,6 +1,7 @@
import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import { AI_PROVIDERS } from "@/shared/constants/providers";
import { resolveProviderServiceKinds } from "@omniroute/open-sse/config/mediaServiceKinds.ts";
import type { MediaKind } from "../../components/mediaKinds";
import { MEDIA_KINDS } from "../../components/mediaKinds";
import MediaProviderPageClient from "./MediaProviderPageClient";
@@ -42,9 +43,14 @@ export default async function MediaProviderDetailPage({ params }: PageProps) {
notFound();
}
// Validate that the provider declares this kind
const serviceKinds = provider.serviceKinds as string[] | undefined;
if (!Array.isArray(serviceKinds) || !serviceKinds.includes(validKind)) {
// Validate that the provider supports this kind — declared serviceKinds unioned
// with the media kinds derived from the backend registries (must mirror the
// listing filter in ../page.tsx, otherwise a listed provider would 404 on click).
const serviceKinds = resolveProviderServiceKinds(
provider.id,
provider.serviceKinds as string[] | undefined
);
if (!serviceKinds.includes(validKind)) {
notFound();
}

View File

@@ -2,6 +2,7 @@ import { notFound } from "next/navigation";
import { getTranslations } from "next-intl/server";
import Link from "next/link";
import { AI_PROVIDERS } from "@/shared/constants/providers";
import { resolveProviderServiceKinds } from "@omniroute/open-sse/config/mediaServiceKinds.ts";
import type { MediaKind } from "../components/mediaKinds";
import { MEDIA_KINDS } from "../components/mediaKinds";
import MediaProviderKindNav from "../components/MediaProviderKindNav";
@@ -28,10 +29,14 @@ export default async function MediaProviderKindPage({ params }: PageProps) {
const validKind = kind as MediaKind;
const t = await getTranslations("media");
// Filter providers that support this kind
// Filter providers that support this kind. Membership is the union of the
// explicitly declared serviceKinds and the media kinds derived from the
// backend registries (audio/video/music/image/embedding) — see
// resolveProviderServiceKinds. This keeps the UI in lockstep with the backend
// without hand-maintaining serviceKinds on every media provider.
const matchingProviders = Object.values(AI_PROVIDERS).filter((p) => {
const serviceKinds = (p as Record<string, unknown>).serviceKinds as string[] | undefined;
return Array.isArray(serviceKinds) && serviceKinds.includes(validKind);
const entry = p as Record<string, unknown> & { id: string; serviceKinds?: string[] };
return resolveProviderServiceKinds(entry.id, entry.serviceKinds).includes(validKind);
});
const kindLabel = t(`kinds.${validKind}`);