import { getToken } from '@/utils/auth' export interface DeliveryTarget { id: number name: string target_type: string awx_inventory_id: number awx_template_id: number enabled: boolean metadata?: string } export interface DeliveryMountPath { path: string available_gi: number fstype?: string } export interface CreateMySQLDeliveryPayload { business_line_id: number target_id: number namespace: string instance_name: string mysql_version: string topology: string mysql_port?: number data_disk: string target_host?: string cpu_milli: number memory_mi: number storage_gi: number cpu_cores?: number memory_gb?: number storage_gb?: number timezone?: string lower_case_table_names?: number character_set?: string collation?: string max_connections?: string | number innodb_redo_log_capacity?: string innodb_flush_log_at_trx_commit?: number sync_binlog?: number innodb_io_capacity?: number long_query_time?: number binlog_expire_logs_seconds?: number max_binlog_size?: string mysql_root_password?: string mysql_admin_password?: string } export interface DeliveryTask { id: string business_line_id: number requested_by: number component: string target_type: string target_id: number namespace: string instance_name: string target_host?: string target_host_ip?: string mysql_port?: number status: string error_message?: string created_at: string updated_at: string started_at?: string finished_at?: string } export interface TaskEvent { id: number task_id: string from_state: string to_state: string stage?: string event_status?: string message: string created_at: string } export interface DeliveryTaskSnapshot { task: DeliveryTask events: TaskEvent[] } export interface DeploymentCredential { username: string host: string password: string } export interface MySQLServiceLedgerItem { name: string datacenter: string business_tag: string instances: number healthy: number address: string status: string status_class: string version: string namespace: string } export const deliveryApi = { async listTargets(): Promise { const data = await authRequest('/auth/api/v1/delivery/targets?component=mysql') return Array.isArray(data.items) ? data.items : [] }, async listTargetMountPaths(targetId: number, host: string): Promise { const data = await authRequest(`/auth/api/v1/delivery/targets/${targetId}/hosts/${encodeURIComponent(host)}/mount-paths`) return Array.isArray(data.items) ? data.items : [] }, async createMySQL(payload: CreateMySQLDeliveryPayload): Promise { const data = await authRequest('/auth/api/v1/delivery/mysql', { method: 'POST', headers: { 'Idempotency-Key': createIdempotencyKey(payload), }, body: JSON.stringify(payload), }) return data.task }, async listTasks(params: { businessLineId?: number; component?: string; active?: boolean } = {}): Promise { const search = new URLSearchParams() if (params.businessLineId) search.set('business_line_id', String(params.businessLineId)) if (params.component) search.set('component', params.component) if (params.active) search.set('active', 'true') const query = search.toString() const data = await authRequest(`/auth/api/v1/delivery/tasks${query ? `?${query}` : ''}`) return Array.isArray(data.items) ? data.items : [] }, async listMySQLServices(businessLineId: number): Promise { const data = await authRequest(`/auth/api/v1/delivery/business-lines/${businessLineId}/mysql-services`) return Array.isArray(data.items) ? data.items : [] }, async getTask(taskId: string): Promise<{ task: DeliveryTask; events: TaskEvent[] }> { const data = await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}`) return { task: data.task, events: Array.isArray(data.events) ? data.events : [], } }, async cancel(taskId: string): Promise { await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/cancel`, { method: 'POST', }) }, streamTask(taskId: string): EventSource { const token = getToken() const search = new URLSearchParams() if (token) search.set('access_token', token) const query = search.toString() return new EventSource(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/stream${query ? `?${query}` : ''}`) }, async retryRollback(taskId: string): Promise { await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/rollback/retry`, { method: 'POST', }) }, async releaseRollback(taskId: string): Promise { await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/rollback/release`, { method: 'POST', }) }, async retryCloudDMRegistration(taskId: string): Promise { await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/clouddm/retry`, { method: 'POST', }) }, async revealCredentials(taskId: string): Promise { const data = await authRequest(`/auth/api/v1/delivery/tasks/${encodeURIComponent(taskId)}/credentials/reveal`, { method: 'POST', }) return Array.isArray(data.items) ? data.items : [] }, } function createIdempotencyKey(payload: CreateMySQLDeliveryPayload) { return [ 'mysql', payload.business_line_id, payload.target_id, payload.namespace, payload.instance_name, Date.now(), ].join(':') } async function authRequest(path: string, init: RequestInit = {}) { const token = getToken() const response = await fetch(path, { ...init, headers: { Accept: 'application/json', 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), ...init.headers, }, }) const text = await response.text() const data = parseResponseBody(text) if (!response.ok) { const message = data?.error || data?.message || text || `HTTP ${response.status}` throw new Error(message) } return data || {} } function parseResponseBody(text: string) { if (!text.trim()) { return {} } try { return JSON.parse(text) } catch { return { error: text } } }