diff --git a/apps/server/src/api/v2/metric_files/download-metric-file.ts b/apps/server/src/api/v2/metric_files/download-metric-file.ts index d4fbe998b..183c54705 100644 --- a/apps/server/src/api/v2/metric_files/download-metric-file.ts +++ b/apps/server/src/api/v2/metric_files/download-metric-file.ts @@ -43,7 +43,7 @@ export async function downloadMetricFileHandler( const timeout = 120000; // 2 minutes const pollInterval = 2000; // Poll every 2 seconds - let run; + let run: Awaited>; while (true) { run = await runs.retrieve(handle.id); diff --git a/apps/server/src/api/v2/metric_files/index.ts b/apps/server/src/api/v2/metric_files/index.ts index eef9539be..275c70bcb 100644 --- a/apps/server/src/api/v2/metric_files/index.ts +++ b/apps/server/src/api/v2/metric_files/index.ts @@ -1,6 +1,7 @@ import { MetricDownloadParamsSchema } from '@buster/server-shared/metrics'; import { zValidator } from '@hono/zod-validator'; import { Hono } from 'hono'; +import { HTTPException } from 'hono/http-exception'; import { requireAuth } from '../../../middleware/auth'; import '../../../types/hono.types'; import { downloadMetricFileHandler } from './download-metric-file'; @@ -28,8 +29,8 @@ const app = new Hono() console.error('Metric files API error:', err); // Let HTTPException responses pass through - if (err instanceof Error && 'getResponse' in err) { - return (err as any).getResponse(); + if (err instanceof HTTPException) { + return err.getResponse(); } // Default error response diff --git a/apps/trigger/src/tasks/export-metric-data/cleanup-export-file.ts b/apps/trigger/src/tasks/export-metric-data/cleanup-export-file.ts index f035c5205..8b482bd3a 100644 --- a/apps/trigger/src/tasks/export-metric-data/cleanup-export-file.ts +++ b/apps/trigger/src/tasks/export-metric-data/cleanup-export-file.ts @@ -2,13 +2,24 @@ import { DeleteObjectCommand, S3Client } from '@aws-sdk/client-s3'; import { logger, task } from '@trigger.dev/sdk'; import { CleanupExportFileInputSchema } from './interfaces'; +// Validate required environment variables +if (!process.env.R2_ACCOUNT_ID) { + throw new Error('R2_ACCOUNT_ID environment variable is missing'); +} +if (!process.env.R2_ACCESS_KEY_ID) { + throw new Error('R2_ACCESS_KEY_ID environment variable is missing'); +} +if (!process.env.R2_SECRET_ACCESS_KEY) { + throw new Error('R2_SECRET_ACCESS_KEY environment variable is missing'); +} + // Initialize R2 client const r2Client = new S3Client({ region: 'auto', endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { - accessKeyId: process.env.R2_ACCESS_KEY_ID!, - secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!, + accessKeyId: process.env.R2_ACCESS_KEY_ID, + secretAccessKey: process.env.R2_SECRET_ACCESS_KEY, }, }); diff --git a/apps/trigger/src/tasks/export-metric-data/export-metric-data.ts b/apps/trigger/src/tasks/export-metric-data/export-metric-data.ts index 70ff7edbd..d5987eb92 100644 --- a/apps/trigger/src/tasks/export-metric-data/export-metric-data.ts +++ b/apps/trigger/src/tasks/export-metric-data/export-metric-data.ts @@ -12,13 +12,24 @@ import { type ExportMetricDataOutput, } from './interfaces'; +// Validate required environment variables +if (!process.env.R2_ACCOUNT_ID) { + throw new Error('R2_ACCOUNT_ID environment variable is missing'); +} +if (!process.env.R2_ACCESS_KEY_ID) { + throw new Error('R2_ACCESS_KEY_ID environment variable is missing'); +} +if (!process.env.R2_SECRET_ACCESS_KEY) { + throw new Error('R2_SECRET_ACCESS_KEY environment variable is missing'); +} + // Initialize R2 client (S3-compatible) const r2Client = new S3Client({ region: 'auto', endpoint: `https://${process.env.R2_ACCOUNT_ID}.r2.cloudflarestorage.com`, credentials: { - accessKeyId: process.env.R2_ACCESS_KEY_ID!, - secretAccessKey: process.env.R2_SECRET_ACCESS_KEY!, + accessKeyId: process.env.R2_ACCESS_KEY_ID, + secretAccessKey: process.env.R2_SECRET_ACCESS_KEY, }, }); @@ -120,11 +131,14 @@ export const exportMetricData: ReturnType< logger.log('Executing metric query', { sql: `${metric.sql?.substring(0, 100)}...` }); const adapter = await createAdapter(credentials); - let queryResult; + let queryResult: Awaited> | undefined; try { + if (!metric.sql) { + throw new Error('Metric SQL is missing'); + } queryResult = await adapter.query( - metric.sql!, + metric.sql, [], // No parameters for metric queries MAX_ROWS, 60000 // 60 second query timeout diff --git a/apps/web/src/components/ui/streaming/AppMarkdownStreaming/useStreamTokenArray.stories.tsx b/apps/web/src/components/ui/streaming/AppMarkdownStreaming/useStreamTokenArray.stories.tsx index 0f19b574f..85a6e3bc4 100644 --- a/apps/web/src/components/ui/streaming/AppMarkdownStreaming/useStreamTokenArray.stories.tsx +++ b/apps/web/src/components/ui/streaming/AppMarkdownStreaming/useStreamTokenArray.stories.tsx @@ -54,7 +54,7 @@ const StreamTokenArrayDemo = ({ }, [tokens, autoStream, streamDelay]); const { throttledTokens, throttledContent, isDone, flushNow, reset } = useStreamTokenArray({ - tokens: (autoStream ? currentTokens : tokens).map(t => ({ token: t, delayMs: 0 })), + tokens: (autoStream ? currentTokens : tokens).map((t) => ({ token: t, delayMs: 0 })), isStreamFinished: autoStream ? finished : isStreamFinished, ...hookProps }); diff --git a/packages/database/src/queries/metrics/get-metric-for-export.ts b/packages/database/src/queries/metrics/get-metric-for-export.ts index 3d28b0d5e..36ac03874 100644 --- a/packages/database/src/queries/metrics/get-metric-for-export.ts +++ b/packages/database/src/queries/metrics/get-metric-for-export.ts @@ -12,7 +12,7 @@ export type GetMetricForExportInput = z.infer; // JSONB content containing SQL and other metadata dataSourceId: string; organizationId: string; secretId: string; @@ -58,13 +58,18 @@ export async function getMetricForExport(input: GetMetricForExportInput): Promis if (typeof result.content === 'object' && result.content !== null) { // Check common locations for SQL in metric content - const content = result.content as Record; + const content = result.content as Record; sql = - content.sql || - content.query || - content.sqlQuery || - content.definition?.sql || - content.definition?.query; + (typeof content.sql === 'string' ? content.sql : undefined) || + (typeof content.query === 'string' ? content.query : undefined) || + (typeof content.sqlQuery === 'string' ? content.sqlQuery : undefined) || + (typeof content.definition === 'object' && content.definition !== null + ? typeof (content.definition as Record).sql === 'string' + ? ((content.definition as Record).sql as string) + : typeof (content.definition as Record).query === 'string' + ? ((content.definition as Record).query as string) + : undefined + : undefined); } if (!sql) { @@ -74,7 +79,7 @@ export async function getMetricForExport(input: GetMetricForExportInput): Promis return { id: result.id, name: result.name, - content: result.content, + content: result.content as Record, dataSourceId: result.dataSourceId, organizationId: result.organizationId, secretId: result.secretId,