@redocly/cli 1.25.2 → 1.25.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # @redocly/cli
2
2
 
3
+ ## 1.25.4
4
+
5
+ ### Patch Changes
6
+
7
+ - Added a warning message to the `push` and `push-status` commands to notify users about upcoming or ongoing resource deprecation.
8
+ - Updated @redocly/openapi-core to v1.25.4.
9
+
10
+ ## 1.25.3
11
+
12
+ ### Patch Changes
13
+
14
+ - Updated @redocly/openapi-core to v1.25.3.
15
+
3
16
  ## 1.25.2
4
17
 
5
18
  ### Patch Changes
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const node_fetch_1 = require("node-fetch");
4
4
  const FormData = require("form-data");
5
+ const colorette_1 = require("colorette");
5
6
  const api_client_1 = require("../api-client");
6
7
  jest.mock('node-fetch', () => ({
7
8
  default: jest.fn(),
@@ -20,7 +21,7 @@ describe('ApiClient', () => {
20
21
  describe('getDefaultBranch()', () => {
21
22
  let apiClient;
22
23
  beforeEach(() => {
23
- apiClient = new api_client_1.ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
24
+ apiClient = new api_client_1.ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
24
25
  });
25
26
  it('should get default project branch', async () => {
26
27
  mockFetchResponse({
@@ -70,19 +71,19 @@ describe('ApiClient', () => {
70
71
  mountBranchName: 'remote-mount-branch-name',
71
72
  mountPath: 'remote-mount-path',
72
73
  };
74
+ const responseMock = {
75
+ id: 'remote-id',
76
+ type: 'CICD',
77
+ mountPath: 'remote-mount-path',
78
+ mountBranchName: 'remote-mount-branch-name',
79
+ organizationId: testOrg,
80
+ projectId: testProject,
81
+ };
73
82
  let apiClient;
74
83
  beforeEach(() => {
75
- apiClient = new api_client_1.ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
84
+ apiClient = new api_client_1.ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
76
85
  });
77
86
  it('should upsert remote', async () => {
78
- const responseMock = {
79
- id: 'remote-id',
80
- type: 'CICD',
81
- mountPath: 'remote-mount-path',
82
- mountBranchName: 'remote-mount-branch-name',
83
- organizationId: testOrg,
84
- projectId: testProject,
85
- };
86
87
  mockFetchResponse({
87
88
  ok: true,
88
89
  json: jest.fn().mockResolvedValue(responseMock),
@@ -162,7 +163,7 @@ describe('ApiClient', () => {
162
163
  };
163
164
  let apiClient;
164
165
  beforeEach(() => {
165
- apiClient = new api_client_1.ReuniteApiClient({ domain: testDomain, apiKey: testToken, version, command });
166
+ apiClient = new api_client_1.ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
166
167
  });
167
168
  it('should push to remote', async () => {
168
169
  let passedFormData = new FormData();
@@ -216,4 +217,117 @@ describe('ApiClient', () => {
216
217
  await expect(apiClient.remotes.push(testOrg, testProject, pushPayload, filesMock)).rejects.toThrow(new api_client_1.ReuniteApiError('Failed to push. Not found.', 404));
217
218
  });
218
219
  });
220
+ describe('Sunset header', () => {
221
+ const upsertRemoteMock = {
222
+ requestFn: () => apiClient.remotes.upsert(testOrg, testProject, {
223
+ mountBranchName: 'remote-mount-branch-name',
224
+ mountPath: 'remote-mount-path',
225
+ }),
226
+ responseBody: {
227
+ id: 'remote-id',
228
+ type: 'CICD',
229
+ mountPath: 'remote-mount-path',
230
+ mountBranchName: 'remote-mount-branch-name',
231
+ organizationId: testOrg,
232
+ projectId: testProject,
233
+ },
234
+ };
235
+ const getDefaultBranchMock = {
236
+ requestFn: () => apiClient.remotes.getDefaultBranch(testOrg, testProject),
237
+ responseBody: {
238
+ branchName: 'test-branch',
239
+ },
240
+ };
241
+ const pushMock = {
242
+ requestFn: () => apiClient.remotes.push(testOrg, testProject, {
243
+ remoteId: 'test-remote-id',
244
+ commit: {
245
+ message: 'test-message',
246
+ author: {
247
+ name: 'test-name',
248
+ email: 'test-email',
249
+ },
250
+ branchName: 'test-branch-name',
251
+ },
252
+ }, [{ path: 'some-file.yaml', stream: Buffer.from('text content') }]),
253
+ responseBody: {
254
+ branchName: 'rem/cicd/rem_01he7sr6ys2agb7w0g9t7978fn-main',
255
+ hasChanges: true,
256
+ files: [
257
+ {
258
+ type: 'file',
259
+ name: 'some-file.yaml',
260
+ path: 'docs/remotes/some-file.yaml',
261
+ lastModified: 1698925132394.2993,
262
+ mimeType: 'text/yaml',
263
+ },
264
+ ],
265
+ commitSha: 'bb23a2f8e012ac0b7b9961b57fb40d8686b21b43',
266
+ outdated: false,
267
+ },
268
+ };
269
+ const endpointMocks = [upsertRemoteMock, getDefaultBranchMock, pushMock];
270
+ let apiClient;
271
+ beforeEach(() => {
272
+ apiClient = new api_client_1.ReuniteApi({ domain: testDomain, apiKey: testToken, version, command });
273
+ });
274
+ it.each(endpointMocks)('should report endpoint sunset in the past', async ({ responseBody, requestFn }) => {
275
+ jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
276
+ const sunsetDate = new Date('2024-09-06T12:30:32.456Z');
277
+ mockFetchResponse({
278
+ ok: true,
279
+ json: jest.fn().mockResolvedValue(responseBody),
280
+ headers: new Headers({
281
+ Sunset: sunsetDate.toISOString(),
282
+ }),
283
+ });
284
+ await requestFn();
285
+ apiClient.reportSunsetWarnings();
286
+ expect(process.stdout.write).toHaveBeenCalledWith((0, colorette_1.red)(`The "push" command is not compatible with your version of Redocly CLI. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`));
287
+ });
288
+ it.each(endpointMocks)('should report endpoint sunset in the future', async ({ responseBody, requestFn }) => {
289
+ jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
290
+ const sunsetDate = new Date(Date.now() + 1000 * 60 * 60 * 24);
291
+ mockFetchResponse({
292
+ ok: true,
293
+ json: jest.fn().mockResolvedValue(responseBody),
294
+ headers: new Headers({
295
+ Sunset: sunsetDate.toISOString(),
296
+ }),
297
+ });
298
+ await requestFn();
299
+ apiClient.reportSunsetWarnings();
300
+ expect(process.stdout.write).toHaveBeenCalledWith((0, colorette_1.yellow)(`The "push" command will be incompatible with your version of Redocly CLI after ${sunsetDate.toLocaleString()}. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`));
301
+ });
302
+ it('should report only expired resource', async () => {
303
+ jest.spyOn(process.stdout, 'write').mockImplementationOnce(() => true);
304
+ mockFetchResponse({
305
+ ok: true,
306
+ json: jest.fn().mockResolvedValue(upsertRemoteMock.responseBody),
307
+ headers: new Headers({
308
+ Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(),
309
+ }),
310
+ });
311
+ await upsertRemoteMock.requestFn();
312
+ mockFetchResponse({
313
+ ok: true,
314
+ json: jest.fn().mockResolvedValue(getDefaultBranchMock.responseBody),
315
+ headers: new Headers({
316
+ Sunset: new Date(Date.now() + 1000 * 60 * 60 * 24).toISOString(),
317
+ }),
318
+ });
319
+ await getDefaultBranchMock.requestFn();
320
+ mockFetchResponse({
321
+ ok: true,
322
+ json: jest.fn().mockResolvedValue(pushMock.responseBody),
323
+ headers: new Headers({
324
+ Sunset: new Date('2024-08-06T12:30:32.456Z').toISOString(),
325
+ }),
326
+ });
327
+ await pushMock.requestFn();
328
+ apiClient.reportSunsetWarnings();
329
+ expect(process.stdout.write).toHaveBeenCalledTimes(1);
330
+ expect(process.stdout.write).toHaveBeenCalledWith((0, colorette_1.red)(`The "push" command is not compatible with your version of Redocly CLI. Update to the latest version by running "npm install @redocly/cli@latest".\n\n`));
331
+ });
332
+ });
219
333
  });
@@ -2,21 +2,25 @@ import { type FetchWithTimeoutOptions } from '../../utils/fetch-with-timeout';
2
2
  import type { Response } from 'node-fetch';
3
3
  import type { ReadStream } from 'fs';
4
4
  import type { ListRemotesResponse, PushResponse, UpsertRemoteResponse } from './types';
5
+ interface BaseApiClient {
6
+ request(url: string, options: FetchWithTimeoutOptions): Promise<Response>;
7
+ }
8
+ type CommandOption = 'push' | 'push-status';
9
+ export type SunsetWarning = {
10
+ sunsetDate: Date;
11
+ isSunsetExpired: boolean;
12
+ };
13
+ export type SunsetWarningsBuffer = SunsetWarning[];
5
14
  export declare class ReuniteApiError extends Error {
6
15
  status: number;
7
16
  constructor(message: string, status: number);
8
17
  }
9
- declare class ReuniteBaseApiClient {
10
- protected version: string;
11
- protected command: string;
12
- constructor(version: string, command: string);
13
- protected getParsedResponse<T>(response: Response): Promise<T>;
14
- protected request(url: string, options: FetchWithTimeoutOptions): Promise<Response>;
15
- }
16
- declare class RemotesApiClient extends ReuniteBaseApiClient {
18
+ declare class RemotesApi {
19
+ private client;
17
20
  private readonly domain;
18
21
  private readonly apiKey;
19
- constructor(domain: string, apiKey: string, version: string, command: string);
22
+ constructor(client: BaseApiClient, domain: string, apiKey: string);
23
+ protected getParsedResponse<T>(response: Response): Promise<T>;
20
24
  getDefaultBranch(organizationId: string, projectId: string): Promise<string>;
21
25
  upsert(organizationId: string, projectId: string, remote: {
22
26
  mountPath: string;
@@ -37,14 +41,18 @@ declare class RemotesApiClient extends ReuniteBaseApiClient {
37
41
  pushId: string;
38
42
  }): Promise<PushResponse>;
39
43
  }
40
- export declare class ReuniteApiClient {
41
- remotes: RemotesApiClient;
44
+ export declare class ReuniteApi {
45
+ private apiClient;
46
+ private version;
47
+ private command;
48
+ remotes: RemotesApi;
42
49
  constructor({ domain, apiKey, version, command, }: {
43
50
  domain: string;
44
51
  apiKey: string;
45
52
  version: string;
46
- command: 'push' | 'push-status';
53
+ command: CommandOption;
47
54
  });
55
+ reportSunsetWarnings(): void;
48
56
  }
49
57
  export type PushPayload = {
50
58
  remoteId: string;
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ReuniteApiClient = exports.ReuniteApiError = void 0;
3
+ exports.ReuniteApi = exports.ReuniteApiError = void 0;
4
+ const colorette_1 = require("colorette");
4
5
  const FormData = require("form-data");
5
6
  const fetch_with_timeout_1 = require("../../utils/fetch-with-timeout");
6
7
  class ReuniteApiError extends Error {
@@ -10,38 +11,70 @@ class ReuniteApiError extends Error {
10
11
  }
11
12
  }
12
13
  exports.ReuniteApiError = ReuniteApiError;
13
- class ReuniteBaseApiClient {
14
+ class ReuniteApiClient {
14
15
  constructor(version, command) {
15
16
  this.version = version;
16
17
  this.command = command;
18
+ this.sunsetWarnings = [];
17
19
  }
18
- async getParsedResponse(response) {
19
- const responseBody = await response.json();
20
- if (response.ok) {
21
- return responseBody;
22
- }
23
- throw new ReuniteApiError(`${responseBody.title || response.statusText || 'Unknown error'}.`, response.status);
24
- }
25
- request(url, options) {
20
+ async request(url, options) {
26
21
  const headers = {
27
22
  ...options.headers,
28
23
  'user-agent': `redocly-cli/${this.version.trim()} ${this.command}`,
29
24
  };
30
- return (0, fetch_with_timeout_1.default)(url, {
25
+ const response = await (0, fetch_with_timeout_1.default)(url, {
31
26
  ...options,
32
27
  headers,
33
28
  });
29
+ this.collectSunsetWarning(response);
30
+ return response;
31
+ }
32
+ collectSunsetWarning(response) {
33
+ const sunsetTime = this.getSunsetDate(response);
34
+ if (!sunsetTime)
35
+ return;
36
+ const sunsetDate = new Date(sunsetTime);
37
+ if (sunsetTime > Date.now()) {
38
+ this.sunsetWarnings.push({
39
+ sunsetDate,
40
+ isSunsetExpired: false,
41
+ });
42
+ }
43
+ else {
44
+ this.sunsetWarnings.push({
45
+ sunsetDate,
46
+ isSunsetExpired: true,
47
+ });
48
+ }
49
+ }
50
+ getSunsetDate(response) {
51
+ const { headers } = response;
52
+ if (!headers) {
53
+ return;
54
+ }
55
+ const sunsetDate = headers.get('sunset') || headers.get('Sunset');
56
+ if (!sunsetDate) {
57
+ return;
58
+ }
59
+ return Date.parse(sunsetDate);
34
60
  }
35
61
  }
36
- class RemotesApiClient extends ReuniteBaseApiClient {
37
- constructor(domain, apiKey, version, command) {
38
- super(version, command);
62
+ class RemotesApi {
63
+ constructor(client, domain, apiKey) {
64
+ this.client = client;
39
65
  this.domain = domain;
40
66
  this.apiKey = apiKey;
41
67
  }
68
+ async getParsedResponse(response) {
69
+ const responseBody = await response.json();
70
+ if (response.ok) {
71
+ return responseBody;
72
+ }
73
+ throw new ReuniteApiError(`${responseBody.title || response.statusText || 'Unknown error'}.`, response.status);
74
+ }
42
75
  async getDefaultBranch(organizationId, projectId) {
43
76
  try {
44
- const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`, {
77
+ const response = await this.client.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`, {
45
78
  timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
46
79
  method: 'GET',
47
80
  headers: {
@@ -62,7 +95,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
62
95
  }
63
96
  async upsert(organizationId, projectId, remote) {
64
97
  try {
65
- const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`, {
98
+ const response = await this.client.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`, {
66
99
  timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
67
100
  method: 'POST',
68
101
  headers: {
@@ -103,7 +136,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
103
136
  }
104
137
  payload.isMainBranch && formData.append('isMainBranch', 'true');
105
138
  try {
106
- const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`, {
139
+ const response = await this.client.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`, {
107
140
  method: 'POST',
108
141
  headers: {
109
142
  Authorization: `Bearer ${this.apiKey}`,
@@ -122,7 +155,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
122
155
  }
123
156
  async getRemotesList({ organizationId, projectId, mountPath, }) {
124
157
  try {
125
- const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`, {
158
+ const response = await this.client.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`, {
126
159
  timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
127
160
  method: 'GET',
128
161
  headers: {
@@ -142,7 +175,7 @@ class RemotesApiClient extends ReuniteBaseApiClient {
142
175
  }
143
176
  async getPush({ organizationId, projectId, pushId, }) {
144
177
  try {
145
- const response = await this.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`, {
178
+ const response = await this.client.request(`${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`, {
146
179
  timeout: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
147
180
  method: 'GET',
148
181
  headers: {
@@ -161,9 +194,32 @@ class RemotesApiClient extends ReuniteBaseApiClient {
161
194
  }
162
195
  }
163
196
  }
164
- class ReuniteApiClient {
197
+ class ReuniteApi {
165
198
  constructor({ domain, apiKey, version, command, }) {
166
- this.remotes = new RemotesApiClient(domain, apiKey, version, command);
199
+ this.command = command;
200
+ this.version = version;
201
+ this.apiClient = new ReuniteApiClient(this.version, this.command);
202
+ this.remotes = new RemotesApi(this.apiClient, domain, apiKey);
203
+ }
204
+ reportSunsetWarnings() {
205
+ const sunsetWarnings = this.apiClient.sunsetWarnings;
206
+ if (sunsetWarnings.length) {
207
+ const [{ isSunsetExpired, sunsetDate }] = sunsetWarnings.sort((a, b) => {
208
+ // First, prioritize by expiration status
209
+ if (a.isSunsetExpired !== b.isSunsetExpired) {
210
+ return a.isSunsetExpired ? -1 : 1;
211
+ }
212
+ // If both are either expired or not, sort by sunset date
213
+ return a.sunsetDate > b.sunsetDate ? 1 : -1;
214
+ });
215
+ const updateVersionMessage = `Update to the latest version by running "npm install @redocly/cli@latest".`;
216
+ if (isSunsetExpired) {
217
+ process.stdout.write((0, colorette_1.red)(`The "${this.command}" command is not compatible with your version of Redocly CLI. ${updateVersionMessage}\n\n`));
218
+ }
219
+ else {
220
+ process.stdout.write((0, colorette_1.yellow)(`The "${this.command}" command will be incompatible with your version of Redocly CLI after ${sunsetDate.toLocaleString()}. ${updateVersionMessage}\n\n`));
221
+ }
222
+ }
167
223
  }
168
224
  }
169
- exports.ReuniteApiClient = ReuniteApiClient;
225
+ exports.ReuniteApi = ReuniteApi;
@@ -15,8 +15,9 @@ jest.mock('colorette', () => ({
15
15
  }));
16
16
  jest.mock('../../api', () => ({
17
17
  ...jest.requireActual('../../api'),
18
- ReuniteApiClient: jest.fn().mockImplementation(function (...args) {
18
+ ReuniteApi: jest.fn().mockImplementation(function (...args) {
19
19
  this.remotes = remotes;
20
+ this.reportSunsetWarnings = jest.fn();
20
21
  }),
21
22
  }));
22
23
  jest.mock('@redocly/openapi-core', () => ({
@@ -14,8 +14,9 @@ jest.mock('@redocly/openapi-core', () => ({
14
14
  }));
15
15
  jest.mock('../../api', () => ({
16
16
  ...jest.requireActual('../../api'),
17
- ReuniteApiClient: jest.fn().mockImplementation(function (...args) {
17
+ ReuniteApi: jest.fn().mockImplementation(function (...args) {
18
18
  this.remotes = remotes;
19
+ this.reportSunsetWarnings = jest.fn();
19
20
  }),
20
21
  }));
21
22
  describe('handlePush()', () => {
@@ -269,7 +270,7 @@ describe('handlePush()', () => {
269
270
  config: mockConfig,
270
271
  version: 'cli-version',
271
272
  });
272
- expect(api_1.ReuniteApiClient).toBeCalledWith({
273
+ expect(api_1.ReuniteApi).toBeCalledWith({
273
274
  domain: 'test-domain-from-env',
274
275
  apiKey: 'test-api-key',
275
276
  version: 'cli-version',
@@ -28,7 +28,7 @@ async function handlePushStatus({ argv, config, version, }) {
28
28
  const continueOnDeployFailures = argv['continue-on-deploy-failures'] || false;
29
29
  try {
30
30
  const apiKey = (0, api_1.getApiKeys)(domain);
31
- const client = new api_1.ReuniteApiClient({ domain, apiKey, version, command: 'push-status' });
31
+ const client = new api_1.ReuniteApi({ domain, apiKey, version, command: 'push-status' });
32
32
  let pushResponse;
33
33
  pushResponse = await (0, utils_2.retryUntilConditionMet)({
34
34
  operation: () => client.remotes.getPush({
@@ -119,6 +119,7 @@ async function handlePushStatus({ argv, config, version, }) {
119
119
  printScorecard(pushResponse.status.production.scorecard);
120
120
  }
121
121
  printPushStatusInfo({ orgId, projectId, pushId, startedAt });
122
+ client.reportSunsetWarnings();
122
123
  const summary = {
123
124
  preview: pushResponse.status.preview,
124
125
  production: pushResponse.isMainBranch ? pushResponse.status.production : null,
@@ -30,10 +30,11 @@ async function handlePush({ argv, config, version, }) {
30
30
  const author = parseCommitAuthor(argv.author);
31
31
  const apiKey = (0, api_1.getApiKeys)(domain);
32
32
  const filesToUpload = collectFilesToPush(argv.files || argv.apis);
33
+ const commandName = 'push';
33
34
  if (!filesToUpload.length) {
34
- return (0, miscellaneous_1.printExecutionTime)('push', startedAt, `No files to upload`);
35
+ return (0, miscellaneous_1.printExecutionTime)(commandName, startedAt, `No files to upload`);
35
36
  }
36
- const client = new api_1.ReuniteApiClient({ domain, apiKey, version, command: 'push' });
37
+ const client = new api_1.ReuniteApi({ domain, apiKey, version, command: commandName });
37
38
  const projectDefaultBranch = await client.remotes.getDefaultBranch(orgId, projectId);
38
39
  const remote = await client.remotes.upsert(orgId, projectId, {
39
40
  mountBranchName: projectDefaultBranch,
@@ -77,7 +78,8 @@ async function handlePush({ argv, config, version, }) {
77
78
  });
78
79
  }
79
80
  verbose &&
80
- (0, miscellaneous_1.printExecutionTime)('push', startedAt, `${(0, utils_1.pluralize)('file', filesToUpload.length)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`);
81
+ (0, miscellaneous_1.printExecutionTime)(commandName, startedAt, `${(0, utils_1.pluralize)('file', filesToUpload.length)} uploaded to organization ${orgId}, project ${projectId}. Push ID: ${id}.`);
82
+ client.reportSunsetWarnings();
81
83
  return {
82
84
  pushId: id,
83
85
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@redocly/cli",
3
- "version": "1.25.2",
3
+ "version": "1.25.4",
4
4
  "description": "",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -36,7 +36,7 @@
36
36
  "Roman Hotsiy <roman@redoc.ly> (https://redoc.ly/)"
37
37
  ],
38
38
  "dependencies": {
39
- "@redocly/openapi-core": "1.25.2",
39
+ "@redocly/openapi-core": "1.25.4",
40
40
  "abort-controller": "^3.0.0",
41
41
  "chokidar": "^3.5.1",
42
42
  "colorette": "^1.2.0",