@knn_labs/conduit-admin-client
Version:
TypeScript client library for Conduit Admin API
1,572 lines (1,560 loc) • 60.5 kB
JavaScript
"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_