fix(mount): persist raw file content in file-index for file mode (#8531)

This commit is contained in:
Chirag Chandrashekhar
2026-07-08 21:59:31 +05:30
committed by GitHub
parent d0863e2a43
commit 55c3003d6b
5 changed files with 30 additions and 11 deletions

View File

@@ -35,6 +35,7 @@ const FILE_DERIVED_REQUEST_FIELDS = [
'request',
'settings',
'examples',
'raw',
'filename',
'pathname',
'partial',

View File

@@ -27,9 +27,21 @@ const MIGRATIONS = [
) WITHOUT ROWID;
CREATE INDEX IF NOT EXISTS idx_collection_path ON file_index_entries(collection_path);
`
},
{
version: 2,
up: `
ALTER TABLE file_index_entries ADD COLUMN raw TEXT;
UPDATE file_index_entries SET mtime = 0, hash = '';
ALTER TABLE file_index_entries ADD COLUMN created_at INTEGER;
ALTER TABLE file_index_entries ADD COLUMN updated_at INTEGER;
UPDATE file_index_entries SET created_at = unixepoch(), updated_at = unixepoch();
`
}
];
// TODO: Check for trigger (ON UPDATE) and then see if we can use that to update updated_at
class FileIndex {
#db;
#dbPath;
@@ -102,12 +114,12 @@ class FileIndex {
entries(collectionPath) {
const root = normalize(collectionPath);
const rows = this.#db.all(
'SELECT relative_path AS relativePath, data FROM file_index_entries WHERE collection_path = ?',
'SELECT relative_path AS relativePath, data, raw FROM file_index_entries WHERE collection_path = ?',
root
);
const map = new Map();
for (const row of rows) {
map.set(row.relativePath, { data: JSON.parse(row.data) });
map.set(row.relativePath, { data: JSON.parse(row.data), raw: row.raw });
}
return map;
}
@@ -125,23 +137,26 @@ class FileIndex {
return;
}
const { mtime, hash, data } = entry;
const { mtime, hash, data, raw } = entry;
const id = idForAbsolutePath(path.join(root, relativePath));
this.#db.run(
`
INSERT INTO file_index_entries (collection_path, relative_path, id, mtime, hash, data)
VALUES (?, ?, ?, ?, ?, ?)
INSERT INTO file_index_entries (collection_path, relative_path, id, mtime, hash, data, raw, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?, ?, unixepoch(), unixepoch())
ON CONFLICT(collection_path, relative_path) DO UPDATE SET
mtime = excluded.mtime,
hash = excluded.hash,
data = excluded.data
data = excluded.data,
raw = excluded.raw,
updated_at = unixepoch()
`,
root,
relativePath,
id,
mtime,
hash,
JSON.stringify(data)
JSON.stringify(data),
raw ?? null
);
}
@@ -155,6 +170,7 @@ class FileIndex {
relativePath,
mtime: stat.mtimeNs,
hash: hashFile(absolutePath),
raw: fs.readFileSync(absolutePath, 'utf8'),
data
});
}

View File

@@ -192,13 +192,14 @@ class MountManager {
entry.state.set(e.relativePath, { data: result.data, error: result.error });
continue;
}
entry.state.set(e.relativePath, { data: result.data });
entry.state.set(e.relativePath, { data: result.data, raw: result.raw });
this.#getIndex().stage(entry.collectionPath, {
op: 'add',
relativePath: e.relativePath,
mtime: result.mtime,
hash: result.hash,
data: result.data
data: result.data,
raw: result.raw
});
}
for (const e of removed) {

View File

@@ -128,6 +128,7 @@ const buildRequestNode = (absolutePath, basename, entry, uidOverrides, uidFor) =
request: data.request,
settings: data.settings,
examples: data.examples,
raw: entry.raw ?? null,
filename: basename,
pathname: absolutePath,
draft: null,

View File

@@ -69,10 +69,10 @@ const parseFile = ({ collectionPath, relativePath, format, type }) => {
const content = buf.toString('utf8');
try {
const data = parseContent(content, format, type, buf.length);
return { relativePath, mtime, hash, data, format, type };
return { relativePath, mtime, hash, data, format, type, raw: content };
} catch (err) {
const data = format === 'bru' && type === 'request' ? extractBruMeta(content) : {};
return { relativePath, mtime, hash, data, format, type, partial: true, error: { message: err.message, stack: err.stack } };
return { relativePath, mtime, hash, data, format, type, raw: content, partial: true, error: { message: err.message, stack: err.stack } };
}
};