mmt-testlight 1.43.0-pre → 1.43.2-pre

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/cli.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- globalThis.__MMT_CLI_VERSION__ = "1.43.0-pre";
2
+ globalThis.__MMT_CLI_VERSION__ = "1.43.2-pre";
3
3
  "use strict";
4
4
  var __create = Object.create;
5
5
  var __defProp = Object.defineProperty;
@@ -121,33 +121,63 @@ var init_mmtFileType = __esm({
121
121
  var CommonData_exports = {};
122
122
  __export(CommonData_exports, {
123
123
  FORMAT_VALUES: () => FORMAT_VALUES,
124
+ REQUEST_FORMAT_VALUES: () => REQUEST_FORMAT_VALUES,
125
+ RESPONSE_FORMAT_VALUES: () => RESPONSE_FORMAT_VALUES,
124
126
  formatDuration: () => formatDuration,
125
127
  jsonTypes: () => jsonTypes,
126
128
  normalizeFormat: () => normalizeFormat,
127
129
  packFormatSpec: () => packFormatSpec,
128
130
  requestFormat: () => requestFormat,
129
131
  responseFormat: () => responseFormat,
132
+ toResponseFormat: () => toResponseFormat,
130
133
  typeOptions: () => MMT_FILE_TYPE_OPTIONS
131
134
  });
135
+ function toResponseFormat(format) {
136
+ return format === "none" ? "auto" : format;
137
+ }
132
138
  function isFormatValue(value) {
133
139
  return typeof value === "string" && FORMAT_VALUES.includes(value);
134
140
  }
141
+ function isRequestFormatValue(value) {
142
+ return typeof value === "string" && (value === "auto" || FORMAT_VALUES.includes(value));
143
+ }
144
+ function isResponseFormatValue(value) {
145
+ return typeof value === "string" && RESPONSE_FORMAT_VALUES.includes(value);
146
+ }
147
+ function coerceResponseFormat(rawResponse, request2) {
148
+ if (rawResponse === void 0 || rawResponse === null || rawResponse === "none") {
149
+ return "auto";
150
+ }
151
+ if (isResponseFormatValue(rawResponse)) {
152
+ return rawResponse;
153
+ }
154
+ if (request2 !== "none" && request2 !== "auto" && isResponseFormatValue(request2)) {
155
+ return request2;
156
+ }
157
+ return "auto";
158
+ }
135
159
  function normalizeFormat(format) {
136
160
  if (format == null) {
137
- return { request: "json", response: "json" };
161
+ return { request: "auto", response: "auto" };
138
162
  }
139
163
  if (typeof format === "string") {
164
+ if (format === "auto") {
165
+ return { request: "auto", response: "auto" };
166
+ }
167
+ if (format === "none") {
168
+ return { request: "none", response: "auto" };
169
+ }
140
170
  const value = isFormatValue(format) ? format : "json";
141
- return { request: value, response: value };
171
+ return { request: value, response: "auto" };
142
172
  }
143
173
  if (typeof format === "object" && !Array.isArray(format)) {
144
174
  const rawRequest = format.request;
145
175
  const rawResponse = format.response ?? format.respond;
146
- const request2 = isFormatValue(rawRequest) ? rawRequest : isFormatValue(rawResponse) ? rawResponse : "json";
147
- const response = isFormatValue(rawResponse) ? rawResponse : request2;
176
+ const request2 = isRequestFormatValue(rawRequest) ? rawRequest : isFormatValue(rawResponse) ? rawResponse : "auto";
177
+ const response = coerceResponseFormat(rawResponse, request2);
148
178
  return { request: request2, response };
149
179
  }
150
- return { request: "json", response: "json" };
180
+ return { request: "auto", response: "auto" };
151
181
  }
152
182
  function requestFormat(format) {
153
183
  return normalizeFormat(format).request;
@@ -160,6 +190,18 @@ function packFormatSpec(format) {
160
190
  return void 0;
161
191
  }
162
192
  const { request: request2, response } = normalizeFormat(format);
193
+ if (request2 === "none" && response === "auto") {
194
+ return "none";
195
+ }
196
+ if (response === "auto" && request2 !== "auto") {
197
+ return request2;
198
+ }
199
+ if (request2 === "auto" && response === "auto") {
200
+ return "auto";
201
+ }
202
+ if (request2 === "auto" || response === "auto") {
203
+ return { request: request2, response };
204
+ }
163
205
  if (request2 === response) {
164
206
  return request2;
165
207
  }
@@ -191,12 +233,24 @@ function formatDuration(ms) {
191
233
  const h = Math.round(ms % 864e5 / 36e5);
192
234
  return h > 0 ? `${d}d ${h}h` : `${d}d`;
193
235
  }
194
- var FORMAT_VALUES, jsonTypes;
236
+ var FORMAT_VALUES, REQUEST_FORMAT_VALUES, RESPONSE_BODY_FORMATS, RESPONSE_FORMAT_VALUES, jsonTypes;
195
237
  var init_CommonData = __esm({
196
238
  "../core/src/CommonData.ts"() {
197
239
  "use strict";
198
240
  init_mmtFileType();
199
- FORMAT_VALUES = ["json", "xml", "xmle", "text", "urlencoded", "binary", "multipart"];
241
+ FORMAT_VALUES = ["none", "json", "xml", "xmle", "text", "html", "urlencoded", "binary", "multipart"];
242
+ REQUEST_FORMAT_VALUES = [...FORMAT_VALUES, "auto"];
243
+ RESPONSE_BODY_FORMATS = [
244
+ "json",
245
+ "xml",
246
+ "xmle",
247
+ "text",
248
+ "html",
249
+ "urlencoded",
250
+ "binary",
251
+ "multipart"
252
+ ];
253
+ RESPONSE_FORMAT_VALUES = [...RESPONSE_BODY_FORMATS, "auto"];
200
254
  jsonTypes = [
201
255
  "object",
202
256
  "object[]",
@@ -649,6 +703,7 @@ var init_TestData = __esm({
649
703
  var apiMethod_exports = {};
650
704
  __export(apiMethod_exports, {
651
705
  hasApiRequestBody: () => hasApiRequestBody,
706
+ httpMethodAllowsRequestBody: () => httpMethodAllowsRequestBody,
652
707
  resolveApiHttpMethod: () => resolveApiHttpMethod
653
708
  });
654
709
  function hasApiRequestBody(body) {
@@ -666,6 +721,10 @@ function hasApiRequestBody(body) {
666
721
  }
667
722
  return true;
668
723
  }
724
+ function httpMethodAllowsRequestBody(method) {
725
+ const trimmed = typeof method === "string" ? method.trim().toLowerCase() : "";
726
+ return trimmed !== "get";
727
+ }
669
728
  function resolveApiHttpMethod(method, body) {
670
729
  const trimmed = typeof method === "string" ? method.trim().toLowerCase() : "";
671
730
  if (trimmed) {
@@ -679,6 +738,181 @@ var init_apiMethod = __esm({
679
738
  }
680
739
  });
681
740
 
741
+ // ../core/src/binaryBody.ts
742
+ function bytesToBase64(bytes) {
743
+ let output = "";
744
+ for (let i = 0; i < bytes.length; i += 3) {
745
+ const a = bytes[i];
746
+ const b = i + 1 < bytes.length ? bytes[i + 1] : 0;
747
+ const c = i + 2 < bytes.length ? bytes[i + 2] : 0;
748
+ const triplet = a << 16 | b << 8 | c;
749
+ output += BASE64_CHARS[triplet >> 18 & 63];
750
+ output += BASE64_CHARS[triplet >> 12 & 63];
751
+ output += i + 1 < bytes.length ? BASE64_CHARS[triplet >> 6 & 63] : "=";
752
+ output += i + 2 < bytes.length ? BASE64_CHARS[triplet & 63] : "=";
753
+ }
754
+ return output;
755
+ }
756
+ function toByteArray(data) {
757
+ if (data instanceof Uint8Array) {
758
+ return data;
759
+ }
760
+ if (data instanceof ArrayBuffer) {
761
+ return new Uint8Array(data);
762
+ }
763
+ if (typeof data === "string") {
764
+ return new TextEncoder().encode(data);
765
+ }
766
+ return new Uint8Array(0);
767
+ }
768
+ function primaryContentType(contentType) {
769
+ return (contentType || "").split(";")[0].trim().toLowerCase();
770
+ }
771
+ function isBinaryContentType(contentType) {
772
+ const ct = primaryContentType(contentType);
773
+ if (!ct) {
774
+ return false;
775
+ }
776
+ if (ct.startsWith("image/")) {
777
+ return true;
778
+ }
779
+ if (ct === "application/octet-stream") {
780
+ return true;
781
+ }
782
+ if (ct === "application/pdf") {
783
+ return true;
784
+ }
785
+ return false;
786
+ }
787
+ function sniffImageMime(bytes) {
788
+ if (bytes.length >= 8 && bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) {
789
+ return "image/png";
790
+ }
791
+ if (bytes.length >= 3 && bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) {
792
+ return "image/jpeg";
793
+ }
794
+ if (bytes.length >= 6 && bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) {
795
+ return "image/gif";
796
+ }
797
+ if (bytes.length >= 12 && bytes[0] === 82 && bytes[1] === 73 && bytes[2] === 70 && bytes[3] === 70 && bytes[8] === 87 && bytes[9] === 69 && bytes[10] === 66 && bytes[11] === 80) {
798
+ return "image/webp";
799
+ }
800
+ const sample = bytes.subarray(0, Math.min(bytes.length, 256));
801
+ let text = "";
802
+ try {
803
+ text = new TextDecoder().decode(sample).trimStart();
804
+ } catch {
805
+ return void 0;
806
+ }
807
+ if (text.startsWith("<svg") || text.startsWith("<?xml") && text.includes("<svg")) {
808
+ return "image/svg+xml";
809
+ }
810
+ return void 0;
811
+ }
812
+ function resolveBinaryPreviewMime(contentType, bytes) {
813
+ const ct = primaryContentType(contentType);
814
+ if (ct.startsWith("image/")) {
815
+ return ct;
816
+ }
817
+ return sniffImageMime(bytes);
818
+ }
819
+ function encodeBinaryBody(bytes, contentType) {
820
+ const previewMime = resolveBinaryPreviewMime(contentType, bytes);
821
+ return {
822
+ __mmtBinary: true,
823
+ base64: bytesToBase64(bytes),
824
+ byteLength: bytes.length,
825
+ contentType: primaryContentType(contentType) || void 0,
826
+ previewMime
827
+ };
828
+ }
829
+ function normalizeHttpResponseBody(data, headers) {
830
+ const bytes = toByteArray(data);
831
+ const contentType = headerContentType(headers);
832
+ if (isBinaryContentType(contentType)) {
833
+ return encodeBinaryBody(bytes, contentType);
834
+ }
835
+ return new TextDecoder("utf-8").decode(bytes);
836
+ }
837
+ function headerContentType(headers) {
838
+ if (!headers) {
839
+ return "";
840
+ }
841
+ for (const [key, value] of Object.entries(headers)) {
842
+ if (key.toLowerCase() === "content-type") {
843
+ return value == null ? "" : String(value);
844
+ }
845
+ }
846
+ return "";
847
+ }
848
+ var BASE64_CHARS;
849
+ var init_binaryBody = __esm({
850
+ "../core/src/binaryBody.ts"() {
851
+ "use strict";
852
+ BASE64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
853
+ }
854
+ });
855
+
856
+ // ../core/src/formatResolve.ts
857
+ function headerContentType2(headers) {
858
+ if (!headers) {
859
+ return "";
860
+ }
861
+ for (const [key, value] of Object.entries(headers)) {
862
+ if (key.toLowerCase() === "content-type") {
863
+ return value == null ? "" : String(value);
864
+ }
865
+ }
866
+ return "";
867
+ }
868
+ function formatFromContentType(contentType) {
869
+ const ct = (contentType || "").toLowerCase();
870
+ if (!ct) {
871
+ return void 0;
872
+ }
873
+ if (ct.includes("json")) {
874
+ return "json";
875
+ }
876
+ if (ct.includes("html")) {
877
+ return "html";
878
+ }
879
+ if (ct.includes("xml")) {
880
+ return "xml";
881
+ }
882
+ if (ct.includes("urlencoded") || ct.includes("x-www-form-urlencoded")) {
883
+ return "urlencoded";
884
+ }
885
+ if (ct.includes("multipart")) {
886
+ return "multipart";
887
+ }
888
+ if (ct.startsWith("image/")) {
889
+ return "binary";
890
+ }
891
+ if (ct.includes("octet-stream")) {
892
+ return "binary";
893
+ }
894
+ if (ct.includes("text/plain")) {
895
+ return "text";
896
+ }
897
+ return void 0;
898
+ }
899
+ function resolveRequestFormat(declared, headers, method) {
900
+ if (declared !== "auto") {
901
+ return declared;
902
+ }
903
+ if (method !== void 0 && !httpMethodAllowsRequestBody(method)) {
904
+ return "none";
905
+ }
906
+ return formatFromContentType(headerContentType2(headers)) ?? "json";
907
+ }
908
+ var init_formatResolve = __esm({
909
+ "../core/src/formatResolve.ts"() {
910
+ "use strict";
911
+ init_apiMethod();
912
+ init_binaryBody();
913
+ }
914
+ });
915
+
682
916
  // ../core/src/RandomResources.ts
683
917
  var COLOR_PALETTE, FIRST_NAMES, LAST_NAMES, CITY_LIST, COUNTRY_LIST, EMAIL_DOMAINS, WEEKDAYS, MONTHS;
684
918
  var init_RandomResources = __esm({
@@ -3650,12 +3884,27 @@ function generateBoundary() {
3650
3884
  }
3651
3885
  return `mmt${Date.now().toString(36)}${Math.random().toString(36).slice(2)}`;
3652
3886
  }
3887
+ function coerceMultipartPartsInput(body) {
3888
+ if (typeof body !== "string") {
3889
+ return body;
3890
+ }
3891
+ const trimmed = body.trim();
3892
+ if (!trimmed.startsWith("[")) {
3893
+ return body;
3894
+ }
3895
+ try {
3896
+ return JSON.parse(trimmed);
3897
+ } catch {
3898
+ return body;
3899
+ }
3900
+ }
3653
3901
  function normalizeMultipartParts(body) {
3654
- if (!Array.isArray(body)) {
3902
+ const input = coerceMultipartPartsInput(body);
3903
+ if (!Array.isArray(input)) {
3655
3904
  throw new Error("Invalid multipart body: expected an array of parts");
3656
3905
  }
3657
3906
  const parts = [];
3658
- for (const raw of body) {
3907
+ for (const raw of input) {
3659
3908
  if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
3660
3909
  throw new Error("Invalid multipart body: each part must be an object");
3661
3910
  }
@@ -4841,6 +5090,117 @@ var init_JSerHelper = __esm({
4841
5090
  }
4842
5091
  });
4843
5092
 
5093
+ // ../core/src/htmlFormat.ts
5094
+ function formatHtmlLenient(html) {
5095
+ const normalized = normalizeNewlines(html);
5096
+ const lines = [];
5097
+ let indent = 0;
5098
+ let i = 0;
5099
+ const pushLine = (text, level = indent) => {
5100
+ const trimmed = text.trim();
5101
+ if (trimmed) {
5102
+ lines.push(`${" ".repeat(level)}${trimmed}`);
5103
+ }
5104
+ };
5105
+ while (i < normalized.length) {
5106
+ if (normalized.slice(i, i + 4) === "<!--") {
5107
+ const commentEnd = normalized.indexOf("-->", i + 4);
5108
+ if (commentEnd === -1) {
5109
+ pushLine(normalized.slice(i));
5110
+ break;
5111
+ }
5112
+ pushLine(normalized.slice(i, commentEnd + 3));
5113
+ i = commentEnd + 3;
5114
+ continue;
5115
+ }
5116
+ if (normalized[i] !== "<") {
5117
+ const next = normalized.indexOf("<", i);
5118
+ const text = normalized.slice(i, next === -1 ? void 0 : next);
5119
+ pushLine(text);
5120
+ i = next === -1 ? normalized.length : next;
5121
+ continue;
5122
+ }
5123
+ const tagEnd = normalized.indexOf(">", i);
5124
+ if (tagEnd === -1) {
5125
+ pushLine(normalized.slice(i));
5126
+ break;
5127
+ }
5128
+ const tag = normalized.slice(i, tagEnd + 1);
5129
+ const tagName = tag.match(/^<\/?([a-zA-Z0-9-]+)/)?.[1]?.toLowerCase();
5130
+ const isClosing = tag.startsWith("</");
5131
+ const isSelfClosing = /\/>\s*$/.test(tag);
5132
+ const isSpecial = tag.startsWith("<!") || tag.startsWith("<?");
5133
+ if (!isClosing && tagName && HTML_RAW_TEXT_ELEMENTS.has(tagName)) {
5134
+ const closeTag = `</${tagName}>`;
5135
+ const closeIdx = normalized.toLowerCase().indexOf(closeTag, tagEnd + 1);
5136
+ pushLine(tag);
5137
+ if (closeIdx !== -1) {
5138
+ pushLine(normalized.slice(tagEnd + 1, closeIdx), indent + 1);
5139
+ pushLine(closeTag);
5140
+ i = closeIdx + closeTag.length;
5141
+ continue;
5142
+ }
5143
+ }
5144
+ if (isClosing && tagName) {
5145
+ indent = Math.max(0, indent - 1);
5146
+ pushLine(tag);
5147
+ i = tagEnd + 1;
5148
+ continue;
5149
+ }
5150
+ pushLine(tag);
5151
+ if (!isSelfClosing && !isSpecial && tagName && !HTML_VOID_ELEMENTS.has(tagName)) {
5152
+ indent++;
5153
+ }
5154
+ i = tagEnd + 1;
5155
+ }
5156
+ return lines.join("\n");
5157
+ }
5158
+ function formatHtmlStrict(html) {
5159
+ const normalized = normalizeNewlines(html);
5160
+ const xmlObj = (0, import_xml_js.xml2js)(normalized, { compact: true });
5161
+ return (0, import_xml_js.js2xml)(xmlObj, {
5162
+ compact: true,
5163
+ spaces: 2,
5164
+ fullTagEmptyElement: true
5165
+ });
5166
+ }
5167
+ function formatHtmlBody(html) {
5168
+ try {
5169
+ return formatHtmlStrict(html);
5170
+ } catch {
5171
+ try {
5172
+ return formatHtmlLenient(html);
5173
+ } catch {
5174
+ return html;
5175
+ }
5176
+ }
5177
+ }
5178
+ var import_xml_js, HTML_VOID_ELEMENTS, HTML_RAW_TEXT_ELEMENTS;
5179
+ var init_htmlFormat = __esm({
5180
+ "../core/src/htmlFormat.ts"() {
5181
+ "use strict";
5182
+ import_xml_js = require("xml-js");
5183
+ init_textLines();
5184
+ HTML_VOID_ELEMENTS = /* @__PURE__ */ new Set([
5185
+ "area",
5186
+ "base",
5187
+ "br",
5188
+ "col",
5189
+ "embed",
5190
+ "hr",
5191
+ "img",
5192
+ "input",
5193
+ "link",
5194
+ "meta",
5195
+ "param",
5196
+ "source",
5197
+ "track",
5198
+ "wbr"
5199
+ ]);
5200
+ HTML_RAW_TEXT_ELEMENTS = /* @__PURE__ */ new Set(["script", "style"]);
5201
+ }
5202
+ });
5203
+
4844
5204
  // ../core/src/expectOperatorYaml.ts
4845
5205
  function quoteExpectOperators(yaml4) {
4846
5206
  const eol = detectNewline(yaml4);
@@ -5233,6 +5593,57 @@ var init_yamlAstMerge = __esm({
5233
5593
  }
5234
5594
  });
5235
5595
 
5596
+ // ../core/src/yamlBlockSteps.ts
5597
+ function pairKey2(pair) {
5598
+ if ((0, import_yaml2.isScalar)(pair.key)) {
5599
+ return String(pair.key.value);
5600
+ }
5601
+ return void 0;
5602
+ }
5603
+ function normalizeStepSequence(seq) {
5604
+ seq.flow = false;
5605
+ for (const item of seq.items) {
5606
+ if ((0, import_yaml2.isMap)(item)) {
5607
+ item.flow = false;
5608
+ forceBlockStyleForStepSequences(item);
5609
+ } else {
5610
+ forceBlockStyleForStepSequences(item);
5611
+ }
5612
+ }
5613
+ }
5614
+ function forceBlockStyleForStepSequences(node) {
5615
+ if (!node) {
5616
+ return;
5617
+ }
5618
+ if ((0, import_yaml2.isMap)(node)) {
5619
+ for (const item of node.items) {
5620
+ if (!(0, import_yaml2.isPair)(item)) {
5621
+ continue;
5622
+ }
5623
+ const key = pairKey2(item);
5624
+ if (key && BLOCK_LIST_KEYS.has(key) && (0, import_yaml2.isSeq)(item.value)) {
5625
+ normalizeStepSequence(item.value);
5626
+ } else {
5627
+ forceBlockStyleForStepSequences(item.value);
5628
+ }
5629
+ }
5630
+ return;
5631
+ }
5632
+ if ((0, import_yaml2.isSeq)(node)) {
5633
+ for (const item of node.items) {
5634
+ forceBlockStyleForStepSequences(item);
5635
+ }
5636
+ }
5637
+ }
5638
+ var import_yaml2, BLOCK_LIST_KEYS;
5639
+ var init_yamlBlockSteps = __esm({
5640
+ "../core/src/yamlBlockSteps.ts"() {
5641
+ "use strict";
5642
+ import_yaml2 = require("yaml");
5643
+ BLOCK_LIST_KEYS = /* @__PURE__ */ new Set(["steps", "stages", "flow", "else"]);
5644
+ }
5645
+ });
5646
+
5236
5647
  // ../core/src/markupConvertor.ts
5237
5648
  var markupConvertor_exports = {};
5238
5649
  __export(markupConvertor_exports, {
@@ -5319,12 +5730,14 @@ function packYaml(obj, originalYaml) {
5319
5730
  doc2.contents = merged;
5320
5731
  }
5321
5732
  applyKeywordScalarStyles(doc2.contents, obj);
5733
+ forceBlockStyleForStepSequences(doc2.contents);
5322
5734
  return stringifyYamlDocument(doc2);
5323
5735
  }
5324
5736
  }
5325
5737
  const doc = new YAML4.Document();
5326
5738
  doc.contents = doc.createNode(normalized);
5327
5739
  applyKeywordScalarStyles(doc.contents, obj);
5740
+ forceBlockStyleForStepSequences(doc.contents);
5328
5741
  return stringifyYamlDocument(doc);
5329
5742
  } catch (e) {
5330
5743
  return "";
@@ -5368,6 +5781,10 @@ function contentTypeForFormat(format) {
5368
5781
  return "application/octet-stream";
5369
5782
  case "multipart":
5370
5783
  return "multipart/form-data";
5784
+ case "none":
5785
+ return "";
5786
+ case "html":
5787
+ return "text/html";
5371
5788
  case "text":
5372
5789
  default:
5373
5790
  return "text/plain";
@@ -5420,14 +5837,81 @@ function parseUrlEncodedBody(body) {
5420
5837
  });
5421
5838
  return result;
5422
5839
  }
5840
+ function coerceBodyToStructuredObject(body) {
5841
+ if (typeof body !== "string") {
5842
+ return body;
5843
+ }
5844
+ const normalized = normalizeNewlines(body);
5845
+ const trimmed = normalized.trimStart();
5846
+ if (!trimmed) {
5847
+ return "";
5848
+ }
5849
+ if (trimmed.startsWith("<")) {
5850
+ return body;
5851
+ }
5852
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
5853
+ try {
5854
+ return JSON.parse(normalized);
5855
+ } catch {
5856
+ }
5857
+ }
5858
+ try {
5859
+ const parsed = YAML4.parse(normalized);
5860
+ if (parsed !== null && typeof parsed === "object") {
5861
+ return parsed;
5862
+ }
5863
+ } catch {
5864
+ }
5865
+ return normalized;
5866
+ }
5423
5867
  function formatXmlBody(body, pretty, expanded) {
5424
- const xmlObj = typeof body === "string" ? (0, import_xml_js.xml2js)(body, { compact: true }) : body;
5425
- return (0, import_xml_js.js2xml)(xmlObj, {
5868
+ const coerced = coerceBodyToStructuredObject(body);
5869
+ if (coerced === "") {
5870
+ return "";
5871
+ }
5872
+ const xmlObj = typeof coerced === "string" ? (0, import_xml_js2.xml2js)(coerced, { compact: true }) : coerced;
5873
+ return (0, import_xml_js2.js2xml)(xmlObj, {
5426
5874
  compact: true,
5427
5875
  spaces: pretty ? 2 : 0,
5428
5876
  fullTagEmptyElement: expanded
5429
5877
  });
5430
5878
  }
5879
+ function normalizeBodyToJsonObject(body) {
5880
+ if (body === null || body === void 0) {
5881
+ return body;
5882
+ }
5883
+ if (typeof body === "object") {
5884
+ return flattenXmlObj(body);
5885
+ }
5886
+ const normalized = normalizeNewlines(body);
5887
+ if (normalized.trim() === "") {
5888
+ return "";
5889
+ }
5890
+ const coerced = coerceBodyToStructuredObject(normalized);
5891
+ if (coerced === "") {
5892
+ return "";
5893
+ }
5894
+ if (typeof coerced === "object") {
5895
+ return flattenXmlObj(coerced);
5896
+ }
5897
+ const trimmed = coerced.trimStart();
5898
+ if (trimmed.startsWith("<")) {
5899
+ try {
5900
+ return flattenXmlObj((0, import_xml_js2.xml2js)(coerced, { compact: true }));
5901
+ } catch {
5902
+ return coerced;
5903
+ }
5904
+ }
5905
+ try {
5906
+ return JSON.parse(coerced);
5907
+ } catch {
5908
+ try {
5909
+ return YAML4.parse(coerced);
5910
+ } catch {
5911
+ return coerced;
5912
+ }
5913
+ }
5914
+ }
5431
5915
  function formatBody(format, body, pretty = true) {
5432
5916
  if (body === null || body === void 0) {
5433
5917
  return "";
@@ -5440,10 +5924,13 @@ function formatBody(format, body, pretty = true) {
5440
5924
  }
5441
5925
  try {
5442
5926
  if (format === "json") {
5443
- const obj = typeof body === "string" ? YAML4.parse(body) : body;
5444
- if (obj === null || obj === void 0) {
5927
+ const obj = normalizeBodyToJsonObject(body);
5928
+ if (obj === null || obj === void 0 || obj === "") {
5445
5929
  return "";
5446
5930
  }
5931
+ if (typeof obj === "string") {
5932
+ return obj;
5933
+ }
5447
5934
  return pretty ? JSON.stringify(obj, null, 2) : JSON.stringify(obj);
5448
5935
  }
5449
5936
  if (isXmlFormat(format)) {
@@ -5464,7 +5951,13 @@ function formatBody(format, body, pretty = true) {
5464
5951
  }
5465
5952
  return typeof body === "string" ? body : String(body ?? "");
5466
5953
  }
5467
- if (format === "text") {
5954
+ if (format === "html") {
5955
+ if (typeof body !== "string") {
5956
+ return JSON.stringify(body, null, pretty ? 2 : 0);
5957
+ }
5958
+ return pretty ? formatHtmlBody(body) : body;
5959
+ }
5960
+ if (format === "text" || format === "none") {
5468
5961
  return typeof body === "string" ? body : JSON.stringify(body, null, pretty ? 2 : 0);
5469
5962
  }
5470
5963
  return typeof body === "string" ? body : YAML4.stringify(body);
@@ -5493,10 +5986,10 @@ function formattedBodyToYamlObject(format, body) {
5493
5986
  try {
5494
5987
  const text = normalizeNewlines(body);
5495
5988
  if (format === "json") {
5496
- return JSON.parse(text);
5989
+ return normalizeBodyToJsonObject(text);
5497
5990
  }
5498
5991
  if (isXmlFormat(format)) {
5499
- const jsObj = (0, import_xml_js.xml2js)(text, { compact: true });
5992
+ const jsObj = (0, import_xml_js2.xml2js)(text, { compact: true });
5500
5993
  return flattenXmlObj(jsObj);
5501
5994
  }
5502
5995
  if (format === "urlencoded") {
@@ -5512,7 +6005,7 @@ function formattedBodyToYamlObject(format, body) {
5512
6005
  return text;
5513
6006
  }
5514
6007
  }
5515
- if (format === "text") {
6008
+ if (format === "text" || format === "html" || format === "none") {
5516
6009
  return text;
5517
6010
  }
5518
6011
  return YAML4.parse(text);
@@ -5536,7 +6029,7 @@ function packBodyForYamlCompare(yamlBody, uiBody, format) {
5536
6029
  }
5537
6030
  function beautify(format, value) {
5538
6031
  try {
5539
- if (format === "json") {
6032
+ if (format === "json" || format === "multipart") {
5540
6033
  return JSON.stringify(JSON.parse(value), null, 2);
5541
6034
  }
5542
6035
  if (isXmlFormat(format)) {
@@ -5545,6 +6038,9 @@ function beautify(format, value) {
5545
6038
  if (format === "urlencoded") {
5546
6039
  return objectToUrlEncoded(parseUrlEncodedBody(value));
5547
6040
  }
6041
+ if (format === "html") {
6042
+ return formatHtmlBody(value);
6043
+ }
5548
6044
  } catch {
5549
6045
  return value;
5550
6046
  }
@@ -5553,6 +6049,9 @@ function beautify(format, value) {
5553
6049
  function beautifyWithContentType(contentType, value) {
5554
6050
  const trimmedValue = value.trimStart();
5555
6051
  const ct = (contentType || "").toLowerCase();
6052
+ if (ct.includes("html")) {
6053
+ return formatHtmlBody(value);
6054
+ }
5556
6055
  if (ct.includes("json") || trimmedValue.startsWith("{") || trimmedValue.startsWith("[")) {
5557
6056
  return beautify("json", value);
5558
6057
  }
@@ -5564,12 +6063,13 @@ function beautifyWithContentType(contentType, value) {
5564
6063
  }
5565
6064
  return value;
5566
6065
  }
5567
- var import_xml_js, YAML4, markupConvertor_default;
6066
+ var import_xml_js2, YAML4, markupConvertor_default;
5568
6067
  var init_markupConvertor = __esm({
5569
6068
  "../core/src/markupConvertor.ts"() {
5570
6069
  "use strict";
5571
- import_xml_js = require("xml-js");
6070
+ import_xml_js2 = require("xml-js");
5572
6071
  YAML4 = __toESM(require("yaml"));
6072
+ init_htmlFormat();
5573
6073
  init_expectOperatorYaml();
5574
6074
  init_omitKeyword();
5575
6075
  init_omitKeyword();
@@ -5577,6 +6077,7 @@ var init_markupConvertor = __esm({
5577
6077
  init_multilineDescriptionYaml();
5578
6078
  init_textLines();
5579
6079
  init_yamlAstMerge();
6080
+ init_yamlBlockSteps();
5580
6081
  markupConvertor_default = parseYaml;
5581
6082
  }
5582
6083
  });
@@ -6185,32 +6686,54 @@ function sectionToText(section, bodyText, headers, cookies, response) {
6185
6686
  return "";
6186
6687
  }
6187
6688
  }
6689
+ function inferExtractBodyType(response) {
6690
+ const headersLower = Object.fromEntries(Object.entries(response.headers || {}).map(([k, v]) => [k.toLowerCase(), v]));
6691
+ const ct = headersLower["content-type"];
6692
+ if (typeof ct === "string") {
6693
+ const lc = ct.toLowerCase();
6694
+ if (lc.includes("json")) {
6695
+ return "json";
6696
+ }
6697
+ if (lc.includes("xml") && !lc.includes("html")) {
6698
+ return "xml";
6699
+ }
6700
+ return "text";
6701
+ }
6702
+ const body = typeof response.body === "string" ? response.body.trimStart() : "";
6703
+ if (body.startsWith("<?xml")) {
6704
+ return "xml";
6705
+ }
6706
+ if (/^<[a-zA-Z!?]/.test(body)) {
6707
+ if (/^<!DOCTYPE\s+html/i.test(body) || /^<html[\s>]/i.test(body)) {
6708
+ return "text";
6709
+ }
6710
+ return "xml";
6711
+ }
6712
+ if (body.startsWith("{") || body.startsWith("[")) {
6713
+ return "json";
6714
+ }
6715
+ return "text";
6716
+ }
6188
6717
  function extractOutputs(response, outputsDef) {
6189
6718
  const result = {};
6190
6719
  const bodyText = typeof response.body === "string" ? response.body : JSON.stringify(response.body);
6191
6720
  let bodyObject = response.body;
6192
6721
  if (response.type === "auto") {
6193
- const headersLower = Object.fromEntries(Object.entries(response.headers || {}).map(([k, v]) => [k.toLowerCase(), v]));
6194
- const ct = headersLower["content-type"];
6195
- if (typeof ct === "string") {
6196
- response.type = ct.includes("xml") ? "xml" : "json";
6197
- } else {
6198
- response.type = response.body && response.body.startsWith && response.body.startsWith("<") ? "xml" : "json";
6199
- }
6722
+ response.type = inferExtractBodyType(response);
6200
6723
  }
6201
6724
  if (response.type === "xml" && typeof response.body === "string") {
6202
6725
  try {
6203
- const jsObj = (0, import_xml_js2.xml2js)(response.body, { compact: true });
6726
+ const jsObj = (0, import_xml_js3.xml2js)(response.body, { compact: true });
6204
6727
  bodyObject = xmlBodyToExtractable(jsObj);
6205
- } catch (e) {
6206
- console.warn("Failed to parse XML:", e);
6728
+ } catch {
6729
+ console.warn("Failed to parse XML");
6207
6730
  bodyObject = {};
6208
6731
  }
6209
6732
  } else if (response.type === "json" && typeof response.body === "string") {
6210
6733
  try {
6211
6734
  bodyObject = JSON.parse(response.body);
6212
- } catch (e) {
6213
- console.warn("Failed to parse JSON:", e);
6735
+ } catch {
6736
+ console.warn("Failed to parse JSON");
6214
6737
  bodyObject = {};
6215
6738
  }
6216
6739
  }
@@ -6296,11 +6819,11 @@ function extractOutputs(response, outputsDef) {
6296
6819
  function mergeWithDefaultExtractionRules(userOutputs) {
6297
6820
  return { ...DEFAULT_EXTRACTION_RULES, ...userOutputs || {} };
6298
6821
  }
6299
- var import_xml_js2, DEFAULT_EXTRACTION_RULES, DEFAULT_OUTPUT_KEYS;
6822
+ var import_xml_js3, DEFAULT_EXTRACTION_RULES, DEFAULT_OUTPUT_KEYS;
6300
6823
  var init_outputExtractor = __esm({
6301
6824
  "../core/src/outputExtractor.ts"() {
6302
6825
  "use strict";
6303
- import_xml_js2 = require("xml-js");
6826
+ import_xml_js3 = require("xml-js");
6304
6827
  init_omitKeyword();
6305
6828
  init_xmlPath();
6306
6829
  DEFAULT_EXTRACTION_RULES = {
@@ -6363,21 +6886,27 @@ __export(apiParsePack_exports, {
6363
6886
  });
6364
6887
  function parseFormatSpec(raw) {
6365
6888
  if (raw == null) {
6366
- return "json";
6889
+ return void 0;
6367
6890
  }
6368
6891
  if (typeof raw === "string") {
6892
+ if (raw === "auto") {
6893
+ return { request: "auto", response: "auto" };
6894
+ }
6369
6895
  return VALID_FORMAT_VALUES.has(raw) ? raw : "json";
6370
6896
  }
6371
6897
  if (typeof raw === "object" && !Array.isArray(raw)) {
6372
- const request2 = VALID_FORMAT_VALUES.has(raw.request) ? raw.request : void 0;
6898
+ const request2 = VALID_REQUEST_FORMAT_VALUES.has(raw.request) ? raw.request : void 0;
6373
6899
  const responseRaw = raw.response ?? raw.respond;
6374
- const response = VALID_FORMAT_VALUES.has(responseRaw) ? responseRaw : void 0;
6900
+ const response = VALID_RESPONSE_FORMAT_VALUES.has(responseRaw) ? responseRaw : void 0;
6375
6901
  if (!request2 && !response) {
6376
- return "json";
6902
+ return void 0;
6377
6903
  }
6378
- return packFormatSpec({ request: request2, response }) || "json";
6904
+ return packFormatSpec({
6905
+ request: request2 ?? "auto",
6906
+ response: response ?? "auto"
6907
+ });
6379
6908
  }
6380
- return "json";
6909
+ return void 0;
6381
6910
  }
6382
6911
  function parseGraphQLConfig(raw) {
6383
6912
  if (!raw || typeof raw !== "object") {
@@ -6737,7 +7266,7 @@ function apiToYaml(api, originalYaml) {
6737
7266
  ;
6738
7267
  return packYaml(yamlObj, originalYaml);
6739
7268
  }
6740
- var VALID_API_ROOT_KEYS, VALID_GRPC_STREAM_VALUES, VALID_FORMAT_VALUES, VALID_AUTH_TYPES;
7269
+ var VALID_API_ROOT_KEYS, VALID_GRPC_STREAM_VALUES, VALID_FORMAT_VALUES, VALID_REQUEST_FORMAT_VALUES, VALID_RESPONSE_FORMAT_VALUES, VALID_AUTH_TYPES;
6741
7270
  var init_apiParsePack = __esm({
6742
7271
  "../core/src/apiParsePack.ts"() {
6743
7272
  "use strict";
@@ -6769,7 +7298,9 @@ var init_apiParsePack = __esm({
6769
7298
  "examples"
6770
7299
  ]);
6771
7300
  VALID_GRPC_STREAM_VALUES = /* @__PURE__ */ new Set(["server", "client", "bidi"]);
6772
- VALID_FORMAT_VALUES = /* @__PURE__ */ new Set(["json", "xml", "xmle", "text", "urlencoded", "binary", "multipart"]);
7301
+ VALID_FORMAT_VALUES = new Set(FORMAT_VALUES);
7302
+ VALID_REQUEST_FORMAT_VALUES = new Set(REQUEST_FORMAT_VALUES);
7303
+ VALID_RESPONSE_FORMAT_VALUES = new Set(RESPONSE_FORMAT_VALUES);
6773
7304
  VALID_AUTH_TYPES = /* @__PURE__ */ new Set(["bearer", "basic", "api-key", "oauth2"]);
6774
7305
  }
6775
7306
  });
@@ -7922,6 +8453,7 @@ __export(testHelper_exports, {
7922
8453
  registerServer_: () => registerServer_,
7923
8454
  reportWithContext_: () => reportWithContext_,
7924
8455
  report_: () => report_,
8456
+ resolveRequestFormat_: () => resolveRequestFormat,
7925
8457
  setAbortSignal_: () => setAbortSignal_,
7926
8458
  setFileLoader_: () => setFileLoader_,
7927
8459
  setServerRunner_: () => setServerRunner_,
@@ -8416,6 +8948,7 @@ var init_testHelper = __esm({
8416
8948
  init_judgeEngine();
8417
8949
  init_judgeEngineOllama();
8418
8950
  init_judgeEngineProviders();
8951
+ init_formatResolve();
8419
8952
  TestAbortError = class extends Error {
8420
8953
  constructor() {
8421
8954
  super("Test run was stopped");
@@ -55173,8 +55706,8 @@ var require_axios = __commonJS({
55173
55706
  let mapped = key[0].toUpperCase() + key.slice(1);
55174
55707
  return {
55175
55708
  get: () => value,
55176
- set(headerValue2) {
55177
- this[mapped] = headerValue2;
55709
+ set(headerValue3) {
55710
+ this[mapped] = headerValue3;
55178
55711
  }
55179
55712
  };
55180
55713
  });
@@ -57441,6 +57974,19 @@ var require_axios = __commonJS({
57441
57974
  });
57442
57975
 
57443
57976
  // ../core/src/networkCore.ts
57977
+ function getHttpsAgentKey(hostname, port, protocol, config, opts) {
57978
+ const skipValidation = opts?.skipCertificateValidation ?? false;
57979
+ const clientId = opts?.fallbackClientCertId || findMatchingClientCertificate(config.clients, hostname, port, protocol)?.id || "";
57980
+ return [
57981
+ hostname,
57982
+ port || "",
57983
+ String(config.sslValidation),
57984
+ String(skipValidation),
57985
+ String(!!config.ca.enabled),
57986
+ clientId,
57987
+ opts?.forceTls12 ? "tls12" : "tls"
57988
+ ].join(":");
57989
+ }
57444
57990
  function getLegacyRenegotiationSecureOptions() {
57445
57991
  let secureOptions = 0;
57446
57992
  const constants4 = crypto2.constants;
@@ -57503,10 +58049,15 @@ function trackSocketForAgent(socket, host, protocol) {
57503
58049
  }
57504
58050
  function createHttpsAgentWithCertificates(hostname, port, protocol, config, opts) {
57505
58051
  const skipValidation = opts?.skipCertificateValidation ?? false;
58052
+ const agentKey = getHttpsAgentKey(hostname, port, protocol, config, opts);
58053
+ const existingAgent = httpsAgentPool.get(agentKey);
58054
+ if (existingAgent) {
58055
+ return existingAgent;
58056
+ }
57506
58057
  const rejectUnauthorized = skipValidation ? false : config.sslValidation;
57507
58058
  const agentOptions = {
57508
58059
  rejectUnauthorized,
57509
- keepAlive: false,
58060
+ keepAlive: true,
57510
58061
  keepAliveMsecs: 3e4
57511
58062
  };
57512
58063
  applyTlsCompatibilityOptions(agentOptions, { forceTls12: opts?.forceTls12 });
@@ -57538,6 +58089,7 @@ function createHttpsAgentWithCertificates(hostname, port, protocol, config, opts
57538
58089
  trackSocketForAgent(socket, host, "https");
57539
58090
  return socket;
57540
58091
  };
58092
+ httpsAgentPool.set(agentKey, agent);
57541
58093
  return agent;
57542
58094
  }
57543
58095
  function hasUsableClientCertificate(client) {
@@ -57710,9 +58262,10 @@ function sendHttp2Request(req, config, reqHeaders, parsedUrl, requestTimeout, sk
57710
58262
  clearTimeout(timer);
57711
58263
  settle2(() => {
57712
58264
  const status = Number(responseHeaders[":status"] || 0);
58265
+ const headers2 = normalizeHttp2ResponseHeaders(responseHeaders);
57713
58266
  resolve2({
57714
- body: Buffer.concat(chunks).toString("utf8"),
57715
- headers: normalizeHttp2ResponseHeaders(responseHeaders),
58267
+ body: normalizeHttpResponseBody(Buffer.concat(chunks), headers2),
58268
+ headers: headers2,
57716
58269
  status,
57717
58270
  statusText: http3.STATUS_CODES[status] || "",
57718
58271
  duration: Date.now() - start,
@@ -57788,7 +58341,7 @@ function sendNativeHttpsRequest(req, config, reqHeaders, parsedUrl, requestTimeo
57788
58341
  }
57789
58342
  }
57790
58343
  resolve2({
57791
- body: Buffer.concat(chunks).toString("utf8"),
58344
+ body: normalizeHttpResponseBody(Buffer.concat(chunks), headersOut),
57792
58345
  headers: headersOut,
57793
58346
  status: res.statusCode || 0,
57794
58347
  statusText: res.statusMessage || "",
@@ -57914,7 +58467,7 @@ async function sendHttpRequest(req, config) {
57914
58467
  withCredentials: true,
57915
58468
  headers: reqHeaders,
57916
58469
  timeout: requestTimeout,
57917
- responseType: "text",
58470
+ responseType: "arraybuffer",
57918
58471
  transformResponse: [(data) => data]
57919
58472
  };
57920
58473
  const executeRequest = (skipValidation = false, fallbackClientCertId, opts) => {
@@ -57942,9 +58495,10 @@ async function sendHttpRequest(req, config) {
57942
58495
  const start = Date.now();
57943
58496
  const toSuccess = (response, warning) => {
57944
58497
  const duration = Date.now() - start;
58498
+ const headers = normalizeAxiosHeaders(response.headers);
57945
58499
  return {
57946
- body: response.data,
57947
- headers: normalizeAxiosHeaders(response.headers),
58500
+ body: normalizeHttpResponseBody(response.data, headers),
58501
+ headers,
57948
58502
  status: response.status,
57949
58503
  statusText: response.statusText,
57950
58504
  duration,
@@ -57955,9 +58509,13 @@ async function sendHttpRequest(req, config) {
57955
58509
  const toError = (err, warning) => {
57956
58510
  const duration = Date.now() - start;
57957
58511
  if (err?.response) {
58512
+ const headers = normalizeAxiosHeaders(err.response.headers);
57958
58513
  return {
57959
- body: err.response.data,
57960
- headers: normalizeAxiosHeaders(err.response.headers),
58514
+ body: normalizeHttpResponseBody(
58515
+ err.response.data ?? err.response.body ?? err.response.text,
58516
+ headers
58517
+ ),
58518
+ headers,
57961
58519
  status: err.response.status,
57962
58520
  statusText: err.response.statusText,
57963
58521
  duration,
@@ -58079,9 +58637,10 @@ function extractBodyFromError(err) {
58079
58637
  }
58080
58638
  try {
58081
58639
  if (err.response) {
58640
+ const headers = normalizeAxiosHeaders(err.response.headers || {});
58082
58641
  const d = err.response.data ?? err.response.body ?? err.response.text;
58083
- if (typeof d === "string") {
58084
- return d;
58642
+ if (typeof d === "string" || d instanceof ArrayBuffer || d instanceof Uint8Array) {
58643
+ return normalizeHttpResponseBody(d, headers);
58085
58644
  }
58086
58645
  try {
58087
58646
  return JSON.stringify(d);
@@ -58101,7 +58660,14 @@ function extractBodyFromError(err) {
58101
58660
  try {
58102
58661
  const bufs = state.buffer.map((b) => b.data).filter(Boolean);
58103
58662
  if (bufs.length > 0) {
58104
- return Buffer.concat(bufs).toString("utf8");
58663
+ const headers = {};
58664
+ const rawHeaders = reqRes.headers || {};
58665
+ for (const [key, value] of Object.entries(rawHeaders)) {
58666
+ if (value !== void 0) {
58667
+ headers[key] = Array.isArray(value) ? value.join(", ") : String(value);
58668
+ }
58669
+ }
58670
+ return normalizeHttpResponseBody(Buffer.concat(bufs), headers);
58105
58671
  }
58106
58672
  } catch {
58107
58673
  }
@@ -58371,7 +58937,7 @@ async function send(req) {
58371
58937
  throw new Error(`Unsupported protocol: ${protocol}`);
58372
58938
  }
58373
58939
  }
58374
- var crypto2, http3, http22, https3, axios2, httpAgentPool, socketConnectionIds, trackedSockets, SELF_SIGNED_TLS_CODES, SELF_SIGNED_MESSAGE_FRAGMENTS, CLIENT_CERTIFICATE_REQUIRED_CODES, CLIENT_CERTIFICATE_REQUIRED_MESSAGE_FRAGMENTS, runnerNetworkConfig;
58940
+ var crypto2, http3, http22, https3, axios2, httpAgentPool, httpsAgentPool, socketConnectionIds, trackedSockets, SELF_SIGNED_TLS_CODES, SELF_SIGNED_MESSAGE_FRAGMENTS, CLIENT_CERTIFICATE_REQUIRED_CODES, CLIENT_CERTIFICATE_REQUIRED_MESSAGE_FRAGMENTS, runnerNetworkConfig;
58375
58941
  var init_networkCore = __esm({
58376
58942
  "../core/src/networkCore.ts"() {
58377
58943
  "use strict";
@@ -58380,12 +58946,14 @@ var init_networkCore = __esm({
58380
58946
  http22 = __toESM(require("http2"));
58381
58947
  https3 = __toESM(require("https"));
58382
58948
  init_wrapper();
58949
+ init_binaryBody();
58383
58950
  init_connectionTracker();
58384
58951
  init_apiMethod();
58385
58952
  init_NetworkData();
58386
58953
  init_connectionTracker();
58387
58954
  axios2 = require_axios();
58388
58955
  httpAgentPool = /* @__PURE__ */ new Map();
58956
+ httpsAgentPool = /* @__PURE__ */ new Map();
58389
58957
  socketConnectionIds = /* @__PURE__ */ new WeakMap();
58390
58958
  trackedSockets = /* @__PURE__ */ new WeakSet();
58391
58959
  SELF_SIGNED_TLS_CODES = /* @__PURE__ */ new Set([
@@ -65135,6 +65703,7 @@ __export(src_exports, {
65135
65703
  reportParser: () => reportParser_exports,
65136
65704
  resolveApiRequest: () => resolveApiRequest,
65137
65705
  runConfig: () => runConfig_exports,
65706
+ runFileCache: () => runFileCache_exports,
65138
65707
  runner: () => runner_exports,
65139
65708
  setenvResolve: () => setenvResolve_exports,
65140
65709
  statusIcons: () => statusIcons_exports,
@@ -65177,8 +65746,10 @@ __export(JSer_exports, {
65177
65746
  // ../core/src/JSerAPI.ts
65178
65747
  init_apiMethod();
65179
65748
  init_CommonData();
65749
+ init_formatResolve();
65180
65750
  init_JSerHelper();
65181
65751
  init_markupConvertor();
65752
+ init_multipartBody();
65182
65753
  init_omitKeyword();
65183
65754
  init_outputExtractor();
65184
65755
  init_variableReplacer();
@@ -65198,7 +65769,12 @@ var apiToJSfunc = async (ctx) => {
65198
65769
  { resolveRuntimeTokens: false }
65199
65770
  );
65200
65771
  replaced = stripOmitFromRequest(replaced);
65201
- const reqFormatForBody = requestFormat(replaced.format);
65772
+ const declaredReqFormat = requestFormat(replaced.format);
65773
+ const reqFormatForBody = resolveRequestFormat(
65774
+ declaredReqFormat,
65775
+ replaced.headers || {},
65776
+ replaced.method
65777
+ );
65202
65778
  if (reqFormatForBody !== "binary" && replaced.body != null) {
65203
65779
  replaced = {
65204
65780
  ...replaced,
@@ -65261,7 +65837,8 @@ var apiToJSfunc = async (ctx) => {
65261
65837
  }
65262
65838
  const protocolExpr = isGraphQL ? `'graphql'` : explicitProtocol ? `'${explicitProtocol}'` : `protocolFromUrl_(__resolvedUrl)`;
65263
65839
  const effectiveMethod = isGraphQL ? "post" : resolveApiHttpMethod(replaced.method, replaced.body);
65264
- const reqFormat = requestFormat(replaced.format);
65840
+ const reqFormat = reqFormatForBody;
65841
+ const isNoneRequest = !isGraphQL && reqFormat === "none";
65265
65842
  const isBinaryRequest = !isGraphQL && reqFormat === "binary";
65266
65843
  const isMultipartRequest = !isGraphQL && reqFormat === "multipart";
65267
65844
  if (isGraphQL) {
@@ -65273,7 +65850,7 @@ var apiToJSfunc = async (ctx) => {
65273
65850
  replaced.headers["Content-Type"] = "application/json";
65274
65851
  headers = Object.entries(replaced.headers).map(([k, v]) => `"${k}": ${toTemplateWithEnvs(String(v))}`).join(", ");
65275
65852
  }
65276
- } else if (reqFormat === "urlencoded" || reqFormat === "binary") {
65853
+ } else if (reqFormat === "urlencoded" || reqFormat === "binary" || reqFormat === "html") {
65277
65854
  const hasContentType = Object.keys(replaced.headers || {}).some(
65278
65855
  (k) => k.toLowerCase() === "content-type"
65279
65856
  );
@@ -65299,7 +65876,7 @@ var apiToJSfunc = async (ctx) => {
65299
65876
  const binaryPathSource = typeof replaced.body === "string" ? replaced.body.trim() : replaced.body == null ? "" : String(replaced.body);
65300
65877
  const binaryPathExpr = toTemplateWithEnvs(binaryPathSource);
65301
65878
  const multipartPartsExpr = isMultipartRequest ? multipartPartsToJs(replaced.body, toTemplateWithEnvs) : "[]";
65302
- const bodyExpr = isGraphQL && graphqlBodyExpr ? graphqlBodyExpr : isBinaryRequest ? "__binaryBody_" : isMultipartRequest ? "__multipartParts_" : toTemplateWithEnvs(formattedBody);
65879
+ const bodyExpr = isGraphQL && graphqlBodyExpr ? graphqlBodyExpr : isNoneRequest ? "undefined" : isBinaryRequest ? "__binaryBody_" : isMultipartRequest ? "__multipartParts_" : toTemplateWithEnvs(formattedBody);
65303
65880
  const binaryLoadLines = isBinaryRequest ? ` const __binaryPath_ = ${binaryPathExpr};
65304
65881
  const __binaryBody_ = await readBinaryFile_(__binaryPath_);
65305
65882
  ` : "";
@@ -65324,7 +65901,8 @@ ${binaryLoadLines}${multipartPrepLines} const req_ = {
65324
65901
  body: ${bodyExpr}
65325
65902
  };
65326
65903
  ${authCode}
65327
- applyOmitToRequest_(req_, '${reqFormat}');
65904
+ ${declaredReqFormat === "auto" ? `const __reqFormat_ = resolveRequestFormat_('auto', req_.headers, req_.body);
65905
+ applyOmitToRequest_(req_, __reqFormat_);` : `applyOmitToRequest_(req_, '${declaredReqFormat}');`}
65328
65906
  ${multipartBuildLines} const res_ = await send_(req_);
65329
65907
 
65330
65908
  const __extractSource_ = {
@@ -65457,10 +66035,11 @@ ${authCode}
65457
66035
  };`;
65458
66036
  }
65459
66037
  function multipartPartsToJs(parts, toTpl) {
65460
- if (!Array.isArray(parts) || parts.length === 0) {
66038
+ const coerced = coerceMultipartPartsInput(parts);
66039
+ if (!Array.isArray(coerced) || coerced.length === 0) {
65461
66040
  return "[]";
65462
66041
  }
65463
- const entries = parts.map((raw) => {
66042
+ const entries = coerced.map((raw) => {
65464
66043
  const part = raw;
65465
66044
  const fields = [`name: ${JSON.stringify(String(part.name ?? ""))}`];
65466
66045
  if (part.file != null && String(part.file).trim() !== "") {
@@ -66247,6 +66826,7 @@ __export(testParsePack_exports, {
66247
66826
  STAGE_KEY_ORDER: () => STAGE_KEY_ORDER,
66248
66827
  STEP_KEY_ORDER: () => STEP_KEY_ORDER,
66249
66828
  getTestFlowStepType: () => getTestFlowStepType,
66829
+ peekTestMetaFromYaml: () => peekTestMetaFromYaml,
66250
66830
  quoteExpectOperators: () => quoteExpectOperators,
66251
66831
  testToYaml: () => testToYaml,
66252
66832
  validateTestData: () => validateTestData,
@@ -66402,7 +66982,11 @@ function reorderStep(step) {
66402
66982
  const order = STEP_KEY_ORDER[stepType];
66403
66983
  let ordered = order ? reorderKeys(step, order) : { ...step };
66404
66984
  if (Array.isArray(ordered.steps)) {
66405
- ordered.steps = reorderSteps(ordered.steps);
66985
+ if (ordered.steps.length > 0) {
66986
+ ordered.steps = reorderSteps(ordered.steps);
66987
+ } else if (stepType === "if" || stepType === "for" || stepType === "repeat" || stepType === "stage") {
66988
+ delete ordered.steps;
66989
+ }
66406
66990
  }
66407
66991
  if (Array.isArray(ordered.else)) {
66408
66992
  ordered.else = reorderSteps(ordered.else);
@@ -66480,6 +67064,22 @@ function normalizeTestFlowStages(stages) {
66480
67064
  return normalized;
66481
67065
  });
66482
67066
  }
67067
+ function peekTestMetaFromYaml(yamlContent) {
67068
+ try {
67069
+ const doc = markupConvertor_default(quoteExpectOperators(yamlContent));
67070
+ if (!doc || typeof doc !== "object") {
67071
+ return {};
67072
+ }
67073
+ const title = typeof doc.title === "string" && doc.title.trim() ? doc.title.trim() : void 0;
67074
+ const tags = Array.isArray(doc.tags) ? doc.tags.map((t) => String(t).trim()).filter(Boolean) : void 0;
67075
+ return {
67076
+ title,
67077
+ tags: tags?.length ? tags : void 0
67078
+ };
67079
+ } catch {
67080
+ return {};
67081
+ }
67082
+ }
66483
67083
  function yamlToTest(yamlContent) {
66484
67084
  try {
66485
67085
  const doc = markupConvertor_default(quoteExpectOperators(yamlContent));
@@ -66957,7 +67557,7 @@ var collectVariables = (document2) => {
66957
67557
  };
66958
67558
  var inferFormat = (formatHint, headers, body) => {
66959
67559
  const hint = String(formatHint || "").toLowerCase();
66960
- if (hint === "json" || hint === "xml" || hint === "xmle" || hint === "text" || hint === "urlencoded") {
67560
+ if (hint === "json" || hint === "xml" || hint === "xmle" || hint === "text" || hint === "html" || hint === "urlencoded") {
66961
67561
  return hint;
66962
67562
  }
66963
67563
  if (hint === "form-urlencoded" || hint === "form_urlencoded" || hint === "form") {
@@ -66968,6 +67568,9 @@ var inferFormat = (formatHint, headers, body) => {
66968
67568
  if (contentType.includes("json")) {
66969
67569
  return "json";
66970
67570
  }
67571
+ if (contentType.includes("html")) {
67572
+ return "html";
67573
+ }
66971
67574
  if (contentType.includes("xml")) {
66972
67575
  return "xml";
66973
67576
  }
@@ -67382,6 +67985,9 @@ var inferFormat2 = (headers, body) => {
67382
67985
  if (contentType.includes("json")) {
67383
67986
  return "json";
67384
67987
  }
67988
+ if (contentType.includes("html")) {
67989
+ return "html";
67990
+ }
67385
67991
  if (contentType.includes("xml")) {
67386
67992
  return "xml";
67387
67993
  }
@@ -67931,6 +68537,116 @@ function validateJudgeObject(obj) {
67931
68537
  // ../core/src/JSerImports.ts
67932
68538
  init_outputExtractor();
67933
68539
  init_variableReplacer();
68540
+
68541
+ // ../core/src/runFileCache.ts
68542
+ var runFileCache_exports = {};
68543
+ __export(runFileCache_exports, {
68544
+ CACHED_IMPORT_FN: () => CACHED_IMPORT_FN,
68545
+ RunFileCache: () => RunFileCache,
68546
+ bindCachedImportFn: () => bindCachedImportFn,
68547
+ getRunFileCache: () => getRunFileCache,
68548
+ resetRunFileCache: () => resetRunFileCache
68549
+ });
68550
+ var CACHED_IMPORT_FN = "__mmt_cached_fn__";
68551
+ function normalizePath2(p) {
68552
+ return String(p ?? "").replace(/\\/g, "/");
68553
+ }
68554
+ function hashText(s) {
68555
+ let h = 2166136261;
68556
+ for (let i = 0; i < s.length; i++) {
68557
+ h ^= s.charCodeAt(i);
68558
+ h = Math.imul(h, 16777619);
68559
+ }
68560
+ return (h >>> 0).toString(16);
68561
+ }
68562
+ function bindCachedImportFn(js, publicName) {
68563
+ if (!js || !publicName) {
68564
+ return js;
68565
+ }
68566
+ return js.split(CACHED_IMPORT_FN).join(publicName);
68567
+ }
68568
+ var RunFileCache = class {
68569
+ constructor() {
68570
+ this.text = /* @__PURE__ */ new Map();
68571
+ this.pending = /* @__PURE__ */ new Map();
68572
+ this.importJs = /* @__PURE__ */ new Map();
68573
+ }
68574
+ reset() {
68575
+ this.text.clear();
68576
+ this.pending.clear();
68577
+ this.importJs.clear();
68578
+ }
68579
+ /**
68580
+ * Call at the start of a top-level run.
68581
+ * With a stamp function, any changed cached file resets the whole cache.
68582
+ * Without a stamp function we cannot know, so the cache is cleared.
68583
+ */
68584
+ async beginRun(stamp) {
68585
+ this.stampFn = stamp;
68586
+ if (!stamp) {
68587
+ this.reset();
68588
+ return;
68589
+ }
68590
+ for (const [path8, entry] of this.text.entries()) {
68591
+ let next = "";
68592
+ try {
68593
+ next = String(await stamp(path8));
68594
+ } catch {
68595
+ next = "missing";
68596
+ }
68597
+ if (next !== entry.stamp) {
68598
+ this.reset();
68599
+ return;
68600
+ }
68601
+ }
68602
+ }
68603
+ wrap(loader) {
68604
+ return async (requestedPath) => {
68605
+ const key = normalizePath2(requestedPath);
68606
+ const hit = this.text.get(key);
68607
+ if (hit) {
68608
+ return hit.content;
68609
+ }
68610
+ let pending = this.pending.get(key);
68611
+ if (!pending) {
68612
+ pending = (async () => {
68613
+ const content = await loader(requestedPath);
68614
+ let stamp = "";
68615
+ if (this.stampFn) {
68616
+ try {
68617
+ stamp = String(await this.stampFn(requestedPath));
68618
+ } catch {
68619
+ stamp = "missing";
68620
+ }
68621
+ }
68622
+ this.text.set(key, { content, stamp });
68623
+ this.pending.delete(key);
68624
+ return content;
68625
+ })();
68626
+ this.pending.set(key, pending);
68627
+ }
68628
+ return pending;
68629
+ };
68630
+ }
68631
+ getImportJs(resolvedPath, content) {
68632
+ return this.importJs.get(this.importKey(resolvedPath, content));
68633
+ }
68634
+ setImportJs(resolvedPath, content, entry) {
68635
+ this.importJs.set(this.importKey(resolvedPath, content), entry);
68636
+ }
68637
+ importKey(resolvedPath, content) {
68638
+ return `${normalizePath2(resolvedPath)}\0${hashText(content)}`;
68639
+ }
68640
+ };
68641
+ var shared = new RunFileCache();
68642
+ function getRunFileCache() {
68643
+ return shared;
68644
+ }
68645
+ function resetRunFileCache() {
68646
+ shared.reset();
68647
+ }
68648
+
68649
+ // ../core/src/JSerImports.ts
67934
68650
  var ImportCodeError = class extends Error {
67935
68651
  constructor(detail, path8) {
67936
68652
  const cleaned = String(detail ?? "").replace(/^Import error(?: in [^:]+)?:\s*/i, "");
@@ -68108,28 +68824,50 @@ var emitResolved = async (resolved, publicNameForPath, tracker, projectRoot) =>
68108
68824
  projectRoot,
68109
68825
  fileLoader: readFile
68110
68826
  });
68827
+ const cache = getRunFileCache();
68828
+ const cached = cache.getImportJs(resolvedPath, processedContent);
68829
+ if (cached) {
68830
+ if (cached.title) {
68831
+ tracker.setFileTitle(resolvedPath, cached.title);
68832
+ }
68833
+ if (cached.inputKeys) {
68834
+ tracker.setInputKeys(resolvedPath, cached.inputKeys);
68835
+ }
68836
+ if (cached.outputKeys) {
68837
+ tracker.setOutputKeys(resolvedPath, cached.outputKeys);
68838
+ }
68839
+ results.push(bindCachedImportFn(cached.js, publicName) + "\n");
68840
+ continue;
68841
+ }
68111
68842
  const api = yamlToAPIStrict(processedContent);
68112
68843
  if (api.title) {
68113
68844
  tracker.setFileTitle(resolvedPath, api.title);
68114
68845
  }
68115
- if (api.inputs && typeof api.inputs === "object") {
68116
- tracker.setInputKeys(resolvedPath, Object.keys(api.inputs));
68846
+ const inputKeys = api.inputs && typeof api.inputs === "object" ? Object.keys(api.inputs) : void 0;
68847
+ if (inputKeys) {
68848
+ tracker.setInputKeys(resolvedPath, inputKeys);
68117
68849
  }
68850
+ let outputKeys;
68118
68851
  if (api.outputs && typeof api.outputs === "object") {
68119
68852
  const userKeys = Object.keys(api.outputs);
68120
- const allKeys = [.../* @__PURE__ */ new Set([...DEFAULT_OUTPUT_KEYS, ...userKeys])];
68121
- tracker.setOutputKeys(resolvedPath, allKeys);
68853
+ outputKeys = [.../* @__PURE__ */ new Set([...DEFAULT_OUTPUT_KEYS, ...userKeys])];
68122
68854
  } else {
68123
- tracker.setOutputKeys(resolvedPath, [...DEFAULT_OUTPUT_KEYS]);
68124
- }
68125
- results.push(
68126
- await apiToJSfunc({
68127
- api,
68128
- name: publicName,
68129
- inputs: {},
68130
- envVars: {}
68131
- }) + "\n"
68132
- );
68855
+ outputKeys = [...DEFAULT_OUTPUT_KEYS];
68856
+ }
68857
+ tracker.setOutputKeys(resolvedPath, outputKeys);
68858
+ const js = await apiToJSfunc({
68859
+ api,
68860
+ name: CACHED_IMPORT_FN,
68861
+ inputs: {},
68862
+ envVars: {}
68863
+ });
68864
+ cache.setImportJs(resolvedPath, processedContent, {
68865
+ js,
68866
+ title: api.title,
68867
+ inputKeys,
68868
+ outputKeys
68869
+ });
68870
+ results.push(bindCachedImportFn(js, publicName) + "\n");
68133
68871
  } else if (type === "csv") {
68134
68872
  results.push(await csvToJSObj(content, publicName) + "\n");
68135
68873
  } else if (isDataImportPath(resolvedPath)) {
@@ -70664,9 +71402,9 @@ function buildCurlParts(input, certificates) {
70664
71402
  parts.push({ kind: "pair", flag: "-X", value: method });
70665
71403
  }
70666
71404
  Object.entries(input.headers || {}).forEach(([key, value]) => {
70667
- const headerValue2 = stringifyCurlValue(value);
70668
- if (headerValue2) {
70669
- parts.push({ kind: "pair", flag: "-H", value: `${key}: ${headerValue2}` });
71405
+ const headerValue3 = stringifyCurlValue(value);
71406
+ if (headerValue3) {
71407
+ parts.push({ kind: "pair", flag: "-H", value: `${key}: ${headerValue3}` });
70670
71408
  }
70671
71409
  });
70672
71410
  const cookiePairs = Object.entries(input.cookies || {}).map(([key, value]) => {
@@ -70956,6 +71694,7 @@ init_variableReplacer();
70956
71694
 
70957
71695
  // ../core/src/resolveApiRequest.ts
70958
71696
  init_CommonData();
71697
+ init_formatResolve();
70959
71698
  init_apiParsePack();
70960
71699
  init_markupConvertor();
70961
71700
  init_omitKeyword();
@@ -70967,7 +71706,10 @@ function resolveApiRequest(api, inputs, envParameters, options = {}) {
70967
71706
  inputs,
70968
71707
  envParameters,
70969
71708
  /* @__PURE__ */ new Set(),
70970
- { refreshRuntimeTokens: options.refreshRuntimeTokens }
71709
+ {
71710
+ refreshRuntimeTokens: options.refreshRuntimeTokens,
71711
+ resolveRuntimeTokens: options.preserveStructuredBody ? false : void 0
71712
+ }
70971
71713
  );
70972
71714
  request2 = stripOmitFromRequest(request2);
70973
71715
  if (request2.auth) {
@@ -70982,8 +71724,13 @@ function resolveApiRequest(api, inputs, envParameters, options = {}) {
70982
71724
  }
70983
71725
  delete request2.auth;
70984
71726
  }
70985
- if (request2.body && typeof request2.body !== "string") {
70986
- request2.body = formatBody(requestFormat(request2.format), request2.body ?? "");
71727
+ const reqFormat = resolveRequestFormat(
71728
+ requestFormat(request2.format),
71729
+ request2.headers,
71730
+ request2.method
71731
+ );
71732
+ if (!options.preserveStructuredBody && request2.body && typeof request2.body !== "string" && reqFormat !== "multipart") {
71733
+ request2.body = formatBody(reqFormat, request2.body ?? "");
70987
71734
  }
70988
71735
  return request2;
70989
71736
  }
@@ -73522,6 +74269,7 @@ __export(postmanConvertor_exports, {
73522
74269
  postmanToAPI: () => postmanToAPI,
73523
74270
  translatePostmanTemplate: () => translatePostmanTemplate
73524
74271
  });
74272
+ init_CommonData();
73525
74273
  init_omitKeyword();
73526
74274
  init_Random();
73527
74275
  var POSTMAN_RANDOM_MAP = {
@@ -73579,6 +74327,44 @@ function translatePostmanTemplate(str) {
73579
74327
  function replacePostmanVars(str) {
73580
74328
  return translatePostmanTemplate(str);
73581
74329
  }
74330
+ function headerValue(headers, name) {
74331
+ if (!headers) {
74332
+ return void 0;
74333
+ }
74334
+ const key = Object.keys(headers).find(
74335
+ (entry) => entry.toLowerCase() === name.toLowerCase()
74336
+ );
74337
+ const value = key ? headers[key] : void 0;
74338
+ return typeof value === "string" ? value : void 0;
74339
+ }
74340
+ function formatFromMediaType(value) {
74341
+ if (!value) {
74342
+ return void 0;
74343
+ }
74344
+ const lc = value.toLowerCase();
74345
+ if (lc.includes("json")) {
74346
+ return "json";
74347
+ }
74348
+ if (lc.includes("xml") && !lc.includes("html")) {
74349
+ return "xml";
74350
+ }
74351
+ if (lc.includes("urlencoded")) {
74352
+ return "urlencoded";
74353
+ }
74354
+ if (lc.includes("multipart")) {
74355
+ return "multipart";
74356
+ }
74357
+ if (lc.includes("octet-stream") || lc.includes("protobuf") || lc.includes("application/pdf") || lc.startsWith("image/") || lc.startsWith("audio/") || lc.startsWith("video/")) {
74358
+ return "binary";
74359
+ }
74360
+ if (lc.includes("html")) {
74361
+ return "html";
74362
+ }
74363
+ if (lc.includes("text") || lc.includes("javascript")) {
74364
+ return "text";
74365
+ }
74366
+ return void 0;
74367
+ }
73582
74368
  function reviveUnquotedMmtTokens(value) {
73583
74369
  if (typeof value === "string") {
73584
74370
  const match = /^__MMT_UNQUOTED_(.+?)__$/.exec(value);
@@ -73920,16 +74706,21 @@ function postmanToAPI(postmanJson) {
73920
74706
  } else if (request2.body?.mode === "file") {
73921
74707
  format = { request: "binary", response: "json" };
73922
74708
  } else {
73923
- const contentType = headers?.["content-type"] ?? headers?.["Content-Type"];
73924
- if (typeof contentType === "string") {
73925
- const lc = contentType.toLowerCase();
73926
- if (lc.includes("xml")) {
73927
- format = "xml";
73928
- } else if (lc.includes("urlencoded") || lc.includes("x-www-form-urlencoded")) {
73929
- format = "urlencoded";
73930
- } else if (lc.includes("text")) {
73931
- format = "text";
73932
- }
74709
+ const contentType = headerValue(headers, "content-type");
74710
+ const fromContentType = formatFromMediaType(contentType);
74711
+ if (fromContentType) {
74712
+ format = fromContentType;
74713
+ }
74714
+ }
74715
+ const acceptFormat = formatFromMediaType(headerValue(headers, "accept"));
74716
+ if (acceptFormat) {
74717
+ if (!request2.body) {
74718
+ format = acceptFormat === "binary" || acceptFormat === "multipart" ? packFormatSpec({ request: "json", response: acceptFormat }) || acceptFormat : acceptFormat;
74719
+ } else {
74720
+ format = packFormatSpec({
74721
+ request: requestFormat(format),
74722
+ response: toResponseFormat(acceptFormat)
74723
+ }) || acceptFormat;
73933
74724
  }
73934
74725
  }
73935
74726
  let protocol = void 0;
@@ -75125,8 +75916,7 @@ function convertHttpToMmt(rawFile, options) {
75125
75916
  const stepId = safeStepIdFromAlias(alias);
75126
75917
  const step = {
75127
75918
  call: alias,
75128
- id: stepId,
75129
- debug: true
75919
+ id: stepId
75130
75920
  };
75131
75921
  const { expect, setenv } = httpRequestCallExtras(request2, stepId);
75132
75922
  if (expect && Object.keys(expect).length > 0) {
@@ -75178,8 +75968,7 @@ function convertBrunoToMmt(rawFile, options) {
75178
75968
  const inlineStep = test2.steps?.[0];
75179
75969
  const step = {
75180
75970
  call: alias,
75181
- id: safeStepIdFromAlias(alias),
75182
- debug: true
75971
+ id: safeStepIdFromAlias(alias)
75183
75972
  };
75184
75973
  if (inlineStep && "expect" in inlineStep && inlineStep.expect && Object.keys(inlineStep.expect).length > 0) {
75185
75974
  step.expect = inlineStep.expect;
@@ -75374,8 +76163,7 @@ function buildPostmanTests(requestFiles, scriptMode, warnings, useProjectRootImp
75374
76163
  }
75375
76164
  const step = {
75376
76165
  call: requestFile.alias,
75377
- id: safeStepIdFromAlias(requestFile.alias),
75378
- debug: true
76166
+ id: safeStepIdFromAlias(requestFile.alias)
75379
76167
  };
75380
76168
  const expect = buildPostmanExpect(requestFile.item, scriptMode, warnings);
75381
76169
  if (expect && Object.keys(expect).length > 0) {
@@ -76040,6 +76828,10 @@ var CREATE_API_LOG_HELPERS_SOURCE = `function createApiLogHelpers() {
76040
76828
  if (body === null || body === undefined || body === '') {
76041
76829
  return '';
76042
76830
  }
76831
+ if (body && typeof body === 'object' && body.__mmtBinary === true &&
76832
+ typeof body.byteLength === 'number') {
76833
+ return \`<binary \${body.byteLength} bytes>\`;
76834
+ }
76043
76835
  if (typeof Buffer !== 'undefined' && Buffer.isBuffer(body)) {
76044
76836
  return \`<binary \${body.length} bytes>\`;
76045
76837
  }
@@ -76267,10 +77059,16 @@ async function runGeneratedJs(runId, js, name, logger, jsRunner, stepReporter, i
76267
77059
  };
76268
77060
  }
76269
77061
  }
76270
- function resolveRelativeTo(targetPath, baseFilePath) {
77062
+ function resolveRelativeTo(targetPath, baseFilePath, projectRoot) {
76271
77063
  if (!targetPath) {
76272
77064
  return targetPath;
76273
77065
  }
77066
+ if (isProjectRootImport(targetPath)) {
77067
+ if (projectRoot) {
77068
+ return resolveProjectRootImport(targetPath, projectRoot);
77069
+ }
77070
+ return targetPath;
77071
+ }
76274
77072
  if (targetPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(targetPath)) {
76275
77073
  return targetPath;
76276
77074
  }
@@ -76866,7 +77664,7 @@ async function executeApi(prepared, options, preLogs) {
76866
77664
  prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
76867
77665
  void 0,
76868
77666
  void 0,
76869
- void 0,
77667
+ options.checkLogMode,
76870
77668
  "API",
76871
77669
  options.binaryFileLoader
76872
77670
  );
@@ -77136,6 +77934,9 @@ function createReportCollector() {
77136
77934
  // ../core/src/suiteBundleRunner.ts
77137
77935
  init_runLog();
77138
77936
  init_testHelper();
77937
+ function resolveSuitePath(targetPath, baseFilePath, options) {
77938
+ return resolveRelativeTo(targetPath, baseFilePath, options.projectRoot);
77939
+ }
77139
77940
  async function startListedServers(params) {
77140
77941
  const { servers, baseFilePath, options, suiteLogger } = params;
77141
77942
  for (const serverPath of servers) {
@@ -77143,7 +77944,7 @@ async function startListedServers(params) {
77143
77944
  suiteLogger("warn", "Suite run cancelled before servers could start.");
77144
77945
  return false;
77145
77946
  }
77146
- const resolvedPath = resolveRelativeTo(serverPath, baseFilePath);
77947
+ const resolvedPath = resolveSuitePath(serverPath, baseFilePath, options);
77147
77948
  const display = basename3(resolvedPath || serverPath);
77148
77949
  if (!options.serverRunner) {
77149
77950
  suiteLogger("error", `Cannot start server '${display}': no server runner provided`);
@@ -77242,7 +78043,7 @@ function reportSkippedBundleNode(params) {
77242
78043
  const { node, bundle, options, nextIndex } = params;
77243
78044
  const currentIndex = nextIndex();
77244
78045
  const suiteRunNonce = typeof options.suiteRunId === "string" ? options.suiteRunId : "";
77245
- const filePath = node.kind === "group" ? bundle.rootSuitePath : resolveRelativeTo(node.path, bundle.rootSuitePath);
78046
+ const filePath = node.kind === "group" ? bundle.rootSuitePath : resolveSuitePath(node.path, bundle.rootSuitePath, options);
77246
78047
  const title = node.kind === "group" ? typeof node.label === "string" && node.label.trim() ? node.label.trim() : node.id : typeof node.title === "string" && node.title.trim() ? node.title.trim() : basename3(filePath || node.path);
77247
78048
  const runId = `suite:${sanitizeIdentifier(bundle.rootSuitePath)}:${suiteRunNonce}:${currentIndex}:${sanitizeIdentifier(node.id)}`;
77248
78049
  options.reporter && options.reporter({
@@ -77288,7 +78089,7 @@ async function runSuiteBundleNode(params) {
77288
78089
  return reportSkippedBundleNode({ node, bundle, options, nextIndex });
77289
78090
  }
77290
78091
  const currentIndex = nextIndex();
77291
- const childFilePath = resolveRelativeTo(node.path, bundle.rootSuitePath);
78092
+ const childFilePath = resolveSuitePath(node.path, bundle.rootSuitePath, options);
77292
78093
  const nodeTitle = typeof node.title === "string" && node.title.trim() ? node.title.trim() : void 0;
77293
78094
  const display = nodeTitle || basename3(childFilePath || node.path);
77294
78095
  const suiteRunNonce = typeof options.suiteRunId === "string" ? options.suiteRunId : "";
@@ -77309,11 +78110,11 @@ async function runSuiteBundleNode(params) {
77309
78110
  const childDocType = detectDocType(childFilePath, childRawText);
77310
78111
  childLogger("debug", `Running suite item: ${display}`);
77311
78112
  const childFileLoader = async (requestedPath) => {
77312
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
78113
+ const resolved = resolveSuitePath(requestedPath, childFilePath, options);
77313
78114
  return await baseFileLoader(resolved);
77314
78115
  };
77315
78116
  const childBinaryFileLoader = options.binaryFileLoader ? async (requestedPath) => {
77316
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
78117
+ const resolved = resolveSuitePath(requestedPath, childFilePath, options);
77317
78118
  return await options.binaryFileLoader(resolved);
77318
78119
  } : void 0;
77319
78120
  options.reporter && options.reporter({
@@ -77468,7 +78269,7 @@ async function runSuiteGroup(params) {
77468
78269
  statuses: serverStatuses
77469
78270
  };
77470
78271
  }
77471
- const nestedPath = resolveRelativeTo(child.path, bundle.rootSuitePath) || child.path;
78272
+ const nestedPath = resolveSuitePath(child.path, bundle.rootSuitePath, options) || child.path;
77472
78273
  const started = await startListedServers({
77473
78274
  servers: child.servers,
77474
78275
  baseFilePath: nestedPath,
@@ -77561,7 +78362,7 @@ async function runSuiteGroup(params) {
77561
78362
  }
77562
78363
  async function startServerNode(params) {
77563
78364
  const { node, bundle, options, suiteLogger } = params;
77564
- const serverFilePath = resolveRelativeTo(node.path, bundle.rootSuitePath);
78365
+ const serverFilePath = resolveSuitePath(node.path, bundle.rootSuitePath, options);
77565
78366
  const display = basename3(serverFilePath || node.path);
77566
78367
  if (!options.serverRunner) {
77567
78368
  suiteLogger("error", `Cannot start server '${node.path}': no server runner provided`);
@@ -77740,7 +78541,7 @@ async function executeSuiteBundle(params) {
77740
78541
  const suiteRunNonce = typeof effectiveOptions.suiteRunId === "string" ? effectiveOptions.suiteRunId : "";
77741
78542
  const targetRunId = `suite:${sanitizeIdentifier(bundle.rootSuitePath)}:${suiteRunNonce}:target:${sanitizeIdentifier(root.id)}`;
77742
78543
  const targetTitle = root.kind === "suite" ? typeof root.title === "string" && root.title.trim() ? root.title.trim() : basename3(root.path) : typeof root.label === "string" && root.label.trim() ? root.label.trim() : root.id;
77743
- const targetFilePath = root.kind === "suite" ? resolveRelativeTo(root.path, bundle.rootSuitePath) : bundle.rootSuitePath;
78544
+ const targetFilePath = root.kind === "suite" ? resolveSuitePath(root.path, bundle.rootSuitePath, effectiveOptions) : bundle.rootSuitePath;
77744
78545
  const targetEntry = root.kind === "suite" ? root.path : root.label;
77745
78546
  effectiveOptions.reporter && effectiveOptions.reporter({
77746
78547
  scope: "suite-item",
@@ -78345,7 +79146,7 @@ function optionalTags(tags) {
78345
79146
  return out.length ? out : void 0;
78346
79147
  }
78347
79148
  async function buildSuiteHierarchyFromSuiteFile(params) {
78348
- const { suiteFilePath, suiteRawText, fileLoader, leafPrefix } = params;
79149
+ const { suiteFilePath, suiteRawText, fileLoader, leafPrefix, projectRoot } = params;
78349
79150
  const convertSuiteToHierarchy = async (targetFilePath, rawText, indexPath, ancestors) => {
78350
79151
  const suiteDoc = yamlToSuite(rawText);
78351
79152
  const nextAncestors = new Set(ancestors);
@@ -78423,7 +79224,7 @@ async function buildSuiteHierarchyFromSuiteFile(params) {
78423
79224
  if (!trimmed || trimmed === "then") {
78424
79225
  return null;
78425
79226
  }
78426
- const resolvedPath = resolveRelativeTo(trimmed, ownerFilePath) || trimmed;
79227
+ const resolvedPath = resolveRelativeTo(trimmed, ownerFilePath, projectRoot) || trimmed;
78427
79228
  let raw = "";
78428
79229
  try {
78429
79230
  raw = await fileLoader(resolvedPath);
@@ -78438,11 +79239,23 @@ async function buildSuiteHierarchyFromSuiteFile(params) {
78438
79239
  let title;
78439
79240
  let tags;
78440
79241
  try {
78441
- const testDoc = isHttpFilePath(resolvedPath) ? httpToTest(raw, resolvedPath) : isBrunoFilePath(resolvedPath) ? brunoToTest(raw, resolvedPath) : yamlToTest(raw);
78442
- if (typeof testDoc?.title === "string" && testDoc.title.trim()) {
78443
- title = testDoc.title.trim();
79242
+ if (isHttpFilePath(resolvedPath)) {
79243
+ const testDoc = httpToTest(raw, resolvedPath);
79244
+ if (typeof testDoc?.title === "string" && testDoc.title.trim()) {
79245
+ title = testDoc.title.trim();
79246
+ }
79247
+ tags = optionalTags(testDoc?.tags);
79248
+ } else if (isBrunoFilePath(resolvedPath)) {
79249
+ const testDoc = brunoToTest(raw, resolvedPath);
79250
+ if (typeof testDoc?.title === "string" && testDoc.title.trim()) {
79251
+ title = testDoc.title.trim();
79252
+ }
79253
+ tags = optionalTags(testDoc?.tags);
79254
+ } else {
79255
+ const meta = peekTestMetaFromYaml(raw);
79256
+ title = meta.title;
79257
+ tags = optionalTags(meta.tags);
78444
79258
  }
78445
- tags = optionalTags(testDoc?.tags);
78446
79259
  } catch {
78447
79260
  }
78448
79261
  const testNode = {
@@ -78700,7 +79513,7 @@ async function executeTest(prepared, options, preLogs) {
78700
79513
  prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
78701
79514
  options.__mmtIsSuiteBundleChildRun === true,
78702
79515
  void 0,
78703
- void 0,
79516
+ options.checkLogMode,
78704
79517
  "Test",
78705
79518
  options.binaryFileLoader
78706
79519
  );
@@ -78892,7 +79705,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
78892
79705
  const envVars = prepared.envVarsUsed || options.envvar || {};
78893
79706
  const displayName = prepared.title || prepared.baseName;
78894
79707
  const identifier = sanitizeIdentifier(displayName);
78895
- const childFilePath = resolveRelativeTo(loadtest.test, prepared.filePath);
79708
+ const childFilePath = resolveRelativeTo(loadtest.test, prepared.filePath, options.projectRoot);
78896
79709
  const childDisplayName = basename3(childFilePath || loadtest.test);
78897
79710
  const threads = Math.max(1, Math.floor(loadtest.threads || 1));
78898
79711
  const repeatIterations = parsePositiveInteger(loadtest.repeat);
@@ -79077,7 +79890,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
79077
79890
  throw new Error(`Failed to load loadtest target ${loadtest.test}: ${e?.message || String(e)}`);
79078
79891
  }
79079
79892
  const childFileLoader = async (requestedPath) => {
79080
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
79893
+ const resolved = resolveRelativeTo(requestedPath, childFilePath, options.projectRoot);
79081
79894
  return await options.fileLoader(resolved);
79082
79895
  };
79083
79896
  try {
@@ -79143,7 +79956,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
79143
79956
  };
79144
79957
  try {
79145
79958
  const childBinaryFileLoader = options.binaryFileLoader ? async (requestedPath) => {
79146
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
79959
+ const resolved = resolveRelativeTo(requestedPath, childFilePath, options.projectRoot);
79147
79960
  return await options.binaryFileLoader(resolved);
79148
79961
  } : void 0;
79149
79962
  const childResult = await runGeneratedJs(
@@ -79362,6 +80175,13 @@ async function prepareRunFromOptions(options, log = () => {
79362
80175
  async function runFile(options) {
79363
80176
  resetCurrentTokenCache();
79364
80177
  resetRandomTokenCache();
80178
+ if (!options.__mmtIsSuiteBundleChildRun) {
80179
+ const cache = getRunFileCache();
80180
+ await cache.beginRun(options.fileStamp);
80181
+ if (typeof options.fileLoader === "function") {
80182
+ options = { ...options, fileLoader: cache.wrap(options.fileLoader) };
80183
+ }
80184
+ }
79365
80185
  const preLogs = [];
79366
80186
  const note = (level, message) => {
79367
80187
  preLogs.push({ level, message });
@@ -79406,7 +80226,8 @@ async function runFile(options) {
79406
80226
  const tree = await buildSuiteHierarchyFromSuiteFile({
79407
80227
  suiteFilePath: prepared.filePath,
79408
80228
  suiteRawText: prepared.rawText,
79409
- fileLoader: options.fileLoader
80229
+ fileLoader: options.fileLoader,
80230
+ projectRoot: options.projectRoot
79410
80231
  });
79411
80232
  bundle = createSuiteBundle({
79412
80233
  rootSuitePath: prepared.filePath,
@@ -80144,7 +80965,7 @@ var mmtReport_exports = {};
80144
80965
  __export(mmtReport_exports, {
80145
80966
  generateMmtReport: () => generateMmtReport
80146
80967
  });
80147
- var import_yaml2 = __toESM(require("yaml"));
80968
+ var import_yaml3 = __toESM(require("yaml"));
80148
80969
  init_CommonData();
80149
80970
  function displayValue3(v) {
80150
80971
  if (v === null || v === void 0) {
@@ -80325,7 +81146,7 @@ function generateMmtReport(results, options) {
80325
81146
  if (!isLoad) {
80326
81147
  report.checks = runs.map(buildCheckEntry);
80327
81148
  }
80328
- return import_yaml2.default.stringify(report, { lineWidth: 0 });
81149
+ return import_yaml3.default.stringify(report, { lineWidth: 0 });
80329
81150
  }
80330
81151
 
80331
81152
  // ../core/src/reportHtml.ts
@@ -81355,7 +82176,7 @@ __export(reportMarkdown_exports, {
81355
82176
  init_CommonData();
81356
82177
  init_markupConvertor();
81357
82178
  init_omitKeyword();
81358
- function headerValue(headers, name) {
82179
+ function headerValue2(headers, name) {
81359
82180
  if (!headers) {
81360
82181
  return void 0;
81361
82182
  }
@@ -81368,7 +82189,7 @@ function headerValue(headers, name) {
81368
82189
  return void 0;
81369
82190
  }
81370
82191
  function detectBodyFormat(body, headers) {
81371
- const contentType = (headerValue(headers, "content-type") || "").toLowerCase();
82192
+ const contentType = (headerValue2(headers, "content-type") || "").toLowerCase();
81372
82193
  if (contentType.includes("json")) {
81373
82194
  return "json";
81374
82195
  }
@@ -81420,7 +82241,7 @@ function formatBodyValue(value, headers) {
81420
82241
  }
81421
82242
  }
81422
82243
  const format = detectBodyFormat(value, headers);
81423
- const contentType = headerValue(headers, "content-type") || "";
82244
+ const contentType = headerValue2(headers, "content-type") || "";
81424
82245
  if (format === "urlencoded") {
81425
82246
  try {
81426
82247
  return { text: prettyUrlEncoded(value), format };
@@ -82862,21 +83683,21 @@ async function buildCliRunArgs(file, opts) {
82862
83683
  envvar = mergeEnv2({ envvar: void 0, manualEnvvars });
82863
83684
  }
82864
83685
  if (suiteEnvConfig) {
82865
- const projectRoot = findProjectRootForCli(full);
83686
+ const projectRoot2 = findProjectRootForCli(full);
82866
83687
  let suitePresetEnv = {};
82867
83688
  if (suiteEnvConfig.preset) {
82868
83689
  let suiteEnvFilePath;
82869
83690
  if (suiteEnvConfig.file) {
82870
83691
  if (suiteEnvConfig.file.startsWith("+/")) {
82871
- suiteEnvFilePath = projectRoot ? import_path2.default.join(projectRoot, suiteEnvConfig.file.slice(2)) : void 0;
83692
+ suiteEnvFilePath = projectRoot2 ? import_path2.default.join(projectRoot2, suiteEnvConfig.file.slice(2)) : void 0;
82872
83693
  } else {
82873
83694
  suiteEnvFilePath = import_path2.default.resolve(dir, suiteEnvConfig.file);
82874
83695
  }
82875
- } else if (projectRoot) {
82876
- suiteEnvFilePath = import_path2.default.join(projectRoot, "multimeter.mmt");
83696
+ } else if (projectRoot2) {
83697
+ suiteEnvFilePath = import_path2.default.join(projectRoot2, "multimeter.mmt");
82877
83698
  }
82878
83699
  if (suiteEnvFilePath && import_fs2.default.existsSync(suiteEnvFilePath)) {
82879
- const suiteEnvDoc = await loadEnvDoc(suiteEnvFilePath, projectRoot || void 0);
83700
+ const suiteEnvDoc = await loadEnvDoc(suiteEnvFilePath, projectRoot2 || void 0);
82880
83701
  suitePresetEnv = resolvePresetsEnv2(suiteEnvDoc, suiteEnvConfig.preset);
82881
83702
  }
82882
83703
  }
@@ -82887,6 +83708,13 @@ async function buildCliRunArgs(file, opts) {
82887
83708
  const suiteVariables = suiteEnvConfig.variables ? { ...suiteEnvConfig.variables } : {};
82888
83709
  envvar = { ...baseEnv, ...suitePresetEnv, ...suiteVariables, ...manualEnvvars };
82889
83710
  }
83711
+ const projectRoot = findProjectRootForCli(full);
83712
+ const resolveCliFilePath = (requested) => {
83713
+ if (isProjectRootImport(requested) && projectRoot) {
83714
+ return resolveProjectRootImport(requested, projectRoot);
83715
+ }
83716
+ return (0, import_pathNormalize.resolveUserPath)(requested, dir, import_path2.default);
83717
+ };
82890
83718
  const runFileOptions = {
82891
83719
  file: rawText,
82892
83720
  fileType: "raw",
@@ -82897,14 +83725,23 @@ async function buildCliRunArgs(file, opts) {
82897
83725
  envvar,
82898
83726
  manualEnvvars,
82899
83727
  fileLoader: async (p) => {
82900
- const rel = (0, import_pathNormalize.resolveUserPath)(p, dir, import_path2.default);
83728
+ const rel = resolveCliFilePath(p);
82901
83729
  if (!import_fs2.default.existsSync(rel)) {
82902
83730
  return "";
82903
83731
  }
82904
83732
  return import_fs2.default.readFileSync(rel, "utf8");
82905
83733
  },
83734
+ fileStamp: async (p) => {
83735
+ const rel = resolveCliFilePath(p);
83736
+ try {
83737
+ const st = import_fs2.default.statSync(rel);
83738
+ return `${st.size}:${st.mtimeMs}`;
83739
+ } catch {
83740
+ return "missing";
83741
+ }
83742
+ },
82906
83743
  binaryFileLoader: async (p) => {
82907
- const rel = (0, import_pathNormalize.resolveUserPath)(p, dir, import_path2.default);
83744
+ const rel = resolveCliFilePath(p);
82908
83745
  return import_fs2.default.promises.readFile(rel);
82909
83746
  },
82910
83747
  jsRunner: async () => {
@@ -82918,7 +83755,8 @@ async function buildCliRunArgs(file, opts) {
82918
83755
  },
82919
83756
  reporter: (_message) => {
82920
83757
  },
82921
- projectRoot: findProjectRootForCli(full)
83758
+ projectRoot,
83759
+ checkLogMode: opts.quiet ? "none" : "default"
82922
83760
  };
82923
83761
  const onlyTags = Array.isArray(opts.tag) ? opts.tag : [];
82924
83762
  const skipTags = Array.isArray(opts.skipTag) ? opts.skipTag : [];
@@ -84235,8 +85073,8 @@ utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
84235
85073
  let mapped = key[0].toUpperCase() + key.slice(1);
84236
85074
  return {
84237
85075
  get: () => value,
84238
- set(headerValue2) {
84239
- this[mapped] = headerValue2;
85076
+ set(headerValue3) {
85077
+ this[mapped] = headerValue3;
84240
85078
  }
84241
85079
  };
84242
85080
  });