@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/src/otel.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { trace } from '@opentelemetry/api';
|
|
2
|
+
import { Resource as OtelResource } from '@opentelemetry/resources';
|
|
3
|
+
import { NodeTracerProvider, SimpleSpanProcessor } from '@opentelemetry/sdk-trace-node';
|
|
4
|
+
import { OTLPTraceExporter } from '@opentelemetry/exporter-trace-otlp-http';
|
|
5
|
+
import { ATTR_SERVICE_NAME, ATTR_SERVICE_VERSION } from '@opentelemetry/semantic-conventions';
|
|
6
|
+
import { version } from './utils/update-version-notifier';
|
|
7
|
+
import { DEFAULT_FETCH_TIMEOUT } from './utils/fetch-with-timeout';
|
|
8
|
+
|
|
9
|
+
import type { Analytics } from './utils/miscellaneous';
|
|
10
|
+
|
|
11
|
+
type Events = {
|
|
12
|
+
[key: string]: Analytics;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const OTEL_TRACES_URL = process.env.OTEL_TRACES_URL || 'https://otel.cloud.redocly.com/v1/traces';
|
|
16
|
+
|
|
17
|
+
export class OtelServerTelemetry {
|
|
18
|
+
init() {
|
|
19
|
+
const nodeTracerProvider = new NodeTracerProvider({
|
|
20
|
+
resource: new OtelResource({
|
|
21
|
+
[ATTR_SERVICE_NAME]: `redocly-cli`,
|
|
22
|
+
[ATTR_SERVICE_VERSION]: `@redocly/cli@${version}`,
|
|
23
|
+
}),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
nodeTracerProvider.addSpanProcessor(
|
|
27
|
+
new SimpleSpanProcessor(
|
|
28
|
+
new OTLPTraceExporter({
|
|
29
|
+
url: OTEL_TRACES_URL,
|
|
30
|
+
headers: {},
|
|
31
|
+
timeoutMillis: DEFAULT_FETCH_TIMEOUT,
|
|
32
|
+
})
|
|
33
|
+
)
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
nodeTracerProvider.register();
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
send<K extends keyof Events>(event: K, data: Events[K]): void {
|
|
40
|
+
const time = new Date();
|
|
41
|
+
const eventId = crypto.randomUUID();
|
|
42
|
+
const span = trace.getTracer('CliTelemetry').startSpan(`event.${event}`, {
|
|
43
|
+
attributes: {
|
|
44
|
+
'cloudevents.event_client.id': eventId,
|
|
45
|
+
'cloudevents.event_client.type': event,
|
|
46
|
+
},
|
|
47
|
+
startTime: time,
|
|
48
|
+
});
|
|
49
|
+
for (const [key, value] of Object.entries(data)) {
|
|
50
|
+
const keySnakeCase = key.replace(/([A-Z])/g, '_$1').toLowerCase();
|
|
51
|
+
if (value !== undefined) {
|
|
52
|
+
span.setAttribute(`cloudevents.event_data.${keySnakeCase}`, value);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
span.end(time);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export const otelTelemetry = new OtelServerTelemetry();
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { getDomain } from '../domains';
|
|
2
|
+
import { getReuniteUrl } from '../domains';
|
|
3
|
+
|
|
4
|
+
import type { Region } from '@redocly/openapi-core';
|
|
5
|
+
|
|
6
|
+
describe('getDomain()', () => {
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
delete process.env.REDOCLY_DOMAIN;
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should return the domain from environment variable', () => {
|
|
12
|
+
process.env.REDOCLY_DOMAIN = 'test-domain';
|
|
13
|
+
|
|
14
|
+
expect(getDomain()).toBe('test-domain');
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should return the default domain if no domain provided', () => {
|
|
18
|
+
process.env.REDOCLY_DOMAIN = '';
|
|
19
|
+
|
|
20
|
+
expect(getDomain()).toBe('https://app.cloud.redocly.com');
|
|
21
|
+
});
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
describe('getReuniteUrl()', () => {
|
|
25
|
+
it('should return US API URL when US region specified', () => {
|
|
26
|
+
expect(getReuniteUrl('us')).toBe('https://app.cloud.redocly.com/api');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should return EU API URL when EU region specified', () => {
|
|
30
|
+
expect(getReuniteUrl('eu')).toBe('https://app.cloud.eu.redocly.com/api');
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should return custom domain API URL when custom domain specified', () => {
|
|
34
|
+
const customDomain = 'https://custom.domain.com';
|
|
35
|
+
expect(getReuniteUrl(customDomain as Region)).toBe('https://custom.domain.com/api');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should return US API URL when no region specified', () => {
|
|
39
|
+
expect(getReuniteUrl()).toBe('https://app.cloud.redocly.com/api');
|
|
40
|
+
});
|
|
41
|
+
});
|
|
@@ -26,7 +26,7 @@ export class ReuniteApiError extends Error {
|
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
class ReuniteApiClient implements BaseApiClient {
|
|
29
|
+
export class ReuniteApiClient implements BaseApiClient {
|
|
30
30
|
public sunsetWarnings: SunsetWarningsBuffer = [];
|
|
31
31
|
|
|
32
32
|
constructor(protected version: string, protected command: string) {}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { Region } from '@redocly/openapi-core';
|
|
2
|
+
|
|
3
|
+
export const REUNITE_URLS: Record<Region, string> = {
|
|
4
|
+
us: 'https://app.cloud.redocly.com',
|
|
5
|
+
eu: 'https://app.cloud.eu.redocly.com',
|
|
6
|
+
} as const;
|
|
7
|
+
|
|
8
|
+
export function getDomain(): string {
|
|
9
|
+
return process.env.REDOCLY_DOMAIN || REUNITE_URLS.us;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export function getReuniteUrl(residency?: string) {
|
|
13
|
+
if (!residency) residency = 'us';
|
|
14
|
+
|
|
15
|
+
let reuniteUrl: string = REUNITE_URLS[residency as Region];
|
|
16
|
+
|
|
17
|
+
if (!reuniteUrl) {
|
|
18
|
+
reuniteUrl = residency;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const url = new URL('/api', reuniteUrl).toString();
|
|
22
|
+
return url;
|
|
23
|
+
}
|
package/src/types.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';
|
|
@@ -37,12 +38,15 @@ export type CommandOptions =
|
|
|
37
38
|
| LintOptions
|
|
38
39
|
| BundleOptions
|
|
39
40
|
| LoginOptions
|
|
41
|
+
| LogoutOptions
|
|
40
42
|
| PreviewDocsOptions
|
|
41
43
|
| BuildDocsArgv
|
|
42
44
|
| PushStatusOptions
|
|
43
45
|
| PreviewProjectOptions
|
|
44
46
|
| TranslationsOptions
|
|
45
|
-
| EjectOptions
|
|
47
|
+
| EjectOptions
|
|
48
|
+
| RespectOptions
|
|
49
|
+
| GenerateArazzoFileOptions;
|
|
46
50
|
|
|
47
51
|
export type VerifyConfigOptions = {
|
|
48
52
|
config?: string;
|
|
@@ -3,6 +3,7 @@ import { blue, gray, green, red, yellow } from 'colorette';
|
|
|
3
3
|
import { performance } from 'perf_hooks';
|
|
4
4
|
import * as glob from 'glob';
|
|
5
5
|
import * as fs from 'fs';
|
|
6
|
+
import * as os from 'os';
|
|
6
7
|
import * as readline from 'readline';
|
|
7
8
|
import { Writable } from 'stream';
|
|
8
9
|
import { execSync } from 'child_process';
|
|
@@ -28,7 +29,7 @@ import { deprecatedRefDocsSchema } from '@redocly/config/lib/reference-docs-conf
|
|
|
28
29
|
import { outputExtensions } from '../types';
|
|
29
30
|
import { version } from './update-version-notifier';
|
|
30
31
|
import { DESTINATION_REGEX } from '../commands/push';
|
|
31
|
-
import
|
|
32
|
+
import { getReuniteUrl } from '../reunite/api';
|
|
32
33
|
|
|
33
34
|
import type { Arguments } from 'yargs';
|
|
34
35
|
import type {
|
|
@@ -565,33 +566,32 @@ export async function sendTelemetry(
|
|
|
565
566
|
} = argv;
|
|
566
567
|
const event_time = new Date().toISOString();
|
|
567
568
|
const redoclyClient = new RedoclyClient();
|
|
568
|
-
const
|
|
569
|
+
const { RedoclyOAuthClient } = await import('../auth/oauth-client');
|
|
570
|
+
const oauthClient = new RedoclyOAuthClient('redocly-cli', version);
|
|
571
|
+
const reuniteUrl = getReuniteUrl(argv.residency as string | undefined);
|
|
572
|
+
const logged_in = redoclyClient.hasTokens() || (await oauthClient.isAuthorized(reuniteUrl));
|
|
569
573
|
const data: Analytics = {
|
|
570
574
|
event: 'cli_command',
|
|
571
575
|
event_time,
|
|
572
|
-
logged_in,
|
|
573
|
-
command
|
|
574
|
-
arguments: cleanArgs(args),
|
|
576
|
+
logged_in: logged_in ? 'yes' : 'no',
|
|
577
|
+
command: `${command}`,
|
|
578
|
+
arguments: JSON.stringify(cleanArgs(args)),
|
|
575
579
|
node_version: process.version,
|
|
576
580
|
npm_version: execSync('npm -v').toString().replace('\n', ''),
|
|
581
|
+
os_platform: os.platform(),
|
|
577
582
|
version,
|
|
578
583
|
exit_code,
|
|
579
584
|
environment: process.env.REDOCLY_ENVIRONMENT,
|
|
580
585
|
environment_ci: process.env.CI,
|
|
581
586
|
raw_input: cleanRawInput(process.argv.slice(2)),
|
|
582
|
-
has_config,
|
|
587
|
+
has_config: has_config ? 'yes' : 'no',
|
|
583
588
|
spec_version,
|
|
584
589
|
spec_keyword,
|
|
585
590
|
spec_full_version,
|
|
586
591
|
};
|
|
587
|
-
await
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
headers: {
|
|
591
|
-
'content-type': 'application/json',
|
|
592
|
-
},
|
|
593
|
-
body: JSON.stringify(data),
|
|
594
|
-
});
|
|
592
|
+
const { otelTelemetry } = await import('../otel');
|
|
593
|
+
otelTelemetry.init();
|
|
594
|
+
otelTelemetry.send(data.command, data);
|
|
595
595
|
} catch (err) {
|
|
596
596
|
// Do nothing.
|
|
597
597
|
}
|
|
@@ -602,17 +602,18 @@ export type ExitCode = 0 | 1 | 2;
|
|
|
602
602
|
export type Analytics = {
|
|
603
603
|
event: string;
|
|
604
604
|
event_time: string;
|
|
605
|
-
logged_in:
|
|
606
|
-
command: string
|
|
607
|
-
arguments:
|
|
605
|
+
logged_in: 'yes' | 'no';
|
|
606
|
+
command: string;
|
|
607
|
+
arguments: string;
|
|
608
608
|
node_version: string;
|
|
609
609
|
npm_version: string;
|
|
610
|
+
os_platform: string;
|
|
610
611
|
version: string;
|
|
611
612
|
exit_code: ExitCode;
|
|
612
613
|
environment?: string;
|
|
613
614
|
environment_ci?: string;
|
|
614
615
|
raw_input: string;
|
|
615
|
-
has_config?:
|
|
616
|
+
has_config?: 'yes' | 'no';
|
|
616
617
|
spec_version?: string;
|
|
617
618
|
spec_keyword?: string;
|
|
618
619
|
spec_full_version?: string;
|