test: add unit tests for @lobechat/prompts (#8967)

* add test and refactor

* update

* move

* fix test

* improve config

* refactor utils server import

* move

* refactor @/utils/server to @lobechat/utils/server

* improve config

* fix tests
This commit is contained in:
Arvin Xu
2025-08-28 20:44:28 +08:00
committed by GitHub
parent d847e44ef7
commit f900f7ce4e
43 changed files with 588 additions and 46 deletions
+1
View File
@@ -8,6 +8,7 @@
- [ ] 💄 style
- [ ] 👷 build
- [ ] ⚡️ perf
- [ ] ✅ test
- [ ] 📝 docs
- [ ] 🔨 chore
-1
View File
@@ -1,5 +1,4 @@
export * from './image';
export * from './locale';
export * from './message';
export * from './settings';
export * from './version';
+3 -2
View File
@@ -1,5 +1,6 @@
import { BRANDING_LOGO_URL } from '@/const/branding';
import { MetaData } from '@/types/meta';
import { MetaData } from '@lobechat/types';
import { BRANDING_LOGO_URL } from './branding';
export const DEFAULT_AVATAR = '🤖';
export const DEFAULT_USER_AVATAR = '😀';
+9 -4
View File
@@ -1,7 +1,12 @@
import { DEFAULT_AGENT_META } from '@/const/meta';
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from '@/const/settings/llm';
import { LobeAgentChatConfig, LobeAgentConfig, LobeAgentTTSConfig } from '@/types/agent';
import { UserDefaultAgent } from '@/types/user/settings';
import {
LobeAgentChatConfig,
LobeAgentConfig,
LobeAgentTTSConfig,
UserDefaultAgent,
} from '@lobechat/types';
import { DEFAULT_AGENT_META } from '../meta';
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from './llm';
export const DEFAUTT_AGENT_TTS_CONFIG: LobeAgentTTSConfig = {
showAllLocaleVoice: false,
@@ -6,9 +6,6 @@ import {
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from './llm';
export const DEFAULT_REWRITE_QUERY =
'Given the following conversation and a follow-up question, rephrase the follow up question to be a standalone question, in its original language. Keep as much details as possible from previous messages. Keep entity names and all.';
export const DEFAULT_SYSTEM_AGENT_ITEM: SystemAgentItem = {
model: DEFAULT_MODEL,
provider: DEFAULT_PROVIDER,
+3 -7
View File
@@ -2,13 +2,9 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
// coverage: {
// all: false,
// provider: 'v8',
// reporter: ['text', 'json', 'lcov', 'text-summary'],
// reportsDirectory: './coverage/app',
// },
coverage: {
reporter: ['text', 'json', 'lcov', 'text-summary'],
},
environment: 'happy-dom',
// setupFiles: join(__dirname, './test/setup.ts'),
},
});
+3
View File
@@ -13,6 +13,9 @@ export default defineConfig({
'@': resolve(__dirname, '../../src'),
/* eslint-enable */
},
coverage: {
reporter: ['text', 'json', 'lcov', 'text-summary'],
},
environment: 'happy-dom',
},
});
-1
View File
@@ -8,7 +8,6 @@
"test:coverage": "vitest --coverage"
},
"dependencies": {
"@lobechat/const": "workspace:*",
"@lobechat/types": "workspace:*"
}
}
@@ -0,0 +1,52 @@
import { describe, expect, it, vi } from 'vitest';
import { chainAbstractChunkText } from '../abstractChunk';
describe('chainAbstractChunkText', () => {
it('should generate correct chat payload for chunk text', () => {
const testText = 'This is a sample chunk of text that needs to be summarized.';
const result = chainAbstractChunkText(testText);
expect(result).toEqual({
messages: [
{
content:
'你是一名擅长从 chunk 中提取摘要的助理,你需要将用户的会话总结为 1~2 句话的摘要,输出成 chunk 所使用的语种',
role: 'system',
},
{
content: `chunk: ${testText}`,
role: 'user',
},
],
});
});
it('should handle empty text', () => {
const result = chainAbstractChunkText('');
expect(result.messages).toHaveLength(2);
expect(result.messages![1].content).toBe('chunk: ');
});
it('should handle text with special characters', () => {
const testText = 'Text with special chars: @#$%^&*()';
const result = chainAbstractChunkText(testText);
expect(result.messages![1].content).toBe(`chunk: ${testText}`);
});
it('should always use system role for first message', () => {
const result = chainAbstractChunkText('test');
expect(result.messages![0].role).toBe('system');
});
it('should always use user role for second message', () => {
const result = chainAbstractChunkText('test');
expect(result.messages![1].role).toBe('user');
});
});
@@ -0,0 +1,100 @@
import { describe, expect, it } from 'vitest';
import { chainAnswerWithContext } from '../answerWithContext';
describe('chainAnswerWithContext', () => {
it('should generate correct chat payload with context and knowledge', () => {
const testParams = {
context: ['Context passage 1', 'Context passage 2'],
knowledge: ['AI', 'Machine Learning'],
question: 'What is artificial intelligence?',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages).toHaveLength(1);
expect(result.messages![0].role).toBe('user');
expect(result.messages![0].content).toContain('AI/Machine Learning');
expect(result.messages![0].content).toContain('Context passage 1');
expect(result.messages![0].content).toContain('Context passage 2');
expect(result.messages![0].content).toContain('What is artificial intelligence?');
});
it('should handle single knowledge area', () => {
const testParams = {
context: ['Single context'],
knowledge: ['Technology'],
question: 'How does it work?',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages![0].content).toContain('Technology');
});
it('should handle multiple knowledge areas', () => {
const testParams = {
context: ['Context'],
knowledge: ['AI', 'ML', 'NLP', 'Computer Vision'],
question: 'Tell me about these fields',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages![0].content).toContain('AI/ML/NLP/Computer Vision');
});
it('should handle empty context array', () => {
const testParams = {
context: [],
knowledge: ['AI'],
question: 'What is AI?',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages![0].content).toContain('<Context>');
expect(result.messages![0].content).toContain('</Context>');
});
it('should include proper context formatting', () => {
const testParams = {
context: ['First passage', 'Second passage'],
knowledge: ['Test'],
question: 'Test question',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages![0].content).toContain(
'<Context>\nFirst passage\nSecond passage\n</Context>',
);
});
it('should include proper instructions about using passages', () => {
const testParams = {
context: ['Context'],
knowledge: ['Knowledge'],
question: 'Question',
};
const result = chainAnswerWithContext(testParams);
const content = result.messages![0].content;
expect(content).toContain('passages might not be relevant');
expect(content).toContain('please only use the passages that are relevant');
expect(content).toContain('answer using your knowledge');
});
it('should include markdown formatting instruction', () => {
const testParams = {
context: ['Context'],
knowledge: ['Knowledge'],
question: 'Question',
};
const result = chainAnswerWithContext(testParams);
expect(result.messages![0].content).toContain('follow markdown syntax');
});
});
@@ -0,0 +1,88 @@
import { describe, expect, it, vi } from 'vitest';
// Mock DEFAULT_REWRITE_QUERY
import { DEFAULT_REWRITE_QUERY, chainRewriteQuery } from '../rewriteQuery';
describe('chainRewriteQuery', () => {
it('should generate correct chat payload with default instruction', () => {
const query = 'What about the weather?';
const context = ['Previous message 1', 'Previous message 2'];
const result = chainRewriteQuery(query, context);
expect(result.messages).toHaveLength(2);
expect(result.messages![0].role).toBe('system');
expect(result.messages![1].role).toBe('user');
expect(result.messages![0].content).toContain(DEFAULT_REWRITE_QUERY);
expect(result.messages![1].content).toContain(query);
});
it('should include chat history in system message', () => {
const query = 'Follow up question';
const context = ['User: Hello', 'Assistant: Hi there'];
const result = chainRewriteQuery(query, context);
expect(result.messages![0].content).toContain('<chatHistory>');
expect(result.messages![0].content).toContain('User: Hello');
expect(result.messages![0].content).toContain('Assistant: Hi there');
expect(result.messages![0].content).toContain('</chatHistory>');
});
it('should use custom instruction when provided', () => {
const query = 'Test query';
const context = ['Context'];
const customInstruction = 'Custom rewrite instruction';
const result = chainRewriteQuery(query, context, customInstruction);
expect(result.messages![0].content).toContain(customInstruction);
expect(result.messages![0].content).not.toContain(DEFAULT_REWRITE_QUERY);
});
it('should format user message correctly', () => {
const query = 'What is the status?';
const context = ['Previous context'];
const result = chainRewriteQuery(query, context);
expect(result.messages![1].content).toBe(`Follow Up Input: ${query}, it's standalone query:`);
});
it('should handle empty context array', () => {
const query = 'Empty context query';
const context: string[] = [];
const result = chainRewriteQuery(query, context);
expect(result.messages![0].content).toContain('<chatHistory>\n\n</chatHistory>');
});
it('should handle single context item', () => {
const query = 'Single context query';
const context = ['Only one message'];
const result = chainRewriteQuery(query, context);
expect(result.messages![0].content).toContain('Only one message');
});
it('should join multiple context items with newlines', () => {
const query = 'Multi context query';
const context = ['Message 1', 'Message 2', 'Message 3'];
const result = chainRewriteQuery(query, context);
expect(result.messages![0].content).toContain('Message 1\nMessage 2\nMessage 3');
});
it('should handle special characters in query', () => {
const query = 'Query with special chars: @#$%^&*()';
const context = ['Context'];
const result = chainRewriteQuery(query, context);
expect(result.messages![1].content).toContain(query);
});
});
@@ -0,0 +1,107 @@
import { describe, expect, it } from 'vitest';
import { chainSummaryGenerationTitle } from '../summaryGenerationTitle';
describe('chainSummaryGenerationTitle', () => {
it('should generate correct chat payload for image modal', () => {
const prompts = ['A beautiful sunset', 'Mountain landscape'];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
expect(result.messages).toHaveLength(2);
expect(result.messages![0].role).toBe('system');
expect(result.messages![1].role).toBe('user');
expect(result.messages![0].content).toContain('AI image prompt');
expect(result.messages![0].content).toContain(locale);
});
it('should generate correct chat payload for video modal', () => {
const prompts = ['Dancing in the rain'];
const modal = 'video' as const;
const locale = 'en-US';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
expect(result.messages![0].content).toContain('AI video prompt');
expect(result.messages![0].content).toContain(locale);
});
it('should format single prompt correctly', () => {
const prompts = ['Single prompt'];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
expect(result.messages![1].content).toContain('1. Single prompt');
});
it('should format multiple prompts with numbering', () => {
const prompts = ['First prompt', 'Second prompt', 'Third prompt'];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
const userMessage = result.messages![1].content;
expect(userMessage).toContain('1. First prompt');
expect(userMessage).toContain('2. Second prompt');
expect(userMessage).toContain('3. Third prompt');
});
it('should include system instructions about title requirements', () => {
const prompts = ['Test prompt'];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
const systemMessage = result.messages![0].content;
expect(systemMessage).toContain('资深的 AI 艺术创作者');
expect(systemMessage).toContain('10个字以内');
expect(systemMessage).toContain('不需要包含标点符号');
});
it('should handle empty prompts array', () => {
const prompts: string[] = [];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
expect(result.messages![1].content).toContain('提示词:\n');
});
it('should handle different locales', () => {
const prompts = ['Test'];
const modal = 'image' as const;
const customLocale = 'ja-JP';
const result = chainSummaryGenerationTitle(prompts, modal, customLocale);
expect(result.messages![0].content).toContain(customLocale);
});
it('should differentiate between image and video modals in instructions', () => {
const prompts = ['Test prompt'];
const locale = 'zh-CN';
const imageResult = chainSummaryGenerationTitle(prompts, 'image', locale);
const videoResult = chainSummaryGenerationTitle(prompts, 'video', locale);
expect(imageResult.messages![0].content).toContain('AI image prompt');
expect(videoResult.messages![0].content).toContain('AI video prompt');
});
it('should format prompts with newlines between them', () => {
const prompts = ['Prompt one', 'Prompt two'];
const modal = 'image' as const;
const locale = 'zh-CN';
const result = chainSummaryGenerationTitle(prompts, modal, locale);
expect(result.messages![1].content).toContain('1. Prompt one\n2. Prompt two');
});
});
@@ -1,4 +1,3 @@
import { DEFAULT_MODEL } from '@lobechat/const';
import { ChatStreamPayload } from '@lobechat/types';
export const chainAbstractChunkText = (text: string): Partial<ChatStreamPayload> => {
@@ -14,6 +13,5 @@ export const chainAbstractChunkText = (text: string): Partial<ChatStreamPayload>
role: 'user',
},
],
model: DEFAULT_MODEL,
};
};
+3 -1
View File
@@ -1,6 +1,8 @@
import { DEFAULT_REWRITE_QUERY } from '@lobechat/const';
import { ChatStreamPayload } from '@lobechat/types';
export const DEFAULT_REWRITE_QUERY =
'Given the following conversation and a follow-up question, rephrase the follow up question to be a standalone question, in its original language. Keep as much details as possible from previous messages. Keep entity names and all.';
export const chainRewriteQuery = (
query: string,
context: string[],
+41
View File
@@ -0,0 +1,41 @@
import { describe, expect, it, vi } from 'vitest';
import * as chains from './chains';
import * as mainExports from './index';
import * as prompts from './prompts';
// Mock the problematic dependency
vi.mock('@/locales/resources', () => ({
supportLocales: ['en-US', 'zh-CN'],
}));
describe('Main Index Export', () => {
it('should export all chains', () => {
expect(mainExports).toEqual(expect.objectContaining(chains));
});
it('should export all prompts', () => {
expect(mainExports).toEqual(expect.objectContaining(prompts));
});
it('should have all expected chain exports', () => {
const chainExports = [
'chainAbstractChunkText',
'chainAnswerWithContext',
'chainLangDetect',
'chainPickEmoji',
'chainRewriteQuery',
'chainSummaryAgentName',
'chainSummaryDescription',
'chainSummaryGenerationTitle',
'chainSummaryHistory',
'chainSummaryTags',
'chainSummaryTitle',
'chainTranslate',
];
chainExports.forEach((exportName) => {
expect(mainExports).toHaveProperty(exportName);
});
});
});
@@ -0,0 +1,136 @@
import { describe, expect, it } from 'vitest';
import { BuiltinSystemRolePrompts } from './index';
describe('BuiltinSystemRolePrompts', () => {
it('should return welcome message only when only welcome is provided', () => {
const result = BuiltinSystemRolePrompts({
welcome: 'Welcome to the assistant!',
});
expect(result).toBe('Welcome to the assistant!');
});
it('should return plugins message only when only plugins is provided', () => {
const result = BuiltinSystemRolePrompts({
plugins: 'Available plugins: calculator, weather',
});
expect(result).toBe('Available plugins: calculator, weather');
});
it('should return history summary when only history is provided', () => {
const result = BuiltinSystemRolePrompts({
historySummary: 'User discussed AI topics previously',
});
expect(result).toContain('<chat_history_summary>');
expect(result).toContain(
'<docstring>Users may have lots of chat messages, here is the summary of the history:</docstring>',
);
expect(result).toContain('<summary>User discussed AI topics previously</summary>');
expect(result).toContain('</chat_history_summary>');
expect(result.trim()).toMatch(/^<chat_history_summary>[\s\S]*<\/chat_history_summary>$/);
});
it('should combine all three parts when all are provided', () => {
const result = BuiltinSystemRolePrompts({
welcome: 'Welcome!',
plugins: 'Plugins available',
historySummary: 'Previous conversation summary',
});
expect(result).toContain('Welcome!');
expect(result).toContain('Plugins available');
expect(result).toContain('<chat_history_summary>');
expect(result).toContain('Previous conversation summary');
expect(result).toContain('</chat_history_summary>');
// Should be joined with double newlines
const parts = result.split('\n\n');
expect(parts).toHaveLength(3);
});
it('should combine welcome and plugins when no history is provided', () => {
const result = BuiltinSystemRolePrompts({
welcome: 'Hello user!',
plugins: 'Available tools',
});
expect(result).toBe('Hello user!\n\nAvailable tools');
});
it('should combine welcome and history when no plugins provided', () => {
const result = BuiltinSystemRolePrompts({
welcome: 'Greetings!',
historySummary: 'Chat history here',
});
expect(result).toContain('Greetings!');
expect(result).toContain('<chat_history_summary>');
expect(result).toContain('Chat history here');
});
it('should combine plugins and history when no welcome provided', () => {
const result = BuiltinSystemRolePrompts({
plugins: 'Tool list',
historySummary: 'Summary of previous chats',
});
expect(result).toContain('Tool list');
expect(result).toContain('<chat_history_summary>');
expect(result).toContain('Summary of previous chats');
});
it('should return empty string when no parameters provided', () => {
const result = BuiltinSystemRolePrompts({});
expect(result).toBe('');
});
it('should filter out falsy values', () => {
const result = BuiltinSystemRolePrompts({
welcome: '',
plugins: 'Valid plugins',
historySummary: undefined,
});
expect(result).toBe('Valid plugins');
});
it('should handle null and undefined values gracefully', () => {
const result = BuiltinSystemRolePrompts({
welcome: undefined,
plugins: null as any,
historySummary: 'Valid history',
});
expect(result).toContain('<chat_history_summary>');
expect(result).toContain('<summary>Valid history</summary>');
expect(result).toContain('</chat_history_summary>');
});
it('should preserve whitespace in individual components', () => {
const result = BuiltinSystemRolePrompts({
welcome: 'Welcome\nwith newlines',
plugins: 'Plugins\twith tabs',
});
expect(result).toContain('Welcome\nwith newlines');
expect(result).toContain('Plugins\twith tabs');
});
it('should format history summary with proper XML structure', () => {
const historySummary = 'User asked about weather and traffic';
const result = BuiltinSystemRolePrompts({
historySummary,
});
expect(result).toContain('<chat_history_summary>');
expect(result).toContain(
'<docstring>Users may have lots of chat messages, here is the summary of the history:</docstring>',
);
expect(result).toContain('<summary>User asked about weather and traffic</summary>');
expect(result).toContain('</chat_history_summary>');
});
});
+3
View File
@@ -2,6 +2,9 @@ import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
coverage: {
reporter: ['text', 'json', 'lcov', 'text-summary'],
},
environment: 'happy-dom',
},
});
+2
View File
@@ -1,3 +1,4 @@
export * from './agent';
export * from './artifact';
export * from './chunk';
export * from './clientDB';
@@ -6,6 +7,7 @@ export * from './fetch';
export * from './knowledgeBase';
export * from './llm';
export * from './message';
export * from './meta';
export * from './user';
export * from './user/settings';
// FIXME: I think we need a refactor for the "openai" types
+5 -1
View File
@@ -2,7 +2,11 @@
"name": "@lobechat/utils",
"version": "1.0.0",
"private": true,
"main": "./src/index.ts",
"exports": {
".": "./src/index.ts",
"./server": "./src/server/index.ts",
"./client": "./src/client/index.ts"
},
"scripts": {
"test": "vitest",
"test:coverage": "vitest --coverage"
+5
View File
@@ -0,0 +1,5 @@
export * from './auth';
export * from './correctOIDCUrl';
export * from './geo';
export * from './responsive';
export * from './xor';
+3
View File
@@ -10,6 +10,9 @@ export default defineConfig({
'@': resolve(__dirname, '../../src'),
/* eslint-enable */
},
coverage: {
reporter: ['text', 'json', 'lcov', 'text-summary'],
},
environment: 'happy-dom',
setupFiles: join(__dirname, './tests/setup.ts'),
},
@@ -1,9 +1,9 @@
import { AgentRuntimeError } from '@lobechat/model-runtime';
import { ChatErrorType } from '@lobechat/types';
import { getXorPayload } from '@lobechat/utils/server';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { createErrorResponse } from '@/utils/errorResponse';
import { getXorPayload } from '@/utils/server/xor';
import { RequestHandler, checkAuth } from './index';
import { checkAuthMethod } from './utils';
@@ -20,7 +20,7 @@ vi.mock('./utils', () => ({
checkAuthMethod: vi.fn(),
}));
vi.mock('@/utils/server/xor', () => ({
vi.mock('@lobechat/utils/server', () => ({
getXorPayload: vi.fn(),
}));
+1 -1
View File
@@ -5,6 +5,7 @@ import {
ModelRuntime,
} from '@lobechat/model-runtime';
import { ChatErrorType } from '@lobechat/types';
import { getXorPayload } from '@lobechat/utils/server';
import { NextRequest } from 'next/server';
import {
@@ -17,7 +18,6 @@ import {
import { ClerkAuth } from '@/libs/clerk-auth';
import { validateOIDCJWT } from '@/libs/oidc-provider/jwt';
import { createErrorResponse } from '@/utils/errorResponse';
import { getXorPayload } from '@/utils/server/xor';
import { checkAuthMethod } from './utils';
+1 -2
View File
@@ -1,9 +1,8 @@
import { correctOIDCUrl, getUserAuth } from '@lobechat/utils/server';
import debug from 'debug';
import { NextRequest, NextResponse } from 'next/server';
import { OIDCService } from '@/server/services/oidc';
import { getUserAuth } from '@/utils/server/auth';
import { correctOIDCUrl } from '@/utils/server/correctOIDCUrl';
const log = debug('lobe-oidc:consent');
@@ -2,11 +2,11 @@
import { getAuth } from '@clerk/nextjs/server';
import { LobeRuntimeAI, ModelRuntime } from '@lobechat/model-runtime';
import { ChatErrorType } from '@lobechat/types';
import { getXorPayload } from '@lobechat/utils/server';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { checkAuthMethod } from '@/app/(backend)/middleware/auth/utils';
import { LOBE_CHAT_AUTH_HEADER, OAUTH_AUTHORIZED } from '@/const/auth';
import { getXorPayload } from '@/utils/server/xor';
import { POST } from './route';
@@ -18,7 +18,7 @@ vi.mock('@/app/(backend)/middleware/auth/utils', () => ({
checkAuthMethod: vi.fn(),
}));
vi.mock('@/utils/server/xor', () => ({
vi.mock('@lobechat/utils/server', () => ({
getXorPayload: vi.fn(),
}));
@@ -1,5 +1,6 @@
import { AgentRuntimeError } from '@lobechat/model-runtime';
import { ChatErrorType, ErrorType, TraceNameMap } from '@lobechat/types';
import { getXorPayload } from '@lobechat/utils/server';
import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk';
import { createGatewayOnEdgeRuntime } from '@lobehub/chat-plugins-gateway';
@@ -8,7 +9,6 @@ import { LOBE_CHAT_TRACE_ID } from '@/const/trace';
import { getAppConfig } from '@/envs/app';
import { TraceClient } from '@/libs/traces';
import { createErrorResponse } from '@/utils/errorResponse';
import { getXorPayload } from '@/utils/server/xor';
import { getTracePayload } from '@/utils/trace';
import { parserPluginSettings } from './settings';
@@ -1,3 +1,4 @@
import { getUserAuth } from '@lobechat/utils/server';
import { notFound } from 'next/navigation';
import { Flexbox } from 'react-layout-kit';
@@ -5,7 +6,6 @@ import FileViewer from '@/features/FileViewer';
import { createCallerFactory } from '@/libs/trpc/lambda';
import { lambdaRouter } from '@/server/routers/lambda';
import { PagePropsWithId } from '@/types/next';
import { getUserAuth } from '@/utils/server/auth';
import FileDetail from '../features/FileDetail';
import Header from './Header';
@@ -1,10 +1,10 @@
import { gerServerDeviceInfo } from '@lobechat/utils/server';
import { notFound } from 'next/navigation';
import { serverFeatureFlags } from '@/config/featureFlags';
import { metadataModule } from '@/server/metadata';
import { translation } from '@/server/translation';
import { DynamicLayoutProps } from '@/types/next';
import { gerServerDeviceInfo } from '@/utils/server/responsive';
import { RouteVariants } from '@/utils/server/routeVariants';
import Page from './index';
@@ -1,6 +1,7 @@
'use client';
import { DEFAULT_REWRITE_QUERY } from '@/const/settings';
import { DEFAULT_REWRITE_QUERY } from '@lobechat/prompts';
import { isServerMode } from '@/const/version';
import { featureFlagsSelectors, useServerConfigStore } from '@/store/serverConfig';
+1 -1
View File
@@ -164,7 +164,7 @@ class OIDCAdapter {
log('[%s] Setting userId: %s', this.name, payload.accountId);
} else {
try {
const { getUserAuth } = await import('@/utils/server/auth');
const { getUserAuth } = await import('@lobechat/utils/server');
try {
const { userId } = await getUserAuth();
if (userId) {
@@ -1,11 +1,11 @@
// @vitest-environment node
import * as utils from '@lobechat/utils/server';
import { TRPCError } from '@trpc/server';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { createCallerFactory } from '@/libs/trpc/edge';
import { AuthContext, createContextInner } from '@/libs/trpc/edge/context';
import { edgeTrpc as trpc } from '@/libs/trpc/edge/init';
import * as utils from '@/utils/server/xor';
import { jwtPayloadChecker } from './jwtPayload';
+1 -2
View File
@@ -1,7 +1,6 @@
import { getXorPayload } from '@lobechat/utils/server';
import { TRPCError } from '@trpc/server';
import { getXorPayload } from '@/utils/server/xor';
import { edgeTrpc } from '../init';
export const jwtPayloadChecker = edgeTrpc.middleware(async (opts) => {
+1 -2
View File
@@ -1,7 +1,6 @@
import { getXorPayload } from '@lobechat/utils/server';
import { TRPCError } from '@trpc/server';
import { getXorPayload } from '@/utils/server/xor';
import { trpc } from '../init';
export const keyVaults = trpc.middleware(async (opts) => {
+3 -3
View File
@@ -1,4 +1,5 @@
import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server';
import { parseDefaultThemeFromCountry } from '@lobechat/utils/server';
import debug from 'debug';
import { NextRequest, NextResponse } from 'next/server';
import { UAParser } from 'ua-parser-js';
@@ -11,11 +12,10 @@ import { LOBE_THEME_APPEARANCE } from '@/const/theme';
import { appEnv } from '@/envs/app';
import NextAuthEdge from '@/libs/next-auth/edge';
import { Locales } from '@/locales/resources';
import { parseBrowserLanguage } from '@/utils/locale';
import { parseDefaultThemeFromCountry } from '@/utils/server/geo';
import { RouteVariants } from '@/utils/server/routeVariants';
import { oidcEnv } from './envs/oidc';
import { parseBrowserLanguage } from './utils/locale';
import { RouteVariants } from './utils/server/routeVariants';
// Create debug logger instances
const logDefault = debug('middleware:default');
+1 -1
View File
@@ -9,7 +9,7 @@ import { SEARCH_SEARXNG_NOT_CONFIG } from '@/types/tool/search';
import { searchRouter } from './search';
// Mock JWT verification
vi.mock('@/utils/server/xor', () => ({
vi.mock('@lobechat/utils/server', () => ({
getXorPayload: vi.fn().mockReturnValue({ userId: '1' }),
}));
+1 -1
View File
@@ -1,7 +1,7 @@
import { LOBE_LOCALE_COOKIE } from '@lobechat/const';
import { setCookie } from '@lobechat/utils';
import { changeLanguage } from 'i18next';
import { LOBE_LOCALE_COOKIE } from '@/const/locale';
import { LocaleMode } from '@/types/locale';
export const switchLang = (locale: LocaleMode) => {
@@ -1,6 +1,7 @@
import { translation } from '@/server/translation';
import { DynamicLayoutProps } from '@/types/next';
import { RouteVariants } from '@/utils/server/routeVariants';
import { RouteVariants } from './routeVariants';
export const parsePageMetaProps = async (props: DynamicLayoutProps) => {
const { locale: hl, isMobile } = await RouteVariants.getVariantsFromProps(props);
+1 -1
View File
@@ -21,7 +21,7 @@
"@/libs/model-runtime": ["./packages/model-runtime/src/index.ts"],
"@/libs/model-runtime/*": ["./packages/model-runtime/src/*"],
"@/database/*": ["./packages/database/src/*", "./src/database/*"],
"@/const/*": ["./packages/const/src/*"],
"@/const/*": ["./packages/const/src/*", "./src/const/*"],
"@/utils/*": ["./packages/utils/src/*", "./src/utils/*"],
"@/types/*": ["./packages/types/src/*", "./src/types/*"],
"@/*": ["./src/*"],
+1
View File
@@ -13,6 +13,7 @@ export default defineConfig({
'@/database/_deprecated': resolve(__dirname, './src/database/_deprecated'),
'@/database': resolve(__dirname, './packages/database/src'),
'@/utils/client/switchLang': resolve(__dirname, './src/utils/client/switchLang'),
'@/const/locale': resolve(__dirname, './src/const/locale'),
// TODO: after refactor the errorResponse, we can remove it
'@/utils/errorResponse': resolve(__dirname, './src/utils/errorResponse'),
'@/utils': resolve(__dirname, './packages/utils/src'),