diff --git a/package-lock.json b/package-lock.json index 4d0871eede..b5b8d5450d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -50,7 +50,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, "license": "Apache-2.0", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -787,7 +786,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.2.0", @@ -818,7 +816,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -836,7 +833,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/@babel/generator": { @@ -1116,7 +1112,6 @@ "version": "7.26.0", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", - "dev": true, "license": "MIT", "dependencies": { "@babel/template": "^7.25.9", @@ -7083,7 +7078,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz", "integrity": "sha512-sVDA58zAw4eWAffKOaQH5/5j3XeayukzDk+ewSsnv3p4yJEZHCCzMDiZM8e0OUrRvmpGZ85jf4yDHkHsgBNr9Q==", - "dev": true, "license": "MIT" }, "node_modules/@types/lodash": { @@ -7096,7 +7090,6 @@ "version": "12.2.3", "resolved": "https://registry.npmjs.org/@types/markdown-it/-/markdown-it-12.2.3.tgz", "integrity": "sha512-GKMHFfv3458yYy+v/N8gjufHO6MSZKCOXpZc5GXIWWy8uldwfmPn98vp81gZ5f9SVw8YYBctgfJ22a2d7AOMeQ==", - "dev": true, "license": "MIT", "dependencies": { "@types/linkify-it": "*", @@ -7107,7 +7100,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@types/mdurl/-/mdurl-2.0.0.tgz", "integrity": "sha512-RGdgjQUZba5p6QEFAVx2OGb8rQDL/cPRG7GiedRzMcJ1tYnUANBncjbSB1NRGwbvjcPeikRABz2nshyPk1bhWg==", - "dev": true, "license": "MIT" }, "node_modules/@types/ms": { @@ -10092,7 +10084,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, "license": "MIT" }, "node_modules/cookie": { @@ -11442,6 +11433,16 @@ "node": ">=12" } }, + "node_modules/electron-devtools-installer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/electron-devtools-installer/-/electron-devtools-installer-4.0.0.tgz", + "integrity": "sha512-9Tntu/jtfSn0n6N/ZI6IdvRqXpDyLQiDuuIbsBI+dL+1Ef7C8J2JwByw58P3TJiNeuqyV3ZkphpNWuZK5iSY2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "unzip-crx-3": "^0.2.0" + } + }, "node_modules/electron-is-dev": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/electron-is-dev/-/electron-is-dev-2.0.0.tgz", @@ -11680,7 +11681,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "license": "MIT", "optional": true, "dependencies": { @@ -12701,7 +12701,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -13775,6 +13774,13 @@ "node": ">= 4" } }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, "node_modules/immer": { "version": "9.0.21", "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz", @@ -15725,6 +15731,52 @@ "extsprintf": "^1.2.0" } }, + "node_modules/jszip": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jszip/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/jszip/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/jszip/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, "node_modules/jwa": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", @@ -15802,6 +15854,16 @@ "node": ">=6" } }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, "node_modules/lilconfig": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", @@ -23107,7 +23169,7 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, + "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -23214,6 +23276,18 @@ "node": ">= 0.8" } }, + "node_modules/unzip-crx-3": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/unzip-crx-3/-/unzip-crx-3-0.2.0.tgz", + "integrity": "sha512-0+JiUq/z7faJ6oifVB5nSwt589v1KCduqIJupNVDoWSXZtWDmjDGO3RAEOvwJ07w90aoXoP4enKsR7ecMrJtWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "jszip": "^3.1.0", + "mkdirp": "^0.5.1", + "yaku": "^0.16.6" + } + }, "node_modules/upath": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", @@ -23807,6 +23881,13 @@ "node": ">=10" } }, + "node_modules/yaku": { + "version": "0.16.7", + "resolved": "https://registry.npmjs.org/yaku/-/yaku-0.16.7.tgz", + "integrity": "sha512-Syu3IB3rZvKvYk7yTiyl1bo/jiEFaaStrgv1V2TIJTqYPStSMQVO8EQjg/z+DRzLq/4LIIharNT3iH1hylEIRw==", + "dev": true, + "license": "MIT" + }, "node_modules/yallist": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", @@ -24112,7 +24193,8 @@ }, "devDependencies": { "electron": "33.2.1", - "electron-builder": "25.1.8" + "electron-builder": "25.1.8", + "electron-devtools-installer": "^4.0.0" }, "optionalDependencies": { "dmg-license": "^1.0.11" diff --git a/packages/bruno-app/src/components/CollectionSettings/ClientCertSettings/index.js b/packages/bruno-app/src/components/CollectionSettings/ClientCertSettings/index.js index ba1debdec9..ccfac9046b 100644 --- a/packages/bruno-app/src/components/CollectionSettings/ClientCertSettings/index.js +++ b/packages/bruno-app/src/components/CollectionSettings/ClientCertSettings/index.js @@ -68,12 +68,13 @@ const ClientCertSettings = ({ root, clientCertConfig, onUpdate, onRemove }) => { }); const getFile = (e) => { - if (e.files?.[0]?.path) { + const filePath = window?.ipcRenderer?.getFilePath(e?.files?.[0]); + if (filePath) { let relativePath; if (isWindowsOS()) { - relativePath = slash(path.win32.relative(root, e.files[0].path)); + relativePath = slash(path.win32.relative(root, filePath)); } else { - relativePath = path.posix.relative(root, e.files[0].path); + relativePath = path.posix.relative(root, filePath); } formik.setFieldValue(e.name, relativePath); } diff --git a/packages/bruno-app/src/components/Preferences/General/index.js b/packages/bruno-app/src/components/Preferences/General/index.js index 0d26c955d4..2867d9841e 100644 --- a/packages/bruno-app/src/components/Preferences/General/index.js +++ b/packages/bruno-app/src/components/Preferences/General/index.js @@ -90,7 +90,10 @@ const General = ({ close }) => { }; const addCaCertificate = (e) => { - formik.setFieldValue('customCaCertificate.filePath', e.target.files[0]?.path); + const filePath = window?.ipcRenderer?.getFilePath(e?.target?.files?.[0]); + if (filePath) { + formik.setFieldValue('customCaCertificate.filePath', filePath); + } }; const deleteCaCertificate = () => { diff --git a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js index ef5143551a..792736b12d 100644 --- a/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js +++ b/packages/bruno-app/src/components/Sidebar/Collections/Collection/CollectionItem/GenerateCodeItem/index.js @@ -63,22 +63,21 @@ const GenerateCodeItem = ({ collection, item, onClose }) => { tabIndex={0} onClick={() => setSelectedLanguage(language)} onKeyDown={(e) => { - if (e.key === 'Tab') { + if (e.key === 'Tab' || (e.shiftKey && e.key === 'Tab')) { e.preventDefault(); const currentIndex = languages.findIndex((lang) => lang.name === selectedLanguage.name); const nextIndex = e.shiftKey ? (currentIndex - 1 + languages.length) % languages.length : (currentIndex + 1) % languages.length; setSelectedLanguage(languages[nextIndex]); - } - if (e.shiftKey && e.key === 'Tab') { - e.preventDefault(); - const currentIndex = languages.findIndex((lang) => lang.name === selectedLanguage.name); - const nextIndex = (currentIndex - 1 + languages.length) % languages.length; - setSelectedLanguage(languages[nextIndex]); + // Explicitly focus on the new active element + const nextElement = document.querySelector(`[data-language="${languages[nextIndex].name}"]`); + nextElement?.focus(); } + }} + data-language={language.name} aria-pressed={language.name === selectedLanguage.name} > {language.name} @@ -89,6 +88,7 @@ const GenerateCodeItem = ({ collection, item, onClose }) => {
{isValidUrl(finalUrl) ? ( { items: [], environments: [], root: { + docs: collection.info.description || '', meta: { name: collection.info.name }, diff --git a/packages/bruno-cli/package.json b/packages/bruno-cli/package.json index 22bc16602c..b616c50e8e 100644 --- a/packages/bruno-cli/package.json +++ b/packages/bruno-cli/package.json @@ -13,6 +13,28 @@ "type": "git", "url": "git+https://github.com/usebruno/bruno.git" }, + "keywords": [ + "API", + "testing", + "automation", + "cli", + "command-line", + "bruno", + "HTTP requests", + "rest-api", + "api-client", + "api-automation", + "request-handling", + "mock-api", + "http-client", + "async", + "promise", + "javascript", + "nodejs", + "automation-tool", + "postman-alternative", + "api-scripting" + ], "scripts": { "test": "node --experimental-vm-modules $(npx which jest)" }, diff --git a/packages/bruno-cli/src/commands/run.js b/packages/bruno-cli/src/commands/run.js index 1961b2ac03..29edf63b9c 100644 --- a/packages/bruno-cli/src/commands/run.js +++ b/packages/bruno-cli/src/commands/run.js @@ -1,7 +1,7 @@ const fs = require('fs'); const chalk = require('chalk'); const path = require('path'); -const { forOwn } = require('lodash'); +const { forOwn, cloneDeep } = require('lodash'); const { exists, isFile, isDirectory } = require('../utils/filesystem'); const { runSingleRequest } = require('../runner/run-single-request'); const { bruToEnvJson, getEnvVars } = require('../utils/bru'); @@ -637,7 +637,7 @@ const handler = async function (argv) { let currentRequestIndex = 0; let nJumps = 0; // count the number of jumps to avoid infinite loops while (currentRequestIndex < bruJsons.length) { - const iter = bruJsons[currentRequestIndex]; + const iter = cloneDeep(bruJsons[currentRequestIndex]); const { bruFilepath, bruJson } = iter; const start = process.hrtime(); diff --git a/packages/bruno-cli/src/utils/common.js b/packages/bruno-cli/src/utils/common.js index 95ac44e628..589c7bf7f4 100644 --- a/packages/bruno-cli/src/utils/common.js +++ b/packages/bruno-cli/src/utils/common.js @@ -44,7 +44,7 @@ const parseDataFromResponse = (response, disableParsingResponseJson = false) => data = JSON.parse(data); } } catch { - console.log('Failed to parse response data as JSON'); + } return { data, dataBuffer }; diff --git a/packages/bruno-electron/package.json b/packages/bruno-electron/package.json index 875295c35a..7e8e255649 100644 --- a/packages/bruno-electron/package.json +++ b/packages/bruno-electron/package.json @@ -63,6 +63,7 @@ }, "devDependencies": { "electron": "33.2.1", - "electron-builder": "25.1.8" + "electron-builder": "25.1.8", + "electron-devtools-installer": "^4.0.0" } } diff --git a/packages/bruno-electron/src/index.js b/packages/bruno-electron/src/index.js index 47ab8ae7c1..4b6494b2f2 100644 --- a/packages/bruno-electron/src/index.js +++ b/packages/bruno-electron/src/index.js @@ -11,7 +11,7 @@ if (isDev) { } const { format } = require('url'); -const { BrowserWindow, app, Menu, ipcMain } = require('electron'); +const { BrowserWindow, app, session, Menu, ipcMain } = require('electron'); const { setContentSecurityPolicy } = require('electron-util'); const menuTemplate = require('./app/menu-template'); @@ -51,6 +51,24 @@ let watcher; // Prepare the renderer once the app is ready app.on('ready', async () => { + + if (isDev) { + const { installExtension, REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS } = require('electron-devtools-installer'); + try { + const extensions = await installExtension([REDUX_DEVTOOLS, REACT_DEVELOPER_TOOLS], { + loadExtensionOptions: {allowFileAccess: true}, + }) + console.log(`Added Extensions: ${extensions.map(ext => ext.name).join(", ")}`) + await require("node:timers/promises").setTimeout(1000); + session.defaultSession.getAllExtensions().map((ext) => { + console.log(`Loading Extension: ${ext.name}`); + session.defaultSession.loadExtension(ext.path) + }); + } catch (err) { + console.error('An error occurred while loading extensions: ', err); + } + } + Menu.setApplicationMenu(menu); const { maximized, x, y, width, height } = loadWindowState(); diff --git a/packages/bruno-electron/src/ipc/network/index.js b/packages/bruno-electron/src/ipc/network/index.js index 5133a1f1df..782878c59a 100644 --- a/packages/bruno-electron/src/ipc/network/index.js +++ b/packages/bruno-electron/src/ipc/network/index.js @@ -1005,7 +1005,7 @@ const registerNetworkIpc = (mainWindow) => { stopRunnerExecution = false; - const item = folderRequests[currentRequestIndex]; + const item = cloneDeep(folderRequests[currentRequestIndex]); let nextRequestName; const itemUid = item.uid; const eventData = { diff --git a/packages/bruno-electron/src/preload.js b/packages/bruno-electron/src/preload.js index 4bfe2216bb..83dfcada81 100644 --- a/packages/bruno-electron/src/preload.js +++ b/packages/bruno-electron/src/preload.js @@ -1,4 +1,4 @@ -const { ipcRenderer, contextBridge } = require('electron'); +const { ipcRenderer, contextBridge, webUtils } = require('electron'); contextBridge.exposeInMainWorld('ipcRenderer', { invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args), @@ -10,5 +10,9 @@ contextBridge.exposeInMainWorld('ipcRenderer', { return () => { ipcRenderer.removeListener(channel, subscription); }; + }, + getFilePath (file) { + const path = webUtils.getPathForFile(file) + return path; } });