chore: reformat

This commit is contained in:
Siddharth Gelera
2025-09-25 15:15:14 +05:30
parent 6188a65b13
commit f962a2c04a
56 changed files with 755 additions and 854 deletions

View File

@@ -237,12 +237,12 @@ export default class CodeEditor extends React.Component {
this.editor.scrollTo(null, this.props.initialScroll);
}
if (this.props.enableLineWrapping !== prevProps.enableLineWrapping){
this.editor.setOption("lineWrapping", this.props.enableLineWrapping);
if (this.props.enableLineWrapping !== prevProps.enableLineWrapping) {
this.editor.setOption('lineWrapping', this.props.enableLineWrapping);
}
if (this.props.mode !== prevProps.mode){
this.editor.setOption("mode", this.props.mode);
if (this.props.mode !== prevProps.mode) {
this.editor.setOption('mode', this.props.mode);
}
this.ignoreChangeEvent = false;

View File

@@ -18,7 +18,7 @@ const BETA_FEATURES = [
{
id: 'websocket',
label: 'Web Socket Support',
description: 'Enable Web Socket request support for making realtime calls to services'
description: 'Enable Web Socket request support for making realtime calls to services',
},
{
id: 'nodevm',

View File

@@ -58,16 +58,18 @@ const ToggleSelector = ({
/>
</button>
{(label || description)
&& <div className="flex flex-col">
<label className="text-xs font-medium text-gray-900 dark:text-gray-100">
{label}
</label>
{description && (
<p className="text-xs text-gray-700 dark:text-gray-400">
{description}
</p>
&& (
<div className="flex flex-col">
<label className="text-xs font-medium text-gray-900 dark:text-gray-100">
{label}
</label>
{description && (
<p className="text-xs text-gray-700 dark:text-gray-400">
{description}
</p>
)}
</div>
)}
</div>}
</div>
);
};

View File

@@ -20,12 +20,12 @@ const StyledWrapper = styled.div`
}
&.active {
color: ${(props) => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important;
color: ${props => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${props => props.theme.tabs.active.border} !important;
}
.content-indicator {
color: ${(props) => props.theme.text}
color: ${props => props.theme.text}
}
}
}

View File

@@ -2,7 +2,7 @@ import styled from 'styled-components';
const Wrapper = styled.div`
.inherit-mode-text {
color: ${(props) => props.theme.colors.text.yellow};
color: ${props => props.theme.colors.text.yellow};
}
`;

View File

@@ -10,64 +10,64 @@ import StyledWrapper from '../../../Auth/AuthMode/StyledWrapper';
const WSAuthMode = ({ item, collection }) => {
const dispatch = useDispatch();
const dropdownTippyRef = useRef();
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
const onDropdownCreate = ref => (dropdownTippyRef.current = ref);
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
const authModes = [
{
name: 'Basic Auth',
mode: 'basic'
mode: 'basic',
},
{
name: 'Bearer Token',
mode: 'bearer'
mode: 'bearer',
},
{
name: 'API Key',
mode: 'apikey'
mode: 'apikey',
},
{
name: 'OAuth2',
mode: 'oauth2'
mode: 'oauth2',
},
{
name: 'Inherit',
mode: 'inherit'
mode: 'inherit',
},
{
name: 'No Auth',
mode: 'none'
}
mode: 'none',
},
];
const Icon = forwardRef((props, ref) => {
return (
<div ref={ref} className="flex items-center justify-center auth-mode-label select-none">
{humanizeRequestAuthMode(authMode)} <IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
{humanizeRequestAuthMode(authMode)}
{' '}
<IconCaretDown className="caret ml-1 mr-1" size={14} strokeWidth={2} />
</div>
);
});
const onModeChange = (value) => {
dispatch(
updateRequestAuthMode({
itemUid: item.uid,
collectionUid: collection.uid,
mode: value
})
);
const onModeChange = value => {
dispatch(updateRequestAuthMode({
itemUid: item.uid,
collectionUid: collection.uid,
mode: value,
}));
};
const onClickHandler = (mode) => {
const onClickHandler = mode => {
dropdownTippyRef?.current?.hide();
onModeChange(mode);
};
return (
<StyledWrapper>
<div className="inline-flex items-center cursor-pointer auth-mode-selector">
<Dropdown onCreate={onDropdownCreate} icon={<Icon />} placement="bottom-end">
{authModes.map((authMode) => (
{authModes.map(authMode => (
<div
key={authMode.mode}
className="dropdown-item"
@@ -82,4 +82,4 @@ const WSAuthMode = ({ item, collection }) => {
);
};
export default WSAuthMode;
export default WSAuthMode;

View File

@@ -19,7 +19,7 @@ const WSAuth = ({ item, collection }) => {
const authMode = item.draft ? get(item, 'draft.request.auth.mode') : get(item, 'request.auth.mode');
const requestTreePath = getTreePathFromCollectionToItem(collection, item);
const request = item.draft
const request = item.draft
? get(item, 'draft.request', {})
: get(item, 'request', {});
@@ -30,13 +30,11 @@ const WSAuth = ({ item, collection }) => {
// Reset to 'none' if current auth mode is not supported
useEffect(() => {
if (authMode && !supportedAuthModes.includes(authMode)) {
dispatch(
updateRequestAuthMode({
itemUid: item.uid,
collectionUid: collection.uid,
mode: 'none'
})
);
dispatch(updateRequestAuthMode({
itemUid: item.uid,
collectionUid: collection.uid,
mode: 'none',
}));
}
}, [authMode, collection.uid, dispatch, item.uid]);
@@ -47,7 +45,7 @@ const WSAuth = ({ item, collection }) => {
let effectiveSource = {
type: 'collection',
name: 'Collection',
auth: collectionAuth
auth: collectionAuth,
};
// Check folders in reverse to find the closest auth configuration
@@ -58,7 +56,7 @@ const WSAuth = ({ item, collection }) => {
effectiveSource = {
type: 'folder',
name: i.name,
auth: folderAuth
auth: folderAuth,
};
break;
}
@@ -80,22 +78,34 @@ const WSAuth = ({ item, collection }) => {
return <ApiKeyAuth collection={collection} item={item} updateAuth={updateAuth} request={request} save={save} />;
}
case 'oauth2': {
return <>
<div className="flex flex-row w-full mt-2 gap-2">
<div>OAuth 2 not <strong>yet</strong> supported by WebSockets. Using no auth instead.</div>
return (
<>
<div className="flex flex-row w-full mt-2 gap-2">
<div>
OAuth 2 not
<strong>yet</strong>
{' '}
supported by WebSockets. Using no auth instead.
</div>
</>
</div>
</>
);
// return <OAuth2 collection={collection} item={item} updateAuth={updateAuth} request={request} save={save} />;
}
case 'inherit': {
const source = getEffectiveAuthSource();
// Only show inherited auth if it's one of the supported types
if (source && supportedAuthModes.includes(source.auth?.mode)) {
return (
<>
<div className="flex flex-row w-full mt-2 gap-2">
<div>Auth inherited from {source.name}: </div>
<div>
Auth inherited from
{source.name}
:
{' '}
</div>
<div className="inherit-mode-text">{humanizeRequestAuthMode(source.auth?.mode)}</div>
</div>
</>
@@ -126,4 +136,4 @@ const WSAuth = ({ item, collection }) => {
);
};
export default WSAuth;
export default WSAuth;

View File

@@ -15,19 +15,17 @@ import WSSettingsPane from '../WSSettingsPane/index';
const WSRequestPane = ({ item, collection, handleRun }) => {
const dispatch = useDispatch();
const tabs = useSelector((state) => state.tabs.tabs);
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const tabs = useSelector(state => state.tabs.tabs);
const activeTabUid = useSelector(state => state.tabs.activeTabUid);
const selectTab = (tab) => {
dispatch(
updateRequestPaneTab({
uid: item.uid,
requestPaneTab: tab
})
);
const selectTab = tab => {
dispatch(updateRequestPaneTab({
uid: item.uid,
requestPaneTab: tab,
}));
};
const getTabPanel = (tab) => {
const getTabPanel = tab => {
switch (tab) {
case 'body': {
return (
@@ -62,14 +60,14 @@ const WSRequestPane = ({ item, collection, handleRun }) => {
return <div>Something went wrong</div>;
}
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
const focusedTab = find(tabs, t => t.uid === activeTabUid);
if (!focusedTab || !focusedTab.uid || !focusedTab.requestPaneTab) {
return <div className="pb-4 px-4">An error occurred!</div>;
}
const getTabClassname = (tabName) => {
const getTabClassname = tabName => {
return classnames(`tab select-none ${tabName}`, {
active: tabName === focusedTab.requestPaneTab
active: tabName === focusedTab.requestPaneTab,
});
};
@@ -78,7 +76,7 @@ const WSRequestPane = ({ item, collection, handleRun }) => {
const docs = getPropertyFromDraftOrRequest(item, 'request.docs');
const auth = getPropertyFromDraftOrRequest(item, 'request.auth');
const activeHeadersLength = headers.filter((header) => header.enabled).length;
const activeHeadersLength = headers.filter(header => header.enabled).length;
useEffect(() => {
if (!focusedTab?.requestPaneTab) {
@@ -110,7 +108,7 @@ const WSRequestPane = ({ item, collection, handleRun }) => {
</div>
<section
className={classnames('flex w-full flex-1 h-full', {
'mt-2': !isMultipleContentTab
'mt-2': !isMultipleContentTab,
})}
>
<HeightBoundContainer>{getTabPanel(focusedTab.requestPaneTab)}</HeightBoundContainer>

View File

@@ -4,8 +4,8 @@ const StyledWrapper = styled.div`
.single-line-editor-wrapper {
padding: 0.15rem 0.4rem;
border-radius: 3px;
border: solid 1px ${(props) => props.theme.input.border};
background-color: ${(props) => props.theme.input.bg};
border: solid 1px ${props => props.theme.input.border};
background-color: ${props => props.theme.input.bg};
}
.tooltip-mod {

View File

@@ -23,30 +23,26 @@ const getPropertyFromDraftOrRequest = (propertyKey, item) =>
const WSSettingsPane = ({ item, collection }) => {
const dispatch = useDispatch();
const { storedTheme } = useTheme();
const requestPreferences = useSelector((state) => state.app.preferences.request);
const requestPreferences = useSelector(state => state.app.preferences.request);
const { _connectionTimeout, keepAliveInterval = 0 } = getPropertyFromDraftOrRequest('settings', item);
const connectionTimeout = _connectionTimeout ?? requestPreferences.timeout
const connectionTimeout = _connectionTimeout ?? requestPreferences.timeout;
const onChangeConnectionTimeout = (val) => {
dispatch(
updateItemSettings({
collectionUid: collection.uid,
itemUid: item.uid,
settings: { connectionTimeout: val }
})
);
const onChangeConnectionTimeout = val => {
dispatch(updateItemSettings({
collectionUid: collection.uid,
itemUid: item.uid,
settings: { connectionTimeout: val },
}));
};
const onChangeKeepAliveInterval = (val) => {
dispatch(
updateItemSettings({
collectionUid: collection.uid,
itemUid: item.uid,
settings: { keepAliveInterval: val }
})
);
const onChangeKeepAliveInterval = val => {
dispatch(updateItemSettings({
collectionUid: collection.uid,
itemUid: item.uid,
settings: { keepAliveInterval: val },
}));
};
return (
@@ -57,13 +53,13 @@ const WSSettingsPane = ({ item, collection }) => {
<InfoTip
infotipId="setting-connection-timeout"
className="tooltip-mod max-w-lg"
content={
content={(
<div>
<p>
<span>Timeout in milliseconds</span>
</p>
</div>
}
)}
/>
</div>
<div>
@@ -71,7 +67,7 @@ const WSSettingsPane = ({ item, collection }) => {
<SingleLineEditor
value={connectionTimeout}
theme={storedTheme}
onChange={(newValue) => onChangeConnectionTimeout(newValue)}
onChange={newValue => onChangeConnectionTimeout(newValue)}
collection={collection}
/>
</div>
@@ -82,7 +78,7 @@ const WSSettingsPane = ({ item, collection }) => {
<InfoTip
infotipId="setting-keep-alive"
className="tooltip-mod max-w-lg"
content={
content={(
<div>
<p>
<span>
@@ -91,7 +87,7 @@ const WSSettingsPane = ({ item, collection }) => {
</p>
<p className="mt-2">0 (zero) = off</p>
</div>
}
)}
/>
</div>
<div>
@@ -99,7 +95,7 @@ const WSSettingsPane = ({ item, collection }) => {
<SingleLineEditor
value={keepAliveInterval}
theme={storedTheme}
onChange={(newValue) => onChangeKeepAliveInterval(newValue)}
onChange={newValue => onChangeKeepAliveInterval(newValue)}
collection={collection}
/>
</div>

View File

@@ -17,7 +17,7 @@ const Wrapper = styled.div`
}
.selected-body-mode {
color: ${(props) => props.theme.colors.text.yellow};
color: ${props => props.theme.colors.text.yellow};
}
}

View File

@@ -4,19 +4,19 @@ import Dropdown from 'components/Dropdown';
import { humanizeRequestBodyMode } from 'utils/collections';
import StyledWrapper from './StyledWrapper';
const WSRequestBodyMode = ({ mode, onModeChange }) => {
const dropdownTippyRef = useRef();
const onDropdownCreate = (ref) => (dropdownTippyRef.current = ref);
const onDropdownCreate = ref => (dropdownTippyRef.current = ref);
const Icon = forwardRef((props, ref) => {
return (
<div ref={ref} className="flex items-center justify-center pl-3 py-1 select-none selected-body-mode">
{humanizeRequestBodyMode(mode)} <IconCaretDown className="caret ml-2" size={14} strokeWidth={2} />
</div>
);
});
return (
<div ref={ref} className="flex items-center justify-center pl-3 py-1 select-none selected-body-mode">
{humanizeRequestBodyMode(mode)}
{' '}
<IconCaretDown className="caret ml-2" size={14} strokeWidth={2} />
</div>
);
});
return (
<StyledWrapper>

View File

@@ -10,7 +10,7 @@ const Wrapper = styled.div`
.ws-message-header {
.font-medium {
color: ${(props) => props.theme.text};
color: ${props => props.theme.text};
}
button {
@@ -40,9 +40,9 @@ const Wrapper = styled.div`
left: 0;
right: 0;
padding-top: 8px;
background: ${(props) => props.theme.bg || '#fff'};
background: ${props => props.theme.bg || '#fff'};
z-index: 15;
border-top: 1px solid ${(props) => props.theme.border || 'rgba(0, 0, 0, 0.1)'};
border-top: 1px solid ${props => props.theme.border || 'rgba(0, 0, 0, 0.1)'};
.add-message-btn {
width: 100%;
@@ -56,4 +56,4 @@ const Wrapper = styled.div`
}
`;
export default Wrapper;
export default Wrapper;

View File

@@ -17,7 +17,7 @@ import { autoDetectLang } from 'utils/codemirror/lang-detect';
const TYPE_BY_DECODER = {
base64: 'binary',
json: 'json',
xml: 'xml'
xml: 'xml',
};
const DECODER_BY_TYPE = invert(TYPE_BY_DECODER);
@@ -31,11 +31,11 @@ const SingleWSMessage = ({
isCollapsed,
onToggleCollapse,
handleRun,
canClientSendMultipleMessages
canClientSendMultipleMessages,
}) => {
const dispatch = useDispatch();
const { displayedTheme } = useTheme();
const preferences = useSelector((state) => state.app.preferences);
const preferences = useSelector(state => state.app.preferences);
const body = item.draft ? get(item, 'draft.request.body') : get(item, 'request.body');
const { name, content, decoder } = message;
@@ -51,31 +51,27 @@ const SingleWSMessage = ({
type: DECODER_BY_TYPE[type],
};
dispatch(
updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid
})
);
dispatch(updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
const onEdit = (value) => {
const onEdit = value => {
const currentMessages = [...(body.ws || [])];
currentMessages[index] = {
name: name ? name : `message ${index + 1}`,
type: DECODER_BY_TYPE[messageFormat],
content: value
content: value,
};
dispatch(
updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid
})
);
dispatch(updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
const onSave = () => dispatch(saveRequest(item.uid, collection.uid));
@@ -85,17 +81,15 @@ const SingleWSMessage = ({
currentMessages.splice(index, 1);
dispatch(
updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid
})
);
dispatch(updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
const getContainerHeight =
canClientSendMultipleMessages && body.ws.length > 1 ? `${isCollapsed ? '' : 'h-80'}` : 'h-full';
const getContainerHeight
= canClientSendMultipleMessages && body.ws.length > 1 ? `${isCollapsed ? '' : 'h-80'}` : 'h-full';
let codeType = messageFormat;
if (TYPE_BY_DECODER[decoder]) {
@@ -105,7 +99,7 @@ const SingleWSMessage = ({
const codemirrorMode = {
text: 'application/text',
xml: 'application/xml',
json: 'application/ld+json'
json: 'application/ld+json',
};
const onPrettify = () => {
@@ -165,7 +159,7 @@ const SingleWSMessage = ({
<IconChevronUp size={16} strokeWidth={1.5} className="text-zinc-700 dark:text-zinc-300" />
)}
</div>
<div className="flex items-center gap-2" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center gap-2" onClick={e => e.stopPropagation()}>
<WSRequestBodyMode mode={messageFormat} onModeChange={onUpdateMessageType} />
<ToolHint text="Prettify" toolhintId={`prettify-msg-${index}`}>
<button
@@ -209,7 +203,7 @@ const SingleWSMessage = ({
};
const WSBody = ({ item, collection, handleRun }) => {
const preferences = useSelector((state) => state.app.preferences);
const preferences = useSelector(state => state.app.preferences);
const isVerticalLayout = preferences?.layout?.responsePaneOrientation === 'vertical';
const dispatch = useDispatch();
const [collapsedMessages, setCollapsedMessages] = useState([]);
@@ -227,10 +221,10 @@ const WSBody = ({ item, collection, handleRun }) => {
}
}, [body?.ws?.length]);
const toggleMessageCollapse = (index) => {
setCollapsedMessages((prev) => {
const toggleMessageCollapse = index => {
setCollapsedMessages(prev => {
if (prev.includes(index)) {
return prev.filter((i) => i !== index);
return prev.filter(i => i !== index);
} else {
return [...prev, index];
}
@@ -242,16 +236,14 @@ const WSBody = ({ item, collection, handleRun }) => {
currentMessages.push({
name: `message ${currentMessages.length + 1}`,
content: '{}'
content: '{}',
});
dispatch(
updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid
})
);
dispatch(updateRequestBody({
content: currentMessages,
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
if (!body?.ws || !Array.isArray(body.ws)) {

View File

@@ -4,12 +4,12 @@ const StyledWrapper = styled.div`
height: 2.3rem;
.input-container {
background-color: ${(props) => props.theme.requestTabPanel.url.bg};
background-color: ${props => props.theme.requestTabPanel.url.bg};
border-top-right-radius: 3px;
border-bottom-right-radius: 3px;
input {
background-color: ${(props) => props.theme.requestTabPanel.url.bg};
background-color: ${props => props.theme.requestTabPanel.url.bg};
outline: none;
box-shadow: none;
@@ -21,12 +21,12 @@ const StyledWrapper = styled.div`
}
.method-ws {
color: ${(props) => props.theme.request.ws};
color: ${props => props.theme.request.ws};
}
.connection-status-strip {
animation: pulse 1.5s ease-in-out infinite;
background-color: ${(props) => props.theme.colors.text.green};
background-color: ${props => props.theme.colors.text.green};
position: absolute;
bottom: 0;
left: 0;
@@ -60,8 +60,8 @@ const StyledWrapper = styled.div`
.infotip-text {
visibility: hidden;
width: auto;
background-color: ${(props) => props.theme.requestTabs.active.bg};
color: ${(props) => props.theme.text};
background-color: ${props => props.theme.requestTabs.active.bg};
color: ${props => props.theme.text};
text-align: center;
border-radius: 4px;
padding: 4px 8px;
@@ -83,7 +83,7 @@ const StyledWrapper = styled.div`
margin-left: -4px;
border-width: 4px;
border-style: solid;
border-color: ${(props) => props.theme.requestTabs.active.bg} transparent transparent transparent;
border-color: ${props => props.theme.requestTabs.active.bg} transparent transparent transparent;
}
.shortcut {
@@ -93,7 +93,7 @@ const StyledWrapper = styled.div`
.connection-controls {
.infotip {
&:hover {
background-color: ${(props) => props.theme.requestTabPanel.url.errorHoverBg};
background-color: ${props => props.theme.requestTabPanel.url.errorHoverBg};
}
}
}

View File

@@ -1,6 +1,6 @@
import { IconArrowRight, IconDeviceFloppy, IconPlugConnected, IconPlugConnectedX } from '@tabler/icons';
import { IconWebSocket } from 'components/Icons/Grpc';
import classnames from "classnames"
import classnames from 'classnames';
import SingleLineEditor from 'components/SingleLineEditor/index';
import { requestUrlChanged } from 'providers/ReduxStore/slices/collections';
import { wsConnectOnly, saveRequest } from 'providers/ReduxStore/slices/collections/actions';
@@ -38,33 +38,31 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
return () => clearInterval(interval);
}, [item.uid]);
const onUrlChange = (value) => {
closeWsConnection(item.uid)
dispatch(
requestUrlChanged({
url: value,
itemUid: item.uid,
collectionUid: collection.uid
})
);
const onUrlChange = value => {
closeWsConnection(item.uid);
dispatch(requestUrlChanged({
url: value,
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
const handleCloseConnection = (e) => {
const handleCloseConnection = e => {
e.stopPropagation();
closeWsConnection(item.uid)
.then(() => {
toast.success('WebSocket connection closed');
setIsConnectionActive(false);
setIsConnecting(false)
setIsConnecting(false);
})
.catch((err) => {
.catch(err => {
console.error('Failed to close WebSocket connection:', err);
toast.error('Failed to close WebSocket connection');
});
};
const handleRunClick = async (e) => {
const handleRunClick = async e => {
e.stopPropagation();
if (!url) {
toast.error('Please enter a valid WebSocket URL');
@@ -73,12 +71,12 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
handleRun(e);
};
const handleConnect = (e) => {
setIsConnecting(true)
dispatch(wsConnectOnly(item, collection.uid));
const handleConnect = e => {
setIsConnecting(true);
dispatch(wsConnectOnly(item, collection.uid));
};
const onSave = (finalValue) => {
const onSave = finalValue => {
dispatch(saveRequest(item.uid, collection.uid));
};
@@ -91,7 +89,7 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
</div>
<SingleLineEditor
value={url}
onSave={(finalValue) => onSave(finalValue)}
onSave={finalValue => onSave(finalValue)}
onChange={onUrlChange}
placeholder="ws://localhost:8080 or wss://example.com"
className="w-full"
@@ -101,7 +99,7 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
<div className="flex items-center h-full mr-2 cursor-pointer">
<div
className="infotip mr-3"
onClick={(e) => {
onClick={e => {
e.stopPropagation();
if (!item.draft) return;
onSave();
@@ -114,7 +112,13 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
className={`${item.draft ? 'cursor-pointer' : 'cursor-default'}`}
/>
<span className="infotip-text text-xs">
Save <span className="shortcut">({saveShortcut})</span>
Save
{' '}
<span className="shortcut">
(
{saveShortcut}
)
</span>
</span>
</div>
@@ -137,8 +141,8 @@ const WsQueryUrl = ({ item, collection, handleRun }) => {
<div className="infotip" onClick={handleConnect}>
<IconPlugConnected
className={
classnames("cursor-pointer",{
"animate-pulse": isConnecting
classnames('cursor-pointer', {
'animate-pulse': isConnecting,
})
}
color={theme.colors.text.green}

View File

@@ -258,7 +258,6 @@ const RequestTabPanel = () => {
);
};
// TODO: reaper, improve selection of panes
return (
<StyledWrapper
@@ -268,11 +267,11 @@ const RequestTabPanel = () => {
>
<div className="pt-4 pb-3 px-4">
{
isGrpcRequest
?<GrpcQueryUrl item={item} collection={collection} handleRun={handleRun} />
: isWsRequest
? <WsQueryUrl item={item} collection={collection} handleRun={handleRun} />
: <QueryUrl item={item} collection={collection} handleRun={handleRun} />
isGrpcRequest
? <GrpcQueryUrl item={item} collection={collection} handleRun={handleRun} />
: isWsRequest
? <WsQueryUrl item={item} collection={collection} handleRun={handleRun} />
: <QueryUrl item={item} collection={collection} handleRun={handleRun} />
}
</div>
<section ref={mainSectionRef} className={`main flex ${isVerticalLayout ? 'flex-col' : ''} flex-grow pb-4 relative overflow-auto`}>
@@ -282,11 +281,10 @@ const RequestTabPanel = () => {
style={isVerticalLayout ? {
height: `${Math.max(topPaneHeight, MIN_TOP_PANE_HEIGHT)}px`,
minHeight: `${MIN_TOP_PANE_HEIGHT}px`,
width: '100%'
width: '100%',
} : {
width: `${Math.max(leftPaneWidth, MIN_LEFT_PANE_WIDTH)}px`
width: `${Math.max(leftPaneWidth, MIN_LEFT_PANE_WIDTH)}px`,
}}
>
{item.type === 'graphql-request' ? (
@@ -299,14 +297,14 @@ const RequestTabPanel = () => {
/>
) : null}
{item.type === 'http-request' ? (
{item.type === 'http-request' ? (
<HttpRequestPane item={item} collection={collection} />
) : null}
{isGrpcRequest ? (
<GrpcRequestPane item={item} collection={collection} handleRun={handleRun} />
) : null}
{isWsRequest ? (
<WSRequestPane item={item} collection={collection} handleRun={handleRun} />
) : null}
@@ -325,10 +323,11 @@ const RequestTabPanel = () => {
response={item.response}
/>
) : item.type === 'ws-request' ? (
<WSResponsePane
item={item}
collection={collection}
response={item.response} />
<WSResponsePane
item={item}
collection={collection}
response={item.response}
/>
) : (
<ResponsePane
item={item}

View File

@@ -69,14 +69,11 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
const getMethodColor = (method = '') => {
const colorMap = {
...theme.request.methods,
...theme.request
}
...theme.request,
};
return colorMap[method.toLocaleLowerCase()];
};
const folder = folderUid ? findItemInCollection(collection, folderUid) : null;
if (['collection-settings', 'collection-overview', 'folder-settings', 'variables', 'collection-runner', 'security-settings'].includes(tab.type)) {
return (
@@ -97,18 +94,18 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
const item = findItemInCollection(collection, tab.uid);
const getMethodText = useCallback((item)=>{
if(!item) return
const getMethodText = useCallback(item => {
if (!item) return;
const isGrpc = item.type === 'grpc-request';
const isWS = item.type === 'ws-request';
if(!isWS && !isGrpc){
if (!isWS && !isGrpc) {
return item.draft ? get(item, 'draft.request.method') : get(item, 'request.method');
}
if(isGrpc){
return "gRPC"
if (isGrpc) {
return 'gRPC';
}
return "WS";
},[item])
return 'WS';
}, [item]);
if (!item) {
return (
@@ -129,8 +126,8 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
}
const isWS = item.type === 'ws-request';
const method = getMethodText(item)
const method = getMethodText(item);
return (
<StyledWrapper className="flex items-center justify-between tab-container px-1">
{showConfirmClose && (
@@ -138,7 +135,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
item={item}
onCancel={() => setShowConfirmClose(false)}
onCloseWithoutSave={() => {
isWS && closeWsConnection(item.uid)
isWS && closeWsConnection(item.uid);
dispatch(
deleteRequestDraft({
itemUid: item.uid,
@@ -182,7 +179,7 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
}
}}
>
<span className="tab-method uppercase" style={{ color:getMethodColor(method), fontSize: 12 }}>
<span className="tab-method uppercase" style={{ color: getMethodColor(method), fontSize: 12 }}>
{method}
</span>
<span className="ml-1 tab-name" title={item.name}>
@@ -202,8 +199,8 @@ const RequestTab = ({ tab, collection, tabIndex, collectionRequestTabs, folderUi
className="flex px-2 close-icon-container"
onClick={(e) => {
if (!item.draft) {
isWS && closeWsConnection(item.uid)
return handleCloseClick(e)
isWS && closeWsConnection(item.uid);
return handleCloseClick(e);
};
e.stopPropagation();

View File

@@ -3,7 +3,7 @@ import styled from 'styled-components';
const StyledWrapper = styled.div`
height: 100%;
overflow: hidden;
background: ${(props) => props.theme.bg};
background: ${props => props.theme.bg};
border-radius: 4px;
div.tabs {
@@ -25,8 +25,8 @@ const StyledWrapper = styled.div`
}
&.active {
color: ${(props) => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important;
color: ${props => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${props => props.theme.tabs.active.border} !important;
}
}
}
@@ -36,15 +36,15 @@ const StyledWrapper = styled.div`
align-items: center;
&.complete {
color: ${(props) => props.theme.colors.text.green};
color: ${props => props.theme.colors.text.green};
}
&.cancelled {
color: ${(props) => props.theme.colors.text.danger};
color: ${props => props.theme.colors.text.danger};
}
&.streaming {
color: ${(props) => props.theme.colors.text.blue};
color: ${props => props.theme.colors.text.blue};
}
}

View File

@@ -4,11 +4,11 @@ const StyledWrapper = styled.div`
overflow-y: auto;
.ws-message.new {
background-color: ${({theme}) => theme.table.striped};
background-color: ${({ theme }) => theme.table.striped};
}
.ws-message:not(:last-child) {
border-bottom: 1px solid ${({theme}) => theme.table.border};
border-bottom: 1px solid ${({ theme }) => theme.table.border};
}
.ws-message:not(:last-child).open {
@@ -16,13 +16,13 @@ const StyledWrapper = styled.div`
}
.ws-incoming {
background: ${(props) => props.theme.bg};
border-color: ${(props) => props.theme.table.border};
background: ${props => props.theme.bg};
border-color: ${props => props.theme.table.border};
}
.ws-outgoing {
background: ${(props) => props.theme.bg};
border-color: ${(props) => props.theme.table.border};
background: ${props => props.theme.bg};
border-color: ${props => props.theme.table.border};
}
.CodeMirror {
@@ -30,12 +30,12 @@ const StyledWrapper = styled.div`
}
.CodeMirror-foldgutter, .CodeMirror-linenumbers, .CodeMirror-lint-markers {
background: ${({theme})=> theme.bg};
background: ${({ theme }) => theme.bg};
}
div[role='tablist'] {
.active {
color: ${(props) => props.theme.colors.text.yellow};
color: ${props => props.theme.colors.text.yellow};
}
}

View File

@@ -10,38 +10,38 @@ import _ from 'lodash';
import { useRef } from 'react';
import { useEffect } from 'react';
const getContentMeta = (content) => {
const getContentMeta = content => {
if (typeof content === 'object') {
return {
isJSON: true,
content: JSON.stringify(content, null, 0)
content: JSON.stringify(content, null, 0),
};
}
try {
return {
isJSON: true,
content: JSON.stringify(JSON.parse(content), null, 0)
content: JSON.stringify(JSON.parse(content), null, 0),
};
} catch {
return {
isJSON: false,
content: content
content: content,
};
}
};
const parseContent = (content) => {
const parseContent = content => {
let contentMeta = getContentMeta(content);
return {
type: contentMeta.isJSON ? 'application/json' : 'text/plain',
content: contentMeta.isJSON ? JSON.stringify(JSON.parse(contentMeta.content), null, 2) : contentMeta.content
content: contentMeta.isJSON ? JSON.stringify(JSON.parse(contentMeta.content), null, 2) : contentMeta.content,
};
};
const getDataTypeText = (type) => {
const getDataTypeText = type => {
const textMap = {
'text/plain': 'RAW',
'application/json': 'JSON'
'application/json': 'JSON',
};
return textMap[type] ?? 'RAW';
};
@@ -52,20 +52,20 @@ const getDataTypeText = (type) => {
*/
const TypeIcon = ({ type }) => {
const commonProps = {
size: 18
size: 18,
};
return {
incoming: <IconArrowDownLeft {...commonProps} />,
outgoing: <IconArrowUpRight {...commonProps} />,
info: <IconInfoCircle {...commonProps} />,
error: <IconExclamationCircle {...commonProps} />
error: <IconExclamationCircle {...commonProps} />,
}[type];
};
const WSMessageItem = ({ message, inFocus }) => {
const [isOpen, setIsOpen] = useState(false);
const [showHex, setShowHex] = useState(false);
const preferences = useSelector((state) => state.app.preferences);
const preferences = useSelector(state => state.app.preferences);
const { displayedTheme } = useTheme();
const [isNew, setIsNew] = useState(false);
const notified = useRef(false);
@@ -90,43 +90,41 @@ const WSMessageItem = ({ message, inFocus }) => {
}
}, [message]);
const canOpenMessage = !isInfo && !isError
const canOpenMessage = !isInfo && !isError;
return (
<div
ref={(node) => {
ref={node => {
if (!node) return;
if (inFocus) node.scrollIntoView();
}}
className={classnames('ws-message flex flex-col p-2', {
'ws-incoming': isIncoming,
'ws-outgoing': !isIncoming,
open: isOpen,
new: isNew
'open': isOpen,
'new': isNew,
})}
>
<div
className={classnames('flex items-center justify-between', {
'cursor-pointer': !isInfo,
'cursor-not-allowed': isInfo
'cursor-not-allowed': isInfo,
})}
onClick={(e) => {
onClick={e => {
if (!canOpenMessage) return;
setIsOpen(!isOpen);
}}
>
<div className="flex min-w-0 shrink">
<span
className={classnames(
'font-semibold flex items-center gap-1',
className={classnames('font-semibold flex items-center gap-1',
{
'text-green-700': isIncoming,
'text-yellow-700': isOutgoing,
'text-blue-700': isInfo,
'text-red-700': isError,
'text-red-700': isError,
}
)}
})}
>
<TypeIcon type={message.type} />
</span>
@@ -136,16 +134,16 @@ const WSMessageItem = ({ message, inFocus }) => {
{message.timestamp && (
<span className="text-xs text-gray-400">{new Date(message.timestamp).toISOString()}</span>
)}
{canOpenMessage
{canOpenMessage
? (
<span className="text-gray-600">
{isOpen ? (
<IconChevronDown size={16} strokeWidth={1.5} className="text-zinc-700 dark:text-zinc-300" />
) : (
<IconChevronRight size={16} strokeWidth={1.5} className="text-zinc-700 dark:text-zinc-300" />
)}
</span>
)
<span className="text-gray-600">
{isOpen ? (
<IconChevronDown size={16} strokeWidth={1.5} className="text-zinc-700 dark:text-zinc-300" />
) : (
<IconChevronRight size={16} strokeWidth={1.5} className="text-zinc-700 dark:text-zinc-300" />
)}
</span>
)
: <span class="w-4"></span>}
</div>
</div>
@@ -154,8 +152,8 @@ const WSMessageItem = ({ message, inFocus }) => {
<div className="mt-2 flex justify-end gap-2 text-xs ws-message-toolbar" role="tablist">
<div
className={classnames('select-none capitalize', {
active: showHex,
'cursor-pointer': !showHex
'active': showHex,
'cursor-pointer': !showHex,
})}
role="tab"
onClick={() => setShowHex(true)}
@@ -164,8 +162,8 @@ const WSMessageItem = ({ message, inFocus }) => {
</div>
<div
className={classnames('select-none capitalize', {
active: !showHex,
'cursor-pointer': showHex
'active': !showHex,
'cursor-pointer': showHex,
})}
role="tab"
onClick={() => setShowHex(false)}

View File

@@ -3,33 +3,33 @@ import styled from 'styled-components';
const StyledWrapper = styled.div`
height: 100%;
overflow: hidden;
background: ${(props) => props.theme.bg};
background: ${props => props.theme.bg};
border-radius: 4px;
.CodeMirror {
height: 100%;
font-family: ${(props) => (props.font === 'default' ? 'monospace' : props.font)};
font-size: ${(props) => (props.fontSize ? props.fontSize : '13px')};
font-family: ${props => (props.font === 'default' ? 'monospace' : props.font)};
font-size: ${props => (props.fontSize ? props.fontSize : '13px')};
}
.accordion-header {
background-color: ${(props) => props.theme.requestTabPanel.card.bg};
background-color: ${props => props.theme.requestTabPanel.card.bg};
&:hover {
background-color: ${(props) => props.theme.plainGrid.hoverBg};
background-color: ${props => props.theme.plainGrid.hoverBg};
}
&.open {
background-color: ${(props) => props.theme.plainGrid.hoverBg};
background-color: ${props => props.theme.plainGrid.hoverBg};
}
}
.error-header {
background-color: ${(props) => (props.theme.bg === '#1e1e1e' ? 'rgba(185, 28, 28, 0.1)' : '#fee2e2')};
background-color: ${props => (props.theme.bg === '#1e1e1e' ? 'rgba(185, 28, 28, 0.1)' : '#fee2e2')};
}
.error-text {
color: ${(props) => props.theme.colors.text.danger};
color: ${props => props.theme.colors.text.danger};
}
div.tabs {
@@ -51,8 +51,8 @@ const StyledWrapper = styled.div`
}
&.active {
color: ${(props) => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important;
color: ${props => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${props => props.theme.tabs.active.border} !important;
}
}
}
@@ -62,15 +62,15 @@ const StyledWrapper = styled.div`
align-items: center;
&.complete {
color: ${(props) => props.theme.colors.text.green};
color: ${props => props.theme.colors.text.green};
}
&.cancelled {
color: ${(props) => props.theme.colors.text.danger};
color: ${props => props.theme.colors.text.danger};
}
&.streaming {
color: ${(props) => props.theme.colors.text.blue};
color: ${props => props.theme.colors.text.blue};
}
}

View File

@@ -10,7 +10,7 @@ import WSError from '../WSError';
const WSQueryResult = ({ item, collection }) => {
const { displayedTheme } = useTheme();
const preferences = useSelector((state) => state.app.preferences);
const preferences = useSelector(state => state.app.preferences);
const [showErrorMessage, setShowErrorMessage] = useState(true);
const response = item.response || {};
@@ -29,7 +29,7 @@ const WSQueryResult = ({ item, collection }) => {
}, [response, hasError]);
// Format a timestamp to a human-readable format
const formatTimestamp = (timestamp) => {
const formatTimestamp = timestamp => {
if (!timestamp) return 'Unknown time';
try {
@@ -41,7 +41,7 @@ const WSQueryResult = ({ item, collection }) => {
};
// Format JSON for display
const formatJSON = (data) => {
const formatJSON = data => {
try {
if (typeof data === 'string') {
return JSON.stringify(JSON.parse(data), null, 2);
@@ -90,7 +90,11 @@ const WSQueryResult = ({ item, collection }) => {
<Accordion.Header index={index} style={{ padding: '8px 12px', minHeight: '40px' }}>
<div className="flex justify-between w-full">
<div className="font-medium">
Response {originalIndex + 1} {index === 0 ? '(Latest)' : ''}
Response
{' '}
{originalIndex + 1}
{' '}
{index === 0 ? '(Latest)' : ''}
</div>
</div>
</Accordion.Header>

View File

@@ -22,7 +22,7 @@ const StyledWrapper = styled.div`
tbody {
tr:nth-child(odd) {
background-color: ${(props) => props.theme.table.striped};
background-color: ${props => props.theme.table.striped};
}
}
}

View File

@@ -2,7 +2,7 @@ import React from 'react';
import StyledWrapper from './StyledWrapper';
const WSResponseHeaders = ({ response }) => {
const formatHeaders = (headers) => {
const formatHeaders = headers => {
if (!headers) return [];
if (Array.isArray(headers)) return headers;
return Object.entries(headers).map(([key, value]) => ({ name: key, value }));

View File

@@ -2,7 +2,7 @@ import styled from 'styled-components';
const StyledWrapper = styled.div`
font-size: 0.8125rem;
color: ${(props) => props.theme.requestTabPanel.responseStatus};
color: ${props => props.theme.requestTabPanel.responseStatus};
`;
export default StyledWrapper;

View File

@@ -7,23 +7,21 @@ import { wsUpdateResponseSortOrder } from 'providers/ReduxStore/slices/collectio
const WSResponseSortOrder = ({ collection, item }) => {
const dispatch = useDispatch();
const order = item.response?.sortOrder ?? -1
const order = item.response?.sortOrder ?? -1;
const toggleSortOrder = ()=>{
dispatch(
wsUpdateResponseSortOrder({
itemUid: item.uid,
collectionUid: collection.uid,
})
);
}
const toggleSortOrder = () => {
dispatch(wsUpdateResponseSortOrder({
itemUid: item.uid,
collectionUid: collection.uid,
}));
};
return (
<StyledWrapper className="ml-2 flex items-center">
<button onClick={toggleSortOrder} title={order === -1 ? 'Latest Last' : 'Latest First'}>
{ order === -1
? <IconSortDescending2 size={16} strokeWidth={1.5} />
: <IconSortAscending2 size={16} strokeWidth={1.5} />}
{ order === -1
? <IconSortDescending2 size={16} strokeWidth={1.5} />
: <IconSortAscending2 size={16} strokeWidth={1.5} />}
</button>
</StyledWrapper>
);

View File

@@ -7,16 +7,16 @@ const Wrapper = styled.div`
align-items: center;
&.text-ok {
color: ${(props) => props.theme.requestTabPanel.responseOk};
color: ${props => props.theme.requestTabPanel.responseOk};
}
&.text-pending {
color: ${(props) => props.theme.requestTabPanel.responsePending};
color: ${props => props.theme.requestTabPanel.responsePending};
}
&.text-error {
color: ${(props) => props.theme.requestTabPanel.responseError};
color: ${props => props.theme.requestTabPanel.responseError};
}
`;
export default Wrapper;
export default Wrapper;

View File

@@ -14,7 +14,7 @@ const wsStatusCodePhraseMap = {
1012: 'SERVICE_RESTART',
1013: 'TRY_AGAIN_LATER',
1014: 'BAD_GATEWAY',
1015: 'TLS_HANDSHAKE'
1015: 'TLS_HANDSHAKE',
};
export default wsStatusCodePhraseMap;
export default wsStatusCodePhraseMap;

View File

@@ -4,15 +4,15 @@ import wsStatusCodePhraseMap from './get-ws-status-code-phrase';
import StyledWrapper from './StyledWrapper';
const WSStatusCode = ({ status, text }) => {
const getTabClassname = (status) => {
const getTabClassname = status => {
return classnames('ml-2', {
// ok if normal connect and normal closure
'text-ok': parseInt(status) === 0 || parseInt(status) === 1000,
'text-error': parseInt(status) !== 1000 && parseInt(status) !== 0
'text-error': parseInt(status) !== 1000 && parseInt(status) !== 0,
});
};
const statusText = text || wsStatusCodePhraseMap[status]
const statusText = text || wsStatusCodePhraseMap[status];
return (
<StyledWrapper className={getTabClassname(status)}>
@@ -22,4 +22,4 @@ const WSStatusCode = ({ status, text }) => {
);
};
export default WSStatusCode;
export default WSStatusCode;

View File

@@ -1,7 +1,7 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
border-left: 4px solid ${(props) => props.theme.colors.text.danger};
border-left: 4px solid ${props => props.theme.colors.text.danger};
border-top: 1px solid transparent;
border-right: 1px solid transparent;
border-bottom: 1px solid transparent;
@@ -10,7 +10,7 @@ const StyledWrapper = styled.div`
max-height: 200px;
min-height: 70px;
overflow-y: auto;
background-color: ${(props) => (props.theme.bg === '#1e1e1e' ? 'rgba(40, 40, 40, 0.5)' : 'rgba(250, 250, 250, 0.9)')};
background-color: ${props => (props.theme.bg === '#1e1e1e' ? 'rgba(40, 40, 40, 0.5)' : 'rgba(250, 250, 250, 0.9)')};
.close-button {
opacity: 0.7;
@@ -21,14 +21,14 @@ const StyledWrapper = styled.div`
}
svg {
color: ${(props) => props.theme.text};
color: ${props => props.theme.text};
}
}
.error-title {
font-weight: 600;
margin-bottom: 0.375rem;
color: ${(props) => props.theme.colors.text.danger};
color: ${props => props.theme.colors.text.danger};
}
.error-message {
@@ -37,7 +37,7 @@ const StyledWrapper = styled.div`
line-height: 1.25rem;
white-space: pre-wrap;
word-break: break-all;
color: ${(props) => props.theme.text};
color: ${props => props.theme.text};
}
`;

View File

@@ -28,26 +28,24 @@ const WSResult = ({ response }) => {
const WSResponsePane = ({ item, collection }) => {
const dispatch = useDispatch();
const tabs = useSelector((state) => state.tabs.tabs);
const activeTabUid = useSelector((state) => state.tabs.activeTabUid);
const tabs = useSelector(state => state.tabs.tabs);
const activeTabUid = useSelector(state => state.tabs.activeTabUid);
const isLoading = ['queued', 'sending'].includes(item.requestState);
const requestTimeline = [...(collection?.timeline || [])].filter((obj) => {
const requestTimeline = [...(collection?.timeline || [])].filter(obj => {
if (obj.itemUid === item.uid) return true;
});
const selectTab = (tab) => {
dispatch(
updateResponsePaneTab({
uid: item.uid,
responsePaneTab: tab
})
);
const selectTab = tab => {
dispatch(updateResponsePaneTab({
uid: item.uid,
responsePaneTab: tab,
}));
};
const response = item.response || {};
const getTabPanel = (tab) => {
const getTabPanel = tab => {
switch (tab) {
case 'response': {
return <WSResult response={response} />;
@@ -84,7 +82,7 @@ const WSResponsePane = ({ item, collection }) => {
return <div>Something went wrong</div>;
}
const focusedTab = find(tabs, (t) => t.uid === activeTabUid);
const focusedTab = find(tabs, t => t.uid === activeTabUid);
if (!focusedTab || !focusedTab.uid || !focusedTab.responsePaneTab) {
return <div className="pb-4 px-4">An error occurred!</div>;
}
@@ -93,23 +91,23 @@ const WSResponsePane = ({ item, collection }) => {
{
name: 'response',
label: 'Messages',
count: Array.isArray(response.responses) ? response.responses.length : 0
count: Array.isArray(response.responses) ? response.responses.length : 0,
},
{
name: 'headers',
label: 'Headers',
count: response.headers ? Object.keys(response.headers).length : 0
count: response.headers ? Object.keys(response.headers).length : 0,
},
{
name: 'timeline',
label: 'Timeline'
}
label: 'Timeline',
},
];
return (
<StyledWrapper className="flex flex-col h-full relative">
<div className="flex flex-wrap items-center pl-3 pr-4 tabs" role="tablist">
{tabConfig.map((tab) => (
{tabConfig.map(tab => (
<Tab
key={tab.name}
name={tab.name}

View File

@@ -15,14 +15,14 @@ const ShareCollection = ({ onClose, collectionUid }) => {
const isCollectionLoading = areItemsLoading(collection);
const hasNonExportableRequestTypes = useMemo(() => {
let types = new Set()
let types = new Set();
const checkItem = (item) => {
if (item.type === 'grpc-request') {
types.add("gRPC")
types.add('gRPC');
return true;
}
if (item.type === 'ws-request') {
types.add("WebSocket")
types.add('WebSocket');
return true;
}
if (item.items) {
@@ -32,8 +32,8 @@ const ShareCollection = ({ onClose, collectionUid }) => {
};
return {
has: collection?.items?.filter(checkItem).length || false,
types:[...types],
}
types: [...types],
};
}, [collection]);
const handleExportBrunoCollection = () => {
@@ -87,7 +87,12 @@ const ShareCollection = ({ onClose, collectionUid }) => {
{hasNonExportableRequestTypes.has && (
<div className="px-3 py-2 bg-yellow-50 w-full dark:bg-yellow-900/20 text-yellow-700 dark:text-yellow-400 text-xs border-b border-yellow-100 dark:border-yellow-800/20 flex items-center">
<IconAlertTriangle size={16} className="mr-2 flex-shrink-0" />
<span>Note: {hasNonExportableRequestTypes.types.join(', ')} requests in this collection will not be exported</span>
<span>
Note:
{hasNonExportableRequestTypes.types.join(', ')}
{' '}
requests in this collection will not be exported
</span>
</div>
)}
<div className="flex items-center p-3 w-full">

View File

@@ -38,7 +38,7 @@ const Wrapper = styled.div`
color: ${(props) => props.theme.request.grpc};
}
.method-ws {
color: ${(props) => props.theme.request.ws};
color: ${props => props.theme.request.ws};
}
`;

View File

@@ -2,20 +2,19 @@ import classnames from 'classnames';
import React from 'react';
import StyledWrapper from './StyledWrapper';
const getMethodFlags = (item) => ({
const getMethodFlags = item => ({
isGrpc: item.type === 'grpc-request',
isWS: item.type === 'ws-request'
isWS: item.type === 'ws-request',
});
const getMethodText = (item, { isGrpc, isWS }) =>
isGrpc
? 'grpc'
: isWS
? 'ws'
: item.request.method.length > 5
? item.request.method.substring(0, 3)
: item.request.method;
? 'ws'
: item.request.method.length > 5
? item.request.method.substring(0, 3)
: item.request.method;
const getClassname = (method = '', { isGrpc, isWS }) => {
method = method.toLocaleLowerCase();
@@ -28,11 +27,10 @@ const getClassname = (method = '', { isGrpc, isWS }) => {
'method-head': method === 'head',
'method-options': method === 'options',
'method-grpc': isGrpc,
'method-ws': isWS
'method-ws': isWS,
});
};
const RequestMethod = ({ item }) => {
if (!['http-request', 'graphql-request', 'grpc-request', 'ws-request'].includes(item.type)) {
return null;

View File

@@ -176,22 +176,20 @@ const NewRequest = ({ collectionUid, item, isEphemeral, onClose }) => {
// will need to handle import from grpcurl command when we support it, now it is just for creating new requests
} else if (isWsRequest) {
dispatch(
newWsRequest({
requestName: values.requestName,
requestMethod: values.requestMethod,
filename: values.filename,
requestType: values.requestType,
requestUrl: values.requestUrl,
collectionUid: collection.uid,
itemUid: item ? item.uid : null
})
)
dispatch(newWsRequest({
requestName: values.requestName,
requestMethod: values.requestMethod,
filename: values.filename,
requestType: values.requestType,
requestUrl: values.requestUrl,
collectionUid: collection.uid,
itemUid: item ? item.uid : null,
}))
.then(() => {
toast.success('New request created!');
onClose();
})
.catch((err) => toast.error(err ? err.message : 'An error occurred while adding the request'));
.catch(err => toast.error(err ? err.message : 'An error occurred while adding the request'));
} else if (isEphemeral) {
const uid = uuid();
dispatch(

View File

@@ -27,7 +27,7 @@ const initialState = {
},
beta: {
grpc: false,
websocket: false
websocket: false,
}
},
generateCode: {

View File

@@ -261,19 +261,19 @@ export const wsConnectOnly = (item, collectionUid) => (dispatch, getState) => {
const globalEnvironmentVariables = getGlobalEnvironmentVariables({
globalEnvironments,
activeGlobalEnvironmentUid
activeGlobalEnvironmentUid,
});
collectionCopy.globalEnvironmentVariables = globalEnvironmentVariables;
const environment = findEnvironmentInCollection(collectionCopy, collectionCopy.activeEnvironmentUid);
connectWS(itemCopy, collectionCopy, environment, collectionCopy.runtimeVariables, { connectOnly: true })
.then(resolve)
.catch((err) => {
toast.error(err.message);
});
})
}
.then(resolve)
.catch(err => {
toast.error(err.message);
});
});
};
export const sendRequest = (item, collectionUid) => (dispatch, getState) => {
const state = getState();
@@ -327,7 +327,7 @@ export const sendRequest = (item, collectionUid) => (dispatch, getState) => {
} else if (isWsRequest) {
sendWsRequest(itemCopy, collectionCopy, environment, collectionCopy.runtimeVariables)
.then(resolve)
.catch((err) => {
.catch(err => {
toast.error(err.message);
});
} else {
@@ -1085,7 +1085,7 @@ export const newGrpcRequest = (params) => (dispatch, getState) => {
});
};
export const newWsRequest = (params) => (dispatch, getState) => {
export const newWsRequest = params => (dispatch, getState) => {
const { requestName, requestMethod, filename, requestUrl, collectionUid, body, auth, headers, itemUid } = params;
return new Promise((resolve, reject) => {
@@ -1109,14 +1109,14 @@ export const newWsRequest = (params) => (dispatch, getState) => {
ws: [
{
name: 'message 1',
content: '{}'
}
]
content: '{}',
},
],
},
auth: auth ?? {
mode: 'inherit'
}
}
mode: 'inherit',
},
},
};
const resolvedFilename = resolveRequestFilename(filename);
@@ -1124,21 +1124,19 @@ export const newWsRequest = (params) => (dispatch, getState) => {
const { ipcRenderer } = window;
// Set the seq field for WebSocket requests
const items = filter(collection.items, (i) => isItemAFolder(i) || isItemARequest(i));
const items = filter(collection.items, i => isItemAFolder(i) || isItemARequest(i));
item.seq = items.length + 1;
ipcRenderer
.invoke('renderer:new-request', fullName, item)
.then(() => {
// task middleware will track this and open the new request in a new tab once request is created
dispatch(
insertTaskIntoQueue({
uid: uuid(),
type: 'OPEN_REQUEST',
collectionUid,
itemPathname: fullName
})
);
dispatch(insertTaskIntoQueue({
uid: uuid(),
type: 'OPEN_REQUEST',
collectionUid,
itemPathname: fullName,
}));
resolve();
})
.catch(reject);

View File

@@ -61,7 +61,7 @@ const wsStatusCodes = {
1012: 'SERVICE_RESTART',
1013: 'TRY_AGAIN_LATER',
1014: 'BAD_GATEWAY',
1015: 'TLS_HANDSHAKE'
1015: 'TLS_HANDSHAKE',
};
const initialState = {
@@ -82,7 +82,7 @@ const initiatedGrpcResponse = {
isError: false,
duration: 0,
responses: [],
timestamp: Date.now()
timestamp: Date.now(),
};
const initiatedWsResponse = {
@@ -99,7 +99,7 @@ const initiatedWsResponse = {
error: null,
errorDetails: null,
metadata: [],
trailers: []
trailers: [],
};
export const collectionsSlice = createSlice({
@@ -346,7 +346,7 @@ export const collectionsSlice = createSlice({
enabled: true,
type: 'text',
uid: uuid(),
ephemeral: true
ephemeral: true,
});
}
}
@@ -394,8 +394,8 @@ export const collectionsSlice = createSlice({
}
// Ensure timestamp is a number (milliseconds since epoch)
const timestamp =
item?.requestSent?.timestamp instanceof Date
const timestamp
= item?.requestSent?.timestamp instanceof Date
? item.requestSent.timestamp.getTime()
: item?.requestSent?.timestamp || Date.now();
@@ -409,7 +409,7 @@ export const collectionsSlice = createSlice({
data: {
request: item.requestSent || item.request,
response: action.payload.response,
timestamp: timestamp
timestamp: timestamp,
}
});
}
@@ -448,7 +448,7 @@ export const collectionsSlice = createSlice({
data: {
request: eventData || item.requestSent || item.request,
timestamp: Date.now(),
eventData: eventData
eventData: eventData,
}
});
},
@@ -514,8 +514,8 @@ export const collectionsSlice = createSlice({
// Handle error status (non-zero code)
if (statusCode !== 0) {
updatedResponse.isError = true;
updatedResponse.error =
statusDetails || `gRPC error with code ${statusCode} (${updatedResponse.statusText})`;
updatedResponse.error
= statusDetails || `gRPC error with code ${statusCode} (${updatedResponse.statusText})`;
}
break;
@@ -571,7 +571,7 @@ export const collectionsSlice = createSlice({
request: item.requestSent || item.request,
response: updatedResponse,
eventData: eventData, // Store the original event data
timestamp: Date.now()
timestamp: Date.now(),
}
});
},
@@ -1388,8 +1388,7 @@ export const collectionsSlice = createSlice({
item.draft.request.body.file = filter(
item.draft.request.body.file,
(p) => p.uid !== action.payload.paramUid
);
p => p.uid !== action.payload.paramUid);
if (item.draft.request.body.file.length > 0) {
item.draft.request.body.file[0].selected = true;
@@ -1773,13 +1772,13 @@ export const collectionsSlice = createSlice({
const params = item.draft.request.vars.req;
item.draft.request.vars.req = updateReorderedItem.map((uid) => {
return params.find((param) => param.uid === uid);
return params.find(param => param.uid === uid);
});
} else if (type === 'response') {
const params = item.draft.request.vars.res;
item.draft.request.vars.res = updateReorderedItem.map((uid) => {
return params.find((param) => param.uid === uid);
return params.find(param => param.uid === uid);
});
}
}
@@ -2173,7 +2172,7 @@ export const collectionsSlice = createSlice({
name: directoryName,
collapsed: true,
type: 'folder',
items: []
items: [],
};
currentSubItems.push(childItem);
}
@@ -2650,7 +2649,7 @@ export const collectionsSlice = createSlice({
url,
credentials,
credentialsId,
debugInfo
debugInfo,
});
collection.oauth2Credentials = filteredOauth2Credentials;
@@ -2673,8 +2672,8 @@ export const collectionsSlice = createSlice({
url,
credentials,
credentialsId,
debugInfo: debugInfo.data
}
debugInfo: debugInfo.data,
},
});
}
},
@@ -2688,8 +2687,7 @@ export const collectionsSlice = createSlice({
let collectionOauth2Credentials = cloneDeep(collection.oauth2Credentials);
const filteredOauth2Credentials = filter(
collectionOauth2Credentials,
(creds) => !(creds.url === url && creds.collectionUid === collectionUid)
);
creds => !(creds.url === url && creds.collectionUid === collectionUid));
collection.oauth2Credentials = filteredOauth2Credentials;
}
},
@@ -2699,8 +2697,7 @@ export const collectionsSlice = createSlice({
const collection = findCollectionByUid(state.collections, collectionUid);
const oauth2Credential = find(
collection?.oauth2Credentials || [],
(creds) => creds.url === url && creds.collectionUid === collectionUid && creds.credentialsId === credentialsId
);
creds => creds.url === url && creds.collectionUid === collectionUid && creds.credentialsId === credentialsId);
return oauth2Credential;
},
@@ -2796,8 +2793,8 @@ export const collectionsSlice = createSlice({
data: {
request: eventData || item.requestSent || item.request,
timestamp: Date.now(),
eventData: eventData
}
eventData: eventData,
},
});
},
wsResponseReceived: (state, action) => {
@@ -2817,40 +2814,40 @@ export const collectionsSlice = createSlice({
...currentResponse,
isError: false,
error: '',
duration: Date.now() - (timestamp || Date.now())
duration: Date.now() - (timestamp || Date.now()),
};
// Process based on event type
switch (eventType) {
case 'message':
// Add message to responses list
updatedResponse.responses = (currentResponse?.responses||[]).concat(eventData)
updatedResponse.responses = (currentResponse?.responses || []).concat(eventData);
break;
case 'redirect':
updatedResponse.requestHeaders = eventData.headers
updatedResponse.responses ||= []
updatedResponse.requestHeaders = eventData.headers;
updatedResponse.responses ||= [];
updatedResponse.responses.push({
message: eventData.message,
message: eventData.message,
type: eventData.type,
timestamp: eventData.timestamp,
})
break
});
break;
case 'upgrade':
updatedResponse.headers = eventData.headers
break
updatedResponse.headers = eventData.headers;
break;
case 'open':
updatedResponse.status = 'CONNECTED';
updatedResponse.statusText = 'CONNECTED';
updatedResponse.statusCode = 0;
updatedResponse.responses ||= []
updatedResponse.responses ||= [];
updatedResponse.responses.push({
message: `Connected to ${eventData.url}`,
type: 'info',
timestamp: eventData.timestamp
})
timestamp: eventData.timestamp,
});
break;
case 'close':
@@ -2861,12 +2858,12 @@ export const collectionsSlice = createSlice({
updatedResponse.statusCode = code;
updatedResponse.statusText = wsStatusCodes[code] || 'CLOSED';
updatedResponse.statusDescription = reason;
updatedResponse.responses.push({
type: code !== 1000 ? 'info' : 'error',
message: reason.trim().length ? ['Closed:',reason.trim()].join(' ') : 'Closed',
message: reason.trim().length ? ['Closed:', reason.trim()].join(' ') : 'Closed',
timestamp,
})
});
break;
case 'error':
@@ -2880,7 +2877,7 @@ export const collectionsSlice = createSlice({
type: 'error',
message: errorDetails || 'WebSocket error occurred',
timestamp,
})
});
break;
@@ -2901,8 +2898,8 @@ export const collectionsSlice = createSlice({
item.response.sortOrder = item.response.sortOrder ? -item.response.sortOrder : -1;
}
}
}
}
},
},
});
export const {
@@ -3032,7 +3029,7 @@ export const {
updateActiveConnections,
runWsRequestEvent,
wsResponseReceived,
wsUpdateResponseSortOrder
wsUpdateResponseSortOrder,
} = collectionsSlice.actions;
export default collectionsSlice.reducer;

View File

@@ -81,8 +81,8 @@ export const tabsSlice = createSlice({
type: type || 'request',
...(uid ? { folderUid: uid } : {}),
preview: preview !== undefined
? preview
: !nonReplaceableTabTypes.includes(type)
? preview
: !nonReplaceableTabTypes.includes(type),
});
state.activeTabUid = uid;
},

View File

@@ -103,14 +103,14 @@ const darkTheme = {
head: '#d69956'
},
grpc: '#6366f1',
ws: '#f59e0b'
ws: '#f59e0b',
},
requestTabPanel: {
url: {
bg: '#3D3D3D',
icon: 'rgb(204, 204, 204)',
errorHoverBg: '#4a2a2a'
errorHoverBg: '#4a2a2a',
},
dragbar: {
border: '#444',
@@ -264,7 +264,7 @@ const darkTheme = {
border: '#373737',
placeholder: {
color: '#a2a2a2',
opacity: 0.5
opacity: 0.5,
},
gutter: {
bg: '#262626'
@@ -308,7 +308,7 @@ const darkTheme = {
tooltip: {
bg: '#1f1f1f',
color: '#ffffff',
shortcutColor: '#f59e0b'
shortcutColor: '#f59e0b',
},
infoTip: {

View File

@@ -103,14 +103,14 @@ const lightTheme = {
head: '#ca7811'
},
grpc: '#6366f1',
ws: '#f59e0b'
ws: '#f59e0b',
},
requestTabPanel: {
url: {
bg: '#f3f3f3',
icon: '#515151',
errorHoverBg: '#fef2f2'
errorHoverBg: '#fef2f2',
},
dragbar: {
border: '#efefef',
@@ -310,7 +310,7 @@ const lightTheme = {
tooltip: {
bg: '#374151',
color: '#ffffff',
shortcutColor: '#f59e0b'
shortcutColor: '#f59e0b',
},
infoTip: {

View File

@@ -1,13 +1,13 @@
/**
* @param {string} snippet
* @param {string} snippet
* @returns {boolean}
*/
export function isXML(snippet){
return /<\/?[a-z][\s\S]*>/i.test(snippet)
export function isXML(snippet) {
return /<\/?[a-z][\s\S]*>/i.test(snippet);
}
/**
* @param {string} snippet
* @param {string} snippet
* @returns {boolean}
*/
export function isJSON(snippet) {
@@ -20,15 +20,15 @@ export function isJSON(snippet) {
}
/**
* @param {string} snippet
* @param {string} snippet
* @returns {string}
*/
export function autoDetectLang(snippet) {
if (isJSON(snippet)) {
return 'json';
}
if(isXML(snippet)){
return 'xml'
if (isXML(snippet)) {
return 'xml';
}
return 'text'
return 'text';
}

View File

@@ -154,7 +154,7 @@ export const areItemsLoading = (folder) => {
export const getItemsLoadStats = (folder) => {
let loadingCount = 0;
let flattenedItems = flattenItems(folder.items);
flattenedItems?.forEach((i) => {
flattenedItems?.forEach(i => {
if (i?.loading) {
loadingCount += 1;
}
@@ -262,7 +262,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
multipartForm: copyMultipartFormParams(si.request.body.multipartForm),
file: copyFileParams(si.request.body.file),
grpc: si.request.body.grpc,
ws: si.request.body.ws
ws: si.request.body.ws,
},
script: si.request.script,
vars: si.request.vars,
@@ -337,7 +337,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
tokenQueryKey: get(si.request, 'auth.oauth2.tokenQueryKey', ''),
autoFetchToken: get(si.request, 'auth.oauth2.autoFetchToken', true),
autoRefreshToken: get(si.request, 'auth.oauth2.autoRefreshToken', true),
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {})
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {}),
};
break;
case 'authorization_code':
@@ -358,7 +358,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
tokenQueryKey: get(si.request, 'auth.oauth2.tokenQueryKey', ''),
autoFetchToken: get(si.request, 'auth.oauth2.autoFetchToken', true),
autoRefreshToken: get(si.request, 'auth.oauth2.autoRefreshToken', true),
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {})
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {}),
};
break;
case 'implicit':
@@ -374,7 +374,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
tokenHeaderPrefix: get(si.request, 'auth.oauth2.tokenHeaderPrefix', 'Bearer'),
tokenQueryKey: get(si.request, 'auth.oauth2.tokenQueryKey', ''),
autoFetchToken: get(si.request, 'auth.oauth2.autoFetchToken', true),
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {})
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {}),
};
break;
case 'client_credentials':
@@ -392,7 +392,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
tokenQueryKey: get(si.request, 'auth.oauth2.tokenQueryKey', ''),
autoFetchToken: get(si.request, 'auth.oauth2.autoFetchToken', true),
autoRefreshToken: get(si.request, 'auth.oauth2.autoRefreshToken', true),
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {})
additionalParameters: get(si.request, 'auth.oauth2.additionalParameters', {}),
};
break;
}
@@ -428,7 +428,7 @@ export const transformCollectionToSaveToExportAsFile = (collection, options = {}
if (di.request.body.mode === 'ws') {
di.request.body.ws = di.request.body.ws.map(({ name, content }, index) => ({
name: name ? name : `message ${index + 1}`,
content: replaceTabsWithSpaces(content)
content: replaceTabsWithSpaces(content),
}));
}
}
@@ -669,8 +669,8 @@ export const transformRequestToSaveToFilesystem = (item) => {
ws: itemToSave.request.body.ws.map(({ name, content, type }, index) => ({
name: name ? name : `message ${index + 1}`,
type,
content: replaceTabsWithSpaces(content)
}))
content: replaceTabsWithSpaces(content),
})),
};
}
@@ -702,9 +702,9 @@ export const deleteItemInCollectionByPathname = (pathname, collection) => {
export const isItemARequest = (item) => {
return (
item.hasOwnProperty('request') &&
['http-request', 'graphql-request', 'grpc-request', 'ws-request'].includes(item.type) &&
!item.items
item.hasOwnProperty('request')
&& ['http-request', 'graphql-request', 'grpc-request', 'ws-request'].includes(item.type)
&& !item.items
);
};
@@ -895,7 +895,7 @@ export const getDefaultRequestPaneTab = (item) => {
export const getGlobalEnvironmentVariables = ({ globalEnvironments, activeGlobalEnvironmentUid }) => {
let variables = {};
const environment = globalEnvironments?.find((env) => env?.uid === activeGlobalEnvironmentUid);
const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid);
if (environment) {
each(environment.variables, (variable) => {
if (variable.name && variable.enabled) {
@@ -907,7 +907,7 @@ export const getGlobalEnvironmentVariables = ({ globalEnvironments, activeGlobal
};
export const getGlobalEnvironmentVariablesMasked = ({ globalEnvironments, activeGlobalEnvironmentUid }) => {
const environment = globalEnvironments?.find((env) => env?.uid === activeGlobalEnvironmentUid);
const environment = globalEnvironments?.find(env => env?.uid === activeGlobalEnvironmentUid);
if (environment && Array.isArray(environment.variables)) {
return environment.variables
@@ -997,7 +997,7 @@ export const getAllVariables = (collection, item) => {
...envVariables,
...folderVariables,
...requestVariables,
...runtimeVariables
...runtimeVariables,
};
const maskedEnvVariables = getEnvironmentVariablesMasked(collection) || [];
@@ -1009,7 +1009,7 @@ export const getAllVariables = (collection, item) => {
const uniqueMaskedVariables = [...new Set([...filteredMaskedEnvVariables, ...filteredMaskedGlobalEnvVariables])];
const oauth2CredentialVariables = getFormattedCollectionOauth2Credentials({
oauth2Credentials: collection?.oauth2Credentials
oauth2Credentials: collection?.oauth2Credentials,
});
return {
@@ -1151,7 +1151,7 @@ export const getReorderedItemsInTargetDirectory = ({ items, targetItemUid, dragg
const draggedItem = findItem(itemsWithFixedSequences, draggedItemUid);
const targetSequence = targetItem?.seq;
const draggedSequence = draggedItem?.seq;
itemsWithFixedSequences?.forEach((item) => {
itemsWithFixedSequences?.forEach(item => {
const isDraggedItem = item?.uid === draggedItemUid;
const isBetween = isItemBetweenSequences(item?.seq, draggedSequence, targetSequence);
if (isBetween) {
@@ -1163,16 +1163,12 @@ export const getReorderedItemsInTargetDirectory = ({ items, targetItemUid, dragg
}
});
// only return items that have been reordered
return itemsWithFixedSequences.filter(
(item) => items?.find((originalItem) => originalItem?.uid === item?.uid)?.seq !== item?.seq
);
return itemsWithFixedSequences.filter(item => items?.find(originalItem => originalItem?.uid === item?.uid)?.seq !== item?.seq);
};
export const getReorderedItemsInSourceDirectory = ({ items }) => {
const itemsWithFixedSequences = resetSequencesInFolder(cloneDeep(items));
return itemsWithFixedSequences.filter(
(item) => items?.find((originalItem) => originalItem?.uid === item?.uid)?.seq !== item?.seq
);
return itemsWithFixedSequences.filter(item => items?.find(originalItem => originalItem?.uid === item?.uid)?.seq !== item?.seq);
};
export const calculateDraggedItemNewPathname = ({ draggedItem, targetItem, dropType, collectionPathname }) => {
@@ -1195,10 +1191,10 @@ export const calculateDraggedItemNewPathname = ({ draggedItem, targetItem, dropT
export const getUniqueTagsFromItems = (items = []) => {
const allTags = new Set();
const getTags = (items) => {
items.forEach((item) => {
items.forEach(item => {
if (isItemARequest(item)) {
const tags = item.draft ? get(item, 'draft.tags', []) : get(item, 'tags', []);
tags.forEach((tag) => allTags.add(tag));
tags.forEach(tag => allTags.add(tag));
}
if (item.items) {
getTags(item.items);
@@ -1215,7 +1211,7 @@ export const getRequestItemsForCollectionRun = ({ recursive, items = [], tags })
if (recursive) {
requestItems = flattenItems(items);
} else {
each(items, (item) => {
each(items, item => {
if (item.request) {
requestItems.push(item);
}
@@ -1223,7 +1219,7 @@ export const getRequestItemsForCollectionRun = ({ recursive, items = [], tags })
}
const requestTypes = ['http-request', 'graphql-request'];
requestItems = requestItems.filter((request) => requestTypes.includes(request.type));
requestItems = requestItems.filter(request => requestTypes.includes(request.type));
if (tags && tags.include && tags.exclude) {
const includeTags = tags.include ? tags.include : [];

View File

@@ -78,7 +78,7 @@ export const transformItemsInCollection = (collection) => {
if (isGrpcRequest) {
delete item.request.params;
}
if (isWSRequest) {
delete item.request.params;
delete item.request.method;

View File

@@ -27,7 +27,7 @@ export const sendNetworkRequest = async (item, collection, environment, runtimeV
export const sendGrpcRequest = async (item, collection, environment, runtimeVariables) => {
return new Promise((resolve, reject) => {
startGrpcRequest(item, collection, environment, runtimeVariables)
startGrpcRequest(item, collection, environment, runtimeVariables)
.then((initialState) => {
// Return an initial state object to update the UI
// The real response data will be handled by event listeners
@@ -103,7 +103,7 @@ export const startGrpcRequest = async (item, collection, environment, runtimeVar
export const sendGrpcMessage = async (item, collectionUid, message) => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
ipcRenderer.invoke('grpc:send-message', item.uid, collectionUid, message)
ipcRenderer.invoke('grpc:send-message', item.uid, collectionUid, message)
.then(resolve)
.catch(reject);
});
@@ -215,15 +215,15 @@ export const generateGrpcSampleMessage = async (methodPath, existingMessage = nu
export const connectWS = async (item, collection, environment, runtimeVariables, options) => {
return new Promise((resolve, reject) => {
startWsConnection(item, collection, environment, runtimeVariables, options)
.then((initialState) => {
.then(initialState => {
// Return an initial state object to update the UI
// The real response data will be handled by event listeners
resolve({
...initialState,
timeline: []
timeline: [],
});
})
.catch((err) => reject(err));
.catch(err => reject(err));
});
};
@@ -237,14 +237,14 @@ export const sendWsRequest = (item, collection, environment, runtimeVariables) =
};
const { request } = item.draft ? item.draft : item;
queueWsMessage(item, collection.uid, request.body.ws[0].content)
.then((initialState) => {
.then(initialState => {
// Return an initial state object to update the UI
// The real response data will be handled by event listeners
resolve({
...initialState,
});
})
.catch((err) => reject(err));
.catch(err => reject(err));
await ensureConnection();
});
};
@@ -262,12 +262,12 @@ export const startWsConnection = async (item, collection, environment, runtimeVa
environment,
runtimeVariables,
settings,
options
options,
})
.then(() => {
resolve();
})
.catch((err) => {
.catch(err => {
reject(err);
});
});
@@ -305,7 +305,7 @@ export const sendWsMessage = async (item, collectionUid, message) => {
* @param {string} requestId - The request ID to close
* @returns {Promise<Object>} - The result of the close operation
*/
export const closeWsConnection = async (requestId) => {
export const closeWsConnection = async requestId => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
ipcRenderer.invoke('ws:close-connection', requestId).then(resolve).catch(reject);
@@ -317,7 +317,7 @@ export const closeWsConnection = async (requestId) => {
* @param {string} requestId - The request ID to check
* @returns {Promise<boolean>} - Whether the connection is active
*/
export const isWsConnectionActive = async (requestId) => {
export const isWsConnectionActive = async requestId => {
return new Promise((resolve, reject) => {
const { ipcRenderer } = window;
ipcRenderer.invoke('ws:is-connection-active', requestId).then(resolve).catch(reject);

View File

@@ -17,102 +17,84 @@ const useWsEventListeners = () => {
// Handle WebSocket requestSent event
const removeWsRequestSentListener = ipcRenderer.on('ws:request', (requestId, collectionUid, eventData) => {
dispatch(
runWsRequestEvent({
eventType: 'request',
itemUid: requestId,
collectionUid: collectionUid,
requestUid: requestId,
eventData
})
);
dispatch(runWsRequestEvent({
eventType: 'request',
itemUid: requestId,
collectionUid: collectionUid,
requestUid: requestId,
eventData,
}));
});
const removeWsUpgradeListener = ipcRenderer.on('ws:upgrade', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'upgrade',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'upgrade',
eventData: eventData,
}));
});
const removeWsRedirectListener = ipcRenderer.on('ws:redirect', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'redirect',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'redirect',
eventData: eventData,
}));
});
// Handle WebSocket message event
const removeWsMessageListener = ipcRenderer.on('ws:message', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'message',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'message',
eventData: eventData,
}));
});
// Handle WebSocket open event
const removeWsOpenListener = ipcRenderer.on('ws:open', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'open',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'open',
eventData: eventData,
}));
});
// Handle WebSocket close event
const removeWsCloseListener = ipcRenderer.on('ws:close', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'close',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'close',
eventData: eventData,
}));
});
// Handle WebSocket error event
const removeWsErrorListener = ipcRenderer.on('ws:error', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'error',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'error',
eventData: eventData,
}));
});
// Handle WebSocket connecting event
const removeWsConnectingListener = ipcRenderer.on('ws:connecting', (requestId, collectionUid, eventData) => {
dispatch(
wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'connecting',
eventData: eventData
})
);
dispatch(wsResponseReceived({
itemUid: requestId,
collectionUid: collectionUid,
eventType: 'connecting',
eventData: eventData,
}));
});
const removeWsConnectionsChangedListener = ipcRenderer.on('ws:connections-changed', (data) => {
const removeWsConnectionsChangedListener = ipcRenderer.on('ws:connections-changed', data => {
dispatch(updateActiveConnectionsInStore(data));
});

View File

@@ -316,7 +316,7 @@ const runSingleRequest = async function (
cookies[name.trim()] = rest.join('=').trim();
}
return cookies;
}, {});
}, {});
const mergedCookies = {
...parseCookies(existingCookieString),
@@ -400,7 +400,7 @@ const runSingleRequest = async function (
try {
let axiosInstance = makeAxiosInstance({
requestMaxRedirects: requestMaxRedirects,
disableCookies: options.disableCookies
disableCookies: options.disableCookies,
});
if (request.ntlmConfig) {
axiosInstance = NtlmClient(request.ntlmConfig, axiosInstance.defaults);
@@ -411,10 +411,8 @@ const runSingleRequest = async function (
// todo: make this happen in prepare-request.js
// interpolate the aws v4 config
request.awsv4config.accessKeyId = interpolateString(request.awsv4config.accessKeyId, interpolationOptions);
request.awsv4config.secretAccessKey = interpolateString(
request.awsv4config.secretAccessKey,
interpolationOptions
);
request.awsv4config.secretAccessKey = interpolateString(request.awsv4config.secretAccessKey,
interpolationOptions);
request.awsv4config.sessionToken = interpolateString(request.awsv4config.sessionToken, interpolationOptions);
request.awsv4config.service = interpolateString(request.awsv4config.service, interpolationOptions);
request.awsv4config.region = interpolateString(request.awsv4config.region, interpolationOptions);
@@ -441,7 +439,7 @@ const runSingleRequest = async function (
responseTime = response.headers.get('request-duration');
response.headers.delete('request-duration');
//save cookies if enabled
// save cookies if enabled
if (!options.disableCookies) {
saveCookies(request.url, response.headers);
}
@@ -459,13 +457,13 @@ const runSingleRequest = async function (
console.log(chalk.red(stripExtension(relativeItemPathname)) + chalk.dim(` (${err.message})`));
return {
test: {
filename: relativeItemPathname
filename: relativeItemPathname,
},
request: {
method: request.method,
url: request.url,
headers: request.headers,
data: request.data
data: request.data,
},
response: {
status: 'error',
@@ -473,16 +471,16 @@ const runSingleRequest = async function (
headers: null,
data: null,
url: null,
responseTime: 0
responseTime: 0,
},
error: err?.message || err?.errors?.map((e) => e?.message)?.at(0) || err?.code || 'Request Failed!',
error: err?.message || err?.errors?.map(e => e?.message)?.at(0) || err?.code || 'Request Failed!',
status: 'error',
assertionResults: [],
testResults: [],
preRequestTestResults,
postResponseTestResults,
nextRequestName: nextRequestName,
shouldStopRunnerExecution
shouldStopRunnerExecution,
};
}
}

View File

@@ -21,7 +21,7 @@ const collectionBruToJson = (bru) => {
const sequence = _.get(json, 'meta.seq');
if (json?.meta) {
transformedJson.meta = {
name: json.meta.name
name: json.meta.name,
};
if (sequence) {
@@ -101,9 +101,9 @@ const bruToJson = (bru) => {
grpc: [
{
name: 'message 1',
content: '{}'
}
]
content: '{}',
},
],
});
} else if (requestType === 'ws-request') {
transformedJson.request.auth.mode = _.get(json, 'ws.auth', 'none');

View File

@@ -24,7 +24,7 @@ const {
safeStringifyJSON,
safeParseJSON,
parseDataFromResponse,
parseDataFromRequest
parseDataFromRequest,
} = require('../../utils/common');
const { chooseFileToSave, writeBinaryFile, writeFile } = require('../../utils/filesystem');
const { addCookieToJar, getDomainsWithCookies, getCookieStringForUrl } = require('../../utils/cookies');
@@ -36,13 +36,13 @@ const {
getEnvVars,
getTreePathFromCollectionToItem,
mergeVars,
sortByNameThenSequence
sortByNameThenSequence,
} = require('../../utils/collection');
const {
getOAuth2TokenUsingAuthorizationCode,
getOAuth2TokenUsingClientCredentials,
getOAuth2TokenUsingPasswordCredentials,
getOAuth2TokenUsingImplicitGrant
getOAuth2TokenUsingImplicitGrant,
} = require('../../utils/oauth2');
const { preferencesUtil } = require('../../store/preferences');
const { getProcessEnvVars } = require('../../store/process-env');
@@ -132,7 +132,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingAuthorizationCode({ request: requestCopy, collectionUid, certsAndProxyConfig }));
request.oauth2Credentials = {
credentials,
@@ -140,7 +140,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
collectionUid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header' && credentials?.access_token) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim();
@@ -158,7 +158,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingImplicitGrant({ request: requestCopy, collectionUid }));
request.oauth2Credentials = {
credentials,
@@ -166,7 +166,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
collectionUid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header') {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
@@ -184,7 +184,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingClientCredentials({ request: requestCopy, collectionUid, certsAndProxyConfig }));
request.oauth2Credentials = {
credentials,
@@ -192,7 +192,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
collectionUid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header' && credentials?.access_token) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim();
@@ -210,7 +210,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingPasswordCredentials({ request: requestCopy, collectionUid, certsAndProxyConfig }));
request.oauth2Credentials = {
credentials,
@@ -218,7 +218,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
collectionUid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header' && credentials?.access_token) {
request.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials.access_token}`.trim();
@@ -249,11 +249,11 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
if (preferencesUtil.shouldSendCookies()) {
const cookieString = getCookieStringForUrl(request.url);
if (cookieString && typeof cookieString === 'string' && cookieString.length) {
const existingCookieHeaderName = Object.keys(request.headers).find((name) => name.toLowerCase() === 'cookie');
const existingCookieHeaderName = Object.keys(request.headers).find(name => name.toLowerCase() === 'cookie');
const existingCookieString = existingCookieHeaderName ? request.headers[existingCookieHeaderName] : '';
// Helper function to parse cookies into an object
const parseCookies = (str) =>
const parseCookies = str =>
str.split(';').reduce((cookies, cookie) => {
const [name, ...rest] = cookie.split('=');
if (name && name.trim()) {
@@ -264,7 +264,7 @@ const configureRequest = async (collectionUid, request, envVars, runtimeVariable
const mergedCookies = {
...parseCookies(existingCookieString),
...parseCookies(cookieString)
...parseCookies(cookieString),
};
const combinedCookieString = Object.entries(mergedCookies)
@@ -381,12 +381,12 @@ const registerNetworkIpc = (mainWindow) => {
channel, // 'main:run-request-event' | 'main:run-folder-event'
basePayload, // request-level or runner-level identifiers
scriptType, // 'pre-request' | 'post-response' | 'test'
error // optional Error
error, // optional Error
}) => {
mainWindow.webContents.send(channel, {
type: `${scriptType}-script-execution`,
...basePayload,
errorMessage: error ? error.message || `An error occurred in ${scriptType.replace('-', ' ')} script` : null
errorMessage: error ? error.message || `An error occurred in ${scriptType.replace('-', ' ')} script` : null,
});
};
@@ -578,7 +578,7 @@ const registerNetworkIpc = (mainWindow) => {
envVars,
processEnvVars,
runtimeVariables,
runInBackground = false
runInBackground = false,
}) => {
const collectionUid = collection.uid;
const collectionPath = collection.pathname;
@@ -600,7 +600,7 @@ const registerNetworkIpc = (mainWindow) => {
envVars,
processEnvVars,
runtimeVariables,
runInBackground: true
runInBackground: true,
});
resolve(res);
}
@@ -608,14 +608,14 @@ const registerNetworkIpc = (mainWindow) => {
});
};
!runInBackground &&
mainWindow.webContents.send('main:run-request-event', {
type: 'request-queued',
requestUid,
collectionUid,
itemUid: item.uid,
cancelTokenUid
});
!runInBackground
&& mainWindow.webContents.send('main:run-request-event', {
type: 'request-queued',
requestUid,
collectionUid,
itemUid: item.uid,
cancelTokenUid,
});
const abortController = new AbortController();
const request = await prepareRequest(item, collection, abortController);
@@ -657,13 +657,13 @@ const registerNetworkIpc = (mainWindow) => {
});
}
!runInBackground &&
notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'pre-request',
error: preRequestError
});
!runInBackground
&& notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'pre-request',
error: preRequestError,
});
if (preRequestError) {
return Promise.reject(preRequestError);
@@ -686,15 +686,15 @@ const registerNetworkIpc = (mainWindow) => {
dataBuffer: requestDataBuffer
};
!runInBackground &&
mainWindow.webContents.send('main:run-request-event', {
type: 'request-sent',
requestSent,
collectionUid,
itemUid: item.uid,
requestUid,
cancelTokenUid
});
!runInBackground
&& mainWindow.webContents.send('main:run-request-event', {
type: 'request-sent',
requestSent,
collectionUid,
itemUid: item.uid,
requestUid,
cancelTokenUid,
});
if (request?.oauth2Credentials) {
mainWindow.webContents.send('main:credentials-update', {
@@ -705,7 +705,7 @@ const registerNetworkIpc = (mainWindow) => {
...(request?.oauth2Credentials?.folderUid
? { folderUid: request.oauth2Credentials.folderUid }
: { itemUid: item.uid }),
debugInfo: request?.oauth2Credentials?.debugInfo
debugInfo: request?.oauth2Credentials?.debugInfo,
});
}
@@ -801,13 +801,13 @@ const registerNetworkIpc = (mainWindow) => {
});
}
!runInBackground &&
notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'post-response',
error: postResponseError
});
!runInBackground
&& notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'post-response',
error: postResponseError,
});
// run assertions
const assertions = get(request, 'assertions');
@@ -822,14 +822,14 @@ const registerNetworkIpc = (mainWindow) => {
processEnvVars
);
!runInBackground &&
mainWindow.webContents.send('main:run-request-event', {
type: 'assertion-results',
results: results,
itemUid: item.uid,
requestUid,
collectionUid
});
!runInBackground
&& mainWindow.webContents.send('main:run-request-event', {
type: 'assertion-results',
results: results,
itemUid: item.uid,
requestUid,
collectionUid,
});
}
const testFile = get(request, 'tests');
@@ -870,14 +870,14 @@ const registerNetworkIpc = (mainWindow) => {
}
}
!runInBackground &&
mainWindow.webContents.send('main:run-request-event', {
type: 'test-results',
results: testResults.results,
itemUid: item.uid,
requestUid,
collectionUid
});
!runInBackground
&& mainWindow.webContents.send('main:run-request-event', {
type: 'test-results',
results: testResults.results,
itemUid: item.uid,
requestUid,
collectionUid,
});
mainWindow.webContents.send('main:script-environment-update', {
envVariables: testResults.envVariables,
@@ -897,13 +897,13 @@ const registerNetworkIpc = (mainWindow) => {
collection.globalEnvironmentVariables = testResults.globalEnvironmentVariables;
!runInBackground &&
notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'test',
error: testError
});
!runInBackground
&& notifyScriptExecution({
channel: 'main:run-request-event',
basePayload: { requestUid, collectionUid, itemUid: item.uid },
scriptType: 'test',
error: testError,
});
const domainsWithCookiesTest = await getDomainsWithCookies();
mainWindow.webContents.send('main:cookies-update', safeParseJSON(safeStringifyJSON(domainsWithCookiesTest)));
@@ -1000,7 +1000,7 @@ const registerNetworkIpc = (mainWindow) => {
envVars,
processEnvVars,
runtimeVariables,
runInBackground: true
runInBackground: true,
});
resolve(res);
}
@@ -1136,10 +1136,8 @@ const registerNetworkIpc = (mainWindow) => {
});
const domainsWithCookiesPreRequest = await getDomainsWithCookies();
mainWindow.webContents.send(
'main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesPreRequest))
);
mainWindow.webContents.send('main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesPreRequest)));
if (preRequestError) {
throw preRequestError;
@@ -1207,7 +1205,7 @@ const registerNetworkIpc = (mainWindow) => {
...(request?.oauth2Credentials?.folderUid
? { folderUid: request.oauth2Credentials.folderUid }
: { itemUid: item.uid }),
debugInfo: request?.oauth2Credentials?.debugInfo
debugInfo: request?.oauth2Credentials?.debugInfo,
});
}
@@ -1260,9 +1258,9 @@ const registerNetworkIpc = (mainWindow) => {
timeline: response.timeline,
url: response.request
? response.request.protocol + '//' + response.request.host + response.request.path
: null
: null,
},
...eventData
...eventData,
});
} catch (error) {
// Skip further processing if request was cancelled
@@ -1287,7 +1285,7 @@ const registerNetworkIpc = (mainWindow) => {
size: Buffer.byteLength(dataBuffer),
data: error.response.data,
responseTime: error.response.responseTime,
timeline: error.response.timeline
timeline: error.response.timeline,
};
// if we get a response from the server, we consider it as a success
@@ -1334,10 +1332,8 @@ const registerNetworkIpc = (mainWindow) => {
});
const domainsWithCookiesPostResponse = await getDomainsWithCookies();
mainWindow.webContents.send(
'main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesPostResponse))
);
mainWindow.webContents.send('main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesPostResponse)));
if (postResponseScriptResult?.nextRequestName !== undefined) {
nextRequestName = postResponseScriptResult.nextRequestName;
@@ -1445,10 +1441,8 @@ const registerNetworkIpc = (mainWindow) => {
});
const domainsWithCookiesTest = await getDomainsWithCookies();
mainWindow.webContents.send(
'main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesTest))
);
mainWindow.webContents.send('main:cookies-update',
safeParseJSON(safeStringifyJSON(domainsWithCookiesTest)));
}
} catch (error) {
mainWindow.webContents.send('main:run-folder-event', {

View File

@@ -12,13 +12,13 @@ const {
mergeScripts,
mergeVars,
mergeAuth,
getFormattedCollectionOauth2Credentials
getFormattedCollectionOauth2Credentials,
} = require('../../utils/collection');
const { getProcessEnvVars } = require('../../store/process-env');
const {
getOAuth2TokenUsingPasswordCredentials,
getOAuth2TokenUsingClientCredentials,
getOAuth2TokenUsingAuthorizationCode
getOAuth2TokenUsingAuthorizationCode,
} = require('../../utils/oauth2');
const { interpolateString } = require('./interpolate-string');
const path = require('node:path');
@@ -29,13 +29,13 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
const collectionRoot = collection?.draft ? get(collection, 'draft', {}) : get(collection, 'root', {});
const headers = {};
each(get(collectionRoot, 'request.headers', []), (h) => {
each(get(collectionRoot, 'request.headers', []), h => {
if (h.enabled && h.name?.toLowerCase() === 'content-type') {
return false;
}
});
each(get(request, 'headers', []), (h) => {
each(get(request, 'headers', []), h => {
if (h.enabled) {
headers[h.name] = h.value;
}
@@ -58,7 +58,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
folderVariables: request.folderVariables,
requestVariables: request.requestVariables,
globalEnvironmentVariables: request.globalEnvironmentVariables,
oauth2CredentialVariables: request.oauth2CredentialVariables
oauth2CredentialVariables: request.oauth2CredentialVariables,
};
wsRequest = setAuthHeaders(wsRequest, request, collection);
@@ -75,11 +75,11 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingAuthorizationCode({
request: requestCopy,
collectionUid: collection.uid,
certsAndProxyConfig
certsAndProxyConfig,
}));
wsRequest.oauth2Credentials = {
credentials,
@@ -87,7 +87,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
collectionUid: collection.uid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
@@ -105,11 +105,11 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingClientCredentials({
request: requestCopy,
collectionUid: collection.uid,
certsAndProxyConfig
certsAndProxyConfig,
}));
wsRequest.oauth2Credentials = {
credentials,
@@ -117,7 +117,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
collectionUid: collection.uid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
@@ -135,11 +135,11 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
credentials,
url: oauth2Url,
credentialsId,
debugInfo
debugInfo,
} = await getOAuth2TokenUsingPasswordCredentials({
request: requestCopy,
collectionUid: collection.uid,
certsAndProxyConfig
certsAndProxyConfig,
}));
wsRequest.oauth2Credentials = {
credentials,
@@ -147,7 +147,7 @@ const prepareWsRequest = async (item, collection, environment, runtimeVariables,
collectionUid: collection.uid,
credentialsId,
debugInfo,
folderUid: request.oauth2Credentials?.folderUid
folderUid: request.oauth2Credentials?.folderUid,
};
if (tokenPlacement == 'header') {
wsRequest.headers['Authorization'] = `${tokenHeaderPrefix} ${credentials?.access_token}`;
@@ -173,7 +173,7 @@ let wsClient;
/**
* Register IPC handlers for WebSocket
*/
const registerWsEventHandlers = (window) => {
const registerWsEventHandlers = window => {
const sendEvent = (eventName, ...args) => {
if (window && window.webContents) {
window.webContents.send(eventName, ...args);
@@ -184,13 +184,12 @@ const registerWsEventHandlers = (window) => {
wsClient = new WsClient(sendEvent);
ipcMain.handle('ws:connections-changed', (event) => {
ipcMain.handle('ws:connections-changed', event => {
sendEvent('ws:connections-changed', event);
});
// Start a new WebSocket connection
ipcMain.handle(
'ws:start-connection',
ipcMain.handle('ws:start-connection',
async (event, { request, collection, environment, runtimeVariables, settings, options = {} }) => {
try {
const requestCopy = cloneDeep(request);
@@ -201,13 +200,13 @@ const registerWsEventHandlers = (window) => {
url: preparedRequest.url,
headers: preparedRequest.headers,
body: preparedRequest.body,
timestamp: Date.now()
timestamp: Date.now(),
};
if (!connectOnly) {
const hasMessages = preparedRequest.body.ws.some((msg) => msg.content.length);
const hasMessages = preparedRequest.body.ws.some(msg => msg.content.length);
if (hasMessages) {
preparedRequest.body.ws.forEach((message) => {
preparedRequest.body.ws.forEach(message => {
wsClient.queueMessage(preparedRequest.uid, collection.uid, message.content);
});
}
@@ -220,8 +219,8 @@ const registerWsEventHandlers = (window) => {
options: {
timeout: settings.connectionTimeout,
keepAlive: settings.keepAliveInterval > 0 ? true : false,
keepAliveInterval: settings.keepAliveInterval
}
keepAliveInterval: settings.keepAliveInterval,
},
});
sendEvent('ws:request', preparedRequest.uid, collection.uid, requestSent);
@@ -236,7 +235,7 @@ const registerWsEventHandlers = (window) => {
...(preparedRequest.oauth2Credentials?.folderUid
? { folderUid: preparedRequest.oauth2Credentials.folderUid }
: { itemUid: preparedRequest.uid }),
debugInfo: preparedRequest.oauth2Credentials.debugInfo
debugInfo: preparedRequest.oauth2Credentials.debugInfo,
});
}
@@ -249,11 +248,10 @@ const registerWsEventHandlers = (window) => {
sendEvent('ws:error', request.uid, collection.uid, { error: error.message });
return { success: false, error: error.message };
}
}
);
});
// Get all active connection IDs
ipcMain.handle('ws:get-active-connections', (event) => {
ipcMain.handle('ws:get-active-connections', event => {
try {
const activeConnectionIds = wsClient.getActiveConnectionIds();
return { success: true, activeConnectionIds };
@@ -309,5 +307,5 @@ const registerWsEventHandlers = (window) => {
module.exports = {
registerWsEventHandlers,
wsClient
wsClient,
};

View File

@@ -35,7 +35,7 @@ export const bruRequestToJson = (data: string | any, parsed: boolean = false): a
const urlPath: Record<typeof requestType, string> = {
'grpc-request': 'grpc.url',
'ws-request': 'ws.url',
default: 'http.url'
'default': 'http.url',
};
const transformedJson = {
type: requestType,
@@ -192,9 +192,9 @@ export const jsonRequestToBru = (json: any): string => {
ws: _.get(json, 'request.body.ws', [
{
name: 'message 1',
content: '{}'
}
])
content: '{}',
},
]),
});
}

View File

@@ -283,16 +283,16 @@ const mapPairListToKeyValPair = (pairList = []) => {
* @param {Record<unknown,unknown>} obj
* @returns {(key:string, opts?:{fallback: number })=>number|undefined}
*/
const createGetNumFromRecord =
(obj) =>
(key, { fallback } = {}) => {
if (!(key in obj)) return fallback;
const asNumber = typeof obj[key] === 'number' ? obj[key] : Number(obj[key]);
if (isNaN(asNumber)) {
return fallback;
}
return asNumber;
};
const createGetNumFromRecord
= obj =>
(key, { fallback } = {}) => {
if (!(key in obj)) return fallback;
const asNumber = typeof obj[key] === 'number' ? obj[key] : Number(obj[key]);
if (isNaN(asNumber)) {
return fallback;
}
return asNumber;
};
const sem = grammar.createSemantics().addAttribute('ast', {
BruFile(tags) {
@@ -434,12 +434,12 @@ const sem = grammar.createSemantics().addAttribute('ast', {
const getNumFromRecord = createGetNumFromRecord(settings);
const keepAliveInterval = getNumFromRecord('keepAliveInterval');
const connectionTimeout = getNumFromRecord('connectionTimeout');
if (keepAliveInterval || connectionTimeout) {
result.settings.keepAliveInterval = keepAliveInterval;
result.settings.connectionTimeout = connectionTimeout;
}
return result;
},
grpc(_1, dictionary) {
@@ -449,7 +449,7 @@ const sem = grammar.createSemantics().addAttribute('ast', {
},
ws(_1, dictionary) {
return {
ws: mapPairListToKeyValPair(dictionary.ast)
ws: mapPairListToKeyValPair(dictionary.ast),
};
},
get(_1, dictionary) {
@@ -991,10 +991,10 @@ const sem = grammar.createSemantics().addAttribute('ast', {
grpc: [
{
name: messageName,
content: '{}'
}
]
}
content: '{}',
},
],
},
};
}
@@ -1004,10 +1004,10 @@ const sem = grammar.createSemantics().addAttribute('ast', {
grpc: [
{
name: messageName,
content: messageContent
}
]
}
content: messageContent,
},
],
},
};
},
});

View File

@@ -2,11 +2,11 @@ const _ = require('lodash');
const { indentString, getValueString } = require('./utils');
const enabled = (items = [], key = 'enabled') => items.filter((item) => item[key]);
const disabled = (items = [], key = 'enabled') => items.filter((item) => !item[key]);
const enabled = (items = [], key = 'enabled') => items.filter(item => item[key]);
const disabled = (items = [], key = 'enabled') => items.filter(item => !item[key]);
const quoteKey = (key) => {
const quotableChars = [':', '"', '{', '}', ' '];
return quotableChars.some((char) => key.includes(char)) ? '"' + key.replaceAll('"', '\\"') + '"' : key;
return quotableChars.some(char => key.includes(char)) ? ('"' + key.replaceAll('"', '\\"') + '"') : key;
};
// remove the last line if two new lines are found
@@ -17,7 +17,8 @@ const stripLastLine = (text) => {
};
const jsonToBru = (json) => {
const { meta, http, grpc, ws, params, headers, metadata, auth, body, script, tests, vars, assertions, settings, docs } = json;
const { meta, http, grpc, params, headers, metadata, auth, body, script, tests, vars, assertions, settings, docs } = json;
let bru = '';
@@ -97,35 +98,6 @@ const jsonToBru = (json) => {
`;
}
if (ws && ws.url) {
bru += `ws {
url: ${ws.url}`;
if (ws.method && ws.method.length) {
bru += `
method: ${ws.method}`;
}
if (ws.body && ws.body.length) {
bru += `
body: ${ws.body}`;
}
if (ws.auth && ws.auth.length) {
bru += `
auth: ${ws.auth}`;
}
if (ws.methodType && ws.methodType.length) {
bru += `
methodType: ${ws.methodType}`;
}
bru += `
}
`;
}
if (params && params.length) {
const queryParams = params.filter((param) => param.type === 'query');
@@ -277,14 +249,10 @@ ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)}
${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header'
? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`)
: ''
}${
auth?.oauth2?.tokenPlacement !== 'header'
? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`)
: ''
}
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
}
@@ -306,14 +274,10 @@ ${indentString(`pkce: ${(auth?.oauth2?.pkce || false).toString()}`)}
${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)}
${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header'
? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`)
: ''
}${
auth?.oauth2?.tokenPlacement !== 'header'
? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`)
: ''
}
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
}
@@ -331,14 +295,10 @@ ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
${indentString(`credentials_placement: ${auth?.oauth2?.credentialsPlacement || ''}`)}
${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header'
? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`)
: ''
}${
auth?.oauth2?.tokenPlacement !== 'header'
? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`)
: ''
}
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
${indentString(`auto_refresh_token: ${(auth?.oauth2?.autoRefreshToken ?? false).toString()}`)}
}
@@ -355,14 +315,10 @@ ${indentString(`scope: ${auth?.oauth2?.scope || ''}`)}
${indentString(`state: ${auth?.oauth2?.state || ''}`)}
${indentString(`credentials_id: ${auth?.oauth2?.credentialsId || ''}`)}
${indentString(`token_placement: ${auth?.oauth2?.tokenPlacement || ''}`)}${
auth?.oauth2?.tokenPlacement == 'header'
? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`)
: ''
}${
auth?.oauth2?.tokenPlacement !== 'header'
? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`)
: ''
}
auth?.oauth2?.tokenPlacement == 'header' ? '\n' + indentString(`token_header_prefix: ${auth?.oauth2?.tokenHeaderPrefix || ''}`) : ''
}${
auth?.oauth2?.tokenPlacement !== 'header' ? '\n' + indentString(`token_query_key: ${auth?.oauth2?.tokenQueryKey || ''}`) : ''
}
${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toString()}`)}
}
@@ -371,111 +327,96 @@ ${indentString(`auto_fetch_token: ${(auth?.oauth2?.autoFetchToken ?? true).toStr
}
if (auth?.oauth2?.additionalParameters) {
const {
authorization: authorizationParams,
token: tokenParams,
refresh: refreshParams
} = auth?.oauth2?.additionalParameters;
const authorizationHeaders = authorizationParams?.filter((p) => p?.sendIn == 'headers');
const { authorization: authorizationParams, token: tokenParams, refresh: refreshParams } = auth?.oauth2?.additionalParameters;
const authorizationHeaders = authorizationParams?.filter(p => p?.sendIn == 'headers');
if (authorizationHeaders?.length) {
bru += `auth:oauth2:additional_params:auth_req:headers {
${indentString(
authorizationHeaders
.filter((item) => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.filter(item => item?.name?.length)
.map(item => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n'))}
}
`;
}
const authorizationQueryParams = authorizationParams?.filter((p) => p?.sendIn == 'queryparams');
const authorizationQueryParams = authorizationParams?.filter(p => p?.sendIn == 'queryparams');
if (authorizationQueryParams?.length) {
bru += `auth:oauth2:additional_params:auth_req:queryparams {
${indentString(
authorizationQueryParams
.filter((item) => item?.name?.length)
.filter(item => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.join('\n'))}
}
`;
}
const tokenHeaders = tokenParams?.filter((p) => p?.sendIn == 'headers');
const tokenHeaders = tokenParams?.filter(p => p?.sendIn == 'headers');
if (tokenHeaders?.length) {
bru += `auth:oauth2:additional_params:access_token_req:headers {
${indentString(
tokenHeaders
.filter((item) => item?.name?.length)
${indentString(tokenHeaders
.filter(item => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.join('\n'))}
}
`;
}
const tokenQueryParams = tokenParams?.filter((p) => p?.sendIn == 'queryparams');
const tokenQueryParams = tokenParams?.filter(p => p?.sendIn == 'queryparams');
if (tokenQueryParams?.length) {
bru += `auth:oauth2:additional_params:access_token_req:queryparams {
${indentString(
tokenQueryParams
.filter((item) => item?.name?.length)
.filter(item => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.join('\n'))}
}
`;
}
const tokenBodyValues = tokenParams?.filter((p) => p?.sendIn == 'body');
const tokenBodyValues = tokenParams?.filter(p => p?.sendIn == 'body');
if (tokenBodyValues?.length) {
bru += `auth:oauth2:additional_params:access_token_req:body {
${indentString(
tokenBodyValues
.filter((item) => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.filter(item => item?.name?.length)
.map(item => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n'))}
}
`;
}
const refreshHeaders = refreshParams?.filter((p) => p?.sendIn == 'headers');
const refreshHeaders = refreshParams?.filter(p => p?.sendIn == 'headers');
if (refreshHeaders?.length) {
bru += `auth:oauth2:additional_params:refresh_token_req:headers {
${indentString(
refreshHeaders
.filter((item) => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.filter(item => item?.name?.length)
.map(item => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n'))}
}
`;
}
const refreshQueryParams = refreshParams?.filter((p) => p?.sendIn == 'queryparams');
const refreshQueryParams = refreshParams?.filter(p => p?.sendIn == 'queryparams');
if (refreshQueryParams?.length) {
bru += `auth:oauth2:additional_params:refresh_token_req:queryparams {
${indentString(
refreshQueryParams
.filter((item) => item?.name?.length)
${indentString(refreshQueryParams
.filter(item => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
.join('\n'))}
}
`;
}
const refreshBodyValues = refreshParams?.filter((p) => p?.sendIn == 'body');
const refreshBodyValues = refreshParams?.filter(p => p?.sendIn == 'body');
if (refreshBodyValues?.length) {
bru += `auth:oauth2:additional_params:refresh_token_req:body {
${indentString(
refreshBodyValues
.filter((item) => item?.name?.length)
.map((item) => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n')
)}
${indentString(refreshBodyValues
.filter(item => item?.name?.length)
.map(item => `${item.enabled ? '' : '~'}${item.name}: ${item.value}`)
.join('\n'))}
}
`;
@@ -585,8 +526,8 @@ ${indentString(body.sparql)}
files
.map((item) => {
const selected = item.selected ? '' : '~';
const contentType =
item.contentType && item.contentType !== '' ? ' @contentType(' + item.contentType + ')' : '';
const contentType
= item.contentType && item.contentType !== '' ? ' @contentType(' + item.contentType + ')' : '';
const filePath = item.filePath || '';
const value = `@file(${filePath})`;
const itemName = 'file';

View File

@@ -28,15 +28,15 @@ module.exports = [
peerDepsExternal(),
nodeResolve({
extensions: ['.js', '.ts', '.tsx', '.json', '.css'],
dedupe: ['@grpc/grpc-js', 'ws'],
preferBuiltins: true
dedupe: ['@grpc/grpc-js'],
preferBuiltins: true,
}),
json(),
commonjs({
transformMixedEsModules: true
}),
typescript({ tsconfig: './tsconfig.json' }),
terser()
terser(),
],
external: ['axios', 'qs', 'ws']
}

View File

@@ -15,7 +15,7 @@ const safeJsonParse = (jsonString, context = 'JSON string') => {
const errorMessage = `Failed to parse ${context}: ${error.message}`;
console.error(errorMessage, {
originalString: jsonString,
parseError: error
parseError: error,
});
throw new Error(errorMessage);
}
@@ -26,8 +26,8 @@ const safeJsonParse = (jsonString, context = 'JSON string') => {
* @param {string} url - The WebSocket URL
* @returns {Object} Parsed URL object with protocol, host, path
*/
const getParsedWsUrlObject = (url) => {
const addProtocolIfMissing = (str) => {
const getParsedWsUrlObject = url => {
const addProtocolIfMissing = str => {
if (str.includes('://')) return str;
// For localhost, default to insecure (grpc://) for local development
@@ -39,7 +39,7 @@ const getParsedWsUrlObject = (url) => {
return `wss://${str}`;
};
const removeTrailingSlash = (str) => (str.endsWith('/') ? str.slice(0, -1) : str);
const removeTrailingSlash = str => (str.endsWith('/') ? str.slice(0, -1) : str);
if (!url) return { host: '', path: '' };
@@ -50,13 +50,13 @@ const getParsedWsUrlObject = (url) => {
host: urlObj.host,
path: removeTrailingSlash(urlObj.pathname),
search: urlObj.search,
fullUrl: urlObj.href
fullUrl: urlObj.href,
};
} catch (err) {
console.error({ err });
return {
host: '',
path: ''
path: '',
};
}
};
@@ -91,7 +91,7 @@ class WsClient {
const wsConnection = new ws.WebSocket(parsedUrl.fullUrl, {
headers,
handshakeTimeout: timeout,
followRedirects: true
followRedirects: true,
});
// Set up event handlers
@@ -107,7 +107,7 @@ class WsClient {
} catch (error) {
console.error('Error creating WebSocket connection:', error);
this.eventCallback('ws:error', requestId, collectionUid, {
error: error.message
error: error.message,
});
throw error;
}
@@ -162,7 +162,7 @@ class WsClient {
}
// Send the message
connection.send(JSON.stringify(messageToSend), (error) => {
connection.send(JSON.stringify(messageToSend), error => {
if (error) {
this.eventCallback('ws:error', requestId, collectionUid, { error });
} else {
@@ -171,14 +171,14 @@ class WsClient {
message: messageToSend,
messageHexdump: hexdump(JSON.stringify(messageToSend)),
type: 'outgoing',
timestamp: Date.now()
timestamp: Date.now(),
});
}
});
} else {
const error = new Error('WebSocket connection not available or not open');
this.eventCallback('ws:error', requestId, collectionUid, {
error: error.message
error: error.message,
});
}
}
@@ -221,7 +221,7 @@ class WsClient {
clearAllConnections() {
const connectionIds = this.getActiveConnectionIds();
this.activeConnections.forEach((connection) => {
this.activeConnections.forEach(connection => {
if (connection.readyState === WebSocket.OPEN) {
connection.close(1000, 'Client clearing all connections');
}
@@ -233,7 +233,7 @@ class WsClient {
if (connectionIds.length > 0) {
this.eventCallback('ws:connections-changed', {
type: 'cleared',
activeConnectionIds: []
activeConnectionIds: [],
});
}
}
@@ -264,37 +264,37 @@ class WsClient {
this.eventCallback('ws:open', requestId, collectionUid, {
timestamp: Date.now(),
url: ws.url
url: ws.url,
});
});
ws.on('redirect', (url, req) => {
const headerNames = req.getHeaderNames();
const headers = Object.fromEntries(headerNames.map((d) => [d, req.getHeader(d)]));
const headers = Object.fromEntries(headerNames.map(d => [d, req.getHeader(d)]));
this.eventCallback('ws:redirect', requestId, collectionUid, {
message: `Redirected to ${url}`,
type: 'info',
timestamp: Date.now(),
headers: headers
headers: headers,
});
});
ws.on('upgrade', (response) => {
ws.on('upgrade', response => {
this.eventCallback('ws:upgrade', requestId, collectionUid, {
type: 'info',
timestamp: Date.now(),
headers: { ...response.headers }
headers: { ...response.headers },
});
});
ws.on('message', (data) => {
ws.on('message', data => {
try {
const message = JSON.parse(data.toString());
this.eventCallback('ws:message', requestId, collectionUid, {
message,
messageHexdump: hexdump(Buffer.from(data)),
type: 'incoming',
timestamp: Date.now()
timestamp: Date.now(),
});
} catch (error) {
// If parsing fails, send as raw data
@@ -302,7 +302,7 @@ class WsClient {
message: data.toString(),
messageHexdump: hexdump(data),
type: 'incoming',
timestamp: Date.now()
timestamp: Date.now(),
});
}
});
@@ -311,15 +311,15 @@ class WsClient {
this.eventCallback('ws:close', requestId, collectionUid, {
code,
reason: Buffer.from(reason).toString(),
timestamp: Date.now()
timestamp: Date.now(),
});
this.#removeConnection(requestId);
});
ws.on('error', (error) => {
ws.on('error', error => {
this.eventCallback('ws:error', requestId, collectionUid, {
error: error.message,
timestamp: Date.now()
timestamp: Date.now(),
});
});
}
@@ -337,7 +337,7 @@ class WsClient {
this.eventCallback('ws:connections-changed', {
type: 'added',
requestId,
activeConnectionIds: this.getActiveConnectionIds()
activeConnectionIds: this.getActiveConnectionIds(),
});
}
@@ -364,7 +364,7 @@ class WsClient {
this.eventCallback('ws:connections-changed', {
type: 'removed',
requestId,
activeConnectionIds: this.getActiveConnectionIds()
activeConnectionIds: this.getActiveConnectionIds(),
});
}
}