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