diff --git a/lib/ghostty.ts b/lib/ghostty.ts index aff971f..9c324ca 100644 --- a/lib/ghostty.ts +++ b/lib/ghostty.ts @@ -55,40 +55,65 @@ export class Ghostty { /** * Load Ghostty WASM from URL or file path + * If no path is provided, attempts to load from common default locations */ - static async load(wasmPath: string): Promise { - let wasmBytes: ArrayBuffer; + static async load(wasmPath?: string): Promise { + // Default WASM paths to try (in order) + const defaultPaths = [ + // When published as npm package + new URL('../ghostty-vt.wasm', import.meta.url).href, + // When used from CDN or local dev + './ghostty-vt.wasm', + '/ghostty-vt.wasm', + ]; + + const pathsToTry = wasmPath ? [wasmPath] : defaultPaths; + let lastError: Error | null = null; + + for (const path of pathsToTry) { + try { + let wasmBytes: ArrayBuffer; + + // Try loading as file first (for Node/Bun environments) + try { + const fs = await import('fs/promises'); + const buffer = await fs.readFile(path); + wasmBytes = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + } catch (e) { + // Fall back to fetch (for browser environments) + const response = await fetch(path); + if (!response.ok) { + throw new Error(`Failed to fetch WASM: ${response.status} ${response.statusText}`); + } + wasmBytes = await response.arrayBuffer(); + if (wasmBytes.byteLength === 0) { + throw new Error(`WASM file is empty (0 bytes). Check path: ${path}`); + } + } - // Try loading as file first (for Node/Bun environments) - try { - const fs = await import('fs/promises'); - const buffer = await fs.readFile(wasmPath); - wasmBytes = buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); - } catch (e) { - // Fall back to fetch (for browser environments) - const response = await fetch(wasmPath); - if (!response.ok) { - throw new Error(`Failed to fetch WASM: ${response.status} ${response.statusText}`); - } - wasmBytes = await response.arrayBuffer(); - if (wasmBytes.byteLength === 0) { - throw new Error(`WASM file is empty (0 bytes). Check path: ${wasmPath}`); + // Successfully loaded, instantiate and return + const wasmModule = await WebAssembly.instantiate(wasmBytes, { + env: { + // Stub out C runtime functions (not used by libghostty-vt) + }, + }); + + return new Ghostty(wasmModule.instance); + } catch (e) { + lastError = e instanceof Error ? e : new Error(String(e)); + // Try next path + continue; } } - const wasmModule = await WebAssembly.instantiate(wasmBytes, { - env: { - log: (ptr: number, len: number) => { - const instance = (wasmModule as any).instance; - const bytes = new Uint8Array(instance.exports.memory.buffer, ptr, len); - const text = new TextDecoder().decode(bytes); - console.log('[ghostty-wasm]', text); - }, - }, - }); - - return new Ghostty(wasmModule.instance); + // All paths failed + throw new Error( + `Failed to load ghostty-vt.wasm. Tried paths: ${pathsToTry.join(', ')}. ` + + `Last error: ${lastError?.message}. ` + + `You can specify a custom path with: new Terminal({ wasmPath: './path/to/ghostty-vt.wasm' })` + ); } + } /** diff --git a/lib/input-handler.test.ts b/lib/input-handler.test.ts index 3a6ee65..8519a2a 100644 --- a/lib/input-handler.test.ts +++ b/lib/input-handler.test.ts @@ -129,8 +129,8 @@ describe('InputHandler', () => { beforeAll(async () => { // Load WASM once for all tests (expensive operation) - const wasmPath = new URL('../ghostty-vt.wasm', import.meta.url).href; - ghostty = await Ghostty.load(wasmPath); + // wasmPath is now optional - auto-detected + ghostty = await Ghostty.load(); }); beforeEach(() => { diff --git a/lib/interfaces.ts b/lib/interfaces.ts index 30e4fae..9164399 100644 --- a/lib/interfaces.ts +++ b/lib/interfaces.ts @@ -12,7 +12,7 @@ export interface ITerminalOptions { fontSize?: number; // Default: 15 fontFamily?: string; // Default: 'monospace' allowTransparency?: boolean; - wasmPath?: string; // Default: '../ghostty-vt.wasm' (relative to examples/) + wasmPath?: string; // Optional: custom WASM path (auto-detected by default) } export interface ITheme { diff --git a/lib/terminal.ts b/lib/terminal.ts index 8f8e329..0ceaba0 100644 --- a/lib/terminal.ts +++ b/lib/terminal.ts @@ -79,7 +79,7 @@ export class Terminal implements ITerminalCore { fontSize: options.fontSize ?? 15, fontFamily: options.fontFamily ?? 'monospace', allowTransparency: options.allowTransparency ?? false, - wasmPath: options.wasmPath ?? '../ghostty-vt.wasm', + wasmPath: options.wasmPath, // Optional - Ghostty.load() handles defaults }; this.cols = this.options.cols; diff --git a/scripts/build-wasm.sh b/scripts/build-wasm.sh index 687a105..e3f136d 100755 --- a/scripts/build-wasm.sh +++ b/scripts/build-wasm.sh @@ -21,7 +21,7 @@ echo "✓ Found Zig $ZIG_VERSION" GHOSTTY_DIR="/tmp/ghostty-for-wasm" if [ ! -d "$GHOSTTY_DIR" ]; then echo "📦 Cloning Ghostty..." - git clone --depth=1 https://github.com/ghostty-org/ghostty.git "$GHOSTTY_DIR" + git clone --depth=1 https://github.com/coder/ghostty.git "$GHOSTTY_DIR" else echo "📦 Updating Ghostty..." cd "$GHOSTTY_DIR"