@redocly/cli 1.29.0 → 1.31.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.
- package/CHANGELOG.md +23 -1
- package/README.md +36 -16
- package/lib/__tests__/commands/push-region.test.js +3 -3
- package/lib/auth/__tests__/device-flow.test.js +62 -0
- package/lib/auth/__tests__/oauth-client.test.js +93 -0
- package/lib/auth/device-flow.d.ts +26 -0
- package/lib/auth/device-flow.js +133 -0
- package/lib/auth/oauth-client.d.ts +14 -0
- package/lib/auth/oauth-client.js +93 -0
- package/lib/commands/auth.d.ts +13 -0
- package/lib/commands/auth.js +51 -0
- package/lib/commands/push.d.ts +1 -1
- package/lib/commands/push.js +4 -4
- package/lib/index.js +103 -15
- package/lib/otel.d.ts +10 -0
- package/lib/otel.js +47 -0
- package/lib/reunite/api/__tests__/domains.test.js +32 -0
- package/lib/{cms → reunite}/api/api-client.d.ts +9 -0
- package/lib/{cms → reunite}/api/api-client.js +2 -1
- package/lib/reunite/api/domains.d.ts +4 -0
- package/lib/reunite/api/domains.js +22 -0
- package/lib/reunite/commands/__tests__/push.test.d.ts +1 -0
- package/lib/reunite/commands/__tests__/utils.test.d.ts +1 -0
- package/lib/types.d.ts +5 -4
- package/lib/utils/miscellaneous.d.ts +5 -4
- package/lib/utils/miscellaneous.js +14 -14
- package/package.json +11 -4
- package/src/__tests__/commands/push-region.test.ts +2 -2
- package/src/auth/__tests__/device-flow.test.ts +73 -0
- package/src/auth/__tests__/oauth-client.test.ts +117 -0
- package/src/auth/device-flow.ts +175 -0
- package/src/auth/oauth-client.ts +111 -0
- package/src/commands/auth.ts +66 -0
- package/src/commands/push.ts +3 -3
- package/src/index.ts +115 -16
- package/src/otel.ts +59 -0
- package/src/reunite/api/__tests__/domains.test.ts +41 -0
- package/src/{cms → reunite}/api/api-client.ts +1 -1
- package/src/reunite/api/domains.ts +23 -0
- package/src/types.ts +8 -4
- package/src/utils/miscellaneous.ts +19 -18
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
- package/lib/cms/api/__tests__/domains.test.js +0 -13
- package/lib/cms/api/domains.d.ts +0 -1
- package/lib/cms/api/domains.js +0 -11
- package/lib/commands/login.d.ts +0 -9
- package/lib/commands/login.js +0 -23
- package/src/cms/api/__tests__/domains.test.ts +0 -15
- package/src/cms/api/domains.ts +0 -11
- package/src/commands/login.ts +0 -34
- /package/lib/{cms/api/__tests__/api-keys.test.d.ts → auth/__tests__/device-flow.test.d.ts} +0 -0
- /package/lib/{cms/api/__tests__/api.client.test.d.ts → auth/__tests__/oauth-client.test.d.ts} +0 -0
- /package/lib/{cms/api/__tests__/domains.test.d.ts → reunite/api/__tests__/api-keys.test.d.ts} +0 -0
- /package/lib/{cms → reunite}/api/__tests__/api-keys.test.js +0 -0
- /package/lib/{cms/commands/__tests__/push-status.test.d.ts → reunite/api/__tests__/api.client.test.d.ts} +0 -0
- /package/lib/{cms → reunite}/api/__tests__/api.client.test.js +0 -0
- /package/lib/{cms/commands/__tests__/push.test.d.ts → reunite/api/__tests__/domains.test.d.ts} +0 -0
- /package/lib/{cms → reunite}/api/api-keys.d.ts +0 -0
- /package/lib/{cms → reunite}/api/api-keys.js +0 -0
- /package/lib/{cms → reunite}/api/index.d.ts +0 -0
- /package/lib/{cms → reunite}/api/index.js +0 -0
- /package/lib/{cms → reunite}/api/types.d.ts +0 -0
- /package/lib/{cms → reunite}/api/types.js +0 -0
- /package/lib/{cms/commands/__tests__/utils.test.d.ts → reunite/commands/__tests__/push-status.test.d.ts} +0 -0
- /package/lib/{cms → reunite}/commands/__tests__/push-status.test.js +0 -0
- /package/lib/{cms → reunite}/commands/__tests__/push.test.js +0 -0
- /package/lib/{cms → reunite}/commands/__tests__/utils.test.js +0 -0
- /package/lib/{cms → reunite}/commands/push-status.d.ts +0 -0
- /package/lib/{cms → reunite}/commands/push-status.js +0 -0
- /package/lib/{cms → reunite}/commands/push.d.ts +0 -0
- /package/lib/{cms → reunite}/commands/push.js +0 -0
- /package/lib/{cms → reunite}/commands/utils.d.ts +0 -0
- /package/lib/{cms → reunite}/commands/utils.js +0 -0
- /package/lib/{cms → reunite}/utils.d.ts +0 -0
- /package/lib/{cms → reunite}/utils.js +0 -0
- /package/src/{cms → reunite}/api/__tests__/api-keys.test.ts +0 -0
- /package/src/{cms → reunite}/api/__tests__/api.client.test.ts +0 -0
- /package/src/{cms → reunite}/api/api-keys.ts +0 -0
- /package/src/{cms → reunite}/api/index.ts +0 -0
- /package/src/{cms → reunite}/api/types.ts +0 -0
- /package/src/{cms → reunite}/commands/__tests__/push-status.test.ts +0 -0
- /package/src/{cms → reunite}/commands/__tests__/push.test.ts +0 -0
- /package/src/{cms → reunite}/commands/__tests__/utils.test.ts +0 -0
- /package/src/{cms → reunite}/commands/push-status.ts +0 -0
- /package/src/{cms → reunite}/commands/push.ts +0 -0
- /package/src/{cms → reunite}/commands/utils.ts +0 -0
- /package/src/{cms → reunite}/utils.ts +0 -0
package/lib/commands/push.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { handlePush as handleCMSPush } from '../
|
|
1
|
+
import { handlePush as handleCMSPush } from '../reunite/commands/push';
|
|
2
2
|
import type { Config, Region } from '@redocly/openapi-core';
|
|
3
3
|
import type { CommandArgs } from '../wrapper';
|
|
4
4
|
import type { VerifyConfigOptions } from '../types';
|
package/lib/commands/push.js
CHANGED
|
@@ -13,9 +13,9 @@ const crypto_1 = require("crypto");
|
|
|
13
13
|
const openapi_core_1 = require("@redocly/openapi-core");
|
|
14
14
|
const utils_1 = require("@redocly/openapi-core/lib/utils");
|
|
15
15
|
const miscellaneous_1 = require("../utils/miscellaneous");
|
|
16
|
-
const
|
|
17
|
-
const push_1 = require("../
|
|
18
|
-
const api_client_1 = require("../
|
|
16
|
+
const auth_1 = require("./auth");
|
|
17
|
+
const push_1 = require("../reunite/commands/push");
|
|
18
|
+
const api_client_1 = require("../reunite/api/api-client");
|
|
19
19
|
const DEFAULT_VERSION = 'latest';
|
|
20
20
|
exports.DESTINATION_REGEX =
|
|
21
21
|
// eslint-disable-next-line no-useless-escape
|
|
@@ -31,7 +31,7 @@ async function handlePush({ argv, config }) {
|
|
|
31
31
|
const isAuthorized = await client.isAuthorizedWithRedoclyByRegion();
|
|
32
32
|
if (!isAuthorized) {
|
|
33
33
|
try {
|
|
34
|
-
const clientToken = await (0,
|
|
34
|
+
const clientToken = await (0, auth_1.promptClientToken)(client.domain);
|
|
35
35
|
await client.login(clientToken);
|
|
36
36
|
}
|
|
37
37
|
catch (e) {
|
package/lib/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const dotenv = require("dotenv");
|
|
4
6
|
require("./utils/assert-node-version");
|
|
5
7
|
const yargs = require("yargs");
|
|
6
8
|
const colors = require("colorette");
|
|
7
|
-
const openapi_core_1 = require("@redocly/openapi-core");
|
|
8
9
|
const types_1 = require("./types");
|
|
9
10
|
const preview_docs_1 = require("./commands/preview-docs");
|
|
10
11
|
const stats_1 = require("./commands/stats");
|
|
11
12
|
const split_1 = require("./commands/split");
|
|
12
13
|
const join_1 = require("./commands/join");
|
|
13
|
-
const push_status_1 = require("./
|
|
14
|
+
const push_status_1 = require("./reunite/commands/push-status");
|
|
14
15
|
const lint_1 = require("./commands/lint");
|
|
15
16
|
const bundle_1 = require("./commands/bundle");
|
|
16
|
-
const
|
|
17
|
+
const auth_1 = require("./commands/auth");
|
|
17
18
|
const build_docs_1 = require("./commands/build-docs");
|
|
18
19
|
const update_version_notifier_1 = require("./utils/update-version-notifier");
|
|
19
20
|
const wrapper_1 = require("./wrapper");
|
|
@@ -22,6 +23,7 @@ const translations_1 = require("./commands/translations");
|
|
|
22
23
|
const eject_1 = require("./commands/eject");
|
|
23
24
|
const constants_1 = require("./commands/preview-project/constants");
|
|
24
25
|
const push_1 = require("./commands/push");
|
|
26
|
+
dotenv.config({ path: path.resolve(process.cwd(), './.env') });
|
|
25
27
|
if (!('replaceAll' in String.prototype)) {
|
|
26
28
|
require('core-js/actual/string/replace-all');
|
|
27
29
|
}
|
|
@@ -521,32 +523,32 @@ yargs
|
|
|
521
523
|
process.env.REDOCLY_CLI_COMMAND = 'check-config';
|
|
522
524
|
(0, wrapper_1.commandWrapper)()(argv);
|
|
523
525
|
})
|
|
524
|
-
.command('login', '
|
|
526
|
+
.command('login', 'Log in to Redocly.', async (yargs) => yargs.options({
|
|
525
527
|
verbose: {
|
|
526
528
|
description: 'Include additional output.',
|
|
527
529
|
type: 'boolean',
|
|
528
530
|
},
|
|
529
|
-
|
|
530
|
-
description: '
|
|
531
|
-
alias: 'r',
|
|
532
|
-
|
|
531
|
+
residency: {
|
|
532
|
+
description: 'Residency of the application. Defaults to `us`.',
|
|
533
|
+
alias: ['r', 'region'],
|
|
534
|
+
type: 'string',
|
|
533
535
|
},
|
|
534
536
|
config: {
|
|
535
537
|
description: 'Path to the config file.',
|
|
536
538
|
requiresArg: true,
|
|
537
539
|
type: 'string',
|
|
538
540
|
},
|
|
541
|
+
next: {
|
|
542
|
+
description: 'Use Reunite application to login.',
|
|
543
|
+
type: 'boolean',
|
|
544
|
+
},
|
|
539
545
|
}), (argv) => {
|
|
540
546
|
process.env.REDOCLY_CLI_COMMAND = 'login';
|
|
541
|
-
(0, wrapper_1.commandWrapper)(
|
|
547
|
+
(0, wrapper_1.commandWrapper)(auth_1.handleLogin)(argv);
|
|
542
548
|
})
|
|
543
|
-
.command('logout', 'Clear your stored credentials for the Redocly API registry.', (yargs) => yargs,
|
|
549
|
+
.command('logout', 'Clear your stored credentials for the Redocly API registry.', (yargs) => yargs, (argv) => {
|
|
544
550
|
process.env.REDOCLY_CLI_COMMAND = 'logout';
|
|
545
|
-
|
|
546
|
-
const client = new openapi_core_1.RedoclyClient();
|
|
547
|
-
client.logout();
|
|
548
|
-
process.stdout.write('Logged out from the Redocly account. ✋\n');
|
|
549
|
-
})(argv);
|
|
551
|
+
(0, wrapper_1.commandWrapper)(auth_1.handleLogout)(argv);
|
|
550
552
|
})
|
|
551
553
|
.command('preview', 'Preview Redocly project using one of the product NPM packages.', (yargs) => yargs.options({
|
|
552
554
|
product: {
|
|
@@ -726,6 +728,92 @@ yargs
|
|
|
726
728
|
}), (argv) => {
|
|
727
729
|
process.env.REDOCLY_CLI_COMMAND = 'eject';
|
|
728
730
|
(0, wrapper_1.commandWrapper)(eject_1.handleEject)(argv);
|
|
731
|
+
})
|
|
732
|
+
.command('respect [files...]', 'Run Arazzo tests.', (yargs) => {
|
|
733
|
+
return yargs
|
|
734
|
+
.positional('files', {
|
|
735
|
+
describe: 'Test files or glob pattern.',
|
|
736
|
+
type: 'string',
|
|
737
|
+
array: true,
|
|
738
|
+
default: [],
|
|
739
|
+
})
|
|
740
|
+
.env('REDOCLY_CLI_RESPECT')
|
|
741
|
+
.options({
|
|
742
|
+
input: {
|
|
743
|
+
alias: 'i',
|
|
744
|
+
describe: 'Input parameters.',
|
|
745
|
+
type: 'string',
|
|
746
|
+
},
|
|
747
|
+
server: {
|
|
748
|
+
alias: 'S',
|
|
749
|
+
describe: 'Server parameters.',
|
|
750
|
+
type: 'string',
|
|
751
|
+
},
|
|
752
|
+
workflow: {
|
|
753
|
+
alias: 'w',
|
|
754
|
+
describe: 'Workflow name.',
|
|
755
|
+
type: 'string',
|
|
756
|
+
array: true,
|
|
757
|
+
},
|
|
758
|
+
skip: {
|
|
759
|
+
alias: 's',
|
|
760
|
+
describe: 'Workflow to skip.',
|
|
761
|
+
type: 'string',
|
|
762
|
+
array: true,
|
|
763
|
+
},
|
|
764
|
+
verbose: {
|
|
765
|
+
alias: 'v',
|
|
766
|
+
describe: 'Apply verbose mode.',
|
|
767
|
+
type: 'boolean',
|
|
768
|
+
},
|
|
769
|
+
'har-output': {
|
|
770
|
+
describe: 'Har file output name.',
|
|
771
|
+
type: 'string',
|
|
772
|
+
},
|
|
773
|
+
'json-output': {
|
|
774
|
+
describe: 'JSON file output name.',
|
|
775
|
+
type: 'string',
|
|
776
|
+
},
|
|
777
|
+
'client-cert': {
|
|
778
|
+
describe: 'Mutual TLS client certificate.',
|
|
779
|
+
type: 'string',
|
|
780
|
+
},
|
|
781
|
+
'client-key': {
|
|
782
|
+
describe: 'Mutual TLS client key.',
|
|
783
|
+
type: 'string',
|
|
784
|
+
},
|
|
785
|
+
'ca-cert': {
|
|
786
|
+
describe: 'Mutual TLS CA certificate.',
|
|
787
|
+
type: 'string',
|
|
788
|
+
},
|
|
789
|
+
severity: {
|
|
790
|
+
describe: 'Severity of the check.',
|
|
791
|
+
type: 'string',
|
|
792
|
+
},
|
|
793
|
+
});
|
|
794
|
+
}, async (argv) => {
|
|
795
|
+
process.env.REDOCLY_CLI_COMMAND = 'respect';
|
|
796
|
+
const { handleRun } = await Promise.resolve().then(() => require('@redocly/respect-core'));
|
|
797
|
+
(0, wrapper_1.commandWrapper)(handleRun)(argv);
|
|
798
|
+
})
|
|
799
|
+
.command('generate-arazzo <descriptionPath>', 'Auto-generate arazzo description file from an API description.', (yargs) => {
|
|
800
|
+
return yargs
|
|
801
|
+
.positional('descriptionPath', {
|
|
802
|
+
describe: 'Description file path.',
|
|
803
|
+
type: 'string',
|
|
804
|
+
})
|
|
805
|
+
.env('REDOCLY_CLI_RESPECT')
|
|
806
|
+
.options({
|
|
807
|
+
'output-file': {
|
|
808
|
+
alias: 'o',
|
|
809
|
+
describe: 'Output File name.',
|
|
810
|
+
type: 'string',
|
|
811
|
+
},
|
|
812
|
+
});
|
|
813
|
+
}, async (argv) => {
|
|
814
|
+
process.env.REDOCLY_CLI_COMMAND = 'generate-arazzo';
|
|
815
|
+
const { handleGenerate } = await Promise.resolve().then(() => require('@redocly/respect-core'));
|
|
816
|
+
(0, wrapper_1.commandWrapper)(handleGenerate)(argv);
|
|
729
817
|
})
|
|
730
818
|
.completion('completion', 'Generate autocomplete script for `redocly` command.')
|
|
731
819
|
.demandCommand(1)
|
package/lib/otel.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { Analytics } from './utils/miscellaneous';
|
|
2
|
+
type Events = {
|
|
3
|
+
[key: string]: Analytics;
|
|
4
|
+
};
|
|
5
|
+
export declare class OtelServerTelemetry {
|
|
6
|
+
init(): void;
|
|
7
|
+
send<K extends keyof Events>(event: K, data: Events[K]): void;
|
|
8
|
+
}
|
|
9
|
+
export declare const otelTelemetry: OtelServerTelemetry;
|
|
10
|
+
export {};
|
package/lib/otel.js
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.otelTelemetry = exports.OtelServerTelemetry = void 0;
|
|
4
|
+
const api_1 = require("@opentelemetry/api");
|
|
5
|
+
const resources_1 = require("@opentelemetry/resources");
|
|
6
|
+
const sdk_trace_node_1 = require("@opentelemetry/sdk-trace-node");
|
|
7
|
+
const exporter_trace_otlp_http_1 = require("@opentelemetry/exporter-trace-otlp-http");
|
|
8
|
+
const semantic_conventions_1 = require("@opentelemetry/semantic-conventions");
|
|
9
|
+
const update_version_notifier_1 = require("./utils/update-version-notifier");
|
|
10
|
+
const fetch_with_timeout_1 = require("./utils/fetch-with-timeout");
|
|
11
|
+
const OTEL_TRACES_URL = process.env.OTEL_TRACES_URL || 'https://otel.cloud.redocly.com/v1/traces';
|
|
12
|
+
class OtelServerTelemetry {
|
|
13
|
+
init() {
|
|
14
|
+
const nodeTracerProvider = new sdk_trace_node_1.NodeTracerProvider({
|
|
15
|
+
resource: new resources_1.Resource({
|
|
16
|
+
[semantic_conventions_1.ATTR_SERVICE_NAME]: `redocly-cli`,
|
|
17
|
+
[semantic_conventions_1.ATTR_SERVICE_VERSION]: `@redocly/cli@${update_version_notifier_1.version}`,
|
|
18
|
+
}),
|
|
19
|
+
});
|
|
20
|
+
nodeTracerProvider.addSpanProcessor(new sdk_trace_node_1.SimpleSpanProcessor(new exporter_trace_otlp_http_1.OTLPTraceExporter({
|
|
21
|
+
url: OTEL_TRACES_URL,
|
|
22
|
+
headers: {},
|
|
23
|
+
timeoutMillis: fetch_with_timeout_1.DEFAULT_FETCH_TIMEOUT,
|
|
24
|
+
})));
|
|
25
|
+
nodeTracerProvider.register();
|
|
26
|
+
}
|
|
27
|
+
send(event, data) {
|
|
28
|
+
const time = new Date();
|
|
29
|
+
const eventId = crypto.randomUUID();
|
|
30
|
+
const span = api_1.trace.getTracer('CliTelemetry').startSpan(`event.${event}`, {
|
|
31
|
+
attributes: {
|
|
32
|
+
'cloudevents.event_client.id': eventId,
|
|
33
|
+
'cloudevents.event_client.type': event,
|
|
34
|
+
},
|
|
35
|
+
startTime: time,
|
|
36
|
+
});
|
|
37
|
+
for (const [key, value] of Object.entries(data)) {
|
|
38
|
+
const keySnakeCase = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
39
|
+
if (value !== undefined) {
|
|
40
|
+
span.setAttribute(`cloudevents.event_data.${keySnakeCase}`, value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
span.end(time);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
exports.OtelServerTelemetry = OtelServerTelemetry;
|
|
47
|
+
exports.otelTelemetry = new OtelServerTelemetry();
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const domains_1 = require("../domains");
|
|
4
|
+
const domains_2 = require("../domains");
|
|
5
|
+
describe('getDomain()', () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
delete process.env.REDOCLY_DOMAIN;
|
|
8
|
+
});
|
|
9
|
+
it('should return the domain from environment variable', () => {
|
|
10
|
+
process.env.REDOCLY_DOMAIN = 'test-domain';
|
|
11
|
+
expect((0, domains_1.getDomain)()).toBe('test-domain');
|
|
12
|
+
});
|
|
13
|
+
it('should return the default domain if no domain provided', () => {
|
|
14
|
+
process.env.REDOCLY_DOMAIN = '';
|
|
15
|
+
expect((0, domains_1.getDomain)()).toBe('https://app.cloud.redocly.com');
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
describe('getReuniteUrl()', () => {
|
|
19
|
+
it('should return US API URL when US region specified', () => {
|
|
20
|
+
expect((0, domains_2.getReuniteUrl)('us')).toBe('https://app.cloud.redocly.com/api');
|
|
21
|
+
});
|
|
22
|
+
it('should return EU API URL when EU region specified', () => {
|
|
23
|
+
expect((0, domains_2.getReuniteUrl)('eu')).toBe('https://app.cloud.eu.redocly.com/api');
|
|
24
|
+
});
|
|
25
|
+
it('should return custom domain API URL when custom domain specified', () => {
|
|
26
|
+
const customDomain = 'https://custom.domain.com';
|
|
27
|
+
expect((0, domains_2.getReuniteUrl)(customDomain)).toBe('https://custom.domain.com/api');
|
|
28
|
+
});
|
|
29
|
+
it('should return US API URL when no region specified', () => {
|
|
30
|
+
expect((0, domains_2.getReuniteUrl)()).toBe('https://app.cloud.redocly.com/api');
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -15,6 +15,15 @@ export declare class ReuniteApiError extends Error {
|
|
|
15
15
|
status: number;
|
|
16
16
|
constructor(message: string, status: number);
|
|
17
17
|
}
|
|
18
|
+
export declare class ReuniteApiClient implements BaseApiClient {
|
|
19
|
+
protected version: string;
|
|
20
|
+
protected command: string;
|
|
21
|
+
sunsetWarnings: SunsetWarningsBuffer;
|
|
22
|
+
constructor(version: string, command: string);
|
|
23
|
+
request(url: string, options: FetchWithTimeoutOptions): Promise<Response>;
|
|
24
|
+
private collectSunsetWarning;
|
|
25
|
+
private getSunsetDate;
|
|
26
|
+
}
|
|
18
27
|
declare class RemotesApi {
|
|
19
28
|
private client;
|
|
20
29
|
private readonly domain;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.ReuniteApi = exports.ReuniteApiError = void 0;
|
|
3
|
+
exports.ReuniteApi = exports.ReuniteApiClient = exports.ReuniteApiError = void 0;
|
|
4
4
|
exports.streamToBuffer = streamToBuffer;
|
|
5
5
|
const colorette_1 = require("colorette");
|
|
6
6
|
const fetch_with_timeout_1 = require("../../utils/fetch-with-timeout");
|
|
@@ -59,6 +59,7 @@ class ReuniteApiClient {
|
|
|
59
59
|
return Date.parse(sunsetDate);
|
|
60
60
|
}
|
|
61
61
|
}
|
|
62
|
+
exports.ReuniteApiClient = ReuniteApiClient;
|
|
62
63
|
class RemotesApi {
|
|
63
64
|
constructor(client, domain, apiKey) {
|
|
64
65
|
this.client = client;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.REUNITE_URLS = void 0;
|
|
4
|
+
exports.getDomain = getDomain;
|
|
5
|
+
exports.getReuniteUrl = getReuniteUrl;
|
|
6
|
+
exports.REUNITE_URLS = {
|
|
7
|
+
us: 'https://app.cloud.redocly.com',
|
|
8
|
+
eu: 'https://app.cloud.eu.redocly.com',
|
|
9
|
+
};
|
|
10
|
+
function getDomain() {
|
|
11
|
+
return process.env.REDOCLY_DOMAIN || exports.REUNITE_URLS.us;
|
|
12
|
+
}
|
|
13
|
+
function getReuniteUrl(residency) {
|
|
14
|
+
if (!residency)
|
|
15
|
+
residency = 'us';
|
|
16
|
+
let reuniteUrl = exports.REUNITE_URLS[residency];
|
|
17
|
+
if (!reuniteUrl) {
|
|
18
|
+
reuniteUrl = residency;
|
|
19
|
+
}
|
|
20
|
+
const url = new URL('/api', reuniteUrl).toString();
|
|
21
|
+
return url;
|
|
22
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/types.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import type { BundleOutputFormat, Region, Config, RuleSeverity } from '@redocly/openapi-core';
|
|
2
|
+
import type { RespectOptions, GenerateArazzoFileOptions } from '@redocly/respect-core';
|
|
2
3
|
import type { ArgumentsCamelCase } from 'yargs';
|
|
3
4
|
import type { LintOptions } from './commands/lint';
|
|
4
5
|
import type { BundleOptions } from './commands/bundle';
|
|
5
6
|
import type { JoinOptions } from './commands/join';
|
|
6
|
-
import type { LoginOptions } from './commands/
|
|
7
|
+
import type { LoginOptions, LogoutOptions } from './commands/auth';
|
|
7
8
|
import type { PushOptions } from './commands/push';
|
|
8
9
|
import type { StatsOptions } from './commands/stats';
|
|
9
10
|
import type { SplitOptions } from './commands/split';
|
|
10
11
|
import type { PreviewDocsOptions } from './commands/preview-docs';
|
|
11
12
|
import type { BuildDocsArgv } from './commands/build-docs/types';
|
|
12
|
-
import type { PushOptions as CMSPushOptions } from './
|
|
13
|
-
import type { PushStatusOptions } from './
|
|
13
|
+
import type { PushOptions as CMSPushOptions } from './reunite/commands/push';
|
|
14
|
+
import type { PushStatusOptions } from './reunite/commands/push-status';
|
|
14
15
|
import type { PreviewProjectOptions } from './commands/preview-project/types';
|
|
15
16
|
import type { TranslationsOptions } from './commands/translations';
|
|
16
17
|
import type { EjectOptions } from './commands/eject';
|
|
@@ -27,7 +28,7 @@ export type Entrypoint = {
|
|
|
27
28
|
export declare const outputExtensions: ReadonlyArray<BundleOutputFormat>;
|
|
28
29
|
export type OutputExtensions = 'json' | 'yaml' | 'yml' | undefined;
|
|
29
30
|
export declare const regionChoices: ReadonlyArray<Region>;
|
|
30
|
-
export type CommandOptions = StatsOptions | SplitOptions | JoinOptions | PushOptions | CMSPushOptions | LintOptions | BundleOptions | LoginOptions | PreviewDocsOptions | BuildDocsArgv | PushStatusOptions | PreviewProjectOptions | TranslationsOptions | EjectOptions;
|
|
31
|
+
export type CommandOptions = StatsOptions | SplitOptions | JoinOptions | PushOptions | CMSPushOptions | LintOptions | BundleOptions | LoginOptions | LogoutOptions | PreviewDocsOptions | BuildDocsArgv | PushStatusOptions | PreviewProjectOptions | TranslationsOptions | EjectOptions | RespectOptions | GenerateArazzoFileOptions;
|
|
31
32
|
export type VerifyConfigOptions = {
|
|
32
33
|
config?: string;
|
|
33
34
|
'lint-config'?: RuleSeverity;
|
|
@@ -59,17 +59,18 @@ export type ExitCode = 0 | 1 | 2;
|
|
|
59
59
|
export type Analytics = {
|
|
60
60
|
event: string;
|
|
61
61
|
event_time: string;
|
|
62
|
-
logged_in:
|
|
63
|
-
command: string
|
|
64
|
-
arguments:
|
|
62
|
+
logged_in: 'yes' | 'no';
|
|
63
|
+
command: string;
|
|
64
|
+
arguments: string;
|
|
65
65
|
node_version: string;
|
|
66
66
|
npm_version: string;
|
|
67
|
+
os_platform: string;
|
|
67
68
|
version: string;
|
|
68
69
|
exit_code: ExitCode;
|
|
69
70
|
environment?: string;
|
|
70
71
|
environment_ci?: string;
|
|
71
72
|
raw_input: string;
|
|
72
|
-
has_config?:
|
|
73
|
+
has_config?: 'yes' | 'no';
|
|
73
74
|
spec_version?: string;
|
|
74
75
|
spec_keyword?: string;
|
|
75
76
|
spec_full_version?: string;
|
|
@@ -37,6 +37,7 @@ const colorette_1 = require("colorette");
|
|
|
37
37
|
const perf_hooks_1 = require("perf_hooks");
|
|
38
38
|
const glob = require("glob");
|
|
39
39
|
const fs = require("fs");
|
|
40
|
+
const os = require("os");
|
|
40
41
|
const readline = require("readline");
|
|
41
42
|
const stream_1 = require("stream");
|
|
42
43
|
const child_process_1 = require("child_process");
|
|
@@ -48,7 +49,7 @@ const reference_docs_config_schema_1 = require("@redocly/config/lib/reference-do
|
|
|
48
49
|
const types_1 = require("../types");
|
|
49
50
|
const update_version_notifier_1 = require("./update-version-notifier");
|
|
50
51
|
const push_1 = require("../commands/push");
|
|
51
|
-
const
|
|
52
|
+
const api_1 = require("../reunite/api");
|
|
52
53
|
async function getFallbackApisOrExit(argsApis, config) {
|
|
53
54
|
const { apis } = config;
|
|
54
55
|
const shouldFallbackToAllDefinitions = !(0, utils_1.isNotEmptyArray)(argsApis) && (0, utils_1.isNotEmptyObject)(apis);
|
|
@@ -448,33 +449,32 @@ async function sendTelemetry(argv, exit_code, has_config, spec_version, spec_key
|
|
|
448
449
|
const { _: [command], $0: _, ...args } = argv;
|
|
449
450
|
const event_time = new Date().toISOString();
|
|
450
451
|
const redoclyClient = new openapi_core_1.RedoclyClient();
|
|
451
|
-
const
|
|
452
|
+
const { RedoclyOAuthClient } = await Promise.resolve().then(() => require('../auth/oauth-client'));
|
|
453
|
+
const oauthClient = new RedoclyOAuthClient('redocly-cli', update_version_notifier_1.version);
|
|
454
|
+
const reuniteUrl = (0, api_1.getReuniteUrl)(argv.residency);
|
|
455
|
+
const logged_in = redoclyClient.hasTokens() || (await oauthClient.isAuthorized(reuniteUrl));
|
|
452
456
|
const data = {
|
|
453
457
|
event: 'cli_command',
|
|
454
458
|
event_time,
|
|
455
|
-
logged_in,
|
|
456
|
-
command
|
|
457
|
-
arguments: cleanArgs(args),
|
|
459
|
+
logged_in: logged_in ? 'yes' : 'no',
|
|
460
|
+
command: `${command}`,
|
|
461
|
+
arguments: JSON.stringify(cleanArgs(args)),
|
|
458
462
|
node_version: process.version,
|
|
459
463
|
npm_version: (0, child_process_1.execSync)('npm -v').toString().replace('\n', ''),
|
|
464
|
+
os_platform: os.platform(),
|
|
460
465
|
version: update_version_notifier_1.version,
|
|
461
466
|
exit_code,
|
|
462
467
|
environment: process.env.REDOCLY_ENVIRONMENT,
|
|
463
468
|
environment_ci: process.env.CI,
|
|
464
469
|
raw_input: cleanRawInput(process.argv.slice(2)),
|
|
465
|
-
has_config,
|
|
470
|
+
has_config: has_config ? 'yes' : 'no',
|
|
466
471
|
spec_version,
|
|
467
472
|
spec_keyword,
|
|
468
473
|
spec_full_version,
|
|
469
474
|
};
|
|
470
|
-
await (
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
headers: {
|
|
474
|
-
'content-type': 'application/json',
|
|
475
|
-
},
|
|
476
|
-
body: JSON.stringify(data),
|
|
477
|
-
});
|
|
475
|
+
const { otelTelemetry } = await Promise.resolve().then(() => require('../otel'));
|
|
476
|
+
otelTelemetry.init();
|
|
477
|
+
otelTelemetry.send(data.command, data);
|
|
478
478
|
}
|
|
479
479
|
catch (err) {
|
|
480
480
|
// Do nothing.
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@redocly/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.31.0",
|
|
4
4
|
"description": "",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"bin": {
|
|
7
|
-
"
|
|
8
|
-
"
|
|
7
|
+
"redocly": "bin/cli.js",
|
|
8
|
+
"openapi": "bin/cli.js"
|
|
9
9
|
},
|
|
10
10
|
"engines": {
|
|
11
11
|
"node": ">=18.17.0",
|
|
@@ -30,22 +30,29 @@
|
|
|
30
30
|
"OpenAPI linter",
|
|
31
31
|
"Swagger linter",
|
|
32
32
|
"AsyncAPI linter",
|
|
33
|
+
"Arazzo linter",
|
|
33
34
|
"oas"
|
|
34
35
|
],
|
|
35
36
|
"contributors": [
|
|
36
37
|
"Roman Hotsiy <roman@redocly.com> (https://redocly.com/)"
|
|
37
38
|
],
|
|
38
39
|
"dependencies": {
|
|
39
|
-
"@redocly/openapi-core": "1.
|
|
40
|
+
"@redocly/openapi-core": "1.31.0",
|
|
40
41
|
"abort-controller": "^3.0.0",
|
|
41
42
|
"chokidar": "^3.5.1",
|
|
42
43
|
"colorette": "^1.2.0",
|
|
43
44
|
"core-js": "^3.32.1",
|
|
45
|
+
"dotenv": "^16.4.7",
|
|
44
46
|
"form-data": "^4.0.0",
|
|
45
47
|
"get-port-please": "^3.0.1",
|
|
46
48
|
"glob": "^7.1.6",
|
|
47
49
|
"handlebars": "^4.7.6",
|
|
48
50
|
"mobx": "^6.0.4",
|
|
51
|
+
"@opentelemetry/api": "1.9.0",
|
|
52
|
+
"@opentelemetry/exporter-trace-otlp-http": "0.53.0",
|
|
53
|
+
"@opentelemetry/resources": "1.26.0",
|
|
54
|
+
"@opentelemetry/sdk-trace-node": "1.26.0",
|
|
55
|
+
"@opentelemetry/semantic-conventions": "1.27.0",
|
|
49
56
|
"pluralize": "^8.0.0",
|
|
50
57
|
"react": "^17.0.0 || ^18.2.0 || ^19.0.0",
|
|
51
58
|
"react-dom": "^17.0.0 || ^18.2.0 || ^19.0.0",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getMergedConfig } from '@redocly/openapi-core';
|
|
2
2
|
import { handlePush } from '../../commands/push';
|
|
3
|
-
import { promptClientToken } from '../../commands/
|
|
3
|
+
import { promptClientToken } from '../../commands/auth';
|
|
4
4
|
import { ConfigFixture } from '../fixtures/config';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
6
|
|
|
@@ -23,7 +23,7 @@ jest.mock('fs', () => ({
|
|
|
23
23
|
|
|
24
24
|
// Mock OpenAPI core
|
|
25
25
|
jest.mock('@redocly/openapi-core');
|
|
26
|
-
jest.mock('../../commands/
|
|
26
|
+
jest.mock('../../commands/auth');
|
|
27
27
|
jest.mock('../../utils/miscellaneous');
|
|
28
28
|
|
|
29
29
|
const mockPromptClientToken = promptClientToken as jest.MockedFunction<typeof promptClientToken>;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { RedoclyOAuthDeviceFlow } from '../device-flow';
|
|
2
|
+
|
|
3
|
+
jest.mock('child_process');
|
|
4
|
+
|
|
5
|
+
describe('RedoclyOAuthDeviceFlow', () => {
|
|
6
|
+
const mockBaseUrl = 'https://test.redocly.com';
|
|
7
|
+
const mockClientName = 'test-client';
|
|
8
|
+
const mockVersion = '1.0.0';
|
|
9
|
+
let flow: RedoclyOAuthDeviceFlow;
|
|
10
|
+
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
flow = new RedoclyOAuthDeviceFlow(mockBaseUrl, mockClientName, mockVersion);
|
|
13
|
+
jest.resetAllMocks();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('verifyToken', () => {
|
|
17
|
+
it('returns true for valid token', async () => {
|
|
18
|
+
jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
|
|
19
|
+
json: () => Promise.resolve({ user: { id: '123' } }),
|
|
20
|
+
} as Response);
|
|
21
|
+
|
|
22
|
+
const result = await flow.verifyToken('valid-token');
|
|
23
|
+
expect(result).toBe(true);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('returns false for invalid token', async () => {
|
|
27
|
+
jest.spyOn(flow['apiClient'], 'request').mockRejectedValue(new Error('Invalid token'));
|
|
28
|
+
const result = await flow.verifyToken('invalid-token');
|
|
29
|
+
expect(result).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe('verifyApiKey', () => {
|
|
34
|
+
it('returns true for valid API key', async () => {
|
|
35
|
+
jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
|
|
36
|
+
json: () => Promise.resolve({ success: true }),
|
|
37
|
+
} as Response);
|
|
38
|
+
|
|
39
|
+
const result = await flow.verifyApiKey('valid-key');
|
|
40
|
+
expect(result).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('returns false for invalid API key', async () => {
|
|
44
|
+
jest.spyOn(flow['apiClient'], 'request').mockRejectedValue(new Error('Invalid API key'));
|
|
45
|
+
const result = await flow.verifyApiKey('invalid-key');
|
|
46
|
+
expect(result).toBe(false);
|
|
47
|
+
});
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
describe('refreshToken', () => {
|
|
51
|
+
it('successfully refreshes token', async () => {
|
|
52
|
+
const mockResponse = {
|
|
53
|
+
access_token: 'new-token',
|
|
54
|
+
refresh_token: 'new-refresh',
|
|
55
|
+
expires_in: 3600,
|
|
56
|
+
};
|
|
57
|
+
jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
|
|
58
|
+
json: () => Promise.resolve(mockResponse),
|
|
59
|
+
} as Response);
|
|
60
|
+
|
|
61
|
+
const result = await flow.refreshToken('old-refresh-token');
|
|
62
|
+
expect(result).toEqual(mockResponse);
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('throws error when refresh fails', async () => {
|
|
66
|
+
jest.spyOn(flow['apiClient'], 'request').mockResolvedValue({
|
|
67
|
+
json: () => Promise.resolve({}),
|
|
68
|
+
} as Response);
|
|
69
|
+
|
|
70
|
+
await expect(flow.refreshToken('invalid-refresh')).rejects.toThrow('Failed to refresh token');
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
});
|