postboy-tui 1.3.2 → 1.3.4

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.
Files changed (3) hide show
  1. package/README.md +4 -4
  2. package/dist/cli.js +84 -69
  3. package/package.json +12 -12
package/README.md CHANGED
@@ -67,7 +67,7 @@ bun i -g postboy-tui@latest
67
67
 
68
68
  ### 1. Intuitive TUI
69
69
 
70
- A clean, keyboard-driven interface designed for productivity. Navigate between panels, compose requests, and view responses without leaving your terminal.
70
+ A clean, keyboard-driven interface designed for productivity. Navigate between panels, compose requests and view responses without leaving your terminal.
71
71
 
72
72
  <img width="1111" height="649" alt="image" src="https://github.com/user-attachments/assets/de940869-4bfe-4349-a1bd-2259d46f2fde" />
73
73
 
@@ -75,7 +75,7 @@ A clean, keyboard-driven interface designed for productivity. Navigate between p
75
75
 
76
76
  ### 2. Request Composer
77
77
 
78
- Create and edit HTTP requests with support for all major methods. Add headers, body, and query parameters with ease.
78
+ Create and edit HTTP requests with support for all major methods. Add headers, body and query parameters with ease.
79
79
 
80
80
  <img width="643" height="428" alt="image" src="https://github.com/user-attachments/assets/304c5903-f3c1-4470-85d2-39eebb184c63" />
81
81
 
@@ -84,7 +84,7 @@ Create and edit HTTP requests with support for all major methods. Add headers, b
84
84
 
85
85
  ### 3. History Management
86
86
 
87
- Automatically saves every request you make. Browse, search, and re-run previous requests.
87
+ Automatically saves every request you make. Browse, search and re-run previous requests.
88
88
 
89
89
 
90
90
  <img width="427" height="440" alt="image" src="https://github.com/user-attachments/assets/cf055710-5701-490c-bfc6-a9afbbea223d" />
@@ -94,7 +94,7 @@ Automatically saves every request you make. Browse, search, and re-run previous
94
94
 
95
95
  ### 4. Response Viewer
96
96
 
97
- View responses in a pretty-printed format. Supports JSON, XML, and raw text. Syntax highlighting for easy reading.
97
+ View responses in a pretty-printed format. Supports JSON, XML and raw text. Syntax highlighting for easy reading.
98
98
 
99
99
  <img width="646" height="692" alt="image" src="https://github.com/user-attachments/assets/d5c60702-c71e-410c-bfbd-2643f78403f3" />
100
100
 
package/dist/cli.js CHANGED
@@ -4428,7 +4428,7 @@ See https://react.dev/link/invalid-hook-call for tips about how to debug and fix
4428
4428
 
4429
4429
  // node_modules/react/index.js
4430
4430
  var require_react = __commonJS((exports, module) => {
4431
- var react_development = __toESM(require_react_development(), 1);
4431
+ var react_development = __toESM(require_react_development());
4432
4432
  if (false) {} else {
4433
4433
  module.exports = react_development;
4434
4434
  }
@@ -4873,7 +4873,7 @@ var require_scheduler_development = __commonJS((exports) => {
4873
4873
 
4874
4874
  // node_modules/react-reconciler/node_modules/scheduler/index.js
4875
4875
  var require_scheduler = __commonJS((exports, module) => {
4876
- var scheduler_development = __toESM(require_scheduler_development(), 1);
4876
+ var scheduler_development = __toESM(require_scheduler_development());
4877
4877
  if (false) {} else {
4878
4878
  module.exports = scheduler_development;
4879
4879
  }
@@ -4881,8 +4881,8 @@ var require_scheduler = __commonJS((exports, module) => {
4881
4881
 
4882
4882
  // node_modules/react-reconciler/cjs/react-reconciler.development.js
4883
4883
  var require_react_reconciler_development = __commonJS((exports, module) => {
4884
- var React = __toESM(require_react(), 1);
4885
- var Scheduler = __toESM(require_scheduler(), 1);
4884
+ var React = __toESM(require_react());
4885
+ var Scheduler = __toESM(require_scheduler());
4886
4886
  module.exports = function($$$config) {
4887
4887
  function findHook(fiber, id) {
4888
4888
  for (fiber = fiber.memoizedState;fiber !== null && 0 < id; )
@@ -31695,7 +31695,7 @@ var require_stack_utils = __commonJS((exports, module) => {
31695
31695
 
31696
31696
  // node_modules/react/cjs/react-jsx-dev-runtime.development.js
31697
31697
  var require_react_jsx_dev_runtime_development = __commonJS((exports) => {
31698
- var React10 = __toESM(require_react(), 1);
31698
+ var React10 = __toESM(require_react());
31699
31699
  (function() {
31700
31700
  function getComponentNameFromType(type) {
31701
31701
  if (type == null)
@@ -31909,7 +31909,7 @@ React keys must be passed directly to JSX without using spread:
31909
31909
 
31910
31910
  // node_modules/react/jsx-dev-runtime.js
31911
31911
  var require_jsx_dev_runtime = __commonJS((exports, module) => {
31912
- var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development(), 1);
31912
+ var react_jsx_dev_runtime_development = __toESM(require_react_jsx_dev_runtime_development());
31913
31913
  if (false) {} else {
31914
31914
  module.exports = react_jsx_dev_runtime_development;
31915
31915
  }
@@ -67644,17 +67644,26 @@ function sendRequest({ method, url, headers = {}, body }) {
67644
67644
  data += chunk;
67645
67645
  });
67646
67646
  res.on("end", () => {
67647
- resolve({
67648
- status: res.statusCode || 0,
67649
- statusText: res.statusMessage || "",
67650
- headers: Object.fromEntries(Object.entries(res.headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : v || ""])),
67651
- body: data
67652
- });
67647
+ try {
67648
+ resolve({
67649
+ status: res.statusCode || 0,
67650
+ statusText: res.statusMessage || "",
67651
+ headers: Object.fromEntries(Object.entries(res.headers).map(([k, v]) => [k, Array.isArray(v) ? v.join(", ") : v || ""])),
67652
+ body: data
67653
+ });
67654
+ } catch (err) {
67655
+ reject(err);
67656
+ }
67653
67657
  });
67654
67658
  });
67655
67659
  req.on("error", reject);
67656
- if (body)
67657
- req.write(body);
67660
+ if (body) {
67661
+ try {
67662
+ req.write(body);
67663
+ } catch (err) {
67664
+ reject(err);
67665
+ }
67666
+ }
67658
67667
  req.end();
67659
67668
  });
67660
67669
  }
@@ -67822,8 +67831,11 @@ var Spinner = ({ theme }) => {
67822
67831
  // src/ui/app/components/Formfield.tsx
67823
67832
  var import_react24 = __toESM(require_react(), 1);
67824
67833
  var jsx_dev_runtime2 = __toESM(require_jsx_dev_runtime(), 1);
67825
- var FormField = ({ label, value, onChange, placeholder, theme, suggestions = [] }) => {
67834
+ var FormField = ({ label, value, onChange, placeholder, theme, suggestions = [], onFocusChange }) => {
67826
67835
  const { isFocused } = use_focus_default();
67836
+ import_react24.useEffect(() => {
67837
+ onFocusChange?.(isFocused);
67838
+ }, [isFocused, onFocusChange]);
67827
67839
  const [showSuggestions, setShowSuggestions] = import_react24.useState(false);
67828
67840
  const [filteredSuggestions, setFilteredSuggestions] = import_react24.useState([]);
67829
67841
  const [highlightedIndex, setHighlightedIndex] = import_react24.useState(0);
@@ -68351,12 +68363,15 @@ var JsonSyntaxHighlight = import_react29.default.memo(({ jsonString, theme }) =>
68351
68363
  // src/ui/app/components/responsepanel.tsx
68352
68364
  var import_react30 = __toESM(require_react(), 1);
68353
68365
  var jsx_dev_runtime9 = __toESM(require_jsx_dev_runtime(), 1);
68354
- var ResponsePanel = import_react30.default.memo(({ response, theme }) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(ScrollableBox, {
68355
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68366
+ var ResponsePanel = import_react30.default.memo(({ response, theme }) => {
68367
+ const [activeTab, setActiveTab] = import_react30.useState("body");
68368
+ const tabs = [{ name: "headers", label: "Headers" }, { name: "body", label: "Body" }];
68369
+ return /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68356
68370
  flexDirection: "column",
68357
- gap: 1,
68371
+ flexGrow: 1,
68358
68372
  children: [
68359
68373
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68374
+ marginBottom: 1,
68360
68375
  children: [
68361
68376
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68362
68377
  width: 8,
@@ -68376,58 +68391,52 @@ var ResponsePanel = import_react30.default.memo(({ response, theme }) => /* @__P
68376
68391
  }, undefined, true, undefined, this)
68377
68392
  ]
68378
68393
  }, undefined, true, undefined, this),
68394
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Tabs, {
68395
+ tabs,
68396
+ activeTab,
68397
+ onChange: setActiveTab,
68398
+ theme
68399
+ }, undefined, false, undefined, this),
68379
68400
  /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68401
+ marginTop: 1,
68402
+ flexGrow: 1,
68380
68403
  children: [
68381
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68382
- width: 8,
68383
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68384
- color: theme.colors.primary,
68385
- children: "HEADERS:"
68386
- }, undefined, false, undefined, this)
68387
- }, undefined, false, undefined, this),
68388
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68389
- flexDirection: "column",
68390
- children: Object.entries(JSON.parse(response.headers || "{}")).map(([key, value]) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68391
- children: [
68392
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68393
- color: theme.colors.accent,
68394
- children: key
68395
- }, undefined, false, undefined, this),
68396
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68397
- color: theme.colors.muted,
68398
- children: ": "
68399
- }, undefined, false, undefined, this),
68400
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68401
- color: theme.colors.success,
68402
- children: String(value)
68403
- }, undefined, false, undefined, this)
68404
- ]
68405
- }, key, true, undefined, this))
68406
- }, undefined, false, undefined, this)
68407
- ]
68408
- }, undefined, true, undefined, this),
68409
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68410
- children: [
68411
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68412
- width: 8,
68413
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68414
- color: theme.colors.primary,
68415
- children: "PAYLOAD:"
68404
+ activeTab === "headers" && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(ScrollableBox, {
68405
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68406
+ flexDirection: "column",
68407
+ children: Object.entries(JSON.parse(response.headers || "{}")).map(([key, value]) => /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68408
+ children: [
68409
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68410
+ color: theme.colors.accent,
68411
+ children: key
68412
+ }, undefined, false, undefined, this),
68413
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68414
+ color: theme.colors.muted,
68415
+ children: ": "
68416
+ }, undefined, false, undefined, this),
68417
+ /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Text, {
68418
+ color: theme.colors.success,
68419
+ children: String(value)
68420
+ }, undefined, false, undefined, this)
68421
+ ]
68422
+ }, key, true, undefined, this))
68416
68423
  }, undefined, false, undefined, this)
68417
68424
  }, undefined, false, undefined, this),
68418
- /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68419
- flexDirection: "column",
68420
- flexGrow: 1,
68421
- children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(JsonSyntaxHighlight, {
68422
- jsonString: response.body,
68423
- theme
68425
+ activeTab === "body" && /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(ScrollableBox, {
68426
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(Box_default, {
68427
+ flexDirection: "column",
68428
+ flexGrow: 1,
68429
+ children: /* @__PURE__ */ jsx_dev_runtime9.jsxDEV(JsonSyntaxHighlight, {
68430
+ jsonString: response.body,
68431
+ theme
68432
+ }, undefined, false, undefined, this)
68424
68433
  }, undefined, false, undefined, this)
68425
68434
  }, undefined, false, undefined, this)
68426
68435
  ]
68427
68436
  }, undefined, true, undefined, this)
68428
68437
  ]
68429
- }, undefined, true, undefined, this)
68430
- }, undefined, false, undefined, this));
68438
+ }, undefined, true, undefined, this);
68439
+ });
68431
68440
 
68432
68441
  // src/utils/themeManager.ts
68433
68442
  import { promises as fs3 } from "fs";
@@ -68554,7 +68563,7 @@ var SendButton = ({ onPress, loading, theme }) => {
68554
68563
  }, undefined, false, undefined, this);
68555
68564
  };
68556
68565
  var HTTP_METHODS = ["GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS", "HEAD"];
68557
- var RequestPanel = import_react31.default.memo(({ request, onMethodChange, onUrlChange, onHeadersChange, onBodyChange, onSend, loading, theme, historyUrls = [] }) => /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
68566
+ var RequestPanel = import_react31.default.memo(({ request, onMethodChange, onUrlChange, onHeadersChange, onBodyChange, onSend, loading, theme, historyUrls = [], onInputFocus }) => /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
68558
68567
  flexDirection: "column",
68559
68568
  gap: 1,
68560
68569
  flexGrow: 1,
@@ -68565,7 +68574,8 @@ var RequestPanel = import_react31.default.memo(({ request, onMethodChange, onUrl
68565
68574
  onChange: onMethodChange,
68566
68575
  placeholder: "GET",
68567
68576
  theme,
68568
- suggestions: HTTP_METHODS
68577
+ suggestions: HTTP_METHODS,
68578
+ onFocusChange: onInputFocus
68569
68579
  }, undefined, false, undefined, this),
68570
68580
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(FormField, {
68571
68581
  label: "URL",
@@ -68573,21 +68583,24 @@ var RequestPanel = import_react31.default.memo(({ request, onMethodChange, onUrl
68573
68583
  onChange: onUrlChange,
68574
68584
  placeholder: "https://api.example.com",
68575
68585
  theme,
68576
- suggestions: historyUrls
68586
+ suggestions: historyUrls,
68587
+ onFocusChange: onInputFocus
68577
68588
  }, undefined, false, undefined, this),
68578
68589
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(FormField, {
68579
68590
  label: "Headers",
68580
68591
  value: request.headers,
68581
68592
  onChange: onHeadersChange,
68582
68593
  placeholder: '{ "key": "value" }',
68583
- theme
68594
+ theme,
68595
+ onFocusChange: onInputFocus
68584
68596
  }, undefined, false, undefined, this),
68585
68597
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(FormField, {
68586
68598
  label: "Body",
68587
68599
  value: request.body,
68588
68600
  onChange: onBodyChange,
68589
68601
  placeholder: '{ "key": "value" }',
68590
- theme
68602
+ theme,
68603
+ onFocusChange: onInputFocus
68591
68604
  }, undefined, false, undefined, this),
68592
68605
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
68593
68606
  marginTop: 1,
@@ -68674,6 +68687,7 @@ var UI = () => {
68674
68687
  const tabs = [{ name: "request", label: "Request" }, { name: "response", label: "Response" }];
68675
68688
  const activeIndex = tabs.findIndex((t) => t.name === activeTab);
68676
68689
  const [showThemeSelector, setShowThemeSelector] = import_react31.useState(false);
68690
+ const [inputFocused, setInputFocused] = import_react31.useState(false);
68677
68691
  use_input_default((input, key) => {
68678
68692
  if (input === "q")
68679
68693
  exit();
@@ -68685,7 +68699,7 @@ var UI = () => {
68685
68699
  setActiveTab(tabs[(activeIndex - 1 + tabs.length) % tabs.length]?.name ?? "request");
68686
68700
  if (key.escape && showThemeSelector)
68687
68701
  setShowThemeSelector(false);
68688
- if ((input === "t" || input === "T") && !key.ctrl && !key.meta)
68702
+ if ((input === "t" || input === "T") && !key.ctrl && !key.meta && !inputFocused)
68689
68703
  setShowThemeSelector((prev) => !prev);
68690
68704
  }, { isActive: true });
68691
68705
  const onMethodChange = import_react31.useCallback((method) => setRequest((r) => ({ ...r, method })), []);
@@ -68835,7 +68849,8 @@ var UI = () => {
68835
68849
  onSend: handleSend,
68836
68850
  loading,
68837
68851
  theme: theme.colors,
68838
- historyUrls
68852
+ historyUrls,
68853
+ onInputFocus: setInputFocused
68839
68854
  }, undefined, false, undefined, this)
68840
68855
  }, undefined, false, undefined, this),
68841
68856
  /* @__PURE__ */ jsx_dev_runtime10.jsxDEV(Box_default, {
@@ -69065,7 +69080,7 @@ async function mockApis() {
69065
69080
 
69066
69081
  // src/index.ts
69067
69082
  var program2 = new Command;
69068
- program2.version("1.3.2").description(import_chalk8.default.yellow("PostBoy CLI - Test your APIs with ease"));
69083
+ program2.version("1.3.4").description(import_chalk8.default.yellow("PostBoy CLI - Test your APIs with ease"));
69069
69084
  program2.command("run").description("Run a test API request").action(testCommand);
69070
69085
  program2.command("mock-list").description("List the mock API servers").action(mockApis);
69071
69086
  program2.command("ui").description("UI for PostBoy").action(uiCommand);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postboy-tui",
3
- "version": "1.3.2",
3
+ "version": "1.3.4",
4
4
  "main": "dist/cli.js",
5
5
  "bin": {
6
6
  "postboy-tui": "dist/cli.js"
@@ -8,22 +8,22 @@
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
- "keywords": [
12
- "postboy",
13
- "tui",
14
- "cli",
15
- "terminal",
16
- "interface",
17
- "developer-tool",
18
- "api-testing"
19
- ],
11
+ "keywords": [
12
+ "postboy",
13
+ "tui",
14
+ "cli",
15
+ "terminal",
16
+ "interface",
17
+ "developer-tool",
18
+ "api-testing"
19
+ ],
20
20
  "scripts": {
21
21
  "start": "bun run src/index.ts",
22
22
  "build": "bun build src/index.ts --outfile=dist/cli.js --target node",
23
23
  "dev": "bun run --watch src/index.ts"
24
24
  },
25
- "repository": "https://github.com/Postboy-tui/app",
26
- "homepage": "httsps://github.com/Postboy-tui/app#readme",
25
+ "repository": "https://github.com/Postboy-tui/app",
26
+ "homepage": "httsps://github.com/Postboy-tui/app#readme",
27
27
  "module": "src/index.ts",
28
28
  "type": "module",
29
29
  "private": false,