first commit

This commit is contained in:
Beyhan Oğur
2026-04-26 21:52:23 +03:00
commit 880f412e2c
2662 changed files with 866266 additions and 0 deletions

View File

@@ -0,0 +1,167 @@
/**
* Routing Rules Utility Functions
* Helper functions for CEL validation, formatting, and rule management
*/
/**
* Validates if a CEL expression has basic correct syntax
* @param expression - The CEL expression to validate
* @returns true if expression appears syntactically valid
*/
export function isValidCELExpression(expression: string): boolean {
if (!expression) {
return true;
}
const trimmed = expression.trim();
if (trimmed.length === 0 || trimmed === "true" || trimmed === "false") {
return true;
}
// Check for basic syntax issues
if (trimmed.includes(";;")) {
return false;
}
// Check for matching brackets/parentheses
const openBrackets = (trimmed.match(/[[{]/g) || []).length;
const closeBrackets = (trimmed.match(/[\]}]/g) || []).length;
const openParens = (trimmed.match(/\(/g) || []).length;
const closeParens = (trimmed.match(/\)/g) || []).length;
if (openBrackets !== closeBrackets || openParens !== closeParens) {
return false;
}
return true;
}
/**
* Formats a fallback string (provider/model) for display
* @param fallback - The fallback string (e.g., "openai/gpt-4o")
* @returns Formatted fallback string
*/
export function formatFallback(fallback: string): string {
if (!fallback) return "";
const parts = fallback.split("/");
return parts.length === 2 ? `${parts[0].toUpperCase()} - ${parts[1]}` : fallback;
}
/**
* Parses a fallback string into provider and model
* @param fallback - The fallback string (e.g., "openai/gpt-4o")
* @returns Object with provider and model, or null if invalid
*/
export function parseFallback(fallback: string): { provider: string; model: string } | null {
if (!fallback) return null;
const parts = fallback.split("/");
if (parts.length !== 2) return null;
return { provider: parts[0], model: parts[1] };
}
/**
* Converts fallback array to string format for display/editing
* @param fallbacks - Array of fallback strings
* @returns Comma-separated string
*/
export function fallbacksToString(fallbacks?: string[]): string {
if (!fallbacks || fallbacks.length === 0) return "";
return fallbacks.join(", ");
}
/**
* Converts comma-separated string to fallback array
* @param str - Comma-separated fallback string
* @returns Array of fallback strings
*/
export function stringToFallbacks(str: string): string[] {
if (!str || str.trim().length === 0) return [];
return str
.split(",")
.map((s) => s.trim())
.filter((s) => s.length > 0);
}
/**
* Gets a friendly display name for a scope
* @param scope - The scope value (global|team|customer|virtual_key)
* @returns Friendly display name
*/
export function getScopeLabel(scope: string): string {
const labels: Record<string, string> = {
global: "Global",
team: "Team",
customer: "Customer",
virtual_key: "Virtual Key",
};
return labels[scope] || scope;
}
/**
* Truncates CEL expression for table display
* @param expression - The CEL expression
* @param maxLength - Maximum length (default 60)
* @returns Truncated expression with ellipsis if needed
*/
export function truncateCELExpression(expression: string, maxLength: number = 60): string {
if (!expression) return "";
if (expression.length <= maxLength) return expression;
return expression.substring(0, maxLength) + "...";
}
/**
* Validates a provider/model combination
* @param provider - The provider name
* @param model - The model name (optional)
* @returns Error message if invalid, empty string if valid
*/
export function validateProviderModel(provider: string, _model?: string): string {
if (!provider || provider.trim().length === 0) {
return "Provider is required";
}
return "";
}
/**
* Generates a CSS class for priority badge color
* @returns CSS class name for styling
*/
export function getPriorityBadgeClass(): string {
return "bg-primary text-primary-foreground";
}
/**
* Gets a user-friendly CEL operator from the expression
* @param expression - The CEL expression
* @returns Array of detected operators
*/
export function detectCELOperators(expression: string): string[] {
const operators: string[] = [];
if (!expression) return operators;
// Common CEL operators
const operatorPatterns = [
{ regex: /==/, label: "Equals" },
{ regex: /!=/, label: "Not equals" },
{ regex: />=/, label: "Greater than or equal" },
{ regex: /<=/, label: "Less than or equal" },
{ regex: />/, label: "Greater than" },
{ regex: /</, label: "Less than" },
{ regex: /&&/, label: "AND" },
{ regex: /\|\|/, label: "OR" },
{ regex: /!(?!=)/, label: "NOT" },
{ regex: /in\s/, label: "IN" },
{ regex: /.matches\(/, label: "Regex" },
{ regex: /.startsWith\(/, label: "StartsWith" },
{ regex: /.contains\(/, label: "Contains" },
{ regex: /.endsWith\(/, label: "EndsWith" },
];
operatorPatterns.forEach(({ regex, label }) => {
if (regex.test(expression) && !operators.includes(label)) {
operators.push(label);
}
});
return operators;
}