Skip to content

Commit cf405f7

Browse files
authored
Merge branch 'master' into draft-setapp-wrapper-support
2 parents 0e7260d + 00d00da commit cf405f7

28 files changed

+613
-309
lines changed

claude.md

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
This is the source code for the desktop app of Requestly. It is an electron app
2+
3+
# Parts of App
4+
This primarily has two render processes:
5+
1. App Renderer:
6+
- The UI of the app that is visible to the user
7+
- held by the `webAppWindow` variable in `src/main.ts`
8+
- loads the UI from `localhost:3000` during developement. The code of which can be found outside this repo at `../requestly/app`. This is the same code as the one that is loaded for the web version of requestly (although the code there is written in a way to recognise and adapt based on whether the website loads inside the web browser or the electron app here)
9+
- this loads a react app
10+
- this process has `nodeIntegration: false` and `sandbox: false`. and this is made to be a frameless window
11+
- loads preload from `./preload.js`
12+
13+
2. Background Renderer:
14+
- The process for all the background stuff. Major responsibilities include:
15+
- running the requestly proxy (whose code can be found inside `../requestly-proxy`) for providing interception functionality and everything related to that
16+
- an abstract FS service for managing access to local files as and when needed - primarily used to provide the capability have "workspaces" that store data fully locally
17+
- held by the `backgroundWindow` variable in `src/main.ts`
18+
- this has `nodeIntegration: true`, `contextIsolation: false` and has remote module enabled.
19+
- this renderer does not load any preload script
20+
21+
3. Main process:
22+
- entry point of the app, hence takes care of core important things like
23+
- all the other parts of the app spawn on launch
24+
- initiator for all essential services and major IPC handlers
25+
- Critical place for all the IPC infrastructure that we have here (explained later)
26+
- handles custom system specific app integrations like:
27+
- handling the custom protocol that the app registers for deep link integrations
28+
- handling the files for which this becomes a default client (`.har` and `.rqly` files)
29+
- Autoupdates - code related to that should be very carefully updated as any issues there would be very hard to resolve (as they would make it difficult to make the fixed release reach affected users)
30+
- this is the node environment where the actual request is made for the Requestly API client
31+
- creates the tray menu to expose basic touch points
32+
- quitting and its related cleanup
33+
- some other basic helpers like:
34+
- preserving cookies
35+
- loading some stored user configs
36+
37+
38+
# IPC infrastructure
39+
- Electron specific constraints:
40+
- IPC can only send serializable data. Objects with functions, circular references, or complex types cannot be transmitted.
41+
- renderers can only talk to the main process and not directly to each other
42+
43+
44+
The code here has several tooling built to make the developer experience of working with IPC a lot easier
45+
46+
1. IPC.js via preload
47+
In the app renderer, there are special wrapper functions for the IPC tooling that expose easy functions for the app renderer to communicate and listen to events from both main and the background renderer
48+
49+
2. IPC forwarding:
50+
there are special IPC channels setup in main process to forward messages from app renderer to background renderer and vice versa (along with replies)
51+
these are exposed via the IPC service through the preload as well
52+
53+
3. `RPCServiceOverIPC` on top of IPC forwarding.
54+
This class in the background process provides a way to create services in the background renderer and consume them inside the app renderer through *"adapters"* that expose easy to consume methods for these services
55+
56+
57+
# Bundling / Packaging nuances
58+
- the code here uses `electron-builder` and `@electron/notarize` and custom webpack scripts to build the final build
59+
- the configs for those are in the package.json
60+
- dependencies that have native code are installed through a postInstall step. and are hence separately mentioned in `release/app/package.json`

package-lock.json

Lines changed: 35 additions & 20 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "requestly",
33
"productName": "Requestly",
4-
"version": "25.11.10",
4+
"version": "25.11.28",
55
"main": "src/main/main.ts",
66
"private": true,
77
"description": "Intercept & Modify HTTP Requests",

release/app/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

release/app/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "requestly",
33
"productName": "Requestly",
4-
"version": "25.11.10",
4+
"version": "25.11.28",
55
"private": true,
66
"description": "Intercept & Modify HTTP Requests",
77
"main": "./dist/main/main.js",

src/lib/autoupdate/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class AutoUpdate {
9393
ipcMain.handle("quit-and-install", () => {
9494
log.info("recieved quit and install")
9595
global.quitAndInstall = true;
96-
let res = autoUpdater.quitAndInstall();
96+
const res = autoUpdater.quitAndInstall();
9797
log.info("finished quit and install", res)
9898
});
9999
};

src/main/actions/cleanup.js

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,31 @@
11
const { app, ipcMain } = require("electron");
22

3-
export const cleanupAndQuit = () => {
4-
cleanup();
5-
6-
if (global.backgroundWindow) {
7-
ipcMain.on("shutdown-success", () => {
8-
console.log("shudown sucess");
9-
app.quit();
10-
});
11-
}
12-
};
13-
143
const cleanup = () => {
15-
if (global.backgroundWindow) {
16-
global.backgroundWindow.webContents.send("shutdown");
4+
if(global.backgroundProcessStarted) {
5+
if (global.backgroundWindow) {
6+
global.backgroundWindow.webContents.send("shutdown");
7+
} else {
8+
// No backgroundWindow. Quit directly without cleanup
9+
app.quit();
10+
}
1711
} else {
18-
// No backgroundWindow. Quit directly without cleanup
1912
app.quit();
2013
}
2114
};
15+
16+
17+
export const getReadyToQuitApp = async () => {
18+
return new Promise((resolve) => {
19+
cleanup();
20+
21+
if (global.backgroundWindow) {
22+
ipcMain.once("shutdown-success", () => {
23+
console.log("shudown sucess");
24+
global.backgroundWindow?.close();
25+
resolve()
26+
});
27+
} else {
28+
resolve();
29+
}
30+
})
31+
};

src/main/actions/getProxiedAxios.ts

Lines changed: 11 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,17 @@ let proxyConfig: ProxyConfig;
3232

3333
function createAxiosInstance(
3434
config: ProxyConfig,
35-
enableRQProxy: boolean = false,
3635
addStoredCookies: boolean = false
3736
): AxiosInstance {
38-
let instance: AxiosInstance;
39-
if (enableRQProxy) {
40-
instance = axios.create({
41-
proxy: false,
42-
httpAgent: new HttpsProxyAgent(`http://${config.ip}:${config.port}`),
43-
httpsAgent: new PatchedHttpsProxyAgent({
44-
host: config.ip,
45-
port: config.port,
46-
ca: readFileSync(config.rootCertPath),
47-
}),
48-
});
49-
} else {
50-
instance = axios.create({
51-
proxy: false,
52-
});
53-
}
37+
const instance = axios.create({
38+
proxy: false,
39+
httpAgent: new HttpsProxyAgent(`http://${config.ip}:${config.port}`),
40+
httpsAgent: new PatchedHttpsProxyAgent({
41+
host: config.ip,
42+
port: config.port,
43+
ca: readFileSync(config.rootCertPath),
44+
}),
45+
});
5446

5547
instance.interceptors.response.use(storeCookiesFromResponse);
5648
if (addStoredCookies) {
@@ -68,8 +60,8 @@ export const createOrUpdateAxiosInstance = (
6860
};
6961

7062
try {
71-
proxiedAxios = createAxiosInstance(proxyConfig, false);
72-
proxiedAxiosWithSessionCookies = createAxiosInstance(proxyConfig, false, true);
63+
proxiedAxios = createAxiosInstance(proxyConfig);
64+
proxiedAxiosWithSessionCookies = createAxiosInstance(proxyConfig, true);
7365
} catch (error) {
7466
/* Do nothing */
7567
console.error("Error creating or updating Axios instance:", error);

src/main/actions/logNetworkRequest.js

Lines changed: 0 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,3 @@
1-
/**
2-
* @param {Array} array into which element will be pushed
3-
* @param {number} required max length of array
4-
* @param {*} element to push
5-
*/
6-
const addToLog = (array, limit, element) => {
7-
const arrayToModify = [...array];
8-
if (arrayToModify.length >= limit) {
9-
arrayToModify.shift();
10-
}
11-
arrayToModify.push(element);
12-
return arrayToModify;
13-
};
14-
151
const logNetworkRequest = (event, message, webAppWindow) => {
162
const newLog = message;
173
if (webAppWindow) {

src/main/actions/logNetworkRequestV2.js

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,6 @@
1-
/**
2-
* @param {Array} array into which element will be pushed
3-
* @param {number} required max length of array
4-
* @param {*} element to push
5-
*/
6-
const addToLog = (array, limit, element) => {
7-
const arrayToModify = [...array];
8-
if (arrayToModify.length >= limit) {
9-
arrayToModify.shift();
10-
}
11-
arrayToModify.push(element);
12-
return arrayToModify;
13-
};
14-
151
const logNetworkRequestV2 = (event, message, webAppWindow) => {
162
const newLog = message;
17-
if (webAppWindow) {
3+
if (webAppWindow && !webAppWindow.isDestroyed()) {
184
webAppWindow.send("log-network-request-v2", newLog);
195
}
206
};

0 commit comments

Comments
 (0)