assistant/renderer/api.ts

70 lines
2.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import type { AssistantBridge, BrowserStateEvent, RevealEvent, ViewMode, ViewportMessage } from '../electron/shared';
declare global {
interface Window {
assistant?: AssistantBridge;
}
}
// 没有 Electron(在普通浏览器里调试界面)时退回到直接请求后端
const FALLBACK_PORT = 8788;
const FALLBACK_BASE = `http://127.0.0.1:${FALLBACK_PORT}/api`;
async function fetchJson<T>(method: string, path: string, body?: unknown): Promise<T> {
const response = await fetch(FALLBACK_BASE + path, {
method,
headers: { 'Content-Type': 'application/json' },
body: body === undefined ? undefined : JSON.stringify(body),
});
const data = (await response.json().catch(() => ({}))) as Record<string, unknown>;
if (!response.ok) {
const detail = typeof data.detail === 'string' ? data.detail : response.statusText;
throw new Error(detail);
}
return data as T;
}
const noop = (): (() => void) => () => undefined;
const fallback: AssistantBridge = {
get: path => fetchJson('GET', path),
post: (path, body) => fetchJson('POST', path, body ?? {}),
put: (path, body) => fetchJson('PUT', path, body ?? {}),
del: path => fetchJson('DELETE', path),
openPath: async () => '当前为浏览器预览,请在桌面端打开本地文件。',
meta: async () => ({ apiPort: FALLBACK_PORT, cdpPort: 0, controlPort: 0, version: 'browser-dev' }),
browser: {
viewport: async () => undefined,
mode: async () => undefined,
onState: noop,
onReveal: noop,
onHide: noop,
onUserInput: noop,
},
};
const bridge: AssistantBridge = window.assistant ?? fallback;
export const isElectron = Boolean(window.assistant);
export const api = {
get: <T>(path: string): Promise<T> => bridge.get(path) as Promise<T>,
post: <T>(path: string, body?: unknown): Promise<T> => bridge.post(path, body) as Promise<T>,
put: <T>(path: string, body?: unknown): Promise<T> => bridge.put(path, body) as Promise<T>,
del: <T>(path: string): Promise<T> => bridge.del(path) as Promise<T>,
openPath: (filePath: string): Promise<string> => bridge.openPath(filePath),
appMeta: () => bridge.meta(),
browser: {
viewport: (message: ViewportMessage): Promise<void> => bridge.browser.viewport(message),
mode: (taskId: string, mode: ViewMode): Promise<void> => bridge.browser.mode(taskId, mode),
onState: (handler: (event: BrowserStateEvent) => void): (() => void) => bridge.browser.onState(handler),
onReveal: (handler: (event: RevealEvent) => void): (() => void) => bridge.browser.onReveal(handler),
onHide: (handler: (event: RevealEvent) => void): (() => void) => bridge.browser.onHide(handler),
onUserInput: (handler: (event: RevealEvent) => void): (() => void) => bridge.browser.onUserInput(handler),
},
};
export function errorText(error: unknown): string {
return error instanceof Error ? error.message : String(error);
}