UNPKG

@knn_labs/conduit-admin-client

Version:
1,572 lines (1,560 loc) 60.5 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { API_PREFIX: () => API_PREFIX, API_VERSION: () => API_VERSION, AnalyticsService: () => AnalyticsService, AuthenticationError: () => AuthenticationError, AuthorizationError: () => AuthorizationError, BUDGET_DURATION: () => BUDGET_DURATION, CACHE_TTL: () => CACHE_TTL, ConduitAdminClient: () => ConduitAdminClient, ConduitError: () => ConduitError, ConflictError: () => ConflictError, DEFAULT_PAGE_SIZE: () => DEFAULT_PAGE_SIZE, ENDPOINTS: () => ENDPOINTS, FILTER_MODE: () => FILTER_MODE, FILTER_TYPE: () => FILTER_TYPE, HTTP_STATUS: () => HTTP_STATUS, IpFilterService: () => IpFilterService, MAX_PAGE_SIZE: () => MAX_PAGE_SIZE, ModelCostService: () => ModelCostService, ModelMappingService: () => ModelMappingService, NetworkError: () => NetworkError, NotFoundError: () => NotFoundError, NotImplementedError: () => NotImplementedError, ProviderService: () => ProviderService, RateLimitError: () => RateLimitError, ServerError: () => ServerError, SettingsService: () => SettingsService, SystemService: () => SystemService, TimeoutError: () => TimeoutError, ValidationError: () => ValidationError, VirtualKeyService: () => VirtualKeyService, default: () => index_default, handleApiError: () => handleApiError, isConduitError: () => isConduitError }); module.exports = __toCommonJS(index_exports); // src/client/BaseApiClient.ts var import_axios = __toESM(require("axios")); // src/utils/errors.ts var ConduitError = class extends Error { constructor(message, statusCode, details, endpoint, method) { super(message); this.name = this.constructor.name; this.statusCode = statusCode; this.details = details; this.endpoint = endpoint; this.method = method; Object.setPrototypeOf(this, new.target.prototype); } toJSON() { return { name: this.name, message: this.message, statusCode: this.statusCode, details: this.details, endpoint: this.endpoint, method: this.method }; } }; var AuthenticationError = class extends ConduitError { constructor(message = "Authentication failed", details, endpoint, method) { super(message, 401, details, endpoint, method); } }; var AuthorizationError = class extends ConduitError { constructor(message = "Access forbidden", details, endpoint, method) { super(message, 403, details, endpoint, method); } }; var ValidationError = class extends ConduitError { constructor(message = "Validation failed", details, endpoint, method) { super(message, 400, details, endpoint, method); } }; var NotFoundError = class extends ConduitError { constructor(message = "Resource not found", details, endpoint, method) { super(message, 404, details, endpoint, method); } }; var ConflictError = class extends ConduitError { constructor(message = "Resource conflict", details, endpoint, method) { super(message, 409, details, endpoint, method); } }; var RateLimitError = class extends ConduitError { constructor(message = "Rate limit exceeded", retryAfter, details, endpoint, method) { super(message, 429, details, endpoint, method); this.retryAfter = retryAfter; } }; var ServerError = class extends ConduitError { constructor(message = "Internal server error", details, endpoint, method) { super(message, 500, details, endpoint, method); } }; var NetworkError = class extends ConduitError { constructor(message = "Network error", details) { super(message, void 0, details); } }; var TimeoutError = class extends ConduitError { constructor(message = "Request timeout", details) { super(message, 408, details); } }; var NotImplementedError = class extends ConduitError { constructor(message, details) { super(message, 501, details); } }; function isConduitError(error) { return error instanceof ConduitError; } function isAxiosError(error) { return typeof error === "object" && error !== null && "response" in error && typeof error.response === "object"; } function isNetworkError(error) { return typeof error === "object" && error !== null && "request" in error && !("response" in error); } function isErrorLike(error) { return typeof error === "object" && error !== null && "message" in error && typeof error.message === "string"; } function handleApiError(error, endpoint, method) { if (isAxiosError(error)) { const { status, data } = error.response; const errorData = data; const baseMessage = errorData?.error || errorData?.message || error.message; const details = errorData?.details || data; const endpointInfo = endpoint && method ? ` (${method.toUpperCase()} ${endpoint})` : ""; const enhancedMessage = `${baseMessage}${endpointInfo}`; switch (status) { case 400: throw new ValidationError(enhancedMessage, details, endpoint, method); case 401: throw new AuthenticationError(enhancedMessage, details, endpoint, method); case 403: throw new AuthorizationError(enhancedMessage, details, endpoint, method); case 404: throw new NotFoundError(enhancedMessage, details, endpoint, method); case 409: throw new ConflictError(enhancedMessage, details, endpoint, method); case 429: { const retryAfterHeader = error.response.headers["retry-after"]; const retryAfter = typeof retryAfterHeader === "string" ? parseInt(retryAfterHeader, 10) : void 0; throw new RateLimitError(enhancedMessage, retryAfter, details, endpoint, method); } case 500: case 502: case 503: case 504: throw new ServerError(enhancedMessage, details, endpoint, method); default: throw new ConduitError(enhancedMessage, status, details, endpoint, method); } } else if (isNetworkError(error)) { const endpointInfo = endpoint && method ? ` (${method.toUpperCase()} ${endpoint})` : ""; if (error.code === "ECONNABORTED") { throw new TimeoutError(`Request timeout${endpointInfo}`, { endpoint, method }); } throw new NetworkError(`Network error: No response received${endpointInfo}`, { code: error.code, endpoint, method }); } else if (isErrorLike(error)) { throw new ConduitError( error.message, void 0, { originalError: error }, endpoint, method ); } else { throw new ConduitError( "Unknown error", void 0, { originalError: error }, endpoint, method ); } } // src/client/BaseApiClient.ts var BaseApiClient = class { constructor(config) { this.logger = config.logger; this.cache = config.cache; this.retryConfig = this.normalizeRetryConfig(config.retries); this.axios = import_axios.default.create({ baseURL: config.baseUrl, timeout: config.timeout || 3e4, headers: { "Content-Type": "application/json", "X-API-Key": config.masterKey, ...config.defaultHeaders } }); this.setupInterceptors(); } normalizeRetryConfig(retries) { if (typeof retries === "number") { return { maxRetries: retries, retryDelay: 1e3, retryCondition: (error) => { return error.code === "ECONNABORTED" || error.code === "ETIMEDOUT" || error.response?.status !== void 0 && error.response.status >= 500; } }; } return retries || { maxRetries: 3, retryDelay: 1e3 }; } setupInterceptors() { this.axios.interceptors.request.use( (config) => { this.logger?.debug(`[${config.method?.toUpperCase()}] ${config.url}`, { params: config.params, data: config.data }); return config; }, (error) => { this.logger?.error("Request interceptor error:", error); return Promise.reject(error); } ); this.axios.interceptors.response.use( (response) => { this.logger?.debug(`[${response.status}] ${response.config.url}`, { data: response.data }); return response; }, async (error) => { const config = error.config; if (!config || typeof config._retry !== "number") { if (config) { config._retry = 0; } } if (config && typeof config._retry === "number" && config._retry < this.retryConfig.maxRetries && this.retryConfig.retryCondition?.(error)) { config._retry = (config._retry || 0) + 1; const delay = this.retryConfig.retryDelay * Math.pow(2, (config._retry || 1) - 1); this.logger?.warn( `Retrying request (attempt ${config._retry || 1}/${this.retryConfig.maxRetries})`, { url: config?.url, delay } ); await new Promise((resolve) => setTimeout(resolve, delay)); return this.axios(config); } this.logger?.error(`Request failed: ${error.message}`, { url: config?.url, status: error.response?.status, data: error.response?.data }); return Promise.reject(error); } ); } async request(config) { try { const axiosConfig = { method: config.method, url: config.url, data: config.data, params: config.params, headers: config.headers, timeout: config.timeout }; const response = await this.axios.request(axiosConfig); return response.data; } catch (error) { handleApiError(error, config.url, config.method); } } async get(url, params, options) { return this.request({ method: "GET", url, params, ...options }); } async post(url, data, options) { return this.request({ method: "POST", url, data, ...options }); } async put(url, data, options) { return this.request({ method: "PUT", url, data, ...options }); } async delete(url, options) { return this.request({ method: "DELETE", url, ...options }); } async patch(url, data, options) { return this.request({ method: "PATCH", url, data, ...options }); } getCacheKey(prefix, ...parts) { return [prefix, ...parts.map((p) => JSON.stringify(p))].join(":"); } async withCache(key, fetcher, ttl) { if (!this.cache) { return fetcher(); } const cached = await this.cache.get(key); if (cached) { this.logger?.debug(`Cache hit: ${key}`); return cached; } this.logger?.debug(`Cache miss: ${key}`); const result = await fetcher(); await this.cache.set(key, result, ttl); return result; } }; // src/constants.ts var API_VERSION = "v1"; var API_PREFIX = "/api"; var ENDPOINTS = { // Virtual Keys VIRTUAL_KEYS: { BASE: "/virtualkeys", BY_ID: (id) => `/virtualkeys/${id}`, RESET_SPEND: (id) => `/virtualkeys/${id}/reset-spend`, VALIDATE: "/virtualkeys/validate", SPEND: (id) => `/virtualkeys/${id}/spend`, CHECK_BUDGET: (id) => `/virtualkeys/${id}/check-budget`, VALIDATION_INFO: (id) => `/virtualkeys/${id}/validation-info`, MAINTENANCE: "/virtualkeys/maintenance" }, // Provider Credentials PROVIDERS: { BASE: "/providercredentials", BY_ID: (id) => `/providercredentials/${id}`, BY_NAME: (name) => `/providercredentials/name/${name}`, NAMES: "/providercredentials/names", TEST_BY_ID: (id) => `/providercredentials/test/${id}`, TEST: "/providercredentials/test" }, // Model Provider Mappings MODEL_MAPPINGS: { BASE: "/modelprovidermapping", BY_ID: (id) => `/modelprovidermapping/${id}`, BY_MODEL: (modelId) => `/modelprovidermapping/by-model/${modelId}`, PROVIDERS: "/modelprovidermapping/providers" }, // IP Filters IP_FILTERS: { BASE: "/ipfilter", BY_ID: (id) => `/ipfilter/${id}`, ENABLED: "/ipfilter/enabled", SETTINGS: "/ipfilter/settings", CHECK: "/ipfilter/check" }, // Model Costs MODEL_COSTS: { BASE: "/modelcosts", BY_ID: (id) => `/modelcosts/${id}`, BY_MODEL: (modelId) => `/modelcosts/model/${modelId}`, BATCH: "/modelcosts/batch" }, // Analytics & Cost Dashboard ANALYTICS: { COST_SUMMARY: "/costdashboard/summary", COST_BY_PERIOD: "/costdashboard/by-period", COST_BY_MODEL: "/costdashboard/by-model", COST_BY_KEY: "/costdashboard/by-key", REQUEST_LOGS: "/logs", REQUEST_LOG_BY_ID: (id) => `/logs/${id}` }, // Provider Health HEALTH: { CONFIGURATIONS: "/providerhealth/configurations", CONFIG_BY_PROVIDER: (provider) => `/providerhealth/configurations/${provider}`, STATUS: "/providerhealth/status", STATUS_BY_PROVIDER: (provider) => `/providerhealth/status/${provider}`, HISTORY: "/providerhealth/history", CHECK: (provider) => `/providerhealth/check/${provider}` }, // System SYSTEM: { INFO: "/systeminfo/info", HEALTH: "/systeminfo/health", BACKUP: "/databasebackup", RESTORE: "/databasebackup/restore", NOTIFICATIONS: "/notifications", NOTIFICATION_BY_ID: (id) => `/notifications/${id}` }, // Settings SETTINGS: { GLOBAL: "/globalsettings", GLOBAL_BY_KEY: (key) => `/globalsettings/${key}`, AUDIO: "/audioconfiguration", AUDIO_BY_PROVIDER: (provider) => `/audioconfiguration/${provider}`, ROUTER: "/router/configuration" } }; var DEFAULT_PAGE_SIZE = 20; var MAX_PAGE_SIZE = 100; var CACHE_TTL = { SHORT: 60, // 1 minute MEDIUM: 300, // 5 minutes LONG: 3600, // 1 hour VERY_LONG: 86400 // 24 hours }; var HTTP_STATUS = { OK: 200, CREATED: 201, NO_CONTENT: 204, BAD_REQUEST: 400, UNAUTHORIZED: 401, FORBIDDEN: 403, NOT_FOUND: 404, CONFLICT: 409, RATE_LIMITED: 429, INTERNAL_ERROR: 500, BAD_GATEWAY: 502, SERVICE_UNAVAILABLE: 503, GATEWAY_TIMEOUT: 504 }; var BUDGET_DURATION = { TOTAL: "Total", DAILY: "Daily", WEEKLY: "Weekly", MONTHLY: "Monthly" }; var FILTER_TYPE = { ALLOW: "Allow", DENY: "Deny" }; var FILTER_MODE = { PERMISSIVE: "permissive", RESTRICTIVE: "restrictive" }; // src/services/VirtualKeyService.ts var import_zod = require("zod"); var createVirtualKeySchema = import_zod.z.object({ keyName: import_zod.z.string().min(1).max(100), allowedModels: import_zod.z.string().optional(), maxBudget: import_zod.z.number().min(0).max(1e6).optional(), budgetDuration: import_zod.z.enum(["Total", "Daily", "Weekly", "Monthly"]).optional(), expiresAt: import_zod.z.string().datetime().optional(), metadata: import_zod.z.string().optional(), rateLimitRpm: import_zod.z.number().min(0).optional(), rateLimitRpd: import_zod.z.number().min(0).optional() }); var VirtualKeyService = class extends BaseApiClient { async create(request) { try { createVirtualKeySchema.parse(request); } catch (error) { throw new ValidationError("Invalid virtual key request", error); } const response = await this.post( ENDPOINTS.VIRTUAL_KEYS.BASE, request ); await this.invalidateCache(); return response; } async list(filters) { const params = { pageNumber: filters?.pageNumber || 1, pageSize: filters?.pageSize || DEFAULT_PAGE_SIZE, search: filters?.search, sortBy: filters?.sortBy?.field, sortDirection: filters?.sortBy?.direction, isEnabled: filters?.isEnabled, hasExpired: filters?.hasExpired, budgetDuration: filters?.budgetDuration, minBudget: filters?.minBudget, maxBudget: filters?.maxBudget, allowedModel: filters?.allowedModel, createdAfter: filters?.createdAfter, createdBefore: filters?.createdBefore, lastUsedAfter: filters?.lastUsedAfter, lastUsedBefore: filters?.lastUsedBefore }; const cacheKey = this.getCacheKey("virtual-keys", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.VIRTUAL_KEYS.BASE, params), CACHE_TTL.SHORT ); } async getById(id) { const cacheKey = this.getCacheKey("virtual-key", id); return this.withCache( cacheKey, () => super.get(ENDPOINTS.VIRTUAL_KEYS.BY_ID(id)), CACHE_TTL.MEDIUM ); } async update(id, request) { await this.put(ENDPOINTS.VIRTUAL_KEYS.BY_ID(id), request); await this.invalidateCache(); } async deleteById(id) { await super.delete(ENDPOINTS.VIRTUAL_KEYS.BY_ID(id)); await this.invalidateCache(); } async search(query) { const filters = { search: query, pageSize: 100 }; return this.list(filters); } async resetSpend(id) { await this.post(ENDPOINTS.VIRTUAL_KEYS.RESET_SPEND(id)); await this.cache?.delete(this.getCacheKey("virtual-key", id)); } async validate(key) { const request = { key }; return this.post( ENDPOINTS.VIRTUAL_KEYS.VALIDATE, request ); } async updateSpend(id, request) { await this.post(ENDPOINTS.VIRTUAL_KEYS.SPEND(id), request); await this.cache?.delete(this.getCacheKey("virtual-key", id)); } async checkBudget(id, estimatedCost) { const request = { estimatedCost }; return this.post( ENDPOINTS.VIRTUAL_KEYS.CHECK_BUDGET(id), request ); } async getValidationInfo(id) { return super.get( ENDPOINTS.VIRTUAL_KEYS.VALIDATION_INFO(id) ); } async performMaintenance(request) { return this.post( ENDPOINTS.VIRTUAL_KEYS.MAINTENANCE, request || {} ); } async getStatistics() { throw new NotImplementedError( "getStatistics requires Admin API endpoint implementation. The WebUI currently calculates statistics client-side by fetching all keys." ); } async bulkCreate(_requests) { throw new NotImplementedError( "bulkCreate requires Admin API endpoint implementation. Consider implementing POST /api/virtualkeys/bulk for batch creation." ); } async exportKeys(_format) { throw new NotImplementedError( "exportKeys requires Admin API endpoint implementation. Consider implementing GET /api/virtualkeys/export with format parameter." ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } }; // src/services/ProviderService.ts var import_zod2 = require("zod"); var createProviderSchema = import_zod2.z.object({ providerName: import_zod2.z.string().min(1), apiKey: import_zod2.z.string().optional(), apiEndpoint: import_zod2.z.string().url().optional(), organizationId: import_zod2.z.string().optional(), additionalConfig: import_zod2.z.string().optional(), isEnabled: import_zod2.z.boolean().optional() }); var updateHealthConfigSchema = import_zod2.z.object({ isEnabled: import_zod2.z.boolean().optional(), checkIntervalSeconds: import_zod2.z.number().min(30).max(3600).optional(), timeoutSeconds: import_zod2.z.number().min(5).max(300).optional(), unhealthyThreshold: import_zod2.z.number().min(1).max(10).optional(), healthyThreshold: import_zod2.z.number().min(1).max(10).optional(), testModel: import_zod2.z.string().optional() }); var ProviderService = class extends BaseApiClient { async create(request) { try { createProviderSchema.parse(request); } catch (error) { throw new ValidationError("Invalid provider credential request", error); } const response = await this.post( ENDPOINTS.PROVIDERS.BASE, request ); await this.invalidateCache(); return response; } async list(filters) { const cacheKey = this.getCacheKey("providers", filters); return this.withCache( cacheKey, () => super.get(ENDPOINTS.PROVIDERS.BASE), CACHE_TTL.MEDIUM ); } async getById(id) { const cacheKey = this.getCacheKey("provider", id); return this.withCache( cacheKey, () => super.get(ENDPOINTS.PROVIDERS.BY_ID(id)), CACHE_TTL.MEDIUM ); } async getByName(providerName) { const cacheKey = this.getCacheKey("provider-name", providerName); return this.withCache( cacheKey, () => super.get(ENDPOINTS.PROVIDERS.BY_NAME(providerName)), CACHE_TTL.MEDIUM ); } async getProviderNames() { const cacheKey = "provider-names"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.PROVIDERS.NAMES), CACHE_TTL.LONG ); } async update(id, request) { await this.put(ENDPOINTS.PROVIDERS.BY_ID(id), request); await this.invalidateCache(); } async deleteById(id) { await super.delete(ENDPOINTS.PROVIDERS.BY_ID(id)); await this.invalidateCache(); } async testConnectionById(id) { return this.post( ENDPOINTS.PROVIDERS.TEST_BY_ID(id) ); } async testConnection(request) { return this.post( ENDPOINTS.PROVIDERS.TEST, request ); } // Health monitoring methods async getHealthConfigurations() { const cacheKey = "provider-health-configs"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.HEALTH.CONFIGURATIONS), CACHE_TTL.SHORT ); } async getHealthConfiguration(providerName) { const cacheKey = this.getCacheKey("provider-health-config", providerName); return this.withCache( cacheKey, () => this.get( ENDPOINTS.HEALTH.CONFIG_BY_PROVIDER(providerName) ), CACHE_TTL.SHORT ); } async updateHealthConfiguration(providerName, request) { try { updateHealthConfigSchema.parse(request); } catch (error) { throw new ValidationError("Invalid health configuration request", error); } await this.put(ENDPOINTS.HEALTH.CONFIG_BY_PROVIDER(providerName), request); await this.invalidateCachePattern("provider-health"); } async getHealthStatus() { return super.get(ENDPOINTS.HEALTH.STATUS); } async getProviderHealthStatus(providerName) { return super.get( ENDPOINTS.HEALTH.STATUS_BY_PROVIDER(providerName) ); } async getHealthHistory(filters) { const params = { pageNumber: filters?.pageNumber || 1, pageSize: filters?.pageSize || DEFAULT_PAGE_SIZE, providerName: filters?.providerName, isHealthy: filters?.isHealthy, startDate: filters?.startDate, endDate: filters?.endDate, minResponseTime: filters?.minResponseTime, maxResponseTime: filters?.maxResponseTime, sortBy: filters?.sortBy?.field, sortDirection: filters?.sortBy?.direction }; return super.get( ENDPOINTS.HEALTH.HISTORY, params ); } async checkHealth(providerName) { return this.post( ENDPOINTS.HEALTH.CHECK(providerName) ); } // Stub methods async getUsageStatistics(_providerName, _startDate, _endDate) { throw new NotImplementedError( "getUsageStatistics requires Admin API endpoint implementation. Consider implementing GET /api/providercredentials/{name}/statistics" ); } async bulkTest(_providerNames) { throw new NotImplementedError( "bulkTest requires Admin API endpoint implementation. Consider implementing POST /api/providercredentials/test/bulk" ); } async getAvailableProviders() { throw new NotImplementedError( "getAvailableProviders requires Admin API endpoint implementation. Consider implementing GET /api/providercredentials/available" ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } async invalidateCachePattern(_pattern) { if (!this.cache) return; await this.cache.clear(); } }; // src/services/ModelMappingService.ts var import_zod3 = require("zod"); var createMappingSchema = import_zod3.z.object({ modelId: import_zod3.z.string().min(1), providerId: import_zod3.z.string().min(1), providerModelId: import_zod3.z.string().min(1), isEnabled: import_zod3.z.boolean().optional(), priority: import_zod3.z.number().min(0).max(100).optional(), metadata: import_zod3.z.string().optional() }); var updateMappingSchema = import_zod3.z.object({ providerId: import_zod3.z.string().min(1).optional(), providerModelId: import_zod3.z.string().min(1).optional(), isEnabled: import_zod3.z.boolean().optional(), priority: import_zod3.z.number().min(0).max(100).optional(), metadata: import_zod3.z.string().optional() }); var ModelMappingService = class extends BaseApiClient { async create(request) { try { createMappingSchema.parse(request); } catch (error) { throw new ValidationError("Invalid model mapping request", error); } const response = await this.post( ENDPOINTS.MODEL_MAPPINGS.BASE, request ); await this.invalidateCache(); return response; } async list(filters) { const params = filters ? { modelId: filters.modelId, providerId: filters.providerId, isEnabled: filters.isEnabled, minPriority: filters.minPriority, maxPriority: filters.maxPriority, sortBy: filters.sortBy?.field, sortDirection: filters.sortBy?.direction } : void 0; const cacheKey = this.getCacheKey("model-mappings", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_MAPPINGS.BASE, params), CACHE_TTL.MEDIUM ); } async getById(id) { const cacheKey = this.getCacheKey("model-mapping", id); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_MAPPINGS.BY_ID(id)), CACHE_TTL.MEDIUM ); } async getByModel(modelId) { const cacheKey = this.getCacheKey("model-mapping-by-model", modelId); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_MAPPINGS.BY_MODEL(modelId)), CACHE_TTL.MEDIUM ); } async update(id, request) { try { updateMappingSchema.parse(request); } catch (error) { throw new ValidationError("Invalid model mapping update request", error); } await this.put(ENDPOINTS.MODEL_MAPPINGS.BY_ID(id), request); await this.invalidateCache(); } async deleteById(id) { await super.delete(ENDPOINTS.MODEL_MAPPINGS.BY_ID(id)); await this.invalidateCache(); } async getAvailableProviders() { const cacheKey = "available-providers"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_MAPPINGS.PROVIDERS), CACHE_TTL.LONG ); } async updatePriority(id, priority) { await this.update(id, { priority }); } async enableMapping(id) { await this.update(id, { isEnabled: true }); } async disableMapping(id) { await this.update(id, { isEnabled: false }); } async reorderMappings(_modelId, mappingIds) { const updates = mappingIds.map((id, index) => ({ id, priority: mappingIds.length - index })); await Promise.all( updates.map( (update) => this.updatePriority(update.id, update.priority) ) ); } // Stub methods async getRoutingInfo(_modelId) { throw new NotImplementedError( "getRoutingInfo requires Admin API endpoint implementation. Consider implementing GET /api/modelprovidermapping/routing/{modelId}" ); } async bulkCreate(_request) { throw new NotImplementedError( "bulkCreate requires Admin API endpoint implementation. Consider implementing POST /api/modelprovidermapping/bulk" ); } async importMappings(_file, _format) { throw new NotImplementedError( "importMappings requires Admin API endpoint implementation. Consider implementing POST /api/modelprovidermapping/import" ); } async exportMappings(_format) { throw new NotImplementedError( "exportMappings requires Admin API endpoint implementation. Consider implementing GET /api/modelprovidermapping/export" ); } async suggestOptimalMapping(_modelId) { throw new NotImplementedError( "suggestOptimalMapping requires Admin API endpoint implementation. Consider implementing POST /api/modelprovidermapping/suggest" ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } }; // src/services/SettingsService.ts var import_zod4 = require("zod"); var createSettingSchema = import_zod4.z.object({ key: import_zod4.z.string().min(1).regex(/^[A-Z_][A-Z0-9_]*$/, "Key must be uppercase with underscores"), value: import_zod4.z.string(), description: import_zod4.z.string().optional(), dataType: import_zod4.z.enum(["string", "number", "boolean", "json"]).optional(), category: import_zod4.z.string().optional(), isSecret: import_zod4.z.boolean().optional() }); var audioConfigSchema = import_zod4.z.object({ provider: import_zod4.z.string().min(1), isEnabled: import_zod4.z.boolean().optional(), apiKey: import_zod4.z.string().optional(), apiEndpoint: import_zod4.z.string().url().optional(), defaultVoice: import_zod4.z.string().optional(), defaultModel: import_zod4.z.string().optional(), maxDuration: import_zod4.z.number().positive().optional(), allowedVoices: import_zod4.z.array(import_zod4.z.string()).optional(), customSettings: import_zod4.z.record(import_zod4.z.any()).optional() }); var SettingsService = class extends BaseApiClient { // Global Settings async getGlobalSettings(filters) { const params = filters ? { category: filters.category, dataType: filters.dataType, isSecret: filters.isSecret, search: filters.searchKey } : void 0; const cacheKey = this.getCacheKey("global-settings", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.SETTINGS.GLOBAL, params), CACHE_TTL.MEDIUM ); } async getGlobalSetting(key) { const cacheKey = this.getCacheKey("global-setting", key); return this.withCache( cacheKey, () => super.get(ENDPOINTS.SETTINGS.GLOBAL_BY_KEY(key)), CACHE_TTL.MEDIUM ); } async createGlobalSetting(request) { try { createSettingSchema.parse(request); } catch (error) { throw new ValidationError("Invalid global setting request", error); } const response = await this.post( ENDPOINTS.SETTINGS.GLOBAL, request ); await this.invalidateCache(); return response; } async updateGlobalSetting(key, request) { await this.put(ENDPOINTS.SETTINGS.GLOBAL_BY_KEY(key), request); await this.invalidateCache(); } async deleteGlobalSetting(key) { await this.delete(ENDPOINTS.SETTINGS.GLOBAL_BY_KEY(key)); await this.invalidateCache(); } // Audio Configuration async getAudioConfigurations() { const cacheKey = "audio-configurations"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.SETTINGS.AUDIO), CACHE_TTL.MEDIUM ); } async getAudioConfiguration(provider) { const cacheKey = this.getCacheKey("audio-config", provider); return this.withCache( cacheKey, () => super.get(ENDPOINTS.SETTINGS.AUDIO_BY_PROVIDER(provider)), CACHE_TTL.MEDIUM ); } async createAudioConfiguration(request) { try { audioConfigSchema.parse(request); } catch (error) { throw new ValidationError("Invalid audio configuration request", error); } const response = await this.post( ENDPOINTS.SETTINGS.AUDIO, request ); await this.invalidateCache(); return response; } async updateAudioConfiguration(provider, request) { await this.put(ENDPOINTS.SETTINGS.AUDIO_BY_PROVIDER(provider), request); await this.invalidateCache(); } async deleteAudioConfiguration(provider) { await this.delete(ENDPOINTS.SETTINGS.AUDIO_BY_PROVIDER(provider)); await this.invalidateCache(); } // Router Configuration async getRouterConfiguration() { const cacheKey = "router-configuration"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.SETTINGS.ROUTER), CACHE_TTL.SHORT ); } async updateRouterConfiguration(request) { await this.put(ENDPOINTS.SETTINGS.ROUTER, request); await this.invalidateCache(); } // Convenience methods async getSetting(key) { const setting = await this.getGlobalSetting(key); return setting.value; } async setSetting(key, value, options) { try { await this.getGlobalSetting(key); await this.updateGlobalSetting(key, { value }); } catch (error) { await this.createGlobalSetting({ key, value, ...options }); } } async getSettingsByCategory(category) { const settings = await this.getGlobalSettings({ category }); return settings; } // Stub methods async getSystemConfiguration() { throw new NotImplementedError( "getSystemConfiguration requires Admin API endpoint implementation. Consider implementing GET /api/settings/system-configuration" ); } async exportSettings(_format) { throw new NotImplementedError( "exportSettings requires Admin API endpoint implementation. Consider implementing GET /api/settings/export" ); } async importSettings(_file, _format) { throw new NotImplementedError( "importSettings requires Admin API endpoint implementation. Consider implementing POST /api/settings/import" ); } async validateConfiguration() { throw new NotImplementedError( "validateConfiguration requires Admin API endpoint implementation. Consider implementing POST /api/settings/validate" ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } }; // src/services/IpFilterService.ts var import_zod5 = require("zod"); var createFilterSchema = import_zod5.z.object({ name: import_zod5.z.string().min(1).max(100), cidrRange: import_zod5.z.string().regex( /^(\d{1,3}\.){3}\d{1,3}\/\d{1,2}$/, "Invalid CIDR format (e.g., 192.168.1.0/24)" ), filterType: import_zod5.z.enum(["Allow", "Deny"]), isEnabled: import_zod5.z.boolean().optional(), description: import_zod5.z.string().max(500).optional() }); var ipCheckSchema = import_zod5.z.object({ ipAddress: import_zod5.z.string().ip(), endpoint: import_zod5.z.string().optional() }); var IpFilterService = class extends BaseApiClient { async create(request) { try { createFilterSchema.parse(request); } catch (error) { throw new ValidationError("Invalid IP filter request", error); } const response = await this.post( ENDPOINTS.IP_FILTERS.BASE, request ); await this.invalidateCache(); return response; } async list(filters) { const params = filters ? { filterType: filters.filterType, isEnabled: filters.isEnabled, nameContains: filters.nameContains, cidrContains: filters.cidrContains, lastMatchedAfter: filters.lastMatchedAfter, lastMatchedBefore: filters.lastMatchedBefore, minMatchCount: filters.minMatchCount, sortBy: filters.sortBy?.field, sortDirection: filters.sortBy?.direction } : void 0; const cacheKey = this.getCacheKey("ip-filters", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.IP_FILTERS.BASE, params), CACHE_TTL.SHORT ); } async getById(id) { const cacheKey = this.getCacheKey("ip-filter", id); return this.withCache( cacheKey, () => super.get(ENDPOINTS.IP_FILTERS.BY_ID(id)), CACHE_TTL.SHORT ); } async getEnabled() { const cacheKey = "ip-filters-enabled"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.IP_FILTERS.ENABLED), CACHE_TTL.SHORT ); } async update(id, request) { await this.put(ENDPOINTS.IP_FILTERS.BY_ID(id), request); await this.invalidateCache(); } async deleteById(id) { await super.delete(ENDPOINTS.IP_FILTERS.BY_ID(id)); await this.invalidateCache(); } async getSettings() { const cacheKey = "ip-filter-settings"; return this.withCache( cacheKey, () => super.get(ENDPOINTS.IP_FILTERS.SETTINGS), CACHE_TTL.SHORT ); } async updateSettings(request) { await this.put(ENDPOINTS.IP_FILTERS.SETTINGS, request); await this.invalidateCache(); } async checkIp(ipAddress, endpoint) { try { ipCheckSchema.parse({ ipAddress, endpoint }); } catch (error) { throw new ValidationError("Invalid IP check request", error); } const request = { ipAddress, endpoint }; return this.post(ENDPOINTS.IP_FILTERS.CHECK, request); } async search(query) { const filters = { nameContains: query }; return this.list(filters); } async enableFilter(id) { await this.update(id, { isEnabled: true }); } async disableFilter(id) { await this.update(id, { isEnabled: false }); } async createAllowFilter(name, cidrRange, description) { return this.create({ name, cidrRange, filterType: "Allow", isEnabled: true, description }); } async createDenyFilter(name, cidrRange, description) { return this.create({ name, cidrRange, filterType: "Deny", isEnabled: true, description }); } async getFiltersByType(filterType) { return this.list({ filterType }); } // Stub methods async getStatistics() { throw new NotImplementedError( "getStatistics requires Admin API endpoint implementation. Consider implementing GET /api/ipfilter/statistics" ); } async bulkCreate(_request) { throw new NotImplementedError( "bulkCreate requires Admin API endpoint implementation. Consider implementing POST /api/ipfilter/bulk" ); } async importFilters(_file, _format) { throw new NotImplementedError( "importFilters requires Admin API endpoint implementation. Consider implementing POST /api/ipfilter/import" ); } async exportFilters(_format, _filterType) { throw new NotImplementedError( "exportFilters requires Admin API endpoint implementation. Consider implementing GET /api/ipfilter/export" ); } async validateCidr(_cidrRange) { throw new NotImplementedError( "validateCidr requires Admin API endpoint implementation. Consider implementing POST /api/ipfilter/validate-cidr" ); } async testRules(_ipAddress, _proposedRules) { throw new NotImplementedError( "testRules requires Admin API endpoint implementation. Consider implementing POST /api/ipfilter/test" ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } }; // src/services/ModelCostService.ts var import_zod6 = require("zod"); var createCostSchema = import_zod6.z.object({ modelId: import_zod6.z.string().min(1), inputTokenCost: import_zod6.z.number().min(0), outputTokenCost: import_zod6.z.number().min(0), currency: import_zod6.z.string().length(3).default("USD"), effectiveDate: import_zod6.z.string().datetime().optional(), expiryDate: import_zod6.z.string().datetime().optional(), providerId: import_zod6.z.string().optional(), description: import_zod6.z.string().max(500).optional(), isActive: import_zod6.z.boolean().optional() }); var calculateCostSchema = import_zod6.z.object({ modelId: import_zod6.z.string().min(1), inputTokens: import_zod6.z.number().min(0), outputTokens: import_zod6.z.number().min(0) }); var ModelCostService = class extends BaseApiClient { async create(request) { try { createCostSchema.parse(request); } catch (error) { throw new ValidationError("Invalid model cost request", error); } const response = await this.post( ENDPOINTS.MODEL_COSTS.BASE, request ); await this.invalidateCache(); return response; } async list(filters) { const params = filters ? { modelId: filters.modelId, providerId: filters.providerId, currency: filters.currency, isActive: filters.isActive, effectiveAfter: filters.effectiveAfter, effectiveBefore: filters.effectiveBefore, minInputCost: filters.minInputCost, maxInputCost: filters.maxInputCost, minOutputCost: filters.minOutputCost, maxOutputCost: filters.maxOutputCost, sortBy: filters.sortBy?.field, sortDirection: filters.sortBy?.direction } : void 0; const cacheKey = this.getCacheKey("model-costs", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_COSTS.BASE, params), CACHE_TTL.LONG ); } async getById(id) { const cacheKey = this.getCacheKey("model-cost", id); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_COSTS.BY_ID(id)), CACHE_TTL.LONG ); } async getByModel(modelId) { const cacheKey = this.getCacheKey("model-cost-by-model", modelId); return this.withCache( cacheKey, () => super.get(ENDPOINTS.MODEL_COSTS.BY_MODEL(modelId)), CACHE_TTL.LONG ); } async update(id, request) { await this.put(ENDPOINTS.MODEL_COSTS.BY_ID(id), request); await this.invalidateCache(); } async deleteById(id) { await super.delete(ENDPOINTS.MODEL_COSTS.BY_ID(id)); await this.invalidateCache(); } async calculateCost(modelId, inputTokens, outputTokens) { try { calculateCostSchema.parse({ modelId, inputTokens, outputTokens }); } catch (error) { throw new ValidationError("Invalid cost calculation request", error); } const costs = await this.getByModel(modelId); const activeCost = costs.find((c) => c.isActive); if (!activeCost) { throw new ValidationError(`No active cost configuration found for model: ${modelId}`); } const inputCost = inputTokens / 1e3 * activeCost.inputTokenCost; const outputCost = outputTokens / 1e3 * activeCost.outputTokenCost; return { modelId, inputTokens, outputTokens, inputCost, outputCost, totalCost: inputCost + outputCost, currency: activeCost.currency, costPerThousandInputTokens: activeCost.inputTokenCost, costPerThousandOutputTokens: activeCost.outputTokenCost }; } async getCurrentCost(modelId) { const costs = await this.getByModel(modelId); return costs.find((c) => c.isActive) || null; } async updateCosts(models, inputCost, outputCost) { const updates = await Promise.all( models.map(async (modelId) => { const costs = await this.getByModel(modelId); const activeCost = costs.find((c) => c.isActive); if (activeCost) { return this.update(activeCost.id, { inputTokenCost: inputCost, outputTokenCost: outputCost }); } else { return this.create({ modelId, inputTokenCost: inputCost, outputTokenCost: outputCost, isActive: true }); } }) ); await Promise.all(updates); } // Stub methods async bulkUpdate(_request) { throw new NotImplementedError( "bulkUpdate requires Admin API endpoint implementation. Consider implementing POST /api/modelcosts/bulk-update" ); } async getHistory(_modelId) { throw new NotImplementedError( "getHistory requires Admin API endpoint implementation. Consider implementing GET /api/modelcosts/history/{modelId}" ); } async estimateCosts(_scenarios, _models) { throw new NotImplementedError( "estimateCosts requires Admin API endpoint implementation. Consider implementing POST /api/modelcosts/estimate" ); } async compareCosts(_baseModel, _comparisonModels, _inputTokens, _outputTokens) { throw new NotImplementedError( "compareCosts requires Admin API endpoint implementation. Consider implementing POST /api/modelcosts/compare" ); } async importCosts(_file, _format) { throw new NotImplementedError( "importCosts requires Admin API endpoint implementation. Consider implementing POST /api/modelcosts/import" ); } async exportCosts(_format, _activeOnly) { throw new NotImplementedError( "exportCosts requires Admin API endpoint implementation. Consider implementing GET /api/modelcosts/export" ); } async invalidateCache() { if (!this.cache) return; await this.cache.clear(); } }; // src/services/AnalyticsService.ts var import_zod7 = require("zod"); var dateRangeSchema = import_zod7.z.object({ startDate: import_zod7.z.string().datetime(), endDate: import_zod7.z.string().datetime() }); var AnalyticsService = class extends BaseApiClient { // Cost Analytics async getCostSummary(dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const cacheKey = this.getCacheKey("cost-summary", dateRange); return this.withCache( cacheKey, () => super.get(ENDPOINTS.ANALYTICS.COST_SUMMARY, dateRange), CACHE_TTL.SHORT ); } async getCostByPeriod(dateRange, groupBy = "day") { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const params = { ...dateRange, groupBy }; const cacheKey = this.getCacheKey("cost-by-period", params); return this.withCache( cacheKey, () => super.get(ENDPOINTS.ANALYTICS.COST_BY_PERIOD, params), CACHE_TTL.SHORT ); } async getCostByModel(dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const cacheKey = this.getCacheKey("cost-by-model", dateRange); return this.withCache( cacheKey, () => super.get( ENDPOINTS.ANALYTICS.COST_BY_MODEL, dateRange ), CACHE_TTL.SHORT ); } async getCostByKey(dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const cacheKey = this.getCacheKey("cost-by-key", dateRange); return this.withCache( cacheKey, () => super.get( ENDPOINTS.ANALYTICS.COST_BY_KEY, dateRange ), CACHE_TTL.SHORT ); } // Request Logs async getRequestLogs(filters) { const params = { pageNumber: filters?.pageNumber || 1, pageSize: filters?.pageSize || DEFAULT_PAGE_SIZE, startDate: filters?.startDate, endDate: filters?.endDate, virtualKeyId: filters?.virtualKeyId, model: filters?.model, provider: filters?.provider, status: filters?.status, minCost: filters?.minCost, maxCost: filters?.maxCost, minDuration: filters?.minDuration, maxDuration: filters?.maxDuration, ipAddress: filters?.ipAddress, sortBy: filters?.sortBy?.field, sortDirection: filters?.sortBy?.direction }; return super.get( ENDPOINTS.ANALYTICS.REQUEST_LOGS, params ); } async getRequestLog(id) { return super.get(ENDPOINTS.ANALYTICS.REQUEST_LOG_BY_ID(id)); } async searchLogs(query, filters) { const response = await this.getRequestLogs({ ...filters, search: query, pageSize: 100 }); return response.items; } // Usage Metrics async getUsageMetrics(dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const cacheKey = this.getCacheKey("usage-metrics", dateRange); return this.withCache( cacheKey, () => super.get("/api/analytics/usage-metrics", dateRange), CACHE_TTL.SHORT ); } async getModelUsage(modelId, dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const params = { modelId, ...dateRange }; const cacheKey = this.getCacheKey("model-usage", params); return this.withCache( cacheKey, () => super.get("/api/analytics/model-usage", params), CACHE_TTL.SHORT ); } async getKeyUsage(keyId, dateRange) { try { dateRangeSchema.parse(dateRange); } catch (error) { throw new ValidationError("Invalid date range", error); } const params = { keyId, ...dateRange }; const cacheKey = this.getCacheKey("key-usage", params); return this.withCache( cacheKey, () => super.get("/api/analytics/key-usage", params), CACHE_TTL.SHORT ); } // Convenience methods async getTodayCosts() { const today = /* @__PURE__ */ new Date(); const startDate = new Date(today.setHours(0, 0, 0, 0)).toISOString(); const endDate = new Date(today.setHours(23, 59, 59, 999)).toISOString(); return this.getCostSummary({ startDate, endDate }); } async getMonthCosts() { const now = /* @__PURE_