Remove legacy client-manager platform path
This commit is contained in:
@@ -241,7 +241,7 @@ export interface RuntimeDiscoveryProbeResponse {
|
||||
|
||||
export interface RuntimeLifecycleProfileResponse {
|
||||
key: string;
|
||||
mode: "local-process" | "hosted-ftp-rcon" | "ftp-only" | "custom-client";
|
||||
mode: "local-process" | "hosted-ftp-rcon" | "ftp-only";
|
||||
capabilities: string[];
|
||||
actionRefs?: Record<string, string>;
|
||||
transportKeys?: string[];
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { PluginBridgeExecuteEnvelope, PluginBridgeExecutionResult } from "./pluginBridge";
|
||||
import type { GameClientBridgeCommandFilterRequest, GameClientBridgeQueueRequest, GameClientBridgeSnapshotQuery } from "../api/types";
|
||||
import type { GameClientBridgeCommandFilterRequest, GameClientBridgeQueueRequest, GameClientBridgeSnapshotQuery, LogStreamCursorRequest, LogStreamCursorResponse, LogStreamListResponse } from "../api/types";
|
||||
|
||||
export interface PluginDataMutation {
|
||||
operation: "put" | "delete";
|
||||
@@ -20,5 +20,9 @@ export interface PluginPageWorkspaceActions {
|
||||
list: (filter?: GameClientBridgeCommandFilterRequest) => Promise<unknown>;
|
||||
snapshots: (query?: GameClientBridgeSnapshotQuery) => Promise<unknown>;
|
||||
};
|
||||
logs?: {
|
||||
listStreams: () => Promise<LogStreamListResponse>;
|
||||
query: (request: LogStreamCursorRequest) => Promise<LogStreamCursorResponse>;
|
||||
};
|
||||
dispatch?: (envelope: PluginBridgeExecuteEnvelope, signal?: AbortSignal) => Promise<PluginBridgeExecutionResult>;
|
||||
}
|
||||
|
||||
@@ -21,9 +21,11 @@ const apiMocks = vi.hoisted(() => ({
|
||||
listGameClientBridgeCommands: vi.fn(),
|
||||
listGameClientBridgeSnapshots: vi.fn(),
|
||||
listGamePlugins: vi.fn(),
|
||||
listLogStreams: vi.fn(),
|
||||
listPluginData: vi.fn(),
|
||||
putPluginData: vi.fn(),
|
||||
queueGameClientBridgeCommand: vi.fn(),
|
||||
queryLogStream: vi.fn(),
|
||||
transactPluginData: vi.fn()
|
||||
}));
|
||||
|
||||
@@ -53,7 +55,7 @@ const plugin: GamePluginResponse = {
|
||||
manifestRef: "artifact://manifests/game.scum/1.0.0",
|
||||
createFormSchemaRef: "schemas/create-form.schema.json",
|
||||
requiredRunCapabilities: [],
|
||||
declaredPermissions: ["server.read", "server.game-client.read", "server.game-client.command"],
|
||||
declaredPermissions: ["server.read", "server.logs.read", "server.game-client.read", "server.game-client.command"],
|
||||
permissions: { ai: true, logs: false, files: false, jobs: true, artifacts: false, remoteAccess: false },
|
||||
lifecycleActions: {},
|
||||
bridgeActions: ["server.instances.read"],
|
||||
@@ -64,7 +66,7 @@ const plugin: GamePluginResponse = {
|
||||
bundleKey: "scum-server-plugin",
|
||||
bundleVersion: "1.0.3",
|
||||
bundleIntegritySha256: "sha256:3488b316d909e597024f8f31c7bc96ab8019f643d74a528dc442d3df0dc3d54e",
|
||||
permissions: ["server.read", "server.game-client.read", "server.game-client.command"],
|
||||
permissions: ["server.read", "server.logs.read", "server.game-client.read", "server.game-client.command"],
|
||||
bridgeActions: ["server.instances.read"]
|
||||
}],
|
||||
tags: ["scum"],
|
||||
@@ -97,6 +99,8 @@ beforeEach(() => {
|
||||
apiMocks.getGameClientBridgeCommand.mockResolvedValue({ id: "command-1" });
|
||||
apiMocks.listGameClientBridgeCommands.mockResolvedValue({ items: [], count: 0 });
|
||||
apiMocks.listGameClientBridgeSnapshots.mockResolvedValue({ items: [], count: 0 });
|
||||
apiMocks.listLogStreams.mockResolvedValue({ items: [{ id: "stream-login", serverInstanceId: "server-1", source: "file", streamKey: "scum.login", latestSeq: 2, storageBackend: "local-segments", retentionPolicy: "default", createdAt: "2026-08-15T12:00:00Z", updatedAt: "2026-08-15T12:00:00Z" }], count: 1 });
|
||||
apiMocks.queryLogStream.mockResolvedValue({ logStreamId: "stream-login", entries: [], nextSeq: 2, latestSeq: 2 });
|
||||
apiMocks.executePluginBridge.mockResolvedValue({ requestId: "request-1", action: "server.instances.read", status: "ok", result: { state: "ready" } });
|
||||
bundleMocks.loadPluginPageBundle.mockResolvedValue(({ workspaceActions }: { workspaceActions?: PluginPageWorkspaceActions }) => {
|
||||
capturedWorkspaceActions = workspaceActions;
|
||||
@@ -186,6 +190,7 @@ describe("PluginPageHostPage", () => {
|
||||
const actions = capturedWorkspaceActions;
|
||||
expect(actions?.pluginData).toBeDefined();
|
||||
expect(actions?.gameClient).toBeDefined();
|
||||
expect(actions?.logs).toBeDefined();
|
||||
expect(actions?.dispatch).toBeDefined();
|
||||
|
||||
const mutations = [
|
||||
@@ -211,6 +216,8 @@ describe("PluginPageHostPage", () => {
|
||||
await actions?.gameClient?.get("command-1");
|
||||
await actions?.gameClient?.list(commandFilter);
|
||||
await actions?.gameClient?.snapshots(snapshotQuery);
|
||||
await actions?.logs?.listStreams();
|
||||
await actions?.logs?.query({ logStreamId: "stream-login", afterSeq: 1, limit: 50 });
|
||||
await expect(actions?.dispatch?.(dispatchEnvelope)).resolves.toMatchObject({ status: "ok", result: { state: "ready" } });
|
||||
|
||||
expect(apiMocks.listPluginData).toHaveBeenCalledWith("server-1", "scum_users", "user-1");
|
||||
@@ -221,6 +228,8 @@ describe("PluginPageHostPage", () => {
|
||||
expect(apiMocks.getGameClientBridgeCommand).toHaveBeenCalledWith("server-1", "command-1");
|
||||
expect(apiMocks.listGameClientBridgeCommands).toHaveBeenCalledWith("server-1", commandFilter);
|
||||
expect(apiMocks.listGameClientBridgeSnapshots).toHaveBeenCalledWith("server-1", snapshotQuery);
|
||||
expect(apiMocks.listLogStreams).toHaveBeenCalledWith("server-1");
|
||||
expect(apiMocks.queryLogStream).toHaveBeenCalledWith({ logStreamId: "stream-login", afterSeq: 1, limit: 50 });
|
||||
expect(apiMocks.executePluginBridge).toHaveBeenCalledWith({
|
||||
requestId: "request-1",
|
||||
pluginId: "game.scum",
|
||||
|
||||
@@ -81,6 +81,18 @@ export function PluginPageHostPage({ params, onNavigate, initialPlugin, embedded
|
||||
list: (filter) => platformApiClient.listGameClientBridgeCommands(serverId, filter),
|
||||
snapshots: (query) => platformApiClient.listGameClientBridgeSnapshots(serverId, query)
|
||||
},
|
||||
logs: {
|
||||
listStreams: () => {
|
||||
const context = hostContextRef.current;
|
||||
if (!serverId || !context?.permissions.includes("server.logs.read")) throw new Error("plugin page is missing server.logs.read");
|
||||
return platformApiClient.listLogStreams(serverId);
|
||||
},
|
||||
query: (request) => {
|
||||
const context = hostContextRef.current;
|
||||
if (!serverId || !context?.permissions.includes("server.logs.read")) throw new Error("plugin page is missing server.logs.read");
|
||||
return platformApiClient.queryLogStream(request);
|
||||
}
|
||||
},
|
||||
dispatch: (envelope, signal) => {
|
||||
const context = hostContextRef.current;
|
||||
if (!context) return Promise.resolve({ requestId: envelope.requestId, action: envelope.action, status: "error", error: { code: "host_unavailable", message: "plugin bridge host is unavailable" } });
|
||||
|
||||
Reference in New Issue
Block a user