@testsmith/api-spector 0.4.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/out/main/chunks/{handle-Coax8Nz1.js → handle-BGYDylL2.js} +6 -0
- package/out/main/chunks/{import-Bilo697Z.js → import-CUcjlmSK.js} +2 -2
- package/out/main/chunks/{request-exec-C0DnGKdd.js → request-exec-DlvyG4rn.js} +1 -1
- package/out/main/chunks/{snapshots-CatB4zLh.js → snapshots-B7rDeWNy.js} +1 -1
- package/out/main/chunks/{soap-handler-B1Huudj7.js → soap-handler-CAyUjzxB.js} +2 -2
- package/out/main/contract.js +3 -3
- package/out/main/index.js +217 -18
- package/out/main/runner.js +3 -3
- package/out/main/wsdl.js +3 -3
- package/out/preload/index.js +9 -0
- package/out/renderer/assets/{index-BtkRge9R.js → index-DGOQFW5S.js} +490 -44
- package/out/renderer/assets/index-DkZ0bxof.css +2 -0
- package/out/renderer/index.html +2 -2
- package/package.json +1 -1
- package/out/renderer/assets/index-B6kFQEbI.css +0 -2
|
@@ -13983,6 +13983,16 @@ const createCollectionsSlice = (set2, get2) => ({
|
|
|
13983
13983
|
if (folder.headers?.length) inheritedHeaders = [...inheritedHeaders, ...folder.headers];
|
|
13984
13984
|
}
|
|
13985
13985
|
return { auth: inheritedAuth, headers: inheritedHeaders };
|
|
13986
|
+
},
|
|
13987
|
+
getInheritedVariables: (requestId) => {
|
|
13988
|
+
const state = get2();
|
|
13989
|
+
const colEntry = Object.values(state.collections).find((c) => c.data.requests[requestId]);
|
|
13990
|
+
if (!colEntry) return {};
|
|
13991
|
+
const merged = {};
|
|
13992
|
+
for (const folder of findFolderPath(colEntry.data.rootFolder, requestId)) {
|
|
13993
|
+
if (folder.variables) Object.assign(merged, folder.variables);
|
|
13994
|
+
}
|
|
13995
|
+
return merged;
|
|
13986
13996
|
}
|
|
13987
13997
|
});
|
|
13988
13998
|
function envSlugRelPath(name2) {
|
|
@@ -14133,6 +14143,7 @@ const createUiSlice = (set2) => ({
|
|
|
14133
14143
|
pinnedResponse: null,
|
|
14134
14144
|
activeGitDiff: null,
|
|
14135
14145
|
quickInsertsOpen: true,
|
|
14146
|
+
sendSignal: 0,
|
|
14136
14147
|
setShowGeneratorPanel: (v) => set2((s) => {
|
|
14137
14148
|
s.showGeneratorPanel = v;
|
|
14138
14149
|
}),
|
|
@@ -14180,6 +14191,9 @@ const createUiSlice = (set2) => ({
|
|
|
14180
14191
|
}),
|
|
14181
14192
|
setQuickInsertsOpen: (open) => set2((s) => {
|
|
14182
14193
|
s.quickInsertsOpen = open;
|
|
14194
|
+
}),
|
|
14195
|
+
requestSend: () => set2((s) => {
|
|
14196
|
+
s.sendSignal += 1;
|
|
14183
14197
|
})
|
|
14184
14198
|
});
|
|
14185
14199
|
const useStore = create()(
|
|
@@ -35817,11 +35831,17 @@ function FolderSettingsModal({ collectionId, folder, onClose }) {
|
|
|
35817
35831
|
const [activeTab, setActiveTab] = reactExports.useState("auth");
|
|
35818
35832
|
const [auth, setAuth] = reactExports.useState(folder.auth ?? { type: "none" });
|
|
35819
35833
|
const [headers, setHeaders] = reactExports.useState(folder.headers ?? []);
|
|
35834
|
+
const [varRows, setVarRows] = reactExports.useState(
|
|
35835
|
+
Object.entries(folder.variables ?? {}).map(([key, value]) => ({ key, value, enabled: true }))
|
|
35836
|
+
);
|
|
35820
35837
|
function patchAuth(patch) {
|
|
35821
35838
|
setAuth((prev) => ({ ...prev, ...patch }));
|
|
35822
35839
|
}
|
|
35823
35840
|
function save() {
|
|
35824
|
-
|
|
35841
|
+
const variables = Object.fromEntries(
|
|
35842
|
+
varRows.filter((r) => r.key.trim()).map((r) => [r.key.trim(), r.value])
|
|
35843
|
+
);
|
|
35844
|
+
updateFolder(collectionId, folder.id, { auth, headers, variables });
|
|
35825
35845
|
onClose();
|
|
35826
35846
|
}
|
|
35827
35847
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -35836,12 +35856,12 @@ function FolderSettingsModal({ collectionId, folder, onClose }) {
|
|
|
35836
35856
|
/* @__PURE__ */ jsxRuntimeExports.jsx("h2", { className: "text-sm font-semibold", children: "Folder settings" }),
|
|
35837
35857
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-surface-600 mt-0.5", children: [
|
|
35838
35858
|
folder.name,
|
|
35839
|
-
" - auth and
|
|
35859
|
+
" - auth, headers and variables inherited by all requests in this folder"
|
|
35840
35860
|
] })
|
|
35841
35861
|
] }),
|
|
35842
35862
|
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onClose, className: "text-surface-400 hover:text-white text-lg leading-none", children: "×" })
|
|
35843
35863
|
] }),
|
|
35844
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex border-b border-surface-800 px-4 shrink-0", children: ["auth", "headers"].map((t2) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35864
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex border-b border-surface-800 px-4 shrink-0", children: ["auth", "headers", "variables"].map((t2) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35845
35865
|
"button",
|
|
35846
35866
|
{
|
|
35847
35867
|
onClick: () => setActiveTab(t2),
|
|
@@ -35868,7 +35888,23 @@ function FolderSettingsModal({ collectionId, folder, onClose }) {
|
|
|
35868
35888
|
valuePlaceholder: "value",
|
|
35869
35889
|
headerMode: true
|
|
35870
35890
|
}
|
|
35871
|
-
)
|
|
35891
|
+
),
|
|
35892
|
+
activeTab === "variables" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
35893
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px] text-surface-600", children: [
|
|
35894
|
+
"Variables scoped to this folder. They override collection variables and are overridden by an inner folder, the active environment, and script-set values. Reference them anywhere with ",
|
|
35895
|
+
"{{name}}",
|
|
35896
|
+
"."
|
|
35897
|
+
] }),
|
|
35898
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
35899
|
+
KVTable,
|
|
35900
|
+
{
|
|
35901
|
+
rows: varRows,
|
|
35902
|
+
onChange: setVarRows,
|
|
35903
|
+
keyPlaceholder: "VARIABLE_NAME",
|
|
35904
|
+
valuePlaceholder: "value"
|
|
35905
|
+
}
|
|
35906
|
+
)
|
|
35907
|
+
] })
|
|
35872
35908
|
] }),
|
|
35873
35909
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 px-4 py-3 border-t border-surface-800 shrink-0", children: [
|
|
35874
35910
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -63874,6 +63910,7 @@ function RequestBuilder({ request }) {
|
|
|
63874
63910
|
}
|
|
63875
63911
|
const [editingName, setEditingName] = reactExports.useState(false);
|
|
63876
63912
|
const [showFuzz, setShowFuzz] = reactExports.useState(false);
|
|
63913
|
+
const [customVerb, setCustomVerb] = reactExports.useState(false);
|
|
63877
63914
|
const [runHooks, setRunHooks] = reactExports.useState(() => localStorage.getItem("runHooks") !== "false");
|
|
63878
63915
|
function toggleRunHooks() {
|
|
63879
63916
|
setRunHooks((prev) => {
|
|
@@ -63885,6 +63922,14 @@ function RequestBuilder({ request }) {
|
|
|
63885
63922
|
function update(patch) {
|
|
63886
63923
|
updateRequest(request.id, patch);
|
|
63887
63924
|
}
|
|
63925
|
+
const sendSignal = useStore((s) => s.sendSignal);
|
|
63926
|
+
const lastSendSignal = reactExports.useRef(sendSignal);
|
|
63927
|
+
reactExports.useEffect(() => {
|
|
63928
|
+
if (sendSignal !== lastSendSignal.current) {
|
|
63929
|
+
lastSendSignal.current = sendSignal;
|
|
63930
|
+
void sendRequest();
|
|
63931
|
+
}
|
|
63932
|
+
}, [sendSignal]);
|
|
63888
63933
|
async function sendRequest() {
|
|
63889
63934
|
if (!activeTabId) return;
|
|
63890
63935
|
setTabSending(activeTabId, true);
|
|
@@ -63903,6 +63948,8 @@ function RequestBuilder({ request }) {
|
|
|
63903
63948
|
};
|
|
63904
63949
|
let collectionVars = {
|
|
63905
63950
|
...activeCollectionId ? collections[activeCollectionId]?.data.collectionVariables ?? {} : {},
|
|
63951
|
+
// Folder-chain variables sit above collection vars and below session/local.
|
|
63952
|
+
...useStore.getState().getInheritedVariables(request.id),
|
|
63906
63953
|
...sessionVars
|
|
63907
63954
|
};
|
|
63908
63955
|
let liveGlobals = { ...globals };
|
|
@@ -64113,15 +64160,39 @@ function RequestBuilder({ request }) {
|
|
|
64113
64160
|
}
|
|
64114
64161
|
)
|
|
64115
64162
|
] }),
|
|
64116
|
-
!isWs && !isSoap && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
64117
|
-
"
|
|
64163
|
+
!isWs && !isSoap && (customVerb ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
64164
|
+
"input",
|
|
64118
64165
|
{
|
|
64166
|
+
autoFocus: true,
|
|
64119
64167
|
value: request.method,
|
|
64120
|
-
onChange: (e) => update({ method: e.target.value }),
|
|
64121
|
-
|
|
64122
|
-
|
|
64168
|
+
onChange: (e) => update({ method: e.target.value.toUpperCase() }),
|
|
64169
|
+
onBlur: () => setCustomVerb(false),
|
|
64170
|
+
onKeyDown: (e) => {
|
|
64171
|
+
if (e.key === "Enter") {
|
|
64172
|
+
e.preventDefault();
|
|
64173
|
+
setCustomVerb(false);
|
|
64174
|
+
}
|
|
64175
|
+
},
|
|
64176
|
+
placeholder: "VERB",
|
|
64177
|
+
title: "Type any HTTP method",
|
|
64178
|
+
className: "w-24 bg-surface-800 border border-blue-500 rounded px-2 py-1.5 text-xs font-bold uppercase focus:outline-none text-fuchsia-400 placeholder-surface-600"
|
|
64123
64179
|
}
|
|
64124
|
-
)
|
|
64180
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
64181
|
+
"select",
|
|
64182
|
+
{
|
|
64183
|
+
value: METHODS.includes(request.method) ? request.method : "__current__",
|
|
64184
|
+
onChange: (e) => {
|
|
64185
|
+
if (e.target.value === "__custom__") setCustomVerb(true);
|
|
64186
|
+
else if (e.target.value !== "__current__") update({ method: e.target.value });
|
|
64187
|
+
},
|
|
64188
|
+
className: `bg-surface-800 border border-surface-700 rounded px-2 py-1.5 text-xs font-bold focus:outline-none focus:border-blue-500 ${METHOD_COLORS[request.method] ?? "text-fuchsia-400"}`,
|
|
64189
|
+
children: [
|
|
64190
|
+
METHODS.map((m) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: m, className: "text-white", children: m }, m)),
|
|
64191
|
+
!METHODS.includes(request.method) && /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__current__", className: "text-white", children: request.method }),
|
|
64192
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "__custom__", className: "text-white", children: "Custom…" })
|
|
64193
|
+
]
|
|
64194
|
+
}
|
|
64195
|
+
)),
|
|
64125
64196
|
isSoap && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
64126
64197
|
"span",
|
|
64127
64198
|
{
|
|
@@ -65297,7 +65368,7 @@ function KVBlock({ label, rows }) {
|
|
|
65297
65368
|
] }, k))
|
|
65298
65369
|
] });
|
|
65299
65370
|
}
|
|
65300
|
-
function HistoryTabRow({ entry, onLoad }) {
|
|
65371
|
+
function HistoryTabRow({ entry, onLoad, onResend }) {
|
|
65301
65372
|
const [open, setOpen] = reactExports.useState(false);
|
|
65302
65373
|
const reqBody = requestBodyText(entry.request.body);
|
|
65303
65374
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-surface-800", children: [
|
|
@@ -65315,7 +65386,8 @@ function HistoryTabRow({ entry, onLoad }) {
|
|
|
65315
65386
|
] }),
|
|
65316
65387
|
entry.environmentName && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] bg-surface-800 text-surface-400 px-1.5 py-0.5 rounded shrink-0", children: entry.environmentName }),
|
|
65317
65388
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[11px] text-surface-500 ml-auto shrink-0", children: new Date(entry.timestamp).toLocaleString([], { month: "short", day: "numeric", hour: "2-digit", minute: "2-digit", second: "2-digit" }) }),
|
|
65318
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onLoad, title: "Load this response into the viewer", className: "text-[10px] text-blue-400 hover:text-blue-300 shrink-0", children: "load" })
|
|
65389
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onLoad, title: "Load this response into the viewer", className: "text-[10px] text-blue-400 hover:text-blue-300 shrink-0", children: "load" }),
|
|
65390
|
+
onResend && /* @__PURE__ */ jsxRuntimeExports.jsx("button", { onClick: onResend, title: "Send this request again", className: "text-[10px] text-emerald-400 hover:text-emerald-300 shrink-0", children: "resend" })
|
|
65319
65391
|
] }),
|
|
65320
65392
|
open && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-4 pb-3 pt-1 flex flex-col gap-3 bg-surface-950/40", children: [
|
|
65321
65393
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
@@ -65356,6 +65428,7 @@ function ResponseViewer() {
|
|
|
65356
65428
|
const hookResults = activeTab?.lastHookResults ?? null;
|
|
65357
65429
|
const requestId = activeTab?.requestId ?? null;
|
|
65358
65430
|
const setTabResponse = useStore((s) => s.setTabResponse);
|
|
65431
|
+
const requestSend = useStore((s) => s.requestSend);
|
|
65359
65432
|
const history2 = useStore((s) => s.history);
|
|
65360
65433
|
const activeEnvironmentId = useStore((s) => s.activeEnvironmentId);
|
|
65361
65434
|
const environments = useStore((s) => s.environments);
|
|
@@ -65379,6 +65452,13 @@ function ResponseViewer() {
|
|
|
65379
65452
|
setTab("console");
|
|
65380
65453
|
}
|
|
65381
65454
|
}, [scriptResult?.preScriptError, scriptResult?.postScriptError]);
|
|
65455
|
+
reactExports.useEffect(() => {
|
|
65456
|
+
if (response?.error) {
|
|
65457
|
+
if (tab !== "request" && tab !== "history") setTab("error");
|
|
65458
|
+
} else if (tab === "error") {
|
|
65459
|
+
setTab("body");
|
|
65460
|
+
}
|
|
65461
|
+
}, [response]);
|
|
65382
65462
|
const [diffMode, setDiffMode] = reactExports.useState(false);
|
|
65383
65463
|
const [showMockModal, setShowMockModal] = reactExports.useState(false);
|
|
65384
65464
|
const [bodyView, setBodyView] = reactExports.useState("raw");
|
|
@@ -65419,12 +65499,6 @@ function ResponseViewer() {
|
|
|
65419
65499
|
if (!response) {
|
|
65420
65500
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "h-full flex items-center justify-center text-surface-400 text-sm", children: "Hit Send to see the response" });
|
|
65421
65501
|
}
|
|
65422
|
-
if (response.error) {
|
|
65423
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col p-4 gap-2", children: [
|
|
65424
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-400 text-sm font-medium", children: "Request failed" }),
|
|
65425
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-red-300 whitespace-pre-wrap", children: response.error })
|
|
65426
|
-
] });
|
|
65427
|
-
}
|
|
65428
65502
|
const contentType = response.headers["content-type"] ?? "";
|
|
65429
65503
|
const isJson = contentType.includes("json");
|
|
65430
65504
|
const isXml = !isJson && (contentType.includes("xml") || contentType.includes("html"));
|
|
@@ -65442,15 +65516,31 @@ function ResponseViewer() {
|
|
|
65442
65516
|
const totalCount = scriptResult?.testResults.length ?? 0;
|
|
65443
65517
|
const consoleCount = scriptResult?.consoleOutput.length ?? 0;
|
|
65444
65518
|
const hasScriptError = !!(scriptResult?.preScriptError || scriptResult?.postScriptError);
|
|
65445
|
-
const
|
|
65519
|
+
const historyBadge = requestHistory.length > 0 ? requestHistory.length : void 0;
|
|
65520
|
+
const tabList = response.error ? [
|
|
65521
|
+
{ id: "error", label: "Error", error: true },
|
|
65522
|
+
{ id: "request", label: "Request" },
|
|
65523
|
+
{ id: "history", label: "History", badge: historyBadge }
|
|
65524
|
+
] : [
|
|
65446
65525
|
{ id: "request", label: "Request" },
|
|
65447
65526
|
{ id: "body", label: "Body", badge: bodyParseError ? "!" : void 0, error: bodyParseError },
|
|
65448
65527
|
{ id: "headers", label: "Headers" },
|
|
65449
65528
|
{ id: "tests", label: "Tests", badge: totalCount > 0 ? `${passedCount}/${totalCount}` : void 0 },
|
|
65450
65529
|
{ id: "console", label: "Console", badge: hasScriptError ? "!" : consoleCount > 0 ? consoleCount : void 0, error: hasScriptError },
|
|
65451
|
-
{ id: "history", label: "History", badge:
|
|
65530
|
+
{ id: "history", label: "History", badge: historyBadge },
|
|
65452
65531
|
{ id: "http", label: "HTTP", badge: httpFindings.length > 0 ? httpErrors > 0 ? "!" : httpFindings.length : void 0, error: httpErrors > 0 }
|
|
65453
65532
|
];
|
|
65533
|
+
const historyContent = requestHistory.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 text-center p-8", children: "No past responses for this request yet. Each send is recorded here." }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex flex-col", children: requestHistory.map((entry) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
65534
|
+
HistoryTabRow,
|
|
65535
|
+
{
|
|
65536
|
+
entry,
|
|
65537
|
+
onLoad: () => {
|
|
65538
|
+
if (activeTabId) setTabResponse(activeTabId, entry.response, entry.scriptResult ?? null);
|
|
65539
|
+
},
|
|
65540
|
+
onResend: requestSend
|
|
65541
|
+
},
|
|
65542
|
+
entry.id
|
|
65543
|
+
)) });
|
|
65454
65544
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "h-full flex flex-col", children: [
|
|
65455
65545
|
hookResults && hookResults.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx(HookResultsPanel, { results: hookResults }),
|
|
65456
65546
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-4 px-4 py-1.5 border-b border-surface-800 flex-shrink-0 overflow-x-auto", children: [
|
|
@@ -65479,7 +65569,7 @@ function ResponseViewer() {
|
|
|
65479
65569
|
},
|
|
65480
65570
|
t2.id
|
|
65481
65571
|
)) }),
|
|
65482
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-auto flex items-center gap-1 shrink-0", children: [
|
|
65572
|
+
!response.error && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-auto flex items-center gap-1 shrink-0", children: [
|
|
65483
65573
|
assertToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-emerald-400 font-medium px-1", children: assertToast.toast.msg }),
|
|
65484
65574
|
contractToast.toast && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-blue-400 font-medium px-1", children: contractToast.toast.msg }),
|
|
65485
65575
|
tab === "body" && supportsTree && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex rounded overflow-hidden border border-surface-800 mr-1", children: [
|
|
@@ -65541,7 +65631,10 @@ function ResponseViewer() {
|
|
|
65541
65631
|
] })
|
|
65542
65632
|
] }),
|
|
65543
65633
|
showMockModal && /* @__PURE__ */ jsxRuntimeExports.jsx(SaveAsMockModal, { onClose: () => setShowMockModal(false) }),
|
|
65544
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-y-auto", children:
|
|
65634
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 flex flex-col overflow-y-auto", children: response.error ? tab === "request" ? /* @__PURE__ */ jsxRuntimeExports.jsx(RequestPanel, { sentRequest }) : tab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: historyContent }) : /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col p-4 gap-2", children: [
|
|
65635
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-red-400 text-sm font-medium", children: "Request failed" }),
|
|
65636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-xs text-red-300 whitespace-pre-wrap", children: response.error })
|
|
65637
|
+
] }) : diffMode && pinnedResponse ? /* @__PURE__ */ jsxRuntimeExports.jsx(DiffView, { pinned: pinnedResponse, current: response }) : tab === "body" && supportsTree && bodyView === "tree" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
65545
65638
|
InteractiveBody,
|
|
65546
65639
|
{
|
|
65547
65640
|
body: response.body,
|
|
@@ -65587,16 +65680,7 @@ function ResponseViewer() {
|
|
|
65587
65680
|
] }),
|
|
65588
65681
|
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-200 mt-1", children: find2.message })
|
|
65589
65682
|
] }, i);
|
|
65590
|
-
}) }) }) : tab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children:
|
|
65591
|
-
HistoryTabRow,
|
|
65592
|
-
{
|
|
65593
|
-
entry,
|
|
65594
|
-
onLoad: () => {
|
|
65595
|
-
if (activeTabId) setTabResponse(activeTabId, entry.response, entry.scriptResult ?? null);
|
|
65596
|
-
}
|
|
65597
|
-
},
|
|
65598
|
-
entry.id
|
|
65599
|
-
)) }) }) : null }),
|
|
65683
|
+
}) }) }) : tab === "history" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0 overflow-y-auto", children: historyContent }) : null }),
|
|
65600
65684
|
headerMenu && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
65601
65685
|
ContextMenu,
|
|
65602
65686
|
{
|
|
@@ -65681,7 +65765,8 @@ const TARGETS = [
|
|
|
65681
65765
|
{ id: "supertest_js", label: "Supertest JS", description: "Jest + Supertest JavaScript tests" },
|
|
65682
65766
|
{ id: "rest_assured", label: "REST Assured", description: "Java + JUnit 5 + Maven pom.xml" },
|
|
65683
65767
|
{ id: "karate", label: "Karate", description: "Karate feature files + JUnit 5 runner + Maven" },
|
|
65684
|
-
{ id: "http_file", label: "HTTP file", description: ".http / .rest file (VSCode REST Client / IntelliJ)" }
|
|
65768
|
+
{ id: "http_file", label: "HTTP file", description: ".http / .rest file (VSCode REST Client / IntelliJ)" },
|
|
65769
|
+
{ id: "curl", label: "cURL", description: "Runnable shell script, one curl command per request" }
|
|
65685
65770
|
];
|
|
65686
65771
|
function GeneratorPanel() {
|
|
65687
65772
|
const setShowGeneratorPanel = useStore((s) => s.setShowGeneratorPanel);
|
|
@@ -65937,6 +66022,7 @@ function HistoryPanel() {
|
|
|
65937
66022
|
const activeTabId = useStore((s) => s.activeTabId);
|
|
65938
66023
|
const setTabResponse = useStore((s) => s.setTabResponse);
|
|
65939
66024
|
const setActiveRequest = useStore((s) => s.setActiveRequest);
|
|
66025
|
+
const requestSend = useStore((s) => s.requestSend);
|
|
65940
66026
|
const collections = useStore((s) => s.collections);
|
|
65941
66027
|
const [selected, setSelected] = reactExports.useState(null);
|
|
65942
66028
|
const [search, setSearch] = reactExports.useState("");
|
|
@@ -65959,8 +66045,8 @@ function HistoryPanel() {
|
|
|
65959
66045
|
}
|
|
65960
66046
|
function open(entry) {
|
|
65961
66047
|
setSelected(entry);
|
|
65962
|
-
const
|
|
65963
|
-
if (
|
|
66048
|
+
const stillExists2 = Object.values(collections).some((c) => entry.request.id in c.data.requests);
|
|
66049
|
+
if (stillExists2) {
|
|
65964
66050
|
setActiveRequest(entry.request.id);
|
|
65965
66051
|
const tabId = useStore.getState().activeTabId;
|
|
65966
66052
|
if (tabId) setTabResponse(tabId, entry.response, entry.scriptResult ?? null);
|
|
@@ -65968,6 +66054,14 @@ function HistoryPanel() {
|
|
|
65968
66054
|
setTabResponse(activeTabId, entry.response, entry.scriptResult ?? null);
|
|
65969
66055
|
}
|
|
65970
66056
|
}
|
|
66057
|
+
function replay(entry) {
|
|
66058
|
+
setSelected(entry);
|
|
66059
|
+
setActiveRequest(entry.request.id);
|
|
66060
|
+
requestSend();
|
|
66061
|
+
}
|
|
66062
|
+
function stillExists(entry) {
|
|
66063
|
+
return Object.values(collections).some((c) => entry.request.id in c.data.requests);
|
|
66064
|
+
}
|
|
65971
66065
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
65972
66066
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-2 py-2 border-b border-surface-800 flex gap-1.5 flex-shrink-0", children: [
|
|
65973
66067
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -66012,7 +66106,8 @@ function HistoryPanel() {
|
|
|
66012
66106
|
{
|
|
66013
66107
|
entry,
|
|
66014
66108
|
isSelected: selected?.id === entry.id,
|
|
66015
|
-
onSelect: () => open(entry)
|
|
66109
|
+
onSelect: () => open(entry),
|
|
66110
|
+
onResend: stillExists(entry) ? () => replay(entry) : void 0
|
|
66016
66111
|
},
|
|
66017
66112
|
entry.id
|
|
66018
66113
|
))
|
|
@@ -66023,19 +66118,40 @@ function HistoryPanel() {
|
|
|
66023
66118
|
function HistoryRow({
|
|
66024
66119
|
entry,
|
|
66025
66120
|
isSelected,
|
|
66026
|
-
onSelect
|
|
66121
|
+
onSelect,
|
|
66122
|
+
onResend
|
|
66027
66123
|
}) {
|
|
66028
66124
|
const status = entry.response.status;
|
|
66029
66125
|
const hasError = !!entry.response.error;
|
|
66030
66126
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
66031
|
-
"
|
|
66127
|
+
"div",
|
|
66032
66128
|
{
|
|
66129
|
+
role: "button",
|
|
66130
|
+
tabIndex: 0,
|
|
66033
66131
|
onClick: onSelect,
|
|
66034
|
-
|
|
66132
|
+
onKeyDown: (e) => {
|
|
66133
|
+
if (e.key === "Enter" || e.key === " ") {
|
|
66134
|
+
e.preventDefault();
|
|
66135
|
+
onSelect();
|
|
66136
|
+
}
|
|
66137
|
+
},
|
|
66138
|
+
className: `group w-full text-left px-3 py-2 border-b border-surface-800/50 transition-colors cursor-pointer ${isSelected ? "bg-surface-800" : "hover:bg-surface-800/50"}`,
|
|
66035
66139
|
children: [
|
|
66036
66140
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
66037
66141
|
/* @__PURE__ */ jsxRuntimeExports.jsx(MethodBadge, { method: entry.request.method, size: "xs" }),
|
|
66038
66142
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-xs truncate text-white", children: entry.request.name }),
|
|
66143
|
+
onResend && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
66144
|
+
"button",
|
|
66145
|
+
{
|
|
66146
|
+
onClick: (e) => {
|
|
66147
|
+
e.stopPropagation();
|
|
66148
|
+
onResend();
|
|
66149
|
+
},
|
|
66150
|
+
title: "Send this request again",
|
|
66151
|
+
className: "text-[10px] text-emerald-400 hover:text-emerald-300 shrink-0 opacity-0 group-hover:opacity-100 transition-opacity",
|
|
66152
|
+
children: "resend"
|
|
66153
|
+
}
|
|
66154
|
+
),
|
|
66039
66155
|
hasError ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-red-400 text-[10px] font-medium shrink-0", children: "ERR" }) : /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `text-[10px] font-bold shrink-0 ${statusColor$2(status)}`, children: status })
|
|
66040
66156
|
] }),
|
|
66041
66157
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-0.5 min-w-0", children: [
|
|
@@ -66059,6 +66175,15 @@ function HistoryRow({
|
|
|
66059
66175
|
const { electron: electron$f } = window;
|
|
66060
66176
|
function WelcomeScreen() {
|
|
66061
66177
|
const { applyWorkspace } = useWorkspaceLoader();
|
|
66178
|
+
const [recents, setRecents] = reactExports.useState([]);
|
|
66179
|
+
const [update, setUpdate] = reactExports.useState(null);
|
|
66180
|
+
reactExports.useEffect(() => {
|
|
66181
|
+
electron$f.getRecentWorkspaces().then(setRecents).catch(() => setRecents([]));
|
|
66182
|
+
electron$f.checkForUpdate().then((info) => {
|
|
66183
|
+
if (info?.updateAvailable) setUpdate(info);
|
|
66184
|
+
}).catch(() => {
|
|
66185
|
+
});
|
|
66186
|
+
}, []);
|
|
66062
66187
|
async function openWorkspace() {
|
|
66063
66188
|
const result = await electron$f.openWorkspace();
|
|
66064
66189
|
if (!result) return;
|
|
@@ -66069,7 +66194,25 @@ function WelcomeScreen() {
|
|
|
66069
66194
|
if (!result) return;
|
|
66070
66195
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
66071
66196
|
}
|
|
66197
|
+
async function openRecent(path) {
|
|
66198
|
+
const result = await electron$f.openWorkspacePath(path);
|
|
66199
|
+
if (!result) {
|
|
66200
|
+
setRecents((prev) => prev.filter((r) => r.path !== path));
|
|
66201
|
+
return;
|
|
66202
|
+
}
|
|
66203
|
+
await applyWorkspace(result.workspace, result.workspacePath);
|
|
66204
|
+
}
|
|
66072
66205
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex flex-col items-center justify-center gap-6 text-center p-8", children: [
|
|
66206
|
+
update && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center gap-1 px-4 py-2 rounded-lg border border-blue-800 bg-blue-950/40 text-xs", children: [
|
|
66207
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-200", children: [
|
|
66208
|
+
"New version available (v",
|
|
66209
|
+
update.latest,
|
|
66210
|
+
", you have v",
|
|
66211
|
+
update.current,
|
|
66212
|
+
")"
|
|
66213
|
+
] }),
|
|
66214
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-[11px] text-blue-300 bg-surface-900 px-2 py-0.5 rounded select-all", children: update.command })
|
|
66215
|
+
] }),
|
|
66073
66216
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { children: [
|
|
66074
66217
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("h1", { className: "text-2xl font-semibold mb-1", children: [
|
|
66075
66218
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "var(--wordmark-muted)" }, children: "API" }),
|
|
@@ -66089,7 +66232,11 @@ function WelcomeScreen() {
|
|
|
66089
66232
|
}
|
|
66090
66233
|
)
|
|
66091
66234
|
] }),
|
|
66092
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: "Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine." })
|
|
66235
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-surface-400 text-sm max-w-sm", children: "Local-first API testing with Robot Framework & Playwright code generation. Secrets stay on your machine." }),
|
|
66236
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[11px] mt-3", style: { color: "var(--text-muted)" }, children: [
|
|
66237
|
+
"version ",
|
|
66238
|
+
"0.4.1"
|
|
66239
|
+
] })
|
|
66093
66240
|
] }),
|
|
66094
66241
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 w-64", children: [
|
|
66095
66242
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -66109,6 +66256,22 @@ function WelcomeScreen() {
|
|
|
66109
66256
|
}
|
|
66110
66257
|
)
|
|
66111
66258
|
] }),
|
|
66259
|
+
recents.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1 w-72 text-left", children: [
|
|
66260
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] uppercase tracking-wider font-semibold px-1", style: { color: "var(--text-muted)" }, children: "Recent workspaces" }),
|
|
66261
|
+
recents.map((r) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
66262
|
+
"button",
|
|
66263
|
+
{
|
|
66264
|
+
onClick: () => openRecent(r.path),
|
|
66265
|
+
title: r.path,
|
|
66266
|
+
className: "flex flex-col items-start px-2 py-1.5 rounded hover:bg-surface-800 transition-colors text-left group",
|
|
66267
|
+
children: [
|
|
66268
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-xs text-surface-200 group-hover:text-white truncate max-w-full", children: r.name }),
|
|
66269
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-surface-500 truncate max-w-full", children: r.path })
|
|
66270
|
+
]
|
|
66271
|
+
},
|
|
66272
|
+
r.path
|
|
66273
|
+
))
|
|
66274
|
+
] }),
|
|
66112
66275
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-surface-400 text-xs max-w-xs", children: [
|
|
66113
66276
|
"A workspace is a ",
|
|
66114
66277
|
/* @__PURE__ */ jsxRuntimeExports.jsx("code", { className: "text-surface-500", children: ".spector" }),
|
|
@@ -67305,6 +67468,230 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
67305
67468
|
}
|
|
67306
67469
|
);
|
|
67307
67470
|
}
|
|
67471
|
+
const SKIP_WITH_ARG = /* @__PURE__ */ new Set([
|
|
67472
|
+
"--connect-timeout",
|
|
67473
|
+
"--max-time",
|
|
67474
|
+
"-m",
|
|
67475
|
+
"--retry",
|
|
67476
|
+
"--resolve",
|
|
67477
|
+
"--cacert",
|
|
67478
|
+
"--cert",
|
|
67479
|
+
"--key",
|
|
67480
|
+
"--proxy",
|
|
67481
|
+
"-x",
|
|
67482
|
+
"--output",
|
|
67483
|
+
"-o",
|
|
67484
|
+
"--write-out",
|
|
67485
|
+
"-w"
|
|
67486
|
+
]);
|
|
67487
|
+
function tokenize(input) {
|
|
67488
|
+
const tokens = [];
|
|
67489
|
+
let cur2 = "";
|
|
67490
|
+
let inTok = false;
|
|
67491
|
+
let i = 0;
|
|
67492
|
+
const n = input.length;
|
|
67493
|
+
while (i < n) {
|
|
67494
|
+
const c = input[i];
|
|
67495
|
+
if (c === "\\" && (input[i + 1] === "\n" || input[i + 1] === "\r")) {
|
|
67496
|
+
i += input[i + 1] === "\r" && input[i + 2] === "\n" ? 3 : 2;
|
|
67497
|
+
continue;
|
|
67498
|
+
}
|
|
67499
|
+
if (c === "'") {
|
|
67500
|
+
inTok = true;
|
|
67501
|
+
i++;
|
|
67502
|
+
while (i < n && input[i] !== "'") cur2 += input[i++];
|
|
67503
|
+
i++;
|
|
67504
|
+
continue;
|
|
67505
|
+
}
|
|
67506
|
+
if (c === '"') {
|
|
67507
|
+
inTok = true;
|
|
67508
|
+
i++;
|
|
67509
|
+
while (i < n && input[i] !== '"') {
|
|
67510
|
+
if (input[i] === "\\" && i + 1 < n && `"\\$\``.includes(input[i + 1])) {
|
|
67511
|
+
cur2 += input[i + 1];
|
|
67512
|
+
i += 2;
|
|
67513
|
+
} else cur2 += input[i++];
|
|
67514
|
+
}
|
|
67515
|
+
i++;
|
|
67516
|
+
continue;
|
|
67517
|
+
}
|
|
67518
|
+
if (/\s/.test(c)) {
|
|
67519
|
+
if (inTok) {
|
|
67520
|
+
tokens.push(cur2);
|
|
67521
|
+
cur2 = "";
|
|
67522
|
+
inTok = false;
|
|
67523
|
+
}
|
|
67524
|
+
i++;
|
|
67525
|
+
continue;
|
|
67526
|
+
}
|
|
67527
|
+
if (c === "\\" && i + 1 < n) {
|
|
67528
|
+
cur2 += input[i + 1];
|
|
67529
|
+
i += 2;
|
|
67530
|
+
inTok = true;
|
|
67531
|
+
continue;
|
|
67532
|
+
}
|
|
67533
|
+
cur2 += c;
|
|
67534
|
+
inTok = true;
|
|
67535
|
+
i++;
|
|
67536
|
+
}
|
|
67537
|
+
if (inTok) tokens.push(cur2);
|
|
67538
|
+
return tokens;
|
|
67539
|
+
}
|
|
67540
|
+
function looksJson(s) {
|
|
67541
|
+
const t2 = s.trim();
|
|
67542
|
+
if (!(t2.startsWith("{") || t2.startsWith("["))) return false;
|
|
67543
|
+
try {
|
|
67544
|
+
JSON.parse(t2);
|
|
67545
|
+
return true;
|
|
67546
|
+
} catch {
|
|
67547
|
+
return false;
|
|
67548
|
+
}
|
|
67549
|
+
}
|
|
67550
|
+
function decodeBasic(b642) {
|
|
67551
|
+
try {
|
|
67552
|
+
const decoded = typeof atob === "function" ? atob(b642) : Buffer.from(b642, "base64").toString("utf8");
|
|
67553
|
+
const idx = decoded.indexOf(":");
|
|
67554
|
+
if (idx === -1) return null;
|
|
67555
|
+
return { username: decoded.slice(0, idx), password: decoded.slice(idx + 1) };
|
|
67556
|
+
} catch {
|
|
67557
|
+
return null;
|
|
67558
|
+
}
|
|
67559
|
+
}
|
|
67560
|
+
function parseCurl(command2) {
|
|
67561
|
+
const tokens = tokenize(command2.trim());
|
|
67562
|
+
if (tokens[0] === "curl") tokens.shift();
|
|
67563
|
+
let method = null;
|
|
67564
|
+
let url = "";
|
|
67565
|
+
let user = null;
|
|
67566
|
+
let forceGet = false;
|
|
67567
|
+
const headers = [];
|
|
67568
|
+
const dataParts = [];
|
|
67569
|
+
const formParts = [];
|
|
67570
|
+
const next = (i) => tokens[i + 1] ?? "";
|
|
67571
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
67572
|
+
const t2 = tokens[i];
|
|
67573
|
+
switch (t2) {
|
|
67574
|
+
case "-X":
|
|
67575
|
+
case "--request":
|
|
67576
|
+
method = next(i);
|
|
67577
|
+
i++;
|
|
67578
|
+
break;
|
|
67579
|
+
case "-H":
|
|
67580
|
+
case "--header": {
|
|
67581
|
+
const raw = next(i);
|
|
67582
|
+
i++;
|
|
67583
|
+
const idx = raw.indexOf(":");
|
|
67584
|
+
if (idx > 0) headers.push({ key: raw.slice(0, idx).trim(), value: raw.slice(idx + 1).trim(), enabled: true });
|
|
67585
|
+
break;
|
|
67586
|
+
}
|
|
67587
|
+
case "-u":
|
|
67588
|
+
case "--user":
|
|
67589
|
+
user = next(i);
|
|
67590
|
+
i++;
|
|
67591
|
+
break;
|
|
67592
|
+
case "-d":
|
|
67593
|
+
case "--data":
|
|
67594
|
+
case "--data-raw":
|
|
67595
|
+
case "--data-ascii":
|
|
67596
|
+
case "--data-binary":
|
|
67597
|
+
dataParts.push(next(i));
|
|
67598
|
+
i++;
|
|
67599
|
+
break;
|
|
67600
|
+
case "--data-urlencode":
|
|
67601
|
+
dataParts.push(next(i));
|
|
67602
|
+
i++;
|
|
67603
|
+
break;
|
|
67604
|
+
case "-F":
|
|
67605
|
+
case "--form":
|
|
67606
|
+
formParts.push(next(i));
|
|
67607
|
+
i++;
|
|
67608
|
+
break;
|
|
67609
|
+
case "-b":
|
|
67610
|
+
case "--cookie":
|
|
67611
|
+
headers.push({ key: "Cookie", value: next(i), enabled: true });
|
|
67612
|
+
i++;
|
|
67613
|
+
break;
|
|
67614
|
+
case "-A":
|
|
67615
|
+
case "--user-agent":
|
|
67616
|
+
headers.push({ key: "User-Agent", value: next(i), enabled: true });
|
|
67617
|
+
i++;
|
|
67618
|
+
break;
|
|
67619
|
+
case "-e":
|
|
67620
|
+
case "--referer":
|
|
67621
|
+
headers.push({ key: "Referer", value: next(i), enabled: true });
|
|
67622
|
+
i++;
|
|
67623
|
+
break;
|
|
67624
|
+
case "--url":
|
|
67625
|
+
url = next(i);
|
|
67626
|
+
i++;
|
|
67627
|
+
break;
|
|
67628
|
+
case "-G":
|
|
67629
|
+
case "--get":
|
|
67630
|
+
forceGet = true;
|
|
67631
|
+
break;
|
|
67632
|
+
case "-I":
|
|
67633
|
+
case "--head":
|
|
67634
|
+
method = method ?? "HEAD";
|
|
67635
|
+
break;
|
|
67636
|
+
default:
|
|
67637
|
+
if (SKIP_WITH_ARG.has(t2)) {
|
|
67638
|
+
i++;
|
|
67639
|
+
break;
|
|
67640
|
+
}
|
|
67641
|
+
if (t2.startsWith("-")) break;
|
|
67642
|
+
if (!url) url = t2;
|
|
67643
|
+
break;
|
|
67644
|
+
}
|
|
67645
|
+
}
|
|
67646
|
+
if (!url) throw new Error("No URL found in the curl command.");
|
|
67647
|
+
const hasData = dataParts.length > 0;
|
|
67648
|
+
const isForm = formParts.length > 0;
|
|
67649
|
+
const resolvedMethod = (forceGet ? "GET" : method ?? (hasData || isForm ? "POST" : "GET")).toUpperCase();
|
|
67650
|
+
let auth = { type: "none" };
|
|
67651
|
+
if (user) {
|
|
67652
|
+
const idx = user.indexOf(":");
|
|
67653
|
+
auth = { type: "basic", username: idx === -1 ? user : user.slice(0, idx), password: idx === -1 ? "" : user.slice(idx + 1) };
|
|
67654
|
+
} else {
|
|
67655
|
+
const authIdx = headers.findIndex((h) => h.key.toLowerCase() === "authorization");
|
|
67656
|
+
if (authIdx !== -1) {
|
|
67657
|
+
const v = headers[authIdx].value;
|
|
67658
|
+
if (/^Bearer\s+/i.test(v)) {
|
|
67659
|
+
auth = { type: "bearer", token: v.replace(/^Bearer\s+/i, "") };
|
|
67660
|
+
headers.splice(authIdx, 1);
|
|
67661
|
+
} else if (/^Basic\s+/i.test(v)) {
|
|
67662
|
+
const creds = decodeBasic(v.replace(/^Basic\s+/i, "").trim());
|
|
67663
|
+
if (creds) {
|
|
67664
|
+
auth = { type: "basic", ...creds };
|
|
67665
|
+
headers.splice(authIdx, 1);
|
|
67666
|
+
}
|
|
67667
|
+
}
|
|
67668
|
+
}
|
|
67669
|
+
}
|
|
67670
|
+
let body = { mode: "none" };
|
|
67671
|
+
if (isForm) {
|
|
67672
|
+
body = {
|
|
67673
|
+
mode: "form",
|
|
67674
|
+
form: formParts.map((kv) => {
|
|
67675
|
+
const idx = kv.indexOf("=");
|
|
67676
|
+
return { key: idx === -1 ? kv : kv.slice(0, idx), value: idx === -1 ? "" : kv.slice(idx + 1), enabled: true };
|
|
67677
|
+
})
|
|
67678
|
+
};
|
|
67679
|
+
} else if (hasData) {
|
|
67680
|
+
const data = dataParts.join("&");
|
|
67681
|
+
const ct = headers.find((h) => h.key.toLowerCase() === "content-type")?.value;
|
|
67682
|
+
if (ct && ct.includes("json") || looksJson(data)) body = { mode: "json", json: data };
|
|
67683
|
+
else body = { mode: "raw", raw: data, rawContentType: ct ?? "application/x-www-form-urlencoded" };
|
|
67684
|
+
}
|
|
67685
|
+
let name2;
|
|
67686
|
+
try {
|
|
67687
|
+
const u = new URL(url.replace(/\{\{[^}]+\}\}/g, "x"));
|
|
67688
|
+
name2 = `${resolvedMethod} ${u.pathname === "/" ? u.hostname : u.pathname}`;
|
|
67689
|
+
} catch {
|
|
67690
|
+
const cleaned = url.replace(/^[a-z]+:\/\//i, "").replace(/\?.*$/, "");
|
|
67691
|
+
name2 = `${resolvedMethod} ${cleaned}`.trim();
|
|
67692
|
+
}
|
|
67693
|
+
return { name: name2, method: resolvedMethod, url, headers, params: [], auth, body };
|
|
67694
|
+
}
|
|
67308
67695
|
const { electron: electron$9 } = window;
|
|
67309
67696
|
const OPTIONS = [
|
|
67310
67697
|
{ id: "postman", label: "Postman", description: "Collection v2.1 JSON" },
|
|
@@ -67312,7 +67699,8 @@ const OPTIONS = [
|
|
|
67312
67699
|
{ id: "insomnia", label: "Insomnia", description: "Export v4 JSON" },
|
|
67313
67700
|
{ id: "bruno", label: "Bruno", description: "bruno.json collection file" },
|
|
67314
67701
|
{ id: "http", label: "HTTP file", description: ".http / .rest (REST Client)" },
|
|
67315
|
-
{ id: "spector", label: "API Spector", description: "An existing .spector / .json collection" }
|
|
67702
|
+
{ id: "spector", label: "API Spector", description: "An existing .spector / .json collection" },
|
|
67703
|
+
{ id: "curl", label: "cURL", description: "Paste a curl command" }
|
|
67316
67704
|
];
|
|
67317
67705
|
function listEndpoints(col) {
|
|
67318
67706
|
const result = [];
|
|
@@ -67336,6 +67724,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
67336
67724
|
const markCollectionClean = useStore((s) => s.markCollectionClean);
|
|
67337
67725
|
const [selected, setSelected] = reactExports.useState(null);
|
|
67338
67726
|
const [url, setUrl] = reactExports.useState("");
|
|
67727
|
+
const [curlText, setCurlText] = reactExports.useState("");
|
|
67339
67728
|
const [loading, setLoading] = reactExports.useState(false);
|
|
67340
67729
|
const [error2, setError] = reactExports.useState(null);
|
|
67341
67730
|
const urlInputRef = reactExports.useRef(null);
|
|
@@ -67414,6 +67803,37 @@ function ImportModal({ onImport, onClose }) {
|
|
|
67414
67803
|
setLoading(false);
|
|
67415
67804
|
}
|
|
67416
67805
|
}
|
|
67806
|
+
function importCurl() {
|
|
67807
|
+
const text = curlText.trim();
|
|
67808
|
+
if (!text) return;
|
|
67809
|
+
setError(null);
|
|
67810
|
+
try {
|
|
67811
|
+
const parsed = parseCurl(text);
|
|
67812
|
+
const reqId = v4();
|
|
67813
|
+
const col = {
|
|
67814
|
+
version: "1.0",
|
|
67815
|
+
id: v4(),
|
|
67816
|
+
name: parsed.name || "Imported request",
|
|
67817
|
+
description: "",
|
|
67818
|
+
rootFolder: { id: v4(), name: "root", description: "", folders: [], requestIds: [reqId] },
|
|
67819
|
+
requests: {
|
|
67820
|
+
[reqId]: {
|
|
67821
|
+
id: reqId,
|
|
67822
|
+
name: parsed.name,
|
|
67823
|
+
method: parsed.method,
|
|
67824
|
+
url: parsed.url,
|
|
67825
|
+
headers: parsed.headers,
|
|
67826
|
+
params: parsed.params,
|
|
67827
|
+
auth: parsed.auth,
|
|
67828
|
+
body: parsed.body
|
|
67829
|
+
}
|
|
67830
|
+
}
|
|
67831
|
+
};
|
|
67832
|
+
enterPreview(col);
|
|
67833
|
+
} catch (err) {
|
|
67834
|
+
setError(err instanceof Error ? err.message : String(err));
|
|
67835
|
+
}
|
|
67836
|
+
}
|
|
67417
67837
|
function toggleId(id2) {
|
|
67418
67838
|
setChosenIds((prev) => {
|
|
67419
67839
|
const next = new Set(prev);
|
|
@@ -67548,7 +67968,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
67548
67968
|
children: [
|
|
67549
67969
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between", children: [
|
|
67550
67970
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("h2", { className: "text-sm font-semibold text-surface-100", children: [
|
|
67551
|
-
"Import
|
|
67971
|
+
"Import - ",
|
|
67552
67972
|
previewCol.name
|
|
67553
67973
|
] }),
|
|
67554
67974
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -67800,6 +68220,24 @@ function ImportModal({ onImport, onClose }) {
|
|
|
67800
68220
|
)
|
|
67801
68221
|
] })
|
|
67802
68222
|
] }),
|
|
68223
|
+
selected === "curl" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
68224
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-surface-500 uppercase tracking-wider font-medium", children: "Paste a curl command" }),
|
|
68225
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
68226
|
+
"textarea",
|
|
68227
|
+
{
|
|
68228
|
+
value: curlText,
|
|
68229
|
+
onChange: (e) => {
|
|
68230
|
+
setCurlText(e.target.value);
|
|
68231
|
+
setError(null);
|
|
68232
|
+
},
|
|
68233
|
+
placeholder: `curl -X POST https://api.example.com/users \\
|
|
68234
|
+
-H 'Content-Type: application/json' \\
|
|
68235
|
+
-d '{"name":"Ada"}'`,
|
|
68236
|
+
rows: 6,
|
|
68237
|
+
className: "w-full text-xs bg-surface-800 border border-surface-700 rounded px-2.5 py-1.5 focus:outline-none focus:border-blue-500 placeholder-surface-600 font-mono resize-y"
|
|
68238
|
+
}
|
|
68239
|
+
)
|
|
68240
|
+
] }),
|
|
67803
68241
|
error2 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[11px] text-red-400", children: error2 }),
|
|
67804
68242
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex justify-end gap-2 pt-1", children: [
|
|
67805
68243
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -67810,7 +68248,15 @@ function ImportModal({ onImport, onClose }) {
|
|
|
67810
68248
|
children: "Cancel"
|
|
67811
68249
|
}
|
|
67812
68250
|
),
|
|
67813
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
68251
|
+
selected === "curl" ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
68252
|
+
"button",
|
|
68253
|
+
{
|
|
68254
|
+
disabled: !curlText.trim() || loading,
|
|
68255
|
+
onClick: importCurl,
|
|
68256
|
+
className: "px-3 py-1.5 text-xs bg-blue-700 hover:bg-blue-600 disabled:bg-surface-800 disabled:text-surface-600 rounded transition-colors",
|
|
68257
|
+
children: "Parse"
|
|
68258
|
+
}
|
|
68259
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
67814
68260
|
"button",
|
|
67815
68261
|
{
|
|
67816
68262
|
disabled: !selected || loading,
|
|
@@ -72134,7 +72580,7 @@ function App() {
|
|
|
72134
72580
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
|
|
72135
72581
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
|
|
72136
72582
|
"v",
|
|
72137
|
-
"0.4.
|
|
72583
|
+
"0.4.1"
|
|
72138
72584
|
] }),
|
|
72139
72585
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "mx-2 opacity-30", children: "·" }),
|
|
72140
72586
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|