mirror of
https://github.com/Kong/insomnia.git
synced 2026-10-27 17:19:42 -04:00
Typed preload (#4886)
* convert preload to typescript * preload types second pass * improve types * fix import * simplify types * remove migration map * preload alongside main * naming improvements * fix global typing by adding vite import types * fix test * isolate main only network code * fix mapping mistake * clarify timeline logic
This commit is contained in:
1 parent
4f5ef73f7e
commit
bbceb6097c
30 files changed
+248
-338
No files matched your search
@@ -31,4 +31,3 @@ packages/insomnia-smoke-test/screenshots
|
||||
*.tsbuildinfo
|
||||
dist
|
||||
.history
|
||||
packages/insomnia/src/main.min.js.map
|
||||
@@ -3,3 +3,6 @@ build
|
||||
|
||||
# Generated
|
||||
src/main.min.js
|
||||
src/main.min.js.map
|
||||
src/preload.js
|
||||
src/preload.js.map
|
||||
@@ -31,8 +31,16 @@ export default async function build(options: Options) {
|
||||
'process.env.INSOMNIA_ENV': JSON.stringify('production'),
|
||||
'process.env.BUILD_DATE': JSON.stringify(new Date()),
|
||||
};
|
||||
|
||||
return esbuild.build({
|
||||
const preload = esbuild.build({
|
||||
entryPoints: ['./src/preload.ts'],
|
||||
outfile: path.join(outdir, 'preload.js'),
|
||||
target: 'esnext',
|
||||
bundle: true,
|
||||
platform: 'node',
|
||||
format: 'cjs',
|
||||
external: ['electron'],
|
||||
});
|
||||
const main = esbuild.build({
|
||||
entryPoints: ['./src/main.development.ts'],
|
||||
outfile: path.join(outdir, 'main.min.js'),
|
||||
bundle: true,
|
||||
@@ -47,6 +55,7 @@ export default async function build(options: Options) {
|
||||
...Object.keys(builtinModules),
|
||||
],
|
||||
});
|
||||
return Promise.all([main, preload]);
|
||||
}
|
||||
|
||||
// Build if ran as a cli script
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
import { build } from 'esbuild';
|
||||
import path from 'path';
|
||||
|
||||
const outdir = path.join(__dirname, 'build');
|
||||
|
||||
build({
|
||||
entryPoints: ['./src/preload.ts'],
|
||||
outfile: path.join(outdir, 'preload.js'),
|
||||
bundle: true,
|
||||
platform: 'node',
|
||||
sourcemap: true,
|
||||
format: 'esm',
|
||||
external: ['@getinsomnia/node-libcurl', 'electron'],
|
||||
});
|
||||
@@ -1,5 +1,4 @@
|
||||
import childProcess from 'child_process';
|
||||
import { build } from 'esbuild';
|
||||
import { readFileSync, writeFileSync } from 'fs';
|
||||
import licenseChecker from 'license-checker';
|
||||
import mkdirp from 'mkdirp';
|
||||
@@ -8,7 +7,7 @@ import path from 'path';
|
||||
import rimraf from 'rimraf';
|
||||
import * as vite from 'vite';
|
||||
|
||||
import buildMain from '../esbuild.main';
|
||||
import buildMainAndPreload from '../esbuild.main';
|
||||
|
||||
// Start build if ran from CLI
|
||||
if (require.main === module) {
|
||||
@@ -138,27 +137,11 @@ export const start = async () => {
|
||||
path.join(buildFolder, 'opensource-licenses.txt')
|
||||
);
|
||||
|
||||
console.log('[build] Building main.min.js');
|
||||
await buildMain({
|
||||
console.log('[build] Building main.min.js and preload');
|
||||
await buildMainAndPreload({
|
||||
mode: 'production',
|
||||
});
|
||||
|
||||
console.log('[build] Building preload');
|
||||
await build({
|
||||
entryPoints: [path.join(__dirname, '../src/preload.js')],
|
||||
outfile: path.join(__dirname, '../build/preload.js'),
|
||||
platform: 'node',
|
||||
bundle: true,
|
||||
target: 'esnext',
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
define: {
|
||||
'process.env.NODE_ENV': JSON.stringify('production'),
|
||||
},
|
||||
minify: true,
|
||||
external: ['electron'],
|
||||
});
|
||||
|
||||
console.log('[build] Building renderer');
|
||||
|
||||
await vite.build({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { describe, expect, it, jest } from '@jest/globals';
|
||||
|
||||
import { containsOnlyDeprecationWarnings, isDeprecatedDependencies } from '../plugins/install';
|
||||
import { containsOnlyDeprecationWarnings, isDeprecatedDependencies } from '../main/install-plugin';
|
||||
|
||||
describe('install.js', () => {
|
||||
describe('containsOnlyDeprecationWarning', () => {
|
||||
|
||||
@@ -450,14 +450,3 @@ export const toTitleCase = (value: string) => (
|
||||
.map(capitalize)
|
||||
.join(' ')
|
||||
);
|
||||
|
||||
// Because node-libcurl changed some names that we used in the timeline
|
||||
export const LIBCURL_DEBUG_MIGRATION_MAP = {
|
||||
HeaderIn: 'HEADER_IN',
|
||||
DataIn: 'DATA_IN',
|
||||
SslDataIn: 'SSL_DATA_IN',
|
||||
HeaderOut: 'HEADER_OUT',
|
||||
DataOut: 'DATA_OUT',
|
||||
SslDataOut: 'SSL_DATA_OUT',
|
||||
Text: 'TEXT',
|
||||
} as const;
|
||||
Vendored
+9
-42
@@ -1,11 +1,13 @@
|
||||
declare module '*.svg' {
|
||||
const content: any;
|
||||
export default content;
|
||||
}
|
||||
import type { MainBridgeAPI } from './main/ipc/main';
|
||||
|
||||
declare module '*.png' {
|
||||
const content: any;
|
||||
export default content;
|
||||
declare global {
|
||||
interface Window {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: Function;
|
||||
main: MainBridgeAPI;
|
||||
dialog: Pick<Electron.Dialog, 'showOpenDialog' | 'showSaveDialog'>;
|
||||
app: Pick<Electron.App, 'getPath' | 'getAppPath'>;
|
||||
shell: Pick<Electron.Shell, 'showItemInFolder'>;
|
||||
}
|
||||
}
|
||||
|
||||
declare const __DEV__: boolean;
|
||||
@@ -19,38 +21,3 @@ declare namespace NodeJS {
|
||||
jsyaml: any;
|
||||
}
|
||||
}
|
||||
|
||||
interface Window {
|
||||
__REDUX_DEVTOOLS_EXTENSION_COMPOSE__: Function;
|
||||
main: {
|
||||
restart: () => void;
|
||||
authorizeUserInWindow: (options: { url: string; urlSuccessRegex?: RegExp; urlFailureRegex?: RegExp; sessionId: string }) => Promise<string>;
|
||||
setMenuBarVisibility: (visible: boolean) => void;
|
||||
installPlugin: (url: string) => void;
|
||||
writeFile: (options: {path: string; content: string}) => Promise<string>;
|
||||
cancelCurlRequest: (requestId: string) => void;
|
||||
curlRequest: (options: {
|
||||
curlOptions: CurlOpt[];
|
||||
responseBodyPath: string;
|
||||
maxTimelineDataSizeKB: number;
|
||||
requestId: string;
|
||||
requestBodyPath?: string;
|
||||
isMultipart: boolean;
|
||||
}) => Promise<{
|
||||
patch: ResponsePatch;
|
||||
debugTimeline: ResponseTimelineEntry[];
|
||||
headerResults: HeaderResult[];
|
||||
}>;
|
||||
};
|
||||
dialog: {
|
||||
showOpenDialog: (options: Electron.OpenDialogOptions) => Promise<Electron.OpenDialogReturnValue>;
|
||||
showSaveDialog: (options: Electron.SaveDialogOptions) => Promise<Electron.SaveDialogReturnValue>;
|
||||
};
|
||||
app: {
|
||||
getPath: (name: string) => string;
|
||||
getAppPath: () => string;
|
||||
};
|
||||
shell: {
|
||||
showItemInFolder: (fullPath: string) => void;
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,6 @@
|
||||
import * as electron from 'electron';
|
||||
import electron, { app, ipcMain, session } from 'electron';
|
||||
import contextMenu from 'electron-context-menu';
|
||||
import installExtension, { REACT_DEVELOPER_TOOLS, REDUX_DEVTOOLS } from 'electron-devtools-installer';
|
||||
import { writeFile } from 'fs/promises';
|
||||
import path from 'path';
|
||||
|
||||
import appConfig from '../config/config.json';
|
||||
@@ -11,16 +10,15 @@ import { database } from './common/database';
|
||||
import { disableSpellcheckerDownload } from './common/electron-helpers';
|
||||
import log, { initializeLogging } from './common/log';
|
||||
import { validateInsomniaConfig } from './common/validate-insomnia-config';
|
||||
import * as grpcIpcMain from './main/grpc-ipc-main';
|
||||
import { registerElectronHandlers } from './main/ipc/electron';
|
||||
import { registergRPCHandlers } from './main/ipc/grpc';
|
||||
import { registerMainHandlers } from './main/ipc/main';
|
||||
import { initializeSentry, sentryWatchAnalyticsEnabled } from './main/sentry';
|
||||
import { checkIfRestartNeeded } from './main/squirrel-startup';
|
||||
import * as updates from './main/updates';
|
||||
import * as windowUtils from './main/window-utils';
|
||||
import * as models from './models/index';
|
||||
import type { Stats } from './models/stats';
|
||||
import { cancelCurlRequest, curlRequest } from './network/libcurl-promise';
|
||||
import { authorizeUserInWindow } from './network/o-auth-2/misc';
|
||||
import installPlugin from './plugins/install';
|
||||
import type { ToastNotification } from './ui/components/toast';
|
||||
|
||||
initializeSentry();
|
||||
@@ -31,7 +29,6 @@ if (checkIfRestartNeeded()) {
|
||||
}
|
||||
|
||||
initializeLogging();
|
||||
const { app, ipcMain, session } = electron;
|
||||
const commandLineArgs = process.argv.slice(1);
|
||||
log.info(`Running version ${getAppVersion()}`);
|
||||
|
||||
@@ -61,6 +58,7 @@ app.on('web-contents-created', (_, contents) => {
|
||||
|
||||
// When the app is first launched
|
||||
app.on('ready', async () => {
|
||||
|
||||
const { error } = validateInsomniaConfig();
|
||||
|
||||
if (error) {
|
||||
@@ -69,6 +67,9 @@ app.on('ready', async () => {
|
||||
app.exit(1);
|
||||
return;
|
||||
}
|
||||
registerElectronHandlers();
|
||||
registerMainHandlers();
|
||||
registergRPCHandlers();
|
||||
|
||||
disableSpellcheckerDownload();
|
||||
|
||||
@@ -92,7 +93,6 @@ app.on('ready', async () => {
|
||||
|
||||
// Init the rest
|
||||
await updates.init();
|
||||
grpcIpcMain.init();
|
||||
});
|
||||
|
||||
// Set as default protocol
|
||||
@@ -218,70 +218,6 @@ async function _trackStats() {
|
||||
|
||||
trackSegmentEvent(SegmentEvent.appStarted, {}, { queueable: true });
|
||||
|
||||
ipcMain.handle('showOpenDialog', async (_, options: Electron.OpenDialogOptions) => {
|
||||
const { filePaths, canceled } = await electron.dialog.showOpenDialog(options);
|
||||
return { filePaths, canceled };
|
||||
});
|
||||
|
||||
ipcMain.handle('showSaveDialog', async (_, options: Electron.SaveDialogOptions) => {
|
||||
const { filePath, canceled } = await electron.dialog.showSaveDialog(options);
|
||||
return { filePath, canceled };
|
||||
});
|
||||
|
||||
ipcMain.handle('installPlugin', (_, options) => {
|
||||
return installPlugin(options);
|
||||
});
|
||||
|
||||
ipcMain.on('showItemInFolder', (_, name) => {
|
||||
electron.shell.showItemInFolder(name);
|
||||
});
|
||||
|
||||
ipcMain.on('restart', () => {
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
});
|
||||
|
||||
ipcMain.on('setMenuBarVisibility', (_, visible) => {
|
||||
electron.BrowserWindow.getAllWindows()
|
||||
.forEach(window => {
|
||||
// the `setMenuBarVisibility` signature uses `visible` semantics
|
||||
window.setMenuBarVisibility(visible);
|
||||
// the `setAutoHideMenu` signature uses `hide` semantics
|
||||
const hide = !visible;
|
||||
window.setAutoHideMenuBar(hide);
|
||||
});
|
||||
});
|
||||
|
||||
ipcMain.on('getPath', (event, name) => {
|
||||
event.returnValue = electron.app.getPath(name);
|
||||
});
|
||||
|
||||
ipcMain.on('getAppPath', event => {
|
||||
event.returnValue = electron.app.getAppPath();
|
||||
});
|
||||
|
||||
ipcMain.handle('authorizeUserInWindow', (_, options) => {
|
||||
const { url, urlSuccessRegex, urlFailureRegex, sessionId } = options;
|
||||
return authorizeUserInWindow({ url, urlSuccessRegex, urlFailureRegex, sessionId });
|
||||
});
|
||||
|
||||
ipcMain.handle('writeFile', async (_, options) => {
|
||||
try {
|
||||
await writeFile(options.path, options.content);
|
||||
return options.path;
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('curlRequest', (_, options) => {
|
||||
return curlRequest(options);
|
||||
});
|
||||
|
||||
ipcMain.on('cancelCurlRequest', (_, requestId: string): void => {
|
||||
cancelCurlRequest(requestId);
|
||||
});
|
||||
|
||||
ipcMain.once('window-ready', () => {
|
||||
const { currentVersion, launches, lastVersion } = stats;
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import { ipcMain } from 'electron';
|
||||
import { GrpcRequestEventEnum } from '../../common/grpc-events';
|
||||
import * as grpc from '../../network/grpc';
|
||||
import { ResponseCallbacks } from '../../network/grpc/response-callbacks';
|
||||
import * as grpcIpcMain from '../grpc-ipc-main';
|
||||
import * as grpcIpcMain from '../ipc/grpc';
|
||||
|
||||
jest.mock('../../network/grpc');
|
||||
|
||||
@@ -14,7 +14,7 @@ describe('grpcIpcMain', () => {
|
||||
};
|
||||
const id = 'abc';
|
||||
beforeEach(() => {
|
||||
grpcIpcMain.init(); // ipcMain is mocked
|
||||
grpcIpcMain.registergRPCHandlers(); // ipcMain is mocked
|
||||
});
|
||||
|
||||
it.each(Object.values(GrpcRequestEventEnum))('should add listener for channel: %s', channel => {
|
||||
|
||||
+1
-2
@@ -1,5 +1,6 @@
|
||||
import childProcess from 'child_process';
|
||||
import * as electron from 'electron';
|
||||
import { app } from 'electron';
|
||||
import fs from 'fs';
|
||||
import fsx from 'fs-extra';
|
||||
import mkdirp from 'mkdirp';
|
||||
@@ -248,8 +249,6 @@ export function isDeprecatedDependencies(str: string) {
|
||||
}
|
||||
|
||||
function _getYarnPath() {
|
||||
const { app } = process.type === 'renderer' ? window : electron;
|
||||
|
||||
// TODO: This is brittle. Make finding this more robust.
|
||||
if (isDevelopment()) {
|
||||
return path.resolve(app.getAppPath(), './bin/yarn-standalone.js');
|
||||
@@ -0,0 +1,36 @@
|
||||
import type { OpenDialogOptions, SaveDialogOptions } from 'electron';
|
||||
import { app, BrowserWindow, dialog, ipcMain, shell } from 'electron';
|
||||
|
||||
export function registerElectronHandlers() {
|
||||
ipcMain.on('setMenuBarVisibility', (_, visible: boolean) => {
|
||||
BrowserWindow.getAllWindows()
|
||||
.forEach(window => {
|
||||
// the `setMenuBarVisibility` signature uses `visible` semantics
|
||||
window.setMenuBarVisibility(visible);
|
||||
// the `setAutoHideMenu` signature uses `hide` semantics
|
||||
const hide = !visible;
|
||||
window.setAutoHideMenuBar(hide);
|
||||
});
|
||||
});
|
||||
ipcMain.handle('showOpenDialog', async (_, options: OpenDialogOptions) => {
|
||||
const { filePaths, canceled } = await dialog.showOpenDialog(options);
|
||||
return { filePaths, canceled };
|
||||
});
|
||||
|
||||
ipcMain.handle('showSaveDialog', async (_, options: SaveDialogOptions) => {
|
||||
const { filePath, canceled } = await dialog.showSaveDialog(options);
|
||||
return { filePath, canceled };
|
||||
});
|
||||
|
||||
ipcMain.on('showItemInFolder', (_, name: string) => {
|
||||
shell.showItemInFolder(name);
|
||||
});
|
||||
|
||||
ipcMain.on('getPath', (event, name: Parameters<typeof Electron.app['getPath']>[0]) => {
|
||||
event.returnValue = app.getPath(name);
|
||||
});
|
||||
|
||||
ipcMain.on('getAppPath', event => {
|
||||
event.returnValue = app.getAppPath();
|
||||
});
|
||||
}
|
||||
+5
-5
@@ -1,11 +1,11 @@
|
||||
import { ipcMain } from 'electron';
|
||||
|
||||
import { GrpcRequestEventEnum } from '../common/grpc-events';
|
||||
import * as grpc from '../network/grpc';
|
||||
import { GrpcIpcRequestParams } from '../network/grpc/prepare';
|
||||
import { ResponseCallbacks } from '../network/grpc/response-callbacks';
|
||||
import { GrpcRequestEventEnum } from '../../common/grpc-events';
|
||||
import * as grpc from '../../network/grpc';
|
||||
import { GrpcIpcRequestParams } from '../../network/grpc/prepare';
|
||||
import { ResponseCallbacks } from '../../network/grpc/response-callbacks';
|
||||
|
||||
export function init() {
|
||||
export function registergRPCHandlers() {
|
||||
ipcMain.on(GrpcRequestEventEnum.start, (event, params: GrpcIpcRequestParams) =>
|
||||
grpc.start(params, new ResponseCallbacks(event)),
|
||||
);
|
||||
@@ -0,0 +1,47 @@
|
||||
import { app, ipcMain } from 'electron';
|
||||
import { writeFile } from 'fs/promises';
|
||||
|
||||
import { authorizeUserInWindow } from '../../network/o-auth-2/misc';
|
||||
import installPlugin from '../install-plugin';
|
||||
import { cancelCurlRequest, curlRequest } from '../network/libcurl-promise';
|
||||
|
||||
export interface MainBridgeAPI {
|
||||
restart: () => void;
|
||||
authorizeUserInWindow: typeof authorizeUserInWindow;
|
||||
setMenuBarVisibility: (visible: boolean) => void;
|
||||
installPlugin: typeof installPlugin;
|
||||
writeFile: (options: { path: string; content: string }) => Promise<string>;
|
||||
cancelCurlRequest: typeof cancelCurlRequest;
|
||||
curlRequest: typeof curlRequest;
|
||||
}
|
||||
export function registerMainHandlers() {
|
||||
ipcMain.handle('authorizeUserInWindow', (_, options: Parameters<typeof authorizeUserInWindow>[0]) => {
|
||||
const { url, urlSuccessRegex, urlFailureRegex, sessionId } = options;
|
||||
return authorizeUserInWindow({ url, urlSuccessRegex, urlFailureRegex, sessionId });
|
||||
});
|
||||
|
||||
ipcMain.handle('writeFile', async (_, options: { path: string; content: string }) => {
|
||||
try {
|
||||
await writeFile(options.path, options.content);
|
||||
return options.path;
|
||||
} catch (err) {
|
||||
throw new Error(err);
|
||||
}
|
||||
});
|
||||
|
||||
ipcMain.handle('curlRequest', (_, options: Parameters<typeof curlRequest>[0]) => {
|
||||
return curlRequest(options);
|
||||
});
|
||||
|
||||
ipcMain.on('cancelCurlRequest', (_, requestId: string): void => {
|
||||
cancelCurlRequest(requestId);
|
||||
});
|
||||
|
||||
ipcMain.handle('installPlugin', (_, lookupName: string) => {
|
||||
return installPlugin(lookupName);
|
||||
});
|
||||
ipcMain.on('restart', () => {
|
||||
app.relaunch();
|
||||
app.exit();
|
||||
});
|
||||
}
|
||||
+46
-38
@@ -11,17 +11,15 @@ import mkdirp from 'mkdirp';
|
||||
import path from 'path';
|
||||
import { Readable, Writable } from 'stream';
|
||||
import tls from 'tls';
|
||||
import { ValueOf } from 'type-fest';
|
||||
import { parse as urlParse } from 'url';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
|
||||
import { version } from '../../package.json';
|
||||
import { AUTH_AWS_IAM, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED } from '../common/constants';
|
||||
import { describeByteSize, hasAuthHeader, hasUserAgentHeader } from '../common/misc';
|
||||
import { ClientCertificate } from '../models/client-certificate';
|
||||
import { ResponseHeader } from '../models/response';
|
||||
import { version } from '../../../package.json';
|
||||
import { AUTH_AWS_IAM, AUTH_DIGEST, AUTH_NETRC, AUTH_NTLM, CONTENT_TYPE_FORM_DATA, CONTENT_TYPE_FORM_URLENCODED } from '../../common/constants';
|
||||
import { describeByteSize, hasAuthHeader, hasUserAgentHeader } from '../../common/misc';
|
||||
import { ClientCertificate } from '../../models/client-certificate';
|
||||
import { ResponseHeader } from '../../models/response';
|
||||
import { buildMultipart } from './multipart';
|
||||
import { ResponsePatch } from './network';
|
||||
import { parseHeaderStrings } from './parse-header-strings';
|
||||
|
||||
interface CurlRequestOptions {
|
||||
@@ -57,8 +55,9 @@ interface SettingsUsedHere {
|
||||
httpsProxy: string;
|
||||
noProxy: string;
|
||||
}
|
||||
interface ResponseTimelineEntry {
|
||||
name: ValueOf<typeof LIBCURL_DEBUG_MIGRATION_MAP>;
|
||||
|
||||
export interface ResponseTimelineEntry {
|
||||
name: keyof typeof CurlInfoDebug;
|
||||
timestamp: number;
|
||||
value: string;
|
||||
}
|
||||
@@ -70,6 +69,26 @@ interface CurlRequestOutput {
|
||||
responseBodyPath?: string;
|
||||
}
|
||||
|
||||
export interface ResponsePatch {
|
||||
bodyCompression?: 'zip' | null;
|
||||
bodyPath?: string;
|
||||
bytesContent?: number;
|
||||
bytesRead?: number;
|
||||
contentType?: string;
|
||||
elapsedTime: number;
|
||||
environmentId?: string | null;
|
||||
error?: string;
|
||||
headers?: ResponseHeader[];
|
||||
httpVersion?: string;
|
||||
message?: string;
|
||||
parentId?: string;
|
||||
settingSendCookies?: boolean;
|
||||
settingStoreCookies?: boolean;
|
||||
statusCode?: number;
|
||||
statusMessage?: string;
|
||||
timelinePath?: string;
|
||||
url?: string;
|
||||
}
|
||||
const getDataDirectory = () => process.env.INSOMNIA_DATA_PATH || electron.app.getPath('userData');
|
||||
|
||||
// NOTE: this is a dictionary of functions to close open listeners
|
||||
@@ -99,23 +118,23 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
if (cert) {
|
||||
curl.setOpt(Curl.option.SSLCERT, cert);
|
||||
curl.setOpt(Curl.option.SSLCERTTYPE, 'PEM');
|
||||
debugTimeline.push({ value: 'Adding SSL PEM certificate', name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: 'Adding SSL PEM certificate', name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
if (pfx) {
|
||||
curl.setOpt(Curl.option.SSLCERT, pfx);
|
||||
curl.setOpt(Curl.option.SSLCERTTYPE, 'P12');
|
||||
debugTimeline.push({ value: 'Adding SSL P12 certificate', name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: 'Adding SSL P12 certificate', name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
if (key) {
|
||||
curl.setOpt(Curl.option.SSLKEY, key);
|
||||
debugTimeline.push({ value: 'Adding SSL KEY certificate', name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: 'Adding SSL KEY certificate', name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
if (passphrase) {
|
||||
curl.setOpt(Curl.option.KEYPASSWD, passphrase);
|
||||
}
|
||||
});
|
||||
const httpVersion = getHttpVersion(settings.preferredHttpVersion);
|
||||
debugTimeline.push({ value: httpVersion.log, name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: httpVersion.log, name: 'Text', timestamp: Date.now() });
|
||||
|
||||
if (httpVersion.curlHttpVersion) {
|
||||
curl.setOpt(Curl.option.HTTP_VERSION, httpVersion.curlHttpVersion);
|
||||
@@ -134,7 +153,7 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
const { httpProxy, httpsProxy, noProxy } = settings;
|
||||
const proxyHost = protocol === 'https:' ? httpsProxy : httpProxy;
|
||||
const proxy = proxyHost ? setDefaultProtocol(proxyHost) : null;
|
||||
debugTimeline.push({ value: `Enable network proxy for ${protocol || ''}`, name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: `Enable network proxy for ${protocol || ''}`, name: 'Text', timestamp: Date.now() });
|
||||
if (proxy) {
|
||||
curl.setOpt(Curl.option.PROXY, proxy);
|
||||
curl.setOpt(Curl.option.PROXYAUTH, CurlAuth.Any);
|
||||
@@ -148,14 +167,14 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
curl.setOpt(Curl.option.TIMEOUT_MS, 0);
|
||||
} else {
|
||||
curl.setOpt(Curl.option.TIMEOUT_MS, timeout);
|
||||
debugTimeline.push({ value: `Enable timeout of ${timeout}ms`, name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: `Enable timeout of ${timeout}ms`, name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
const { validateSSL } = settings;
|
||||
if (!validateSSL) {
|
||||
curl.setOpt(Curl.option.SSL_VERIFYHOST, 0);
|
||||
curl.setOpt(Curl.option.SSL_VERIFYPEER, 0);
|
||||
}
|
||||
debugTimeline.push({ value: `${validateSSL ? 'Enable' : 'Disable'} SSL validation`, name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: `${validateSSL ? 'Enable' : 'Disable'} SSL validation`, name: 'Text', timestamp: Date.now() });
|
||||
|
||||
if (req.settingFollowRedirects === 'off') {
|
||||
curl.setOpt(Curl.option.FOLLOWLOCATION, false);
|
||||
@@ -178,7 +197,7 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
}
|
||||
// set-cookies from previous redirects
|
||||
if (cookieJar.cookies.length) {
|
||||
debugTimeline.push({ value: `Enable cookie sending with jar of ${cookieJar.cookies.length} cookie${cookieJar.cookies.length !== 1 ? 's' : ''}`, name: 'TEXT', timestamp: Date.now() });
|
||||
debugTimeline.push({ value: `Enable cookie sending with jar of ${cookieJar.cookies.length} cookie${cookieJar.cookies.length !== 1 ? 's' : ''}`, name: 'Text', timestamp: Date.now() });
|
||||
for (const cookie of cookieJar.cookies) {
|
||||
const setCookie = [
|
||||
cookie.httpOnly ? `#HttpOnly_${cookie.domain}` : cookie.domain,
|
||||
@@ -277,21 +296,22 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: resolves "Text" from CurlInfoDebug[CurlInfoDebug.Text]
|
||||
let name = CurlInfoDebug[infoType] as keyof typeof CurlInfoDebug;
|
||||
let timelineMessage;
|
||||
if (infoType === CurlInfoDebug.DataOut) {
|
||||
const isRequestData = infoType === CurlInfoDebug.DataOut;
|
||||
if (isRequestData) {
|
||||
// Ignore large post data messages
|
||||
const isLessThan10KB = buffer.length / 1024 < (settings.maxTimelineDataSizeKB || 1);
|
||||
timelineMessage = isLessThan10KB ? buffer.toString('utf8') : `(${describeByteSize(buffer.length)} hidden)`;
|
||||
}
|
||||
if (infoType === CurlInfoDebug.DataIn) {
|
||||
const isResponseData = infoType === CurlInfoDebug.DataIn;
|
||||
if (isResponseData) {
|
||||
timelineMessage = `Received ${describeByteSize(buffer.length)} chunk`;
|
||||
name = 'Text';
|
||||
}
|
||||
|
||||
debugTimeline.push({
|
||||
name: infoType === CurlInfoDebug.DataIn ? 'TEXT' : LIBCURL_DEBUG_MIGRATION_MAP[CurlInfoDebug[infoType]],
|
||||
value: timelineMessage || buffer.toString('utf8'),
|
||||
timestamp: Date.now(),
|
||||
});
|
||||
const value = timelineMessage || buffer.toString('utf8');
|
||||
debugTimeline.push({ name, value, timestamp: Date.now() });
|
||||
return 0;
|
||||
});
|
||||
|
||||
@@ -300,7 +320,7 @@ export const curlRequest = (options: CurlRequestOptions) => new Promise<CurlRequ
|
||||
curl.enable(CurlFeature.Raw);
|
||||
// NOTE: legacy write end callback
|
||||
curl.on('end', () => responseBodyWriteStream.end());
|
||||
curl.on('end', async (_1, _2, rawHeaders: Buffer) => {
|
||||
curl.on('end', async (_1: any, _2: any, rawHeaders: Buffer) => {
|
||||
const patch = {
|
||||
bytesContent: responseBodyBytes,
|
||||
bytesRead: curl.getInfo(Curl.info.SIZE_DOWNLOAD) as number,
|
||||
@@ -357,18 +377,6 @@ const closeReadFunction = (fd: number, isMultipart: boolean, path?: string) => {
|
||||
}
|
||||
};
|
||||
|
||||
// Because node-libcurl changed some names that we used in the timeline
|
||||
const LIBCURL_DEBUG_MIGRATION_MAP: Record<string, string> = {
|
||||
HeaderIn: 'HEADER_IN',
|
||||
DataIn: 'DATA_IN',
|
||||
SslDataIn: 'SSL_DATA_IN',
|
||||
HeaderOut: 'HEADER_OUT',
|
||||
DataOut: 'DATA_OUT',
|
||||
SslDataOut: 'SSL_DATA_OUT',
|
||||
Text: 'TEXT',
|
||||
'': '',
|
||||
};
|
||||
|
||||
interface HeaderResult {
|
||||
headers: ResponseHeader[];
|
||||
version: string;
|
||||
+1
-1
@@ -7,7 +7,7 @@ import { lookup } from 'mime-types';
|
||||
import os from 'os';
|
||||
import path from 'path';
|
||||
|
||||
import type { RequestBodyParameter } from '../models/request';
|
||||
import type { RequestBodyParameter } from '../../models/request';
|
||||
|
||||
export const DEFAULT_BOUNDARY = 'X-INSOMNIA-BOUNDARY';
|
||||
|
||||
+2
-2
@@ -7,7 +7,7 @@ import {
|
||||
AUTH_DIGEST,
|
||||
AUTH_NTLM,
|
||||
CONTENT_TYPE_FORM_DATA,
|
||||
} from '../common/constants';
|
||||
} from '../../common/constants';
|
||||
import {
|
||||
getContentTypeHeader,
|
||||
getHostHeader,
|
||||
@@ -15,7 +15,7 @@ import {
|
||||
hasAcceptHeader,
|
||||
hasAuthHeader,
|
||||
hasContentTypeHeader,
|
||||
} from '../common/misc';
|
||||
} from '../../common/misc';
|
||||
import { DEFAULT_BOUNDARY } from './multipart';
|
||||
|
||||
// Special header value that will prevent the header being sent
|
||||
@@ -1,10 +1,9 @@
|
||||
import fs from 'fs';
|
||||
import { Readable } from 'stream';
|
||||
import { ValueOf } from 'type-fest';
|
||||
import zlib from 'zlib';
|
||||
|
||||
import { database as db, Query } from '../common/database';
|
||||
import { LIBCURL_DEBUG_MIGRATION_MAP } from '../common/misc';
|
||||
import type { ResponseTimelineEntry } from '../main/network/libcurl-promise';
|
||||
import type { BaseModel } from './index';
|
||||
import * as models from './index';
|
||||
|
||||
@@ -23,12 +22,6 @@ export interface ResponseHeader {
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface ResponseTimelineEntry {
|
||||
name: ValueOf<typeof LIBCURL_DEBUG_MIGRATION_MAP>;
|
||||
timestamp: number;
|
||||
value: string;
|
||||
}
|
||||
|
||||
type Compression = 'zip' | null | '__NEEDS_MIGRATION__' | undefined;
|
||||
|
||||
export interface BaseResponse {
|
||||
@@ -234,7 +227,7 @@ export function getTimeline(response: Response, showBody?: boolean) {
|
||||
const timeline = JSON.parse(rawBuffer.toString()) as ResponseTimelineEntry[];
|
||||
const body: ResponseTimelineEntry[] = showBody ? [
|
||||
{
|
||||
name: LIBCURL_DEBUG_MIGRATION_MAP.DataOut,
|
||||
name: 'DataOut',
|
||||
timestamp: Date.now(),
|
||||
value: fs.readFileSync(bodyPath).toString(),
|
||||
},
|
||||
|
||||
@@ -4,7 +4,7 @@ import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import { globalBeforeEach } from '../../__jest__/before-each';
|
||||
import { buildMultipart, DEFAULT_BOUNDARY } from '../multipart';
|
||||
import { buildMultipart, DEFAULT_BOUNDARY } from '../../main/network/multipart';
|
||||
|
||||
window.app = electron.app;
|
||||
|
||||
|
||||
@@ -17,12 +17,12 @@ import {
|
||||
} from '../../common/constants';
|
||||
import { filterHeaders } from '../../common/misc';
|
||||
import { getRenderedRequestAndContext } from '../../common/render';
|
||||
import { _parseHeaders, getHttpVersion } from '../../main/network/libcurl-promise';
|
||||
import { DEFAULT_BOUNDARY } from '../../main/network/multipart';
|
||||
import { _getAwsAuthHeaders } from '../../main/network/parse-header-strings';
|
||||
import * as models from '../../models';
|
||||
import { _parseHeaders, getHttpVersion } from '../libcurl-promise';
|
||||
import { DEFAULT_BOUNDARY } from '../multipart';
|
||||
import * as networkUtils from '../network';
|
||||
import { getSetCookiesFromResponseHeaders } from '../network';
|
||||
import { _getAwsAuthHeaders } from '../parse-header-strings';
|
||||
|
||||
window.app = electron.app;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { describe, expect, it } from '@jest/globals';
|
||||
|
||||
import { AUTH_AWS_IAM, CONTENT_TYPE_FORM_DATA } from '../../common/constants';
|
||||
import { parseHeaderStrings } from '../parse-header-strings';
|
||||
import { parseHeaderStrings } from '../../main/network/parse-header-strings';
|
||||
|
||||
describe('parseHeaderStrings', () => {
|
||||
it('should default with empty inputs', () => {
|
||||
|
||||
@@ -25,7 +25,7 @@ export async function getAuthHeader(renderedRequest: RenderedRequest, url: strin
|
||||
const requestId = renderedRequest._id;
|
||||
|
||||
if (authentication.disabled) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
if (authentication.type === AUTH_BASIC) {
|
||||
@@ -51,7 +51,7 @@ export async function getAuthHeader(renderedRequest: RenderedRequest, url: strin
|
||||
const token = oAuth2Token.accessToken;
|
||||
return _buildBearerHeader(token, authentication.tokenPrefix);
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ export async function getAuthHeader(renderedRequest: RenderedRequest, url: strin
|
||||
value: oAuth1Token.Authorization,
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,12 +138,12 @@ export async function getAuthHeader(renderedRequest: RenderedRequest, url: strin
|
||||
});
|
||||
}
|
||||
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
export const _buildBearerHeader = (accessToken: string, prefix: string) => {
|
||||
if (!accessToken) {
|
||||
return null;
|
||||
return;
|
||||
}
|
||||
|
||||
const header = {
|
||||
|
||||
@@ -28,11 +28,11 @@ import {
|
||||
RENDER_PURPOSE_NO_RENDER,
|
||||
RENDER_PURPOSE_SEND,
|
||||
} from '../common/render';
|
||||
import type { ResponsePatch, ResponseTimelineEntry } from '../main/network/libcurl-promise';
|
||||
import * as models from '../models';
|
||||
import { ClientCertificate } from '../models/client-certificate';
|
||||
import type { Environment } from '../models/environment';
|
||||
import type { Request } from '../models/request';
|
||||
import type { ResponseHeader, ResponseTimelineEntry } from '../models/response';
|
||||
import type { Settings } from '../models/settings';
|
||||
import { isWorkspace } from '../models/workspace';
|
||||
import * as pluginContexts from '../plugins/context/index';
|
||||
@@ -40,27 +40,6 @@ import * as plugins from '../plugins/index';
|
||||
import { getAuthHeader } from './authentication';
|
||||
import { urlMatchesCertHost } from './url-matches-cert-host';
|
||||
|
||||
export interface ResponsePatch {
|
||||
bodyCompression?: 'zip' | null;
|
||||
bodyPath?: string;
|
||||
bytesContent?: number;
|
||||
bytesRead?: number;
|
||||
contentType?: string;
|
||||
elapsedTime: number;
|
||||
environmentId?: string | null;
|
||||
error?: string;
|
||||
headers?: ResponseHeader[];
|
||||
httpVersion?: string;
|
||||
message?: string;
|
||||
parentId?: string;
|
||||
settingSendCookies?: boolean;
|
||||
settingStoreCookies?: boolean;
|
||||
statusCode?: number;
|
||||
statusMessage?: string;
|
||||
timelinePath?: string;
|
||||
url?: string;
|
||||
}
|
||||
|
||||
// Time since user's last keypress to wait before making the request
|
||||
const MAX_DELAY_TIME = 1000;
|
||||
|
||||
@@ -95,8 +74,8 @@ export async function _actuallySend(
|
||||
// NOTE: conditionally use ipc bridge, renderer cannot import native modules directly
|
||||
const nodejsCancelCurlRequest = process.type === 'renderer'
|
||||
? window.main.cancelCurlRequest
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
: require('./libcurl-promise').cancelCurlRequest;
|
||||
: (await import('../main/network/libcurl-promise')).cancelCurlRequest;
|
||||
|
||||
nodejsCancelCurlRequest(renderedRequest._id);
|
||||
return resolve({
|
||||
elapsedTime: 0,
|
||||
@@ -122,12 +101,12 @@ export async function _actuallySend(
|
||||
const socketUrl = (match && match[3]) || '';
|
||||
finalUrl = `${protocol}//${socketUrl}`;
|
||||
}
|
||||
timeline.push({ value: `Preparing request to ${finalUrl}`, name: 'TEXT', timestamp: Date.now() });
|
||||
timeline.push({ value: `Current time is ${new Date().toISOString()}`, name: 'TEXT', timestamp: Date.now() });
|
||||
timeline.push({ value: `${renderedRequest.settingEncodeUrl ? 'Enable' : 'Disable'} automatic URL encoding`, name: 'TEXT', timestamp: Date.now() });
|
||||
timeline.push({ value: `Preparing request to ${finalUrl}`, name: 'Text', timestamp: Date.now() });
|
||||
timeline.push({ value: `Current time is ${new Date().toISOString()}`, name: 'Text', timestamp: Date.now() });
|
||||
timeline.push({ value: `${renderedRequest.settingEncodeUrl ? 'Enable' : 'Disable'} automatic URL encoding`, name: 'Text', timestamp: Date.now() });
|
||||
|
||||
if (!renderedRequest.settingSendCookies) {
|
||||
timeline.push({ value: 'Disable cookie sending due to user setting', name: 'TEXT', timestamp: Date.now() });
|
||||
timeline.push({ value: 'Disable cookie sending due to user setting', name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
|
||||
const certificates = clientCertificates.filter(c => !c.disabled && urlMatchesCertHost(setDefaultProtocol(c.host, 'https:'), renderedRequest.url));
|
||||
@@ -137,8 +116,8 @@ export async function _actuallySend(
|
||||
// NOTE: conditionally use ipc bridge, renderer cannot import native modules directly
|
||||
const nodejsCurlRequest = process.type === 'renderer'
|
||||
? window.main.curlRequest
|
||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||
: require('./libcurl-promise').curlRequest;
|
||||
: (await import('../main/network/libcurl-promise')).curlRequest;
|
||||
|
||||
const requestOptions = {
|
||||
requestId: renderedRequest._id,
|
||||
req: renderedRequest,
|
||||
@@ -160,11 +139,11 @@ export async function _actuallySend(
|
||||
if (totalSetCookies) {
|
||||
const currentUrl = getCurrentUrl({ headerResults, finalUrl });
|
||||
const { cookies, rejectedCookies } = await addSetCookiesToToughCookieJar({ setCookieStrings, currentUrl, cookieJar });
|
||||
rejectedCookies.forEach(errorMessage => timeline.push({ value: `Rejected cookie: ${errorMessage}`, name: 'TEXT', timestamp: Date.now() }));
|
||||
rejectedCookies.forEach(errorMessage => timeline.push({ value: `Rejected cookie: ${errorMessage}`, name: 'Text', timestamp: Date.now() }));
|
||||
const hasCookiesToPersist = totalSetCookies > rejectedCookies.length;
|
||||
if (hasCookiesToPersist) {
|
||||
await models.cookieJar.update(cookieJar, { cookies });
|
||||
timeline.push({ value: `Saved ${totalSetCookies} cookies`, name: 'TEXT', timestamp: Date.now() });
|
||||
timeline.push({ value: `Saved ${totalSetCookies} cookies`, name: 'Text', timestamp: Date.now() });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
const { contextBridge, ipcRenderer } = require('electron');
|
||||
|
||||
const main = {
|
||||
restart: () => ipcRenderer.send('restart'),
|
||||
authorizeUserInWindow: (/** @type {any} */ options) => ipcRenderer.invoke('authorizeUserInWindow', options),
|
||||
setMenuBarVisibility: (/** @type {any} */ options) => ipcRenderer.send('setMenuBarVisibility', options),
|
||||
installPlugin: (/** @type {any} */ options) => ipcRenderer.invoke('installPlugin', options),
|
||||
curlRequest: (/** @type {any} */ options) => ipcRenderer.invoke('curlRequest', options),
|
||||
cancelCurlRequest: (/** @type {any} */ options) => ipcRenderer.send('cancelCurlRequest', options),
|
||||
writeFile: (/** @type {any} */ options) => ipcRenderer.invoke('writeFile', options),
|
||||
};
|
||||
const dialog = {
|
||||
showOpenDialog: (/** @type {any} */ options) => ipcRenderer.invoke('showOpenDialog', options),
|
||||
showSaveDialog: (/** @type {any} */ options) => ipcRenderer.invoke('showSaveDialog', options),
|
||||
};
|
||||
const app = {
|
||||
getPath: (/** @type {any} */ options) => ipcRenderer.sendSync('getPath', options),
|
||||
getAppPath: (/** @type {any} */ options) => ipcRenderer.sendSync('getAppPath', options),
|
||||
};
|
||||
const shell = {
|
||||
showItemInFolder: (/** @type {any} */ options) => ipcRenderer.send('showItemInFolder', options),
|
||||
};
|
||||
|
||||
if (process.contextIsolated) {
|
||||
contextBridge.exposeInMainWorld('main', main);
|
||||
contextBridge.exposeInMainWorld('dialog', dialog);
|
||||
contextBridge.exposeInMainWorld('app', app);
|
||||
contextBridge.exposeInMainWorld('shell', shell);
|
||||
} else {
|
||||
window.main = main;
|
||||
window.dialog = dialog;
|
||||
window.app = app;
|
||||
window.shell = shell;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { contextBridge, ipcRenderer } from 'electron';
|
||||
|
||||
const main: Window['main'] = {
|
||||
restart: () => ipcRenderer.send('restart'),
|
||||
authorizeUserInWindow: options => ipcRenderer.invoke('authorizeUserInWindow', options),
|
||||
setMenuBarVisibility: options => ipcRenderer.send('setMenuBarVisibility', options),
|
||||
installPlugin: options => ipcRenderer.invoke('installPlugin', options),
|
||||
curlRequest: options => ipcRenderer.invoke('curlRequest', options),
|
||||
cancelCurlRequest: options => ipcRenderer.send('cancelCurlRequest', options),
|
||||
writeFile: options => ipcRenderer.invoke('writeFile', options),
|
||||
};
|
||||
const dialog: Window['dialog'] = {
|
||||
showOpenDialog: options => ipcRenderer.invoke('showOpenDialog', options),
|
||||
showSaveDialog: options => ipcRenderer.invoke('showSaveDialog', options),
|
||||
};
|
||||
const app: Window['app'] = {
|
||||
getPath: options => ipcRenderer.sendSync('getPath', options),
|
||||
getAppPath: () => ipcRenderer.sendSync('getAppPath'),
|
||||
};
|
||||
const shell: Window['shell'] = {
|
||||
showItemInFolder: options => ipcRenderer.send('showItemInFolder', options),
|
||||
};
|
||||
|
||||
if (process.contextIsolated) {
|
||||
contextBridge.exposeInMainWorld('main', main);
|
||||
contextBridge.exposeInMainWorld('dialog', dialog);
|
||||
contextBridge.exposeInMainWorld('app', app);
|
||||
contextBridge.exposeInMainWorld('shell', shell);
|
||||
} else {
|
||||
window.main = main;
|
||||
window.dialog = dialog;
|
||||
window.app = app;
|
||||
window.shell = shell;
|
||||
}
|
||||
@@ -21,12 +21,12 @@ import { hotKeyRefs } from '../../../../common/hotkeys';
|
||||
import { executeHotKey } from '../../../../common/hotkeys-listener';
|
||||
import { markdownToHTML } from '../../../../common/markdown-to-html';
|
||||
import { jsonParseOr } from '../../../../common/misc';
|
||||
import type { ResponsePatch } from '../../../../main/network/libcurl-promise';
|
||||
import * as models from '../../../../models/index';
|
||||
import type { Request } from '../../../../models/request';
|
||||
import { newBodyRaw } from '../../../../models/request';
|
||||
import type { Settings } from '../../../../models/settings';
|
||||
import type { Workspace } from '../../../../models/workspace';
|
||||
import type { ResponsePatch } from '../../../../network/network';
|
||||
import * as network from '../../../../network/network';
|
||||
import { Dropdown } from '../../base/dropdown/dropdown';
|
||||
import { DropdownButton } from '../../base/dropdown/dropdown-button';
|
||||
|
||||
@@ -136,7 +136,7 @@ export class ResponsePane extends PureComponent<Props> {
|
||||
|
||||
const timeline = models.response.getTimeline(response);
|
||||
const headers = timeline
|
||||
.filter(v => v.name === 'HEADER_IN')
|
||||
.filter(v => v.name === 'HeaderIn')
|
||||
.map(v => v.value)
|
||||
.join('');
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import React, { PureComponent } from 'react';
|
||||
|
||||
import { clickLink } from '../../../common/electron-helpers';
|
||||
import { LIBCURL_DEBUG_MIGRATION_MAP } from '../../../common/misc';
|
||||
import type { ResponseTimelineEntry } from '../../../main/network/libcurl-promise';
|
||||
import * as models from '../../../models';
|
||||
import { Response, ResponseTimelineEntry } from '../../../models/response';
|
||||
import type { Response } from '../../../models/response';
|
||||
import { CodeEditor } from '../codemirror/code-editor';
|
||||
|
||||
interface Props {
|
||||
@@ -47,40 +47,16 @@ export class ResponseTimelineViewer extends PureComponent<Props, State> {
|
||||
renderRow(row: ResponseTimelineEntry, i: number, all: ResponseTimelineEntry[]) {
|
||||
const { name, value } = row;
|
||||
const previousName = i > 0 ? all[i - 1].name : '';
|
||||
let prefix: string | null = null;
|
||||
|
||||
switch (name) {
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.HeaderIn:
|
||||
prefix = '< ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.DataIn:
|
||||
prefix = '| ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.SslDataIn:
|
||||
prefix = '<< ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.HeaderOut:
|
||||
prefix = '> ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.DataOut:
|
||||
prefix = '| ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.SslDataOut:
|
||||
prefix = '>> ';
|
||||
break;
|
||||
|
||||
case LIBCURL_DEBUG_MIGRATION_MAP.Text:
|
||||
prefix = '* ';
|
||||
break;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
const prefixLookup: Record<ResponseTimelineEntry['name'], string> = {
|
||||
HeaderIn: '< ',
|
||||
DataIn: '| ',
|
||||
SslDataIn: '<< ',
|
||||
HeaderOut: '> ',
|
||||
DataOut: '| ',
|
||||
SslDataOut: '>> ',
|
||||
Text: '* ',
|
||||
};
|
||||
const prefix: string = prefixLookup[name] || '* ';
|
||||
|
||||
const lines = (value + '').replace(/\n$/, '').split('\n');
|
||||
const newLines = lines.filter(l => !l.match(/^\s*$/)).map(l => `${prefix}${l}`);
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
"jsx": "react",
|
||||
"experimentalDecorators": true,
|
||||
"skipLibCheck": true,
|
||||
"types": ["node"],
|
||||
"types": ["node", "vite/client"],
|
||||
},
|
||||
"include": [
|
||||
"**/*.d.ts",
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
"package.json",
|
||||
"scripts",
|
||||
"send-request",
|
||||
"vite.config.ts",
|
||||
"vite.config.ts"
|
||||
],
|
||||
"exclude": [
|
||||
"**/@types/mocha",
|
||||
|
||||
Reference in new issue
Block a user