@redocly/cli
Version:
[@Redocly](https://redocly.com) CLI is your all-in-one OpenAPI utility. It builds, manages, improves, and quality-checks your OpenAPI descriptions, all of which comes in handy for various phases of the API Lifecycle. Create your own rulesets to make API g
142 lines • 5.91 kB
JavaScript
import * as os from 'node:os';
import * as fs from 'node:fs';
import { execSync } from 'node:child_process';
import { isAbsoluteUrl } from '@redocly/openapi-core';
import { version } from './package.js';
import { getReuniteUrl } from '../reunite/api/index.js';
import { respondWithinMs } from './network-check.js';
export async function sendTelemetry({ config, argv, exit_code, spec_version, spec_keyword, spec_full_version, respect_x_security_auth_types, }) {
try {
if (!argv) {
return;
}
const hasInternet = await respondWithinMs(1000);
if (!hasInternet) {
return;
}
const { _: [command], $0: _, ...args } = argv;
const event_time = new Date().toISOString();
const residency = args.residency || config?.resolvedConfig?.residency;
const { RedoclyOAuthClient } = await import('../auth/oauth-client.js');
const oauthClient = new RedoclyOAuthClient('redocly-cli', version);
const reuniteUrl = getReuniteUrl(residency);
const logged_in = await oauthClient.isAuthorized(reuniteUrl);
const data = {
event: 'cli_command',
event_time,
logged_in: logged_in ? 'yes' : 'no',
command: `${command}`,
...cleanArgs(args, process.argv.slice(2)),
node_version: process.version,
npm_version: execSync('npm -v').toString().replace('\n', ''),
os_platform: os.platform(),
version,
exit_code,
environment: process.env.REDOCLY_ENVIRONMENT,
metadata: process.env.REDOCLY_CLI_TELEMETRY_METADATA,
environment_ci: process.env.CI,
has_config: typeof config?.document?.parsed === 'undefined' ? 'no' : 'yes',
spec_version,
spec_keyword,
spec_full_version,
respect_x_security_auth_types: spec_version === 'arazzo1' && respect_x_security_auth_types?.length
? JSON.stringify(respect_x_security_auth_types)
: undefined,
};
const { otelTelemetry } = await import('./otel.js');
otelTelemetry.send(data.command, data);
}
catch (err) {
// Do nothing.
}
}
export function collectXSecurityAuthTypes(document, respectXSecurityAuthTypesAndSchemeName) {
for (const workflow of document.workflows ?? []) {
// Collect auth types from workflow-level x-security
for (const security of workflow['x-security'] ?? []) {
const scheme = security.scheme;
if (scheme?.type) {
const authType = scheme.type === 'http' ? scheme.scheme : scheme.type;
if (authType && !respectXSecurityAuthTypesAndSchemeName.includes(authType)) {
respectXSecurityAuthTypesAndSchemeName.push(authType);
}
}
}
// Collect auth types from step-level x-security
for (const step of workflow.steps ?? []) {
for (const security of step['x-security'] ?? []) {
// Handle scheme case
const scheme = security.scheme;
if (scheme?.type) {
const authType = scheme.type === 'http' ? scheme.scheme : scheme.type;
if (authType && !respectXSecurityAuthTypesAndSchemeName.includes(authType)) {
respectXSecurityAuthTypesAndSchemeName.push(authType);
}
}
// Handle schemeName case
const schemeName = security.schemeName;
if (schemeName && !respectXSecurityAuthTypesAndSchemeName.includes(schemeName)) {
respectXSecurityAuthTypesAndSchemeName.push(schemeName);
}
}
}
}
}
function isFile(value) {
return fs.existsSync(value) && fs.statSync(value).isFile();
}
function isDirectory(value) {
return fs.existsSync(value) && fs.statSync(value).isDirectory();
}
function cleanString(value) {
if (!value) {
return value;
}
if (isAbsoluteUrl(value)) {
return value.split('://')[0] + '://url';
}
if (isFile(value)) {
return value.replace(/.+\.([^.]+)$/, (_, ext) => 'file-' + ext);
}
if (isDirectory(value)) {
return 'folder';
}
return value;
}
function replaceArgs(commandInput, targets, replacement) {
const targetValues = Array.isArray(targets) ? targets : [targets];
for (const target of targetValues) {
commandInput = commandInput.replaceAll(target, replacement);
}
return commandInput;
}
export function cleanArgs(parsedArgs, rawArgv) {
const KEYS_TO_CLEAN = ['organization', 'o', 'input', 'i', 'client-cert', 'client-key', 'ca-cert'];
let commandInput = rawArgv.join(' ');
const commandArguments = {};
for (const [key, value] of Object.entries(parsedArgs)) {
if (KEYS_TO_CLEAN.includes(key)) {
commandArguments[key] = '***';
commandInput = replaceArgs(commandInput, value, '***');
}
else if (typeof value === 'string') {
const cleanedValue = cleanString(value);
commandArguments[key] = cleanedValue;
commandInput = replaceArgs(commandInput, value, cleanedValue);
}
else if (Array.isArray(value)) {
commandArguments[key] = value.map(cleanString);
for (const replacedValue of value) {
const newValue = cleanString(replacedValue);
if (commandInput.includes(replacedValue)) {
commandInput = commandInput.replaceAll(replacedValue, newValue);
}
}
}
else {
commandArguments[key] = value;
}
}
return { arguments: JSON.stringify(commandArguments), raw_input: commandInput };
}
//# sourceMappingURL=telemetry.js.map