858 lines
28 KiB
TypeScript
858 lines
28 KiB
TypeScript
import {
|
|
Budget,
|
|
CreateCustomerRequest,
|
|
CreateModelConfigRequest,
|
|
CreatePricingOverrideRequest,
|
|
UpdatePricingOverrideRequest,
|
|
CreateTeamRequest,
|
|
CreateVirtualKeyRequest,
|
|
Customer,
|
|
DebugStatsResponse,
|
|
GetBudgetsResponse,
|
|
GetCustomersParams,
|
|
GetCustomersResponse,
|
|
GetModelConfigsParams,
|
|
GetModelConfigsResponse,
|
|
GetPricingOverridesResponse,
|
|
GetProviderGovernanceResponse,
|
|
GetRateLimitsResponse,
|
|
GetTeamsParams,
|
|
GetTeamsResponse,
|
|
GetUsageStatsResponse,
|
|
GetVirtualKeysParams,
|
|
GetVirtualKeysResponse,
|
|
HealthCheckResponse,
|
|
ModelConfig,
|
|
ProviderGovernance,
|
|
PricingOverride,
|
|
RateLimit,
|
|
ResetUsageRequest,
|
|
Team,
|
|
UpdateBudgetRequest,
|
|
UpdateCustomerRequest,
|
|
UpdateModelConfigRequest,
|
|
UpdateProviderGovernanceRequest,
|
|
UpdateRateLimitRequest,
|
|
UpdateTeamRequest,
|
|
UpdateVirtualKeyRequest,
|
|
VirtualKey,
|
|
} from "@/lib/types/governance";
|
|
import { baseApi } from "./baseApi";
|
|
|
|
type PricingOverrideQueryArgs = {
|
|
scopeKind?: string;
|
|
virtualKeyID?: string;
|
|
providerID?: string;
|
|
providerKeyID?: string;
|
|
limit?: number;
|
|
offset?: number;
|
|
search?: string;
|
|
};
|
|
|
|
export const governanceApi = baseApi.injectEndpoints({
|
|
endpoints: (builder) => ({
|
|
// Virtual Keys
|
|
getVirtualKeys: builder.query<GetVirtualKeysResponse, GetVirtualKeysParams | void>({
|
|
query: (params) => ({
|
|
url: "/governance/virtual-keys",
|
|
params: {
|
|
...(params?.limit && { limit: params.limit }),
|
|
...(params?.offset !== undefined && { offset: params.offset }),
|
|
...(params?.search && { search: params.search }),
|
|
...(params?.customer_id && { customer_id: params.customer_id }),
|
|
...(params?.team_id && { team_id: params.team_id }),
|
|
...(params?.exclude_access_profile_managed_virtual === true && {
|
|
exclude_access_profile_managed_virtual: "true",
|
|
}),
|
|
...(params?.sort_by && { sort_by: params.sort_by }),
|
|
...(params?.order && { order: params.order }),
|
|
...(params?.export && { export: "true" }),
|
|
},
|
|
}),
|
|
providesTags: ["VirtualKeys"],
|
|
}),
|
|
|
|
getVirtualKey: builder.query<{ virtual_key: VirtualKey }, string>({
|
|
query: (vkId) => `/governance/virtual-keys/${vkId}`,
|
|
providesTags: (result, error, vkId) => [{ type: "VirtualKeys", id: vkId }],
|
|
}),
|
|
|
|
createVirtualKey: builder.mutation<{ message: string; virtual_key: VirtualKey }, CreateVirtualKeyRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/virtual-keys",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
invalidatesTags: ["VirtualKeys"],
|
|
}),
|
|
|
|
updateVirtualKey: builder.mutation<{ message: string; virtual_key: VirtualKey }, { vkId: string; data: UpdateVirtualKeyRequest }>({
|
|
query: ({ vkId, data }) => ({
|
|
url: `/governance/virtual-keys/${vkId}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
invalidatesTags: ["VirtualKeys"],
|
|
}),
|
|
|
|
deleteVirtualKey: builder.mutation<{ message: string }, string>({
|
|
query: (vkId) => ({
|
|
url: `/governance/virtual-keys/${vkId}`,
|
|
method: "DELETE",
|
|
}),
|
|
invalidatesTags: ["VirtualKeys"],
|
|
}),
|
|
|
|
// Teams
|
|
getTeams: builder.query<GetTeamsResponse, GetTeamsParams | void>({
|
|
query: (params) => ({
|
|
url: "/governance/teams",
|
|
params: {
|
|
...(params?.limit && { limit: params.limit }),
|
|
...(params?.offset !== undefined && { offset: params.offset }),
|
|
...(params?.search && { search: params.search }),
|
|
...(params?.customer_id && { customer_id: params.customer_id }),
|
|
},
|
|
}),
|
|
providesTags: ["Teams"],
|
|
}),
|
|
|
|
getTeam: builder.query<{ team: Team }, string>({
|
|
query: (teamId) => `/governance/teams/${teamId}`,
|
|
providesTags: (result, error, teamId) => [{ type: "Teams", id: teamId }],
|
|
}),
|
|
|
|
createTeam: builder.mutation<{ message: string; team: Team }, CreateTeamRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/teams",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted(arg, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getTeams" || entry?.status !== "fulfilled") continue;
|
|
const search = entry.originalArgs?.search as string | undefined;
|
|
if (search && !data.team.name.toLowerCase().includes(search.toLowerCase())) continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getTeams", entry.originalArgs, (draft) => {
|
|
if (!draft.teams) draft.teams = [];
|
|
draft.teams.unshift(data.team);
|
|
draft.count = (draft.count || 0) + 1;
|
|
draft.total_count = (draft.total_count || 0) + 1;
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
updateTeam: builder.mutation<{ message: string; team: Team }, { teamId: string; data: UpdateTeamRequest }>({
|
|
query: ({ teamId, data }) => ({
|
|
url: `/governance/teams/${teamId}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ teamId }, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getTeams" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getTeams", entry.originalArgs, (draft) => {
|
|
if (!draft.teams) return;
|
|
const index = draft.teams.findIndex((t) => t.id === teamId);
|
|
if (index !== -1) {
|
|
draft.teams[index] = data.team;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getTeam", teamId, (draft) => {
|
|
draft.team = data.team;
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteTeam: builder.mutation<{ message: string }, string>({
|
|
query: (teamId) => ({
|
|
url: `/governance/teams/${teamId}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(teamId, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getTeams" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getTeams", entry.originalArgs, (draft) => {
|
|
if (!draft.teams) return;
|
|
const before = draft.teams.length;
|
|
draft.teams = draft.teams.filter((t) => t.id !== teamId);
|
|
if (draft.teams.length < before) {
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
draft.total_count = Math.max(0, (draft.total_count || 0) - 1);
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
// Customers
|
|
getCustomers: builder.query<GetCustomersResponse, GetCustomersParams | void>({
|
|
query: (params) => ({
|
|
url: "/governance/customers",
|
|
params: {
|
|
...(params?.limit && { limit: params.limit }),
|
|
...(params?.offset !== undefined && { offset: params.offset }),
|
|
...(params?.search && { search: params.search }),
|
|
},
|
|
}),
|
|
providesTags: ["Customers"],
|
|
}),
|
|
|
|
getCustomer: builder.query<{ customer: Customer }, string>({
|
|
query: (customerId) => `/governance/customers/${customerId}`,
|
|
providesTags: (result, error, customerId) => [{ type: "Customers", id: customerId }],
|
|
}),
|
|
|
|
createCustomer: builder.mutation<{ message: string; customer: Customer }, CreateCustomerRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/customers",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted(arg, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getCustomers" || entry?.status !== "fulfilled") continue;
|
|
const search = entry.originalArgs?.search as string | undefined;
|
|
if (search && !data.customer.name.toLowerCase().includes(search.toLowerCase())) continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getCustomers", entry.originalArgs, (draft) => {
|
|
if (!draft.customers) draft.customers = [];
|
|
draft.customers.unshift(data.customer);
|
|
draft.count = (draft.count || 0) + 1;
|
|
draft.total_count = (draft.total_count || 0) + 1;
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
updateCustomer: builder.mutation<{ message: string; customer: Customer }, { customerId: string; data: UpdateCustomerRequest }>({
|
|
query: ({ customerId, data }) => ({
|
|
url: `/governance/customers/${customerId}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ customerId }, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getCustomers" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getCustomers", entry.originalArgs, (draft) => {
|
|
if (!draft.customers) return;
|
|
const index = draft.customers.findIndex((c) => c.id === customerId);
|
|
if (index !== -1) {
|
|
draft.customers[index] = data.customer;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getCustomer", customerId, (draft) => {
|
|
draft.customer = data.customer;
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteCustomer: builder.mutation<{ message: string }, string>({
|
|
query: (customerId) => ({
|
|
url: `/governance/customers/${customerId}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(customerId, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getCustomers" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getCustomers", entry.originalArgs, (draft) => {
|
|
if (!draft.customers) return;
|
|
const before = draft.customers.length;
|
|
draft.customers = draft.customers.filter((c) => c.id !== customerId);
|
|
if (draft.customers.length < before) {
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
draft.total_count = Math.max(0, (draft.total_count || 0) - 1);
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
// Budgets
|
|
getBudgets: builder.query<GetBudgetsResponse, void>({
|
|
query: () => "/governance/budgets",
|
|
providesTags: ["Budgets"],
|
|
}),
|
|
|
|
getBudget: builder.query<{ budget: Budget }, string>({
|
|
query: (budgetId) => `/governance/budgets/${budgetId}`,
|
|
providesTags: (result, error, budgetId) => [{ type: "Budgets", id: budgetId }],
|
|
}),
|
|
|
|
updateBudget: builder.mutation<{ message: string; budget: Budget }, { budgetId: string; data: UpdateBudgetRequest }>({
|
|
query: ({ budgetId, data }) => ({
|
|
url: `/governance/budgets/${budgetId}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ budgetId }, { dispatch, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getBudgets", undefined, (draft) => {
|
|
if (!draft.budgets) return;
|
|
const index = draft.budgets.findIndex((b) => b.id === budgetId);
|
|
if (index !== -1) {
|
|
draft.budgets[index] = data.budget;
|
|
}
|
|
}),
|
|
);
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getBudget", budgetId, (draft) => {
|
|
draft.budget = data.budget;
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteBudget: builder.mutation<{ message: string }, string>({
|
|
query: (budgetId) => ({
|
|
url: `/governance/budgets/${budgetId}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(budgetId, { dispatch, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getBudgets", undefined, (draft) => {
|
|
if (!draft.budgets) return;
|
|
draft.budgets = draft.budgets.filter((b) => b.id !== budgetId);
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
// Rate Limits
|
|
getRateLimits: builder.query<GetRateLimitsResponse, void>({
|
|
query: () => "/governance/rate-limits",
|
|
providesTags: ["RateLimits"],
|
|
}),
|
|
|
|
getRateLimit: builder.query<{ rate_limit: RateLimit }, string>({
|
|
query: (rateLimitId) => `/governance/rate-limits/${rateLimitId}`,
|
|
providesTags: (result, error, rateLimitId) => [{ type: "RateLimits", id: rateLimitId }],
|
|
}),
|
|
|
|
updateRateLimit: builder.mutation<{ message: string; rate_limit: RateLimit }, { rateLimitId: string; data: UpdateRateLimitRequest }>({
|
|
query: ({ rateLimitId, data }) => ({
|
|
url: `/governance/rate-limits/${rateLimitId}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ rateLimitId }, { dispatch, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getRateLimits", undefined, (draft) => {
|
|
if (!draft.rate_limits) return;
|
|
const index = draft.rate_limits.findIndex((r) => r.id === rateLimitId);
|
|
if (index !== -1) {
|
|
draft.rate_limits[index] = data.rate_limit;
|
|
}
|
|
}),
|
|
);
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getRateLimit", rateLimitId, (draft) => {
|
|
draft.rate_limit = data.rate_limit;
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteRateLimit: builder.mutation<{ message: string }, string>({
|
|
query: (rateLimitId) => ({
|
|
url: `/governance/rate-limits/${rateLimitId}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(rateLimitId, { dispatch, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getRateLimits", undefined, (draft) => {
|
|
if (!draft.rate_limits) return;
|
|
draft.rate_limits = draft.rate_limits.filter((r) => r.id !== rateLimitId);
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
// Usage Stats
|
|
getUsageStats: builder.query<GetUsageStatsResponse, { virtualKeyId?: string }>({
|
|
query: ({ virtualKeyId } = {}) => ({
|
|
url: "/governance/usage-stats",
|
|
params: virtualKeyId ? { virtual_key_id: virtualKeyId } : {},
|
|
}),
|
|
providesTags: ["UsageStats"],
|
|
}),
|
|
|
|
resetUsage: builder.mutation<{ message: string }, ResetUsageRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/usage-reset",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
invalidatesTags: ["UsageStats"],
|
|
}),
|
|
|
|
// Debug endpoints
|
|
getGovernanceDebugStats: builder.query<DebugStatsResponse, void>({
|
|
query: () => "/governance/debug/stats",
|
|
providesTags: ["DebugStats"],
|
|
}),
|
|
|
|
getGovernanceHealth: builder.query<HealthCheckResponse, void>({
|
|
query: () => "/governance/debug/health",
|
|
providesTags: ["HealthCheck"],
|
|
}),
|
|
|
|
// Model Configs
|
|
getModelConfigs: builder.query<GetModelConfigsResponse, GetModelConfigsParams | void>({
|
|
query: (params) => ({
|
|
url: "/governance/model-configs",
|
|
params: {
|
|
...(params?.limit && { limit: params.limit }),
|
|
...(params?.offset !== undefined && { offset: params.offset }),
|
|
...(params?.search && { search: params.search }),
|
|
},
|
|
}),
|
|
providesTags: ["ModelConfigs"],
|
|
}),
|
|
|
|
getModelConfig: builder.query<{ model_config: ModelConfig }, string>({
|
|
query: (id) => `/governance/model-configs/${id}`,
|
|
providesTags: (result, error, id) => [{ type: "ModelConfigs", id }],
|
|
}),
|
|
|
|
createModelConfig: builder.mutation<{ message: string; model_config: ModelConfig }, CreateModelConfigRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/model-configs",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted(arg, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getModelConfigs" || entry?.status !== "fulfilled") continue;
|
|
const search = entry.originalArgs?.search as string | undefined;
|
|
if (search && !data.model_config.model_name.toLowerCase().includes(search.toLowerCase())) continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getModelConfigs", entry.originalArgs, (draft) => {
|
|
if (!draft.model_configs) draft.model_configs = [];
|
|
draft.model_configs.unshift(data.model_config);
|
|
draft.count = (draft.count || 0) + 1;
|
|
draft.total_count = (draft.total_count || 0) + 1;
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed, do nothing - error handling bubbled up
|
|
}
|
|
},
|
|
}),
|
|
|
|
updateModelConfig: builder.mutation<{ message: string; model_config: ModelConfig }, { id: string; data: UpdateModelConfigRequest }>({
|
|
query: ({ id, data }) => ({
|
|
url: `/governance/model-configs/${id}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ id }, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getModelConfigs" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getModelConfigs", entry.originalArgs, (draft) => {
|
|
if (!draft.model_configs) return;
|
|
const index = draft.model_configs.findIndex((mc) => mc.id === id);
|
|
if (index !== -1) {
|
|
draft.model_configs[index] = data.model_config;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getModelConfig", id, (draft) => {
|
|
draft.model_config = data.model_config;
|
|
}),
|
|
);
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteModelConfig: builder.mutation<{ message: string }, string>({
|
|
query: (id) => ({
|
|
url: `/governance/model-configs/${id}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(id, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getModelConfigs" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getModelConfigs", entry.originalArgs, (draft) => {
|
|
if (!draft.model_configs) return;
|
|
const before = draft.model_configs.length;
|
|
draft.model_configs = draft.model_configs.filter((mc) => mc.id !== id);
|
|
if (draft.model_configs.length < before) {
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
draft.total_count = Math.max(0, (draft.total_count || 0) - 1);
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
getPricingOverrides: builder.query<GetPricingOverridesResponse, PricingOverrideQueryArgs | void>({
|
|
query: (params) => ({
|
|
url: "/governance/pricing-overrides",
|
|
params: {
|
|
scope_kind: params?.scopeKind,
|
|
virtual_key_id: params?.virtualKeyID,
|
|
provider_id: params?.providerID,
|
|
provider_key_id: params?.providerKeyID,
|
|
...(params?.limit !== undefined && { limit: params.limit }),
|
|
...(params?.offset !== undefined && { offset: params.offset }),
|
|
...(params?.search && { search: params.search }),
|
|
},
|
|
}),
|
|
providesTags: ["PricingOverrides"],
|
|
}),
|
|
|
|
createPricingOverride: builder.mutation<{ message: string; pricing_override: PricingOverride }, CreatePricingOverrideRequest>({
|
|
query: (data) => ({
|
|
url: "/governance/pricing-overrides",
|
|
method: "POST",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted(_arg, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const created = data.pricing_override;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getPricingOverrides" || entry?.status !== "fulfilled") continue;
|
|
const args: PricingOverrideQueryArgs = entry.originalArgs ?? {};
|
|
const matchesQuery =
|
|
(!args.scopeKind || args.scopeKind === created.scope_kind) &&
|
|
(!args.virtualKeyID || args.virtualKeyID === created.virtual_key_id) &&
|
|
(!args.providerID || args.providerID === created.provider_id) &&
|
|
(!args.providerKeyID || args.providerKeyID === created.provider_key_id) &&
|
|
(!args.search || created.name?.toLowerCase().includes(args.search.toLowerCase()));
|
|
if (!matchesQuery) continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getPricingOverrides", entry.originalArgs, (draft) => {
|
|
if (!draft.pricing_overrides) draft.pricing_overrides = [];
|
|
if (!args.offset || args.offset === 0) {
|
|
draft.pricing_overrides.unshift(created);
|
|
draft.count = (draft.count || 0) + 1;
|
|
draft.total_count = (draft.total_count || 0) + 1;
|
|
} else {
|
|
draft.total_count = (draft.total_count || 0) + 1;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
updatePricingOverride: builder.mutation<
|
|
{ message: string; pricing_override: PricingOverride },
|
|
{ id: string; data: UpdatePricingOverrideRequest }
|
|
>({
|
|
query: ({ id, data }) => ({
|
|
url: `/governance/pricing-overrides/${id}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ id }, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const updated = data.pricing_override;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getPricingOverrides" || entry?.status !== "fulfilled") continue;
|
|
const args: PricingOverrideQueryArgs = entry.originalArgs ?? {};
|
|
const matchesQuery =
|
|
(!args.scopeKind || args.scopeKind === updated.scope_kind) &&
|
|
(!args.virtualKeyID || args.virtualKeyID === updated.virtual_key_id) &&
|
|
(!args.providerID || args.providerID === updated.provider_id) &&
|
|
(!args.providerKeyID || args.providerKeyID === updated.provider_key_id);
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getPricingOverrides", entry.originalArgs, (draft) => {
|
|
if (!draft.pricing_overrides) return;
|
|
const index = draft.pricing_overrides.findIndex((o) => o.id === id);
|
|
if (index === -1) return;
|
|
if (matchesQuery) {
|
|
draft.pricing_overrides[index] = updated;
|
|
} else {
|
|
// Override no longer belongs in this filtered list
|
|
draft.pricing_overrides.splice(index, 1);
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
draft.total_count = Math.max(0, (draft.total_count || 0) - 1);
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deletePricingOverride: builder.mutation<{ message: string }, string>({
|
|
query: (id) => ({
|
|
url: `/governance/pricing-overrides/${id}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(id, { dispatch, getState, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
const queries = (getState() as any).api.queries;
|
|
for (const entry of Object.values(queries) as any[]) {
|
|
if (entry?.endpointName !== "getPricingOverrides" || entry?.status !== "fulfilled") continue;
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getPricingOverrides", entry.originalArgs, (draft) => {
|
|
if (!draft.pricing_overrides) return;
|
|
const before = draft.pricing_overrides.length;
|
|
draft.pricing_overrides = draft.pricing_overrides.filter((o) => o.id !== id);
|
|
const removed = before - draft.pricing_overrides.length;
|
|
if (removed > 0) {
|
|
draft.count = Math.max(0, (draft.count || 0) - removed);
|
|
draft.total_count = Math.max(0, (draft.total_count || 0) - removed);
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
// Provider Governance
|
|
getProviderGovernance: builder.query<GetProviderGovernanceResponse, { fromMemory?: boolean } | void>({
|
|
query: (params) => ({
|
|
url: "/governance/providers",
|
|
params: { from_memory: params?.fromMemory ?? false },
|
|
}),
|
|
providesTags: ["ProviderGovernance"],
|
|
}),
|
|
|
|
updateProviderGovernance: builder.mutation<
|
|
{ message: string; provider: ProviderGovernance },
|
|
{ provider: string; data: UpdateProviderGovernanceRequest }
|
|
>({
|
|
query: ({ provider, data }) => ({
|
|
url: `/governance/providers/${encodeURIComponent(provider)}`,
|
|
method: "PUT",
|
|
body: data,
|
|
}),
|
|
async onQueryStarted({ provider }, { dispatch, queryFulfilled }) {
|
|
try {
|
|
const { data } = await queryFulfilled;
|
|
const variants = [undefined, { fromMemory: true }] as const;
|
|
for (const variant of variants) {
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getProviderGovernance", variant, (draft) => {
|
|
if (!draft.providers) draft.providers = [];
|
|
const index = draft.providers.findIndex((p) => p.provider === provider);
|
|
if (index !== -1) {
|
|
draft.providers[index] = data.provider;
|
|
} else {
|
|
// New provider governance - add to list
|
|
draft.providers.push(data.provider);
|
|
draft.count = (draft.count || 0) + 1;
|
|
}
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
|
|
deleteProviderGovernance: builder.mutation<{ message: string }, string>({
|
|
query: (provider) => ({
|
|
url: `/governance/providers/${encodeURIComponent(provider)}`,
|
|
method: "DELETE",
|
|
}),
|
|
async onQueryStarted(provider, { dispatch, queryFulfilled }) {
|
|
try {
|
|
await queryFulfilled;
|
|
const variants = [undefined, { fromMemory: true }] as const;
|
|
for (const variant of variants) {
|
|
dispatch(
|
|
governanceApi.util.updateQueryData("getProviderGovernance", variant, (draft) => {
|
|
if (!draft.providers) return;
|
|
draft.providers = draft.providers.filter((p) => p.provider !== provider);
|
|
draft.count = Math.max(0, (draft.count || 0) - 1);
|
|
}),
|
|
);
|
|
}
|
|
} catch {
|
|
// Mutation failed
|
|
}
|
|
},
|
|
}),
|
|
}),
|
|
});
|
|
|
|
export const {
|
|
// Virtual Keys
|
|
useGetVirtualKeysQuery,
|
|
useGetVirtualKeyQuery,
|
|
useCreateVirtualKeyMutation,
|
|
useUpdateVirtualKeyMutation,
|
|
useDeleteVirtualKeyMutation,
|
|
|
|
// Teams
|
|
useGetTeamsQuery,
|
|
useGetTeamQuery,
|
|
useCreateTeamMutation,
|
|
useUpdateTeamMutation,
|
|
useDeleteTeamMutation,
|
|
|
|
// Customers
|
|
useGetCustomersQuery,
|
|
useGetCustomerQuery,
|
|
useCreateCustomerMutation,
|
|
useUpdateCustomerMutation,
|
|
useDeleteCustomerMutation,
|
|
|
|
// Budgets
|
|
useGetBudgetsQuery,
|
|
useGetBudgetQuery,
|
|
useUpdateBudgetMutation,
|
|
useDeleteBudgetMutation,
|
|
|
|
// Rate Limits
|
|
useGetRateLimitsQuery,
|
|
useGetRateLimitQuery,
|
|
useUpdateRateLimitMutation,
|
|
useDeleteRateLimitMutation,
|
|
|
|
// Usage Stats
|
|
useGetUsageStatsQuery,
|
|
useResetUsageMutation,
|
|
|
|
// Debug
|
|
useGetGovernanceDebugStatsQuery,
|
|
useGetGovernanceHealthQuery,
|
|
|
|
// Model Configs
|
|
useGetModelConfigsQuery,
|
|
useGetModelConfigQuery,
|
|
useCreateModelConfigMutation,
|
|
useUpdateModelConfigMutation,
|
|
useDeleteModelConfigMutation,
|
|
useGetPricingOverridesQuery,
|
|
useCreatePricingOverrideMutation,
|
|
useUpdatePricingOverrideMutation,
|
|
useDeletePricingOverrideMutation,
|
|
|
|
// Provider Governance
|
|
useGetProviderGovernanceQuery,
|
|
useUpdateProviderGovernanceMutation,
|
|
useDeleteProviderGovernanceMutation,
|
|
|
|
// Lazy queries
|
|
useLazyGetVirtualKeysQuery,
|
|
useLazyGetVirtualKeyQuery,
|
|
useLazyGetTeamsQuery,
|
|
useLazyGetTeamQuery,
|
|
useLazyGetCustomersQuery,
|
|
useLazyGetCustomerQuery,
|
|
useLazyGetBudgetsQuery,
|
|
useLazyGetBudgetQuery,
|
|
useLazyGetRateLimitsQuery,
|
|
useLazyGetRateLimitQuery,
|
|
useLazyGetUsageStatsQuery,
|
|
useLazyGetGovernanceDebugStatsQuery,
|
|
useLazyGetGovernanceHealthQuery,
|
|
useLazyGetModelConfigsQuery,
|
|
useLazyGetProviderGovernanceQuery,
|
|
} = governanceApi; |