mirror of
https://github.com/getcompanion-ai/co-mono.git
synced 2026-04-15 20:03:05 +00:00
fix(coding-agent): load photon wasm in compiled binaries
This commit is contained in:
parent
61833b3dc9
commit
964f17b8d1
3 changed files with 99 additions and 4 deletions
|
|
@ -8,17 +8,107 @@
|
|||
* The challenge: photon-node's CJS entry uses fs.readFileSync(__dirname + '/photon_rs_bg.wasm')
|
||||
* which bakes the build machine's absolute path into Bun compiled binaries.
|
||||
*
|
||||
* Solution: Lazy-load photon via dynamic import and gracefully handle failures.
|
||||
* Image processing functions have fallbacks that return original images when photon isn't available.
|
||||
* Solution:
|
||||
* 1. Patch fs.readFileSync to redirect missing photon_rs_bg.wasm reads
|
||||
* 2. Copy photon_rs_bg.wasm next to the executable in build:binary
|
||||
*/
|
||||
|
||||
import type { PathOrFileDescriptor } from "fs";
|
||||
import { createRequire } from "module";
|
||||
import * as path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
const fs = require("fs") as typeof import("fs");
|
||||
|
||||
// Re-export types from the main package
|
||||
export type { PhotonImage as PhotonImageType } from "@silvia-odwyer/photon-node";
|
||||
|
||||
type ReadFileSync = typeof fs.readFileSync;
|
||||
|
||||
const WASM_FILENAME = "photon_rs_bg.wasm";
|
||||
|
||||
// Lazy-loaded photon module
|
||||
let photonModule: typeof import("@silvia-odwyer/photon-node") | null = null;
|
||||
let loadPromise: Promise<typeof import("@silvia-odwyer/photon-node") | null> | null = null;
|
||||
|
||||
function pathOrNull(file: PathOrFileDescriptor): string | null {
|
||||
if (typeof file === "string") {
|
||||
return file;
|
||||
}
|
||||
if (file instanceof URL) {
|
||||
return fileURLToPath(file);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function getFallbackWasmPaths(): string[] {
|
||||
const execDir = path.dirname(process.execPath);
|
||||
return [
|
||||
path.join(execDir, WASM_FILENAME),
|
||||
path.join(execDir, "photon", WASM_FILENAME),
|
||||
path.join(process.cwd(), WASM_FILENAME),
|
||||
];
|
||||
}
|
||||
|
||||
function patchPhotonWasmRead(): () => void {
|
||||
const originalReadFileSync: ReadFileSync = fs.readFileSync.bind(fs);
|
||||
const fallbackPaths = getFallbackWasmPaths();
|
||||
const mutableFs = fs as { readFileSync: ReadFileSync };
|
||||
|
||||
const patchedReadFileSync: ReadFileSync = ((...args: Parameters<ReadFileSync>) => {
|
||||
const [file, options] = args;
|
||||
const resolvedPath = pathOrNull(file);
|
||||
|
||||
if (resolvedPath?.endsWith(WASM_FILENAME)) {
|
||||
try {
|
||||
return originalReadFileSync(...args);
|
||||
} catch (error) {
|
||||
const err = error as NodeJS.ErrnoException;
|
||||
if (err?.code && err.code !== "ENOENT") {
|
||||
throw error;
|
||||
}
|
||||
|
||||
for (const fallbackPath of fallbackPaths) {
|
||||
if (!fs.existsSync(fallbackPath)) {
|
||||
continue;
|
||||
}
|
||||
if (options === undefined) {
|
||||
return originalReadFileSync(fallbackPath);
|
||||
}
|
||||
return originalReadFileSync(fallbackPath, options);
|
||||
}
|
||||
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return originalReadFileSync(...args);
|
||||
}) as ReadFileSync;
|
||||
|
||||
try {
|
||||
mutableFs.readFileSync = patchedReadFileSync;
|
||||
} catch {
|
||||
Object.defineProperty(fs, "readFileSync", {
|
||||
value: patchedReadFileSync,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
|
||||
return () => {
|
||||
try {
|
||||
mutableFs.readFileSync = originalReadFileSync;
|
||||
} catch {
|
||||
Object.defineProperty(fs, "readFileSync", {
|
||||
value: originalReadFileSync,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the photon module asynchronously.
|
||||
* Returns cached module on subsequent calls.
|
||||
|
|
@ -33,12 +123,16 @@ export async function loadPhoton(): Promise<typeof import("@silvia-odwyer/photon
|
|||
}
|
||||
|
||||
loadPromise = (async () => {
|
||||
const restoreReadFileSync = patchPhotonWasmRead();
|
||||
try {
|
||||
photonModule = await import("@silvia-odwyer/photon-node");
|
||||
return photonModule;
|
||||
} catch {
|
||||
photonModule = null;
|
||||
return photonModule;
|
||||
} finally {
|
||||
restoreReadFileSync();
|
||||
}
|
||||
return photonModule;
|
||||
})();
|
||||
|
||||
return loadPromise;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue