@lobehub/chat 1.123.2 โ†’ 1.123.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -2,6 +2,56 @@
2
2
 
3
3
  # Changelog
4
4
 
5
+ ### [Version 1.123.4](https://github.com/lobehub/lobe-chat/compare/v1.123.3...v1.123.4)
6
+
7
+ <sup>Released on **2025-09-05**</sup>
8
+
9
+ #### โ™ป Code Refactoring
10
+
11
+ - **misc**: Remove edge runtime.
12
+
13
+ <br/>
14
+
15
+ <details>
16
+ <summary><kbd>Improvements and Fixes</kbd></summary>
17
+
18
+ #### Code refactoring
19
+
20
+ - **misc**: Remove edge runtime, closes [#9085](https://github.com/lobehub/lobe-chat/issues/9085) ([d3544f9](https://github.com/lobehub/lobe-chat/commit/d3544f9))
21
+
22
+ </details>
23
+
24
+ <div align="right">
25
+
26
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
27
+
28
+ </div>
29
+
30
+ ### [Version 1.123.3](https://github.com/lobehub/lobe-chat/compare/v1.123.2...v1.123.3)
31
+
32
+ <sup>Released on **2025-09-05**</sup>
33
+
34
+ #### ๐Ÿ› Bug Fixes
35
+
36
+ - **misc**: Fix mobile header title to loog not ellipsis.
37
+
38
+ <br/>
39
+
40
+ <details>
41
+ <summary><kbd>Improvements and Fixes</kbd></summary>
42
+
43
+ #### What's fixed
44
+
45
+ - **misc**: Fix mobile header title to loog not ellipsis, closes [#9109](https://github.com/lobehub/lobe-chat/issues/9109) ([9b8435b](https://github.com/lobehub/lobe-chat/commit/9b8435b))
46
+
47
+ </details>
48
+
49
+ <div align="right">
50
+
51
+ [![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
52
+
53
+ </div>
54
+
5
55
  ### [Version 1.123.2](https://github.com/lobehub/lobe-chat/compare/v1.123.1...v1.123.2)
6
56
 
7
57
  <sup>Released on **2025-09-05**</sup>
package/changelog/v1.json CHANGED
@@ -1,4 +1,22 @@
1
1
  [
2
+ {
3
+ "children": {
4
+ "improvements": [
5
+ "Remove edge runtime."
6
+ ]
7
+ },
8
+ "date": "2025-09-05",
9
+ "version": "1.123.4"
10
+ },
11
+ {
12
+ "children": {
13
+ "fixes": [
14
+ "Fix mobile header title to loog not ellipsis."
15
+ ]
16
+ },
17
+ "date": "2025-09-05",
18
+ "version": "1.123.3"
19
+ },
2
20
  {
3
21
  "children": {
4
22
  "fixes": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.123.2",
3
+ "version": "1.123.4",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -11,7 +11,7 @@ import { ChatStreamPayload } from '@/types/openai/chat';
11
11
  import { createErrorResponse } from '@/utils/errorResponse';
12
12
  import { getTracePayload } from '@/utils/trace';
13
13
 
14
- export const runtime = 'edge';
14
+ export const maxDuration = 300;
15
15
 
16
16
  export const POST = checkAuth(async (req: Request, { params, jwtPayload, createRuntime }) => {
17
17
  const { provider } = await params;
@@ -6,6 +6,7 @@ import { safeParseJSON } from '@/utils/safeParseJSON';
6
6
 
7
7
  import { POST as UniverseRoute } from '../[provider]/route';
8
8
 
9
+ export const maxDuration = 300;
9
10
  // due to the Chinese region does not support accessing Google
10
11
  // we need to use proxy to access it
11
12
  // refs: https://github.com/google/generative-ai-js/issues/29#issuecomment-1866246513
@@ -31,7 +31,16 @@ const ChatHeaderTitle = memo(() => {
31
31
  <ChatHeader.Title
32
32
  desc={
33
33
  <Flexbox align={'center'} gap={4} horizontal onClick={() => toggleConfig()}>
34
- <span>{topic?.title || t('title', { ns: 'topic' })}</span>
34
+ <span
35
+ style={{
36
+ maxWidth: '60vw',
37
+ overflow: 'hidden',
38
+ textOverflow: 'ellipsis',
39
+ whiteSpace: 'nowrap',
40
+ }}
41
+ >
42
+ {topic?.title || t('title', { ns: 'topic' })}
43
+ </span>
35
44
  <ActionIcon
36
45
  active
37
46
  icon={ChevronDown}
@@ -6,7 +6,6 @@ import { getServerDBConfig } from '@/config/db';
6
6
  import { LobeNextAuthDbAdapter } from './adapter';
7
7
  import { ssoProviders } from './sso-providers';
8
8
 
9
-
10
9
  const {
11
10
  NEXT_AUTH_DEBUG,
12
11
  NEXT_AUTH_SECRET,
@@ -1,81 +1,94 @@
1
1
  import { ModelProvider } from '@lobechat/model-runtime';
2
- import { createTRPCClient, httpBatchLink } from '@trpc/client';
2
+ import { TRPCLink, createTRPCClient, httpBatchLink } from '@trpc/client';
3
3
  import { createTRPCReact } from '@trpc/react-query';
4
+ import { observable } from '@trpc/server/observable';
4
5
  import debug from 'debug';
5
6
  import superjson from 'superjson';
6
7
 
7
8
  import { isDesktop } from '@/const/version';
8
9
  import type { LambdaRouter } from '@/server/routers/lambda';
9
10
 
10
- import { ErrorResponse } from './types';
11
-
12
11
  const log = debug('lobe-image:lambda-client');
13
12
 
14
- const links = [
15
- httpBatchLink({
16
- fetch: async (input, init) => {
17
- if (isDesktop) {
18
- const { desktopRemoteRPCFetch } = await import('@/utils/electron/desktopRemoteRPCFetch');
13
+ // handle error
14
+ const errorHandlingLink: TRPCLink<LambdaRouter> = () => {
15
+ return ({ op, next }) =>
16
+ observable((observer) =>
17
+ next(op).subscribe({
18
+ complete: () => observer.complete(),
19
+ error: async (err) => {
20
+ const showError = (op.context?.showNotification as boolean) ?? true;
21
+
22
+ if (showError) {
23
+ const status = err.data?.httpStatus as number;
24
+
25
+ const { loginRequired } = await import('@/components/Error/loginRequiredNotification');
26
+ const { fetchErrorNotification } = await import(
27
+ '@/components/Error/fetchErrorNotification'
28
+ );
29
+
30
+ switch (status) {
31
+ case 401: {
32
+ loginRequired.redirect();
33
+ break;
34
+ }
35
+
36
+ default: {
37
+ fetchErrorNotification.error({ errorMessage: err.message, status });
38
+ }
39
+ }
40
+ }
19
41
 
20
- // eslint-disable-next-line no-undef
21
- const res = await desktopRemoteRPCFetch(input as string, init as RequestInit);
42
+ observer.error(err);
43
+ },
44
+ next: (value) => observer.next(value),
45
+ }),
46
+ );
47
+ };
22
48
 
23
- if (res) return res;
24
- }
49
+ // 2. httpBatchLink
50
+ const customHttpBatchLink = httpBatchLink({
51
+ fetch: async (input, init) => {
52
+ if (isDesktop) {
53
+ const { desktopRemoteRPCFetch } = await import('@/utils/electron/desktopRemoteRPCFetch');
25
54
 
26
55
  // eslint-disable-next-line no-undef
27
- const response = await fetch(input, init as RequestInit);
28
-
29
- if (response.ok) return response;
30
-
31
- const errorRes: ErrorResponse = await response.clone().json();
32
-
33
- const { loginRequired } = await import('@/components/Error/loginRequiredNotification');
34
- const { fetchErrorNotification } = await import('@/components/Error/fetchErrorNotification');
35
-
36
- errorRes.forEach((item) => {
37
- const errorData = item.error.json;
38
- const status = errorData.data.httpStatus;
56
+ const res = await desktopRemoteRPCFetch(input as string, init as RequestInit);
57
+
58
+ if (res) return res;
59
+ }
60
+
61
+ // eslint-disable-next-line no-undef
62
+ return await fetch(input, init as RequestInit);
63
+ },
64
+ headers: async () => {
65
+ // dynamic import to avoid circular dependency
66
+ const { createHeaderWithAuth } = await import('@/services/_auth');
67
+
68
+ let provider: ModelProvider = ModelProvider.OpenAI;
69
+ // for image page, we need to get the provider from the store
70
+ log('Getting provider from store for image page: %s', location.pathname);
71
+ if (location.pathname === '/image') {
72
+ const { getImageStoreState } = await import('@/store/image');
73
+ const { imageGenerationConfigSelectors } = await import(
74
+ '@/store/image/slices/generationConfig/selectors'
75
+ );
76
+ provider = imageGenerationConfigSelectors.provider(getImageStoreState()) as ModelProvider;
77
+ log('Getting provider from store for image page: %s', provider);
78
+ }
79
+
80
+ // TODO: we need to support provider select for chat page
81
+ const headers = await createHeaderWithAuth({ provider });
82
+ log('Headers: %O', headers);
83
+ return headers;
84
+ },
85
+ maxURLLength: 2083,
86
+ transformer: superjson,
87
+ url: '/trpc/lambda',
88
+ });
39
89
 
40
- switch (status) {
41
- case 401: {
42
- loginRequired.redirect();
43
- break;
44
- }
45
- default: {
46
- fetchErrorNotification.error({ errorMessage: errorData.message, status });
47
- }
48
- }
49
- });
50
-
51
- return response;
52
- },
53
- headers: async () => {
54
- // dynamic import to avoid circular dependency
55
- const { createHeaderWithAuth } = await import('@/services/_auth');
56
-
57
- let provider: ModelProvider = ModelProvider.OpenAI;
58
- // for image page, we need to get the provider from the store
59
- log('Getting provider from store for image page: %s', location.pathname);
60
- if (location.pathname === '/image') {
61
- const { getImageStoreState } = await import('@/store/image');
62
- const { imageGenerationConfigSelectors } = await import(
63
- '@/store/image/slices/generationConfig/selectors'
64
- );
65
- provider = imageGenerationConfigSelectors.provider(getImageStoreState()) as ModelProvider;
66
- log('Getting provider from store for image page: %s', provider);
67
- }
68
-
69
- // TODO: we need to support provider select for chat page
70
- const headers = await createHeaderWithAuth({ provider });
71
- log('Headers: %O', headers);
72
- return headers;
73
- },
74
- maxURLLength: 2083,
75
- transformer: superjson,
76
- url: '/trpc/lambda',
77
- }),
78
- ];
90
+ // 3. assembly links
91
+ const links = [errorHandlingLink, customHttpBatchLink];
79
92
 
80
93
  export const lambdaClient = createTRPCClient<LambdaRouter>({
81
94
  links,
@@ -1,30 +0,0 @@
1
- // @vitest-environment edge-runtime
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { POST as UniverseRoute } from '../[provider]/route';
5
- import { POST, preferredRegion, runtime } from './route';
6
-
7
- // ๆจกๆ‹Ÿ '../[provider]/route'
8
- vi.mock('../[provider]/route', () => ({
9
- POST: vi.fn().mockResolvedValue('mocked response'),
10
- }));
11
-
12
- describe('Configuration tests', () => {
13
- it('should have runtime set to "edge"', () => {
14
- expect(runtime).toBe('edge');
15
- });
16
-
17
- it('should contain specific regions in preferredRegion', () => {
18
- expect(preferredRegion).not.contain(['hk1']);
19
- });
20
- });
21
-
22
- describe('Anthropic POST function tests', () => {
23
- it('should call UniverseRoute with correct parameters', async () => {
24
- const mockRequest = new Request('https://example.com', { method: 'POST' });
25
- await POST(mockRequest);
26
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
27
- params: Promise.resolve({ provider: 'anthropic' }),
28
- });
29
- });
30
- });
@@ -1,21 +0,0 @@
1
- import { POST as UniverseRoute } from '../[provider]/route';
2
-
3
- export const runtime = 'edge';
4
-
5
- export const preferredRegion = [
6
- 'bom1',
7
- 'cle1',
8
- 'cpt1',
9
- 'gru1',
10
- 'hnd1',
11
- 'iad1',
12
- 'icn1',
13
- 'kix1',
14
- 'pdx1',
15
- 'sfo1',
16
- 'sin1',
17
- 'syd1',
18
- ];
19
-
20
- export const POST = async (req: Request) =>
21
- UniverseRoute(req, { params: Promise.resolve({ provider: 'anthropic' }) });
@@ -1,35 +0,0 @@
1
- // @vitest-environment edge-runtime
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { POST as UniverseRoute } from '../[provider]/route';
5
- import { POST, preferredRegion, runtime } from './route';
6
-
7
- // ๆจกๆ‹Ÿ '../[provider]/route'
8
- vi.mock('../[provider]/route', () => ({
9
- POST: vi.fn().mockResolvedValue('mocked response'),
10
- }));
11
-
12
- describe('Configuration tests', () => {
13
- it('should have runtime set to "edge"', () => {
14
- expect(runtime).toBe('edge');
15
- });
16
-
17
- it('should contain specific regions in preferredRegion', () => {
18
- expect(preferredRegion).not.contain(['hkg1']);
19
- expect(preferredRegion).not.contain(['dub1']);
20
- expect(preferredRegion).not.contain(['cdg1']);
21
- expect(preferredRegion).not.contain(['fra1']);
22
- expect(preferredRegion).not.contain(['lhr1']);
23
- expect(preferredRegion).not.contain(['arn1']);
24
- });
25
- });
26
-
27
- describe('Google POST function tests', () => {
28
- it('should call UniverseRoute with correct parameters', async () => {
29
- const mockRequest = new Request('https://example.com', { method: 'POST' });
30
- await POST(mockRequest);
31
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
32
- params: Promise.resolve({ provider: 'google' }),
33
- });
34
- });
35
- });
@@ -1,25 +0,0 @@
1
- import { POST as UniverseRoute } from '../[provider]/route';
2
-
3
- export const runtime = 'edge';
4
-
5
- // due to Gemini-1.5-pro is not available in Hong Kong, we need to set the preferred region to exclude "Hong Kong (hkg1)".
6
- // the paid service of the Gemini API is required in the following regions until 8 July 2024. The free service is not available. Therefore, the regions is temporarily disabled.
7
- // regions include Dublin (dub1, Ireland), Paris (cdg1, France), Frankfurt (fra1, Germany), London (lhr1, UK), and Stockholm (arn1, Sweden).
8
- // refs: https://ai.google.dev/gemini-api/docs/available-regions
9
- export const preferredRegion = [
10
- 'icn1',
11
- 'sin1',
12
- 'hnd1',
13
- 'kix1',
14
- 'bom1',
15
- 'cpt1',
16
- 'pdx1',
17
- 'cle1',
18
- 'syd1',
19
- 'iad1',
20
- 'sfo1',
21
- 'gru1',
22
- ];
23
-
24
- export const POST = async (req: Request) =>
25
- UniverseRoute(req, { params: Promise.resolve({ provider: 'google' }) });
@@ -1,29 +0,0 @@
1
- // @vitest-environment edge-runtime
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { POST as UniverseRoute } from '../[provider]/route';
5
- import { POST, preferredRegion, runtime } from './route';
6
-
7
- vi.mock('../[provider]/route', () => ({
8
- POST: vi.fn().mockResolvedValue('mocked response'),
9
- }));
10
-
11
- describe('Configuration tests', () => {
12
- it('should have runtime set to "edge"', () => {
13
- expect(runtime).toBe('edge');
14
- });
15
-
16
- it('should contain specific regions in preferredRegion', () => {
17
- expect(preferredRegion).not.contain(['hk1']);
18
- });
19
- });
20
-
21
- describe('Groq POST function tests', () => {
22
- it('should call UniverseRoute with correct parameters', async () => {
23
- const mockRequest = new Request('https://example.com', { method: 'POST' });
24
- await POST(mockRequest);
25
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
26
- params: Promise.resolve({ provider: 'groq' }),
27
- });
28
- });
29
- });
@@ -1,21 +0,0 @@
1
- import { POST as UniverseRoute } from '../[provider]/route';
2
-
3
- export const runtime = 'edge';
4
-
5
- export const preferredRegion = [
6
- 'bom1',
7
- 'cle1',
8
- 'cpt1',
9
- 'gru1',
10
- 'hnd1',
11
- 'iad1',
12
- 'icn1',
13
- 'kix1',
14
- 'pdx1',
15
- 'sfo1',
16
- 'sin1',
17
- 'syd1',
18
- ];
19
-
20
- export const POST = async (req: Request) =>
21
- UniverseRoute(req, { params: Promise.resolve({ provider: 'groq' }) });
@@ -1,30 +0,0 @@
1
- // @vitest-environment edge-runtime
2
- import { describe, expect, it, vi } from 'vitest';
3
-
4
- import { POST as UniverseRoute } from '../[provider]/route';
5
- import { POST, preferredRegion, runtime } from './route';
6
-
7
- // ๆจกๆ‹Ÿ '../[provider]/route'
8
- vi.mock('../[provider]/route', () => ({
9
- POST: vi.fn().mockResolvedValue('mocked response'),
10
- }));
11
-
12
- describe('Configuration tests', () => {
13
- it('should have runtime set to "edge"', () => {
14
- expect(runtime).toBe('edge');
15
- });
16
-
17
- it('should contain specific regions in preferredRegion', () => {
18
- expect(preferredRegion).not.contain(['hkg1']);
19
- });
20
- });
21
-
22
- describe('OpenAI POST function tests', () => {
23
- it('should call UniverseRoute with correct parameters', async () => {
24
- const mockRequest = new Request('https://example.com', { method: 'POST' });
25
- await POST(mockRequest);
26
- expect(UniverseRoute).toHaveBeenCalledWith(mockRequest, {
27
- params: Promise.resolve({ provider: 'openai' }),
28
- });
29
- });
30
- });
@@ -1,26 +0,0 @@
1
- import { POST as UniverseRoute } from '../[provider]/route';
2
-
3
- export const runtime = 'edge';
4
-
5
- export const preferredRegion = [
6
- 'arn1',
7
- 'bom1',
8
- 'cdg1',
9
- 'cle1',
10
- 'cpt1',
11
- 'dub1',
12
- 'fra1',
13
- 'gru1',
14
- 'hnd1',
15
- 'iad1',
16
- 'icn1',
17
- 'kix1',
18
- 'lhr1',
19
- 'pdx1',
20
- 'sfo1',
21
- 'sin1',
22
- 'syd1',
23
- ];
24
-
25
- export const POST = async (req: Request) =>
26
- UniverseRoute(req, { params: Promise.resolve({ provider: 'openai' }) });