import { mkdtempSync, rmSync, writeFileSync, mkdirSync } from 'node:fs'; import { readFile, stat } from 'node:fs/promises'; import { tmpdir } from 'node:os'; import path from 'node:path'; import { afterEach, beforeEach, describe, expect, it } from 'vitest'; import { InlineAssetsLimitError, inlineRelativeAssets, type AssetHandle, type InlineAssetReader, } from '../src/inline-assets.js'; // FS-backed reader that mirrors the production GET /api/projects/:id/export // shape — stat for size, readFile for body — so this suite exercises the // helper through the same handle contract callers use in apps/daemon/src/ // import-export-routes.ts. The in-memory-reader edge cases live in // export-inline-route.test.ts; this file covers FS round-trip, // top-level-vs-nested scoping, and the byte-cap surface that maps to the // 413 PAYLOAD_TOO_LARGE envelope. describe('inlineRelativeAssets (FS-backed)', () => { let root: string; beforeEach(() => { root = mkdtempSync(path.join(tmpdir(), 'od-inline-assets-')); }); afterEach(() => { rmSync(root, { recursive: true, force: true }); }); function write(rel: string, body: string | Buffer) { const target = path.join(root, rel); mkdirSync(path.dirname(target), { recursive: true }); writeFileSync(target, body); } function fsReader(): InlineAssetReader { return async (rel) => { const abs = path.join(root, rel); try { const s = await stat(abs); const handle: AssetHandle = { size: s.size, read: async () => { try { return await readFile(abs, 'utf8'); } catch { return null; } }, }; return handle; } catch { return null; } }; } it('inlines a top-level as a