77 lines
2.3 KiB
TypeScript
77 lines
2.3 KiB
TypeScript
import { existsSync } from 'node:fs';
|
|
import { join } from 'node:path';
|
|
import type { TaxonomyHydrationInput, TaxonomyHydrationResult } from '@/lib/server/taxonomy/types';
|
|
|
|
function candidateBinaryPaths() {
|
|
return [
|
|
process.env.FISCAL_XBRL_BIN?.trim(),
|
|
join(process.cwd(), 'bin', 'fiscal-xbrl'),
|
|
join(process.cwd(), 'rust', 'target', 'release', 'fiscal-xbrl'),
|
|
join(process.cwd(), 'rust', 'target', 'debug', 'fiscal-xbrl')
|
|
].filter((value): value is string => typeof value === 'string' && value.length > 0);
|
|
}
|
|
|
|
export function resolveFiscalXbrlBinary() {
|
|
const resolved = candidateBinaryPaths().find((path) => existsSync(path));
|
|
if (!resolved) {
|
|
throw new Error('Rust XBRL sidecar binary is required but was not found. Set FISCAL_XBRL_BIN or build `fiscal-xbrl` under rust/target.');
|
|
}
|
|
|
|
return resolved;
|
|
}
|
|
|
|
export async function hydrateFilingTaxonomySnapshotFromSidecar(
|
|
input: TaxonomyHydrationInput
|
|
): Promise<TaxonomyHydrationResult> {
|
|
const binary = resolveFiscalXbrlBinary();
|
|
const timeoutMs = Math.max(Number(process.env.XBRL_ENGINE_TIMEOUT_MS ?? 45_000), 1_000);
|
|
const command = [binary, 'hydrate-filing'];
|
|
const requestBody = JSON.stringify({
|
|
filingId: input.filingId,
|
|
ticker: input.ticker,
|
|
cik: input.cik,
|
|
accessionNumber: input.accessionNumber,
|
|
filingDate: input.filingDate,
|
|
filingType: input.filingType,
|
|
filingUrl: input.filingUrl,
|
|
primaryDocument: input.primaryDocument,
|
|
cacheDir: process.env.FISCAL_XBRL_CACHE_DIR ?? join(process.cwd(), '.cache', 'xbrl')
|
|
});
|
|
|
|
const child = Bun.spawn(command, {
|
|
stdin: 'pipe',
|
|
stdout: 'pipe',
|
|
stderr: 'pipe',
|
|
env: {
|
|
...process.env
|
|
}
|
|
});
|
|
|
|
child.stdin.write(new TextEncoder().encode(requestBody));
|
|
child.stdin.end();
|
|
|
|
const timeout = setTimeout(() => {
|
|
child.kill();
|
|
}, timeoutMs);
|
|
|
|
try {
|
|
const [stdout, stderr, exitCode] = await Promise.all([
|
|
new Response(child.stdout).text(),
|
|
new Response(child.stderr).text(),
|
|
child.exited
|
|
]);
|
|
|
|
if (stderr.trim().length > 0) {
|
|
console.warn(`[fiscal-xbrl] ${stderr.trim()}`);
|
|
}
|
|
|
|
if (exitCode !== 0) {
|
|
throw new Error(`Rust XBRL sidecar failed with exit code ${exitCode}: ${stderr.trim() || stdout.trim() || 'no error output'}`);
|
|
}
|
|
|
|
return JSON.parse(stdout) as TaxonomyHydrationResult;
|
|
} finally {
|
|
clearTimeout(timeout);
|
|
}
|
|
}
|