@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.
@@ -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$m } = window;
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$m.saveCollection(relPath, data);
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$m.saveWorkspace(workspace);
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$l } = window;
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$l.loadCollection(colPath);
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$l.loadEnvironment(envPath);
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$l.loadMock(relPath);
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$l.loadCollection(ws2.collections[0]);
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$k } = window;
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$k.wsdlFetch(soap.wsdlUrl.trim());
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$j } = window;
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$j.setSecret(ref2, secretValue);
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$j.oauth2StartFlow(auth, vars);
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$j.oauth2StartFlow(auth, vars);
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$j.oauth2RefreshToken(auth, {}, oauth2RefreshToken);
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$i } = window;
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$i.inferContractSchema(lastResponse.body);
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$h } = window;
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$h.onWsMessage(({ requestId, message }) => {
49636
+ electron$i.onWsMessage(({ requestId, message }) => {
49616
49637
  addWsMessage(requestId, message);
49617
49638
  });
49618
- electron$h.onWsStatus(({ requestId, status, error: error2 }) => {
49639
+ electron$i.onWsStatus(({ requestId, status, error: error2 }) => {
49619
49640
  setWsStatus(requestId, status, error2);
49620
49641
  });
49621
49642
  return () => {
49622
- electron$h.offWsEvents();
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$h.wsConnect(request.id, request.url, headers);
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$h.wsDisconnect(request.id);
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$h.wsSend(request.id, text);
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$g } = window;
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$g.sendRequest({
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$f } = window;
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$f.saveMock(entry.relPath, updated);
50560
+ await electron$g.saveMock(entry.relPath, updated);
50540
50561
  const ws2 = useStore.getState().workspace;
50541
- if (ws2) await electron$f.saveWorkspace(ws2);
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$f.saveMock(entry.relPath, updated);
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$f.inferContractSchema(response.body) : null;
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$e } = window;
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$e.generateCode({ collection: col, environment: env, target });
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$e.saveGeneratedFilesAsZip(files, col?.name ?? "api-tests", target);
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$1(status) {
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$1(status)}`, children: status })
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$d } = window;
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$d.openWorkspace();
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$d.newWorkspace();
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$c } = window;
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$c.setMasterKey(password);
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$b } = window;
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$b.checkMasterKey();
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$b.saveWorkspace(ws2);
51603
+ if (ws2) await electron$c.saveWorkspace(ws2);
51583
51604
  }
51584
- await electron$b.saveEnvironment(newRelPath, env);
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$a } = window;
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$a.checkMasterKey();
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$9 } = window;
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$9.saveWorkspace(updated);
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$8 } = window;
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$8.generateDocs(buildPayload());
52230
+ const content2 = await electron$9.generateDocs(buildPayload());
52210
52231
  const filename = format2 === "html" ? "api-docs.html" : "api-docs.md";
52211
- await electron$8.saveResults(content2, filename);
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$8.generateDocs(buildPayload());
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$7 } = window;
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$7.importPostman();
52357
- if (opt.id === "openapi") col = await electron$7.importOpenApi();
52358
- if (opt.id === "insomnia") col = await electron$7.importInsomnia();
52359
- if (opt.id === "bruno") col = await electron$7.importBruno();
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$7.importOpenApiFromUrl(trimmed);
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$6 } = window;
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$6.saveCollection(relPath, data);
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$6.saveEnvironment(relPath, data);
52600
+ await electron$7.saveEnvironment(relPath, data);
52580
52601
  }
52581
- if (workspace) await electron$6.saveWorkspace(workspace);
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$6.saveCollection(relPath, col);
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$6.saveWorkspace(updated);
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$6.openWorkspace();
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$6.newWorkspace();
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$6.closeWorkspace();
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$5 } = window;
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$5.onRunProgress((result) => {
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$5.runCollection({
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$5.offRunProgress();
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$5.saveResults(content2, `spector-results.${ext}`);
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$4 } = window;
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$4.saveWorkspace(ws2);
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$4.saveMock(entry.relPath, entry.data);
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$4.mockStop(mockId);
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$4.saveWorkspace(ws2);
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$4.mockStop(mockId);
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$4.saveMock(entry.relPath, latest2);
53668
- await electron$4.mockStart(latest2);
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$3 } = window;
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$3.saveMock(entry.relPath, updated);
54147
- if (running) await electron$3.mockUpdateRoutes(mock.id, updated.routes ?? []);
54148
- if (workspace) await electron$3.saveWorkspace(workspace);
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$3.mockStop(mock.id);
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$3.saveMock(entry.relPath, latest2);
54159
- await electron$3.mockStart(latest2);
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$3.mockStop(mock.id);
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.staged.length === 0 && allUnstaged.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-surface-500 px-3 py-4", children: "Working tree clean." })
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.2"
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" && 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: [
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",