reqwise-core 1.1.4 → 1.2.0

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/dist/index.js CHANGED
@@ -68,6 +68,18 @@ function initStorage(cfg3) {
68
68
  }
69
69
  function saveEntry(entry) {
70
70
  memory.push(entry);
71
+ if (config.historyTTL && config.historyTTL > 0) {
72
+ const now = Date.now();
73
+ const ttlMs = config.historyTTL * 24 * 60 * 60 * 1e3;
74
+ memory = memory.filter((e) => {
75
+ try {
76
+ const entryTime = new Date(e.timestamp).getTime();
77
+ return now - entryTime < ttlMs;
78
+ } catch (e2) {
79
+ return true;
80
+ }
81
+ });
82
+ }
71
83
  if (config.maxItems && memory.length > config.maxItems) {
72
84
  memory = memory.slice(-config.maxItems);
73
85
  }
@@ -131,6 +143,7 @@ __export(index_exports, {
131
143
  i18n: () => i18n_default,
132
144
  panel: () => panel_default,
133
145
  renderer: () => renderer_default,
146
+ rendererSetConfig: () => setConfig2,
134
147
  storage: () => storage_default
135
148
  });
136
149
  module.exports = __toCommonJS(index_exports);
@@ -265,13 +278,15 @@ var catalog = {
265
278
  form_url: "URL",
266
279
  form_headers: "Headers (JSON)",
267
280
  form_body: "Body (JSON)",
268
- send_request: "\u2192 Send Request",
281
+ send_request: "Send Request",
269
282
  clear_form: "Clear",
270
283
  enter_url_warning: "Please enter a URL",
271
284
  response_label: "Response",
272
285
  error_label: "Error",
273
286
  manual_badge: "Manual",
274
- time: "Time"
287
+ time: "Time",
288
+ all_methods: "All Methods",
289
+ all_statuses: "All Statuses"
275
290
  },
276
291
  tr: {
277
292
  requests: "\u0130stekler",
@@ -322,7 +337,9 @@ var catalog = {
322
337
  response_label: "Yan\u0131t",
323
338
  error_label: "Hata",
324
339
  manual_badge: "Manuel",
325
- time: "Saat"
340
+ time: "Saat",
341
+ all_methods: "T\xFCm Metotlar",
342
+ all_statuses: "T\xFCm Durumlar"
326
343
  },
327
344
  az: {
328
345
  requests: "Sor\u011Fular",
@@ -373,7 +390,9 @@ var catalog = {
373
390
  response_label: "Cavab",
374
391
  error_label: "X\u0259ta",
375
392
  manual_badge: "Manuel",
376
- time: "Vaxt"
393
+ time: "Vaxt",
394
+ all_methods: "B\xFCt\xFCn Metodlar",
395
+ all_statuses: "B\xFCt\xFCn Statuslar"
377
396
  },
378
397
  ru: {
379
398
  requests: "\u0417\u0430\u043F\u0440\u043E\u0441\u044B",
@@ -424,7 +443,9 @@ var catalog = {
424
443
  response_label: "\u041E\u0442\u0432\u0435\u0442",
425
444
  error_label: "\u041E\u0448\u0438\u0431\u043A\u0430",
426
445
  manual_badge: "\u0412\u0440\u0443\u0447\u043D\u0443\u044E",
427
- time: "\u0412\u0440\u0435\u043C\u044F"
446
+ time: "\u0412\u0440\u0435\u043C\u044F",
447
+ all_methods: "\u0412\u0441\u0435 \u043C\u0435\u0442\u043E\u0434\u044B",
448
+ all_statuses: "\u0412\u0441\u0435 \u0441\u0442\u0430\u0442\u0443\u0441\u044B"
428
449
  },
429
450
  de: {
430
451
  requests: "Anfragen",
@@ -475,7 +496,9 @@ var catalog = {
475
496
  response_label: "Antwort",
476
497
  error_label: "Fehler",
477
498
  manual_badge: "Manuell",
478
- time: "Zeit"
499
+ time: "Zeit",
500
+ all_methods: "Alle Methoden",
501
+ all_statuses: "Alle Status"
479
502
  },
480
503
  fr: {
481
504
  requests: "Requ\xEAtes",
@@ -526,7 +549,9 @@ var catalog = {
526
549
  response_label: "R\xE9ponse",
527
550
  error_label: "Erreur",
528
551
  manual_badge: "Manuel",
529
- time: "Heure"
552
+ time: "Heure",
553
+ all_methods: "Toutes les m\xE9thodes",
554
+ all_statuses: "Tous les statuts"
530
555
  },
531
556
  es: {
532
557
  requests: "Solicitudes",
@@ -577,7 +602,9 @@ var catalog = {
577
602
  response_label: "Respuesta",
578
603
  error_label: "Error",
579
604
  manual_badge: "Manual",
580
- time: "Hora"
605
+ time: "Hora",
606
+ all_methods: "Todos los m\xE9todos",
607
+ all_statuses: "Todos los estados"
581
608
  },
582
609
  pt: {
583
610
  requests: "Requisi\xE7\xF5es",
@@ -628,7 +655,9 @@ var catalog = {
628
655
  response_label: "Resposta",
629
656
  error_label: "Erro",
630
657
  manual_badge: "Manual",
631
- time: "Hora"
658
+ time: "Hora",
659
+ all_methods: "Todos os m\xE9todos",
660
+ all_statuses: "Todos os estados"
632
661
  },
633
662
  zh: {
634
663
  requests: "\u8BF7\u6C42",
@@ -679,7 +708,9 @@ var catalog = {
679
708
  response_label: "\u54CD\u5E94",
680
709
  error_label: "\u9519\u8BEF",
681
710
  manual_badge: "\u624B\u52A8",
682
- time: "\u65F6\u95F4"
711
+ time: "\u65F6\u95F4",
712
+ all_methods: "\u6240\u6709\u65B9\u6CD5",
713
+ all_statuses: "\u6240\u6709\u72B6\u6001"
683
714
  },
684
715
  ja: {
685
716
  requests: "\u30EA\u30AF\u30A8\u30B9\u30C8",
@@ -730,7 +761,9 @@ var catalog = {
730
761
  response_label: "\u30EC\u30B9\u30DD\u30F3\u30B9",
731
762
  error_label: "\u30A8\u30E9\u30FC",
732
763
  manual_badge: "\u624B\u52D5",
733
- time: "\u6642\u523B"
764
+ time: "\u6642\u523B",
765
+ all_methods: "\u3059\u3079\u3066\u306E\u30E1\u30BD\u30C3\u30C9",
766
+ all_statuses: "\u3059\u3079\u3066\u306E\u30B9\u30C6\u30FC\u30BF\u30B9"
734
767
  },
735
768
  ar: {
736
769
  requests: "\u0627\u0644\u0637\u0644\u0628\u0627\u062A",
@@ -781,7 +814,9 @@ var catalog = {
781
814
  response_label: "\u0627\u0644\u0627\u0633\u062A\u062C\u0627\u0628\u0629",
782
815
  error_label: "\u062E\u0637\u0623",
783
816
  manual_badge: "\u064A\u062F\u0648\u064A",
784
- time: "\u0627\u0644\u0648\u0642\u062A"
817
+ time: "\u0627\u0644\u0648\u0642\u062A",
818
+ all_methods: "\u062C\u0645\u064A\u0639 \u0627\u0644\u0623\u0633\u0627\u0644\u064A\u0628",
819
+ all_statuses: "\u062C\u0645\u064A\u0639 \u0627\u0644\u062D\u0627\u0644\u0627\u062A"
785
820
  },
786
821
  ko: {
787
822
  requests: "\uC694\uCCAD",
@@ -832,7 +867,9 @@ var catalog = {
832
867
  response_label: "\uC751\uB2F5",
833
868
  error_label: "\uC624\uB958",
834
869
  manual_badge: "\uC218\uB3D9",
835
- time: "\uC2DC\uAC04"
870
+ time: "\uC2DC\uAC04",
871
+ all_methods: "\uBAA8\uB4E0 \uBA54\uC11C\uB4DC",
872
+ all_statuses: "\uBAA8\uB4E0 \uC0C1\uD0DC"
836
873
  },
837
874
  it: {
838
875
  requests: "Richieste",
@@ -883,7 +920,9 @@ var catalog = {
883
920
  response_label: "Risposta",
884
921
  error_label: "Errore",
885
922
  manual_badge: "Manuale",
886
- time: "Ora"
923
+ time: "Ora",
924
+ all_methods: "Tutti i metodi",
925
+ all_statuses: "Tutti gli stati"
887
926
  },
888
927
  pl: {
889
928
  requests: "\u017B\u0105dania",
@@ -934,7 +973,9 @@ var catalog = {
934
973
  response_label: "Odpowied\u017A",
935
974
  error_label: "B\u0142\u0105d",
936
975
  manual_badge: "R\u0119cznie",
937
- time: "Czas"
976
+ time: "Czas",
977
+ all_methods: "Wszystkie metody",
978
+ all_statuses: "Wszystkie statusy"
938
979
  },
939
980
  nl: {
940
981
  requests: "Verzoeken",
@@ -985,7 +1026,9 @@ var catalog = {
985
1026
  response_label: "Antwoord",
986
1027
  error_label: "Fout",
987
1028
  manual_badge: "Handmatig",
988
- time: "Tijd"
1029
+ time: "Tijd",
1030
+ all_methods: "Alle methoden",
1031
+ all_statuses: "Alle statussen"
989
1032
  }
990
1033
  };
991
1034
  try {
@@ -1051,13 +1094,19 @@ var i18n_default = {
1051
1094
  init_storage();
1052
1095
  var START_TS = /* @__PURE__ */ Symbol("reqwise_start_ts");
1053
1096
  var cfg2 = {
1054
- theme: "dark",
1097
+ theme: "system",
1055
1098
  placement: "right",
1099
+ show: "general",
1056
1100
  defaultOpen: false,
1057
1101
  enabled: true,
1058
- maxItems: 200,
1102
+ hotkey: "ctrl+shift+e",
1103
+ maxItems: 500,
1059
1104
  persistHistory: true,
1060
- defaultLang: "en"
1105
+ defaultLang: "en",
1106
+ langs: ["en"],
1107
+ ignore: [],
1108
+ maskHeaders: [],
1109
+ maskFields: []
1061
1110
  };
1062
1111
  function initClient(c) {
1063
1112
  if (c) cfg2 = { ...cfg2 || {}, ...c };
@@ -1089,7 +1138,21 @@ function buildEntry(base) {
1089
1138
  }
1090
1139
  function recordPartial(entry) {
1091
1140
  const e = buildEntry(entry);
1141
+ try {
1142
+ if (cfg2.onRequest) cfg2.onRequest(entry);
1143
+ } catch (err) {
1144
+ console.error("[reqwise] onRequest callback error", err);
1145
+ }
1092
1146
  storage_default.saveEntry(e);
1147
+ try {
1148
+ if (e.error && cfg2.onError) {
1149
+ cfg2.onError(e);
1150
+ } else if (!e.error && cfg2.onResponse) {
1151
+ cfg2.onResponse(e);
1152
+ }
1153
+ } catch (err) {
1154
+ console.error("[reqwise] onResponse/onError callback error", err);
1155
+ }
1093
1156
  }
1094
1157
  function wrapAxios(instance) {
1095
1158
  if (!instance || typeof instance.interceptors !== "object") return;
@@ -1106,9 +1169,10 @@ function wrapAxios(instance) {
1106
1169
  const req = res.config || {};
1107
1170
  const start = req[START_TS] || Date.now();
1108
1171
  const duration = Date.now() - start;
1172
+ const fullUrl = (req.baseURL || "") + (req.url || "");
1109
1173
  const entry = buildEntry({
1110
1174
  method: (req.method || "GET").toUpperCase(),
1111
- url: req.url || req.baseURL || "",
1175
+ url: fullUrl || "",
1112
1176
  requestHeaders: filter_default.maskHeaders(req.headers),
1113
1177
  requestBody: filter_default.maskFields(req.data),
1114
1178
  status: res.status,
@@ -1128,9 +1192,10 @@ function wrapAxios(instance) {
1128
1192
  const start = req[START_TS] || Date.now();
1129
1193
  const duration = Date.now() - start;
1130
1194
  const response = err?.response || {};
1195
+ const fullUrl = (req.baseURL || "") + (req.url || "");
1131
1196
  const entry = buildEntry({
1132
1197
  method: (req.method || "GET").toUpperCase(),
1133
- url: req.url || req.baseURL || "",
1198
+ url: fullUrl || "",
1134
1199
  requestHeaders: filter_default.maskHeaders(req.headers),
1135
1200
  requestBody: filter_default.maskFields(req.data),
1136
1201
  status: response.status,
@@ -1190,50 +1255,50 @@ async function fetchWithRecord(input, init) {
1190
1255
  throw err;
1191
1256
  }
1192
1257
  }
1193
- async function get(url, config2) {
1258
+ async function get(url, config3) {
1194
1259
  if (cfg2.axiosInstance && typeof cfg2.axiosInstance.get === "function") {
1195
- return cfg2.axiosInstance.get(url, config2);
1260
+ return cfg2.axiosInstance.get(url, config3);
1196
1261
  }
1197
- return fetchWithRecord(url, { method: "GET", headers: config2?.headers });
1262
+ return fetchWithRecord(url, { method: "GET", headers: config3?.headers });
1198
1263
  }
1199
- async function post(url, data, config2) {
1264
+ async function post(url, data, config3) {
1200
1265
  if (cfg2.axiosInstance && typeof cfg2.axiosInstance.post === "function") {
1201
- return cfg2.axiosInstance.post(url, data, config2);
1266
+ return cfg2.axiosInstance.post(url, data, config3);
1202
1267
  }
1203
1268
  const body = typeof data === "string" ? data : JSON.stringify(data);
1204
1269
  return fetchWithRecord(url, {
1205
1270
  method: "POST",
1206
1271
  body,
1207
- headers: { "Content-Type": "application/json", ...config2?.headers }
1272
+ headers: { "Content-Type": "application/json", ...config3?.headers }
1208
1273
  });
1209
1274
  }
1210
- async function put(url, data, config2) {
1275
+ async function put(url, data, config3) {
1211
1276
  if (cfg2.axiosInstance && typeof cfg2.axiosInstance.put === "function") {
1212
- return cfg2.axiosInstance.put(url, data, config2);
1277
+ return cfg2.axiosInstance.put(url, data, config3);
1213
1278
  }
1214
1279
  const body = typeof data === "string" ? data : JSON.stringify(data);
1215
1280
  return fetchWithRecord(url, {
1216
1281
  method: "PUT",
1217
1282
  body,
1218
- headers: { "Content-Type": "application/json", ...config2?.headers }
1283
+ headers: { "Content-Type": "application/json", ...config3?.headers }
1219
1284
  });
1220
1285
  }
1221
- async function patch(url, data, config2) {
1286
+ async function patch(url, data, config3) {
1222
1287
  if (cfg2.axiosInstance && typeof cfg2.axiosInstance.patch === "function") {
1223
- return cfg2.axiosInstance.patch(url, data, config2);
1288
+ return cfg2.axiosInstance.patch(url, data, config3);
1224
1289
  }
1225
1290
  const body = typeof data === "string" ? data : JSON.stringify(data);
1226
1291
  return fetchWithRecord(url, {
1227
1292
  method: "PATCH",
1228
1293
  body,
1229
- headers: { "Content-Type": "application/json", ...config2?.headers }
1294
+ headers: { "Content-Type": "application/json", ...config3?.headers }
1230
1295
  });
1231
1296
  }
1232
- async function del(url, config2) {
1297
+ async function del(url, config3) {
1233
1298
  if (cfg2.axiosInstance && typeof cfg2.axiosInstance.delete === "function") {
1234
- return cfg2.axiosInstance.delete(url, config2);
1299
+ return cfg2.axiosInstance.delete(url, config3);
1235
1300
  }
1236
- return fetchWithRecord(url, { method: "DELETE", headers: config2?.headers });
1301
+ return fetchWithRecord(url, { method: "DELETE", headers: config3?.headers });
1237
1302
  }
1238
1303
  var ReqwiseClient = {
1239
1304
  init: initClient,
@@ -1274,7 +1339,8 @@ var styles = `
1274
1339
  position: fixed;
1275
1340
  right: 0;
1276
1341
  top: 0;
1277
- height: auto;
1342
+ bottom: 0;
1343
+ height: 100vh;
1278
1344
  width: var(--rq-width);
1279
1345
  min-width: var(--rq-min-width);
1280
1346
  max-width: 800px;
@@ -1287,7 +1353,6 @@ var styles = `
1287
1353
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', sans-serif;
1288
1354
  font-size: 14px;
1289
1355
  line-height: 1.5;
1290
- overflow: visible;
1291
1356
  transition: transform var(--rq-duration) ease;
1292
1357
  }
1293
1358
 
@@ -1396,6 +1461,7 @@ var styles = `
1396
1461
  display: flex;
1397
1462
  gap: 32px;
1398
1463
  padding: 0 24px;
1464
+ margin-bottom: 16px;
1399
1465
  border-bottom: 1px solid var(--rq-border);
1400
1466
  flex-shrink: 0;
1401
1467
  background: var(--rq-bg);
@@ -1425,11 +1491,12 @@ var styles = `
1425
1491
 
1426
1492
  /* Body/Content */
1427
1493
  #reqwise-panel .rq-body {
1428
- overflow-y: auto;
1429
- overflow-x: hidden;
1430
- padding: 24px;
1494
+ display: flex;
1495
+ flex-direction: column;
1496
+ overflow: hidden;
1497
+ padding: 0;
1431
1498
  flex: 1 1 auto;
1432
- scroll-behavior: smooth;
1499
+ min-height: 0;
1433
1500
  }
1434
1501
 
1435
1502
  #reqwise-panel .rq-body::-webkit-scrollbar {
@@ -1608,6 +1675,37 @@ var styles = `
1608
1675
  color: var(--rq-fg);
1609
1676
  }
1610
1677
 
1678
+ /* Expandable JSON - collapsed by default */
1679
+ .rq-json-expandable {
1680
+ transition: max-height var(--rq-duration) ease;
1681
+ overflow: hidden;
1682
+ }
1683
+
1684
+ .rq-json-expandable.rq-json-collapsed {
1685
+ max-height: 140px;
1686
+ position: relative;
1687
+ overflow-y: hidden;
1688
+ }
1689
+
1690
+ .rq-json-expandable.rq-json-collapsed::after {
1691
+ content: '';
1692
+ position: absolute;
1693
+ bottom: 0;
1694
+ left: 0;
1695
+ right: 0;
1696
+ height: 40px;
1697
+ background: linear-gradient(transparent, var(--rq-bg-secondary));
1698
+ pointer-events: none;
1699
+ }
1700
+
1701
+ .rq-json-expandable:not(.rq-json-collapsed) {
1702
+ max-height: none;
1703
+ }
1704
+
1705
+ .rq-json-expandable:not(.rq-json-collapsed)::after {
1706
+ display: none;
1707
+ }
1708
+
1611
1709
  .rq-json-key {
1612
1710
  color: #0ea5e9;
1613
1711
  }
@@ -1770,6 +1868,25 @@ var styles = `
1770
1868
  opacity: 0.9;
1771
1869
  }
1772
1870
 
1871
+ /* Expand/collapse toggle */
1872
+ .rq-expand-toggle {
1873
+ padding: 4px 8px;
1874
+ font-size: 11px;
1875
+ background: var(--rq-bg-secondary);
1876
+ border: 1px solid var(--rq-border);
1877
+ border-radius: 3px;
1878
+ color: var(--rq-fg);
1879
+ cursor: pointer;
1880
+ font-weight: 500;
1881
+ transition: all var(--rq-duration) ease;
1882
+ white-space: nowrap;
1883
+ }
1884
+
1885
+ .rq-expand-toggle:hover {
1886
+ border-color: var(--rq-fg-secondary);
1887
+ background: rgba(255, 255, 255, 0.08);
1888
+ }
1889
+
1773
1890
  /* Placements */
1774
1891
  #reqwise-panel.placement-left {
1775
1892
  left: 0;
@@ -1842,63 +1959,84 @@ var styles = `
1842
1959
  display: inline-flex !important;
1843
1960
  }
1844
1961
 
1845
- .rq-toggle:hover { transform: scale(1.03); }
1846
-
1847
1962
  .rq-toggle img { width: 20px; height: 20px; object-fit: contain; filter: drop-shadow(0 2px 4px rgba(0,0,0,0.08)); }
1848
1963
 
1849
- /* Placement-specific toggle positioning (relative to panel so it moves with it) */
1850
- #reqwise-panel.placement-right .rq-toggle {
1964
+ /* Toggle button positioning (inside panel, at the edge) */
1965
+ .rq-toggle {
1851
1966
  position: absolute;
1852
- left: -40px; /* adjacent to panel, to the left */
1853
1967
  top: 50%;
1854
1968
  transform: translateY(-50%);
1969
+ z-index: calc(var(--rq-z) + 1);
1970
+ }
1971
+
1972
+ #reqwise-panel.placement-right .rq-toggle {
1973
+ left: -40px;
1855
1974
  border-radius: 6px 0 0 6px;
1856
- writing-mode: vertical-rl; /* vertical text, reading from right side */
1975
+ writing-mode: vertical-rl;
1857
1976
  width: 40px;
1858
1977
  }
1859
1978
 
1860
1979
  #reqwise-panel.placement-left .rq-toggle {
1861
- position: absolute;
1862
- right: -40px; /* adjacent to panel, to the right (panel on left) */
1863
- top: 50%;
1864
- transform: translateY(-50%);
1980
+ right: -40px;
1865
1981
  border-radius: 0 6px 6px 0;
1866
- writing-mode: vertical-rl; /* match right placement so text faces inward */
1982
+ writing-mode: vertical-rl;
1867
1983
  width: 40px;
1868
1984
  }
1869
1985
 
1870
- /* Rotate logo when toggle is vertical so it faces toward the page (opposite of panel) */
1871
1986
  #reqwise-panel.placement-right .rq-toggle img { transform: rotate(90deg); }
1872
1987
  #reqwise-panel.placement-left .rq-toggle img { transform: rotate(-90deg); }
1873
1988
 
1874
1989
  #reqwise-panel.placement-top .rq-toggle {
1875
- position: absolute;
1876
- bottom: -40px; /* place toggle below the top panel (under it) */
1990
+ top: 100%;
1877
1991
  left: 50%;
1878
1992
  transform: translateX(-50%);
1879
- writing-mode: horizontal-tb;
1880
1993
  border-radius: 0 0 6px 6px;
1994
+ writing-mode: horizontal-tb;
1881
1995
  width: auto;
1882
1996
  min-width: 140px;
1883
- padding: 8px 16px;
1997
+ padding: 8px 12px;
1998
+ }
1999
+
2000
+ #reqwise-panel.placement-top[data-size="full"] .rq-toggle {
2001
+ top: auto;
2002
+ bottom: 0;
2003
+ }
2004
+
2005
+ #reqwise-panel.placement-top.rq-closed[data-size="full"] .rq-toggle {
2006
+ top: 100%;
2007
+ bottom: auto;
1884
2008
  }
1885
2009
 
1886
2010
  #reqwise-panel.placement-bottom .rq-toggle {
1887
- position: absolute;
1888
- top: -40px; /* place toggle above the bottom panel (on top of it) */
2011
+ bottom: 100%;
2012
+ top: auto;
1889
2013
  left: 50%;
1890
2014
  transform: translateX(-50%);
1891
- writing-mode: horizontal-tb;
1892
2015
  border-radius: 6px 6px 0 0;
2016
+ writing-mode: horizontal-tb;
1893
2017
  width: auto;
1894
2018
  min-width: 140px;
1895
- padding: 8px 16px;
2019
+ padding: 8px 12px;
2020
+ }
2021
+
2022
+ #reqwise-panel.placement-bottom[data-size="full"] .rq-toggle {
2023
+ bottom: auto;
2024
+ top: 0;
2025
+ }
2026
+
2027
+ #reqwise-panel.placement-bottom.rq-closed[data-size="full"] .rq-toggle {
2028
+ bottom: 100%;
2029
+ top: auto;
1896
2030
  }
1897
2031
 
1898
2032
  .rq-toggle span { white-space: nowrap; }
1899
2033
 
1900
2034
  /* Scale wrapper: transforms content inside aside without affecting panel slide transform */
1901
2035
  .rq-scale-wrapper {
2036
+ display: flex;
2037
+ flex-direction: column;
2038
+ min-height: 0;
2039
+ flex: 1;
1902
2040
  transform-origin: center center;
1903
2041
  transition: transform var(--rq-duration) ease;
1904
2042
  }
@@ -1908,12 +2046,27 @@ var styles = `
1908
2046
  .rq-zoom-btn { background: transparent; border: 1px solid var(--rq-border); color: var(--rq-fg); padding: 6px 8px; border-radius: 6px; cursor: pointer; font-weight: 700 }
1909
2047
  .rq-zoom-btn:hover { background: rgba(255,255,255,0.02) }
1910
2048
 
1911
- /* Panel closed states: slide fully off-screen toward its placement */
2049
+ /* Panel closed states: button stays at screen edge */
1912
2050
  #reqwise-panel.placement-right.rq-closed { transform: translateX(100%); }
1913
2051
  #reqwise-panel.placement-left.rq-closed { transform: translateX(-100%); }
1914
2052
  #reqwise-panel.placement-top.rq-closed { transform: translateY(-100%); }
1915
2053
  #reqwise-panel.placement-bottom.rq-closed { transform: translateY(100%); }
1916
2054
 
2055
+ /* Size variants: sm, md, lg, full */
2056
+ #reqwise-panel[data-size="sm"] { width: 320px; }
2057
+ #reqwise-panel[data-size="md"] { width: 420px; }
2058
+ #reqwise-panel[data-size="lg"] { width: 560px; }
2059
+ #reqwise-panel[data-size="full"] { width: 100vw; max-width: 100vw; }
2060
+
2061
+ #reqwise-panel.placement-top[data-size="sm"],
2062
+ #reqwise-panel.placement-bottom[data-size="sm"] { width: 100vw; height: 30vh; }
2063
+ #reqwise-panel.placement-top[data-size="md"],
2064
+ #reqwise-panel.placement-bottom[data-size="md"] { width: 100vw; height: 40vh; }
2065
+ #reqwise-panel.placement-top[data-size="lg"],
2066
+ #reqwise-panel.placement-bottom[data-size="lg"] { width: 100vw; height: 55vh; }
2067
+ #reqwise-panel.placement-top[data-size="full"],
2068
+ #reqwise-panel.placement-bottom[data-size="full"] { width: 100vw; height: 100vh; }
2069
+
1917
2070
  /* Corner handles for resize cursor (invisible) */
1918
2071
  .rq-corner-handle {
1919
2072
  position: absolute;
@@ -1927,6 +2080,17 @@ var styles = `
1927
2080
  .rq-corner-bottom-left { left: -8px; bottom: -8px; cursor: nesw-resize; }
1928
2081
  .rq-corner-bottom-right { right: -8px; bottom: -8px; cursor: nwse-resize; }
1929
2082
 
2083
+ /* Highlight variants: error and slow */
2084
+ .rq-card.rq-highlight-error {
2085
+ border-left: 4px solid #ef4444;
2086
+ background: rgba(239, 68, 68, 0.04);
2087
+ }
2088
+
2089
+ .rq-card.rq-highlight-slow {
2090
+ border-left: 4px solid #f97316;
2091
+ background: rgba(249, 115, 22, 0.04);
2092
+ }
2093
+
1930
2094
  /* Responsive */
1931
2095
  @media (max-width: 768px) {
1932
2096
  :root {
@@ -1974,6 +2138,175 @@ var styles = `
1974
2138
  scroll-behavior: auto !important;
1975
2139
  }
1976
2140
  }
2141
+
2142
+ /* Highlight styles for error and slow requests */
2143
+ #reqwise-panel .rq-card.rq-error {
2144
+ border: 2px solid var(--rq-error) !important;
2145
+ background: rgba(239, 68, 68, 0.03);
2146
+ }
2147
+
2148
+ #reqwise-panel .rq-card.rq-slow {
2149
+ border: 2px solid var(--rq-warning) !important;
2150
+ background: rgba(249, 115, 22, 0.03);
2151
+ }
2152
+
2153
+ /* Font sizing consistency */
2154
+ #reqwise-panel {
2155
+ font-size: 14px;
2156
+ }
2157
+
2158
+ #reqwise-panel .rq-card-title {
2159
+ font-size: 14px;
2160
+ font-weight: 600;
2161
+ margin: 0;
2162
+ white-space: nowrap;
2163
+ overflow: hidden;
2164
+ text-overflow: ellipsis;
2165
+ }
2166
+
2167
+ #reqwise-panel .rq-card-header {
2168
+ display: flex;
2169
+ align-items: center;
2170
+ gap: 8px;
2171
+ flex-wrap: wrap;
2172
+ }
2173
+
2174
+ #reqwise-panel .rq-meta-item {
2175
+ display: flex;
2176
+ flex-direction: column;
2177
+ gap: 4px;
2178
+ font-size: 13px;
2179
+ }
2180
+
2181
+ #reqwise-panel .rq-meta-label {
2182
+ font-size: 12px;
2183
+ font-weight: 600;
2184
+ color: var(--rq-fg-secondary);
2185
+ }
2186
+
2187
+ #reqwise-panel .rq-meta-code {
2188
+ font-size: 12px;
2189
+ font-family: 'Monaco', 'Courier New', monospace;
2190
+ word-break: break-all;
2191
+ }
2192
+
2193
+ /* Main content container */
2194
+ #reqwise-panel .rq-main {
2195
+ min-height: 0;
2196
+ flex: 1;
2197
+ overflow-y: auto;
2198
+ overflow-x: hidden;
2199
+ padding: 24px;
2200
+ scroll-behavior: smooth;
2201
+ }
2202
+
2203
+ #reqwise-panel .rq-main::-webkit-scrollbar {
2204
+ width: 8px;
2205
+ }
2206
+
2207
+ #reqwise-panel .rq-main::-webkit-scrollbar-track {
2208
+ background: transparent;
2209
+ }
2210
+
2211
+ #reqwise-panel .rq-main::-webkit-scrollbar-thumb {
2212
+ background: var(--rq-border);
2213
+ border-radius: 4px;
2214
+ }
2215
+
2216
+ #reqwise-panel .rq-main::-webkit-scrollbar-thumb:hover {
2217
+ background: var(--rq-fg-secondary);
2218
+ }
2219
+
2220
+ /* Scroll in lists */
2221
+ #reqwise-panel .rq-list {
2222
+ overflow-y: auto;
2223
+ overflow-x: hidden;
2224
+ }
2225
+
2226
+ #reqwise-panel .rq-list::-webkit-scrollbar {
2227
+ width: 8px;
2228
+ }
2229
+
2230
+ #reqwise-panel .rq-list::-webkit-scrollbar-track {
2231
+ background: transparent;
2232
+ }
2233
+
2234
+ #reqwise-panel .rq-list::-webkit-scrollbar-thumb {
2235
+ background: var(--rq-border);
2236
+ border-radius: 4px;
2237
+ }
2238
+
2239
+ #reqwise-panel .rq-list::-webkit-scrollbar-thumb:hover {
2240
+ background: var(--rq-fg-secondary);
2241
+ }
2242
+
2243
+ /* Zoom buttons fix */
2244
+ #reqwise-panel .rq-zoom-btn {
2245
+ min-width: 32px;
2246
+ height: 32px;
2247
+ padding: 6px;
2248
+ display: flex;
2249
+ align-items: center;
2250
+ justify-content: center;
2251
+ background: var(--rq-bg-secondary);
2252
+ border: 1px solid var(--rq-border);
2253
+ color: var(--rq-fg);
2254
+ border-radius: 6px;
2255
+ cursor: pointer;
2256
+ font-weight: 700;
2257
+ font-size: 14px;
2258
+ transition: background 150ms ease;
2259
+ }
2260
+
2261
+ #reqwise-panel .rq-zoom-btn:hover {
2262
+ background: rgba(255, 255, 255, 0.08);
2263
+ }
2264
+
2265
+ #reqwise-panel .rq-zoom-btn:active {
2266
+ background: rgba(255, 255, 255, 0.12);
2267
+ }
2268
+
2269
+ /* Group styles */
2270
+ #reqwise-panel .rq-group {
2271
+ margin-bottom: 16px;
2272
+ }
2273
+
2274
+ #reqwise-panel .rq-group-header {
2275
+ padding: 12px 24px;
2276
+ background: var(--rq-bg-secondary);
2277
+ border: 1px solid var(--rq-border);
2278
+ border-radius: 6px;
2279
+ font-weight: 600;
2280
+ font-size: 13px;
2281
+ cursor: pointer;
2282
+ user-select: none;
2283
+ display: flex;
2284
+ align-items: center;
2285
+ justify-content: space-between;
2286
+ gap: 8px;
2287
+ }
2288
+
2289
+ #reqwise-panel .rq-group-header:hover {
2290
+ background: rgba(255, 255, 255, 0.05);
2291
+ }
2292
+
2293
+ #reqwise-panel .rq-group-items {
2294
+ margin-top: 8px;
2295
+ padding-left: 12px;
2296
+ }
2297
+
2298
+ #reqwise-panel .rq-group-items.collapsed {
2299
+ display: none;
2300
+ }
2301
+
2302
+ #reqwise-panel .rq-group-toggle {
2303
+ display: inline-block;
2304
+ transition: transform var(--rq-duration) ease;
2305
+ }
2306
+
2307
+ #reqwise-panel .rq-group-toggle.collapsed {
2308
+ transform: rotate(-90deg);
2309
+ }
1977
2310
  `;
1978
2311
  var styles_default = styles;
1979
2312
 
@@ -2294,15 +2627,30 @@ var panel = /* @__PURE__ */ (() => {
2294
2627
  else if (cfg3.theme === "dark") p.setAttribute("data-theme", "dark");
2295
2628
  else p.removeAttribute("data-theme");
2296
2629
  }
2297
- function mount(config2) {
2630
+ function applySize() {
2631
+ if (!isBrowser()) return;
2632
+ const p = document.getElementById(PANEL_ID);
2633
+ if (!p) return;
2634
+ p.setAttribute("data-size", cfg3.size || "md");
2635
+ }
2636
+ function applyOpacity() {
2637
+ if (!isBrowser()) return;
2638
+ const p = document.getElementById(PANEL_ID);
2639
+ if (!p) return;
2640
+ const opacity = cfg3.opacity ?? 1;
2641
+ p.style.opacity = String(Math.max(0, Math.min(1, opacity)));
2642
+ }
2643
+ function mount(config3) {
2298
2644
  try {
2299
2645
  if (!isBrowser()) return;
2300
2646
  if (mounted) return;
2301
- cfg3 = { defaultOpen: false, placement: "right", hotkey: "ctrl+shift+e", theme: "system", ...config2 || {} };
2647
+ cfg3 = { defaultOpen: false, placement: "right", hotkey: "ctrl+shift+e", theme: "system", size: "md", opacity: 1, ...config3 || {} };
2302
2648
  hotkeyParts = parseHotkey(cfg3.hotkey);
2303
2649
  injectStyles();
2304
2650
  createPanelElement();
2305
2651
  applyTheme();
2652
+ applySize();
2653
+ applyOpacity();
2306
2654
  createToggle();
2307
2655
  try {
2308
2656
  const p = document.getElementById(PANEL_ID);
@@ -2339,22 +2687,11 @@ var panel = /* @__PURE__ */ (() => {
2339
2687
  function setOpenState(next) {
2340
2688
  try {
2341
2689
  const p = document.getElementById(PANEL_ID);
2342
- const t2 = document.getElementById(TOGGLE_ID);
2343
2690
  open = !!next;
2344
2691
  if (p) {
2345
2692
  p.classList.toggle("rq-closed", !open);
2346
2693
  p.setAttribute("aria-hidden", String(!open));
2347
2694
  }
2348
- if (open && renderer2 && p) {
2349
- const body = p.querySelector(".rq-body");
2350
- if (body) {
2351
- try {
2352
- renderer2(body);
2353
- } catch (e) {
2354
- console.error("[reqwise] renderer error", e);
2355
- }
2356
- }
2357
- }
2358
2695
  } catch (e) {
2359
2696
  console.error("[reqwise] setOpenState error", e);
2360
2697
  }
@@ -2416,6 +2753,10 @@ var panel_default = panel;
2416
2753
  // src/renderer.ts
2417
2754
  init_storage();
2418
2755
  var ENDPOINTS_KEY = "reqwise_endpoints_v1";
2756
+ var config2 = { show: "general" };
2757
+ function setConfig2(cfg3) {
2758
+ config2 = { ...config2, ...cfg3 };
2759
+ }
2419
2760
  function safeParseJSON(s) {
2420
2761
  try {
2421
2762
  return s ? JSON.parse(s) : null;
@@ -2448,10 +2789,10 @@ function inferType(val) {
2448
2789
  function updateEndpointsFromEntry(entry) {
2449
2790
  try {
2450
2791
  if (!entry || !entry.url) return;
2451
- const { pathname, search } = normalizePath(entry.url);
2792
+ const { pathname, search, origin } = normalizePath(entry.url);
2452
2793
  const endpoints = loadEndpoints();
2453
2794
  const key = pathname;
2454
- if (!endpoints[key]) endpoints[key] = { path: key, methods: {}, params: {}, examples: [], count: 0, lastSeen: 0 };
2795
+ if (!endpoints[key]) endpoints[key] = { path: pathname, fullPath: entry.url.split("?")[0], origin, methods: {}, params: {}, examples: [], count: 0, lastSeen: 0 };
2455
2796
  const meta = endpoints[key];
2456
2797
  meta.count = (meta.count || 0) + 1;
2457
2798
  meta.lastSeen = Date.now();
@@ -2523,6 +2864,63 @@ function renderCurrent(container) {
2523
2864
  }
2524
2865
  const html = entries.map((e) => formatCard(e)).join("");
2525
2866
  main.innerHTML = html;
2867
+ const sendBtns = main.querySelectorAll(".rq-send-btn");
2868
+ sendBtns.forEach((btn) => {
2869
+ btn.addEventListener("click", () => {
2870
+ const method = btn.getAttribute("data-method") || "GET";
2871
+ const url = btn.getAttribute("data-url") || "";
2872
+ const bodyStr = btn.getAttribute("data-body") || "{}";
2873
+ let body = {};
2874
+ try {
2875
+ body = JSON.parse(bodyStr);
2876
+ } catch (e) {
2877
+ }
2878
+ const panel2 = document.getElementById("reqwise-panel");
2879
+ if (!panel2) return;
2880
+ const sendTab = panel2.querySelector('[data-tabname="send"]');
2881
+ if (sendTab) sendTab.click();
2882
+ setTimeout(() => {
2883
+ const form = main.querySelector(".rq-form");
2884
+ if (!form) return;
2885
+ const methodSelect = form.querySelector('[name="method"]');
2886
+ const urlInput = form.querySelector('[name="url"]');
2887
+ const bodyInput = form.querySelector('[name="body"]');
2888
+ if (methodSelect) methodSelect.value = method;
2889
+ if (urlInput) {
2890
+ urlInput.value = url;
2891
+ urlInput.focus();
2892
+ }
2893
+ if (bodyInput && Object.keys(body).length > 0) {
2894
+ bodyInput.value = JSON.stringify(body, null, 2);
2895
+ }
2896
+ }, 50);
2897
+ });
2898
+ });
2899
+ const expandToggles = main.querySelectorAll(".rq-expand-toggle");
2900
+ expandToggles.forEach((btn) => {
2901
+ btn.addEventListener("click", () => {
2902
+ const entryId = btn.getAttribute("data-entry-id");
2903
+ if (!entryId) return;
2904
+ const expandables = main.querySelectorAll(`.rq-json-expandable[data-entry-id="${entryId}"]`);
2905
+ const allExpanded = Array.from(expandables).every((el) => !el.classList.contains("rq-json-collapsed"));
2906
+ expandables.forEach((el) => {
2907
+ if (allExpanded) {
2908
+ el.classList.add("rq-json-collapsed");
2909
+ } else {
2910
+ el.classList.remove("rq-json-collapsed");
2911
+ }
2912
+ });
2913
+ btn.textContent = allExpanded ? "Show more \u25BC" : "Show less \u25B2";
2914
+ });
2915
+ });
2916
+ }
2917
+ function countJSONLines(obj) {
2918
+ try {
2919
+ const json = typeof obj === "string" ? obj : JSON.stringify(obj, null, 2);
2920
+ return json.split("\n").length;
2921
+ } catch (e) {
2922
+ return 0;
2923
+ }
2526
2924
  }
2527
2925
  function formatCard(e) {
2528
2926
  const statusBadge = getStatusBadge(e.status);
@@ -2530,6 +2928,34 @@ function formatCard(e) {
2530
2928
  const errorClass = e.error ? "error" : "";
2531
2929
  const duration = e.duration ? `${e.duration}ms` : "\u2014";
2532
2930
  const statusText = e.statusText ? e.statusText : "";
2931
+ const entryId = e.id || "";
2932
+ const requestLines = e.requestBody ? countJSONLines(e.requestBody) : 0;
2933
+ const responseLines = e.responseBody ? countJSONLines(e.responseBody) : 0;
2934
+ const hasLargeContent = requestLines > 10 || responseLines > 10;
2935
+ if (config2.show === "general") {
2936
+ return `
2937
+ <div class="rq-card">
2938
+ <div class="rq-card-header">
2939
+ <h3 class="rq-card-title">${e.method || "GET"} ${extractPath(e.url)}</h3>
2940
+ ${e.source === "manual" ? '<span class="rq-badge">' + i18n_default.t("manual_badge") + "</span>" : ""}
2941
+ ${statusBadge}
2942
+ </div>
2943
+ <div class="rq-meta">
2944
+ <div class="rq-meta-item">
2945
+ <span class="rq-meta-label">${i18n_default.t("duration")}:</span>
2946
+ <code class="rq-meta-code">${duration}</code>
2947
+ </div>
2948
+ <div class="rq-meta-item">
2949
+ <span class="rq-meta-label">${i18n_default.t("time")}:</span>
2950
+ <code class="rq-meta-code">${new Date(e.timestamp).toLocaleTimeString()}</code>
2951
+ </div>
2952
+ </div>
2953
+ <div style="margin-top: 12px; display: flex; gap: 8px;">
2954
+ <button class="rq-btn primary rq-send-btn" data-entry-id="${entryId}" data-method="${escapeHtml(e.method || "GET")}" data-url="${escapeHtml(e.url)}" data-body="${escapeHtml(JSON.stringify(e.requestBody || {}))}" style="font-size: 12px; padding: 6px 12px; flex: 1;">\u2192 ${i18n_default.t("send_request")}</button>
2955
+ </div>
2956
+ </div>
2957
+ `;
2958
+ }
2533
2959
  return `
2534
2960
  <div class="rq-card">
2535
2961
  <div class="rq-card-header">
@@ -2537,7 +2963,7 @@ function formatCard(e) {
2537
2963
  ${e.source === "manual" ? '<span class="rq-badge">' + i18n_default.t("manual_badge") + "</span>" : ""}
2538
2964
  ${statusBadge}
2539
2965
  </div>
2540
-
2966
+
2541
2967
  <div class="rq-meta">
2542
2968
  <div class="rq-meta-item">
2543
2969
  <span class="rq-meta-label">${i18n_default.t("form_url")}:</span>
@@ -2561,8 +2987,11 @@ function formatCard(e) {
2561
2987
 
2562
2988
  ${e.requestBody && ["POST", "PUT", "PATCH"].includes(e.method || "") ? `
2563
2989
  <div class="rq-section">
2564
- <div class="rq-section-label">${i18n_default.t("request")} ${i18n_default.t("body")}</div>
2565
- <div class="rq-json">${highlightJSON(e.requestBody)}</div>
2990
+ <div class="rq-section-label">
2991
+ ${i18n_default.t("request")} ${i18n_default.t("body")}
2992
+ ${requestLines > 10 ? `<button class="rq-expand-toggle" data-entry-id="${entryId}" style="margin-left: 8px;">Show more \u25BC</button>` : ""}
2993
+ </div>
2994
+ <div class="rq-json ${requestLines > 10 ? "rq-json-expandable rq-json-collapsed" : ""}" data-entry-id="${entryId}" data-section="request">${highlightJSON(e.requestBody)}</div>
2566
2995
  </div>
2567
2996
  ` : ""}
2568
2997
 
@@ -2578,10 +3007,17 @@ function formatCard(e) {
2578
3007
 
2579
3008
  ${e.responseBody !== void 0 ? `
2580
3009
  <div class="rq-section">
2581
- <div class="rq-section-label">${i18n_default.t("response_label")}</div>
2582
- <div class="rq-json">${highlightJSON(e.responseBody)}</div>
3010
+ <div class="rq-section-label">
3011
+ ${i18n_default.t("response_label")}
3012
+ ${responseLines > 10 ? `<button class="rq-expand-toggle" data-entry-id="${entryId}" style="margin-left: 8px;">Show more \u25BC</button>` : ""}
3013
+ </div>
3014
+ <div class="rq-json ${responseLines > 10 ? "rq-json-expandable rq-json-collapsed" : ""}" data-entry-id="${entryId}" data-section="response">${highlightJSON(e.responseBody)}</div>
2583
3015
  </div>
2584
3016
  ` : ""}
3017
+
3018
+ <div style="margin-top: 12px; display: flex; gap: 8px;">
3019
+ <button class="rq-btn primary rq-send-btn" data-entry-id="${entryId}" data-method="${escapeHtml(e.method || "GET")}" data-url="${escapeHtml(e.url)}" data-body="${escapeHtml(JSON.stringify(e.requestBody || {}))}" style="font-size: 12px; padding: 6px 12px; flex: 1;">\u2192 ${i18n_default.t("send_request")}</button>
3020
+ </div>
2585
3021
  </div>
2586
3022
  `;
2587
3023
  }
@@ -2663,8 +3099,24 @@ function renderHistory(container) {
2663
3099
  return;
2664
3100
  }
2665
3101
  main.innerHTML = `
2666
- <div class="rq-section" style="margin-bottom: 16px;">
2667
- <input type="text" class="rq-filter rq-form-input" placeholder="${i18n_default.t("filter_placeholder")}" style="width: 100%;" />
3102
+ <div class="rq-section" style="margin-bottom: 16px; display: flex; gap: 8px; flex-wrap: wrap; align-items: center;">
3103
+ <input type="text" class="rq-filter-text rq-form-input" placeholder="${i18n_default.t("filter_placeholder")}" style="flex: 1; min-width: 150px;" />
3104
+ <select class="rq-filter-method rq-form-select" style="min-width: 100px;">
3105
+ <option value="">${i18n_default.t("all_methods")}</option>
3106
+ <option value="GET">GET</option>
3107
+ <option value="POST">POST</option>
3108
+ <option value="PUT">PUT</option>
3109
+ <option value="PATCH">PATCH</option>
3110
+ <option value="DELETE">DELETE</option>
3111
+ </select>
3112
+ <select class="rq-filter-status rq-form-select" style="min-width: 100px;">
3113
+ <option value="">${i18n_default.t("all_statuses")}</option>
3114
+ <option value="2xx">2xx ${i18n_default.t("status_success")}</option>
3115
+ <option value="4xx">4xx ${i18n_default.t("status_client_error")}</option>
3116
+ <option value="5xx">5xx ${i18n_default.t("status_server_error")}</option>
3117
+ <option value="error">${i18n_default.t("error_label")}</option>
3118
+ </select>
3119
+ <button class="rq-filter-clear rq-btn" style="padding: 8px 12px; font-size: 12px;">${i18n_default.t("clear_form")}</button>
2668
3120
  </div>
2669
3121
  <div class="rq-list"></div>
2670
3122
  `;
@@ -2674,15 +3126,111 @@ function renderHistory(container) {
2674
3126
  list.innerHTML = `<div class="rq-empty" style="min-height: 200px;"><p>${i18n_default.t("no_matching_requests")}</p></div>`;
2675
3127
  return;
2676
3128
  }
2677
- list.innerHTML = items.map((e) => formatHistoryCard(e)).join("");
2678
- }
2679
- const filter = main.querySelector(".rq-filter");
2680
- filter.addEventListener("input", () => {
2681
- const q = filter.value.toLowerCase();
2682
- const filtered = entries.filter(
2683
- (e) => (e.method || "").toLowerCase().includes(q) || (e.status || "").toString().includes(q) || (e.url || "").toLowerCase().includes(q) || (e.page || "").toLowerCase().includes(q)
2684
- );
3129
+ let html = "";
3130
+ if (config2.groupBy && (config2.groupBy === "url" || config2.groupBy === "method" || config2.groupBy === "status" || config2.groupBy === "page")) {
3131
+ const groups = {};
3132
+ for (const item of items) {
3133
+ let key = "";
3134
+ if (config2.groupBy === "url") key = item.url || "unknown";
3135
+ else if (config2.groupBy === "method") key = item.method || "GET";
3136
+ else if (config2.groupBy === "status") key = item.status ? item.status >= 400 ? "Error" : "Success" : "Pending";
3137
+ else if (config2.groupBy === "page") key = item.page || "unknown";
3138
+ if (!groups[key]) groups[key] = [];
3139
+ groups[key].push(item);
3140
+ }
3141
+ for (const [key, groupItems] of Object.entries(groups)) {
3142
+ const count = groupItems.length;
3143
+ const groupId = `group-${key.replace(/[^a-z0-9]/gi, "-")}`;
3144
+ html += `
3145
+ <div class="rq-group">
3146
+ <div class="rq-group-header" data-group-id="${groupId}">
3147
+ <span class="rq-group-toggle">\u25BC</span>
3148
+ <span style="flex: 1; text-align: left;">${escapeHtml(key)} (${count})</span>
3149
+ </div>
3150
+ <div class="rq-group-items" data-group-id="${groupId}">
3151
+ ${groupItems.map((e) => formatHistoryCard(e)).join("")}
3152
+ </div>
3153
+ </div>
3154
+ `;
3155
+ }
3156
+ } else {
3157
+ html = items.map((e) => formatHistoryCard(e)).join("");
3158
+ }
3159
+ list.innerHTML = html;
3160
+ if (config2.groupBy) {
3161
+ const headers = list.querySelectorAll(".rq-group-header");
3162
+ headers.forEach((header) => {
3163
+ header.addEventListener("click", () => {
3164
+ const groupId = header.getAttribute("data-group-id");
3165
+ const items2 = list.querySelector(`.rq-group-items[data-group-id="${groupId}"]`);
3166
+ const toggle = header.querySelector(".rq-group-toggle");
3167
+ if (items2 && toggle) {
3168
+ items2.classList.toggle("collapsed");
3169
+ toggle.classList.toggle("collapsed");
3170
+ }
3171
+ });
3172
+ });
3173
+ }
3174
+ const sendBtns = list.querySelectorAll(".rq-send-btn");
3175
+ sendBtns.forEach((btn) => {
3176
+ btn.addEventListener("click", () => {
3177
+ const method = btn.getAttribute("data-method") || "GET";
3178
+ const url = btn.getAttribute("data-url") || "";
3179
+ const bodyStr = btn.getAttribute("data-body") || "{}";
3180
+ let body = {};
3181
+ try {
3182
+ body = JSON.parse(bodyStr);
3183
+ } catch (e) {
3184
+ }
3185
+ const panel2 = document.getElementById("reqwise-panel");
3186
+ if (!panel2) return;
3187
+ const sendTab = panel2.querySelector('[data-tabname="send"]');
3188
+ if (sendTab) sendTab.click();
3189
+ setTimeout(() => {
3190
+ const form = main.querySelector(".rq-form");
3191
+ if (!form) return;
3192
+ const methodSelect = form.querySelector('[name="method"]');
3193
+ const urlInput = form.querySelector('[name="url"]');
3194
+ const bodyInput = form.querySelector('[name="body"]');
3195
+ if (methodSelect) methodSelect.value = method;
3196
+ if (urlInput) {
3197
+ urlInput.value = url;
3198
+ urlInput.focus();
3199
+ }
3200
+ if (bodyInput && Object.keys(body).length > 0) {
3201
+ bodyInput.value = JSON.stringify(body, null, 2);
3202
+ }
3203
+ }, 50);
3204
+ });
3205
+ });
3206
+ }
3207
+ function applyFilters() {
3208
+ const searchQ = main.querySelector(".rq-filter-text").value.toLowerCase();
3209
+ const methodF = main.querySelector(".rq-filter-method").value;
3210
+ const statusF = main.querySelector(".rq-filter-status").value;
3211
+ const filtered = entries.filter((e) => {
3212
+ if (searchQ && !((e.method || "").toLowerCase().includes(searchQ) || (e.status || "").toString().includes(searchQ) || (e.url || "").toLowerCase().includes(searchQ) || (e.page || "").toLowerCase().includes(searchQ))) return false;
3213
+ if (methodF && (e.method || "GET").toUpperCase() !== methodF.toUpperCase()) return false;
3214
+ if (statusF === "error" && !e.error) return false;
3215
+ if (statusF === "2xx" && (!e.status || e.status < 200 || e.status >= 300)) return false;
3216
+ if (statusF === "4xx" && (!e.status || e.status < 400 || e.status >= 500)) return false;
3217
+ if (statusF === "5xx" && (!e.status || e.status < 500)) return false;
3218
+ return true;
3219
+ });
2685
3220
  renderList(filtered);
3221
+ }
3222
+ const filterText = main.querySelector(".rq-filter-text");
3223
+ const filterMethod = main.querySelector(".rq-filter-method");
3224
+ const filterStatus = main.querySelector(".rq-filter-status");
3225
+ const filterClear = main.querySelector(".rq-filter-clear");
3226
+ filterText.addEventListener("input", applyFilters);
3227
+ filterMethod.addEventListener("change", applyFilters);
3228
+ filterStatus.addEventListener("change", applyFilters);
3229
+ filterClear.addEventListener("click", () => {
3230
+ filterText.value = "";
3231
+ filterMethod.value = "";
3232
+ filterStatus.value = "";
3233
+ applyFilters();
2686
3234
  });
2687
3235
  renderList(entries);
2688
3236
  }
@@ -2690,14 +3238,21 @@ function formatHistoryCard(e) {
2690
3238
  const statusBadge = getStatusBadge(e.status);
2691
3239
  const duration = e.duration ? `${e.duration}ms` : "\u2014";
2692
3240
  const statusText = e.statusText ? e.statusText : "";
3241
+ const entryId = e.id || "";
3242
+ let highlightClass = "";
3243
+ if (config2.highlight === "error" && e.status && (e.status >= 400 || e.error)) {
3244
+ highlightClass = "rq-error";
3245
+ } else if (config2.highlight === "slow" && e.duration && e.duration > 500) {
3246
+ highlightClass = "rq-slow";
3247
+ }
2693
3248
  return `
2694
- <div class="rq-card" style="border: 1px solid var(--rq-border); border-radius: 8px; padding: 16px; margin-bottom: 12px;">
3249
+ <div class="rq-card ${highlightClass}" style="border: 1px solid var(--rq-border); border-radius: 8px; padding: 16px; margin-bottom: 12px;">
2695
3250
  <div class="rq-card-header">
2696
3251
  <h4 class="rq-card-title">${e.method || "GET"} ${extractPath(e.url)}</h4>
2697
3252
  ${statusBadge}
2698
3253
  ${e.source === "manual" ? '<span class="rq-badge">' + i18n_default.t("manual_badge") + "</span>" : ""}
2699
3254
  </div>
2700
-
3255
+
2701
3256
  <div class="rq-meta" style="gap: 12px; margin-top: 8px;">
2702
3257
  <div class="rq-meta-item">
2703
3258
  <span class="rq-meta-label">${i18n_default.t("endpoint_label")}:</span>
@@ -2714,6 +3269,10 @@ function formatHistoryCard(e) {
2714
3269
  <code class="rq-meta-code">${new Date(e.timestamp).toLocaleTimeString()}</code>
2715
3270
  </div>
2716
3271
  </div>
3272
+
3273
+ <div style="margin-top: 12px; display: flex; gap: 8px;">
3274
+ <button class="rq-btn primary rq-send-btn" data-entry-id="${entryId}" data-method="${escapeHtml(e.method || "GET")}" data-url="${escapeHtml(e.url)}" data-body="${escapeHtml(JSON.stringify(e.requestBody || {}))}" style="font-size: 12px; padding: 6px 12px; flex: 1;">\u2192 ${i18n_default.t("send_request")}</button>
3275
+ </div>
2717
3276
  </div>
2718
3277
  `;
2719
3278
  }
@@ -2856,10 +3415,13 @@ function renderEndpoints(container) {
2856
3415
  `;
2857
3416
  }).join("");
2858
3417
  const examples = (e.examples || []).slice(0, 3).map((ex) => `<code class="rq-meta-code">${escapeHtml(ex)}</code>`).join("<br/>");
3418
+ const methodsArray = Object.keys(e.methods || {});
3419
+ const primaryMethod = methodsArray.length > 0 ? methodsArray[0] : "GET";
3420
+ const fullUrl = e.fullPath || (e.origin ? e.origin + e.path : e.path);
2859
3421
  return `
2860
3422
  <div class="rq-card" style="border: 1px solid var(--rq-border); border-radius: 8px; padding: 16px; margin-bottom: 12px;">
2861
3423
  <div class="rq-card-header">
2862
- <h4 class="rq-card-title">${escapeHtml(e.path)}</h4>
3424
+ <h4 class="rq-card-title" style="word-break: break-all;">${escapeHtml(fullUrl)}</h4>
2863
3425
  <span style="background: var(--rq-bg-secondary); padding: 4px 12px; border-radius: 4px; font-size: 12px; color: var(--rq-fg-secondary);">${e.count || 0} ${i18n_default.t("hits")}</span>
2864
3426
  </div>
2865
3427
 
@@ -2883,10 +3445,36 @@ function renderEndpoints(container) {
2883
3445
  <div style="margin-top: 12px; font-size: 12px; color: var(--rq-fg-secondary);">
2884
3446
  ${i18n_default.t("last_seen")}: ${new Date(e.lastSeen).toLocaleTimeString()}
2885
3447
  </div>
3448
+
3449
+ <div style="margin-top: 12px; display: flex; gap: 8px;">
3450
+ <button class="rq-btn primary rq-endpoint-send-btn" data-method="${escapeHtml(primaryMethod)}" data-url="${escapeHtml(fullUrl)}" style="font-size: 12px; padding: 6px 12px; flex: 1;">\u2192 ${i18n_default.t("send_request")}</button>
3451
+ </div>
2886
3452
  </div>
2887
3453
  `;
2888
3454
  }).join("");
2889
3455
  main.innerHTML = html;
3456
+ const endpointSendBtns = main.querySelectorAll(".rq-endpoint-send-btn");
3457
+ endpointSendBtns.forEach((btn) => {
3458
+ btn.addEventListener("click", () => {
3459
+ const method = btn.getAttribute("data-method") || "GET";
3460
+ const url = btn.getAttribute("data-url") || "/";
3461
+ const panel2 = document.getElementById("reqwise-panel");
3462
+ if (!panel2) return;
3463
+ const sendTab = panel2.querySelector('[data-tabname="send"]');
3464
+ if (sendTab) sendTab.click();
3465
+ setTimeout(() => {
3466
+ const form = main.querySelector(".rq-form");
3467
+ if (!form) return;
3468
+ const methodSelect = form.querySelector('[name="method"]');
3469
+ const urlInput = form.querySelector('[name="url"]');
3470
+ if (methodSelect) methodSelect.value = method;
3471
+ if (urlInput) {
3472
+ urlInput.value = url;
3473
+ urlInput.focus();
3474
+ }
3475
+ }, 50);
3476
+ });
3477
+ });
2890
3478
  }
2891
3479
  function renderer(container) {
2892
3480
  try {
@@ -2933,6 +3521,7 @@ var index_default = _default;
2933
3521
  i18n,
2934
3522
  panel,
2935
3523
  renderer,
3524
+ rendererSetConfig,
2936
3525
  storage
2937
3526
  });
2938
3527
  //# sourceMappingURL=index.js.map