@lobehub/chat 1.39.2 → 1.40.0

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.
Files changed (203) hide show
  1. package/.env.example +19 -8
  2. package/.eslintignore +1 -1
  3. package/CHANGELOG.md +58 -0
  4. package/changelog/v1.json +21 -0
  5. package/docs/.cdn.cache.json +25 -0
  6. package/docs/changelog/2023-09-09-plugin-system.mdx +1 -1
  7. package/docs/changelog/2023-09-09-plugin-system.zh-CN.mdx +1 -1
  8. package/docs/changelog/2024-09-20-artifacts.mdx +1 -1
  9. package/docs/changelog/2024-09-20-artifacts.zh-CN.mdx +1 -1
  10. package/docs/changelog/2024-10-27-pin-assistant.mdx +2 -2
  11. package/docs/changelog/2024-10-27-pin-assistant.zh-CN.mdx +2 -2
  12. package/docs/changelog/2024-11-06-share-text-json.mdx +2 -2
  13. package/docs/changelog/2024-11-06-share-text-json.zh-CN.mdx +2 -2
  14. package/docs/changelog/index.json +16 -16
  15. package/locales/ar/changelog.json +18 -0
  16. package/locales/ar/common.json +1 -0
  17. package/locales/ar/metadata.json +4 -0
  18. package/locales/bg-BG/changelog.json +18 -0
  19. package/locales/bg-BG/common.json +1 -0
  20. package/locales/bg-BG/metadata.json +4 -0
  21. package/locales/de-DE/changelog.json +18 -0
  22. package/locales/de-DE/common.json +1 -0
  23. package/locales/de-DE/metadata.json +4 -0
  24. package/locales/en-US/changelog.json +18 -0
  25. package/locales/en-US/common.json +1 -0
  26. package/locales/en-US/metadata.json +4 -0
  27. package/locales/es-ES/changelog.json +18 -0
  28. package/locales/es-ES/common.json +1 -0
  29. package/locales/es-ES/metadata.json +4 -0
  30. package/locales/fa-IR/changelog.json +18 -0
  31. package/locales/fa-IR/common.json +1 -0
  32. package/locales/fa-IR/metadata.json +4 -0
  33. package/locales/fr-FR/changelog.json +18 -0
  34. package/locales/fr-FR/common.json +1 -0
  35. package/locales/fr-FR/metadata.json +4 -0
  36. package/locales/it-IT/changelog.json +18 -0
  37. package/locales/it-IT/common.json +1 -0
  38. package/locales/it-IT/metadata.json +4 -0
  39. package/locales/ja-JP/changelog.json +18 -0
  40. package/locales/ja-JP/common.json +1 -0
  41. package/locales/ja-JP/metadata.json +4 -0
  42. package/locales/ko-KR/changelog.json +18 -0
  43. package/locales/ko-KR/common.json +1 -0
  44. package/locales/ko-KR/metadata.json +4 -0
  45. package/locales/nl-NL/changelog.json +18 -0
  46. package/locales/nl-NL/common.json +1 -0
  47. package/locales/nl-NL/metadata.json +4 -0
  48. package/locales/pl-PL/changelog.json +18 -0
  49. package/locales/pl-PL/common.json +1 -0
  50. package/locales/pl-PL/metadata.json +4 -0
  51. package/locales/pt-BR/changelog.json +18 -0
  52. package/locales/pt-BR/common.json +1 -0
  53. package/locales/pt-BR/metadata.json +4 -0
  54. package/locales/ru-RU/changelog.json +18 -0
  55. package/locales/ru-RU/common.json +1 -0
  56. package/locales/ru-RU/metadata.json +4 -0
  57. package/locales/tr-TR/changelog.json +18 -0
  58. package/locales/tr-TR/common.json +1 -0
  59. package/locales/tr-TR/metadata.json +4 -0
  60. package/locales/vi-VN/changelog.json +18 -0
  61. package/locales/vi-VN/common.json +1 -0
  62. package/locales/vi-VN/metadata.json +4 -0
  63. package/locales/zh-CN/changelog.json +18 -0
  64. package/locales/zh-CN/common.json +1 -0
  65. package/locales/zh-CN/metadata.json +4 -0
  66. package/locales/zh-TW/changelog.json +18 -0
  67. package/locales/zh-TW/common.json +1 -0
  68. package/locales/zh-TW/metadata.json +4 -0
  69. package/package.json +6 -1
  70. package/scripts/cdnWorkflow/index.ts +217 -0
  71. package/scripts/cdnWorkflow/optimized.ts +21 -0
  72. package/scripts/cdnWorkflow/s3/index.ts +120 -0
  73. package/scripts/cdnWorkflow/s3/types.ts +25 -0
  74. package/scripts/cdnWorkflow/s3/utils.ts +106 -0
  75. package/scripts/cdnWorkflow/uploader.ts +73 -0
  76. package/scripts/cdnWorkflow/utils.ts +93 -0
  77. package/src/app/(main)/(mobile)/me/(home)/__tests__/useCategory.test.tsx +25 -12
  78. package/src/app/(main)/(mobile)/me/(home)/features/useCategory.tsx +19 -9
  79. package/src/app/(main)/(mobile)/me/(home)/loading.tsx +1 -1
  80. package/src/app/(main)/(mobile)/me/data/loading.tsx +1 -1
  81. package/src/app/(main)/(mobile)/me/profile/loading.tsx +1 -1
  82. package/src/app/(main)/(mobile)/me/settings/loading.tsx +1 -1
  83. package/src/app/(main)/_layout/Desktop.tsx +4 -1
  84. package/src/app/(main)/_layout/Mobile.tsx +2 -1
  85. package/src/app/(main)/changelog/_layout/Desktop.tsx +25 -0
  86. package/src/app/(main)/changelog/_layout/Mobile/Header.tsx +33 -0
  87. package/src/app/(main)/changelog/_layout/Mobile/index.tsx +21 -0
  88. package/src/app/(main)/changelog/error.tsx +5 -0
  89. package/src/app/(main)/changelog/features/GridLayout.tsx +22 -0
  90. package/src/app/(main)/changelog/features/Hero.tsx +40 -0
  91. package/src/app/(main)/changelog/features/Post.tsx +56 -0
  92. package/src/app/(main)/changelog/features/PublishedTime.tsx +50 -0
  93. package/src/app/(main)/changelog/features/VersionTag.tsx +27 -0
  94. package/src/app/(main)/changelog/layout.tsx +10 -0
  95. package/src/app/(main)/changelog/loading.tsx +3 -0
  96. package/src/app/(main)/changelog/modal/page.tsx +23 -0
  97. package/src/app/(main)/changelog/not-found.tsx +3 -0
  98. package/src/app/(main)/changelog/page.tsx +73 -0
  99. package/src/app/(main)/chat/(workspace)/@portal/default.tsx +1 -1
  100. package/src/app/(main)/chat/(workspace)/@portal/loading.tsx +1 -1
  101. package/src/app/(main)/chat/(workspace)/page.tsx +9 -2
  102. package/src/app/(main)/chat/@session/default.tsx +3 -2
  103. package/src/app/(main)/chat/loading.tsx +1 -1
  104. package/src/app/(main)/chat/settings/loading.tsx +1 -1
  105. package/src/app/(main)/discover/loading.tsx +1 -1
  106. package/src/app/(main)/files/loading.tsx +2 -22
  107. package/src/app/(main)/profile/loading.tsx +1 -1
  108. package/src/app/(main)/repos/[id]/evals/dataset/page.tsx +1 -1
  109. package/src/app/(main)/repos/[id]/evals/evaluation/page.tsx +1 -1
  110. package/src/app/(main)/settings/@category/default.tsx +6 -2
  111. package/src/app/(main)/settings/_layout/Desktop/SideBar.tsx +1 -1
  112. package/src/app/(main)/settings/about/features/Version.tsx +2 -2
  113. package/src/app/(main)/settings/loading.tsx +2 -8
  114. package/src/app/@modal/(.)changelog/modal/features/Cover.tsx +48 -0
  115. package/src/app/@modal/(.)changelog/modal/features/Hero.tsx +29 -0
  116. package/src/app/@modal/(.)changelog/modal/features/Pagination.tsx +54 -0
  117. package/src/app/@modal/(.)changelog/modal/features/Post.tsx +57 -0
  118. package/src/app/@modal/(.)changelog/modal/features/PublishedTime.tsx +50 -0
  119. package/src/app/@modal/(.)changelog/modal/features/ReadDetail.tsx +94 -0
  120. package/src/app/@modal/(.)changelog/modal/features/UpdateChangelogStatus.tsx +21 -0
  121. package/src/app/@modal/(.)changelog/modal/features/VersionTag.tsx +27 -0
  122. package/src/app/@modal/(.)changelog/modal/layout.tsx +39 -0
  123. package/src/app/@modal/(.)changelog/modal/loading.tsx +10 -0
  124. package/src/app/@modal/(.)changelog/modal/page.tsx +37 -0
  125. package/src/app/@modal/(.)settings/modal/layout.tsx +19 -16
  126. package/src/app/@modal/_layout/ModalLayout.tsx +63 -0
  127. package/src/app/@modal/chat/(.)settings/modal/layout.tsx +20 -17
  128. package/src/app/@modal/layout.tsx +5 -69
  129. package/src/app/loading/Client/Content.tsx +1 -1
  130. package/src/app/loading/Server/Content.tsx +1 -1
  131. package/src/components/Loading/BrandTextLoading/LobeChatText/SVG.tsx +44 -0
  132. package/src/components/Loading/BrandTextLoading/LobeChatText/index.tsx +6 -0
  133. package/src/components/Loading/BrandTextLoading/LobeChatText/style.css +32 -0
  134. package/src/components/Loading/BrandTextLoading/index.tsx +11 -0
  135. package/src/components/{SkeletonLoading → Loading/SkeletonLoading}/index.tsx +1 -1
  136. package/src/components/mdx/Image.tsx +50 -0
  137. package/src/components/mdx/index.tsx +2 -0
  138. package/src/const/url.ts +1 -0
  139. package/src/features/ChangelogModal/index.tsx +22 -0
  140. package/src/features/FileViewer/Renderer/TXT/index.tsx +1 -1
  141. package/src/features/Portal/FilePreview/Body/index.tsx +1 -1
  142. package/src/features/Portal/Home/Body/Files/FileList/index.tsx +1 -1
  143. package/src/features/Setting/Footer.tsx +3 -1
  144. package/src/features/Setting/SettingContainer.tsx +1 -0
  145. package/src/features/User/UserPanel/useMenu.tsx +50 -46
  146. package/src/features/User/__tests__/useMenu.test.tsx +7 -6
  147. package/src/hooks/useInterceptingRoutes.ts +1 -6
  148. package/src/hooks/useShare.tsx +1 -0
  149. package/src/locales/default/changelog.ts +18 -0
  150. package/src/locales/default/common.ts +1 -0
  151. package/src/locales/default/index.ts +2 -0
  152. package/src/locales/default/metadata.ts +4 -0
  153. package/src/server/metadata.ts +5 -3
  154. package/src/server/routers/edge/appStatus.ts +3 -0
  155. package/src/server/routers/edge/index.ts +2 -0
  156. package/src/server/routers/lambda/agent.ts +1 -1
  157. package/src/server/services/changelog/index.test.ts +310 -0
  158. package/src/server/services/changelog/index.ts +196 -0
  159. package/src/server/services/discover/index.test.ts +0 -1
  160. package/src/server/sitemap.ts +4 -1
  161. package/src/services/__tests__/chat.test.ts +1 -1
  162. package/src/services/__tests__/global.test.ts +5 -2
  163. package/src/services/_auth.ts +1 -1
  164. package/src/services/agent.ts +25 -21
  165. package/src/services/chat.ts +2 -2
  166. package/src/services/file/ClientS3/index.ts +6 -6
  167. package/src/services/file/client.ts +14 -15
  168. package/src/services/file/server.ts +20 -25
  169. package/src/services/global.ts +2 -2
  170. package/src/services/import/client.ts +6 -5
  171. package/src/services/import/server.ts +6 -5
  172. package/src/services/import/type.ts +7 -0
  173. package/src/services/knowledgeBase.ts +19 -19
  174. package/src/services/message/_deprecated.ts +5 -0
  175. package/src/services/message/client.ts +52 -48
  176. package/src/services/message/server.ts +50 -53
  177. package/src/services/message/type.ts +2 -2
  178. package/src/services/plugin/client.ts +16 -22
  179. package/src/services/plugin/server.ts +15 -19
  180. package/src/services/rag.ts +18 -18
  181. package/src/services/ragEval.ts +29 -26
  182. package/src/services/session/_deprecated.ts +2 -2
  183. package/src/services/session/client.ts +55 -81
  184. package/src/services/session/server.ts +50 -74
  185. package/src/services/session/type.ts +4 -6
  186. package/src/services/share.ts +4 -4
  187. package/src/services/textToImage.ts +5 -2
  188. package/src/services/thread/client.ts +9 -15
  189. package/src/services/thread/server.ts +10 -15
  190. package/src/services/topic/client.ts +25 -25
  191. package/src/services/topic/server.ts +25 -42
  192. package/src/services/trace.ts +4 -4
  193. package/src/services/user/client.ts +13 -17
  194. package/src/services/user/server.ts +9 -13
  195. package/src/services/user/type.ts +1 -1
  196. package/src/store/chat/slices/message/reducer.ts +3 -2
  197. package/src/store/global/action.ts +27 -22
  198. package/src/store/global/initialState.ts +1 -0
  199. package/src/types/changelog.ts +6 -0
  200. package/src/types/message/index.ts +10 -8
  201. package/src/app/@modal/features/InterceptingContext.tsx +0 -9
  202. /package/src/components/{CircleLoading → Loading/CircleLoading}/index.tsx +0 -0
  203. /package/src/components/{FullscreenLoading → Loading/FullscreenLoading}/index.tsx +0 -0
@@ -0,0 +1,196 @@
1
+ import dayjs from 'dayjs';
2
+ import matter from 'gray-matter';
3
+ import { markdownToTxt } from 'markdown-to-txt';
4
+ import semver from 'semver';
5
+ import urlJoin from 'url-join';
6
+
7
+ import { Locales } from '@/locales/resources';
8
+ import { ChangelogIndexItem } from '@/types/changelog';
9
+
10
+ const BASE_URL = 'https://raw.githubusercontent.com';
11
+ const LAST_MODIFIED = new Date().toISOString();
12
+
13
+ const docCdnPrefix = process.env.DOC_S3_PUBLIC_DOMAIN || '';
14
+
15
+ export interface ChangelogConfig {
16
+ branch: string;
17
+ cdnPath: string;
18
+ changelogPath: string;
19
+ docsPath: string;
20
+ majorVersion: number;
21
+ repo: string;
22
+ type: 'cloud' | 'community';
23
+ user: string;
24
+ }
25
+
26
+ export class ChangelogService {
27
+ cdnUrls: {
28
+ [key: string]: string;
29
+ } = {};
30
+ config: ChangelogConfig = {
31
+ branch: process.env.DOCS_BRANCH || 'main',
32
+ cdnPath: 'docs/.cdn.cache.json',
33
+ changelogPath: 'changelog',
34
+ docsPath: 'docs/changelog',
35
+ majorVersion: 1,
36
+ repo: 'lobe-chat',
37
+ type: 'cloud',
38
+ user: 'lobehub',
39
+ };
40
+
41
+ async getLatestChangelogId() {
42
+ const index = await this.getChangelogIndex();
43
+ return index[0]?.id;
44
+ }
45
+
46
+ async getChangelogIndex(): Promise<ChangelogIndexItem[]> {
47
+ try {
48
+ const url = this.genUrl(urlJoin(this.config.docsPath, 'index.json'));
49
+
50
+ const res = await fetch(url);
51
+
52
+ const data = await res.json();
53
+
54
+ return this.mergeChangelogs(data.cloud, data.community).slice(0, 5);
55
+ } catch (e) {
56
+ console.error('Error getting changelog lists:', e);
57
+ return false as any;
58
+ }
59
+ }
60
+
61
+ async getIndexItemById(id: string) {
62
+ const index = await this.getChangelogIndex();
63
+ return index.find((item) => item.id === id);
64
+ }
65
+
66
+ async getPostById(id: string, options?: { locale?: Locales }) {
67
+ await this.cdnInit();
68
+ try {
69
+ const post = await this.getIndexItemById(id);
70
+
71
+ const filename = options?.locale === 'en-US' ? `${id}.mdx` : `${id}.zh-CN.mdx`;
72
+ const url = this.genUrl(urlJoin(this.config.docsPath, filename));
73
+
74
+ const response = await fetch(url);
75
+ const text = await response.text();
76
+ const { data, content } = matter(text);
77
+
78
+ const regex = /^#\s(.+)/;
79
+ const match = regex.exec(content.trim());
80
+ const matches = content.trim().split(regex);
81
+
82
+ let description: string;
83
+
84
+ if (matches[2]) {
85
+ description = matches[2] ? matches[2].trim() : '';
86
+ } else {
87
+ description = matches[1] ? matches[1].trim() : '';
88
+ }
89
+
90
+ if (docCdnPrefix) {
91
+ const images = this.extractHttpsLinks(content);
92
+ for (const url of images) {
93
+ const cdnUrl = this.replaceCdnUrl(url);
94
+ if (cdnUrl && url !== cdnUrl) {
95
+ description = description.replaceAll(url, cdnUrl);
96
+ }
97
+ }
98
+ }
99
+
100
+ return {
101
+ date: post?.date
102
+ ? new Date(post.date)
103
+ : data?.date
104
+ ? new Date(data.date)
105
+ : new Date(LAST_MODIFIED),
106
+ description: markdownToTxt(description.replaceAll('\n', '').replaceAll(' ', ' ')).slice(
107
+ 0,
108
+ 160,
109
+ ),
110
+ image: post?.image ? this.replaceCdnUrl(post.image) : undefined,
111
+ tags: ['changelog'],
112
+ title: match ? match[1] : '',
113
+ ...data,
114
+ content: description,
115
+ rawTitle: match ? match[1] : '',
116
+ };
117
+ } catch {
118
+ console.error('Error getting changlog post by id', id);
119
+ return false as any;
120
+ }
121
+ }
122
+
123
+ private mergeChangelogs(
124
+ cloud: ChangelogIndexItem[],
125
+ community: ChangelogIndexItem[],
126
+ ): ChangelogIndexItem[] {
127
+ if (this.config.type === 'community') {
128
+ return community;
129
+ }
130
+
131
+ const merged = [...community];
132
+
133
+ for (const cloudItem of cloud) {
134
+ const index = merged.findIndex((item) => item.id === cloudItem.id);
135
+ if (index !== -1) {
136
+ merged[index] = cloudItem;
137
+ } else {
138
+ merged.push(cloudItem);
139
+ }
140
+ }
141
+
142
+ return merged
143
+ .map((item) => ({
144
+ ...item,
145
+ date: dayjs(item.date).format('YYYY-MM-DD'),
146
+ versionRange: this.formatVersionRange(item.versionRange),
147
+ }))
148
+ .sort((a, b) => semver.rcompare(a.versionRange[0], b.versionRange[0]));
149
+ }
150
+
151
+ private formatVersionRange(range: string[]): string[] {
152
+ if (range.length === 1) {
153
+ return range;
154
+ }
155
+
156
+ const [v1, v2]: any = range.map((v) => semver.parse(v)?.toString());
157
+
158
+ const minVersion = semver.lt(v1, v2) ? v1 : v2;
159
+ const maxVersion = semver.gt(v1, v2) ? v1 : v2;
160
+
161
+ return [maxVersion, minVersion];
162
+ }
163
+
164
+ private genUrl(path: string) {
165
+ return urlJoin(BASE_URL, this.config.user, this.config.repo, this.config.branch, path);
166
+ }
167
+
168
+ private extractHttpsLinks(text: string) {
169
+ const regex = /https:\/\/[^\s"')>]+/g;
170
+ const links = text.match(regex);
171
+ return links || [];
172
+ }
173
+
174
+ private async cdnInit() {
175
+ if (!docCdnPrefix) return;
176
+ if (Object.keys(this.cdnUrls).length === 0) {
177
+ try {
178
+ const url = this.genUrl(this.config.cdnPath);
179
+ const res = await fetch(url);
180
+ const data = await res.json();
181
+ if (data) {
182
+ this.cdnUrls = data;
183
+ }
184
+ } catch (error) {
185
+ console.error('Error getting changelog cdn cache:', error);
186
+ }
187
+ }
188
+ }
189
+
190
+ private replaceCdnUrl(url: string) {
191
+ if (!docCdnPrefix || !this.cdnUrls?.[url]) {
192
+ return url;
193
+ }
194
+ return urlJoin(docCdnPrefix, this.cdnUrls[url]);
195
+ }
196
+ }
@@ -1,7 +1,6 @@
1
1
  // @vitest-environment node
2
2
  import { beforeEach, describe, expect, it, vi } from 'vitest';
3
3
 
4
- import { DEFAULT_LANG } from '@/const/locale';
5
4
  import { AssistantCategory, PluginCategory } from '@/types/discover';
6
5
 
7
6
  import { DiscoverService } from './index';
@@ -3,6 +3,7 @@ import { MetadataRoute } from 'next';
3
3
  import qs from 'query-string';
4
4
  import urlJoin from 'url-join';
5
5
 
6
+ import { serverFeatureFlags } from '@/config/featureFlags';
6
7
  import { DEFAULT_LANG } from '@/const/locale';
7
8
  import { SITEMAP_BASE_URL } from '@/const/url';
8
9
  import { Locales, locales as allLocales } from '@/locales/resources';
@@ -195,12 +196,14 @@ export class Sitemap {
195
196
  }
196
197
 
197
198
  async getPage(): Promise<MetadataRoute.Sitemap> {
199
+ const hideDocs = serverFeatureFlags().hideDocs;
198
200
  const assistantsCategory = Object.values(AssistantCategory);
199
201
  const pluginCategory = Object.values(PluginCategory);
200
202
  const modelCategory = await this.discoverService.getProviderList(DEFAULT_LANG);
201
203
  return [
202
204
  ...this._genSitemap('/', { noLocales: true }),
203
205
  ...this._genSitemap('/chat', { noLocales: true }),
206
+ ...(!hideDocs ? this._genSitemap('/changelog', { noLocales: true }) : []),
204
207
  /* ↓ cloud slot ↓ */
205
208
 
206
209
  /* ↑ cloud slot ↑ */
@@ -227,7 +230,7 @@ export class Sitemap {
227
230
  }),
228
231
  ),
229
232
  ...this._genSitemap('/discover/providers', { changeFrequency: 'daily', priority: 0.7 }),
230
- ];
233
+ ].filter(Boolean);
231
234
  }
232
235
  getRobots() {
233
236
  return [
@@ -904,7 +904,7 @@ describe('ChatService', () => {
904
904
  * initialization of AgentRuntime with different providers
905
905
  */
906
906
  vi.mock('../_auth', async (importOriginal) => {
907
- return await importOriginal();
907
+ return importOriginal();
908
908
  });
909
909
  describe('AgentRuntimeOnClient', () => {
910
910
  describe('initializeWithClientStore', () => {
@@ -18,6 +18,9 @@ vi.mock('@/libs/trpc/client', () => {
18
18
  getGlobalConfig: { query: vi.fn() },
19
19
  getDefaultAgentConfig: { query: vi.fn() },
20
20
  },
21
+ appStatus: {
22
+ getLatestChangelogId: { query: vi.fn() },
23
+ },
21
24
  },
22
25
  };
23
26
  });
@@ -28,14 +31,14 @@ describe('GlobalService', () => {
28
31
  // Arrange
29
32
  const mockVersion = '1.0.0';
30
33
  (fetch as Mock).mockResolvedValue({
31
- json: () => Promise.resolve({ 'dist-tags': { latest: mockVersion } }),
34
+ json: () => Promise.resolve({ version: mockVersion }),
32
35
  });
33
36
 
34
37
  // Act
35
38
  const version = await globalService.getLatestVersion();
36
39
 
37
40
  // Assert
38
- expect(fetch).toHaveBeenCalledWith('https://registry.npmmirror.com/@lobehub/chat');
41
+ expect(fetch).toHaveBeenCalledWith('https://registry.npmmirror.com/@lobehub/chat/latest');
39
42
  expect(version).toBe(mockVersion);
40
43
  });
41
44
 
@@ -78,7 +78,7 @@ const createAuthTokenWithPayload = async (payload = {}) => {
78
78
  const accessCode = keyVaultsConfigSelectors.password(useUserStore.getState());
79
79
  const userId = userProfileSelectors.userId(useUserStore.getState());
80
80
 
81
- return await createJWT<JWTPayload>({ accessCode, userId, ...payload });
81
+ return createJWT<JWTPayload>({ accessCode, userId, ...payload });
82
82
  };
83
83
 
84
84
  interface AuthParams {
@@ -1,45 +1,49 @@
1
1
  import { lambdaClient } from '@/libs/trpc/client';
2
2
 
3
3
  class AgentService {
4
- async createAgentKnowledgeBase(agentId: string, knowledgeBaseId: string, enabled?: boolean) {
5
- return await lambdaClient.agent.createAgentKnowledgeBase.mutate({
4
+ createAgentKnowledgeBase = async (
5
+ agentId: string,
6
+ knowledgeBaseId: string,
7
+ enabled?: boolean,
8
+ ) => {
9
+ return lambdaClient.agent.createAgentKnowledgeBase.mutate({
6
10
  agentId,
7
11
  enabled,
8
12
  knowledgeBaseId,
9
13
  });
10
- }
14
+ };
11
15
 
12
- async deleteAgentKnowledgeBase(agentId: string, knowledgeBaseId: string) {
13
- return await lambdaClient.agent.deleteAgentKnowledgeBase.mutate({ agentId, knowledgeBaseId });
14
- }
16
+ deleteAgentKnowledgeBase = async (agentId: string, knowledgeBaseId: string) => {
17
+ return lambdaClient.agent.deleteAgentKnowledgeBase.mutate({ agentId, knowledgeBaseId });
18
+ };
15
19
 
16
- async toggleKnowledgeBase(agentId: string, knowledgeBaseId: string, enabled?: boolean) {
17
- return await lambdaClient.agent.toggleKnowledgeBase.mutate({
20
+ toggleKnowledgeBase = async (agentId: string, knowledgeBaseId: string, enabled?: boolean) => {
21
+ return lambdaClient.agent.toggleKnowledgeBase.mutate({
18
22
  agentId,
19
23
  enabled,
20
24
  knowledgeBaseId,
21
25
  });
22
- }
26
+ };
23
27
 
24
- async createAgentFiles(agentId: string, fileIds: string[], enabled?: boolean) {
25
- return await lambdaClient.agent.createAgentFiles.mutate({ agentId, enabled, fileIds });
26
- }
28
+ createAgentFiles = async (agentId: string, fileIds: string[], enabled?: boolean) => {
29
+ return lambdaClient.agent.createAgentFiles.mutate({ agentId, enabled, fileIds });
30
+ };
27
31
 
28
- async deleteAgentFile(agentId: string, fileId: string) {
29
- return await lambdaClient.agent.deleteAgentFile.mutate({ agentId, fileId });
30
- }
32
+ deleteAgentFile = async (agentId: string, fileId: string) => {
33
+ return lambdaClient.agent.deleteAgentFile.mutate({ agentId, fileId });
34
+ };
31
35
 
32
- async toggleFile(agentId: string, fileId: string, enabled?: boolean) {
33
- return await lambdaClient.agent.toggleFile.mutate({
36
+ toggleFile = async (agentId: string, fileId: string, enabled?: boolean) => {
37
+ return lambdaClient.agent.toggleFile.mutate({
34
38
  agentId,
35
39
  enabled,
36
40
  fileId,
37
41
  });
38
- }
42
+ };
39
43
 
40
- async getFilesAndKnowledgeBases(agentId: string) {
41
- return await lambdaClient.agent.getKnowledgeBasesAndFiles.query({ agentId });
42
- }
44
+ getFilesAndKnowledgeBases = async (agentId: string) => {
45
+ return lambdaClient.agent.getKnowledgeBasesAndFiles.query({ agentId });
46
+ };
43
47
  }
44
48
 
45
49
  export const agentService = new AgentService();
@@ -499,7 +499,7 @@ class ChatService {
499
499
  return this.reorderToolMessages(postMessages);
500
500
  };
501
501
 
502
- private mapTrace(trace?: TracePayload, tag?: TraceTagMap): TracePayload {
502
+ private mapTrace = (trace?: TracePayload, tag?: TraceTagMap): TracePayload => {
503
503
  const tags = sessionMetaSelectors.currentAgentMeta(useSessionStore.getState()).tags || [];
504
504
 
505
505
  const enabled = preferenceSelectors.userAllowTrace(useUserStore.getState());
@@ -512,7 +512,7 @@ class ChatService {
512
512
  tags: [tag, ...(trace?.tags || []), ...tags].filter(Boolean) as string[],
513
513
  userId: userProfileSelectors.userId(useUserStore.getState()),
514
514
  };
515
- }
515
+ };
516
516
 
517
517
  /**
518
518
  * Fetch chat completion on the client side.
@@ -17,21 +17,21 @@ export class BrowserS3Storage {
17
17
  * @param key 文件 hash
18
18
  * @param file File 对象
19
19
  */
20
- async putObject(key: string, file: File): Promise<void> {
20
+ putObject = async (key: string, file: File): Promise<void> => {
21
21
  try {
22
22
  const data = await file.arrayBuffer();
23
23
  await set(key, { data, name: file.name, type: file.type }, this.store);
24
24
  } catch (e) {
25
25
  throw new Error(`Failed to put file ${file.name}: ${(e as Error).message}`);
26
26
  }
27
- }
27
+ };
28
28
 
29
29
  /**
30
30
  * 获取文件
31
31
  * @param key 文件 hash
32
32
  * @returns File 对象
33
33
  */
34
- async getObject(key: string): Promise<File | undefined> {
34
+ getObject = async (key: string): Promise<File | undefined> => {
35
35
  try {
36
36
  const res = await get<{ data: ArrayBuffer; name: string; type: string }>(key, this.store);
37
37
  if (!res) return;
@@ -40,19 +40,19 @@ export class BrowserS3Storage {
40
40
  } catch (e) {
41
41
  throw new Error(`Failed to get object (key=${key}): ${(e as Error).message}`);
42
42
  }
43
- }
43
+ };
44
44
 
45
45
  /**
46
46
  * 删除文件
47
47
  * @param key 文件 hash
48
48
  */
49
- async deleteObject(key: string): Promise<void> {
49
+ deleteObject = async (key: string): Promise<void> => {
50
50
  try {
51
51
  await del(key, this.store);
52
52
  } catch (e) {
53
53
  throw new Error(`Failed to delete object (key=${key}): ${(e as Error).message}`);
54
54
  }
55
- }
55
+ };
56
56
  }
57
57
 
58
58
  export const clientS3Storage = new BrowserS3Storage();
@@ -2,7 +2,6 @@ import { clientDB } from '@/database/client/db';
2
2
  import { FileModel } from '@/database/server/models/file';
3
3
  import { BaseClientService } from '@/services/baseClientService';
4
4
  import { clientS3Storage } from '@/services/file/ClientS3';
5
- import { FileItem, UploadFileParams } from '@/types/files';
6
5
 
7
6
  import { IFileService } from './type';
8
7
 
@@ -11,7 +10,7 @@ export class ClientService extends BaseClientService implements IFileService {
11
10
  return new FileModel(clientDB as any, this.userId);
12
11
  }
13
12
 
14
- async createFile(file: UploadFileParams) {
13
+ createFile: IFileService['createFile'] = async (file) => {
15
14
  // save to local storage
16
15
  // we may want to save to a remote server later
17
16
  const res = await this.fileModel.create(
@@ -34,9 +33,9 @@ export class ClientService extends BaseClientService implements IFileService {
34
33
  id: res.id,
35
34
  url: `data:${file.fileType};base64,${base64}`,
36
35
  };
37
- }
36
+ };
38
37
 
39
- async getFile(id: string): Promise<FileItem> {
38
+ getFile: IFileService['getFile'] = async (id) => {
40
39
  const item = await this.fileModel.findById(id);
41
40
  if (!item) {
42
41
  throw new Error('file not found');
@@ -57,28 +56,28 @@ export class ClientService extends BaseClientService implements IFileService {
57
56
  updatedAt: new Date(item.updatedAt),
58
57
  url,
59
58
  };
60
- }
59
+ };
61
60
 
62
- async removeFile(id: string) {
61
+ removeFile: IFileService['removeFile'] = async (id) => {
63
62
  await this.fileModel.delete(id, false);
64
- }
63
+ };
65
64
 
66
- async removeFiles(ids: string[]) {
65
+ removeFiles: IFileService['removeFiles'] = async (ids) => {
67
66
  await this.fileModel.deleteMany(ids, false);
68
- }
67
+ };
69
68
 
70
- async removeAllFiles() {
69
+ removeAllFiles: IFileService['removeAllFiles'] = async () => {
71
70
  return this.fileModel.clear();
72
- }
71
+ };
73
72
 
74
- async checkFileHash(hash: string) {
73
+ checkFileHash: IFileService['checkFileHash'] = async (hash) => {
75
74
  return this.fileModel.checkHash(hash);
76
- }
75
+ };
77
76
 
78
- private async getBase64ByFileHash(hash: string) {
77
+ private getBase64ByFileHash = async (hash: string) => {
79
78
  const fileItem = await clientS3Storage.getObject(hash);
80
79
  if (!fileItem) throw new Error('file not found');
81
80
 
82
81
  return Buffer.from(await fileItem.arrayBuffer()).toString('base64');
83
- }
82
+ };
84
83
  }
@@ -1,10 +1,5 @@
1
1
  import { lambdaClient } from '@/libs/trpc/client';
2
- import {
3
- FileItem,
4
- QueryFileListParams,
5
- QueryFileListSchemaType,
6
- UploadFileParams,
7
- } from '@/types/files';
2
+ import { QueryFileListParams, QueryFileListSchemaType, UploadFileParams } from '@/types/files';
8
3
 
9
4
  import { IFileService } from './type';
10
5
 
@@ -14,11 +9,11 @@ interface CreateFileParams extends Omit<UploadFileParams, 'url'> {
14
9
  }
15
10
 
16
11
  export class ServerService implements IFileService {
17
- async createFile(params: UploadFileParams, knowledgeBaseId?: string) {
12
+ createFile: IFileService['createFile'] = async (params, knowledgeBaseId) => {
18
13
  return lambdaClient.file.createFile.mutate({ ...params, knowledgeBaseId } as CreateFileParams);
19
- }
14
+ };
20
15
 
21
- async getFile(id: string): Promise<FileItem> {
16
+ getFile: IFileService['getFile'] = async (id) => {
22
17
  const item = await lambdaClient.file.findById.query({ id });
23
18
 
24
19
  if (!item) {
@@ -26,33 +21,33 @@ export class ServerService implements IFileService {
26
21
  }
27
22
 
28
23
  return { ...item, type: item.fileType };
29
- }
24
+ };
30
25
 
31
- async removeFile(id: string) {
26
+ removeFile: IFileService['removeFile'] = async (id) => {
32
27
  await lambdaClient.file.removeFile.mutate({ id });
33
- }
28
+ };
34
29
 
35
- async removeFiles(ids: string[]) {
30
+ removeFiles: IFileService['removeFiles'] = async (ids) => {
36
31
  await lambdaClient.file.removeFiles.mutate({ ids });
37
- }
32
+ };
38
33
 
39
- async removeAllFiles() {
34
+ removeAllFiles: IFileService['removeAllFiles'] = async () => {
40
35
  await lambdaClient.file.removeAllFiles.mutate();
41
- }
36
+ };
42
37
 
43
- async getFiles(params: QueryFileListParams) {
38
+ getFiles = async (params: QueryFileListParams) => {
44
39
  return lambdaClient.file.getFiles.query(params as QueryFileListSchemaType);
45
- }
40
+ };
46
41
 
47
- async getFileItem(id: string) {
42
+ getFileItem = async (id: string) => {
48
43
  return lambdaClient.file.getFileItemById.query({ id });
49
- }
44
+ };
50
45
 
51
- async checkFileHash(hash: string) {
46
+ checkFileHash: IFileService['checkFileHash'] = async (hash) => {
52
47
  return lambdaClient.file.checkFileHash.mutate({ hash });
53
- }
48
+ };
54
49
 
55
- async removeFileAsyncTask(id: string, type: 'embedding' | 'chunk') {
56
- return await lambdaClient.file.removeFileAsyncTask.mutate({ id, type });
57
- }
50
+ removeFileAsyncTask = async (id: string, type: 'embedding' | 'chunk') => {
51
+ return lambdaClient.file.removeFileAsyncTask.mutate({ id, type });
52
+ };
58
53
  }
@@ -4,7 +4,7 @@ import { edgeClient } from '@/libs/trpc/client';
4
4
  import { LobeAgentConfig } from '@/types/agent';
5
5
  import { GlobalServerConfig } from '@/types/serverConfig';
6
6
 
7
- const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat';
7
+ const VERSION_URL = 'https://registry.npmmirror.com/@lobehub/chat/latest';
8
8
 
9
9
  class GlobalService {
10
10
  /**
@@ -14,7 +14,7 @@ class GlobalService {
14
14
  const res = await fetch(VERSION_URL);
15
15
  const data = await res.json();
16
16
 
17
- return data['dist-tags']?.latest;
17
+ return data['version'];
18
18
  };
19
19
 
20
20
  getGlobalConfig = async (): Promise<GlobalServerConfig> => {
@@ -2,19 +2,20 @@ import { clientDB } from '@/database/client/db';
2
2
  import { DataImporterRepos } from '@/database/repositories/dataImporter';
3
3
  import { BaseClientService } from '@/services/baseClientService';
4
4
  import { useUserStore } from '@/store/user';
5
- import { ImportStage, ImporterEntryData, OnImportCallbacks } from '@/types/importer';
6
- import { UserSettings } from '@/types/user/settings';
5
+ import { ImportStage } from '@/types/importer';
7
6
 
8
- export class ClientService extends BaseClientService {
7
+ import { IImportService } from './type';
8
+
9
+ export class ClientService extends BaseClientService implements IImportService {
9
10
  private get dataImporter(): DataImporterRepos {
10
11
  return new DataImporterRepos(clientDB as any, this.userId);
11
12
  }
12
13
 
13
- importSettings = async (settings: UserSettings) => {
14
+ importSettings: IImportService['importSettings'] = async (settings) => {
14
15
  await useUserStore.getState().importAppSettings(settings);
15
16
  };
16
17
 
17
- importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks) => {
18
+ importData: IImportService['importData'] = async (data, callbacks) => {
18
19
  callbacks?.onStageChange?.(ImportStage.Importing);
19
20
  const time = Date.now();
20
21
  try {
@@ -2,16 +2,17 @@ import { DefaultErrorShape } from '@trpc/server/unstable-core-do-not-import';
2
2
 
3
3
  import { edgeClient, lambdaClient } from '@/libs/trpc/client';
4
4
  import { useUserStore } from '@/store/user';
5
- import { ImportStage, ImporterEntryData, OnImportCallbacks } from '@/types/importer';
6
- import { UserSettings } from '@/types/user/settings';
5
+ import { ImportStage, OnImportCallbacks } from '@/types/importer';
7
6
  import { uuid } from '@/utils/uuid';
8
7
 
9
- export class ServerService {
10
- importSettings = async (settings: UserSettings) => {
8
+ import { IImportService } from './type';
9
+
10
+ export class ServerService implements IImportService {
11
+ importSettings: IImportService['importSettings'] = async (settings) => {
11
12
  await useUserStore.getState().importAppSettings(settings);
12
13
  };
13
14
 
14
- importData = async (data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void> => {
15
+ importData: IImportService['importData'] = async (data, callbacks) => {
15
16
  const handleError = (e: unknown) => {
16
17
  callbacks?.onStageChange?.(ImportStage.Error);
17
18
  const error = e as DefaultErrorShape;
@@ -0,0 +1,7 @@
1
+ import { ImporterEntryData, OnImportCallbacks } from '@/types/importer';
2
+ import { UserSettings } from '@/types/user/settings';
3
+
4
+ export interface IImportService {
5
+ importData(data: ImporterEntryData, callbacks?: OnImportCallbacks): Promise<void>;
6
+ importSettings(settings: UserSettings): Promise<void>;
7
+ }