All files / src/stores apiKeys.ts

83.63% Statements 46/55
69.69% Branches 23/33
100% Functions 7/7
83.33% Lines 45/54

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143                                                                    5x 46x 46x 46x 46x 46x     15x 1x     14x 14x   14x 13x 13x 13x     14x 14x 14x 1x     14x 6x     6x               6x                   6x 5x   1x   6x 6x     1x 1x 1x   1x   7x         1x       2x 1x     1x 1x       1x 1x       2x 1x 1x 1x 1x       46x                          
import { defineStore } from 'pinia'
import { ref } from 'vue'
import api from '@/services/api'
 
export interface ApiKey {
  id: string
  tenantId: string
  name: string
  keyHash: string
  permissions: string[]
  allowedEntityIds: string[]
  expiresAt?: string
  status: 'active' | 'expired' | 'revoked'
  createdBy: string
  createdAt: string
  revokedAt?: string
  revokedBy?: string
  lastUsedAt?: string
}
 
export interface CreateApiKeyRequest {
  name: string
  permissions: string[]
  allowedEntityIds: string[]
  expiresAt?: string
}
 
export interface CreateApiKeyResponse {
  apiKey: ApiKey // The API key object
  key: string // The plain key (only returned once!)
  message?: string
  warning?: string
}
 
export const useApiKeysStore = defineStore('apiKeys', () => {
  const apiKeys = ref<ApiKey[]>([])
  const loading = ref(false)
  const error = ref<string | null>(null)
  const nextToken = ref<string | null>(null)
  const hasMore = ref(false)
 
  async function fetchApiKeys(reset = true) {
    if (loading.value || (!reset && !hasMore.value)) {
      return
    }
 
    loading.value = true
    error.value = null
 
    if (reset) {
      apiKeys.value = []
      nextToken.value = null
      hasMore.value = true
    }
 
    try {
      const params: any = { limit: 30 }
      if (!reset && nextToken.value) {
        params.nextToken = nextToken.value
      }
 
      const response = await api.get('/v1/admin/api-keys', { params })
      const data = response.data
 
      // Handle different response formats
      Iif (Array.isArray(data)) {
        // Direct array response
        if (reset) {
          apiKeys.value = data
        } else {
          apiKeys.value = [...apiKeys.value, ...data]
        }
        hasMore.value = false
      } else if (Idata.apiKeys) {
        // Backend returns { apiKeys: [...], count: n }
        if (reset) {
          apiKeys.value = data.apiKeys
        } else {
          apiKeys.value = [...apiKeys.value, ...data.apiKeys]
        }
        hasMore.value = false
      } else {
        // Paginated response { items: [...], nextToken, hasMore }
        if (reset) {
          apiKeys.value = data.items
        } else {
          apiKeys.value = [...apiKeys.value, ...data.items]
        }
        nextToken.value = data.nextToken
        hasMore.value = data.hasMore
      }
    } catch (err: any) {
      error.value = err.response?.data?.error || err.message || 'Failed to fetch API keys'
      Eif (reset) {
        apiKeys.value = []
      }
      throw err
    } finally {
      loading.value = false
    }
  }
 
  async function loadMoreApiKeys() {
    await fetchApiKeys(false)
  }
 
  async function createApiKey(data: CreateApiKeyRequest): Promise<CreateApiKeyResponse> {
    const response = await api.post('/v1/admin/api-keys', data)
    Iif (!Array.isArray(apiKeys.value)) {
      apiKeys.value = []
    }
    apiKeys.value.unshift(response.data.apiKey) // Add the API key object to beginning
    return response.data
  }
 
  async function getApiKey(id: string): Promise<ApiKey> {
    const response = await api.get(`/v1/admin/api-keys/${id}`)
    return response.data
  }
 
  async function revokeApiKey(id: string) {
    await api.delete(`/v1/admin/api-keys/${id}`)
    const index = apiKeys.value.findIndex((k) => k.id === id)
    Eif (index !== -1 && apiKeys.value[index]) {
      apiKeys.value[index].status = 'revoked'
      apiKeys.value[index].revokedAt = new Date().toISOString()
    }
  }
 
  return {
    apiKeys,
    loading,
    error,
    nextToken,
    hasMore,
    fetchApiKeys,
    loadMoreApiKeys,
    createApiKey,
    getApiKey,
    revokeApiKey
  }
})