import type { ApiSettings, DeltaDeletedItem } from "@govoplan/core-webui"; import { apiFetch } from "@govoplan/core-webui"; export type PermissionItem = { scope: string; label: string; description: string; category: string; level: "tenant" | "system"; system_template_id?: string | null; system_required?: boolean; }; export type AdminOverview = { active_tenant_id: string; active_tenant_name: string; tenant_count?: number | null; system_account_count?: number | null; system_group_template_count?: number | null; system_role_template_count?: number | null; user_count: number; active_user_count: number; group_count: number; role_count: number; active_api_key_count: number; capabilities: string[]; }; export type TenantAdminItem = { id: string; slug: string; name: string; description?: string | null; default_locale: string; settings: Record; allow_custom_groups?: boolean | null; allow_custom_roles?: boolean | null; allow_api_keys?: boolean | null; effective_governance: Record; is_active: boolean; counts: Record; created_at: string; updated_at: string; }; export type PrivacyRetentionPolicyFieldKey = | "store_raw_campaign_json" | "raw_campaign_json_retention_days" | "generated_eml_retention_days" | "stored_report_detail_retention_days" | "mock_mailbox_retention_days" | "audit_detail_retention_days" | "audit_detail_level"; export type PrivacyRetentionLimitPermissions = Record; export type PrivacyRetentionLimitPermissionPatch = Partial; export type PrivacyRetentionPolicy = { store_raw_campaign_json: boolean; raw_campaign_json_retention_days?: number | null; generated_eml_retention_days?: number | null; stored_report_detail_retention_days?: number | null; mock_mailbox_retention_days?: number | null; audit_detail_retention_days?: number | null; audit_detail_level: "full" | "redacted" | "minimal"; allow_lower_level_limits: PrivacyRetentionLimitPermissions; }; export type PrivacyRetentionPolicyPatch = Partial> & { allow_lower_level_limits?: PrivacyRetentionLimitPermissionPatch; }; export type MaintenanceMode = { enabled: boolean; message?: string | null; }; export type LanguagePackage = { code: string; label: string; native_label?: string | null; }; export type SystemSettingsItem = { default_locale: string; allow_tenant_custom_groups: boolean; allow_tenant_custom_roles: boolean; allow_tenant_api_keys: boolean; privacy_retention_policy: PrivacyRetentionPolicy; maintenance_mode: MaintenanceMode; available_languages: LanguagePackage[]; enabled_language_codes: string[]; settings: Record; }; export type SystemSettingsDeltaSections = Partial<{ defaults: Pick; tenant_capabilities: Pick; languages: Pick; privacy_retention_policy: SystemSettingsItem["privacy_retention_policy"]; maintenance_mode: SystemSettingsItem["maintenance_mode"]; settings: SystemSettingsItem["settings"]; }>; export type SystemSettingsUpdatePayload = { default_locale: string; allow_tenant_custom_groups: boolean; allow_tenant_custom_roles: boolean; allow_tenant_api_keys: boolean; privacy_retention_policy?: PrivacyRetentionPolicy | null; maintenance_mode?: MaintenanceMode | null; available_languages?: LanguagePackage[] | null; enabled_language_codes?: string[] | null; change_request_id?: string | null; }; export type ConfigurationChangeRequest = { id: string; key: string; label?: string; target?: Record; dry_run: boolean; requested_by: string; requested_at: string; updated_at: string; status: string; approvals: Array>; plan: Record; value_preview?: unknown; }; export type ConfigurationChangeRecord = { id: string; version: number; key: string; target?: Record; actor_user_id: string; approval_request_id?: string | null; approval_user_ids: string[]; before?: unknown; after?: unknown; rollback_value?: unknown; status: string; created_at: string; }; export type ConfigurationPackageDiagnostic = { severity: "blocker" | "warning" | "info"; code: string; message: string; module_id?: string | null; object_ref?: string | null; resolution?: string | null; }; export type ConfigurationPackageRequiredData = { key: string; label: string; data_type: string; required: boolean; secret: boolean; description?: string | null; }; export type ConfigurationPackagePlanItem = { action: "create" | "update" | "bind" | "skip" | "blocked" | "noop"; module_id: string; fragment_type: string; fragment_id?: string | null; summary?: string | null; }; export type ConfigurationPackageFragment = { module_id: string; fragment_type: string; fragment_id?: string | null; payload: Record; }; export type ConfigurationPackageRunPayload = { package: Record; tenant_id?: string | null; supplied_data?: Record; change_request_id?: string | null; }; type DeltaResponseFields = { deleted: DeltaDeletedItem[]; watermark?: string | null; has_more: boolean; full: boolean; }; function deltaSuffix(options: { since?: string | null; limit?: number } = {}): string { const params = new URLSearchParams(); if (options.since) params.set("since", options.since); if (options.limit) params.set("limit", String(options.limit)); return params.toString() ? `?${params.toString()}` : ""; } export type SystemSettingsDeltaResponse = { item?: SystemSettingsItem | null; sections: SystemSettingsDeltaSections; changed_sections: string[]; } & DeltaResponseFields; export type ConfigurationChangesDeltaResponse = { requests: ConfigurationChangeRequest[]; history: ConfigurationChangeRecord[]; } & DeltaResponseFields; export type ModuleCatalogItem = { id: string; name: string; version: string; installed: boolean; current_enabled: boolean; desired_enabled: boolean; protected: boolean; restart_required: boolean; dependencies: string[]; optional_dependencies: string[]; dependents: string[]; permissions_count: number; role_templates_count: number; route_contributed: boolean; nav_count: number; frontend_package?: string | null; migration_module_id?: string | null; migration_script_location?: string | null; runtime_toggle_supported: boolean; install_uninstall_supported: boolean; }; export type ModuleCatalogResponse = { modules: ModuleCatalogItem[]; current_enabled: string[]; desired_enabled: string[]; configured_enabled: string[]; protected_modules: string[]; restart_required: boolean; runtime_toggle_supported: boolean; install_uninstall_supported: boolean; install_plan_supported: boolean; package_mutation_supported: boolean; maintenance_mode: MaintenanceMode; notes: string[]; }; export type ModuleInstallPlanItem = { module_id: string; action: "install" | "uninstall"; python_package?: string | null; python_ref?: string | null; webui_package?: string | null; webui_ref?: string | null; destroy_data: boolean; status: "planned" | "applied" | "blocked"; notes?: string | null; }; export type ModuleInstallPreflightIssue = { severity: "blocker" | "warning" | "info"; code: string; message: string; module_id?: string | null; }; export type ModuleInstallChecklistItem = { id: string; label: string; status: "done" | "pending" | "blocked" | "warning"; detail?: string | null; }; export type ModuleInstallPreflight = { allowed: boolean; maintenance_mode: boolean; frontend_rebuild_required: boolean; restart_required: boolean; commands: string[]; rollback_commands: string[]; issues: ModuleInstallPreflightIssue[]; checklist: ModuleInstallChecklistItem[]; }; export type ModuleInstallPlanResponse = { items: ModuleInstallPlanItem[]; updated_at?: string | null; commands: string[]; maintenance_mode: MaintenanceMode; preflight?: ModuleInstallPreflight | null; notes: string[]; }; export type ModuleInstallerLockStatus = { locked: boolean; path: string; [key: string]: unknown; }; export type ModuleInstallerDaemonStatus = { running: boolean; status: string; path: string; [key: string]: unknown; }; export type ModuleInstallerRunSummary = { run_id: string; status: string; started_at?: string | null; finished_at?: string | null; request_id?: string | null; requested_by?: string | null; trace?: Record | null; rollback_status?: string | null; supervisor_status?: string | null; error?: string | null; record_path: string; commands_count: number; planned_modules: string[]; }; export type ModuleInstallerRunListResponse = { runs: ModuleInstallerRunSummary[]; lock: ModuleInstallerLockStatus; cursor?: string | null; next_cursor?: string | null; full?: boolean; }; export type ModuleInstallerRequestOptions = { build_webui: boolean; migrate_database: boolean; webui_root?: string | null; npm_bin?: string | null; database_backup_command?: string | null; database_restore_command?: string | null; database_restore_check_command?: string | null; activate_installed_modules: boolean; remove_uninstalled_modules_from_desired: boolean; restart_commands: string[]; health_urls: string[]; health_timeout_seconds: number; health_interval_seconds: number; }; export type ModuleInstallerRequestItem = { request_id: string; status: string; created_at: string; requested_by?: string | null; started_at?: string | null; finished_at?: string | null; cancelled_at?: string | null; cancelled_by?: string | null; retry_of?: string | null; trace?: Record | null; error?: string | null; record_path?: string | null; options: Record; }; export type ModuleInstallerRequestListResponse = { requests: ModuleInstallerRequestItem[]; daemon: ModuleInstallerDaemonStatus; cursor?: string | null; next_cursor?: string | null; full?: boolean; }; export type ModulePackageCatalogItem = { module_id: string; name: string; description?: string | null; version?: string | null; action: "install" | "uninstall"; python_package?: string | null; python_ref?: string | null; webui_package?: string | null; webui_ref?: string | null; license_features: string[]; license_allowed: boolean; license_enforced: boolean; license_missing_features: string[]; license_reason?: string | null; notes?: string | null; tags: string[]; }; export type ModuleLicenseDiagnostics = { configured: boolean; valid: boolean; path?: string | null; license_id?: string | null; subject?: string | null; features: string[]; valid_from?: string | null; valid_until?: string | null; signed: boolean; trusted: boolean; key_id?: string | null; enforced: boolean; allowed: boolean; required_features: string[]; missing_features: string[]; expires_in_days?: number | null; reason?: string | null; guidance: string[]; }; export type ModulePackageCatalogResponse = { modules: ModulePackageCatalogItem[]; configured: boolean; valid: boolean; path?: string | null; source?: string | null; source_type?: string | null; cache_used: boolean; cache_path?: string | null; channel?: string | null; sequence?: number | null; generated_at?: string | null; not_before?: string | null; expires_at?: string | null; signed: boolean; trusted: boolean; key_id?: string | null; license: ModuleLicenseDiagnostics; warnings: string[]; error?: string | null; }; export type GovernanceAssignment = { tenant_id: string; mode: "available" | "required"; }; export type GovernanceTemplateItem = { id: string; kind: "group" | "role"; slug: string; name: string; description?: string | null; permissions: string[]; effective_permission_count: number; is_active: boolean; assignments: GovernanceAssignment[]; created_at: string; updated_at: string; }; export function fetchAdminOverview(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/overview"); } export async function fetchPermissionCatalog(settings: ApiSettings): Promise { const response = await apiFetch<{ permissions: PermissionItem[] }>(settings, "/api/v1/admin/permissions"); return response.permissions; } export async function fetchTenants(settings: ApiSettings): Promise { const response = await apiFetch<{ tenants: TenantAdminItem[] }>(settings, "/api/v1/admin/tenants"); return response.tenants; } export function fetchSystemSettings(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/system/settings"); } export function fetchSystemSettingsDelta(settings: ApiSettings, options: { since?: string | null; limit?: number } = {}): Promise { const suffix = deltaSuffix(options); return apiFetch(settings, `/api/v1/admin/system/settings/delta${suffix}`); } export function updateSystemSettings(settings: ApiSettings, payload: SystemSettingsUpdatePayload): Promise { return apiFetch(settings, "/api/v1/admin/system/settings", { method: "PATCH", body: JSON.stringify(payload) }); } export function fetchModuleCatalog(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/system/modules"); } export function updateModuleState(settings: ApiSettings, enabledModules: string[], changeRequestId?: string | null): Promise { return apiFetch(settings, "/api/v1/admin/system/modules", { method: "PUT", body: JSON.stringify({ enabled_modules: enabledModules, change_request_id: changeRequestId ?? null }) }); } export function fetchModuleInstallPlan(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/system/modules/install-plan"); } export function fetchModuleInstallerRuns(settings: ApiSettings, options: { page_size?: number; cursor?: string | null } = {}): Promise { const params = new URLSearchParams(); if (options.page_size) params.set("page_size", String(options.page_size)); if (options.cursor) params.set("cursor", options.cursor); const suffix = params.toString() ? `?${params.toString()}` : ""; return apiFetch(settings, `/api/v1/admin/system/modules/install-runs${suffix}`); } export function fetchModuleInstallerRequests(settings: ApiSettings, options: { page_size?: number; cursor?: string | null } = {}): Promise { const params = new URLSearchParams(); if (options.page_size) params.set("page_size", String(options.page_size)); if (options.cursor) params.set("cursor", options.cursor); const suffix = params.toString() ? `?${params.toString()}` : ""; return apiFetch(settings, `/api/v1/admin/system/modules/install-requests${suffix}`); } export function createModuleInstallerRequest(settings: ApiSettings, options: ModuleInstallerRequestOptions): Promise { return apiFetch(settings, "/api/v1/admin/system/modules/install-requests", { method: "POST", body: JSON.stringify({ options }) }); } export function cancelModuleInstallerRequest(settings: ApiSettings, requestId: string): Promise { return apiFetch(settings, `/api/v1/admin/system/modules/install-requests/${requestId}/cancel`, { method: "POST" }); } export function retryModuleInstallerRequest(settings: ApiSettings, requestId: string): Promise { return apiFetch(settings, `/api/v1/admin/system/modules/install-requests/${requestId}/retry`, { method: "POST" }); } export function fetchModulePackageCatalog(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/system/modules/package-catalog"); } export function planModuleInstallFromCatalog(settings: ApiSettings, moduleId: string): Promise { return apiFetch(settings, `/api/v1/admin/system/modules/install-plan/catalog/${encodeURIComponent(moduleId)}`, { method: "POST" }); } export function planModuleUninstall(settings: ApiSettings, moduleId: string): Promise { return apiFetch(settings, `/api/v1/admin/system/modules/${encodeURIComponent(moduleId)}/uninstall-plan`, { method: "POST" }); } export function updateModuleInstallPlan(settings: ApiSettings, items: ModuleInstallPlanItem[], changeRequestId?: string | null): Promise { return apiFetch(settings, "/api/v1/admin/system/modules/install-plan", { method: "PUT", body: JSON.stringify({ items, change_request_id: changeRequestId ?? null }) }); } export function clearModuleInstallPlan(settings: ApiSettings): Promise { return apiFetch(settings, "/api/v1/admin/system/modules/install-plan", { method: "DELETE" }); } export async function fetchGovernanceTemplates(settings: ApiSettings, kind?: "group" | "role"): Promise { const suffix = kind ? `?kind=${encodeURIComponent(kind)}` : ""; const response = await apiFetch<{ templates: GovernanceTemplateItem[] }>(settings, `/api/v1/admin/system/governance-templates${suffix}`); return response.templates; } export function createGovernanceTemplate(settings: ApiSettings, payload: Omit & { change_request_id?: string | null }): Promise { return apiFetch(settings, "/api/v1/admin/system/governance-templates", { method: "POST", body: JSON.stringify(payload) }); } export function updateGovernanceTemplate(settings: ApiSettings, templateId: string, payload: Omit & { change_request_id?: string | null }): Promise { return apiFetch(settings, `/api/v1/admin/system/governance-templates/${templateId}`, { method: "PATCH", body: JSON.stringify(payload) }); } export function deleteGovernanceTemplate(settings: ApiSettings, templateId: string, changeRequestId?: string | null): Promise { const suffix = changeRequestId ? `?change_request_id=${encodeURIComponent(changeRequestId)}` : ""; return apiFetch(settings, `/api/v1/admin/system/governance-templates/${templateId}${suffix}`, { method: "DELETE" }); } export function fetchConfigurationChanges(settings: ApiSettings): Promise<{ requests: ConfigurationChangeRequest[]; history: ConfigurationChangeRecord[] }> { return apiFetch(settings, "/api/v1/admin/configuration-changes"); } export function fetchConfigurationChangesDelta(settings: ApiSettings, options: { since?: string | null; limit?: number } = {}): Promise { const suffix = deltaSuffix(options); return apiFetch(settings, `/api/v1/admin/configuration-changes/delta${suffix}`); } export async function createConfigurationChangeRequest(settings: ApiSettings, payload: { key: string; value?: unknown; dry_run?: boolean; target?: Record; reason?: string | null; }): Promise { const response = await apiFetch<{ request: ConfigurationChangeRequest }>(settings, "/api/v1/admin/configuration-change-requests", { method: "POST", body: JSON.stringify(payload) }); return response.request; } export async function approveConfigurationChangeRequest(settings: ApiSettings, requestId: string, reason?: string | null): Promise { const response = await apiFetch<{ request: ConfigurationChangeRequest }>(settings, `/api/v1/admin/configuration-change-requests/${encodeURIComponent(requestId)}/approve`, { method: "POST", body: JSON.stringify({ reason: reason ?? null }) }); return response.request; } export function fetchConfigurationPackageCatalogValidation(settings: ApiSettings): Promise<{ validation: Record }> { return apiFetch(settings, "/api/v1/admin/configuration-packages/catalog"); } export function dryRunConfigurationPackage(settings: ApiSettings, payload: ConfigurationPackageRunPayload): Promise<{ diagnostics: ConfigurationPackageDiagnostic[]; required_data: ConfigurationPackageRequiredData[]; plan: ConfigurationPackagePlanItem[]; }> { return apiFetch(settings, "/api/v1/admin/configuration-packages/dry-run", { method: "POST", body: JSON.stringify(payload) }); } export function applyConfigurationPackage(settings: ApiSettings, payload: ConfigurationPackageRunPayload): Promise<{ diagnostics: ConfigurationPackageDiagnostic[]; created_refs: Record; updated_refs: Record; }> { return apiFetch(settings, "/api/v1/admin/configuration-packages/apply", { method: "POST", body: JSON.stringify(payload) }); } export function exportConfigurationPackage(settings: ApiSettings, payload: { tenant_id?: string | null; scopes?: string[]; module_ids?: string[]; object_refs?: string[]; }): Promise<{ fragments: ConfigurationPackageFragment[]; data_requirements: ConfigurationPackageRequiredData[]; diagnostics: ConfigurationPackageDiagnostic[]; }> { return apiFetch(settings, "/api/v1/admin/configuration-packages/export", { method: "POST", body: JSON.stringify(payload) }); }