@testsmith/api-spector 0.1.2 → 0.1.3
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/bin/cli.js +13 -4
- package/out/main/chunks/recorder-DFxJgn9c.js +241 -0
- package/out/main/index.js +34 -0
- package/out/main/record.js +109 -0
- package/out/preload/index.js +15 -0
- package/out/renderer/assets/index-B46MEuwy.css +2 -0
- package/out/renderer/assets/{index-BXpiAoKF.js → index-BEMJvOJV.js} +548 -93
- package/out/renderer/index.html +2 -2
- package/package.json +3 -2
- package/out/renderer/assets/index-QI8AWMd3.css +0 -2
|
@@ -13423,6 +13423,11 @@ const useStore = create()(
|
|
|
13423
13423
|
mocks: {},
|
|
13424
13424
|
activeMockId: null,
|
|
13425
13425
|
mockLogs: {},
|
|
13426
|
+
recorderOpen: false,
|
|
13427
|
+
recorderRunning: false,
|
|
13428
|
+
recorderUpstream: "",
|
|
13429
|
+
recorderPort: 4001,
|
|
13430
|
+
recorderTargetMockId: "",
|
|
13426
13431
|
runnerModal: { open: false, collectionId: null, folderId: null, filterTags: [] },
|
|
13427
13432
|
runnerResults: [],
|
|
13428
13433
|
runnerRunning: false,
|
|
@@ -13960,6 +13965,22 @@ const useStore = create()(
|
|
|
13960
13965
|
clearMockLogs: (serverId) => set2((s) => {
|
|
13961
13966
|
s.mockLogs[serverId] = [];
|
|
13962
13967
|
}),
|
|
13968
|
+
// ── Recorder ──────────────────────────────────────────────────────────────
|
|
13969
|
+
setRecorderOpen: (open) => set2((s) => {
|
|
13970
|
+
s.recorderOpen = open;
|
|
13971
|
+
}),
|
|
13972
|
+
setRecorderRunning: (running) => set2((s) => {
|
|
13973
|
+
s.recorderRunning = running;
|
|
13974
|
+
}),
|
|
13975
|
+
setRecorderUpstream: (url) => set2((s) => {
|
|
13976
|
+
s.recorderUpstream = url;
|
|
13977
|
+
}),
|
|
13978
|
+
setRecorderPort: (port) => set2((s) => {
|
|
13979
|
+
s.recorderPort = port;
|
|
13980
|
+
}),
|
|
13981
|
+
setRecorderTargetMockId: (id2) => set2((s) => {
|
|
13982
|
+
s.recorderTargetMockId = id2;
|
|
13983
|
+
}),
|
|
13963
13984
|
// ── WebSocket ─────────────────────────────────────────────────────────────
|
|
13964
13985
|
setWsStatus: (requestId, status, error2) => set2((s) => {
|
|
13965
13986
|
if (!s.wsConnections[requestId]) {
|
|
@@ -13983,7 +14004,7 @@ const useStore = create()(
|
|
|
13983
14004
|
})
|
|
13984
14005
|
}))
|
|
13985
14006
|
);
|
|
13986
|
-
const { electron: electron$
|
|
14007
|
+
const { electron: electron$n } = window;
|
|
13987
14008
|
function useAutoSave() {
|
|
13988
14009
|
const collections = useStore((s) => s.collections);
|
|
13989
14010
|
useStore((s) => s.environments);
|
|
@@ -13999,7 +14020,7 @@ function useAutoSave() {
|
|
|
13999
14020
|
for (const { relPath, data, dirty } of dirtyCollections) {
|
|
14000
14021
|
if (!dirty) continue;
|
|
14001
14022
|
try {
|
|
14002
|
-
await electron$
|
|
14023
|
+
await electron$n.saveCollection(relPath, data);
|
|
14003
14024
|
markCollectionClean(data.id);
|
|
14004
14025
|
} catch (e) {
|
|
14005
14026
|
console.error("Auto-save failed for", relPath, e);
|
|
@@ -14015,7 +14036,7 @@ function useAutoSave() {
|
|
|
14015
14036
|
if (wsTimerRef.current) clearTimeout(wsTimerRef.current);
|
|
14016
14037
|
wsTimerRef.current = setTimeout(async () => {
|
|
14017
14038
|
try {
|
|
14018
|
-
await electron$
|
|
14039
|
+
await electron$n.saveWorkspace(workspace);
|
|
14019
14040
|
} catch {
|
|
14020
14041
|
}
|
|
14021
14042
|
}, 300);
|
|
@@ -14024,7 +14045,7 @@ function useAutoSave() {
|
|
|
14024
14045
|
};
|
|
14025
14046
|
}, [workspace]);
|
|
14026
14047
|
}
|
|
14027
|
-
const { electron: electron$
|
|
14048
|
+
const { electron: electron$m } = window;
|
|
14028
14049
|
function useWorkspaceLoader() {
|
|
14029
14050
|
const loadCollection = useStore((s) => s.loadCollection);
|
|
14030
14051
|
const loadEnvironment = useStore((s) => s.loadEnvironment);
|
|
@@ -14043,28 +14064,28 @@ function useWorkspaceLoader() {
|
|
|
14043
14064
|
});
|
|
14044
14065
|
for (const colPath of ws2.collections) {
|
|
14045
14066
|
try {
|
|
14046
|
-
const col = await electron$
|
|
14067
|
+
const col = await electron$m.loadCollection(colPath);
|
|
14047
14068
|
loadCollection(colPath, col);
|
|
14048
14069
|
} catch {
|
|
14049
14070
|
}
|
|
14050
14071
|
}
|
|
14051
14072
|
for (const envPath of ws2.environments) {
|
|
14052
14073
|
try {
|
|
14053
|
-
const env = await electron$
|
|
14074
|
+
const env = await electron$m.loadEnvironment(envPath);
|
|
14054
14075
|
loadEnvironment(envPath, env);
|
|
14055
14076
|
} catch {
|
|
14056
14077
|
}
|
|
14057
14078
|
}
|
|
14058
14079
|
for (const relPath of ws2.mocks ?? []) {
|
|
14059
14080
|
try {
|
|
14060
|
-
const mockData = await electron$
|
|
14081
|
+
const mockData = await electron$m.loadMock(relPath);
|
|
14061
14082
|
loadMock(relPath, mockData);
|
|
14062
14083
|
} catch {
|
|
14063
14084
|
}
|
|
14064
14085
|
}
|
|
14065
14086
|
if (ws2.collections.length > 0) {
|
|
14066
14087
|
try {
|
|
14067
|
-
const firstCol = await electron$
|
|
14088
|
+
const firstCol = await electron$m.loadCollection(ws2.collections[0]);
|
|
14068
14089
|
setActiveCollection(firstCol.id);
|
|
14069
14090
|
} catch {
|
|
14070
14091
|
}
|
|
@@ -42246,7 +42267,7 @@ const autoCloseTags = /* @__PURE__ */ EditorView.inputHandler.of((view, from, to
|
|
|
42246
42267
|
]);
|
|
42247
42268
|
return true;
|
|
42248
42269
|
});
|
|
42249
|
-
const { electron: electron$
|
|
42270
|
+
const { electron: electron$l } = window;
|
|
42250
42271
|
function SoapEditor({ request, onChange }) {
|
|
42251
42272
|
const soap = request.body.soap ?? {
|
|
42252
42273
|
wsdlUrl: "",
|
|
@@ -42263,7 +42284,7 @@ function SoapEditor({ request, onChange }) {
|
|
|
42263
42284
|
setFetching(true);
|
|
42264
42285
|
setFetchError(null);
|
|
42265
42286
|
try {
|
|
42266
|
-
const result = await electron$
|
|
42287
|
+
const result = await electron$l.wsdlFetch(soap.wsdlUrl.trim());
|
|
42267
42288
|
setOperations(result.operations);
|
|
42268
42289
|
if (result.operations.length > 0) {
|
|
42269
42290
|
const first = result.operations[0];
|
|
@@ -42423,7 +42444,7 @@ function BodyTab({ request, onChange }) {
|
|
|
42423
42444
|
mode === "soap" && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(SoapEditor, { request, onChange }) })
|
|
42424
42445
|
] });
|
|
42425
42446
|
}
|
|
42426
|
-
const { electron: electron$
|
|
42447
|
+
const { electron: electron$k } = window;
|
|
42427
42448
|
const AUTH_TYPES = ["none", "bearer", "basic", "digest", "ntlm", "apikey", "oauth2"];
|
|
42428
42449
|
function AuthTab({ request, onChange }) {
|
|
42429
42450
|
const auth = request.auth;
|
|
@@ -42437,7 +42458,7 @@ function AuthTab({ request, onChange }) {
|
|
|
42437
42458
|
}
|
|
42438
42459
|
async function saveSecret(ref2) {
|
|
42439
42460
|
if (!secretValue || !ref2) return;
|
|
42440
|
-
await electron$
|
|
42461
|
+
await electron$k.setSecret(ref2, secretValue);
|
|
42441
42462
|
setSaved(true);
|
|
42442
42463
|
setSecretValue("");
|
|
42443
42464
|
setTimeout(() => setSaved(false), 2e3);
|
|
@@ -42448,14 +42469,14 @@ function AuthTab({ request, onChange }) {
|
|
|
42448
42469
|
try {
|
|
42449
42470
|
const vars = {};
|
|
42450
42471
|
if (auth.oauth2Flow === "authorization_code") {
|
|
42451
|
-
const result = await electron$
|
|
42472
|
+
const result = await electron$k.oauth2StartFlow(auth, vars);
|
|
42452
42473
|
setAuth({
|
|
42453
42474
|
oauth2CachedToken: result.accessToken,
|
|
42454
42475
|
oauth2TokenExpiry: result.expiresAt
|
|
42455
42476
|
});
|
|
42456
42477
|
if (result.refreshToken) setOauth2RT(result.refreshToken);
|
|
42457
42478
|
} else {
|
|
42458
|
-
const result = await electron$
|
|
42479
|
+
const result = await electron$k.oauth2StartFlow(auth, vars);
|
|
42459
42480
|
setAuth({
|
|
42460
42481
|
oauth2CachedToken: result.accessToken,
|
|
42461
42482
|
oauth2TokenExpiry: result.expiresAt
|
|
@@ -42473,7 +42494,7 @@ function AuthTab({ request, onChange }) {
|
|
|
42473
42494
|
setOauth2Status("fetching");
|
|
42474
42495
|
setOauth2Error("");
|
|
42475
42496
|
try {
|
|
42476
|
-
const result = await electron$
|
|
42497
|
+
const result = await electron$k.oauth2RefreshToken(auth, {}, oauth2RefreshToken);
|
|
42477
42498
|
setAuth({
|
|
42478
42499
|
oauth2CachedToken: result.accessToken,
|
|
42479
42500
|
oauth2TokenExpiry: result.expiresAt
|
|
@@ -49470,7 +49491,7 @@ function SchemaTab({ request, onChange }) {
|
|
|
49470
49491
|
] }) })
|
|
49471
49492
|
] });
|
|
49472
49493
|
}
|
|
49473
|
-
const { electron: electron$
|
|
49494
|
+
const { electron: electron$j } = window;
|
|
49474
49495
|
const EMPTY = { statusCode: 200, headers: [], bodySchema: "" };
|
|
49475
49496
|
function ContractTab({ request, onChange }) {
|
|
49476
49497
|
const activeTab = useStore((s) => s.tabs.find((t2) => t2.id === s.activeTabId));
|
|
@@ -49484,7 +49505,7 @@ function ContractTab({ request, onChange }) {
|
|
|
49484
49505
|
if (!lastResponse?.body) return;
|
|
49485
49506
|
setInferring(true);
|
|
49486
49507
|
try {
|
|
49487
|
-
const schema = await electron$
|
|
49508
|
+
const schema = await electron$j.inferContractSchema(lastResponse.body);
|
|
49488
49509
|
if (schema) update({ bodySchema: schema });
|
|
49489
49510
|
} finally {
|
|
49490
49511
|
setInferring(false);
|
|
@@ -49592,7 +49613,7 @@ function ContractTab({ request, onChange }) {
|
|
|
49592
49613
|
] })
|
|
49593
49614
|
] });
|
|
49594
49615
|
}
|
|
49595
|
-
const { electron: electron$
|
|
49616
|
+
const { electron: electron$i } = window;
|
|
49596
49617
|
function formatTime$1(ts) {
|
|
49597
49618
|
const d = new Date(ts);
|
|
49598
49619
|
const hh = String(d.getHours()).padStart(2, "0");
|
|
@@ -49612,14 +49633,14 @@ function WebSocketPanel({ request }) {
|
|
|
49612
49633
|
const [sendText, setSendText] = reactExports.useState("");
|
|
49613
49634
|
const logEndRef = reactExports.useRef(null);
|
|
49614
49635
|
reactExports.useEffect(() => {
|
|
49615
|
-
electron$
|
|
49636
|
+
electron$i.onWsMessage(({ requestId, message }) => {
|
|
49616
49637
|
addWsMessage(requestId, message);
|
|
49617
49638
|
});
|
|
49618
|
-
electron$
|
|
49639
|
+
electron$i.onWsStatus(({ requestId, status, error: error2 }) => {
|
|
49619
49640
|
setWsStatus(requestId, status, error2);
|
|
49620
49641
|
});
|
|
49621
49642
|
return () => {
|
|
49622
|
-
electron$
|
|
49643
|
+
electron$i.offWsEvents();
|
|
49623
49644
|
};
|
|
49624
49645
|
}, [addWsMessage, setWsStatus]);
|
|
49625
49646
|
reactExports.useEffect(() => {
|
|
@@ -49632,19 +49653,19 @@ function WebSocketPanel({ request }) {
|
|
|
49632
49653
|
if (h.enabled && h.key) headers[h.key] = h.value;
|
|
49633
49654
|
}
|
|
49634
49655
|
try {
|
|
49635
|
-
await electron$
|
|
49656
|
+
await electron$i.wsConnect(request.id, request.url, headers);
|
|
49636
49657
|
} catch (err) {
|
|
49637
49658
|
setWsStatus(request.id, "error", err instanceof Error ? err.message : String(err));
|
|
49638
49659
|
}
|
|
49639
49660
|
}
|
|
49640
49661
|
async function disconnect() {
|
|
49641
|
-
await electron$
|
|
49662
|
+
await electron$i.wsDisconnect(request.id);
|
|
49642
49663
|
}
|
|
49643
49664
|
async function sendMessage() {
|
|
49644
49665
|
const text = sendText.trim();
|
|
49645
49666
|
if (!text || !isConnected) return;
|
|
49646
49667
|
try {
|
|
49647
|
-
await electron$
|
|
49668
|
+
await electron$i.wsSend(request.id, text);
|
|
49648
49669
|
const msg = {
|
|
49649
49670
|
id: crypto.randomUUID(),
|
|
49650
49671
|
direction: "sent",
|
|
@@ -49747,7 +49768,7 @@ function WebSocketPanel({ request }) {
|
|
|
49747
49768
|
] })
|
|
49748
49769
|
] });
|
|
49749
49770
|
}
|
|
49750
|
-
const { electron: electron$
|
|
49771
|
+
const { electron: electron$h } = window;
|
|
49751
49772
|
const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
49752
49773
|
const METHOD_COLORS = {
|
|
49753
49774
|
GET: "text-emerald-400",
|
|
@@ -49801,7 +49822,7 @@ function RequestBuilder({ request }) {
|
|
|
49801
49822
|
auth: mergedAuth,
|
|
49802
49823
|
headers: mergedHeaders
|
|
49803
49824
|
};
|
|
49804
|
-
const result = await electron$
|
|
49825
|
+
const result = await electron$h.sendRequest({
|
|
49805
49826
|
request: mergedRequest,
|
|
49806
49827
|
environment: activeEnv,
|
|
49807
49828
|
collectionVars,
|
|
@@ -50450,7 +50471,7 @@ function InteractiveBody({ body, contentType, onAssert }) {
|
|
|
50450
50471
|
treeContent
|
|
50451
50472
|
] });
|
|
50452
50473
|
}
|
|
50453
|
-
const { electron: electron$
|
|
50474
|
+
const { electron: electron$g } = window;
|
|
50454
50475
|
function prettyJson(raw) {
|
|
50455
50476
|
try {
|
|
50456
50477
|
return JSON.stringify(JSON.parse(raw), null, 2);
|
|
@@ -50536,14 +50557,14 @@ function SaveAsMockModal({ onClose }) {
|
|
|
50536
50557
|
const entry = state.mocks[serverId];
|
|
50537
50558
|
const updated = { ...entry.data, name: newServerName, port: Number(newServerPort), routes: [route] };
|
|
50538
50559
|
updateMock(serverId, updated);
|
|
50539
|
-
await electron$
|
|
50560
|
+
await electron$g.saveMock(entry.relPath, updated);
|
|
50540
50561
|
const ws2 = useStore.getState().workspace;
|
|
50541
|
-
if (ws2) await electron$
|
|
50562
|
+
if (ws2) await electron$g.saveWorkspace(ws2);
|
|
50542
50563
|
} else {
|
|
50543
50564
|
const entry = useStore.getState().mocks[serverId];
|
|
50544
50565
|
const updated = { ...entry.data, routes: [...entry.data.routes, route] };
|
|
50545
50566
|
updateMock(serverId, updated);
|
|
50546
|
-
await electron$
|
|
50567
|
+
await electron$g.saveMock(entry.relPath, updated);
|
|
50547
50568
|
}
|
|
50548
50569
|
onClose();
|
|
50549
50570
|
} finally {
|
|
@@ -50774,7 +50795,7 @@ function ResponseViewer() {
|
|
|
50774
50795
|
const [contractToast, setContractToast] = reactExports.useState(false);
|
|
50775
50796
|
async function saveAsContract() {
|
|
50776
50797
|
if (!response || !requestId || !activeTabId) return;
|
|
50777
|
-
const schema = response.body ? await electron$
|
|
50798
|
+
const schema = response.body ? await electron$g.inferContractSchema(response.body) : null;
|
|
50778
50799
|
const contentType2 = response.headers["content-type"];
|
|
50779
50800
|
const headers = contentType2 ? [{ key: "content-type", value: contentType2, required: true }] : [];
|
|
50780
50801
|
updateRequest(requestId, {
|
|
@@ -51017,7 +51038,7 @@ function ConsolePanel({ scriptResult }) {
|
|
|
51017
51038
|
i
|
|
51018
51039
|
)) });
|
|
51019
51040
|
}
|
|
51020
|
-
const { electron: electron$
|
|
51041
|
+
const { electron: electron$f } = window;
|
|
51021
51042
|
const TARGETS = [
|
|
51022
51043
|
{ id: "robot_framework", label: "Robot Framework", description: "Python RequestsLibrary keywords + test suite" },
|
|
51023
51044
|
{ id: "playwright_ts", label: "Playwright TS", description: "TypeScript page-object API classes + spec files" },
|
|
@@ -51048,7 +51069,7 @@ function GeneratorPanel() {
|
|
|
51048
51069
|
try {
|
|
51049
51070
|
const col = collections[selectedCollectionId]?.data;
|
|
51050
51071
|
const env = activeEnvironmentId ? environments[activeEnvironmentId]?.data ?? null : null;
|
|
51051
|
-
const generated = await electron$
|
|
51072
|
+
const generated = await electron$f.generateCode({ collection: col, environment: env, target });
|
|
51052
51073
|
setFiles(generated);
|
|
51053
51074
|
setSelectedFile(generated[0]?.path ?? null);
|
|
51054
51075
|
} catch (e) {
|
|
@@ -51060,7 +51081,7 @@ function GeneratorPanel() {
|
|
|
51060
51081
|
async function saveZip() {
|
|
51061
51082
|
if (files.length === 0) return;
|
|
51062
51083
|
const col = collections[selectedCollectionId]?.data;
|
|
51063
|
-
await electron$
|
|
51084
|
+
await electron$f.saveGeneratedFilesAsZip(files, col?.name ?? "api-tests", target);
|
|
51064
51085
|
}
|
|
51065
51086
|
const selectedContent = files.find((f) => f.path === selectedFile)?.content ?? "";
|
|
51066
51087
|
const activeTarget = TARGETS.find((t2) => t2.id === target);
|
|
@@ -51165,7 +51186,7 @@ const STATUS_COLOR = {
|
|
|
51165
51186
|
"4": "text-orange-400",
|
|
51166
51187
|
"5": "text-red-400"
|
|
51167
51188
|
};
|
|
51168
|
-
function statusColor$
|
|
51189
|
+
function statusColor$2(status) {
|
|
51169
51190
|
return STATUS_COLOR[String(status)[0]] ?? "text-surface-400";
|
|
51170
51191
|
}
|
|
51171
51192
|
function formatTime(ts) {
|
|
@@ -51264,7 +51285,7 @@ function HistoryRow({
|
|
|
51264
51285
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 min-w-0", children: [
|
|
51265
51286
|
/* @__PURE__ */ jsxRuntimeExports.jsx(MethodBadge, { method: entry.request.method, size: "xs" }),
|
|
51266
51287
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 text-xs truncate text-white", children: entry.request.name }),
|
|
51267
|
-
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$
|
|
51288
|
+
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 })
|
|
51268
51289
|
] }),
|
|
51269
51290
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 mt-0.5 min-w-0", children: [
|
|
51270
51291
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-surface-400 truncate flex-1 font-mono", children: entry.resolvedUrl }),
|
|
@@ -51284,16 +51305,16 @@ function HistoryRow({
|
|
|
51284
51305
|
}
|
|
51285
51306
|
);
|
|
51286
51307
|
}
|
|
51287
|
-
const { electron: electron$
|
|
51308
|
+
const { electron: electron$e } = window;
|
|
51288
51309
|
function WelcomeScreen() {
|
|
51289
51310
|
const { applyWorkspace } = useWorkspaceLoader();
|
|
51290
51311
|
async function openWorkspace() {
|
|
51291
|
-
const result = await electron$
|
|
51312
|
+
const result = await electron$e.openWorkspace();
|
|
51292
51313
|
if (!result) return;
|
|
51293
51314
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
51294
51315
|
}
|
|
51295
51316
|
async function newWorkspace() {
|
|
51296
|
-
const result = await electron$
|
|
51317
|
+
const result = await electron$e.newWorkspace();
|
|
51297
51318
|
if (!result) return;
|
|
51298
51319
|
await applyWorkspace(result.workspace, result.workspacePath);
|
|
51299
51320
|
}
|
|
@@ -51327,7 +51348,7 @@ function WelcomeScreen() {
|
|
|
51327
51348
|
] })
|
|
51328
51349
|
] });
|
|
51329
51350
|
}
|
|
51330
|
-
const { electron: electron$
|
|
51351
|
+
const { electron: electron$d } = window;
|
|
51331
51352
|
const EXAMPLES = [
|
|
51332
51353
|
{
|
|
51333
51354
|
label: "macOS / Linux (~/.zshrc or ~/.bashrc)",
|
|
@@ -51351,7 +51372,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
51351
51372
|
setError("Password cannot be empty.");
|
|
51352
51373
|
return;
|
|
51353
51374
|
}
|
|
51354
|
-
await electron$
|
|
51375
|
+
await electron$d.setMasterKey(password);
|
|
51355
51376
|
onSuccess(password);
|
|
51356
51377
|
}
|
|
51357
51378
|
function copy(idx, text) {
|
|
@@ -51441,7 +51462,7 @@ function MasterKeyModal({ onSuccess, onCancel }) {
|
|
|
51441
51462
|
}
|
|
51442
51463
|
);
|
|
51443
51464
|
}
|
|
51444
|
-
const { electron: electron$
|
|
51465
|
+
const { electron: electron$c } = window;
|
|
51445
51466
|
async function shortHash(value) {
|
|
51446
51467
|
const buf = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
|
|
51447
51468
|
return Array.from(new Uint8Array(buf)).map((b) => b.toString(16).padStart(2, "0")).join("").slice(0, 8);
|
|
@@ -51542,7 +51563,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51542
51563
|
async function saveEncrypted(idx) {
|
|
51543
51564
|
const plaintext = secretInputs[idx] ?? "";
|
|
51544
51565
|
if (!plaintext) return;
|
|
51545
|
-
const { set: set2 } = await electron$
|
|
51566
|
+
const { set: set2 } = await electron$c.checkMasterKey();
|
|
51546
51567
|
if (!set2) {
|
|
51547
51568
|
setPendingEncryptIdx(idx);
|
|
51548
51569
|
return;
|
|
@@ -51579,9 +51600,9 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51579
51600
|
} : state.workspace
|
|
51580
51601
|
}));
|
|
51581
51602
|
const ws2 = useStore.getState().workspace;
|
|
51582
|
-
if (ws2) await electron$
|
|
51603
|
+
if (ws2) await electron$c.saveWorkspace(ws2);
|
|
51583
51604
|
}
|
|
51584
|
-
await electron$
|
|
51605
|
+
await electron$c.saveEnvironment(newRelPath, env);
|
|
51585
51606
|
}
|
|
51586
51607
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
51587
51608
|
pendingEncryptIdx !== null && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -51865,7 +51886,7 @@ function EnvironmentEditor({ onClose }) {
|
|
|
51865
51886
|
)
|
|
51866
51887
|
] });
|
|
51867
51888
|
}
|
|
51868
|
-
const { electron: electron$
|
|
51889
|
+
const { electron: electron$b } = window;
|
|
51869
51890
|
function EnvironmentBar({ inline = false }) {
|
|
51870
51891
|
const environments = useStore((s) => s.environments);
|
|
51871
51892
|
const activeEnvironmentId = useStore((s) => s.activeEnvironmentId);
|
|
@@ -51879,7 +51900,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
51879
51900
|
if (id2) {
|
|
51880
51901
|
const hasSecrets = environments[id2]?.data.variables.some((v) => v.enabled && v.secret);
|
|
51881
51902
|
if (hasSecrets) {
|
|
51882
|
-
const { set: set2 } = await electron$
|
|
51903
|
+
const { set: set2 } = await electron$b.checkMasterKey();
|
|
51883
51904
|
if (!set2) {
|
|
51884
51905
|
setPendingEnvId(id2);
|
|
51885
51906
|
return;
|
|
@@ -51933,7 +51954,7 @@ function EnvironmentBar({ inline = false }) {
|
|
|
51933
51954
|
controls
|
|
51934
51955
|
] });
|
|
51935
51956
|
}
|
|
51936
|
-
const { electron: electron$
|
|
51957
|
+
const { electron: electron$a } = window;
|
|
51937
51958
|
const DEFAULT_PII_PATTERNS = ["authorization", "password", "token", "secret", "api-key", "x-api-key"];
|
|
51938
51959
|
function WorkspaceSettingsModal({ onClose }) {
|
|
51939
51960
|
const workspace = useStore((s) => s.workspace);
|
|
@@ -51979,7 +52000,7 @@ function WorkspaceSettingsModal({ onClose }) {
|
|
|
51979
52000
|
settings.piiMaskPatterns = patterns;
|
|
51980
52001
|
updateWorkspaceSettings(settings);
|
|
51981
52002
|
const updated = useStore.getState().workspace;
|
|
51982
|
-
if (updated) await electron$
|
|
52003
|
+
if (updated) await electron$a.saveWorkspace(updated);
|
|
51983
52004
|
onClose();
|
|
51984
52005
|
}
|
|
51985
52006
|
const tabs = [
|
|
@@ -52177,7 +52198,7 @@ function WorkspaceSettingsModal({ onClose }) {
|
|
|
52177
52198
|
}
|
|
52178
52199
|
);
|
|
52179
52200
|
}
|
|
52180
|
-
const { electron: electron$
|
|
52201
|
+
const { electron: electron$9 } = window;
|
|
52181
52202
|
function DocsGeneratorModal({ onClose }) {
|
|
52182
52203
|
const collections = useStore((s) => s.collections);
|
|
52183
52204
|
const collectionList = Object.values(collections);
|
|
@@ -52206,9 +52227,9 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52206
52227
|
setGenerating(true);
|
|
52207
52228
|
setError(null);
|
|
52208
52229
|
try {
|
|
52209
|
-
const content2 = await electron$
|
|
52230
|
+
const content2 = await electron$9.generateDocs(buildPayload());
|
|
52210
52231
|
const filename = format2 === "html" ? "api-docs.html" : "api-docs.md";
|
|
52211
|
-
await electron$
|
|
52232
|
+
await electron$9.saveResults(content2, filename);
|
|
52212
52233
|
} catch (err) {
|
|
52213
52234
|
setError(err instanceof Error ? err.message : String(err));
|
|
52214
52235
|
} finally {
|
|
@@ -52219,7 +52240,7 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52219
52240
|
setGenerating(true);
|
|
52220
52241
|
setError(null);
|
|
52221
52242
|
try {
|
|
52222
|
-
const content2 = await electron$
|
|
52243
|
+
const content2 = await electron$9.generateDocs(buildPayload());
|
|
52223
52244
|
setPreview(content2);
|
|
52224
52245
|
} catch (err) {
|
|
52225
52246
|
setError(err instanceof Error ? err.message : String(err));
|
|
@@ -52335,7 +52356,7 @@ function DocsGeneratorModal({ onClose }) {
|
|
|
52335
52356
|
] })
|
|
52336
52357
|
] }) });
|
|
52337
52358
|
}
|
|
52338
|
-
const { electron: electron$
|
|
52359
|
+
const { electron: electron$8 } = window;
|
|
52339
52360
|
const OPTIONS = [
|
|
52340
52361
|
{ id: "postman", label: "Postman", description: "Collection v2.1 JSON" },
|
|
52341
52362
|
{ id: "openapi", label: "OpenAPI", description: "JSON or YAML (v3.x)", supportsUrl: true },
|
|
@@ -52353,10 +52374,10 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52353
52374
|
setError(null);
|
|
52354
52375
|
try {
|
|
52355
52376
|
let col = null;
|
|
52356
|
-
if (opt.id === "postman") col = await electron$
|
|
52357
|
-
if (opt.id === "openapi") col = await electron$
|
|
52358
|
-
if (opt.id === "insomnia") col = await electron$
|
|
52359
|
-
if (opt.id === "bruno") col = await electron$
|
|
52377
|
+
if (opt.id === "postman") col = await electron$8.importPostman();
|
|
52378
|
+
if (opt.id === "openapi") col = await electron$8.importOpenApi();
|
|
52379
|
+
if (opt.id === "insomnia") col = await electron$8.importInsomnia();
|
|
52380
|
+
if (opt.id === "bruno") col = await electron$8.importBruno();
|
|
52360
52381
|
onImport(col);
|
|
52361
52382
|
onClose();
|
|
52362
52383
|
} catch (err) {
|
|
@@ -52371,7 +52392,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52371
52392
|
setLoading(true);
|
|
52372
52393
|
setError(null);
|
|
52373
52394
|
try {
|
|
52374
|
-
const col = await electron$
|
|
52395
|
+
const col = await electron$8.importOpenApiFromUrl(trimmed);
|
|
52375
52396
|
onImport(col);
|
|
52376
52397
|
onClose();
|
|
52377
52398
|
} catch (err) {
|
|
@@ -52466,7 +52487,7 @@ function ImportModal({ onImport, onClose }) {
|
|
|
52466
52487
|
}
|
|
52467
52488
|
) });
|
|
52468
52489
|
}
|
|
52469
|
-
const { electron: electron$
|
|
52490
|
+
const { electron: electron$7 } = window;
|
|
52470
52491
|
const ZOOM_STEPS = [0.75, 0.9, 1, 1.1, 1.25, 1.5];
|
|
52471
52492
|
function PreferencesPopover() {
|
|
52472
52493
|
const theme2 = useStore((s) => s.theme);
|
|
@@ -52572,13 +52593,13 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52572
52593
|
try {
|
|
52573
52594
|
for (const { relPath, data, dirty } of Object.values(collections)) {
|
|
52574
52595
|
if (!dirty) continue;
|
|
52575
|
-
await electron$
|
|
52596
|
+
await electron$7.saveCollection(relPath, data);
|
|
52576
52597
|
markCollectionClean(data.id);
|
|
52577
52598
|
}
|
|
52578
52599
|
for (const { relPath, data } of Object.values(environments)) {
|
|
52579
|
-
await electron$
|
|
52600
|
+
await electron$7.saveEnvironment(relPath, data);
|
|
52580
52601
|
}
|
|
52581
|
-
if (workspace) await electron$
|
|
52602
|
+
if (workspace) await electron$7.saveWorkspace(workspace);
|
|
52582
52603
|
} finally {
|
|
52583
52604
|
setSaving(false);
|
|
52584
52605
|
}
|
|
@@ -52586,14 +52607,14 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52586
52607
|
async function afterImport(col) {
|
|
52587
52608
|
if (!col) return;
|
|
52588
52609
|
const relPath = colRelPath(col.name, col.id);
|
|
52589
|
-
await electron$
|
|
52610
|
+
await electron$7.saveCollection(relPath, col);
|
|
52590
52611
|
loadCollection(relPath, col);
|
|
52591
52612
|
setActiveCollection(col.id);
|
|
52592
52613
|
const ws2 = useStore.getState().workspace;
|
|
52593
52614
|
if (ws2 && !ws2.collections.includes(relPath)) {
|
|
52594
52615
|
const updated = { ...ws2, collections: [...ws2.collections, relPath] };
|
|
52595
52616
|
useStore.setState({ workspace: updated });
|
|
52596
|
-
await electron$
|
|
52617
|
+
await electron$7.saveWorkspace(updated);
|
|
52597
52618
|
}
|
|
52598
52619
|
}
|
|
52599
52620
|
if (!workspace) return null;
|
|
@@ -52659,7 +52680,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52659
52680
|
"button",
|
|
52660
52681
|
{
|
|
52661
52682
|
onClick: async () => {
|
|
52662
|
-
const result = await electron$
|
|
52683
|
+
const result = await electron$7.openWorkspace();
|
|
52663
52684
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
52664
52685
|
},
|
|
52665
52686
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -52671,7 +52692,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52671
52692
|
"button",
|
|
52672
52693
|
{
|
|
52673
52694
|
onClick: async () => {
|
|
52674
|
-
const result = await electron$
|
|
52695
|
+
const result = await electron$7.newWorkspace();
|
|
52675
52696
|
if (result) await applyWorkspace(result.workspace, result.workspacePath);
|
|
52676
52697
|
},
|
|
52677
52698
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -52683,7 +52704,7 @@ function Toolbar({ onOpenDocs: _onOpenDocs }) {
|
|
|
52683
52704
|
"button",
|
|
52684
52705
|
{
|
|
52685
52706
|
onClick: async () => {
|
|
52686
|
-
await electron$
|
|
52707
|
+
await electron$7.closeWorkspace();
|
|
52687
52708
|
closeWorkspace();
|
|
52688
52709
|
},
|
|
52689
52710
|
className: "px-2.5 py-1 text-xs bg-surface-800 hover:bg-surface-700 rounded transition-colors",
|
|
@@ -53080,7 +53101,7 @@ api-tests:
|
|
|
53080
53101
|
function EmptyState({ message }) {
|
|
53081
53102
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-24 text-surface-400 text-xs", children: message });
|
|
53082
53103
|
}
|
|
53083
|
-
const { electron: electron$
|
|
53104
|
+
const { electron: electron$6 } = window;
|
|
53084
53105
|
function collectRequests(collectionId, folderId, filterTags) {
|
|
53085
53106
|
const state = useStore.getState();
|
|
53086
53107
|
const col = state.collections[collectionId]?.data;
|
|
@@ -53176,13 +53197,13 @@ function RunnerModal() {
|
|
|
53176
53197
|
setSummary(null);
|
|
53177
53198
|
setRunnerRunning(true);
|
|
53178
53199
|
progressIdxRef.current = 0;
|
|
53179
|
-
electron$
|
|
53200
|
+
electron$6.onRunProgress((result) => {
|
|
53180
53201
|
const idx = progressIdxRef.current;
|
|
53181
53202
|
patchRunnerResult(idx, result);
|
|
53182
53203
|
if (result.status !== "running") progressIdxRef.current++;
|
|
53183
53204
|
});
|
|
53184
53205
|
try {
|
|
53185
|
-
const s = await electron$
|
|
53206
|
+
const s = await electron$6.runCollection({
|
|
53186
53207
|
items: items2,
|
|
53187
53208
|
environment: env,
|
|
53188
53209
|
globals,
|
|
@@ -53193,7 +53214,7 @@ function RunnerModal() {
|
|
|
53193
53214
|
});
|
|
53194
53215
|
setSummary(s);
|
|
53195
53216
|
} finally {
|
|
53196
|
-
electron$
|
|
53217
|
+
electron$6.offRunProgress();
|
|
53197
53218
|
setRunnerRunning(false);
|
|
53198
53219
|
}
|
|
53199
53220
|
}, [collectionId, folderId, filterTags, selectedEnvId, environments, globals, colEntry, requestDelay, workspaceSettings, setRunnerResults, patchRunnerResult, setRunnerRunning]);
|
|
@@ -53406,7 +53427,7 @@ function RunnerModal() {
|
|
|
53406
53427
|
};
|
|
53407
53428
|
const content2 = exportFormat === "junit" ? buildJUnitReport(runnerResults, summary, meta2) : exportFormat === "html" ? buildHtmlReport(runnerResults, summary, meta2) : buildJsonReport(runnerResults, summary, meta2);
|
|
53408
53429
|
const ext = exportFormat === "junit" ? "xml" : exportFormat === "html" ? "html" : "json";
|
|
53409
|
-
electron$
|
|
53430
|
+
electron$6.saveResults(content2, `spector-results.${ext}`);
|
|
53410
53431
|
},
|
|
53411
53432
|
className: "px-2.5 py-0.5 bg-surface-800 hover:bg-surface-700 rounded transition-colors text-[11px] whitespace-nowrap",
|
|
53412
53433
|
children: "Export results"
|
|
@@ -53624,7 +53645,7 @@ function CollectionPanel() {
|
|
|
53624
53645
|
] })
|
|
53625
53646
|
] });
|
|
53626
53647
|
}
|
|
53627
|
-
const { electron: electron$
|
|
53648
|
+
const { electron: electron$5 } = window;
|
|
53628
53649
|
function MockPanel() {
|
|
53629
53650
|
const mocks = useStore((s) => s.mocks);
|
|
53630
53651
|
const activeMockId = useStore((s) => s.activeMockId);
|
|
@@ -53632,16 +53653,25 @@ function MockPanel() {
|
|
|
53632
53653
|
const addMock = useStore((s) => s.addMock);
|
|
53633
53654
|
const deleteMock = useStore((s) => s.deleteMock);
|
|
53634
53655
|
const setRunning = useStore((s) => s.setMockRunning);
|
|
53656
|
+
const recorderOpen = useStore((s) => s.recorderOpen);
|
|
53657
|
+
const recorderRunning = useStore((s) => s.recorderRunning);
|
|
53658
|
+
const recorderUpstream = useStore((s) => s.recorderUpstream);
|
|
53659
|
+
const recorderPort = useStore((s) => s.recorderPort);
|
|
53660
|
+
const setRecorderOpen = useStore((s) => s.setRecorderOpen);
|
|
53661
|
+
const setRecorderRunning = useStore((s) => s.setRecorderRunning);
|
|
53662
|
+
const setRecorderUpstream = useStore((s) => s.setRecorderUpstream);
|
|
53663
|
+
const setRecorderPort = useStore((s) => s.setRecorderPort);
|
|
53664
|
+
const [recorderError, setRecorderError] = reactExports.useState("");
|
|
53635
53665
|
const mockList = Object.values(mocks);
|
|
53636
53666
|
async function handleAddMock() {
|
|
53637
53667
|
addMock();
|
|
53638
53668
|
const ws2 = useStore.getState().workspace;
|
|
53639
|
-
if (ws2) await electron$
|
|
53669
|
+
if (ws2) await electron$5.saveWorkspace(ws2);
|
|
53640
53670
|
const state = useStore.getState();
|
|
53641
53671
|
const newId = state.activeMockId;
|
|
53642
53672
|
if (newId) {
|
|
53643
53673
|
const entry = state.mocks[newId];
|
|
53644
|
-
await electron$
|
|
53674
|
+
await electron$5.saveMock(entry.relPath, entry.data);
|
|
53645
53675
|
setActiveMock(newId);
|
|
53646
53676
|
}
|
|
53647
53677
|
}
|
|
@@ -53649,10 +53679,19 @@ function MockPanel() {
|
|
|
53649
53679
|
e.stopPropagation();
|
|
53650
53680
|
const entry = useStore.getState().mocks[mockId];
|
|
53651
53681
|
if (!entry) return;
|
|
53652
|
-
if (entry.running) await electron$
|
|
53682
|
+
if (entry.running) await electron$5.mockStop(mockId);
|
|
53653
53683
|
deleteMock(mockId);
|
|
53654
53684
|
const ws2 = useStore.getState().workspace;
|
|
53655
|
-
if (ws2) await electron$
|
|
53685
|
+
if (ws2) await electron$5.saveWorkspace(ws2);
|
|
53686
|
+
}
|
|
53687
|
+
async function handleStartRecorder() {
|
|
53688
|
+
setRecorderError("");
|
|
53689
|
+
try {
|
|
53690
|
+
await electron$5.recordStart({ upstream: recorderUpstream, port: recorderPort });
|
|
53691
|
+
setRecorderRunning(true);
|
|
53692
|
+
} catch (err) {
|
|
53693
|
+
setRecorderError(err instanceof Error ? err.message : String(err));
|
|
53694
|
+
}
|
|
53656
53695
|
}
|
|
53657
53696
|
async function toggleRunning(e, mockId) {
|
|
53658
53697
|
e.stopPropagation();
|
|
@@ -53660,18 +53699,75 @@ function MockPanel() {
|
|
|
53660
53699
|
if (!entry) return;
|
|
53661
53700
|
try {
|
|
53662
53701
|
if (entry.running) {
|
|
53663
|
-
await electron$
|
|
53702
|
+
await electron$5.mockStop(mockId);
|
|
53664
53703
|
setRunning(mockId, false);
|
|
53665
53704
|
} else {
|
|
53666
53705
|
const latest2 = useStore.getState().mocks[mockId].data;
|
|
53667
|
-
await electron$
|
|
53668
|
-
await electron$
|
|
53706
|
+
await electron$5.saveMock(entry.relPath, latest2);
|
|
53707
|
+
await electron$5.mockStart(latest2);
|
|
53669
53708
|
setRunning(mockId, true);
|
|
53670
53709
|
}
|
|
53671
53710
|
} catch {
|
|
53672
53711
|
}
|
|
53673
53712
|
}
|
|
53674
53713
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [
|
|
53714
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-b border-surface-800 flex-shrink-0", children: [
|
|
53715
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
53716
|
+
"button",
|
|
53717
|
+
{
|
|
53718
|
+
onClick: () => setRecorderOpen(!recorderOpen),
|
|
53719
|
+
className: "w-full flex items-center justify-between px-3 py-2 hover:bg-surface-800/40 transition-colors",
|
|
53720
|
+
children: [
|
|
53721
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
53722
|
+
recorderRunning && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-red-500 animate-pulse" }),
|
|
53723
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-surface-600", children: "Recorder" })
|
|
53724
|
+
] }),
|
|
53725
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] text-surface-600", children: recorderOpen ? "▲" : "▼" })
|
|
53726
|
+
]
|
|
53727
|
+
}
|
|
53728
|
+
),
|
|
53729
|
+
recorderOpen && !recorderRunning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 pb-3 flex flex-col gap-2", children: [
|
|
53730
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
53731
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-surface-500", children: "Upstream URL" }),
|
|
53732
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53733
|
+
"input",
|
|
53734
|
+
{
|
|
53735
|
+
value: recorderUpstream,
|
|
53736
|
+
onChange: (e) => setRecorderUpstream(e.target.value),
|
|
53737
|
+
placeholder: "https://api.example.com",
|
|
53738
|
+
className: "w-full bg-surface-900 border border-surface-700 rounded px-2 py-1 text-[11px] text-surface-100 placeholder-surface-600 focus:outline-none focus:border-blue-500"
|
|
53739
|
+
}
|
|
53740
|
+
)
|
|
53741
|
+
] }),
|
|
53742
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1", children: [
|
|
53743
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { className: "text-[10px] text-surface-500", children: "Local port" }),
|
|
53744
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53745
|
+
"input",
|
|
53746
|
+
{
|
|
53747
|
+
type: "number",
|
|
53748
|
+
value: recorderPort,
|
|
53749
|
+
onChange: (e) => setRecorderPort(Number(e.target.value)),
|
|
53750
|
+
className: "w-full bg-surface-900 border border-surface-700 rounded px-2 py-1 text-[11px] text-surface-100 focus:outline-none focus:border-blue-500"
|
|
53751
|
+
}
|
|
53752
|
+
)
|
|
53753
|
+
] }),
|
|
53754
|
+
recorderError && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-red-400", children: recorderError }),
|
|
53755
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
53756
|
+
"button",
|
|
53757
|
+
{
|
|
53758
|
+
onClick: handleStartRecorder,
|
|
53759
|
+
disabled: !recorderUpstream,
|
|
53760
|
+
className: "w-full py-1 rounded text-[11px] bg-red-900/40 text-red-400 hover:bg-red-800/50 transition-colors disabled:opacity-40 disabled:cursor-not-allowed",
|
|
53761
|
+
children: "⏺ Start recording"
|
|
53762
|
+
}
|
|
53763
|
+
)
|
|
53764
|
+
] }),
|
|
53765
|
+
recorderOpen && recorderRunning && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 pb-2 text-[10px] text-surface-400", children: [
|
|
53766
|
+
"Recording → ",
|
|
53767
|
+
recorderUpstream,
|
|
53768
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ml-2 text-surface-600", children: "(open panel to manage)" })
|
|
53769
|
+
] })
|
|
53770
|
+
] }),
|
|
53675
53771
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-2 flex items-center justify-between border-b border-surface-800 flex-shrink-0", children: [
|
|
53676
53772
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-[10px] font-semibold uppercase tracking-widest text-surface-600", children: "Mock Servers" }),
|
|
53677
53773
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -53741,7 +53837,7 @@ function MockPanel() {
|
|
|
53741
53837
|
}) })
|
|
53742
53838
|
] });
|
|
53743
53839
|
}
|
|
53744
|
-
const { electron: electron$
|
|
53840
|
+
const { electron: electron$4 } = window;
|
|
53745
53841
|
const METHODS_PLUS_ANY = ["ANY", "GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"];
|
|
53746
53842
|
function RouteRow({
|
|
53747
53843
|
route,
|
|
@@ -54143,20 +54239,20 @@ function MockDetailPanel({ mockId }) {
|
|
|
54143
54239
|
const routes = mock.routes ?? [];
|
|
54144
54240
|
async function save(updated) {
|
|
54145
54241
|
updateMock(mock.id, updated);
|
|
54146
|
-
await electron$
|
|
54147
|
-
if (running) await electron$
|
|
54148
|
-
if (workspace) await electron$
|
|
54242
|
+
await electron$4.saveMock(entry.relPath, updated);
|
|
54243
|
+
if (running) await electron$4.mockUpdateRoutes(mock.id, updated.routes ?? []);
|
|
54244
|
+
if (workspace) await electron$4.saveWorkspace(workspace);
|
|
54149
54245
|
}
|
|
54150
54246
|
async function toggleRunning() {
|
|
54151
54247
|
setError(null);
|
|
54152
54248
|
try {
|
|
54153
54249
|
if (running) {
|
|
54154
|
-
await electron$
|
|
54250
|
+
await electron$4.mockStop(mock.id);
|
|
54155
54251
|
setRunning(mock.id, false);
|
|
54156
54252
|
} else {
|
|
54157
54253
|
const latest2 = useStore.getState().mocks[mock.id].data;
|
|
54158
|
-
await electron$
|
|
54159
|
-
await electron$
|
|
54254
|
+
await electron$4.saveMock(entry.relPath, latest2);
|
|
54255
|
+
await electron$4.mockStart(latest2);
|
|
54160
54256
|
setRunning(mock.id, true);
|
|
54161
54257
|
}
|
|
54162
54258
|
} catch (e) {
|
|
@@ -54269,7 +54365,7 @@ function MockDetailPanel({ mockId }) {
|
|
|
54269
54365
|
"button",
|
|
54270
54366
|
{
|
|
54271
54367
|
onClick: () => {
|
|
54272
|
-
if (running) electron$
|
|
54368
|
+
if (running) electron$4.mockStop(mock.id);
|
|
54273
54369
|
deleteMock(mock.id);
|
|
54274
54370
|
setActive2(null);
|
|
54275
54371
|
},
|
|
@@ -54336,6 +54432,250 @@ function MockDetailPanel({ mockId }) {
|
|
|
54336
54432
|
] })
|
|
54337
54433
|
] });
|
|
54338
54434
|
}
|
|
54435
|
+
const { electron: electron$3 } = window;
|
|
54436
|
+
function statusColor$1(status) {
|
|
54437
|
+
if (status === 0) return "text-yellow-400";
|
|
54438
|
+
if (status < 300) return "text-emerald-400";
|
|
54439
|
+
if (status < 400) return "text-blue-400";
|
|
54440
|
+
return "text-red-400";
|
|
54441
|
+
}
|
|
54442
|
+
function methodColor(method) {
|
|
54443
|
+
switch (method.toUpperCase()) {
|
|
54444
|
+
case "GET":
|
|
54445
|
+
return "text-emerald-400";
|
|
54446
|
+
case "POST":
|
|
54447
|
+
return "text-blue-400";
|
|
54448
|
+
case "PUT":
|
|
54449
|
+
case "PATCH":
|
|
54450
|
+
return "text-yellow-400";
|
|
54451
|
+
case "DELETE":
|
|
54452
|
+
return "text-red-400";
|
|
54453
|
+
default:
|
|
54454
|
+
return "text-surface-300";
|
|
54455
|
+
}
|
|
54456
|
+
}
|
|
54457
|
+
function RecorderPanel({ onImportMock, onClose, defaultTargetMockId }) {
|
|
54458
|
+
const [entries, setEntries] = reactExports.useState([]);
|
|
54459
|
+
const [selected, setSelected] = reactExports.useState(null);
|
|
54460
|
+
const [stopped, setStopped] = reactExports.useState(false);
|
|
54461
|
+
const [session, setSession] = reactExports.useState(null);
|
|
54462
|
+
const [importing, setImporting] = reactExports.useState(false);
|
|
54463
|
+
const [importTarget, setImportTarget] = reactExports.useState(defaultTargetMockId || "new");
|
|
54464
|
+
const listRef = reactExports.useRef(null);
|
|
54465
|
+
const upstream = useStore((s) => s.recorderUpstream);
|
|
54466
|
+
const mockList = Object.values(useStore((s) => s.mocks));
|
|
54467
|
+
reactExports.useEffect(() => {
|
|
54468
|
+
electron$3.onRecordHit((entry) => {
|
|
54469
|
+
setEntries((prev) => {
|
|
54470
|
+
const next = [...prev, entry];
|
|
54471
|
+
setTimeout(() => {
|
|
54472
|
+
if (listRef.current) listRef.current.scrollTop = listRef.current.scrollHeight;
|
|
54473
|
+
}, 0);
|
|
54474
|
+
return next;
|
|
54475
|
+
});
|
|
54476
|
+
});
|
|
54477
|
+
return () => {
|
|
54478
|
+
electron$3.offRecordHit();
|
|
54479
|
+
};
|
|
54480
|
+
}, []);
|
|
54481
|
+
async function handleStop() {
|
|
54482
|
+
try {
|
|
54483
|
+
const s = await electron$3.recordStop();
|
|
54484
|
+
setSession(s);
|
|
54485
|
+
setStopped(true);
|
|
54486
|
+
} catch {
|
|
54487
|
+
}
|
|
54488
|
+
}
|
|
54489
|
+
async function handleImport() {
|
|
54490
|
+
if (!session) return;
|
|
54491
|
+
setImporting(true);
|
|
54492
|
+
try {
|
|
54493
|
+
await onImportMock(session, importTarget === "new" ? null : importTarget);
|
|
54494
|
+
} finally {
|
|
54495
|
+
setImporting(false);
|
|
54496
|
+
}
|
|
54497
|
+
}
|
|
54498
|
+
const total = entries.length;
|
|
54499
|
+
const errors2 = entries.filter((e) => e.response.status === 0 || e.response.status >= 400).length;
|
|
54500
|
+
const avgMs = total > 0 ? Math.round(entries.reduce((s, e) => s + e.durationMs, 0) / total) : 0;
|
|
54501
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col h-full bg-surface-950 text-surface-200 min-h-0", children: [
|
|
54502
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center justify-between px-4 py-2.5 border-b border-surface-800 flex-shrink-0", children: [
|
|
54503
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
54504
|
+
!stopped && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "w-2 h-2 rounded-full bg-red-500 animate-pulse" }),
|
|
54505
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-sm font-semibold text-surface-100", children: stopped ? "Recording stopped" : "Recording…" }),
|
|
54506
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] font-mono text-surface-400 truncate max-w-[260px]", children: [
|
|
54507
|
+
"→ ",
|
|
54508
|
+
upstream
|
|
54509
|
+
] })
|
|
54510
|
+
] }),
|
|
54511
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center gap-2", children: !stopped ? /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54512
|
+
"button",
|
|
54513
|
+
{
|
|
54514
|
+
onClick: handleStop,
|
|
54515
|
+
className: "px-2.5 py-1 rounded text-[11px] bg-red-900/40 text-red-400 hover:bg-red-800/50 transition-colors",
|
|
54516
|
+
children: "■ Stop"
|
|
54517
|
+
}
|
|
54518
|
+
) : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
|
|
54519
|
+
session && session.entries.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
54520
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54521
|
+
"select",
|
|
54522
|
+
{
|
|
54523
|
+
value: importTarget,
|
|
54524
|
+
onChange: (e) => setImportTarget(e.target.value),
|
|
54525
|
+
className: "bg-surface-800 border border-surface-700 rounded px-2 py-1 text-[11px] text-surface-200 focus:outline-none focus:border-blue-500",
|
|
54526
|
+
children: [
|
|
54527
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: "new", children: "— New mock server —" }),
|
|
54528
|
+
mockList.map((entry) => /* @__PURE__ */ jsxRuntimeExports.jsx("option", { value: entry.data.id, children: entry.data.name }, entry.data.id))
|
|
54529
|
+
]
|
|
54530
|
+
}
|
|
54531
|
+
),
|
|
54532
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54533
|
+
"button",
|
|
54534
|
+
{
|
|
54535
|
+
onClick: handleImport,
|
|
54536
|
+
disabled: importing,
|
|
54537
|
+
className: "px-2.5 py-1 rounded text-[11px] bg-blue-600 text-white hover:bg-blue-500 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap",
|
|
54538
|
+
children: importing ? "Importing…" : "⧉ Import"
|
|
54539
|
+
}
|
|
54540
|
+
)
|
|
54541
|
+
] }),
|
|
54542
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54543
|
+
"button",
|
|
54544
|
+
{
|
|
54545
|
+
onClick: onClose,
|
|
54546
|
+
className: "px-2.5 py-1 rounded text-[11px] text-surface-500 hover:text-surface-300 transition-colors",
|
|
54547
|
+
children: "✕ Close"
|
|
54548
|
+
}
|
|
54549
|
+
)
|
|
54550
|
+
] }) })
|
|
54551
|
+
] }),
|
|
54552
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-4 px-4 py-1.5 border-b border-surface-800/50 flex-shrink-0 text-[11px]", children: [
|
|
54553
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-400", children: [
|
|
54554
|
+
"Requests: ",
|
|
54555
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-200 font-medium", children: total })
|
|
54556
|
+
] }),
|
|
54557
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-400", children: [
|
|
54558
|
+
"Errors: ",
|
|
54559
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: errors2 > 0 ? "text-red-400 font-medium" : "text-surface-200 font-medium", children: errors2 })
|
|
54560
|
+
] }),
|
|
54561
|
+
total > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-400", children: [
|
|
54562
|
+
"Avg: ",
|
|
54563
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-200 font-medium", children: [
|
|
54564
|
+
avgMs,
|
|
54565
|
+
"ms"
|
|
54566
|
+
] })
|
|
54567
|
+
] })
|
|
54568
|
+
] }),
|
|
54569
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-1 min-h-0", children: [
|
|
54570
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54571
|
+
"div",
|
|
54572
|
+
{
|
|
54573
|
+
ref: listRef,
|
|
54574
|
+
className: "w-72 flex-shrink-0 overflow-y-auto border-r border-surface-800",
|
|
54575
|
+
children: entries.length === 0 ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col items-center justify-center h-full text-surface-500 text-xs gap-2 p-4 text-center", children: [
|
|
54576
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-2xl opacity-30", children: "⏺" }),
|
|
54577
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: "Waiting for requests…" }),
|
|
54578
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("p", { className: "text-[10px]", children: [
|
|
54579
|
+
"Point your app at http://localhost:",
|
|
54580
|
+
useStore.getState().recorderPort
|
|
54581
|
+
] })
|
|
54582
|
+
] }) : entries.map((entry) => {
|
|
54583
|
+
const active = selected?.id === entry.id;
|
|
54584
|
+
const sc = statusColor$1(entry.response.status);
|
|
54585
|
+
const mc = methodColor(entry.request.method);
|
|
54586
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
54587
|
+
"button",
|
|
54588
|
+
{
|
|
54589
|
+
onClick: () => setSelected(entry),
|
|
54590
|
+
className: `w-full flex items-center gap-2 px-3 py-2 text-left border-b border-surface-800/40 transition-colors text-[11px] ${active ? "bg-surface-800" : "hover:bg-surface-800/50"}`,
|
|
54591
|
+
children: [
|
|
54592
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono font-bold w-12 shrink-0 ${mc}`, children: entry.request.method }),
|
|
54593
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-surface-200 font-mono", children: entry.request.path }),
|
|
54594
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono font-semibold shrink-0 ${sc}`, children: entry.response.status || "ERR" }),
|
|
54595
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-500 shrink-0 w-10 text-right", children: [
|
|
54596
|
+
entry.durationMs,
|
|
54597
|
+
"ms"
|
|
54598
|
+
] })
|
|
54599
|
+
]
|
|
54600
|
+
},
|
|
54601
|
+
entry.id
|
|
54602
|
+
);
|
|
54603
|
+
})
|
|
54604
|
+
}
|
|
54605
|
+
),
|
|
54606
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 overflow-y-auto p-4 min-w-0", children: !selected ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex items-center justify-center h-full text-surface-500 text-xs", children: "Select a request to inspect" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(EntryDetail, { entry: selected }) })
|
|
54607
|
+
] })
|
|
54608
|
+
] });
|
|
54609
|
+
}
|
|
54610
|
+
function EntryDetail({ entry }) {
|
|
54611
|
+
const [tab, setTab] = reactExports.useState("request");
|
|
54612
|
+
const mc = methodColor(entry.request.method);
|
|
54613
|
+
const sc = statusColor$1(entry.response.status);
|
|
54614
|
+
const prettyBody = (raw) => {
|
|
54615
|
+
if (!raw) return "";
|
|
54616
|
+
if (raw.startsWith("base64:")) return "[binary content — base64 encoded]";
|
|
54617
|
+
try {
|
|
54618
|
+
return JSON.stringify(JSON.parse(raw), null, 2);
|
|
54619
|
+
} catch {
|
|
54620
|
+
return raw;
|
|
54621
|
+
}
|
|
54622
|
+
};
|
|
54623
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3 text-[12px]", children: [
|
|
54624
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex items-center gap-2 flex-wrap", children: [
|
|
54625
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `font-mono font-bold ${mc}`, children: entry.request.method }),
|
|
54626
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-surface-100 break-all", children: entry.request.path }),
|
|
54627
|
+
Object.keys(entry.request.query).length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "font-mono text-surface-400 break-all", children: [
|
|
54628
|
+
"?",
|
|
54629
|
+
new URLSearchParams(entry.request.query).toString()
|
|
54630
|
+
] }),
|
|
54631
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: `font-mono font-semibold ml-auto ${sc}`, children: [
|
|
54632
|
+
entry.response.status || "ERR",
|
|
54633
|
+
" ",
|
|
54634
|
+
entry.response.statusText
|
|
54635
|
+
] }),
|
|
54636
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-surface-500", children: [
|
|
54637
|
+
entry.durationMs,
|
|
54638
|
+
"ms"
|
|
54639
|
+
] })
|
|
54640
|
+
] }),
|
|
54641
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] text-surface-500", children: entry.timestamp }),
|
|
54642
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex border-b border-surface-800", children: ["request", "response"].map((t2) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
54643
|
+
"button",
|
|
54644
|
+
{
|
|
54645
|
+
onClick: () => setTab(t2),
|
|
54646
|
+
className: `px-3 py-1.5 text-[11px] capitalize transition-colors border-b-2 -mb-px ${tab === t2 ? "border-blue-500 text-blue-300" : "border-transparent text-surface-400 hover:text-surface-200"}`,
|
|
54647
|
+
children: t2
|
|
54648
|
+
},
|
|
54649
|
+
t2
|
|
54650
|
+
)) }),
|
|
54651
|
+
tab === "request" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
54652
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Section, { label: "Headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeadersTable, { headers: entry.request.headers }) }),
|
|
54653
|
+
entry.request.body && /* @__PURE__ */ jsxRuntimeExports.jsx(Section, { label: "Body", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-[11px] whitespace-pre-wrap break-all text-surface-200 bg-surface-900 border border-surface-700 rounded p-3 max-h-72 overflow-y-auto", children: prettyBody(entry.request.body) }) })
|
|
54654
|
+
] }),
|
|
54655
|
+
tab === "response" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
54656
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(Section, { label: "Headers", children: /* @__PURE__ */ jsxRuntimeExports.jsx(HeadersTable, { headers: entry.response.headers }) }),
|
|
54657
|
+
entry.response.body && /* @__PURE__ */ jsxRuntimeExports.jsx(Section, { label: "Body", children: /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "font-mono text-[11px] whitespace-pre-wrap break-all text-surface-200 bg-surface-900 border border-surface-700 rounded p-3 max-h-72 overflow-y-auto", children: prettyBody(entry.response.body) }) }),
|
|
54658
|
+
entry.response.binary && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-[10px] text-yellow-400", children: "Binary response — body stored as base64" })
|
|
54659
|
+
] })
|
|
54660
|
+
] });
|
|
54661
|
+
}
|
|
54662
|
+
function Section({ label, children }) {
|
|
54663
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex flex-col gap-1.5", children: [
|
|
54664
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "text-[10px] font-semibold uppercase tracking-wider text-surface-500", children: label }),
|
|
54665
|
+
children
|
|
54666
|
+
] });
|
|
54667
|
+
}
|
|
54668
|
+
function HeadersTable({ headers }) {
|
|
54669
|
+
const entries = Object.entries(headers);
|
|
54670
|
+
if (entries.length === 0) return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-500 text-[11px]", children: "none" });
|
|
54671
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "font-mono text-[11px] flex flex-col gap-0.5", children: entries.map(([k, v]) => /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-2 min-w-0", children: [
|
|
54672
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-blue-300 shrink-0", children: [
|
|
54673
|
+
k,
|
|
54674
|
+
":"
|
|
54675
|
+
] }),
|
|
54676
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-surface-300 break-all", children: v })
|
|
54677
|
+
] }, k)) });
|
|
54678
|
+
}
|
|
54339
54679
|
const { electron: electron$2 } = window;
|
|
54340
54680
|
function ContractPanel() {
|
|
54341
54681
|
const collections = useStore((s) => s.collections);
|
|
@@ -54594,7 +54934,7 @@ function StatusBadge({ status }) {
|
|
|
54594
54934
|
function DiffViewer({ diff }) {
|
|
54595
54935
|
if (!diff) return /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 p-3", children: "No changes." });
|
|
54596
54936
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("pre", { className: "text-[11px] font-mono overflow-auto p-3 leading-relaxed", children: diff.split("\n").map((line, i) => {
|
|
54597
|
-
const cls = line.startsWith("+") && !line.startsWith("+++") ? "text-emerald-400" : line.startsWith("-") && !line.startsWith("---") ? "text-red-400" : line.startsWith("@@") ? "text-blue-400" : "text-surface-400";
|
|
54937
|
+
const cls = line.startsWith("<<<<<<<") ? "text-red-400 font-bold bg-red-900/20" : line.startsWith("=======") ? "text-amber-400 font-bold bg-amber-900/20" : line.startsWith(">>>>>>>") ? "text-blue-400 font-bold bg-blue-900/20" : line.startsWith("+") && !line.startsWith("+++") ? "text-emerald-400" : line.startsWith("-") && !line.startsWith("---") ? "text-red-400" : line.startsWith("@@") ? "text-blue-400" : "text-surface-400";
|
|
54598
54938
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: cls, children: line || " " }, i);
|
|
54599
54939
|
}) });
|
|
54600
54940
|
}
|
|
@@ -54676,6 +55016,17 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54676
55016
|
setPushing(false);
|
|
54677
55017
|
}
|
|
54678
55018
|
}
|
|
55019
|
+
async function resolveConflict(path, mode) {
|
|
55020
|
+
try {
|
|
55021
|
+
if (mode === "ours") await electron$1.gitResolveOurs(path);
|
|
55022
|
+
else if (mode === "theirs") await electron$1.gitResolveTheirs(path);
|
|
55023
|
+
else await electron$1.gitMarkResolved(path);
|
|
55024
|
+
if (diffFile === path) setDiffFile(null);
|
|
55025
|
+
onRefresh();
|
|
55026
|
+
} catch (e) {
|
|
55027
|
+
setError(String(e));
|
|
55028
|
+
}
|
|
55029
|
+
}
|
|
54679
55030
|
const allUnstaged = [...status.unstaged, ...status.untracked];
|
|
54680
55031
|
const hasStaged = status.staged.length > 0;
|
|
54681
55032
|
const needsPush = status.ahead > 0;
|
|
@@ -54730,6 +55081,13 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54730
55081
|
}
|
|
54731
55082
|
)
|
|
54732
55083
|
] }) : /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "mx-3 mt-2 px-2 py-1 rounded text-[11px] text-surface-600 border border-surface-800 flex-shrink-0", children: "✓ Nothing to push" })),
|
|
55084
|
+
status.conflicted.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mx-3 mt-2 px-2 py-1.5 rounded text-[11px] bg-red-900/20 text-red-300 border border-red-800/40 flex-shrink-0", children: [
|
|
55085
|
+
"⚠ ",
|
|
55086
|
+
status.conflicted.length,
|
|
55087
|
+
" merge conflict",
|
|
55088
|
+
status.conflicted.length !== 1 ? "s" : "",
|
|
55089
|
+
" — resolve below before committing"
|
|
55090
|
+
] }),
|
|
54733
55091
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toast, { toast }),
|
|
54734
55092
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 min-h-0 overflow-y-auto", children: [
|
|
54735
55093
|
hasStaged && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
@@ -54814,7 +55172,64 @@ function ChangesTab({ status, onRefresh }) {
|
|
|
54814
55172
|
f.path
|
|
54815
55173
|
))
|
|
54816
55174
|
] }),
|
|
54817
|
-
status.
|
|
55175
|
+
status.conflicted.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { children: [
|
|
55176
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "px-3 py-1.5", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "text-[10px] uppercase tracking-widest text-red-400 font-semibold", children: [
|
|
55177
|
+
"Conflicts (",
|
|
55178
|
+
status.conflicted.length,
|
|
55179
|
+
")"
|
|
55180
|
+
] }) }),
|
|
55181
|
+
status.conflicted.map((path) => /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
55182
|
+
"div",
|
|
55183
|
+
{
|
|
55184
|
+
className: `flex items-center gap-2 px-3 py-1 hover:bg-surface-800/50 cursor-pointer group text-xs ${diffFile === path && !diffStaged ? "bg-surface-800" : ""}`,
|
|
55185
|
+
onClick: () => showDiff({ path, status: "modified" }, false),
|
|
55186
|
+
children: [
|
|
55187
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "font-mono text-[11px] font-bold w-4 shrink-0 text-red-400", children: "!" }),
|
|
55188
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "flex-1 truncate text-red-300", children: path }),
|
|
55189
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex gap-1 opacity-0 group-hover:opacity-100 transition-all", children: [
|
|
55190
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55191
|
+
"button",
|
|
55192
|
+
{
|
|
55193
|
+
onClick: (e) => {
|
|
55194
|
+
e.stopPropagation();
|
|
55195
|
+
resolveConflict(path, "ours");
|
|
55196
|
+
},
|
|
55197
|
+
className: "text-[10px] px-1.5 py-0.5 rounded bg-surface-700 text-surface-300 hover:bg-emerald-900/50 hover:text-emerald-300 transition-colors",
|
|
55198
|
+
title: "Accept ours (current branch)",
|
|
55199
|
+
children: "Ours"
|
|
55200
|
+
}
|
|
55201
|
+
),
|
|
55202
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55203
|
+
"button",
|
|
55204
|
+
{
|
|
55205
|
+
onClick: (e) => {
|
|
55206
|
+
e.stopPropagation();
|
|
55207
|
+
resolveConflict(path, "theirs");
|
|
55208
|
+
},
|
|
55209
|
+
className: "text-[10px] px-1.5 py-0.5 rounded bg-surface-700 text-surface-300 hover:bg-blue-900/50 hover:text-blue-300 transition-colors",
|
|
55210
|
+
title: "Accept theirs (incoming)",
|
|
55211
|
+
children: "Theirs"
|
|
55212
|
+
}
|
|
55213
|
+
),
|
|
55214
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55215
|
+
"button",
|
|
55216
|
+
{
|
|
55217
|
+
onClick: (e) => {
|
|
55218
|
+
e.stopPropagation();
|
|
55219
|
+
resolveConflict(path, "mark");
|
|
55220
|
+
},
|
|
55221
|
+
className: "text-[10px] px-1.5 py-0.5 rounded bg-surface-700 text-surface-300 hover:bg-surface-600 transition-colors",
|
|
55222
|
+
title: "Mark as resolved (manual edit)",
|
|
55223
|
+
children: "✓"
|
|
55224
|
+
}
|
|
55225
|
+
)
|
|
55226
|
+
] })
|
|
55227
|
+
]
|
|
55228
|
+
},
|
|
55229
|
+
path
|
|
55230
|
+
))
|
|
55231
|
+
] }),
|
|
55232
|
+
status.staged.length === 0 && allUnstaged.length === 0 && status.conflicted.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "Working tree clean." })
|
|
54818
55233
|
] }),
|
|
54819
55234
|
diffFile && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border-t border-surface-800 flex flex-col max-h-48 min-h-0", children: [
|
|
54820
55235
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "px-3 py-1 flex items-center justify-between flex-shrink-0 border-b border-surface-800", children: [
|
|
@@ -55578,6 +55993,12 @@ function App() {
|
|
|
55578
55993
|
const addCollection = useStore((s) => s.addCollection);
|
|
55579
55994
|
const addMockHit = useStore((s) => s.addMockHit);
|
|
55580
55995
|
const activeMockId = useStore((s) => s.activeMockId);
|
|
55996
|
+
const recorderRunning = useStore((s) => s.recorderRunning);
|
|
55997
|
+
const recorderTargetMockId = useStore((s) => s.recorderTargetMockId);
|
|
55998
|
+
const setRecorderRunning = useStore((s) => s.setRecorderRunning);
|
|
55999
|
+
const loadMock = useStore((s) => s.loadMock);
|
|
56000
|
+
const setActiveMockId = useStore((s) => s.setActiveMockId);
|
|
56001
|
+
const updateMock = useStore((s) => s.updateMock);
|
|
55581
56002
|
const theme2 = useStore((s) => s.theme);
|
|
55582
56003
|
const setCommandPaletteOpen = useStore((s) => s.setCommandPaletteOpen);
|
|
55583
56004
|
const setWsStatus = useStore((s) => s.setWsStatus);
|
|
@@ -55639,7 +56060,7 @@ function App() {
|
|
|
55639
56060
|
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { style: { color: "#6aa3c8" }, children: "Spector" }),
|
|
55640
56061
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ml-2 text-[10px] font-normal opacity-50", children: [
|
|
55641
56062
|
"v",
|
|
55642
|
-
"0.1.
|
|
56063
|
+
"0.1.3"
|
|
55643
56064
|
] })
|
|
55644
56065
|
] }) }),
|
|
55645
56066
|
/* @__PURE__ */ jsxRuntimeExports.jsx(Toolbar, { onOpenDocs: () => setDocsModalOpen(true) }),
|
|
@@ -55756,7 +56177,41 @@ function App() {
|
|
|
55756
56177
|
tab.id
|
|
55757
56178
|
);
|
|
55758
56179
|
}) }),
|
|
55759
|
-
sidebarTab === "contracts" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ContractResultsPanel, {}) }) : sidebarTab === "mocks" &&
|
|
56180
|
+
sidebarTab === "contracts" ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(ContractResultsPanel, {}) }) : sidebarTab === "mocks" && recorderRunning ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
56181
|
+
RecorderPanel,
|
|
56182
|
+
{
|
|
56183
|
+
defaultTargetMockId: recorderTargetMockId,
|
|
56184
|
+
onClose: () => setRecorderRunning(false),
|
|
56185
|
+
onImportMock: async (session, targetMockId) => {
|
|
56186
|
+
const name2 = `Recorded — ${new URL(session.upstream).hostname}`;
|
|
56187
|
+
const newRoutes = await electron.recordToMock(session.entries, session.upstream, name2, session.port);
|
|
56188
|
+
if (targetMockId) {
|
|
56189
|
+
const existing = useStore.getState().mocks[targetMockId];
|
|
56190
|
+
if (existing) {
|
|
56191
|
+
const existingKeys = new Set(existing.data.routes.map((r) => `${r.method}:${r.path}`));
|
|
56192
|
+
const toAdd = newRoutes.routes.filter((r) => !existingKeys.has(`${r.method}:${r.path}`));
|
|
56193
|
+
const updated = { ...existing.data, routes: [...existing.data.routes, ...toAdd] };
|
|
56194
|
+
updateMock(targetMockId, updated);
|
|
56195
|
+
await electron.saveMock(existing.relPath, updated);
|
|
56196
|
+
setActiveMockId(targetMockId);
|
|
56197
|
+
setRecorderRunning(false);
|
|
56198
|
+
}
|
|
56199
|
+
} else {
|
|
56200
|
+
const relPath = `mocks/${newRoutes.id}.mock.json`;
|
|
56201
|
+
loadMock(relPath, newRoutes);
|
|
56202
|
+
await electron.saveMock(relPath, newRoutes);
|
|
56203
|
+
const ws2 = useStore.getState().workspace;
|
|
56204
|
+
if (ws2) {
|
|
56205
|
+
if (!ws2.mocks) ws2.mocks = [];
|
|
56206
|
+
ws2.mocks.push(relPath);
|
|
56207
|
+
await electron.saveWorkspace(ws2);
|
|
56208
|
+
}
|
|
56209
|
+
setActiveMockId(newRoutes.id);
|
|
56210
|
+
setRecorderRunning(false);
|
|
56211
|
+
}
|
|
56212
|
+
}
|
|
56213
|
+
}
|
|
56214
|
+
) }) : sidebarTab === "mocks" && activeMockId ? /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-h-0", children: /* @__PURE__ */ jsxRuntimeExports.jsx(MockDetailPanel, { mockId: activeMockId }) }) : activeRequest ? /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex-1 flex min-h-0", children: [
|
|
55760
56215
|
/* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "flex-1 min-w-0 flex flex-col overflow-hidden", children: /* @__PURE__ */ jsxRuntimeExports.jsx(RequestBuilder, { request: activeRequest }) }),
|
|
55761
56216
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
55762
56217
|
"button",
|