- Introduced a new Docker setup for running claude-devtools in standalone mode without Electron. - Added Dockerfile and docker-compose.yml for easy deployment. - Implemented .dockerignore to exclude unnecessary files from the Docker context. - Updated package.json with new scripts for building and running the standalone server. - Enhanced README with Docker usage instructions and environment variable configurations. - Modified HttpServer to support serving static files and API in standalone mode. - Updated various components to ensure compatibility with standalone operation.
68 lines
2.4 KiB
TypeScript
68 lines
2.4 KiB
TypeScript
/**
|
|
* Unified API adapter.
|
|
*
|
|
* When running inside Electron, the preload script exposes `window.electronAPI`.
|
|
* When running in a browser (e.g. via the HTTP server), we fall back to an
|
|
* HTTP+SSE client that implements the same interface.
|
|
*
|
|
* All renderer code should import `api` from this module instead of
|
|
* accessing `window.electronAPI` directly.
|
|
*
|
|
* The instance is resolved lazily on first property access so that test code
|
|
* can install mocks on `window.electronAPI` before the adapter resolves.
|
|
*/
|
|
|
|
import { HttpAPIClient } from './httpClient';
|
|
|
|
import type { ElectronAPI } from '@shared/types/api';
|
|
|
|
/**
|
|
* Resolves the base URL for the HTTP API client.
|
|
*
|
|
* - Electron "server mode" (browser opened via ?port=XXXX): use explicit port on 127.0.0.1
|
|
* - Standalone/Docker (page served by the same server): use window.location.origin
|
|
* to avoid cross-origin issues (localhost vs 127.0.0.1)
|
|
*/
|
|
function getHttpBaseUrl(): string {
|
|
const params = new URLSearchParams(window.location.search);
|
|
const explicitPort = params.get('port');
|
|
if (explicitPort) {
|
|
return `http://127.0.0.1:${parseInt(explicitPort, 10)}`;
|
|
}
|
|
return window.location.origin;
|
|
}
|
|
|
|
let httpClient: HttpAPIClient | null = null;
|
|
|
|
function getImpl(): ElectronAPI {
|
|
if (window.electronAPI) return window.electronAPI;
|
|
// Lazily create the HTTP client only when actually needed (browser mode).
|
|
// Caching avoids creating multiple EventSource connections.
|
|
if (!httpClient) {
|
|
httpClient = new HttpAPIClient(getHttpBaseUrl());
|
|
}
|
|
return httpClient;
|
|
}
|
|
|
|
/**
|
|
* Proxy that lazily resolves the underlying ElectronAPI on first property access.
|
|
* In Electron: delegates to `window.electronAPI` (set by preload).
|
|
* In browser: delegates to `HttpAPIClient` (created on first use).
|
|
* In tests: delegates to whatever mock is installed on `window.electronAPI`.
|
|
*/
|
|
/**
|
|
* Whether the app is running inside Electron (true) or in a browser via HTTP server (false).
|
|
* Use this to hide Electron-only UI (settings, traffic lights, etc.) in browser mode.
|
|
*/
|
|
export const isElectronMode = (): boolean => !!window.electronAPI;
|
|
|
|
export const api: ElectronAPI = new Proxy({} as ElectronAPI, {
|
|
get(_target, prop, receiver) {
|
|
const impl = getImpl();
|
|
const value = Reflect.get(impl, prop, receiver) as unknown;
|
|
if (typeof value === 'function') {
|
|
return (value as (...args: unknown[]) => unknown).bind(impl);
|
|
}
|
|
return value;
|
|
},
|
|
});
|