diff --git a/.vscode/buster.code-workspace b/.vscode/buster.code-workspace index 162400a94..689cebe60 100644 --- a/.vscode/buster.code-workspace +++ b/.vscode/buster.code-workspace @@ -1,23 +1,23 @@ { "folders": [ - { "path": "./apps/api" }, - { "path": "./apps/electric-server" }, - { "path": "./apps/server" }, - { "path": "./apps/trigger" }, - { "path": "./apps/web" }, - { "path": "./packages/access-controls" }, - { "path": "./packages/ai" }, - { "path": "./packages/data-source" }, - { "path": "./packages/database" }, - { "path": "./packages/rerank" }, - { "path": "./packages/server-shared" }, - { "path": "./packages/slack" }, - { "path": "./packages/stored-values" }, - { "path": "./packages/supabase" }, - { "path": "./packages/test-utils" }, - { "path": "./packages/typescript-config" }, - { "path": "./packages/vitest-config" }, - { "path": "./packages/web-tools" } + { "path": "../apps/api" }, + { "path": "../apps/electric-server" }, + { "path": "../apps/server" }, + { "path": "../apps/trigger" }, + { "path": "../apps/web" }, + { "path": "../packages/access-controls" }, + { "path": "../packages/ai" }, + { "path": "../packages/data-source" }, + { "path": "../packages/database" }, + { "path": "../packages/rerank" }, + { "path": "../packages/server-shared" }, + { "path": "../packages/slack" }, + { "path": "../packages/stored-values" }, + { "path": "../packages/supabase" }, + { "path": "../packages/test-utils" }, + { "path": "../packages/typescript-config" }, + { "path": "../packages/vitest-config" }, + { "path": "../packages/web-tools" } ], "settings": { "editor.defaultFormatter": "biomejs.biome", diff --git a/.vscode/settings.json b/.vscode/settings.json index ef4ccee52..68b25e9cf 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,6 +9,39 @@ "typescript.suggest.autoImports": true, "typescript.updateImportsOnFileMove.enabled": "always", + // CRITICAL: Enable TypeScript build mode for project references + "typescript.enablePromptUseWorkspaceTsdk": true, + "typescript.tsdk": "node_modules/typescript/lib", + "typescript.preferences.preferTypeOnlyAutoImports": true, + + // Force TypeScript to use project references + "typescript.tsserver.useSyntaxServer": "never", + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + + // MONOREPO CRITICAL: Force real-time checking + "typescript.tsserver.watchOptions": { + "watchFile": "priorityPollingInterval", + "watchDirectory": "dynamicPriorityPolling", + "fallbackPolling": "dynamicPriorityPolling", + "synchronousWatchDirectory": true, + "excludeDirectories": ["**/node_modules", "**/target", "**/.turbo"], + "excludeFiles": [] + }, + + // Enable automatic TypeScript build + "typescript.tsc.autoDetect": "on", + + // Force TypeScript to track all project references + "typescript.tsserver.includeCompletionsForModuleExports": true, + "typescript.tsserver.includePackageJsonAutoImports": "on", + // CRITICAL: Disable syntax-only mode to get full type checking + + // Increase memory for large monorepo + "typescript.tsserver.maxTsServerMemory": 16384, + + // Force restart on config changes + "typescript.tsserver.restartOnConfigChange": true, + // Ensure dist folders are NEVER excluded from file watching "files.watcherExclude": { "**/node_modules/**": true, @@ -16,6 +49,7 @@ "**/.git/subtree-cache/**": true, "**/target/**": true, "**/.turbo/**": true + // NOTE: We explicitly DO NOT exclude dist folders from watching }, // Exclude dist folders from file explorer (but keep them in watcher) @@ -47,8 +81,7 @@ "typescript.format.enable": true, "typescript.check.npmIsInstalled": false, "typescript.disableAutomaticTypeAcquisition": true, - - + // Default Biome formatting for all file types "[typescript]": { "editor.defaultFormatter": "biomejs.biome" diff --git a/apps/server/src/api/v2/currency/index.ts b/apps/server/src/api/v2/currency/index.ts index eba3c307e..b431ef09b 100644 --- a/apps/server/src/api/v2/currency/index.ts +++ b/apps/server/src/api/v2/currency/index.ts @@ -1,4 +1,4 @@ -import type { Currency } from '@buster/server-shared/currency'; +import type { Currency, CurrencyResponse } from '@buster/server-shared/currency'; import { Hono } from 'hono'; import { requireAuth } from '../../../middleware/auth'; import { CURRENCIES_MAP } from './config'; @@ -6,7 +6,7 @@ import { CURRENCIES_MAP } from './config'; const app = new Hono(); app.use('*', requireAuth).get('/', async (c) => { - return c.json(CURRENCIES_MAP); + return c.json(CURRENCIES_MAP); }); export default app; diff --git a/apps/trigger/env.d.ts b/apps/trigger/env.d.ts index 4ca1a56bf..1d27e4256 100644 --- a/apps/trigger/env.d.ts +++ b/apps/trigger/env.d.ts @@ -7,6 +7,8 @@ declare global { ENVIRONMENT: string; NODE_ENV?: 'development' | 'production' | 'test'; BUSTER_URL: string; + BUSTER_ALERT_CHANNEL_TOKEN?: string; + BUSTER_ALERT_CHANNEL_ID?: string; } } } diff --git a/apps/trigger/src/tasks/message-post-processing/helpers/slack-notifier.ts b/apps/trigger/src/tasks/message-post-processing/helpers/slack-notifier.ts index 269aaf1b2..d01d74e79 100644 --- a/apps/trigger/src/tasks/message-post-processing/helpers/slack-notifier.ts +++ b/apps/trigger/src/tasks/message-post-processing/helpers/slack-notifier.ts @@ -211,6 +211,24 @@ export async function sendSlackNotification( slackMessage ); + const busterChannelToken = process.env.BUSTER_ALERT_CHANNEL_TOKEN; + const busterChannelId = process.env.BUSTER_ALERT_CHANNEL_ID; + + //Step 6: Send Alert To Buster Channel + if (busterChannelToken && busterChannelId) { + const busterResult = await sendSlackMessage( + busterChannelToken, + busterChannelId, + slackMessage + ); + if (!busterResult.success) { + logger.warn('Failed to send alert to Buster channel', { + error: busterResult.error, + channelId: busterChannelId, + }); + } + } + if (result.success) { logger.log('Successfully sent Slack notification', { organizationId: params.organizationId, diff --git a/apps/web/src/api/buster-electric/messages/hooks.ts b/apps/web/src/api/buster-electric/messages/hooks.ts index aa8a731c6..facef37ff 100644 --- a/apps/web/src/api/buster-electric/messages/hooks.ts +++ b/apps/web/src/api/buster-electric/messages/hooks.ts @@ -4,7 +4,7 @@ import { useShape, useShapeStream } from '../instances'; import { useChatUpdate } from '@/context/Chats/useChatUpdate'; import { updateMessageShapeToIChatMessage } from './helpers'; import { useMemoizedFn } from '@/hooks'; -import { useGetChatMemoized } from '@/api/buster_rest/chats'; +import { prefetchGetListChats, useGetChatMemoized } from '@/api/buster_rest/chats'; import uniq from 'lodash/uniq'; export const useGetMessage = ({ chatId, messageId }: { chatId: string; messageId: string }) => { @@ -33,6 +33,7 @@ export const useTrackAndUpdateMessageChanges = ( ) => { const { onUpdateChatMessage, onUpdateChat } = useChatUpdate(); const getChatMemoized = useGetChatMemoized(); + const shape = useMemo( () => messageShape({ chatId: chatId || '', messageId }), [chatId, messageId] @@ -58,6 +59,10 @@ export const useTrackAndUpdateMessageChanges = ( message_ids: allMessageIds }); } + + if (iChatMessage.is_completed) { + prefetchGetListChats() + } } callback?.(iChatMessage); onUpdateChatMessage(iChatMessage); diff --git a/apps/web/src/api/buster_rest/chats/queryRequests.ts b/apps/web/src/api/buster_rest/chats/queryRequests.ts index 616d3d838..bd19988aa 100644 --- a/apps/web/src/api/buster_rest/chats/queryRequests.ts +++ b/apps/web/src/api/buster_rest/chats/queryRequests.ts @@ -38,7 +38,7 @@ export const useGetListChats = ( filters?: Omit[0], 'page_token' | 'page_size'> ) => { const filtersCompiled: Parameters[0] = useMemo( - () => ({ admin_view: false, page_token: 0, page_size: 3500, ...filters }), + () => ({ admin_view: false, page_token: 0, page_size: 5000, ...filters }), [filters] ); diff --git a/apps/web/src/api/buster_rest/chats/requestsV2.ts b/apps/web/src/api/buster_rest/chats/requestsV2.ts index 33546f28d..acb8811ae 100644 --- a/apps/web/src/api/buster_rest/chats/requestsV2.ts +++ b/apps/web/src/api/buster_rest/chats/requestsV2.ts @@ -6,5 +6,5 @@ export const createNewChat = async (props: ChatCreateRequest) => { }; export const stopChat = async ({ chatId }: { chatId: string }) => { - return mainApiV2.patch(`/chats/${chatId}`, { stop: true }).then((res) => res.data); + return mainApiV2.delete(`/chats/${chatId}/cancel`).then((res) => res.data); }; diff --git a/apps/web/src/api/query_keys/chat.ts b/apps/web/src/api/query_keys/chat.ts index 7c975394e..39c8ca982 100644 --- a/apps/web/src/api/query_keys/chat.ts +++ b/apps/web/src/api/query_keys/chat.ts @@ -29,7 +29,7 @@ const chatsGetList = ( filters?: Omit[0], 'page_token' | 'page_size'> ) => queryOptions({ - queryKey: ['chats', 'list', filters || { page_token: 0, page_size: 3500 }] as const, + queryKey: ['chats', 'list', filters || { page_token: 0, page_size: 5000, admin_view: false }] as const, staleTime: 60 * 1000, // 1 minute initialData: [], initialDataUpdatedAt: 0 diff --git a/apps/web/src/api/query_keys/currency.ts b/apps/web/src/api/query_keys/currency.ts index a9cecebd6..349e2b8fd 100644 --- a/apps/web/src/api/query_keys/currency.ts +++ b/apps/web/src/api/query_keys/currency.ts @@ -1,6 +1,7 @@ import { queryOptions } from '@tanstack/react-query'; +import { CurrencyResponse } from '@buster/server-shared/currency'; -export const getCurrencies = queryOptions<{ code: string; description: string; flag: string }[]>({ +export const getCurrencies = queryOptions({ queryKey: ['nextjs', 'list', 'currencies'], initialData: [], initialDataUpdatedAt: 0, diff --git a/apps/web/src/components/ui/inputs/InputTextAreaButton.tsx b/apps/web/src/components/ui/inputs/InputTextAreaButton.tsx index b293f417d..8fe8cb60c 100644 --- a/apps/web/src/components/ui/inputs/InputTextAreaButton.tsx +++ b/apps/web/src/components/ui/inputs/InputTextAreaButton.tsx @@ -108,29 +108,25 @@ const SubmitButton: React.FC<{ onSubmitPreflight: () => void; onStop?: () => void; }> = React.memo(({ disabled, sendIcon, loading, loadingIcon, onSubmitPreflight, onStop }) => { - const memoizedPrefix = useMemo(() => { - return ( + const prefix = ( +
-
- {sendIcon} -
-
- {loadingIcon} -
+ className={`absolute inset-0 transition-all duration-300 ease-out ${loading ? 'scale-80 opacity-0' : 'scale-100 opacity-100'}`}> + {sendIcon}
- ); - }, [loading, sendIcon, loadingIcon]); +
+ {loadingIcon} +
+
+ ); return (