Optimized the root .gitignore to exclude virtual environments, node modules, and temp folders to ensure clean and lightweight version tracking. Co-authored-by: Cursor <cursoragent@cursor.com>
158 lines
3.8 KiB
TypeScript
158 lines
3.8 KiB
TypeScript
import { limitErrorText, readErrorString } from './httpUtils';
|
|
|
|
export function formatAxureProxyErrorDetails(error: any): string {
|
|
const parts: string[] = [];
|
|
const message = readErrorString(error?.message);
|
|
const causeMessage = readErrorString(error?.cause?.message);
|
|
const code = readErrorString(error?.code) || readErrorString(error?.cause?.code);
|
|
const errno = readErrorString(error?.errno) || readErrorString(error?.cause?.errno);
|
|
const syscall = readErrorString(error?.syscall) || readErrorString(error?.cause?.syscall);
|
|
const address = readErrorString(error?.address) || readErrorString(error?.cause?.address);
|
|
const port =
|
|
typeof error?.port === 'number'
|
|
? String(error.port)
|
|
: typeof error?.cause?.port === 'number'
|
|
? String(error.cause.port)
|
|
: '';
|
|
|
|
if (message) {
|
|
parts.push(message);
|
|
}
|
|
if (causeMessage && causeMessage !== message) {
|
|
parts.push(`cause=${causeMessage}`);
|
|
}
|
|
if (code) {
|
|
parts.push(`code=${code}`);
|
|
}
|
|
if (errno && errno !== code) {
|
|
parts.push(`errno=${errno}`);
|
|
}
|
|
if (syscall) {
|
|
parts.push(`syscall=${syscall}`);
|
|
}
|
|
if (address) {
|
|
parts.push(`address=${address}`);
|
|
}
|
|
if (port) {
|
|
parts.push(`port=${port}`);
|
|
}
|
|
|
|
return parts.join('; ') || 'Unknown upstream error';
|
|
}
|
|
|
|
export function normalizeAxvgPayloadText(rawBody: string): string {
|
|
const source = rawBody.trim();
|
|
if (!source) {
|
|
return '// axvg\n{}';
|
|
}
|
|
|
|
if (source.startsWith('// axvg')) {
|
|
return source;
|
|
}
|
|
|
|
return `// axvg\n${source}`;
|
|
}
|
|
|
|
export function buildAxureBridgeUnavailablePayload(params: {
|
|
route: string;
|
|
method: string;
|
|
bridgeUrl: string;
|
|
payloadBytes?: number;
|
|
error?: any;
|
|
status?: number;
|
|
statusText?: string;
|
|
responseText?: string;
|
|
}) {
|
|
const errorCode =
|
|
readErrorString(params.error?.code)
|
|
|| readErrorString(params.error?.cause?.code)
|
|
|| undefined;
|
|
const errorMessage =
|
|
readErrorString(params.error?.message)
|
|
|| readErrorString(params.responseText)
|
|
|| (typeof params.status === 'number' ? `Axure Bridge unavailable (HTTP ${params.status})` : 'Axure Bridge unavailable');
|
|
const details =
|
|
params.error
|
|
? formatAxureProxyErrorDetails(params.error)
|
|
: limitErrorText(readErrorString(params.responseText), 800) || undefined;
|
|
|
|
return {
|
|
available: false,
|
|
running: false,
|
|
success: false,
|
|
error: errorMessage,
|
|
details,
|
|
code: errorCode,
|
|
route: params.route,
|
|
method: params.method,
|
|
bridgeUrl: params.bridgeUrl,
|
|
payloadBytes: params.payloadBytes || undefined,
|
|
status: typeof params.status === 'number' ? params.status : undefined,
|
|
statusText: readErrorString(params.statusText) || undefined,
|
|
};
|
|
}
|
|
|
|
export function isLoopbackOrPrivateHostname(hostname: string): boolean {
|
|
const normalized = String(hostname || '').trim().toLowerCase();
|
|
if (!normalized) {
|
|
return true;
|
|
}
|
|
|
|
if (
|
|
normalized === 'localhost' ||
|
|
normalized === '127.0.0.1' ||
|
|
normalized === '0.0.0.0' ||
|
|
normalized === '::1' ||
|
|
normalized === '[::1]'
|
|
) {
|
|
return true;
|
|
}
|
|
|
|
if (/^127\./.test(normalized)) {
|
|
return true;
|
|
}
|
|
|
|
if (/^10\./.test(normalized)) {
|
|
return true;
|
|
}
|
|
|
|
if (/^192\.168\./.test(normalized)) {
|
|
return true;
|
|
}
|
|
|
|
if (/^169\.254\./.test(normalized)) {
|
|
return true;
|
|
}
|
|
|
|
const match172 = normalized.match(/^172\.(\d{1,3})\./);
|
|
if (match172) {
|
|
const secondOctet = Number(match172[1]);
|
|
if (secondOctet >= 16 && secondOctet <= 31) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
export function isAllowedProxyImageUrl(rawUrl: string): boolean {
|
|
let parsedUrl: URL;
|
|
try {
|
|
parsedUrl = new URL(rawUrl);
|
|
} catch {
|
|
return false;
|
|
}
|
|
|
|
if (parsedUrl.protocol !== 'http:' && parsedUrl.protocol !== 'https:') {
|
|
return false;
|
|
}
|
|
|
|
if (isLoopbackOrPrivateHostname(parsedUrl.hostname)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
export { limitErrorText };
|