diff --git a/packages/bruno-electron/src/services/mount/manager.js b/packages/bruno-electron/src/services/mount/manager.js index 5427e9813..3943dda39 100644 --- a/packages/bruno-electron/src/services/mount/manager.js +++ b/packages/bruno-electron/src/services/mount/manager.js @@ -189,7 +189,7 @@ class MountManager { const result = parsed.get(e.relativePath); if (!result) continue; if (result.error) { - entry.state.set(e.relativePath, { error: result.error }); + entry.state.set(e.relativePath, { data: result.data, error: result.error }); continue; } entry.state.set(e.relativePath, { data: result.data }); diff --git a/packages/bruno-electron/src/services/mount/tree-builder.js b/packages/bruno-electron/src/services/mount/tree-builder.js index 57061f9a8..7caae6ba6 100644 --- a/packages/bruno-electron/src/services/mount/tree-builder.js +++ b/packages/bruno-electron/src/services/mount/tree-builder.js @@ -182,6 +182,9 @@ const buildTree = (collectionPath, parserResults, options = {}) => { hydrateRequestUuids(data, null, collectionPath); tree.root = data; } + if (tree.root && typeof tree.root === 'object') { + tree.root.pathname = path.join(collectionPath, relativePath); + } } } else if (cls.type === 'folder') { folderRoots.set(path.dirname(relativePath), entry); diff --git a/packages/bruno-electron/src/services/pool/index.js b/packages/bruno-electron/src/services/pool/index.js index 57038962e..c80aa5b0b 100644 --- a/packages/bruno-electron/src/services/pool/index.js +++ b/packages/bruno-electron/src/services/pool/index.js @@ -15,7 +15,8 @@ class Pool { const workers = Math.max(1, size ?? os.availableParallelism()); this.#pool = workerpool.pool(WORKER_FILE, { maxWorkers: workers, - workerType: 'thread' + workerType: 'thread', + workerThreadOpts: { resourceLimits: { maxOldGenerationSizeMb: 512 } } }); } diff --git a/packages/bruno-electron/src/services/pool/jobs/parse-file.js b/packages/bruno-electron/src/services/pool/jobs/parse-file.js index a837f083f..e0e94074e 100644 --- a/packages/bruno-electron/src/services/pool/jobs/parse-file.js +++ b/packages/bruno-electron/src/services/pool/jobs/parse-file.js @@ -5,11 +5,49 @@ const filestore = require('@usebruno/filestore'); const sha256 = (buf) => crypto.createHash('sha256').update(buf).digest('hex'); -const parseContent = (content, format, type) => { +const REDACT_BODY_THRESHOLD = 512 * 1024; + +const parseLargeBruRequest = (content, format) => { + const { bruFileStringWithRedactedBody, extractedBodyContent } = filestore.parseRequestAndRedactBody(content, { format }); + const data = filestore.parseRequest(bruFileStringWithRedactedBody, { format }); + data.request = data.request || {}; + data.request.body = data.request.body || {}; + const body = extractedBodyContent || {}; + if (body.json) data.request.body.json = body.json; + if (body.text) data.request.body.text = body.text; + if (body.xml) data.request.body.xml = body.xml; + if (body.sparql) data.request.body.sparql = body.sparql; + if (body.graphql) { + data.request.body.graphql = data.request.body.graphql || {}; + data.request.body.graphql.query = body.graphql; + } + return data; +}; + +const extractBruMeta = (content) => { + const data = {}; + const match = content.match(/meta\s*\{\s*([\s\S]*?)\s*\}/); + if (match) { + for (const line of match[1].replace(/\r\n/g, '\n').split('\n')) { + const idx = line.indexOf(':'); + if (idx === -1) continue; + const key = line.slice(0, idx).trim(); + const value = line.slice(idx + 1).trim(); + if (!key || !value) continue; + data[key] = Number.isNaN(Number(value)) ? value : Number(value); + } + } + if (data.type === 'http') data.type = 'http-request'; + else if (data.type === 'graphql') data.type = 'graphql-request'; + return data; +}; + +const parseContent = (content, format, type, byteSize) => { if (type === 'config' || format === 'json') return JSON.parse(content); const options = { format }; switch (type) { case 'request': + if (format === 'bru' && byteSize >= REDACT_BODY_THRESHOLD) return parseLargeBruRequest(content, format); return filestore.parseRequest(content, options); case 'collection': return filestore.parseCollection(content, options); @@ -26,9 +64,16 @@ const parseFile = ({ collectionPath, relativePath, format, type }) => { const absolutePath = path.join(collectionPath, relativePath); const buf = fs.readFileSync(absolutePath); const stat = fs.statSync(absolutePath, { bigint: true }); + const mtime = stat.mtimeNs; + const hash = sha256(buf); const content = buf.toString('utf8'); - const data = parseContent(content, format, type); - return { relativePath, mtime: stat.mtimeNs, hash: sha256(buf), data, format, type }; + try { + const data = parseContent(content, format, type, buf.length); + return { relativePath, mtime, hash, data, format, type }; + } 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 } }; + } }; module.exports = parseFile;