mmt-testlight 1.43.0-pre → 1.43.1-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.1-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() !== "") {
@@ -66402,7 +66981,11 @@ function reorderStep(step) {
66402
66981
  const order = STEP_KEY_ORDER[stepType];
66403
66982
  let ordered = order ? reorderKeys(step, order) : { ...step };
66404
66983
  if (Array.isArray(ordered.steps)) {
66405
- ordered.steps = reorderSteps(ordered.steps);
66984
+ if (ordered.steps.length > 0) {
66985
+ ordered.steps = reorderSteps(ordered.steps);
66986
+ } else if (stepType === "if" || stepType === "for" || stepType === "repeat" || stepType === "stage") {
66987
+ delete ordered.steps;
66988
+ }
66406
66989
  }
66407
66990
  if (Array.isArray(ordered.else)) {
66408
66991
  ordered.else = reorderSteps(ordered.else);
@@ -66957,7 +67540,7 @@ var collectVariables = (document2) => {
66957
67540
  };
66958
67541
  var inferFormat = (formatHint, headers, body) => {
66959
67542
  const hint = String(formatHint || "").toLowerCase();
66960
- if (hint === "json" || hint === "xml" || hint === "xmle" || hint === "text" || hint === "urlencoded") {
67543
+ if (hint === "json" || hint === "xml" || hint === "xmle" || hint === "text" || hint === "html" || hint === "urlencoded") {
66961
67544
  return hint;
66962
67545
  }
66963
67546
  if (hint === "form-urlencoded" || hint === "form_urlencoded" || hint === "form") {
@@ -66968,6 +67551,9 @@ var inferFormat = (formatHint, headers, body) => {
66968
67551
  if (contentType.includes("json")) {
66969
67552
  return "json";
66970
67553
  }
67554
+ if (contentType.includes("html")) {
67555
+ return "html";
67556
+ }
66971
67557
  if (contentType.includes("xml")) {
66972
67558
  return "xml";
66973
67559
  }
@@ -67382,6 +67968,9 @@ var inferFormat2 = (headers, body) => {
67382
67968
  if (contentType.includes("json")) {
67383
67969
  return "json";
67384
67970
  }
67971
+ if (contentType.includes("html")) {
67972
+ return "html";
67973
+ }
67385
67974
  if (contentType.includes("xml")) {
67386
67975
  return "xml";
67387
67976
  }
@@ -67931,6 +68520,116 @@ function validateJudgeObject(obj) {
67931
68520
  // ../core/src/JSerImports.ts
67932
68521
  init_outputExtractor();
67933
68522
  init_variableReplacer();
68523
+
68524
+ // ../core/src/runFileCache.ts
68525
+ var runFileCache_exports = {};
68526
+ __export(runFileCache_exports, {
68527
+ CACHED_IMPORT_FN: () => CACHED_IMPORT_FN,
68528
+ RunFileCache: () => RunFileCache,
68529
+ bindCachedImportFn: () => bindCachedImportFn,
68530
+ getRunFileCache: () => getRunFileCache,
68531
+ resetRunFileCache: () => resetRunFileCache
68532
+ });
68533
+ var CACHED_IMPORT_FN = "__mmt_cached_fn__";
68534
+ function normalizePath2(p) {
68535
+ return String(p ?? "").replace(/\\/g, "/");
68536
+ }
68537
+ function hashText(s) {
68538
+ let h = 2166136261;
68539
+ for (let i = 0; i < s.length; i++) {
68540
+ h ^= s.charCodeAt(i);
68541
+ h = Math.imul(h, 16777619);
68542
+ }
68543
+ return (h >>> 0).toString(16);
68544
+ }
68545
+ function bindCachedImportFn(js, publicName) {
68546
+ if (!js || !publicName) {
68547
+ return js;
68548
+ }
68549
+ return js.split(CACHED_IMPORT_FN).join(publicName);
68550
+ }
68551
+ var RunFileCache = class {
68552
+ constructor() {
68553
+ this.text = /* @__PURE__ */ new Map();
68554
+ this.pending = /* @__PURE__ */ new Map();
68555
+ this.importJs = /* @__PURE__ */ new Map();
68556
+ }
68557
+ reset() {
68558
+ this.text.clear();
68559
+ this.pending.clear();
68560
+ this.importJs.clear();
68561
+ }
68562
+ /**
68563
+ * Call at the start of a top-level run.
68564
+ * With a stamp function, any changed cached file resets the whole cache.
68565
+ * Without a stamp function we cannot know, so the cache is cleared.
68566
+ */
68567
+ async beginRun(stamp) {
68568
+ this.stampFn = stamp;
68569
+ if (!stamp) {
68570
+ this.reset();
68571
+ return;
68572
+ }
68573
+ for (const [path8, entry] of this.text.entries()) {
68574
+ let next = "";
68575
+ try {
68576
+ next = String(await stamp(path8));
68577
+ } catch {
68578
+ next = "missing";
68579
+ }
68580
+ if (next !== entry.stamp) {
68581
+ this.reset();
68582
+ return;
68583
+ }
68584
+ }
68585
+ }
68586
+ wrap(loader) {
68587
+ return async (requestedPath) => {
68588
+ const key = normalizePath2(requestedPath);
68589
+ const hit = this.text.get(key);
68590
+ if (hit) {
68591
+ return hit.content;
68592
+ }
68593
+ let pending = this.pending.get(key);
68594
+ if (!pending) {
68595
+ pending = (async () => {
68596
+ const content = await loader(requestedPath);
68597
+ let stamp = "";
68598
+ if (this.stampFn) {
68599
+ try {
68600
+ stamp = String(await this.stampFn(requestedPath));
68601
+ } catch {
68602
+ stamp = "missing";
68603
+ }
68604
+ }
68605
+ this.text.set(key, { content, stamp });
68606
+ this.pending.delete(key);
68607
+ return content;
68608
+ })();
68609
+ this.pending.set(key, pending);
68610
+ }
68611
+ return pending;
68612
+ };
68613
+ }
68614
+ getImportJs(resolvedPath, content) {
68615
+ return this.importJs.get(this.importKey(resolvedPath, content));
68616
+ }
68617
+ setImportJs(resolvedPath, content, entry) {
68618
+ this.importJs.set(this.importKey(resolvedPath, content), entry);
68619
+ }
68620
+ importKey(resolvedPath, content) {
68621
+ return `${normalizePath2(resolvedPath)}\0${hashText(content)}`;
68622
+ }
68623
+ };
68624
+ var shared = new RunFileCache();
68625
+ function getRunFileCache() {
68626
+ return shared;
68627
+ }
68628
+ function resetRunFileCache() {
68629
+ shared.reset();
68630
+ }
68631
+
68632
+ // ../core/src/JSerImports.ts
67934
68633
  var ImportCodeError = class extends Error {
67935
68634
  constructor(detail, path8) {
67936
68635
  const cleaned = String(detail ?? "").replace(/^Import error(?: in [^:]+)?:\s*/i, "");
@@ -68108,28 +68807,50 @@ var emitResolved = async (resolved, publicNameForPath, tracker, projectRoot) =>
68108
68807
  projectRoot,
68109
68808
  fileLoader: readFile
68110
68809
  });
68810
+ const cache = getRunFileCache();
68811
+ const cached = cache.getImportJs(resolvedPath, processedContent);
68812
+ if (cached) {
68813
+ if (cached.title) {
68814
+ tracker.setFileTitle(resolvedPath, cached.title);
68815
+ }
68816
+ if (cached.inputKeys) {
68817
+ tracker.setInputKeys(resolvedPath, cached.inputKeys);
68818
+ }
68819
+ if (cached.outputKeys) {
68820
+ tracker.setOutputKeys(resolvedPath, cached.outputKeys);
68821
+ }
68822
+ results.push(bindCachedImportFn(cached.js, publicName) + "\n");
68823
+ continue;
68824
+ }
68111
68825
  const api = yamlToAPIStrict(processedContent);
68112
68826
  if (api.title) {
68113
68827
  tracker.setFileTitle(resolvedPath, api.title);
68114
68828
  }
68115
- if (api.inputs && typeof api.inputs === "object") {
68116
- tracker.setInputKeys(resolvedPath, Object.keys(api.inputs));
68829
+ const inputKeys = api.inputs && typeof api.inputs === "object" ? Object.keys(api.inputs) : void 0;
68830
+ if (inputKeys) {
68831
+ tracker.setInputKeys(resolvedPath, inputKeys);
68117
68832
  }
68833
+ let outputKeys;
68118
68834
  if (api.outputs && typeof api.outputs === "object") {
68119
68835
  const userKeys = Object.keys(api.outputs);
68120
- const allKeys = [.../* @__PURE__ */ new Set([...DEFAULT_OUTPUT_KEYS, ...userKeys])];
68121
- tracker.setOutputKeys(resolvedPath, allKeys);
68836
+ outputKeys = [.../* @__PURE__ */ new Set([...DEFAULT_OUTPUT_KEYS, ...userKeys])];
68122
68837
  } 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
- );
68838
+ outputKeys = [...DEFAULT_OUTPUT_KEYS];
68839
+ }
68840
+ tracker.setOutputKeys(resolvedPath, outputKeys);
68841
+ const js = await apiToJSfunc({
68842
+ api,
68843
+ name: CACHED_IMPORT_FN,
68844
+ inputs: {},
68845
+ envVars: {}
68846
+ });
68847
+ cache.setImportJs(resolvedPath, processedContent, {
68848
+ js,
68849
+ title: api.title,
68850
+ inputKeys,
68851
+ outputKeys
68852
+ });
68853
+ results.push(bindCachedImportFn(js, publicName) + "\n");
68133
68854
  } else if (type === "csv") {
68134
68855
  results.push(await csvToJSObj(content, publicName) + "\n");
68135
68856
  } else if (isDataImportPath(resolvedPath)) {
@@ -70664,9 +71385,9 @@ function buildCurlParts(input, certificates) {
70664
71385
  parts.push({ kind: "pair", flag: "-X", value: method });
70665
71386
  }
70666
71387
  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}` });
71388
+ const headerValue3 = stringifyCurlValue(value);
71389
+ if (headerValue3) {
71390
+ parts.push({ kind: "pair", flag: "-H", value: `${key}: ${headerValue3}` });
70670
71391
  }
70671
71392
  });
70672
71393
  const cookiePairs = Object.entries(input.cookies || {}).map(([key, value]) => {
@@ -70956,6 +71677,7 @@ init_variableReplacer();
70956
71677
 
70957
71678
  // ../core/src/resolveApiRequest.ts
70958
71679
  init_CommonData();
71680
+ init_formatResolve();
70959
71681
  init_apiParsePack();
70960
71682
  init_markupConvertor();
70961
71683
  init_omitKeyword();
@@ -70967,7 +71689,10 @@ function resolveApiRequest(api, inputs, envParameters, options = {}) {
70967
71689
  inputs,
70968
71690
  envParameters,
70969
71691
  /* @__PURE__ */ new Set(),
70970
- { refreshRuntimeTokens: options.refreshRuntimeTokens }
71692
+ {
71693
+ refreshRuntimeTokens: options.refreshRuntimeTokens,
71694
+ resolveRuntimeTokens: options.preserveStructuredBody ? false : void 0
71695
+ }
70971
71696
  );
70972
71697
  request2 = stripOmitFromRequest(request2);
70973
71698
  if (request2.auth) {
@@ -70982,8 +71707,13 @@ function resolveApiRequest(api, inputs, envParameters, options = {}) {
70982
71707
  }
70983
71708
  delete request2.auth;
70984
71709
  }
70985
- if (request2.body && typeof request2.body !== "string") {
70986
- request2.body = formatBody(requestFormat(request2.format), request2.body ?? "");
71710
+ const reqFormat = resolveRequestFormat(
71711
+ requestFormat(request2.format),
71712
+ request2.headers,
71713
+ request2.method
71714
+ );
71715
+ if (!options.preserveStructuredBody && request2.body && typeof request2.body !== "string" && reqFormat !== "multipart") {
71716
+ request2.body = formatBody(reqFormat, request2.body ?? "");
70987
71717
  }
70988
71718
  return request2;
70989
71719
  }
@@ -73522,6 +74252,7 @@ __export(postmanConvertor_exports, {
73522
74252
  postmanToAPI: () => postmanToAPI,
73523
74253
  translatePostmanTemplate: () => translatePostmanTemplate
73524
74254
  });
74255
+ init_CommonData();
73525
74256
  init_omitKeyword();
73526
74257
  init_Random();
73527
74258
  var POSTMAN_RANDOM_MAP = {
@@ -73579,6 +74310,44 @@ function translatePostmanTemplate(str) {
73579
74310
  function replacePostmanVars(str) {
73580
74311
  return translatePostmanTemplate(str);
73581
74312
  }
74313
+ function headerValue(headers, name) {
74314
+ if (!headers) {
74315
+ return void 0;
74316
+ }
74317
+ const key = Object.keys(headers).find(
74318
+ (entry) => entry.toLowerCase() === name.toLowerCase()
74319
+ );
74320
+ const value = key ? headers[key] : void 0;
74321
+ return typeof value === "string" ? value : void 0;
74322
+ }
74323
+ function formatFromMediaType(value) {
74324
+ if (!value) {
74325
+ return void 0;
74326
+ }
74327
+ const lc = value.toLowerCase();
74328
+ if (lc.includes("json")) {
74329
+ return "json";
74330
+ }
74331
+ if (lc.includes("xml") && !lc.includes("html")) {
74332
+ return "xml";
74333
+ }
74334
+ if (lc.includes("urlencoded")) {
74335
+ return "urlencoded";
74336
+ }
74337
+ if (lc.includes("multipart")) {
74338
+ return "multipart";
74339
+ }
74340
+ if (lc.includes("octet-stream") || lc.includes("protobuf") || lc.includes("application/pdf") || lc.startsWith("image/") || lc.startsWith("audio/") || lc.startsWith("video/")) {
74341
+ return "binary";
74342
+ }
74343
+ if (lc.includes("html")) {
74344
+ return "html";
74345
+ }
74346
+ if (lc.includes("text") || lc.includes("javascript")) {
74347
+ return "text";
74348
+ }
74349
+ return void 0;
74350
+ }
73582
74351
  function reviveUnquotedMmtTokens(value) {
73583
74352
  if (typeof value === "string") {
73584
74353
  const match = /^__MMT_UNQUOTED_(.+?)__$/.exec(value);
@@ -73920,16 +74689,21 @@ function postmanToAPI(postmanJson) {
73920
74689
  } else if (request2.body?.mode === "file") {
73921
74690
  format = { request: "binary", response: "json" };
73922
74691
  } 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
- }
74692
+ const contentType = headerValue(headers, "content-type");
74693
+ const fromContentType = formatFromMediaType(contentType);
74694
+ if (fromContentType) {
74695
+ format = fromContentType;
74696
+ }
74697
+ }
74698
+ const acceptFormat = formatFromMediaType(headerValue(headers, "accept"));
74699
+ if (acceptFormat) {
74700
+ if (!request2.body) {
74701
+ format = acceptFormat === "binary" || acceptFormat === "multipart" ? packFormatSpec({ request: "json", response: acceptFormat }) || acceptFormat : acceptFormat;
74702
+ } else {
74703
+ format = packFormatSpec({
74704
+ request: requestFormat(format),
74705
+ response: toResponseFormat(acceptFormat)
74706
+ }) || acceptFormat;
73933
74707
  }
73934
74708
  }
73935
74709
  let protocol = void 0;
@@ -75125,8 +75899,7 @@ function convertHttpToMmt(rawFile, options) {
75125
75899
  const stepId = safeStepIdFromAlias(alias);
75126
75900
  const step = {
75127
75901
  call: alias,
75128
- id: stepId,
75129
- debug: true
75902
+ id: stepId
75130
75903
  };
75131
75904
  const { expect, setenv } = httpRequestCallExtras(request2, stepId);
75132
75905
  if (expect && Object.keys(expect).length > 0) {
@@ -75178,8 +75951,7 @@ function convertBrunoToMmt(rawFile, options) {
75178
75951
  const inlineStep = test2.steps?.[0];
75179
75952
  const step = {
75180
75953
  call: alias,
75181
- id: safeStepIdFromAlias(alias),
75182
- debug: true
75954
+ id: safeStepIdFromAlias(alias)
75183
75955
  };
75184
75956
  if (inlineStep && "expect" in inlineStep && inlineStep.expect && Object.keys(inlineStep.expect).length > 0) {
75185
75957
  step.expect = inlineStep.expect;
@@ -75374,8 +76146,7 @@ function buildPostmanTests(requestFiles, scriptMode, warnings, useProjectRootImp
75374
76146
  }
75375
76147
  const step = {
75376
76148
  call: requestFile.alias,
75377
- id: safeStepIdFromAlias(requestFile.alias),
75378
- debug: true
76149
+ id: safeStepIdFromAlias(requestFile.alias)
75379
76150
  };
75380
76151
  const expect = buildPostmanExpect(requestFile.item, scriptMode, warnings);
75381
76152
  if (expect && Object.keys(expect).length > 0) {
@@ -76040,6 +76811,10 @@ var CREATE_API_LOG_HELPERS_SOURCE = `function createApiLogHelpers() {
76040
76811
  if (body === null || body === undefined || body === '') {
76041
76812
  return '';
76042
76813
  }
76814
+ if (body && typeof body === 'object' && body.__mmtBinary === true &&
76815
+ typeof body.byteLength === 'number') {
76816
+ return \`<binary \${body.byteLength} bytes>\`;
76817
+ }
76043
76818
  if (typeof Buffer !== 'undefined' && Buffer.isBuffer(body)) {
76044
76819
  return \`<binary \${body.length} bytes>\`;
76045
76820
  }
@@ -76267,10 +77042,16 @@ async function runGeneratedJs(runId, js, name, logger, jsRunner, stepReporter, i
76267
77042
  };
76268
77043
  }
76269
77044
  }
76270
- function resolveRelativeTo(targetPath, baseFilePath) {
77045
+ function resolveRelativeTo(targetPath, baseFilePath, projectRoot) {
76271
77046
  if (!targetPath) {
76272
77047
  return targetPath;
76273
77048
  }
77049
+ if (isProjectRootImport(targetPath)) {
77050
+ if (projectRoot) {
77051
+ return resolveProjectRootImport(targetPath, projectRoot);
77052
+ }
77053
+ return targetPath;
77054
+ }
76274
77055
  if (targetPath.startsWith("/") || /^[A-Za-z]:[\\/]/.test(targetPath)) {
76275
77056
  return targetPath;
76276
77057
  }
@@ -76866,7 +77647,7 @@ async function executeApi(prepared, options, preLogs) {
76866
77647
  prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
76867
77648
  void 0,
76868
77649
  void 0,
76869
- void 0,
77650
+ options.checkLogMode,
76870
77651
  "API",
76871
77652
  options.binaryFileLoader
76872
77653
  );
@@ -77136,6 +77917,9 @@ function createReportCollector() {
77136
77917
  // ../core/src/suiteBundleRunner.ts
77137
77918
  init_runLog();
77138
77919
  init_testHelper();
77920
+ function resolveSuitePath(targetPath, baseFilePath, options) {
77921
+ return resolveRelativeTo(targetPath, baseFilePath, options.projectRoot);
77922
+ }
77139
77923
  async function startListedServers(params) {
77140
77924
  const { servers, baseFilePath, options, suiteLogger } = params;
77141
77925
  for (const serverPath of servers) {
@@ -77143,7 +77927,7 @@ async function startListedServers(params) {
77143
77927
  suiteLogger("warn", "Suite run cancelled before servers could start.");
77144
77928
  return false;
77145
77929
  }
77146
- const resolvedPath = resolveRelativeTo(serverPath, baseFilePath);
77930
+ const resolvedPath = resolveSuitePath(serverPath, baseFilePath, options);
77147
77931
  const display = basename3(resolvedPath || serverPath);
77148
77932
  if (!options.serverRunner) {
77149
77933
  suiteLogger("error", `Cannot start server '${display}': no server runner provided`);
@@ -77242,7 +78026,7 @@ function reportSkippedBundleNode(params) {
77242
78026
  const { node, bundle, options, nextIndex } = params;
77243
78027
  const currentIndex = nextIndex();
77244
78028
  const suiteRunNonce = typeof options.suiteRunId === "string" ? options.suiteRunId : "";
77245
- const filePath = node.kind === "group" ? bundle.rootSuitePath : resolveRelativeTo(node.path, bundle.rootSuitePath);
78029
+ const filePath = node.kind === "group" ? bundle.rootSuitePath : resolveSuitePath(node.path, bundle.rootSuitePath, options);
77246
78030
  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
78031
  const runId = `suite:${sanitizeIdentifier(bundle.rootSuitePath)}:${suiteRunNonce}:${currentIndex}:${sanitizeIdentifier(node.id)}`;
77248
78032
  options.reporter && options.reporter({
@@ -77288,7 +78072,7 @@ async function runSuiteBundleNode(params) {
77288
78072
  return reportSkippedBundleNode({ node, bundle, options, nextIndex });
77289
78073
  }
77290
78074
  const currentIndex = nextIndex();
77291
- const childFilePath = resolveRelativeTo(node.path, bundle.rootSuitePath);
78075
+ const childFilePath = resolveSuitePath(node.path, bundle.rootSuitePath, options);
77292
78076
  const nodeTitle = typeof node.title === "string" && node.title.trim() ? node.title.trim() : void 0;
77293
78077
  const display = nodeTitle || basename3(childFilePath || node.path);
77294
78078
  const suiteRunNonce = typeof options.suiteRunId === "string" ? options.suiteRunId : "";
@@ -77309,11 +78093,11 @@ async function runSuiteBundleNode(params) {
77309
78093
  const childDocType = detectDocType(childFilePath, childRawText);
77310
78094
  childLogger("debug", `Running suite item: ${display}`);
77311
78095
  const childFileLoader = async (requestedPath) => {
77312
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
78096
+ const resolved = resolveSuitePath(requestedPath, childFilePath, options);
77313
78097
  return await baseFileLoader(resolved);
77314
78098
  };
77315
78099
  const childBinaryFileLoader = options.binaryFileLoader ? async (requestedPath) => {
77316
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
78100
+ const resolved = resolveSuitePath(requestedPath, childFilePath, options);
77317
78101
  return await options.binaryFileLoader(resolved);
77318
78102
  } : void 0;
77319
78103
  options.reporter && options.reporter({
@@ -77468,7 +78252,7 @@ async function runSuiteGroup(params) {
77468
78252
  statuses: serverStatuses
77469
78253
  };
77470
78254
  }
77471
- const nestedPath = resolveRelativeTo(child.path, bundle.rootSuitePath) || child.path;
78255
+ const nestedPath = resolveSuitePath(child.path, bundle.rootSuitePath, options) || child.path;
77472
78256
  const started = await startListedServers({
77473
78257
  servers: child.servers,
77474
78258
  baseFilePath: nestedPath,
@@ -77561,7 +78345,7 @@ async function runSuiteGroup(params) {
77561
78345
  }
77562
78346
  async function startServerNode(params) {
77563
78347
  const { node, bundle, options, suiteLogger } = params;
77564
- const serverFilePath = resolveRelativeTo(node.path, bundle.rootSuitePath);
78348
+ const serverFilePath = resolveSuitePath(node.path, bundle.rootSuitePath, options);
77565
78349
  const display = basename3(serverFilePath || node.path);
77566
78350
  if (!options.serverRunner) {
77567
78351
  suiteLogger("error", `Cannot start server '${node.path}': no server runner provided`);
@@ -77740,7 +78524,7 @@ async function executeSuiteBundle(params) {
77740
78524
  const suiteRunNonce = typeof effectiveOptions.suiteRunId === "string" ? effectiveOptions.suiteRunId : "";
77741
78525
  const targetRunId = `suite:${sanitizeIdentifier(bundle.rootSuitePath)}:${suiteRunNonce}:target:${sanitizeIdentifier(root.id)}`;
77742
78526
  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;
78527
+ const targetFilePath = root.kind === "suite" ? resolveSuitePath(root.path, bundle.rootSuitePath, effectiveOptions) : bundle.rootSuitePath;
77744
78528
  const targetEntry = root.kind === "suite" ? root.path : root.label;
77745
78529
  effectiveOptions.reporter && effectiveOptions.reporter({
77746
78530
  scope: "suite-item",
@@ -78345,7 +79129,7 @@ function optionalTags(tags) {
78345
79129
  return out.length ? out : void 0;
78346
79130
  }
78347
79131
  async function buildSuiteHierarchyFromSuiteFile(params) {
78348
- const { suiteFilePath, suiteRawText, fileLoader, leafPrefix } = params;
79132
+ const { suiteFilePath, suiteRawText, fileLoader, leafPrefix, projectRoot } = params;
78349
79133
  const convertSuiteToHierarchy = async (targetFilePath, rawText, indexPath, ancestors) => {
78350
79134
  const suiteDoc = yamlToSuite(rawText);
78351
79135
  const nextAncestors = new Set(ancestors);
@@ -78423,7 +79207,7 @@ async function buildSuiteHierarchyFromSuiteFile(params) {
78423
79207
  if (!trimmed || trimmed === "then") {
78424
79208
  return null;
78425
79209
  }
78426
- const resolvedPath = resolveRelativeTo(trimmed, ownerFilePath) || trimmed;
79210
+ const resolvedPath = resolveRelativeTo(trimmed, ownerFilePath, projectRoot) || trimmed;
78427
79211
  let raw = "";
78428
79212
  try {
78429
79213
  raw = await fileLoader(resolvedPath);
@@ -78700,7 +79484,7 @@ async function executeTest(prepared, options, preLogs) {
78700
79484
  prepared.filePath ? prepared.filePath.split(/[/\\]/).slice(0, -1).join("/") : void 0,
78701
79485
  options.__mmtIsSuiteBundleChildRun === true,
78702
79486
  void 0,
78703
- void 0,
79487
+ options.checkLogMode,
78704
79488
  "Test",
78705
79489
  options.binaryFileLoader
78706
79490
  );
@@ -78892,7 +79676,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
78892
79676
  const envVars = prepared.envVarsUsed || options.envvar || {};
78893
79677
  const displayName = prepared.title || prepared.baseName;
78894
79678
  const identifier = sanitizeIdentifier(displayName);
78895
- const childFilePath = resolveRelativeTo(loadtest.test, prepared.filePath);
79679
+ const childFilePath = resolveRelativeTo(loadtest.test, prepared.filePath, options.projectRoot);
78896
79680
  const childDisplayName = basename3(childFilePath || loadtest.test);
78897
79681
  const threads = Math.max(1, Math.floor(loadtest.threads || 1));
78898
79682
  const repeatIterations = parsePositiveInteger(loadtest.repeat);
@@ -79077,7 +79861,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
79077
79861
  throw new Error(`Failed to load loadtest target ${loadtest.test}: ${e?.message || String(e)}`);
79078
79862
  }
79079
79863
  const childFileLoader = async (requestedPath) => {
79080
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
79864
+ const resolved = resolveRelativeTo(requestedPath, childFilePath, options.projectRoot);
79081
79865
  return await options.fileLoader(resolved);
79082
79866
  };
79083
79867
  try {
@@ -79143,7 +79927,7 @@ async function executeLoadTestBody(prepared, options, preLogs, runFile2) {
79143
79927
  };
79144
79928
  try {
79145
79929
  const childBinaryFileLoader = options.binaryFileLoader ? async (requestedPath) => {
79146
- const resolved = resolveRelativeTo(requestedPath, childFilePath);
79930
+ const resolved = resolveRelativeTo(requestedPath, childFilePath, options.projectRoot);
79147
79931
  return await options.binaryFileLoader(resolved);
79148
79932
  } : void 0;
79149
79933
  const childResult = await runGeneratedJs(
@@ -79362,6 +80146,13 @@ async function prepareRunFromOptions(options, log = () => {
79362
80146
  async function runFile(options) {
79363
80147
  resetCurrentTokenCache();
79364
80148
  resetRandomTokenCache();
80149
+ if (!options.__mmtIsSuiteBundleChildRun) {
80150
+ const cache = getRunFileCache();
80151
+ await cache.beginRun(options.fileStamp);
80152
+ if (typeof options.fileLoader === "function") {
80153
+ options = { ...options, fileLoader: cache.wrap(options.fileLoader) };
80154
+ }
80155
+ }
79365
80156
  const preLogs = [];
79366
80157
  const note = (level, message) => {
79367
80158
  preLogs.push({ level, message });
@@ -79406,7 +80197,8 @@ async function runFile(options) {
79406
80197
  const tree = await buildSuiteHierarchyFromSuiteFile({
79407
80198
  suiteFilePath: prepared.filePath,
79408
80199
  suiteRawText: prepared.rawText,
79409
- fileLoader: options.fileLoader
80200
+ fileLoader: options.fileLoader,
80201
+ projectRoot: options.projectRoot
79410
80202
  });
79411
80203
  bundle = createSuiteBundle({
79412
80204
  rootSuitePath: prepared.filePath,
@@ -80144,7 +80936,7 @@ var mmtReport_exports = {};
80144
80936
  __export(mmtReport_exports, {
80145
80937
  generateMmtReport: () => generateMmtReport
80146
80938
  });
80147
- var import_yaml2 = __toESM(require("yaml"));
80939
+ var import_yaml3 = __toESM(require("yaml"));
80148
80940
  init_CommonData();
80149
80941
  function displayValue3(v) {
80150
80942
  if (v === null || v === void 0) {
@@ -80325,7 +81117,7 @@ function generateMmtReport(results, options) {
80325
81117
  if (!isLoad) {
80326
81118
  report.checks = runs.map(buildCheckEntry);
80327
81119
  }
80328
- return import_yaml2.default.stringify(report, { lineWidth: 0 });
81120
+ return import_yaml3.default.stringify(report, { lineWidth: 0 });
80329
81121
  }
80330
81122
 
80331
81123
  // ../core/src/reportHtml.ts
@@ -81355,7 +82147,7 @@ __export(reportMarkdown_exports, {
81355
82147
  init_CommonData();
81356
82148
  init_markupConvertor();
81357
82149
  init_omitKeyword();
81358
- function headerValue(headers, name) {
82150
+ function headerValue2(headers, name) {
81359
82151
  if (!headers) {
81360
82152
  return void 0;
81361
82153
  }
@@ -81368,7 +82160,7 @@ function headerValue(headers, name) {
81368
82160
  return void 0;
81369
82161
  }
81370
82162
  function detectBodyFormat(body, headers) {
81371
- const contentType = (headerValue(headers, "content-type") || "").toLowerCase();
82163
+ const contentType = (headerValue2(headers, "content-type") || "").toLowerCase();
81372
82164
  if (contentType.includes("json")) {
81373
82165
  return "json";
81374
82166
  }
@@ -81420,7 +82212,7 @@ function formatBodyValue(value, headers) {
81420
82212
  }
81421
82213
  }
81422
82214
  const format = detectBodyFormat(value, headers);
81423
- const contentType = headerValue(headers, "content-type") || "";
82215
+ const contentType = headerValue2(headers, "content-type") || "";
81424
82216
  if (format === "urlencoded") {
81425
82217
  try {
81426
82218
  return { text: prettyUrlEncoded(value), format };
@@ -82862,21 +83654,21 @@ async function buildCliRunArgs(file, opts) {
82862
83654
  envvar = mergeEnv2({ envvar: void 0, manualEnvvars });
82863
83655
  }
82864
83656
  if (suiteEnvConfig) {
82865
- const projectRoot = findProjectRootForCli(full);
83657
+ const projectRoot2 = findProjectRootForCli(full);
82866
83658
  let suitePresetEnv = {};
82867
83659
  if (suiteEnvConfig.preset) {
82868
83660
  let suiteEnvFilePath;
82869
83661
  if (suiteEnvConfig.file) {
82870
83662
  if (suiteEnvConfig.file.startsWith("+/")) {
82871
- suiteEnvFilePath = projectRoot ? import_path2.default.join(projectRoot, suiteEnvConfig.file.slice(2)) : void 0;
83663
+ suiteEnvFilePath = projectRoot2 ? import_path2.default.join(projectRoot2, suiteEnvConfig.file.slice(2)) : void 0;
82872
83664
  } else {
82873
83665
  suiteEnvFilePath = import_path2.default.resolve(dir, suiteEnvConfig.file);
82874
83666
  }
82875
- } else if (projectRoot) {
82876
- suiteEnvFilePath = import_path2.default.join(projectRoot, "multimeter.mmt");
83667
+ } else if (projectRoot2) {
83668
+ suiteEnvFilePath = import_path2.default.join(projectRoot2, "multimeter.mmt");
82877
83669
  }
82878
83670
  if (suiteEnvFilePath && import_fs2.default.existsSync(suiteEnvFilePath)) {
82879
- const suiteEnvDoc = await loadEnvDoc(suiteEnvFilePath, projectRoot || void 0);
83671
+ const suiteEnvDoc = await loadEnvDoc(suiteEnvFilePath, projectRoot2 || void 0);
82880
83672
  suitePresetEnv = resolvePresetsEnv2(suiteEnvDoc, suiteEnvConfig.preset);
82881
83673
  }
82882
83674
  }
@@ -82887,6 +83679,13 @@ async function buildCliRunArgs(file, opts) {
82887
83679
  const suiteVariables = suiteEnvConfig.variables ? { ...suiteEnvConfig.variables } : {};
82888
83680
  envvar = { ...baseEnv, ...suitePresetEnv, ...suiteVariables, ...manualEnvvars };
82889
83681
  }
83682
+ const projectRoot = findProjectRootForCli(full);
83683
+ const resolveCliFilePath = (requested) => {
83684
+ if (isProjectRootImport(requested) && projectRoot) {
83685
+ return resolveProjectRootImport(requested, projectRoot);
83686
+ }
83687
+ return (0, import_pathNormalize.resolveUserPath)(requested, dir, import_path2.default);
83688
+ };
82890
83689
  const runFileOptions = {
82891
83690
  file: rawText,
82892
83691
  fileType: "raw",
@@ -82897,14 +83696,23 @@ async function buildCliRunArgs(file, opts) {
82897
83696
  envvar,
82898
83697
  manualEnvvars,
82899
83698
  fileLoader: async (p) => {
82900
- const rel = (0, import_pathNormalize.resolveUserPath)(p, dir, import_path2.default);
83699
+ const rel = resolveCliFilePath(p);
82901
83700
  if (!import_fs2.default.existsSync(rel)) {
82902
83701
  return "";
82903
83702
  }
82904
83703
  return import_fs2.default.readFileSync(rel, "utf8");
82905
83704
  },
83705
+ fileStamp: async (p) => {
83706
+ const rel = resolveCliFilePath(p);
83707
+ try {
83708
+ const st = import_fs2.default.statSync(rel);
83709
+ return `${st.size}:${st.mtimeMs}`;
83710
+ } catch {
83711
+ return "missing";
83712
+ }
83713
+ },
82906
83714
  binaryFileLoader: async (p) => {
82907
- const rel = (0, import_pathNormalize.resolveUserPath)(p, dir, import_path2.default);
83715
+ const rel = resolveCliFilePath(p);
82908
83716
  return import_fs2.default.promises.readFile(rel);
82909
83717
  },
82910
83718
  jsRunner: async () => {
@@ -82918,7 +83726,8 @@ async function buildCliRunArgs(file, opts) {
82918
83726
  },
82919
83727
  reporter: (_message) => {
82920
83728
  },
82921
- projectRoot: findProjectRootForCli(full)
83729
+ projectRoot,
83730
+ checkLogMode: opts.quiet ? "none" : "default"
82922
83731
  };
82923
83732
  const onlyTags = Array.isArray(opts.tag) ? opts.tag : [];
82924
83733
  const skipTags = Array.isArray(opts.skipTag) ? opts.skipTag : [];
@@ -84235,8 +85044,8 @@ utils_default.reduceDescriptors(AxiosHeaders.prototype, ({ value }, key) => {
84235
85044
  let mapped = key[0].toUpperCase() + key.slice(1);
84236
85045
  return {
84237
85046
  get: () => value,
84238
- set(headerValue2) {
84239
- this[mapped] = headerValue2;
85047
+ set(headerValue3) {
85048
+ this[mapped] = headerValue3;
84240
85049
  }
84241
85050
  };
84242
85051
  });