@puls-atlas/cli
Version:
The Puls Atlas CLI tool for managing Atlas projects
154 lines • 5.68 kB
JavaScript
import { execFileSync } from 'child_process';
import { isBoolean, isNumber, isPlainObject } from 'es-toolkit/compat';
import jwt from 'jsonwebtoken';
import { getSecret, runGcloudFileCommand } from '../../utils/index.js';
import { normalizeOptionalString } from '../../utils/value.js';
import { SHARED_REQUEST_AUTH_SECRET } from '../search/deploymentConfig.js';
import { resolveSyncCloudRunDeployConfig } from './deploymentConfig.js';
import { SYNC_SERVICE_NAME } from './resourceNames.js';
const ATLAS_SYNC_AUTH_HEADER = 'x-atlas-sync-authorization';
const MAX_ADMIN_ERROR_DETAIL_LENGTH = 300;
export { SYNC_SERVICE_NAME };
const getIssuedAt = now => {
const value = typeof now === 'function' ? now() : new Date();
return value instanceof Date ? value : new Date(value);
};
const getSyncServiceUrl = (context, options = {}) => {
const runCommand = options.runCommand ?? execFileSync;
const {
region
} = resolveSyncCloudRunDeployConfig(context);
return runGcloudFileCommand(['run', 'services', 'describe', SYNC_SERVICE_NAME, `--project=${context.projectId}`, '--platform=managed', `--region=${region}`, '--format="value(status.url)"'], {
encoding: 'utf8'
}, runCommand).trim();
};
export const getSyncServiceUrlFromContext = (context, options = {}) => getSyncServiceUrl(context, options);
export const createSyncApiAdminToken = ({
now,
path,
projectId,
requestAuthToken,
serviceUrl
}) => {
const issuedAt = getIssuedAt(now);
const serviceHost = new URL(serviceUrl).host;
return jwt.sign({
exp: Math.floor(issuedAt.getTime() / 1e3) + 300,
host: serviceHost,
iss: projectId,
path
}, requestAuthToken);
};
const parseJsonResponse = responseText => {
const normalized = normalizeOptionalString(responseText);
if (!normalized) {
return null;
}
try {
return JSON.parse(normalized);
} catch {
return normalized;
}
};
const normalizeAdminErrorDetailValue = value => {
if (typeof value === 'string') {
return normalizeOptionalString(value);
}
if (isNumber(value) || isBoolean(value)) {
return String(value);
}
return null;
};
const truncateAdminErrorDetailValue = value => {
if (typeof value !== 'string') {
return null;
}
if (value.length <= MAX_ADMIN_ERROR_DETAIL_LENGTH) {
return value;
}
return `${value.slice(0, MAX_ADMIN_ERROR_DETAIL_LENGTH - 3)}...`;
};
const resolveProviderResponseSummary = responseBody => {
const normalizedResponseBody = normalizeAdminErrorDetailValue(responseBody);
if (!normalizedResponseBody) {
return null;
}
const parsedResponseBody = parseJsonResponse(normalizedResponseBody);
if (parsedResponseBody && isPlainObject(parsedResponseBody)) {
const providerMessage = normalizeAdminErrorDetailValue(parsedResponseBody.message);
if (providerMessage) {
return truncateAdminErrorDetailValue(providerMessage);
}
}
return truncateAdminErrorDetailValue(normalizedResponseBody);
};
const summarizeAdminErrorDetails = details => {
const directValue = normalizeAdminErrorDetailValue(details);
if (directValue) {
return directValue;
}
if (!details || !isPlainObject(details)) {
return null;
}
const summaryParts = [];
for (const key of ['cause', 'error', 'code', 'url', 'host', 'status', 'workloadKey']) {
const value = normalizeAdminErrorDetailValue(details[key]);
if (value) {
summaryParts.push(`${key}=${value}`);
}
}
const providerResponseSummary = resolveProviderResponseSummary(details.responseBody);
if (providerResponseSummary) {
summaryParts.push(`providerResponse=${providerResponseSummary}`);
}
return summaryParts.length > 0 ? summaryParts.join('; ') : null;
};
const ensureTrailingPeriod = value => /[^.!?]$/.test(value) ? `${value}.` : value;
const createAdminRequestErrorMessage = (responsePayload, status) => {
const detailsSummary = summarizeAdminErrorDetails(responsePayload?.details ?? null);
const baseMessage = normalizeOptionalString(responsePayload?.message) ?? `Atlas sync admin request failed with status ${status}.`;
if (!detailsSummary || baseMessage.includes(detailsSummary)) {
return baseMessage;
}
return `${ensureTrailingPeriod(baseMessage)} Details: ${detailsSummary}.`;
};
const executeAdminRequest = async (context, {
method = 'GET',
path,
payload
}, dependencies = {}) => {
const fetchImpl = dependencies.fetchImpl ?? fetch;
const getSecretImpl = dependencies.getSecretImpl ?? getSecret;
const requestAuthToken = await getSecretImpl(SHARED_REQUEST_AUTH_SECRET, 'latest', context.projectId);
const serviceUrl = dependencies.serviceUrl ?? getSyncServiceUrl(context, dependencies);
const token = createSyncApiAdminToken({
now: dependencies.now,
path,
projectId: context.projectId,
requestAuthToken,
serviceUrl
});
const requestOptions = {
headers: {
[ATLAS_SYNC_AUTH_HEADER]: `Bearer ${token}`,
...(payload !== undefined ? {
'content-type': 'application/json'
} : {})
},
method
};
if (payload !== undefined) {
requestOptions.body = JSON.stringify(payload);
}
const response = await fetchImpl(`${serviceUrl}${path}`, requestOptions);
const responseText = await response.text();
const responsePayload = parseJsonResponse(responseText);
if (!response.ok) {
const error = new Error(createAdminRequestErrorMessage(responsePayload, response.status));
error.details = responsePayload?.details ?? null;
error.status = response.status;
throw error;
}
return responsePayload;
};
export const executeSyncAdminRequest = (context, options, dependencies = {}) => executeAdminRequest(context, options, dependencies);