Files
analiticaNucleo/nuxt4-app/server/utils/metabase.ts
josedario87 244b1ae7fb
All checks were successful
build-and-deploy / build (push) Successful in 43s
build-and-deploy / deploy (push) Successful in 4s
fix: move Metabase credentials to runtime config
Move hardcoded Metabase credentials to Nuxt runtime config to
allow configuration via environment variables and follow security
best practices.

Changes:
- Update server/utils/metabase.ts to use useRuntimeConfig()
- Add metabase config to nuxt.config.ts runtimeConfig
- Update .env.example with Metabase configuration template

Environment variables:
- METABASE_URL (default: https://metabase.nucleoriofrio.com)
- METABASE_EMAIL (required for authentication)
- METABASE_PASSWORD (required for authentication)
2025-10-13 17:50:21 -06:00

129 lines
3.2 KiB
TypeScript

/**
* Metabase API utility
*
* Handles authentication and requests to Metabase API
*/
const config = useRuntimeConfig()
const METABASE_URL = config.metabaseUrl || 'https://metabase.nucleoriofrio.com'
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<string> {
// 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<T = any>(
endpoint: string,
options: RequestInit = {}
): Promise<T> {
const token = await getMetabaseToken()
try {
const response = await $fetch<T>(`${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<T>(`${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
}
}
})
}