@redocly/cli 2.37.0 → 2.39.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.
@@ -0,0 +1,681 @@
1
+ import { createRequire as __createRequire } from 'node:module';
2
+ const require = __createRequire(import.meta.url);
3
+ import {
4
+ DEFAULT_FETCH_TIMEOUT
5
+ } from "./Y6DTFCLS.js";
6
+ import {
7
+ require_dist
8
+ } from "./4FB5ZIPP.js";
9
+ import {
10
+ version
11
+ } from "./2LEVMD2A.js";
12
+ import {
13
+ require_undici
14
+ } from "./XB6C62FW.js";
15
+ import {
16
+ blue,
17
+ green,
18
+ logger
19
+ } from "./KYZEVOA2.js";
20
+ import {
21
+ __toESM
22
+ } from "./5ILQMFXK.js";
23
+
24
+ // src/auth/oauth-client.ts
25
+ import { Buffer as Buffer2 } from "node:buffer";
26
+ import crypto from "node:crypto";
27
+ import { mkdirSync, existsSync, writeFileSync, readFileSync, rmSync } from "node:fs";
28
+ import { homedir } from "node:os";
29
+ import path from "node:path";
30
+
31
+ // src/reunite/api/domains.ts
32
+ var REUNITE_URLS = {
33
+ us: "https://app.cloud.redocly.com",
34
+ eu: "https://app.cloud.eu.redocly.com"
35
+ };
36
+ function getDomain() {
37
+ return process.env.REDOCLY_DOMAIN || REUNITE_URLS.us;
38
+ }
39
+ var getReuniteUrl = withHttpsValidation(
40
+ (config, residencyOption) => {
41
+ try {
42
+ const residency = residencyOption || config?.resolvedConfig.residency;
43
+ if (isLegacyResidency(residency)) {
44
+ return REUNITE_URLS[residency];
45
+ }
46
+ if (residency) {
47
+ return new URL(residency).origin;
48
+ }
49
+ if (config?.resolvedConfig.scorecard?.fromProjectUrl) {
50
+ return new URL(config.resolvedConfig.scorecard.fromProjectUrl).origin;
51
+ }
52
+ return REUNITE_URLS.us;
53
+ } catch {
54
+ throw new InvalidReuniteUrlError();
55
+ }
56
+ }
57
+ );
58
+ function isValidReuniteUrl(reuniteUrl) {
59
+ try {
60
+ getReuniteUrl(void 0, reuniteUrl);
61
+ } catch {
62
+ return false;
63
+ }
64
+ return true;
65
+ }
66
+ function withHttpsValidation(fn) {
67
+ return (...args) => {
68
+ const url = fn(...args);
69
+ if (!url.startsWith("https://")) {
70
+ throw new InvalidReuniteUrlError();
71
+ }
72
+ return url;
73
+ };
74
+ }
75
+ var InvalidReuniteUrlError = class extends Error {
76
+ constructor() {
77
+ super("Invalid Reunite URL");
78
+ }
79
+ };
80
+ function isLegacyResidency(value) {
81
+ return typeof value === "string" && value in REUNITE_URLS;
82
+ }
83
+
84
+ // src/auth/device-flow.ts
85
+ import * as childProcess from "node:child_process";
86
+
87
+ // src/utils/fetch-with-timeout.ts
88
+ var import_undici = __toESM(require_undici(), 1);
89
+
90
+ // src/utils/proxy-agent.ts
91
+ var import_https_proxy_agent = __toESM(require_dist(), 1);
92
+ function getProxyUrl() {
93
+ return process.env.HTTPS_PROXY || process.env.HTTP_PROXY || process.env.http_proxy || process.env.https_proxy;
94
+ }
95
+ function shouldBypassProxy(url) {
96
+ const noProxy = process.env.NO_PROXY || process.env.no_proxy;
97
+ if (!noProxy) return false;
98
+ const entries = noProxy.split(",").map((s) => s.trim().toLowerCase()).filter(Boolean);
99
+ if (entries.length === 0) return false;
100
+ let hostname;
101
+ try {
102
+ hostname = new URL(url).hostname.toLowerCase();
103
+ } catch {
104
+ return false;
105
+ }
106
+ return entries.some((entry) => {
107
+ if (entry === "*") return true;
108
+ if (hostname === entry) return true;
109
+ if (entry.startsWith(".") && hostname.endsWith(entry)) return true;
110
+ if (!entry.startsWith(".") && hostname.endsWith("." + entry)) return true;
111
+ return false;
112
+ });
113
+ }
114
+
115
+ // src/utils/fetch-with-timeout.ts
116
+ var fetch_with_timeout_default = async (url, { timeout, ...options } = {}) => {
117
+ const proxyUrl = getProxyUrl();
118
+ const useProxy = proxyUrl && !shouldBypassProxy(url);
119
+ let dispatcher;
120
+ const connectOptions = timeout ? { connect: { timeout } } : {};
121
+ if (useProxy) {
122
+ dispatcher = new import_undici.ProxyAgent({
123
+ uri: proxyUrl,
124
+ ...connectOptions
125
+ });
126
+ } else if (timeout) {
127
+ dispatcher = new import_undici.Agent(connectOptions);
128
+ }
129
+ const res = await fetch(url, {
130
+ signal: timeout ? AbortSignal.timeout(timeout) : void 0,
131
+ ...options,
132
+ dispatcher
133
+ });
134
+ return res;
135
+ };
136
+
137
+ // src/reunite/api/api-client.ts
138
+ var ReuniteApiError = class extends Error {
139
+ constructor(message, status) {
140
+ super(message);
141
+ this.status = status;
142
+ }
143
+ status;
144
+ };
145
+ var ReuniteApiClient = class {
146
+ constructor(command) {
147
+ this.command = command;
148
+ }
149
+ command;
150
+ sunsetWarnings = [];
151
+ async request(url, options) {
152
+ const headers = {
153
+ ...options.headers,
154
+ "user-agent": `redocly-cli/${version} ${this.command}`
155
+ };
156
+ try {
157
+ const response = await fetch_with_timeout_default(url, {
158
+ ...options,
159
+ headers
160
+ });
161
+ this.collectSunsetWarning(response);
162
+ return response;
163
+ } catch (err) {
164
+ let errorMessage = "Failed to fetch.";
165
+ if (err.cause) {
166
+ errorMessage += ` Caused by ${err.cause.message || err.cause.name}.`;
167
+ }
168
+ if (err.code || err.cause?.code) {
169
+ errorMessage += ` Code: ${err.code || err.cause?.code}`;
170
+ }
171
+ throw new Error(errorMessage);
172
+ }
173
+ }
174
+ collectSunsetWarning(response) {
175
+ const sunsetTime = this.getSunsetDate(response);
176
+ if (!sunsetTime) return;
177
+ const sunsetDate = new Date(sunsetTime);
178
+ if (sunsetTime > Date.now()) {
179
+ this.sunsetWarnings.push({
180
+ sunsetDate,
181
+ isSunsetExpired: false
182
+ });
183
+ } else {
184
+ this.sunsetWarnings.push({
185
+ sunsetDate,
186
+ isSunsetExpired: true
187
+ });
188
+ }
189
+ }
190
+ getSunsetDate(response) {
191
+ const { headers } = response;
192
+ if (!headers) {
193
+ return;
194
+ }
195
+ const sunsetDate = headers.get("sunset") || headers.get("Sunset");
196
+ if (!sunsetDate) {
197
+ return;
198
+ }
199
+ return Date.parse(sunsetDate);
200
+ }
201
+ };
202
+ var RemotesApi = class {
203
+ constructor(client, domain, apiKey) {
204
+ this.client = client;
205
+ this.domain = domain;
206
+ this.apiKey = apiKey;
207
+ }
208
+ client;
209
+ domain;
210
+ apiKey;
211
+ async getParsedResponse(response) {
212
+ const responseBody = await response.json();
213
+ if (response.ok) {
214
+ return responseBody;
215
+ }
216
+ throw new ReuniteApiError(
217
+ `${responseBody.title || response.statusText || "Unknown error"}.`,
218
+ response.status
219
+ );
220
+ }
221
+ async getDefaultBranch(organizationId, projectId) {
222
+ try {
223
+ const response = await this.client.request(
224
+ `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/source`,
225
+ {
226
+ timeout: DEFAULT_FETCH_TIMEOUT,
227
+ method: "GET",
228
+ headers: {
229
+ "Content-Type": "application/json",
230
+ Authorization: `Bearer ${this.apiKey}`
231
+ }
232
+ }
233
+ );
234
+ const source = await this.getParsedResponse(response);
235
+ return source.branchName;
236
+ } catch (err) {
237
+ const message = `Failed to fetch default branch. ${err.message}`;
238
+ if (err instanceof ReuniteApiError) {
239
+ throw new ReuniteApiError(message, err.status);
240
+ }
241
+ throw new Error(message);
242
+ }
243
+ }
244
+ async upsert(organizationId, projectId, remote) {
245
+ try {
246
+ const response = await this.client.request(
247
+ `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes`,
248
+ {
249
+ timeout: DEFAULT_FETCH_TIMEOUT,
250
+ method: "POST",
251
+ headers: {
252
+ "Content-Type": "application/json",
253
+ Authorization: `Bearer ${this.apiKey}`
254
+ },
255
+ body: JSON.stringify({
256
+ mountPath: remote.mountPath,
257
+ mountBranchName: remote.mountBranchName,
258
+ type: "CICD",
259
+ autoMerge: true
260
+ })
261
+ }
262
+ );
263
+ return await this.getParsedResponse(response);
264
+ } catch (err) {
265
+ const message = `Failed to upsert remote. ${err.message}`;
266
+ if (err instanceof ReuniteApiError) {
267
+ throw new ReuniteApiError(message, err.status);
268
+ }
269
+ throw new Error(message);
270
+ }
271
+ }
272
+ async push(organizationId, projectId, payload, files) {
273
+ const formData = new globalThis.FormData();
274
+ formData.append("remoteId", payload.remoteId);
275
+ formData.append("commit[message]", payload.commit.message);
276
+ formData.append("commit[author][name]", payload.commit.author.name);
277
+ formData.append("commit[author][email]", payload.commit.author.email);
278
+ formData.append("commit[branchName]", payload.commit.branchName);
279
+ if (payload.commit.url) {
280
+ formData.append("commit[url]", payload.commit.url);
281
+ }
282
+ if (payload.commit.namespace) {
283
+ formData.append("commit[namespaceId]", payload.commit.namespace);
284
+ }
285
+ if (payload.commit.sha) {
286
+ formData.append("commit[sha]", payload.commit.sha);
287
+ }
288
+ if (payload.commit.repository) {
289
+ formData.append("commit[repositoryId]", payload.commit.repository);
290
+ }
291
+ if (payload.commit.createdAt) {
292
+ formData.append("commit[createdAt]", payload.commit.createdAt);
293
+ }
294
+ for (const file of files) {
295
+ const blob = Buffer.isBuffer(file.stream) ? new Blob([file.stream]) : new Blob([await streamToBuffer(file.stream)]);
296
+ formData.append(`files[${file.path}]`, blob, file.path);
297
+ }
298
+ if (payload.isMainBranch) {
299
+ formData.append("isMainBranch", "true");
300
+ }
301
+ try {
302
+ const response = await this.client.request(
303
+ `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes`,
304
+ {
305
+ method: "POST",
306
+ headers: {
307
+ Authorization: `Bearer ${this.apiKey}`
308
+ },
309
+ body: formData
310
+ }
311
+ );
312
+ return await this.getParsedResponse(response);
313
+ } catch (err) {
314
+ const message = `Failed to push. ${err.message}`;
315
+ if (err instanceof ReuniteApiError) {
316
+ throw new ReuniteApiError(message, err.status);
317
+ }
318
+ throw new Error(message);
319
+ }
320
+ }
321
+ async getRemotesList({
322
+ organizationId,
323
+ projectId,
324
+ mountPath
325
+ }) {
326
+ try {
327
+ const response = await this.client.request(
328
+ `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/remotes?filter=mountPath:/${mountPath}/`,
329
+ {
330
+ timeout: DEFAULT_FETCH_TIMEOUT,
331
+ method: "GET",
332
+ headers: {
333
+ "Content-Type": "application/json",
334
+ Authorization: `Bearer ${this.apiKey}`
335
+ }
336
+ }
337
+ );
338
+ return await this.getParsedResponse(response);
339
+ } catch (err) {
340
+ const message = `Failed to get remote list. ${err.message}`;
341
+ if (err instanceof ReuniteApiError) {
342
+ throw new ReuniteApiError(message, err.status);
343
+ }
344
+ throw new Error(message);
345
+ }
346
+ }
347
+ async getPush({
348
+ organizationId,
349
+ projectId,
350
+ pushId
351
+ }) {
352
+ try {
353
+ const response = await this.client.request(
354
+ `${this.domain}/api/orgs/${organizationId}/projects/${projectId}/pushes/${pushId}`,
355
+ {
356
+ timeout: DEFAULT_FETCH_TIMEOUT,
357
+ method: "GET",
358
+ headers: {
359
+ "Content-Type": "application/json",
360
+ Authorization: `Bearer ${this.apiKey}`
361
+ }
362
+ }
363
+ );
364
+ return await this.getParsedResponse(response);
365
+ } catch (err) {
366
+ const message = `Failed to get push status. ${err.message}`;
367
+ if (err instanceof ReuniteApiError) {
368
+ throw new ReuniteApiError(message, err.status);
369
+ }
370
+ throw new Error(message);
371
+ }
372
+ }
373
+ };
374
+ var ReuniteApi = class {
375
+ apiClient;
376
+ command;
377
+ remotes;
378
+ constructor({
379
+ domain,
380
+ apiKey,
381
+ command
382
+ }) {
383
+ this.command = command;
384
+ this.apiClient = new ReuniteApiClient(this.command);
385
+ this.remotes = new RemotesApi(this.apiClient, domain, apiKey);
386
+ }
387
+ reportSunsetWarnings() {
388
+ const sunsetWarnings = this.apiClient.sunsetWarnings;
389
+ if (sunsetWarnings.length) {
390
+ const [{ isSunsetExpired, sunsetDate }] = sunsetWarnings.sort(
391
+ (a, b) => {
392
+ if (a.isSunsetExpired !== b.isSunsetExpired) {
393
+ return a.isSunsetExpired ? -1 : 1;
394
+ }
395
+ return a.sunsetDate > b.sunsetDate ? 1 : -1;
396
+ }
397
+ );
398
+ const updateVersionMessage = `Update to the latest version by running "npm install @redocly/cli@latest".`;
399
+ if (isSunsetExpired) {
400
+ logger.error(
401
+ `The "${this.command}" command is not compatible with your version of Redocly CLI. ${updateVersionMessage}
402
+
403
+ `
404
+ );
405
+ } else {
406
+ logger.warn(
407
+ `The "${this.command}" command will be incompatible with your version of Redocly CLI after ${sunsetDate.toLocaleString()}. ${updateVersionMessage}
408
+
409
+ `
410
+ );
411
+ }
412
+ }
413
+ }
414
+ };
415
+ async function streamToBuffer(stream) {
416
+ const chunks = [];
417
+ for await (const chunk of stream) {
418
+ chunks.push(chunk);
419
+ }
420
+ return Buffer.concat(chunks);
421
+ }
422
+
423
+ // src/auth/device-flow.ts
424
+ var RedoclyOAuthDeviceFlow = class {
425
+ constructor(baseUrl) {
426
+ this.baseUrl = baseUrl;
427
+ this.apiClient = new ReuniteApiClient("login");
428
+ }
429
+ baseUrl;
430
+ apiClient;
431
+ clientName = "redocly-cli";
432
+ async run() {
433
+ const code = await this.getDeviceCode();
434
+ logger.output(
435
+ "Attempting to automatically open the SSO authorization page in your default browser.\n"
436
+ );
437
+ logger.output(
438
+ "If the browser does not open or you wish to use a different device to authorize this request, open the following URL:\n\n"
439
+ );
440
+ logger.output(blue(code.verificationUri));
441
+ logger.output(`
442
+
443
+ `);
444
+ logger.output(`Then enter the code:
445
+
446
+ `);
447
+ logger.output(blue(code.userCode));
448
+ logger.output(`
449
+
450
+ `);
451
+ this.openBrowser(code.verificationUriComplete);
452
+ const accessToken = await this.pollingAccessToken(
453
+ code.deviceCode,
454
+ code.interval,
455
+ code.expiresIn
456
+ );
457
+ logger.output(green("\u2705 Logged in\n\n"));
458
+ return this.withResidency(accessToken);
459
+ }
460
+ openBrowser(url) {
461
+ try {
462
+ const cmd = process.platform === "win32" ? `start ${url}` : process.platform === "darwin" ? `open ${url}` : `xdg-open ${url}`;
463
+ childProcess.execSync(cmd);
464
+ } catch {
465
+ }
466
+ }
467
+ async verifyToken(accessToken) {
468
+ try {
469
+ const response = await this.sendRequest("/session", "GET", void 0, {
470
+ Cookie: `accessToken=${accessToken};`
471
+ });
472
+ return !!response.user;
473
+ } catch {
474
+ return false;
475
+ }
476
+ }
477
+ async verifyApiKey(apiKey) {
478
+ try {
479
+ const response = await this.sendRequest("/api-keys-verify", "POST", {
480
+ apiKey
481
+ });
482
+ return !!response.success;
483
+ } catch {
484
+ return false;
485
+ }
486
+ }
487
+ async refreshToken(refreshToken) {
488
+ const response = await this.sendRequest(`/device-rotate-token`, "POST", {
489
+ grant_type: "refresh_token",
490
+ client_name: this.clientName,
491
+ refresh_token: refreshToken
492
+ });
493
+ if (!response.access_token) {
494
+ throw new Error("Failed to refresh token");
495
+ }
496
+ return this.withResidency({
497
+ access_token: response.access_token,
498
+ refresh_token: response.refresh_token,
499
+ expires_in: response.expires_in
500
+ });
501
+ }
502
+ async pollingAccessToken(deviceCode, interval, expiresIn) {
503
+ return new Promise((resolve, reject) => {
504
+ const intervalId = setInterval(async () => {
505
+ const response = await this.getAccessToken(deviceCode);
506
+ if (response.access_token) {
507
+ clearInterval(intervalId);
508
+ clearTimeout(timeoutId);
509
+ resolve(response);
510
+ }
511
+ if (response.error && response.error !== "authorization_pending") {
512
+ clearInterval(intervalId);
513
+ clearTimeout(timeoutId);
514
+ reject(response.error_description);
515
+ }
516
+ }, interval * 1e3);
517
+ const timeoutId = setTimeout(async () => {
518
+ clearInterval(intervalId);
519
+ clearTimeout(timeoutId);
520
+ reject("Authorization has expired. Please try again.");
521
+ }, expiresIn * 1e3);
522
+ });
523
+ }
524
+ async getAccessToken(deviceCode) {
525
+ return await this.sendRequest("/device-token", "POST", {
526
+ client_name: this.clientName,
527
+ device_code: deviceCode,
528
+ grant_type: "urn:ietf:params:oauth:grant-type:device_code"
529
+ });
530
+ }
531
+ async getDeviceCode() {
532
+ const {
533
+ device_code: deviceCode,
534
+ user_code: userCode,
535
+ verification_uri: verificationUri,
536
+ verification_uri_complete: verificationUriComplete,
537
+ interval = 10,
538
+ expires_in: expiresIn = 300
539
+ } = await this.sendRequest("/device-authorize", "POST", {
540
+ client_name: this.clientName
541
+ });
542
+ return {
543
+ deviceCode,
544
+ userCode,
545
+ verificationUri,
546
+ verificationUriComplete,
547
+ interval,
548
+ expiresIn
549
+ };
550
+ }
551
+ async sendRequest(path2, method = "GET", body = void 0, headers = {}) {
552
+ const url = `${this.baseUrl}/api${path2}`;
553
+ const response = await this.apiClient.request(url, {
554
+ body: body ? JSON.stringify(body) : body,
555
+ method,
556
+ headers: { "Content-Type": "application/json", ...headers },
557
+ timeout: DEFAULT_FETCH_TIMEOUT
558
+ });
559
+ if (response.status === 204) {
560
+ return { success: true };
561
+ }
562
+ return await response.json();
563
+ }
564
+ withResidency(credentials) {
565
+ return {
566
+ ...credentials,
567
+ residency: this.baseUrl
568
+ };
569
+ }
570
+ };
571
+
572
+ // src/auth/oauth-client.ts
573
+ var CREDENTIALS_SALT = "4618dbc9-8aed-4e27-aaf0-225f4603e5a4";
574
+ var CRYPTO_ALGORITHM = "aes-256-cbc";
575
+ var RedoclyOAuthClient = class {
576
+ credentialsFolderPath;
577
+ credentialsFilePath;
578
+ credentialsFileName;
579
+ key;
580
+ iv;
581
+ constructor() {
582
+ const homeDirPath = homedir();
583
+ this.credentialsFolderPath = path.join(homeDirPath, ".redocly");
584
+ this.credentialsFileName = "credentials";
585
+ this.credentialsFilePath = path.join(this.credentialsFolderPath, this.credentialsFileName);
586
+ this.key = crypto.createHash("sha256").update(`${this.credentialsFolderPath}${CREDENTIALS_SALT}`).digest();
587
+ this.iv = crypto.createHash("md5").update(this.credentialsFolderPath).digest();
588
+ mkdirSync(this.credentialsFolderPath, { recursive: true });
589
+ }
590
+ async login(baseUrl) {
591
+ const deviceFlow = new RedoclyOAuthDeviceFlow(baseUrl);
592
+ const credentials = await deviceFlow.run();
593
+ if (!credentials) {
594
+ throw new Error("Failed to login. No credentials received.");
595
+ }
596
+ this.saveCredentials(credentials);
597
+ }
598
+ async logout() {
599
+ try {
600
+ this.removeCredentials();
601
+ } catch (err) {
602
+ }
603
+ }
604
+ async isAuthorized(reuniteUrl, apiKey) {
605
+ if (apiKey) {
606
+ const deviceFlow = new RedoclyOAuthDeviceFlow(reuniteUrl);
607
+ return deviceFlow.verifyApiKey(apiKey);
608
+ }
609
+ const accessToken = await this.getAccessToken(reuniteUrl);
610
+ return Boolean(accessToken);
611
+ }
612
+ getAccessToken = async (reuniteUrl) => {
613
+ const deviceFlow = new RedoclyOAuthDeviceFlow(reuniteUrl);
614
+ const credentials = await this.readCredentials();
615
+ if (!credentials || !isValidReuniteUrl(reuniteUrl) || credentials.residency && credentials.residency !== reuniteUrl) {
616
+ return null;
617
+ }
618
+ const isValid = await deviceFlow.verifyToken(credentials.access_token);
619
+ if (isValid) {
620
+ return credentials.access_token;
621
+ }
622
+ try {
623
+ const newCredentials = await deviceFlow.refreshToken(credentials.refresh_token);
624
+ await this.saveCredentials(newCredentials);
625
+ return newCredentials.access_token;
626
+ } catch {
627
+ return null;
628
+ }
629
+ };
630
+ async saveCredentials(credentials) {
631
+ try {
632
+ const encryptedCredentials = this.encryptCredentials(credentials);
633
+ writeFileSync(this.credentialsFilePath, encryptedCredentials, "utf8");
634
+ } catch (error) {
635
+ logger.error(`Failed to save credentials: ${error.message}`);
636
+ }
637
+ }
638
+ async readCredentials() {
639
+ if (!existsSync(this.credentialsFilePath)) {
640
+ return null;
641
+ }
642
+ try {
643
+ const encryptedCredentials = readFileSync(this.credentialsFilePath, "utf8");
644
+ return this.decryptCredentials(encryptedCredentials);
645
+ } catch {
646
+ return null;
647
+ }
648
+ }
649
+ async removeCredentials() {
650
+ if (existsSync(this.credentialsFilePath)) {
651
+ rmSync(this.credentialsFilePath);
652
+ }
653
+ }
654
+ encryptCredentials(credentials) {
655
+ const cipher = crypto.createCipheriv(CRYPTO_ALGORITHM, this.key, this.iv);
656
+ const encrypted = Buffer2.concat([
657
+ cipher.update(JSON.stringify(credentials), "utf8"),
658
+ cipher.final()
659
+ ]);
660
+ return encrypted.toString("hex");
661
+ }
662
+ decryptCredentials(encryptedCredentials) {
663
+ const decipher = crypto.createDecipheriv(CRYPTO_ALGORITHM, this.key, this.iv);
664
+ const decrypted = Buffer2.concat([
665
+ decipher.update(Buffer2.from(encryptedCredentials, "hex")),
666
+ decipher.final()
667
+ ]);
668
+ return JSON.parse(decrypted.toString("utf8"));
669
+ }
670
+ };
671
+
672
+ export {
673
+ getDomain,
674
+ getReuniteUrl,
675
+ getProxyUrl,
676
+ shouldBypassProxy,
677
+ fetch_with_timeout_default,
678
+ ReuniteApiError,
679
+ ReuniteApi,
680
+ RedoclyOAuthClient
681
+ };