Implement platform management features

This commit is contained in:
npc0-hue
2026-08-17 08:48:45 +08:00
parent 65353cf269
commit 302f1f64b7
38 changed files with 2185 additions and 110 deletions
+13 -1
View File
@@ -736,8 +736,18 @@ describe("PlatformApiClient AI providers", () => {
expect(client.serverLogEventsUrl("server-1")).toBe("/api/v1/server-instances/server-1/logs/events");
});
it("scopes explicit terminal history lists to the selected server", async () => {
const fetchMock = vi.fn(async (_input: RequestInfo | URL) => new Response(JSON.stringify({ items: [], count: 0 }), { status: 200, headers: { "Content-Type": "application/json" } }));
vi.stubGlobal("fetch", fetchMock);
const client = new PlatformApiClient("/api/v1", () => "terminal-session");
await expect(client.listLogStreams("server/scum 1")).resolves.toEqual({ items: [], count: 0 });
expect(String(fetchMock.mock.calls[0]?.[0])).toBe("/api/v1/log-streams?serverInstanceId=server%2Fscum%201");
});
it("streams terminal log SSE with bearer authorization and dispatches live events", async () => {
const payload = "event: stream\ndata: {\"id\":\"log-1\",\"serverInstanceId\":\"server-1\"}\n\nevent: log\ndata: {\"streamId\":\"log-1\",\"entry\":{\"seq\":3,\"line\":\"live line\"}}\n\nevent: ready\ndata: {\"serverInstanceId\":\"server-1\"}\n\n";
const payload = "event: session\ndata: {\"serverInstanceId\":\"server-1\",\"logSessionId\":\"session-2\"}\n\nevent: stream\ndata: {\"id\":\"log-1\",\"serverInstanceId\":\"server-1\"}\n\nevent: log\ndata: {\"streamId\":\"log-1\",\"entry\":{\"seq\":3,\"line\":\"live line\"}}\n\nevent: ready\ndata: {\"serverInstanceId\":\"server-1\"}\n\n";
const fetchMock = vi.fn(async (_input: RequestInfo | URL, init?: RequestInit) => {
expect(new Headers(init?.headers).get("Authorization")).toBe("Bearer terminal-session");
expect(new Headers(init?.headers).get("Accept")).toBe("text/event-stream");
@@ -747,11 +757,13 @@ describe("PlatformApiClient AI providers", () => {
const client = new PlatformApiClient("/api/v1", () => "terminal-session");
const events: string[] = [];
const stream = client.openServerLogEvents("server-1", { historyLimit: 2 });
stream.addEventListener("session", (event) => events.push(`session:${event.data}`));
stream.addEventListener("stream", (event) => events.push(`stream:${event.data}`));
stream.addEventListener("log", (event) => events.push(`log:${event.data}`));
stream.addEventListener("ready", (event) => events.push(`ready:${event.data}`));
await vi.waitFor(() => expect(events).toEqual([
'session:{"serverInstanceId":"server-1","logSessionId":"session-2"}',
'stream:{"id":"log-1","serverInstanceId":"server-1"}',
'log:{"streamId":"log-1","entry":{"seq":3,"line":"live line"}}',
'ready:{"serverInstanceId":"server-1"}'
+3 -2
View File
@@ -602,8 +602,9 @@ export class PlatformApiClient {
});
}
async listLogStreams(): Promise<LogStreamListResponse> {
return this.request<LogStreamListResponse>("/log-streams");
async listLogStreams(serverInstanceId?: string): Promise<LogStreamListResponse> {
const query = serverInstanceId ? `?serverInstanceId=${encodeURIComponent(serverInstanceId)}` : "";
return this.request<LogStreamListResponse>(`/log-streams${query}`);
}
openServerLogEvents(id: string, options: LogStreamEventOptions = {}): PlatformEventStream {
+12 -1
View File
@@ -600,7 +600,6 @@ export interface RuntimeBindingResponse {
export interface ServerLifecycleCommandRequest {
expectedConfigVersion: number;
expectedChecksum?: string;
idempotencyKey: string;
}
@@ -1478,6 +1477,8 @@ export interface LogStreamResponse {
serverInstanceId: string;
source: string;
streamKey: string;
logSessionId?: string;
sessionStartedAt?: string;
latestSeq: number;
storageBackend: string;
retentionPolicy: string;
@@ -1517,6 +1518,8 @@ export interface LogStreamEventResponse {
streamId: string;
source: string;
streamKey: string;
logSessionId?: string;
sessionStartedAt?: string;
latestSeq: number;
entry: LogEntryBody;
}
@@ -1527,6 +1530,14 @@ export interface LogStreamEventsReadyResponse {
serverTime: string;
}
export interface LogStreamEventsSessionResponse {
serverInstanceId: string;
logSessionId?: string;
sessionStartedAt?: string;
streamCount: number;
serverTime: string;
}
export interface LogStreamEventOptions {
historyLimit?: number;
}