@redocly/cli 2.38.0 → 2.40.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -646,9 +646,9 @@ Packages:
646
646
  @noble/hashes@1.8.0 — Copyright (c) 2022 Paul Miller (https://paulmillr.com)
647
647
  @redocly/ajv@8.11.2 — Copyright (c) 2015-2021 Evgeny Poberezkin
648
648
  @redocly/ajv@8.18.3 — Copyright (c) 2015-2021 Evgeny Poberezkin
649
- @redocly/cli-otel@0.3.1 — Copyright 2025 Redocly Inc, all rights reserved.
649
+ @redocly/cli-otel@0.3.4 — Copyright 2025 Redocly Inc, all rights reserved.
650
650
  @redocly/config@0.22.0 — Copyright 2024 Redocly Inc.
651
- @redocly/config@0.50.1 — Copyright 2024 Redocly Inc.
651
+ @redocly/config@0.52.0 — Copyright 2024 Redocly Inc.
652
652
  @redocly/openapi-core@1.34.16
653
653
  agent-base@7.1.4 — Copyright (c) 2013 Nathan Rajlich <nathan@tootallnate.net>
654
654
  ajv-formats@3.0.1 — Copyright (c) 2020 Evgeny Poberezkin
@@ -678,6 +678,7 @@ Packages:
678
678
  js-levenshtein@1.1.6 — Copyright (c) 2017 Gustaf Andersson
679
679
  js-tokens@4.0.0 — Copyright (c) 2014, 2015, 2016, 2017, 2018 Simon Lydell
680
680
  js-yaml@4.2.0 — Copyright (C) 2011-2015 by Vitaly Puzrin
681
+ js-yaml@5.2.1 — Copyright (C) 2011-2015 by Vitaly Puzrin
681
682
  json-pointer@0.6.2 — Copyright (c) 2016 Manuel Stofer
682
683
  json-schema-traverse@1.0.0 — Copyright (c) 2017 Evgeny Poberezkin
683
684
  jsonpointer@5.0.1 — Copyright (c) 2011-2015 Jan Lehnardt <jan@apache.org> & Marc Bachmann <https://github.com/marcbachmann>
@@ -3,7 +3,7 @@ const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  AbortFlowError,
5
5
  exitWithError
6
- } from "./FL4Q7PMA.js";
6
+ } from "./4BR7G6JO.js";
7
7
  import {
8
8
  ConfigValidationError,
9
9
  HandledError,
@@ -27,7 +27,7 @@ import {
27
27
  red,
28
28
  stringifyYaml,
29
29
  yellow
30
- } from "./MIPR6NCD.js";
30
+ } from "./HT6ZGKQQ.js";
31
31
 
32
32
  // src/commands/lint.ts
33
33
  import { performance as performance3 } from "perf_hooks";
@@ -2,24 +2,26 @@ import { createRequire as __createRequire } from 'node:module';
2
2
  const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  ValidationSession,
5
- createNormalizedExchange,
6
- isJsonMime,
7
5
  loadOpenApiIndex,
8
- normalizeFsPath,
9
6
  parseCsv,
10
7
  renderReport
11
- } from "./AAQTUNZI.js";
8
+ } from "./V2UTD4F3.js";
9
+ import {
10
+ createNormalizedExchange,
11
+ isJsonMime,
12
+ normalizeFsPath
13
+ } from "./TYUOO44G.js";
12
14
  import {
13
15
  AbortFlowError,
14
16
  exitWithError
15
- } from "./FL4Q7PMA.js";
17
+ } from "./4BR7G6JO.js";
16
18
  import {
17
19
  require_undici
18
20
  } from "./XB6C62FW.js";
19
21
  import {
20
22
  isPlainObject,
21
23
  logger
22
- } from "./MIPR6NCD.js";
24
+ } from "./HT6ZGKQQ.js";
23
25
  import "./Z2I5YXYN.js";
24
26
  import {
25
27
  __toESM
@@ -437,6 +439,7 @@ async function handleProxy({ argv, config, version }) {
437
439
  openApiIndex,
438
440
  matchMode: argv["match-mode"],
439
441
  ignoreCookies: argv["ignore-cookies"],
442
+ ignoreHeaders: argv["ignore-headers"] ? parseCsv(argv["ignore-headers"]) : void 0,
440
443
  previewFindingsLimit: argv["max-findings"],
441
444
  activeRules: argv.rules ? parseCsv(argv.rules) : void 0
442
445
  });
@@ -2,7 +2,7 @@ import { createRequire as __createRequire } from 'node:module';
2
2
  const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  HandledError
5
- } from "./MIPR6NCD.js";
5
+ } from "./HT6ZGKQQ.js";
6
6
 
7
7
  // src/utils/error.ts
8
8
  var AbortFlowError = class extends Error {
@@ -0,0 +1,175 @@
1
+ import { createRequire as __createRequire } from 'node:module';
2
+ const require = __createRequire(import.meta.url);
3
+ import {
4
+ selectTrafficParser
5
+ } from "./JBIFNX5C.js";
6
+ import {
7
+ ValidationSession,
8
+ loadOpenApiIndex,
9
+ parseCsv,
10
+ renderReport
11
+ } from "./V2UTD4F3.js";
12
+ import {
13
+ listFilesRecursively,
14
+ normalizeFsPath
15
+ } from "./TYUOO44G.js";
16
+ import {
17
+ AbortFlowError,
18
+ exitWithError
19
+ } from "./4BR7G6JO.js";
20
+ import {
21
+ logger
22
+ } from "./HT6ZGKQQ.js";
23
+ import "./Z2I5YXYN.js";
24
+ import "./5ILQMFXK.js";
25
+
26
+ // src/commands/drift/index.ts
27
+ import { mkdir, writeFile } from "node:fs/promises";
28
+ import path from "node:path";
29
+
30
+ // src/commands/drift/engine/runner.ts
31
+ async function runTrafficValidation(options) {
32
+ const trafficFiles = await listFilesRecursively(options.trafficPath);
33
+ if (trafficFiles.length === 0) {
34
+ throw new Error("No traffic files found in the provided traffic path.");
35
+ }
36
+ const session = ValidationSession.create({
37
+ openApiIndex: options.openApiIndex,
38
+ matchMode: options.matchMode,
39
+ ignoreCookies: options.ignoreCookies,
40
+ ignoreHeaders: options.ignoreHeaders,
41
+ previewFindingsLimit: options.previewFindingsLimit,
42
+ activeRules: options.activeRules,
43
+ server: options.server,
44
+ minSeverity: options.minSeverity
45
+ });
46
+ let supportedTrafficFileCount = 0;
47
+ let exchangeIndex = 0;
48
+ for (const trafficFile of trafficFiles) {
49
+ const parser = await selectTrafficParser(trafficFile, options.format);
50
+ if (!parser) {
51
+ logger.warn(`Skipping traffic file with unrecognized format: ${trafficFile}
52
+ `);
53
+ continue;
54
+ }
55
+ supportedTrafficFileCount += 1;
56
+ for await (const exchange of parser.parse(trafficFile)) {
57
+ await session.process({ ...exchange, index: exchangeIndex });
58
+ exchangeIndex += 1;
59
+ }
60
+ }
61
+ if (supportedTrafficFileCount === 0) {
62
+ throw new Error(
63
+ "No supported traffic files found. In auto mode, files must match built-in traffic parser signatures."
64
+ );
65
+ }
66
+ if (exchangeIndex === 0) {
67
+ throw new Error("No HTTP exchanges were parsed from the provided traffic files.");
68
+ }
69
+ return session.finalize();
70
+ }
71
+
72
+ // src/commands/drift/index.ts
73
+ var USE_COLOR = Boolean(process.stdout.isTTY) && process.env.NO_COLOR === void 0;
74
+ function collectSpecServerUrls(openApiIndex) {
75
+ const urls = /* @__PURE__ */ new Set();
76
+ for (const operations of openApiIndex.operationsByMethod.values()) {
77
+ for (const operation of operations) {
78
+ for (const server of operation.servers) {
79
+ urls.add(server.rawUrl);
80
+ }
81
+ }
82
+ }
83
+ return Array.from(urls).sort();
84
+ }
85
+ function warnWhenNothingMatched(summary, openApiIndex, server) {
86
+ const validatedExchanges = summary.totalExchanges - summary.skippedExchanges;
87
+ if (validatedExchanges === 0 && summary.skippedExchanges > 0) {
88
+ logger.warn(
89
+ `All ${summary.skippedExchanges} exchange(s) were outside the --server "${server}" and were skipped. Check that the server matches the traffic URLs.
90
+ `
91
+ );
92
+ return;
93
+ }
94
+ if (summary.documentedExchanges > 0 || validatedExchanges === 0) {
95
+ return;
96
+ }
97
+ const serverUrls = collectSpecServerUrls(openApiIndex);
98
+ const hint = server ? `Check that the --server "${server}" matches the traffic URLs and that the description paths align with the remainder.` : summary.hostCompatibleExchanges === validatedExchanges ? `The traffic hosts are compatible with the description servers (${serverUrls.join(
99
+ ", "
100
+ )}), so the endpoints are likely undocumented; if they should be documented, check that the description base paths and paths align with the traffic URLs, or use --server to declare the server the traffic was captured against.` : `Check that the traffic host and base path match the description servers (${serverUrls.join(
101
+ ", "
102
+ )}), or use --server to declare the server the traffic was captured against.`;
103
+ logger.warn(
104
+ `None of the ${validatedExchanges} validated exchange(s) matched a documented operation. ${hint}
105
+ `
106
+ );
107
+ }
108
+ async function writeOutput(outputPath, content) {
109
+ const resolved = normalizeFsPath(outputPath);
110
+ await mkdir(path.dirname(resolved), { recursive: true });
111
+ await writeFile(resolved, content, "utf8");
112
+ }
113
+ async function handleDrift({ argv, config }) {
114
+ const trafficPath = normalizeFsPath(argv.traffic);
115
+ const trafficFormat = argv["traffic-format"];
116
+ const activeRules = argv.rules ? parseCsv(argv.rules) : void 0;
117
+ const ignoreHeaders = argv["ignore-headers"] ? parseCsv(argv["ignore-headers"]) : void 0;
118
+ const server = argv.server;
119
+ if (server && argv["match-mode"]) {
120
+ return exitWithError(
121
+ "The --server and --match-mode options are mutually exclusive: --match-mode controls how requests are located via the description servers, while --server replaces the description servers with the one the traffic was captured against."
122
+ );
123
+ }
124
+ const matchMode = argv["match-mode"] ?? "strict-host";
125
+ const specPath = normalizeFsPath(argv.api);
126
+ const openApiIndex = await loadOpenApiIndex(specPath, config);
127
+ if (openApiIndex.loadedOperations === 0) {
128
+ return exitWithError(`No OpenAPI operations were loaded from: ${specPath}`);
129
+ }
130
+ const { runId, summary, findings } = await runTrafficValidation({
131
+ trafficPath,
132
+ format: trafficFormat,
133
+ matchMode,
134
+ ignoreCookies: argv["ignore-cookies"],
135
+ ignoreHeaders,
136
+ previewFindingsLimit: argv["max-findings"],
137
+ activeRules,
138
+ openApiIndex,
139
+ server,
140
+ minSeverity: argv["min-severity"]
141
+ });
142
+ warnWhenNothingMatched(summary, openApiIndex, server);
143
+ const report = renderReport(
144
+ {
145
+ runId,
146
+ summary,
147
+ findings,
148
+ meta: {
149
+ specSource: specPath,
150
+ trafficPath,
151
+ format: trafficFormat,
152
+ matchMode,
153
+ server
154
+ }
155
+ },
156
+ {
157
+ format: argv["report-format"],
158
+ color: USE_COLOR && argv["report-format"] === "pretty" && !argv.output,
159
+ maxFindings: argv["max-findings"]
160
+ }
161
+ );
162
+ if (argv.output) {
163
+ await writeOutput(argv.output, report);
164
+ logger.info(`Drift report written to: ${normalizeFsPath(argv.output)}
165
+ `);
166
+ } else {
167
+ logger.output(report);
168
+ }
169
+ if (summary.findingsBySeverity.error > 0) {
170
+ throw new AbortFlowError("Drift detected.");
171
+ }
172
+ }
173
+ export {
174
+ handleDrift
175
+ };
@@ -4,7 +4,7 @@ const require = __createRequire(import.meta.url);
4
4
  // package.json
5
5
  var package_default = {
6
6
  name: "@redocly/cli",
7
- version: "2.38.0",
7
+ version: "2.40.0",
8
8
  description: "",
9
9
  license: "MIT",
10
10
  bin: {
@@ -48,9 +48,9 @@ var package_default = {
48
48
  "@opentelemetry/resources": "2.8.0",
49
49
  "@opentelemetry/sdk-trace-node": "2.8.0",
50
50
  "@opentelemetry/semantic-conventions": "1.41.1",
51
- "@redocly/cli-otel": "0.3.1",
52
- "@redocly/openapi-core": "2.38.0",
53
- "@redocly/respect-core": "2.38.0",
51
+ "@redocly/cli-otel": "0.3.4",
52
+ "@redocly/openapi-core": "2.40.0",
53
+ "@redocly/respect-core": "2.40.0",
54
54
  "@types/cookie": "0.6.0",
55
55
  "@types/har-format": "^1.2.16",
56
56
  "@types/react": "^17.0.0 || ^18.2.21 || ^19.2.16",
@@ -3,17 +3,17 @@ const require = __createRequire(import.meta.url);
3
3
  import {
4
4
  getExecutionTime,
5
5
  getFallbackApisOrExit
6
- } from "./QUMOPKXU.js";
6
+ } from "./325TP2UK.js";
7
7
  import {
8
8
  exitWithError
9
- } from "./FL4Q7PMA.js";
9
+ } from "./4BR7G6JO.js";
10
10
  import {
11
11
  require_dist
12
12
  } from "./4FB5ZIPP.js";
13
13
  import {
14
14
  redocStandaloneSri,
15
15
  redocVersion
16
- } from "./PIMMKQJ7.js";
16
+ } from "./6DYZ77KC.js";
17
17
  import {
18
18
  require_json_pointer,
19
19
  require_openapi_sampler
@@ -25,7 +25,7 @@ import {
25
25
  require_fast_deep_equal,
26
26
  require_json_schema_traverse,
27
27
  require_pluralize
28
- } from "./MIPR6NCD.js";
28
+ } from "./HT6ZGKQQ.js";
29
29
  import "./Z2I5YXYN.js";
30
30
  import {
31
31
  __commonJS,
@@ -1,16 +1,16 @@
1
1
  import { createRequire as __createRequire } from 'node:module';
2
2
  const require = __createRequire(import.meta.url);
3
3
  import {
4
- G,
4
+ F,
5
5
  ulid
6
- } from "./ICAVAH7N.js";
6
+ } from "./ICPYP2LP.js";
7
7
  import {
8
8
  DEFAULT_FETCH_TIMEOUT,
9
9
  OTEL_TRACES_URL
10
10
  } from "./Y6DTFCLS.js";
11
11
  import {
12
12
  version
13
- } from "./PIMMKQJ7.js";
13
+ } from "./6DYZ77KC.js";
14
14
  import {
15
15
  diag,
16
16
  esm_exports,
@@ -13359,7 +13359,7 @@ var OtelServerTelemetry = class {
13359
13359
  const time = new Date(cloudEvent.time);
13360
13360
  const tracer = this.nodeTracerProvider.getTracer("CliTelemetry");
13361
13361
  const spanName = `event.${cloudEvent.type}`;
13362
- const attributes = G(cloudEvent, time);
13362
+ const attributes = F(cloudEvent, time);
13363
13363
  const span = tracer.startSpan(spanName, {
13364
13364
  attributes,
13365
13365
  startTime: time