import apiClient from "./apiClient"; export type ClientStatus = "active" | "inactive"; export type ClientType = "private" | "pkce"; export type ClientSummary = { id: string; name: string; type: ClientType; status: ClientStatus; createdAt?: string; clientSecret?: string; tokenEndpointAuthMethod?: string; jwksUri?: string; backchannelLogoutUri?: string; backchannelLogoutSessionRequired?: boolean; redirectUris: string[]; scopes: string[]; metadata?: Record; }; export type ClientListResponse = { items: ClientSummary[]; limit: number; offset: number; }; export type TenantSummary = { id: string; type: string; parentId?: string | null; name: string; slug: string; description: string; status: string; domains?: string[]; config?: Record; memberCount: number; createdAt: string; updatedAt: string; }; export type TenantListResponse = { items: TenantSummary[]; limit: number; offset: number; total: number; }; export type DevStats = { total_clients: number; active_sessions: number; auth_failures_24h: number; }; export type RPUsageDailyMetric = { date: string; tenantId: string; tenantType: string; tenantName?: string; clientId: string; clientName: string; loginRequests: number; otherRequests: number; uniqueSubjects: number; }; export type RPUsagePeriod = "day" | "week" | "month"; export type RPUsageDailyResponse = { items: RPUsageDailyMetric[]; days: number; period: RPUsagePeriod; tenantId?: string; }; export type DevAuditLog = { event_id: string; timestamp: string; user_id: string; event_type: string; status: string; ip_address: string; user_agent: string; device_id?: string; details?: string; }; export type DevAuditLogListResponse = { items: DevAuditLog[]; limit: number; cursor?: string; next_cursor?: string; }; export type ClientEndpoints = { discovery: string; issuer: string; authorization: string; token: string; userinfo: string; }; export type ClientDetailResponse = { client: ClientSummary & { clientSecret?: string; metadata?: Record; }; endpoints: ClientEndpoints; headlessJwksCache?: { clientId: string; jwksUri: string; cachedAt: string; expiresAt: string; lastCheckedAt?: string; lastSuccessfulVerificationAt?: string; lastRefreshStatus?: "success" | "failure" | "pending"; lastError?: string; consecutiveFailures?: number; cachedKids?: string[]; etag?: string; lastModified?: string; parsedKeys?: Array<{ kid?: string; kty?: string; use?: string; alg?: string; n?: string; }>; }; }; export type ClientUpsertRequest = { id?: string; name?: string; type?: ClientType; status?: ClientStatus; redirectUris?: string[]; scopes?: string[]; grantTypes?: string[]; responseTypes?: string[]; tokenEndpointAuthMethod?: string; jwksUri?: string; backchannelLogoutUri?: string; backchannelLogoutSessionRequired?: boolean; metadata?: Record; }; export type ClientRelation = { relation: string; subject: string; subjectType: string; subjectId: string; userName?: string; userEmail?: string; userLoginId?: string; }; export type ClientRelationListResponse = { items: ClientRelation[]; }; export type ClientRelationUpsertRequest = { relation: string; subject?: string; userId?: string; }; export type DevAssignableUser = { id: string; name: string; email: string; loginId?: string; }; export type DevAssignableUserListResponse = { items: DevAssignableUser[]; }; export type DevUserSummary = { id: string; email: string; loginId?: string; name: string; phone?: string; role: string; status: string; tenantSlug?: string; companyCode?: string; tenant?: TenantSummary; joinedTenants?: TenantSummary[]; metadata?: Record; department?: string; grade?: string; position?: string; jobTitle?: string; createdAt: string; updatedAt: string; }; export type ConsentSummary = { subject: string; userName?: string; clientId: string; clientName?: string; grantedScopes: string[]; authenticatedAt?: string; createdAt: string; deletedAt?: string; status: "active" | "revoked"; tenantId?: string; tenantName?: string; rpMetadata?: Record; }; export type ConsentListResponse = { items: ConsentSummary[]; }; export type RPUserMetadataResponse = { clientId: string; userId: string; metadata: Record; }; // --- Federation / IdP Config Types --- export type ProviderType = "oidc" | "saml"; export type IdpConfig = { id: string; client_id: string; // Changed from tenant_id provider_type: ProviderType; display_name: string; status: "active" | "inactive"; issuer_url?: string; // OIDC specific fields oidc_client_id?: string; oidc_client_secret?: string; scopes?: string; // SAML specific fields metadata_url?: string; metadata_xml?: string; entity_id?: string; acs_url?: string; createdAt: string; updatedAt: string; }; export type IdpConfigCreateRequest = Omit< IdpConfig, "id" | "createdAt" | "updatedAt" >; export type IdpConfigUpdateRequest = Partial; // --- End Federation Types --- export async function fetchClients() { const { data } = await apiClient.get("/dev/clients"); return data; } export async function fetchDevStats() { const { data } = await apiClient.get("/dev/stats"); return data; } export async function fetchDevRPUsageDaily({ days = 14, period = "day", }: { days?: number; period?: RPUsagePeriod; } = {}) { const { data } = await apiClient.get( "/dev/rp-usage/daily", { params: { days, period }, }, ); return data; } export async function fetchTenants( limit = 1000, offset = 0, parentId?: string, ) { const { data } = await apiClient.get("/tenants", { params: { limit, offset, parentId }, }); return data; } export async function fetchClient(clientId: string) { const { data } = await apiClient.get( `/dev/clients/${clientId}`, ); return data; } export async function fetchClientRelations(clientId: string) { const { data } = await apiClient.get( `/dev/clients/${clientId}/relations`, ); return data; } export async function fetchRPUserMetadata(clientId: string, userId: string) { const { data } = await apiClient.get( `/dev/clients/${clientId}/users/${userId}/metadata`, ); return data; } export async function updateRPUserMetadata( clientId: string, userId: string, metadata: Record, ) { const { data } = await apiClient.put( `/dev/clients/${clientId}/users/${userId}/metadata`, { metadata }, ); return data; } export async function fetchDevUsers( search: string, limit = 10, clientId?: string, ) { const { data } = await apiClient.get( "/dev/users", { params: { search, limit, clientId }, }, ); return data; } export async function fetchDevUser(userId: string) { const { data } = await apiClient.get( `/admin/users/${userId}`, ); return data; } export async function addClientRelation( clientId: string, payload: ClientRelationUpsertRequest, ) { const { data } = await apiClient.post( `/dev/clients/${clientId}/relations`, payload, ); return data; } export async function removeClientRelation( clientId: string, relation: string, subject: string, ) { await apiClient.delete(`/dev/clients/${clientId}/relations`, { params: { relation, subject }, }); } export async function updateClientStatus( clientId: string, status: ClientStatus, ) { const { data } = await apiClient.patch( `/dev/clients/${clientId}/status`, { status }, ); return data; } export async function createClient(payload: ClientUpsertRequest) { const { data } = await apiClient.post( "/dev/clients", payload, ); return data; } export async function updateClient( clientId: string, payload: ClientUpsertRequest, ) { const { data } = await apiClient.put( `/dev/clients/${clientId}`, payload, ); return data; } export async function rotateClientSecret(clientId: string) { const { data } = await apiClient.post( `/dev/clients/${clientId}/secret/rotate`, ); return data; } export async function refreshHeadlessJwksCache(clientId: string) { const { data } = await apiClient.post( `/dev/clients/${clientId}/headless-jwks/refresh`, ); return data; } export async function revokeHeadlessJwksCache(clientId: string) { await apiClient.delete(`/dev/clients/${clientId}/headless-jwks/cache`); } export async function deleteClient(clientId: string) { await apiClient.delete(`/dev/clients/${clientId}`); } export async function fetchConsents( subject: string, clientId?: string, status?: string, ) { const params: Record = { subject }; if (clientId) { params.client_id = clientId; } if (status && status !== "all") { params.status = status; } const { data } = await apiClient.get("/dev/consents", { params, }); return data; } export async function revokeConsent(subject: string, clientId?: string) { const params: Record = { subject }; if (clientId) { params.client_id = clientId; } await apiClient.delete("/dev/consents", { params }); } // --- Federation / IdP Config API Calls --- export async function listIdpConfigsForClient(clientId: string) { const { data } = await apiClient.get( `/dev/clients/${clientId}/idps`, ); return data; } export async function createIdpConfigForClient( payload: IdpConfigCreateRequest, ) { const { data } = await apiClient.post( `/dev/clients/${payload.client_id}/idps`, payload, ); return data; } export async function updateIdpConfig( clientId: string, idpId: string, payload: IdpConfigUpdateRequest, ) { const { data } = await apiClient.put( `/dev/clients/${clientId}/idps/${idpId}`, payload, ); return data; } export async function deleteIdpConfig(clientId: string, idpId: string) { await apiClient.delete(`/dev/clients/${clientId}/idps/${idpId}`); } export async function fetchDevAuditLogs( limit = 50, cursor?: string, filters?: { action?: string; client_id?: string; status?: string; tenant_id?: string; }, ) { const { data } = await apiClient.get( "/dev/audit-logs", { params: { limit, cursor, action: filters?.action, client_id: filters?.client_id, status: filters?.status, tenant_id: filters?.tenant_id, }, }, ); return data; } export type MyTenantSummary = Pick & Partial; export async function fetchMyTenants() { const { data } = await apiClient.get("/dev/my-tenants"); return data; } // --- Developer Request API --- export type DeveloperRequestStatus = | "pending" | "approved" | "rejected" | "cancelled" | "none"; export type DeveloperRequest = { id: number; userId: string; tenantId: string; name: string; organization: string; email?: string; phone?: string; role?: string; reason: string; accessPages?: string[]; status: DeveloperRequestStatus; adminNotes?: string; createdAt: string; updatedAt: string; }; export type DeveloperGrant = DeveloperRequest; export type DeveloperAccessStatus = { status: DeveloperRequestStatus | "none"; approvedPages?: string[]; pendingPages?: string[]; }; export async function fetchDeveloperRequestStatus(tenantId?: string) { const { data } = await apiClient.get( "/dev/developer-request/status", { params: { tenantId }, }, ); return data; } export async function requestDeveloperAccess(payload: { name: string; organization: string; reason: string; tenantId: string; accessPages: string[]; }) { const { data } = await apiClient.post<{ status: string }>( "/dev/developer-request", payload, ); return data; } export async function fetchDeveloperRequests(status?: string) { const { data } = await apiClient.get( "/dev/developer-request/list", { params: { status }, }, ); return data; } export async function approveDeveloperRequest(id: number, adminNotes: string) { const { data } = await apiClient.post<{ status: string }>( `/dev/developer-request/${id}/approve`, { adminNotes }, ); return data; } export async function rejectDeveloperRequest(id: number, adminNotes: string) { const { data } = await apiClient.post<{ status: string }>( `/dev/developer-request/${id}/reject`, { adminNotes }, ); return data; } export async function cancelDeveloperRequestApproval( id: number, adminNotes: string, ) { const { data } = await apiClient.post<{ status: string }>( `/dev/developer-request/${id}/cancel-approval`, { adminNotes }, ); return data; } export async function fetchDeveloperGrants(tenantId?: string) { const { data } = await apiClient.get( "/dev/developer-grants", { params: { tenantId }, }, ); return data; } export async function createDeveloperGrant(payload: { userId: string; tenantId: string; reason?: string; adminNotes?: string; accessPages: string[]; }) { const { data } = await apiClient.post( "/dev/developer-grants", payload, ); return data; } export async function revokeDeveloperGrant(id: number, adminNotes: string) { const { data } = await apiClient.post<{ status: string }>( `/dev/developer-grants/${id}/revoke`, { adminNotes }, ); return data; }