rails-profiler 0.17.0 → 0.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: af1361f732061dbeaa22f808fb18e31d812e570eac67a7dd08687257d1400399
4
- data.tar.gz: 0603edc83c99eb5122896e7aeb07a7cff85e944acfc45a3fc1268eae2b4e69aa
3
+ metadata.gz: a755b6d8e9f74901cac774282d218553d40fe1c59efe7e9a7973e2a6c7cf38ca
4
+ data.tar.gz: 5f157e934571a297d1aa6484312cbc001478b71b776c940179d91f4b04f31d85
5
5
  SHA512:
6
- metadata.gz: 5e615b88c8d7253e24e00b416b1e5b6b858627a629714a6f041c77673fa1be1aee23bc57b999fc5016b101263c5fbc510594d6300994c007ccdef62ddab2fe42
7
- data.tar.gz: 2cbe8336230ebd48a49b706a82d3f898516841b2b93d424a74a4f0aa9d9f23ab917e75ea91aef70a238f3c79db3460d3974765eda260e71efbee1864229b3f30
6
+ metadata.gz: 02b2e42cb2409c7db8a54277323d7c13483b10884ebd041c60aef6b8f874cde66d90cf3d02e0b60d65b526ad8e5d8d58bc52e19c7a60943ddfe65f97b1e655e3
7
+ data.tar.gz: 7c13611e50dc1ada83e5e61f0cbee9f5cf1bf256a16d776012ff59c6a07abe6fff7b3a636f702e1445f44f6750207bbcf0fce25fcc3234d2f5008ad0c7be8f02
@@ -396,6 +396,24 @@
396
396
  return "function" == typeof t3 ? t3(n2) : t3;
397
397
  }
398
398
 
399
+ // app/assets/typescript/profiler/components/dashboard/tabs/shared/utils.ts
400
+ function methodBadge(method) {
401
+ const map = { GET: "info", POST: "success", PUT: "warning", PATCH: "warning", DELETE: "error" };
402
+ return map[method] || "default";
403
+ }
404
+ function statusBadge(status) {
405
+ if (status === 0) return "error";
406
+ if (status >= 200 && status < 300) return "success";
407
+ if (status >= 400) return "error";
408
+ return "warning";
409
+ }
410
+ function formatBytes(bytes) {
411
+ if (bytes < 0) return "\u2014";
412
+ if (bytes < 1024) return `${bytes} B`;
413
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
414
+ return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
415
+ }
416
+
399
417
  // node_modules/preact/jsx-runtime/dist/jsxRuntime.module.js
400
418
  var f3 = 0;
401
419
  function u3(e3, t3, n2, o3, i3, u4) {
@@ -407,21 +425,53 @@
407
425
  return l.vnode && l.vnode(l3), l3;
408
426
  }
409
427
 
410
- // app/assets/typescript/profiler/components/dashboard/tabs/HttpTab.tsx
411
- function methodBadge(method) {
412
- const map = { GET: "info", POST: "success", PUT: "warning", PATCH: "warning", DELETE: "error" };
413
- return map[method] || "default";
428
+ // app/assets/typescript/profiler/components/dashboard/tabs/shared/HttpComponents.tsx
429
+ function CopyButton({ text }) {
430
+ const [copied, setCopied] = d2(false);
431
+ function copy() {
432
+ navigator.clipboard.writeText(text).then(() => {
433
+ setCopied(true);
434
+ setTimeout(() => setCopied(false), 2e3);
435
+ });
436
+ }
437
+ return /* @__PURE__ */ u3("button", { onClick: copy, class: "profiler-body-download-btn profiler-text--xs", style: "cursor:pointer", children: copied ? "Copied!" : "Copy" });
414
438
  }
415
- function statusBadge(status) {
416
- if (status === 0) return "error";
417
- if (status >= 200 && status < 300) return "success";
418
- if (status >= 400) return "error";
419
- return "warning";
439
+ function mimeToExt(mime) {
440
+ const m3 = mime.split(";")[0].trim().toLowerCase();
441
+ const map = {
442
+ "application/json": ".json",
443
+ "application/ld+json": ".jsonld",
444
+ "application/xml": ".xml",
445
+ "text/xml": ".xml",
446
+ "text/csv": ".csv",
447
+ "application/csv": ".csv",
448
+ "text/html": ".html",
449
+ "text/plain": ".txt",
450
+ "text/css": ".css",
451
+ "application/javascript": ".js",
452
+ "text/javascript": ".js",
453
+ "image/svg+xml": ".svg",
454
+ "image/png": ".png",
455
+ "image/jpeg": ".jpg",
456
+ "image/gif": ".gif",
457
+ "image/webp": ".webp",
458
+ "image/avif": ".avif",
459
+ "application/pdf": ".pdf",
460
+ "application/zip": ".zip",
461
+ "application/gzip": ".gz",
462
+ "application/octet-stream": ".bin"
463
+ };
464
+ return map[m3] || ".bin";
420
465
  }
421
- function formatBytes(n2) {
422
- if (n2 === 0) return "0 B";
423
- if (n2 < 1024) return `${n2} B`;
424
- return `${(n2 / 1024).toFixed(1)} KB`;
466
+ function DownloadTextButton({ text, mime }) {
467
+ const [url, setUrl] = d2(null);
468
+ y2(() => {
469
+ const objectUrl = URL.createObjectURL(new Blob([text], { type: mime }));
470
+ setUrl(objectUrl);
471
+ return () => URL.revokeObjectURL(objectUrl);
472
+ }, [text, mime]);
473
+ if (!url) return null;
474
+ return /* @__PURE__ */ u3("a", { href: url, download: `body${mimeToExt(mime)}`, class: "profiler-body-download-btn profiler-text--xs", children: "Download" });
425
475
  }
426
476
  function HeadersTable({ headers }) {
427
477
  const entries = Object.entries(headers);
@@ -494,8 +544,6 @@
494
544
  if (category === "xml") return formatXml(body);
495
545
  return body;
496
546
  }
497
- var PREVIEW_LIMIT = 500;
498
- var CSV_ROW_LIMIT = 10;
499
547
  function categoryMime(category) {
500
548
  const map = {
501
549
  json: "application/json",
@@ -506,53 +554,8 @@
506
554
  };
507
555
  return map[category] || "text/plain";
508
556
  }
509
- function mimeToExt(mime) {
510
- const m3 = mime.split(";")[0].trim().toLowerCase();
511
- const map = {
512
- "application/json": ".json",
513
- "application/ld+json": ".jsonld",
514
- "application/xml": ".xml",
515
- "text/xml": ".xml",
516
- "text/csv": ".csv",
517
- "application/csv": ".csv",
518
- "text/html": ".html",
519
- "text/plain": ".txt",
520
- "text/css": ".css",
521
- "application/javascript": ".js",
522
- "text/javascript": ".js",
523
- "image/svg+xml": ".svg",
524
- "image/png": ".png",
525
- "image/jpeg": ".jpg",
526
- "image/gif": ".gif",
527
- "image/webp": ".webp",
528
- "image/avif": ".avif",
529
- "application/pdf": ".pdf",
530
- "application/zip": ".zip",
531
- "application/gzip": ".gz",
532
- "application/octet-stream": ".bin"
533
- };
534
- return map[m3] || ".bin";
535
- }
536
- function CopyButton({ text }) {
537
- const [copied, setCopied] = d2(false);
538
- function copy() {
539
- navigator.clipboard.writeText(text).then(() => {
540
- setCopied(true);
541
- setTimeout(() => setCopied(false), 2e3);
542
- });
543
- }
544
- return /* @__PURE__ */ u3("button", { onClick: copy, class: "profiler-body-download-btn profiler-text--xs", style: "cursor:pointer", children: copied ? "Copied!" : "Copy" });
545
- }
546
- function DownloadTextButton({ text, mime }) {
547
- const [url, setUrl] = d2(null);
548
- y2(() => {
549
- const objectUrl = URL.createObjectURL(new Blob([text], { type: mime }));
550
- setUrl(objectUrl);
551
- return () => URL.revokeObjectURL(objectUrl);
552
- }, [text, mime]);
553
- if (!url) return null;
554
- return /* @__PURE__ */ u3("a", { href: url, download: `body${mimeToExt(mime)}`, class: "profiler-body-download-btn profiler-text--xs", children: "Download" });
555
- }
557
+ var PREVIEW_LIMIT = 500;
558
+ var CSV_ROW_LIMIT = 10;
556
559
  function SmartBodyPreview({ body, encoding, headers }) {
557
560
  const [expanded, setExpanded] = d2(false);
558
561
  const [objectUrl, setObjectUrl] = d2(null);
@@ -611,7 +614,7 @@
611
614
  )
612
615
  ] });
613
616
  }
614
- const formatted = formatTextBody(body, category) ?? body;
617
+ const formatted = formatTextBody(body, category);
615
618
  const preview = expanded ? formatted : formatted.slice(0, PREVIEW_LIMIT);
616
619
  const truncated = formatted.length > PREVIEW_LIMIT && !expanded;
617
620
  return /* @__PURE__ */ u3("div", { children: [
@@ -634,6 +637,98 @@
634
637
  )
635
638
  ] });
636
639
  }
640
+ function HttpReqRespDetail({ request, response, backtrace }) {
641
+ return /* @__PURE__ */ u3("div", { style: "padding:12px 4px 4px;border-top:1px solid rgba(0,0,0,0.08);margin-top:8px", children: [
642
+ /* @__PURE__ */ u3("div", { style: "margin-bottom:16px", children: [
643
+ /* @__PURE__ */ u3("div", { class: "profiler-text--sm", style: "font-weight:600;margin-bottom:8px;color:var(--profiler-muted)", children: "REQUEST" }),
644
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Headers" }),
645
+ /* @__PURE__ */ u3(HeadersTable, { headers: request.headers }),
646
+ request.params && Object.keys(request.params).length > 0 && !request.body && /* @__PURE__ */ u3(k, { children: [
647
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-top:10px;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Params" }),
648
+ /* @__PURE__ */ u3("pre", { class: "profiler-code profiler-text--xs", style: "margin:0", children: JSON.stringify(request.params, null, 2) })
649
+ ] }),
650
+ request.body && /* @__PURE__ */ u3(k, { children: [
651
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-top:10px;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Body" }),
652
+ /* @__PURE__ */ u3(SmartBodyPreview, { body: request.body, encoding: request.body_encoding, headers: request.headers })
653
+ ] })
654
+ ] }),
655
+ /* @__PURE__ */ u3("div", { children: [
656
+ /* @__PURE__ */ u3("div", { class: "profiler-text--sm", style: "font-weight:600;margin-bottom:8px;color:var(--profiler-muted)", children: "RESPONSE" }),
657
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Headers" }),
658
+ /* @__PURE__ */ u3(HeadersTable, { headers: response.headers }),
659
+ response.body && /* @__PURE__ */ u3(k, { children: [
660
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-top:10px;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Body" }),
661
+ /* @__PURE__ */ u3(SmartBodyPreview, { body: response.body, encoding: response.body_encoding, headers: response.headers })
662
+ ] })
663
+ ] }),
664
+ backtrace && backtrace.length > 1 && /* @__PURE__ */ u3("div", { style: "margin-top:12px", children: [
665
+ /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Backtrace" }),
666
+ backtrace.map((frame, i3) => /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "padding:2px 0", children: frame }, i3))
667
+ ] })
668
+ ] });
669
+ }
670
+ function HttpCardHeader({ method, url, copyUrl: copyUrlOverride, status, duration, curlCommand, expandable, open, onToggle }) {
671
+ const [copiedUrl, setCopiedUrl] = d2(false);
672
+ const [copiedCurl, setCopiedCurl] = d2(false);
673
+ function handleCopyUrl(e3) {
674
+ e3.stopPropagation();
675
+ navigator.clipboard.writeText(copyUrlOverride ?? url).then(() => {
676
+ setCopiedUrl(true);
677
+ setTimeout(() => setCopiedUrl(false), 2e3);
678
+ });
679
+ }
680
+ function handleCopyCurl(e3) {
681
+ e3.stopPropagation();
682
+ navigator.clipboard.writeText(curlCommand).then(() => {
683
+ setCopiedCurl(true);
684
+ setTimeout(() => setCopiedCurl(false), 2e3);
685
+ });
686
+ }
687
+ return /* @__PURE__ */ u3(
688
+ "div",
689
+ {
690
+ class: "profiler-ajax-card__row",
691
+ style: expandable ? "cursor:pointer;user-select:none" : void 0,
692
+ onClick: expandable ? onToggle : void 0,
693
+ children: [
694
+ /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-3", style: "min-width:0;flex:1", children: [
695
+ expandable && /* @__PURE__ */ u3("span", { style: "font-size:11px;color:var(--profiler-muted)", children: open ? "\u25BE" : "\u25B8" }),
696
+ /* @__PURE__ */ u3("span", { class: `profiler-ajax-card__method badge-${methodBadge(method)}`, children: method }),
697
+ /* @__PURE__ */ u3("strong", { class: "profiler-ajax-card__path", style: "word-break:break-all", children: url }),
698
+ /* @__PURE__ */ u3(
699
+ "button",
700
+ {
701
+ onClick: handleCopyUrl,
702
+ class: "profiler-body-download-btn profiler-text--xs",
703
+ style: "flex-shrink:0;cursor:pointer",
704
+ title: "Copy URL",
705
+ children: copiedUrl ? "Copied!" : "Copy URL"
706
+ }
707
+ ),
708
+ /* @__PURE__ */ u3(
709
+ "button",
710
+ {
711
+ onClick: handleCopyCurl,
712
+ class: "profiler-body-download-btn profiler-text--xs",
713
+ style: "flex-shrink:0;cursor:pointer",
714
+ title: "Copy as cURL",
715
+ children: copiedCurl ? "Copied!" : "Copy as cURL"
716
+ }
717
+ )
718
+ ] }),
719
+ /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", style: "flex-shrink:0", children: [
720
+ /* @__PURE__ */ u3("span", { class: `badge-${statusBadge(status)}`, children: status === 0 ? "ERR" : status }),
721
+ /* @__PURE__ */ u3("span", { class: duration >= 500 ? "badge-error" : duration >= 100 ? "badge-warning" : "badge-success", children: [
722
+ duration.toFixed(2),
723
+ " ms"
724
+ ] })
725
+ ] })
726
+ ]
727
+ }
728
+ );
729
+ }
730
+
731
+ // app/assets/typescript/profiler/components/dashboard/tabs/HttpTab.tsx
637
732
  function waterfallBarColor(status, duration) {
638
733
  if (status === 0 || status >= 500) return "var(--profiler-error, #ef4444)";
639
734
  if (status >= 400) return "var(--profiler-warning, #f59e0b)";
@@ -711,55 +806,21 @@
711
806
  }
712
807
  function HttpRequestDetail({ req, index, threshold }) {
713
808
  const [open, setOpen] = d2(false);
714
- const [copiedUrl, setCopiedUrl] = d2(false);
715
- const [copiedCurl, setCopiedCurl] = d2(false);
716
809
  const isError = req.status >= 400 || req.status === 0;
717
810
  const isSlow = req.duration >= threshold;
718
811
  const cardCls = isError ? "profiler-ajax-card--error" : isSlow ? "profiler-ajax-card--warning" : "profiler-ajax-card--success";
719
- function copyUrl(e3) {
720
- e3.stopPropagation();
721
- navigator.clipboard.writeText(req.url).then(() => {
722
- setCopiedUrl(true);
723
- setTimeout(() => setCopiedUrl(false), 2e3);
724
- });
725
- }
726
- function copyCurl() {
727
- navigator.clipboard.writeText(buildCurl(req)).then(() => {
728
- setCopiedCurl(true);
729
- setTimeout(() => setCopiedCurl(false), 2e3);
730
- });
731
- }
732
812
  return /* @__PURE__ */ u3("div", { class: `profiler-ajax-card ${cardCls}`, style: "margin-bottom:8px", children: [
733
813
  /* @__PURE__ */ u3(
734
- "div",
814
+ HttpCardHeader,
735
815
  {
736
- class: "profiler-ajax-card__row",
737
- style: "cursor:pointer;user-select:none",
738
- onClick: () => setOpen((o3) => !o3),
739
- children: [
740
- /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-3", style: "min-width:0;flex:1", children: [
741
- /* @__PURE__ */ u3("span", { style: "font-size:11px;color:var(--profiler-muted)", children: open ? "\u25BE" : "\u25B8" }),
742
- /* @__PURE__ */ u3("span", { class: `profiler-ajax-card__method badge-${methodBadge(req.method)}`, children: req.method }),
743
- /* @__PURE__ */ u3("strong", { class: "profiler-ajax-card__path", style: "word-break:break-all", children: req.url }),
744
- /* @__PURE__ */ u3(
745
- "button",
746
- {
747
- onClick: copyUrl,
748
- class: "profiler-body-download-btn profiler-text--xs",
749
- style: "flex-shrink:0;cursor:pointer",
750
- title: "Copy URL",
751
- children: copiedUrl ? "Copied!" : "Copy URL"
752
- }
753
- )
754
- ] }),
755
- /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", style: "flex-shrink:0", children: [
756
- /* @__PURE__ */ u3("span", { class: `badge-${statusBadge(req.status)}`, children: req.status === 0 ? "ERR" : req.status }),
757
- /* @__PURE__ */ u3("span", { class: req.duration >= 500 ? "badge-error" : req.duration >= 100 ? "badge-warning" : "badge-success", children: [
758
- req.duration.toFixed(2),
759
- " ms"
760
- ] })
761
- ] })
762
- ]
816
+ method: req.method,
817
+ url: req.url,
818
+ status: req.status,
819
+ duration: req.duration,
820
+ curlCommand: buildCurl(req),
821
+ expandable: true,
822
+ open,
823
+ onToggle: () => setOpen((o3) => !o3)
763
824
  }
764
825
  ),
765
826
  /* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: [
@@ -772,31 +833,14 @@
772
833
  req.backtrace && req.backtrace.length > 0 && /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--muted", style: "margin-left:12px", children: req.backtrace[0] })
773
834
  ] }),
774
835
  req.error && /* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--error", children: req.error }) }),
775
- open && /* @__PURE__ */ u3("div", { style: "padding:12px 4px 4px;border-top:1px solid rgba(0,0,0,0.08);margin-top:8px", children: [
776
- /* @__PURE__ */ u3("div", { style: "margin-bottom:12px", children: /* @__PURE__ */ u3("button", { onClick: copyCurl, class: "profiler-body-download-btn profiler-text--xs", style: "cursor:pointer", children: copiedCurl ? "Copied!" : "Copy as cURL" }) }),
777
- /* @__PURE__ */ u3("div", { style: "margin-bottom:16px", children: [
778
- /* @__PURE__ */ u3("div", { class: "profiler-text--sm", style: "font-weight:600;margin-bottom:8px;color:var(--profiler-muted)", children: "REQUEST" }),
779
- /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Headers" }),
780
- /* @__PURE__ */ u3(HeadersTable, { headers: req.request_headers || {} }),
781
- req.request_body && /* @__PURE__ */ u3(k, { children: [
782
- /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-top:10px;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Body" }),
783
- /* @__PURE__ */ u3(SmartBodyPreview, { body: req.request_body, encoding: req.request_body_encoding, headers: req.request_headers || {} })
784
- ] })
785
- ] }),
786
- /* @__PURE__ */ u3("div", { children: [
787
- /* @__PURE__ */ u3("div", { class: "profiler-text--sm", style: "font-weight:600;margin-bottom:8px;color:var(--profiler-muted)", children: "RESPONSE" }),
788
- /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Headers" }),
789
- /* @__PURE__ */ u3(HeadersTable, { headers: req.response_headers || {} }),
790
- req.response_body && /* @__PURE__ */ u3(k, { children: [
791
- /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-top:10px;margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Body" }),
792
- /* @__PURE__ */ u3(SmartBodyPreview, { body: req.response_body, encoding: req.response_body_encoding, headers: req.response_headers || {} })
793
- ] })
794
- ] }),
795
- req.backtrace && req.backtrace.length > 1 && /* @__PURE__ */ u3("div", { style: "margin-top:12px", children: [
796
- /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "margin-bottom:4px;text-transform:uppercase;letter-spacing:.5px", children: "Backtrace" }),
797
- req.backtrace.map((frame, i3) => /* @__PURE__ */ u3("div", { class: "profiler-text--xs profiler-text--muted", style: "padding:2px 0", children: frame }, i3))
798
- ] })
799
- ] })
836
+ open && /* @__PURE__ */ u3(
837
+ HttpReqRespDetail,
838
+ {
839
+ request: { headers: req.request_headers || {}, body: req.request_body, body_encoding: req.request_body_encoding },
840
+ response: { headers: req.response_headers || {}, body: req.response_body, body_encoding: req.response_body_encoding },
841
+ backtrace: req.backtrace
842
+ }
843
+ )
800
844
  ] });
801
845
  }
802
846
  function HttpTab({ httpData }) {
@@ -2100,107 +2144,43 @@
2100
2144
  return parts.join(" \\\n");
2101
2145
  }
2102
2146
  function RequestTab({ profile }) {
2103
- const [copied, setCopied] = d2(false);
2104
- const curl = buildCurl2(profile);
2105
2147
  const routeData = profile.collectors_data?.request ?? {};
2106
- function copyToClipboard() {
2107
- navigator.clipboard.writeText(curl).then(() => {
2108
- setCopied(true);
2109
- setTimeout(() => setCopied(false), 2e3);
2110
- });
2111
- }
2112
- return /* @__PURE__ */ u3(k, { children: [
2113
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header", children: "Request" }),
2114
- /* @__PURE__ */ u3("table", { children: [
2115
- /* @__PURE__ */ u3("tr", { children: [
2116
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", style: "width: 200px;", children: "Path" }),
2117
- /* @__PURE__ */ u3("td", { children: profile.path })
2118
- ] }),
2119
- /* @__PURE__ */ u3("tr", { children: [
2120
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Method" }),
2121
- /* @__PURE__ */ u3("td", { children: profile.method })
2122
- ] }),
2123
- /* @__PURE__ */ u3("tr", { children: [
2124
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Status" }),
2125
- /* @__PURE__ */ u3("td", { children: profile.status })
2126
- ] }),
2127
- /* @__PURE__ */ u3("tr", { children: [
2128
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Duration" }),
2129
- /* @__PURE__ */ u3("td", { children: [
2130
- profile.duration.toFixed(2),
2131
- " ms"
2132
- ] })
2133
- ] }),
2134
- routeData.controller_action && /* @__PURE__ */ u3("tr", { children: [
2135
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Controller#Action" }),
2136
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: routeData.controller_action })
2137
- ] }),
2138
- routeData.route_name && /* @__PURE__ */ u3("tr", { children: [
2139
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Route Name" }),
2140
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: routeData.route_name })
2141
- ] }),
2142
- routeData.route_pattern && /* @__PURE__ */ u3("tr", { children: [
2143
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Route Pattern" }),
2144
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: routeData.route_pattern })
2145
- ] }),
2146
- routeData.route_params && Object.keys(routeData.route_params).length > 0 && /* @__PURE__ */ u3("tr", { children: [
2147
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", children: "Route Params" }),
2148
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: Object.entries(routeData.route_params).map(([k3, v3]) => `${k3}: ${v3}`).join(", ") })
2148
+ const hasParams = profile.params && Object.keys(profile.params).length > 0;
2149
+ return /* @__PURE__ */ u3("div", { class: "profiler-ajax-card profiler-ajax-card--success", style: "margin-bottom:8px;background:var(--profiler-bg-elevated);transform:translateX(3px);box-shadow:var(--profiler-shadow-sm);transition:none", children: [
2150
+ /* @__PURE__ */ u3(
2151
+ HttpCardHeader,
2152
+ {
2153
+ method: profile.method,
2154
+ url: profile.path,
2155
+ copyUrl: `http://localhost:3000${profile.path}`,
2156
+ status: profile.status,
2157
+ duration: profile.duration,
2158
+ curlCommand: buildCurl2(profile)
2159
+ }
2160
+ ),
2161
+ (routeData.controller_action || routeData.route_pattern) && /* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: [
2162
+ routeData.controller_action && /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--muted", style: "margin-right:16px", children: routeData.controller_action }),
2163
+ routeData.route_pattern && /* @__PURE__ */ u3("span", { class: "profiler-text--xs profiler-text--muted", style: "font-family:monospace", children: [
2164
+ routeData.route_name ? `${routeData.route_name} \xB7 ` : "",
2165
+ routeData.route_pattern
2149
2166
  ] })
2150
2167
  ] }),
2151
- profile.headers && Object.keys(profile.headers).length > 0 && /* @__PURE__ */ u3(k, { children: [
2152
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Request Headers" }),
2153
- /* @__PURE__ */ u3("table", { children: Object.entries(profile.headers).map(([k3, v3]) => /* @__PURE__ */ u3("tr", { children: [
2154
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", style: "width: 200px;", children: k3 }),
2155
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: String(v3) })
2156
- ] }, k3)) })
2157
- ] }),
2158
- profile.params && Object.keys(profile.params).length > 0 && /* @__PURE__ */ u3(k, { children: [
2159
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Request Params" }),
2160
- /* @__PURE__ */ u3("pre", { class: "profiler-code profiler-text--xs", children: JSON.stringify(profile.params, null, 2) })
2161
- ] }),
2162
- profile.request_body && /* @__PURE__ */ u3(k, { children: [
2163
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Request Body" }),
2164
- /* @__PURE__ */ u3(
2165
- SmartBodyPreview,
2166
- {
2168
+ /* @__PURE__ */ u3(
2169
+ HttpReqRespDetail,
2170
+ {
2171
+ request: {
2172
+ headers: profile.headers ?? {},
2167
2173
  body: profile.request_body,
2168
- encoding: profile.request_body_encoding,
2169
- headers: profile.headers ?? {}
2170
- }
2171
- )
2172
- ] }),
2173
- profile.response_headers && Object.keys(profile.response_headers).length > 0 && /* @__PURE__ */ u3(k, { children: [
2174
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Response Headers" }),
2175
- /* @__PURE__ */ u3("table", { children: Object.entries(profile.response_headers).map(([k3, v3]) => /* @__PURE__ */ u3("tr", { children: [
2176
- /* @__PURE__ */ u3("th", { class: "profiler-text--sm", style: "width: 200px;", children: k3 }),
2177
- /* @__PURE__ */ u3("td", { class: "profiler-text--mono profiler-text--xs", children: String(v3) })
2178
- ] }, k3)) })
2179
- ] }),
2180
- profile.response_body && /* @__PURE__ */ u3(k, { children: [
2181
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Response Body" }),
2182
- /* @__PURE__ */ u3(
2183
- SmartBodyPreview,
2184
- {
2174
+ body_encoding: profile.request_body_encoding,
2175
+ params: hasParams ? profile.params : void 0
2176
+ },
2177
+ response: {
2178
+ headers: profile.response_headers ?? {},
2185
2179
  body: profile.response_body,
2186
- encoding: profile.response_body_encoding,
2187
- headers: profile.response_headers ?? {}
2180
+ body_encoding: profile.response_body_encoding
2188
2181
  }
2189
- )
2190
- ] }),
2191
- /* @__PURE__ */ u3("h2", { class: "profiler-section__header profiler-mt-6", children: "Curl Command" }),
2192
- /* @__PURE__ */ u3("div", { style: "position: relative;", children: [
2193
- /* @__PURE__ */ u3(
2194
- "button",
2195
- {
2196
- onClick: copyToClipboard,
2197
- class: "profiler-body-download-btn",
2198
- style: "position: absolute; top: 8px; right: 8px; z-index: 1;",
2199
- children: copied ? "Copied!" : "Copy"
2200
- }
2201
- ),
2202
- /* @__PURE__ */ u3("pre", { class: "profiler-code profiler-text--xs", style: "padding-right: 80px;", children: curl })
2203
- ] })
2182
+ }
2183
+ )
2204
2184
  ] });
2205
2185
  }
2206
2186
 
@@ -3081,12 +3061,6 @@
3081
3061
  custom: "Custom",
3082
3062
  method: "Method"
3083
3063
  };
3084
- function formatBytes3(bytes) {
3085
- if (bytes < 0) return "\u2014";
3086
- if (bytes < 1024) return `${bytes} B`;
3087
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
3088
- return `${(bytes / (1024 * 1024)).toFixed(2)} MB`;
3089
- }
3090
3064
  function FlameGraphTab({ flamegraphData, perfData, functionProfileData }) {
3091
3065
  const canvasRef = A2(null);
3092
3066
  const containerRef = A2(null);
@@ -3592,7 +3566,7 @@
3592
3566
  ] }),
3593
3567
  showMemory && /* @__PURE__ */ u3("div", { class: "stat-item", children: [
3594
3568
  /* @__PURE__ */ u3("span", { class: "stat-label", children: "Memory" }),
3595
- /* @__PURE__ */ u3("span", { class: "stat-value", children: formatBytes3(data.total_memory_bytes ?? 0) })
3569
+ /* @__PURE__ */ u3("span", { class: "stat-value", children: formatBytes(data.total_memory_bytes ?? 0) })
3596
3570
  ] })
3597
3571
  ] }),
3598
3572
  rootCalls.length > 0 && /* @__PURE__ */ u3(
@@ -3698,7 +3672,7 @@
3698
3672
  " ",
3699
3673
  /* @__PURE__ */ u3("small", { children: "obj" })
3700
3674
  ] }),
3701
- showMemory && /* @__PURE__ */ u3("td", { class: "profiler-text--right profiler-text--muted", children: formatBytes3(fn.memory_bytes) })
3675
+ showMemory && /* @__PURE__ */ u3("td", { class: "profiler-text--right profiler-text--muted", children: formatBytes(fn.memory_bytes) })
3702
3676
  ]
3703
3677
  },
3704
3678
  i3
@@ -3835,15 +3809,6 @@
3835
3809
  }
3836
3810
 
3837
3811
  // app/assets/typescript/profiler/components/dashboard/tabs/AjaxTab.tsx
3838
- function methodBadge2(method) {
3839
- const map = { GET: "info", POST: "success", PUT: "warning", PATCH: "warning", DELETE: "error" };
3840
- return map[method] || "default";
3841
- }
3842
- function statusBadge2(status) {
3843
- if (status >= 200 && status < 300) return "success";
3844
- if (status >= 400) return "error";
3845
- return "warning";
3846
- }
3847
3812
  function AjaxTab({ ajaxData }) {
3848
3813
  if (!ajaxData?.requests?.length) {
3849
3814
  return /* @__PURE__ */ u3("div", { class: "profiler-empty", children: [
@@ -3879,7 +3844,7 @@
3879
3844
  /* @__PURE__ */ u3("div", { class: "profiler-panel profiler-panel--sm", children: [
3880
3845
  /* @__PURE__ */ u3("h3", { class: "profiler-text--sm profiler-text--muted profiler-text--uppercase profiler-mb-3", children: "By Method" }),
3881
3846
  Object.entries(ajaxData.by_method).map(([method, count]) => /* @__PURE__ */ u3("div", { class: "profiler-kv-row", children: [
3882
- /* @__PURE__ */ u3("span", { class: `badge-${methodBadge2(method)}`, children: method }),
3847
+ /* @__PURE__ */ u3("span", { class: `badge-${methodBadge(method)}`, children: method }),
3883
3848
  /* @__PURE__ */ u3("strong", { children: count })
3884
3849
  ] }, method))
3885
3850
  ] }),
@@ -3895,11 +3860,11 @@
3895
3860
  ajaxData.requests.map((req, index) => /* @__PURE__ */ u3("div", { class: `profiler-ajax-card profiler-ajax-card--${req.status >= 200 && req.status < 300 ? "success" : "error"}`, children: [
3896
3861
  /* @__PURE__ */ u3("div", { class: "profiler-ajax-card__row", children: [
3897
3862
  /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-3", children: [
3898
- /* @__PURE__ */ u3("span", { class: `profiler-ajax-card__method badge-${methodBadge2(req.method)}`, children: req.method }),
3863
+ /* @__PURE__ */ u3("span", { class: `profiler-ajax-card__method badge-${methodBadge(req.method)}`, children: req.method }),
3899
3864
  /* @__PURE__ */ u3("strong", { class: "profiler-ajax-card__path", children: req.path })
3900
3865
  ] }),
3901
3866
  /* @__PURE__ */ u3("div", { class: "profiler-flex profiler-flex--gap-2", children: [
3902
- /* @__PURE__ */ u3("span", { class: `badge-${statusBadge2(req.status)}`, children: req.status }),
3867
+ /* @__PURE__ */ u3("span", { class: `badge-${statusBadge(req.status)}`, children: req.status }),
3903
3868
  /* @__PURE__ */ u3("span", { class: req.duration >= 500 ? "badge-error" : req.duration >= 100 ? "badge-warning" : "badge-success", children: [
3904
3869
  req.duration.toFixed(2),
3905
3870
  " ms"
@@ -22,6 +22,9 @@ module Profiler
22
22
 
23
23
  url = build_url(host, port, req.path, use_ssl?)
24
24
  req_body = req.body.to_s
25
+ # Fallback: body may be passed as the 2nd argument and only applied
26
+ # to req inside super via req.set_body_internal(body)
27
+ req_body = body.to_s if req_body.empty? && body
25
28
  req_headers = req.to_hash.transform_values { |v| v.join(", ") }
26
29
  request_id = SecureRandom.hex(8)
27
30
  started_at = Time.now.iso8601(3)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Profiler
4
- VERSION = "0.17.0"
4
+ VERSION = "0.18.0"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails-profiler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sébastien Duplessy
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-13 00:00:00.000000000 Z
11
+ date: 2026-04-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails