Wenchao An 6fe87b65fa
feat(extensions): show package-owned usage in extension details (#8031)
* feat(extensions): show package-owned usage in extension details

* test(extensions): align bookmark checks with detail UI

* fix(extensions): reconcile package documentation and locale fallbacks

* fix(extensions): align discovery locale fallback

* fix(extensions): isolate malformed optional documentation

* docs: keep backend guidance within inherited budget
2026-11-10 18:41:27 +08:00

39 lines
1.2 KiB
TypeScript

import { z } from "zod";
import { fetch } from "@/core/api/fetcher";
import { getBackendBaseURL } from "@/core/config";
import { documentationSchema } from "./documentation";
const contributions = z.array(
z.object({
namespace: z.string(),
viewer_id: z.string().nullable().optional(),
module: z.string().nullable(),
backend_actions: z.array(z.string()).optional(),
model_tools: z.array(z.string()).optional(),
documentation: documentationSchema.optional().catch(undefined),
runtime_only: z.boolean().optional(),
entry: z.string().nullable(),
// Keep unknown transports so the loader can reject only that contribution.
transport: z.string().nullable().optional(),
title: z.string(),
description: z.string(),
settings: z.record(
z.string(),
z.union([z.boolean(), z.number(), z.string()]),
),
}),
);
export const frontendExtensionsQueryKey = ["frontend-extensions"] as const;
export async function fetchFrontendExtensions() {
const response = await fetch(`${getBackendBaseURL()}/api/plugins`, {
cache: "no-store",
});
if (!response.ok)
throw new Error(`Frontend extensions unavailable (${response.status})`);
return contributions.parse(await response.json());
}