/** * Metabase API utility * * Handles authentication and requests to Metabase API */ const config = useRuntimeConfig() const METABASE_URL = config.metabaseUrl || 'http://metabase:3000' const METABASE_EMAIL = config.metabaseEmail || 'claudeCode0@nucleoriofrio.com' const METABASE_PASSWORD = config.metabasePassword || 'vK^NyZdZDH#p' let sessionToken: string | null = null let tokenExpiry: number = 0 /** * Get a valid Metabase session token * Reuses existing token if still valid, otherwise requests a new one */ export async function getMetabaseToken(): Promise { // Check if we have a valid token if (sessionToken && Date.now() < tokenExpiry) { return sessionToken } // Request a new token try { const response = await $fetch<{ id: string }>(`${METABASE_URL}/api/session`, { method: 'POST', body: { username: METABASE_EMAIL, password: METABASE_PASSWORD } }) sessionToken = response.id // Tokens expire after 14 days by default, but we'll refresh after 13 days to be safe tokenExpiry = Date.now() + (13 * 24 * 60 * 60 * 1000) console.log('[Metabase] New session token obtained') return sessionToken } catch (error) { console.error('[Metabase] Failed to obtain session token:', error) throw createError({ statusCode: 500, statusMessage: 'Failed to authenticate with Metabase' }) } } /** * Make an authenticated request to Metabase API */ export async function metabaseFetch( endpoint: string, options: RequestInit = {} ): Promise { const token = await getMetabaseToken() try { const response = await $fetch(`${METABASE_URL}${endpoint}`, { ...options, headers: { ...options.headers, 'X-Metabase-Session': token, 'Content-Type': 'application/json' } }) return response } catch (error: any) { console.error(`[Metabase] Request failed for ${endpoint}:`, error) // If token is invalid, clear it and retry once if (error.statusCode === 401) { console.log('[Metabase] Token invalid, clearing and retrying...') sessionToken = null tokenExpiry = 0 // Retry once with fresh token const newToken = await getMetabaseToken() return await $fetch(`${METABASE_URL}${endpoint}`, { ...options, headers: { ...options.headers, 'X-Metabase-Session': newToken, 'Content-Type': 'application/json' } }) } throw createError({ statusCode: error.statusCode || 500, statusMessage: error.message || 'Metabase request failed' }) } } /** * Get database metadata */ export async function getMetabaseDatabases() { return metabaseFetch('/api/database') } /** * Get tables from a specific database */ export async function getMetabaseTables(databaseId: number) { return metabaseFetch(`/api/database/${databaseId}/metadata`) } /** * Execute a query against a table */ export async function queryMetabaseTable(databaseId: number, tableId: number, query: any = {}) { return metabaseFetch('/api/dataset', { method: 'POST', body: { database: databaseId, type: 'query', query: { 'source-table': tableId, ...query } } }) }