@lobehub/lobehub 2.0.0-next.38 → 2.0.0-next.39

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 (103) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/apps/desktop/src/main/modules/networkProxy/__tests__/dispatcher.test.ts +401 -0
  3. package/apps/desktop/src/main/modules/networkProxy/__tests__/tester.test.ts +531 -0
  4. package/apps/desktop/src/main/modules/networkProxy/__tests__/urlBuilder.test.ts +349 -0
  5. package/apps/desktop/src/main/modules/networkProxy/__tests__/validator.test.ts +492 -0
  6. package/changelog/v1.json +5 -0
  7. package/locales/ar/auth.json +45 -1
  8. package/locales/bg-BG/auth.json +45 -1
  9. package/locales/de-DE/auth.json +45 -1
  10. package/locales/en-US/auth.json +45 -1
  11. package/locales/es-ES/auth.json +45 -1
  12. package/locales/fa-IR/auth.json +45 -1
  13. package/locales/fr-FR/auth.json +45 -1
  14. package/locales/it-IT/auth.json +45 -1
  15. package/locales/ja-JP/auth.json +45 -1
  16. package/locales/ko-KR/auth.json +45 -1
  17. package/locales/nl-NL/auth.json +45 -1
  18. package/locales/pl-PL/auth.json +45 -1
  19. package/locales/pt-BR/auth.json +45 -1
  20. package/locales/ru-RU/auth.json +45 -1
  21. package/locales/tr-TR/auth.json +45 -1
  22. package/locales/vi-VN/auth.json +45 -1
  23. package/locales/zh-CN/auth.json +45 -1
  24. package/locales/zh-TW/auth.json +45 -1
  25. package/package.json +1 -1
  26. package/packages/context-engine/src/processors/MessageCleanup.ts +1 -0
  27. package/packages/context-engine/src/processors/__tests__/MessageCleanup.test.ts +28 -0
  28. package/packages/obervability-otel/package.json +3 -1
  29. package/packages/obervability-otel/src/api.ts +2 -0
  30. package/packages/obervability-otel/src/trpc/convention.ts +16 -0
  31. package/packages/obervability-otel/src/trpc/index.test.ts +38 -0
  32. package/packages/obervability-otel/src/trpc/index.ts +62 -0
  33. package/packages/obervability-otel/src/trpc/metrics.ts +31 -0
  34. package/packages/types/src/usage/usageRecord.ts +54 -0
  35. package/src/app/[variants]/(main)/profile/hooks/useCategory.tsx +10 -1
  36. package/src/app/[variants]/(main)/profile/usage/Client.tsx +114 -0
  37. package/src/app/[variants]/(main)/profile/usage/features/UsageCards/ActiveModels/ModelTable.tsx +175 -0
  38. package/src/app/[variants]/(main)/profile/usage/features/UsageCards/ActiveModels/index.tsx +126 -0
  39. package/src/app/[variants]/(main)/profile/usage/features/UsageCards/MonthSpend.tsx +53 -0
  40. package/src/app/[variants]/(main)/profile/usage/features/UsageCards/TodaySpend.tsx +67 -0
  41. package/src/app/[variants]/(main)/profile/usage/features/UsageCards/index.tsx +19 -0
  42. package/src/app/[variants]/(main)/profile/usage/features/UsageTable.tsx +145 -0
  43. package/src/app/[variants]/(main)/profile/usage/features/UsageTrends.tsx +107 -0
  44. package/src/app/[variants]/(main)/profile/usage/features/components/UsageBarChart.tsx +48 -0
  45. package/src/app/[variants]/(main)/profile/usage/page.tsx +23 -0
  46. package/src/features/Conversation/Messages/Assistant/Tool/Render/CustomRender.tsx +3 -3
  47. package/src/features/Conversation/Messages/Group/Actions/WithoutContentId.tsx +37 -14
  48. package/src/features/Conversation/Messages/Group/Error/index.tsx +1 -1
  49. package/src/features/Conversation/Messages/Group/GroupChildren.tsx +13 -35
  50. package/src/features/Conversation/Messages/Group/GroupItem.tsx +43 -0
  51. package/src/features/Conversation/Messages/Group/Tool/Inspector/index.tsx +1 -2
  52. package/src/features/Conversation/Messages/Group/Tool/Render/CustomRender.tsx +1 -1
  53. package/src/features/Conversation/Messages/Group/Tool/index.tsx +0 -2
  54. package/src/features/Conversation/Messages/Group/index.tsx +7 -2
  55. package/src/features/Conversation/hooks/useChatListActionsBar.tsx +21 -7
  56. package/src/features/PluginsUI/Render/BuiltinType/index.tsx +1 -1
  57. package/src/features/PluginsUI/Render/MCPType/index.tsx +52 -0
  58. package/src/features/PluginsUI/Render/StandaloneType/Iframe.tsx +2 -2
  59. package/src/features/PluginsUI/Render/index.tsx +17 -0
  60. package/src/libs/mcp/client.ts +3 -2
  61. package/src/libs/mcp/types.ts +71 -0
  62. package/src/libs/trpc/lambda/index.ts +5 -2
  63. package/src/libs/trpc/middleware/openTelemetry.ts +141 -0
  64. package/src/locales/default/auth.ts +44 -0
  65. package/src/locales/default/chat.ts +1 -0
  66. package/src/server/routers/desktop/mcp.ts +1 -3
  67. package/src/server/routers/lambda/index.ts +2 -0
  68. package/src/server/routers/lambda/usage.ts +36 -0
  69. package/src/server/routers/tools/mcp.ts +1 -3
  70. package/src/server/services/mcp/index.test.ts +28 -15
  71. package/src/server/services/mcp/index.ts +29 -18
  72. package/src/server/services/usage/index.test.ts +310 -0
  73. package/src/server/services/usage/index.ts +164 -0
  74. package/src/services/chat/contextEngineering.test.ts +4 -0
  75. package/src/services/mcp.test.ts +7 -1
  76. package/src/services/mcp.ts +13 -12
  77. package/src/services/usage.ts +13 -0
  78. package/src/store/chat/agents/createAgentExecutors.ts +2 -3
  79. package/src/store/chat/slices/aiChat/actions/conversationLifecycle.ts +40 -1
  80. package/src/store/chat/slices/aiChat/actions/streamingExecutor.ts +13 -5
  81. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +3 -3
  82. package/src/store/chat/slices/builtinTool/actions/__tests__/search.test.ts +6 -6
  83. package/src/store/chat/slices/builtinTool/actions/interpreter.ts +2 -2
  84. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +2 -2
  85. package/src/store/chat/slices/builtinTool/actions/search.ts +6 -6
  86. package/src/store/chat/slices/message/actions/publicApi.ts +19 -1
  87. package/src/store/chat/slices/message/initialState.ts +5 -0
  88. package/src/store/chat/slices/message/selectors/chat.test.ts +22 -602
  89. package/src/store/chat/slices/message/selectors/chat.ts +0 -2
  90. package/src/store/chat/slices/message/selectors/dbMessage.test.ts +51 -0
  91. package/src/store/chat/slices/message/selectors/displayMessage.test.ts +818 -0
  92. package/src/store/chat/slices/message/selectors/displayMessage.ts +52 -1
  93. package/src/store/chat/slices/message/selectors/messageState.ts +2 -0
  94. package/src/store/chat/slices/plugin/action.test.ts +4 -4
  95. package/src/store/chat/slices/plugin/actions/index.ts +39 -0
  96. package/src/store/chat/slices/plugin/actions/internals.ts +83 -0
  97. package/src/store/chat/slices/plugin/actions/optimisticUpdate.ts +188 -0
  98. package/src/store/chat/slices/plugin/actions/pluginTypes.ts +213 -0
  99. package/src/store/chat/slices/plugin/actions/publicApi.ts +115 -0
  100. package/src/store/chat/slices/plugin/actions/workflow.ts +121 -0
  101. package/src/store/chat/store.ts +1 -1
  102. package/src/store/global/initialState.ts +1 -0
  103. package/src/store/chat/slices/plugin/action.ts +0 -539
@@ -0,0 +1,349 @@
1
+ import { NetworkProxySettings } from '@lobechat/electron-client-ipc';
2
+ import { describe, expect, it } from 'vitest';
3
+
4
+ import { ProxyUrlBuilder } from '../urlBuilder';
5
+
6
+ describe('ProxyUrlBuilder', () => {
7
+ const baseConfig: NetworkProxySettings = {
8
+ enableProxy: true,
9
+ proxyType: 'http',
10
+ proxyServer: 'proxy.example.com',
11
+ proxyPort: '8080',
12
+ proxyRequireAuth: false,
13
+ proxyBypass: 'localhost,127.0.0.1,::1',
14
+ };
15
+
16
+ describe('build', () => {
17
+ describe('without authentication', () => {
18
+ it('should build URL with http proxy type', () => {
19
+ const config: NetworkProxySettings = {
20
+ ...baseConfig,
21
+ proxyType: 'http',
22
+ };
23
+
24
+ const url = ProxyUrlBuilder.build(config);
25
+
26
+ expect(url).toBe('http://proxy.example.com:8080');
27
+ });
28
+
29
+ it('should build URL with https proxy type', () => {
30
+ const config: NetworkProxySettings = {
31
+ ...baseConfig,
32
+ proxyType: 'https',
33
+ };
34
+
35
+ const url = ProxyUrlBuilder.build(config);
36
+
37
+ expect(url).toBe('https://proxy.example.com:8080');
38
+ });
39
+
40
+ it('should build URL with socks5 proxy type', () => {
41
+ const config: NetworkProxySettings = {
42
+ ...baseConfig,
43
+ proxyType: 'socks5',
44
+ };
45
+
46
+ const url = ProxyUrlBuilder.build(config);
47
+
48
+ expect(url).toBe('socks5://proxy.example.com:8080');
49
+ });
50
+
51
+ it('should build URL with IPv4 address', () => {
52
+ const config: NetworkProxySettings = {
53
+ ...baseConfig,
54
+ proxyServer: '192.168.1.1',
55
+ };
56
+
57
+ const url = ProxyUrlBuilder.build(config);
58
+
59
+ expect(url).toBe('http://192.168.1.1:8080');
60
+ });
61
+
62
+ it('should build URL with localhost', () => {
63
+ const config: NetworkProxySettings = {
64
+ ...baseConfig,
65
+ proxyServer: 'localhost',
66
+ };
67
+
68
+ const url = ProxyUrlBuilder.build(config);
69
+
70
+ expect(url).toBe('http://localhost:8080');
71
+ });
72
+
73
+ it('should build URL with different port', () => {
74
+ const config: NetworkProxySettings = {
75
+ ...baseConfig,
76
+ proxyPort: '3128',
77
+ };
78
+
79
+ const url = ProxyUrlBuilder.build(config);
80
+
81
+ expect(url).toBe('http://proxy.example.com:3128');
82
+ });
83
+ });
84
+
85
+ describe('with authentication', () => {
86
+ it('should build URL with username and password', () => {
87
+ const config: NetworkProxySettings = {
88
+ ...baseConfig,
89
+ proxyRequireAuth: true,
90
+ proxyUsername: 'testuser',
91
+ proxyPassword: 'testpass',
92
+ };
93
+
94
+ const url = ProxyUrlBuilder.build(config);
95
+
96
+ expect(url).toBe('http://testuser:testpass@proxy.example.com:8080');
97
+ });
98
+
99
+ it('should build URL with encoded username containing @ symbol', () => {
100
+ const config: NetworkProxySettings = {
101
+ ...baseConfig,
102
+ proxyRequireAuth: true,
103
+ proxyUsername: 'user@domain.com',
104
+ proxyPassword: 'password',
105
+ };
106
+
107
+ const url = ProxyUrlBuilder.build(config);
108
+
109
+ expect(url).toBe('http://user%40domain.com:password@proxy.example.com:8080');
110
+ // Verify encoding
111
+ expect(url).toContain('user%40domain.com');
112
+ });
113
+
114
+ it('should build URL with encoded password containing colon', () => {
115
+ const config: NetworkProxySettings = {
116
+ ...baseConfig,
117
+ proxyRequireAuth: true,
118
+ proxyUsername: 'user',
119
+ proxyPassword: 'pass:word',
120
+ };
121
+
122
+ const url = ProxyUrlBuilder.build(config);
123
+
124
+ expect(url).toBe('http://user:pass%3Aword@proxy.example.com:8080');
125
+ // Verify encoding
126
+ expect(url).toContain('pass%3Aword');
127
+ });
128
+
129
+ it('should build URL with encoded special characters in username', () => {
130
+ const config: NetworkProxySettings = {
131
+ ...baseConfig,
132
+ proxyRequireAuth: true,
133
+ proxyUsername: 'user name',
134
+ proxyPassword: 'password',
135
+ };
136
+
137
+ const url = ProxyUrlBuilder.build(config);
138
+
139
+ expect(url).toBe('http://user%20name:password@proxy.example.com:8080');
140
+ // Verify encoding
141
+ expect(url).toContain('user%20name');
142
+ });
143
+
144
+ it('should build URL with encoded special characters in password', () => {
145
+ const config: NetworkProxySettings = {
146
+ ...baseConfig,
147
+ proxyRequireAuth: true,
148
+ proxyUsername: 'user',
149
+ proxyPassword: 'p@ss w0rd!',
150
+ };
151
+
152
+ const url = ProxyUrlBuilder.build(config);
153
+
154
+ // Verify encoding of special characters
155
+ expect(url).toContain(encodeURIComponent('p@ss w0rd!'));
156
+ expect(url).toContain('user:');
157
+ expect(url).toContain('@proxy.example.com:8080');
158
+ });
159
+
160
+ it('should build URL with encoded slash in credentials', () => {
161
+ const config: NetworkProxySettings = {
162
+ ...baseConfig,
163
+ proxyRequireAuth: true,
164
+ proxyUsername: 'domain/user',
165
+ proxyPassword: 'pass/word',
166
+ };
167
+
168
+ const url = ProxyUrlBuilder.build(config);
169
+
170
+ expect(url).toBe('http://domain%2Fuser:pass%2Fword@proxy.example.com:8080');
171
+ // Verify encoding
172
+ expect(url).toContain('domain%2Fuser');
173
+ expect(url).toContain('pass%2Fword');
174
+ });
175
+
176
+ it('should build URL with encoded hash in credentials', () => {
177
+ const config: NetworkProxySettings = {
178
+ ...baseConfig,
179
+ proxyRequireAuth: true,
180
+ proxyUsername: 'user#123',
181
+ proxyPassword: 'pass#word',
182
+ };
183
+
184
+ const url = ProxyUrlBuilder.build(config);
185
+
186
+ expect(url).toBe('http://user%23123:pass%23word@proxy.example.com:8080');
187
+ // Verify encoding
188
+ expect(url).toContain('user%23123');
189
+ expect(url).toContain('pass%23word');
190
+ });
191
+
192
+ it('should build URL with encoded question mark in credentials', () => {
193
+ const config: NetworkProxySettings = {
194
+ ...baseConfig,
195
+ proxyRequireAuth: true,
196
+ proxyUsername: 'user?name',
197
+ proxyPassword: 'pass?word',
198
+ };
199
+
200
+ const url = ProxyUrlBuilder.build(config);
201
+
202
+ expect(url).toBe('http://user%3Fname:pass%3Fword@proxy.example.com:8080');
203
+ // Verify encoding
204
+ expect(url).toContain('user%3Fname');
205
+ expect(url).toContain('pass%3Fword');
206
+ });
207
+
208
+ it('should build URL with https proxy type and auth', () => {
209
+ const config: NetworkProxySettings = {
210
+ ...baseConfig,
211
+ proxyType: 'https',
212
+ proxyRequireAuth: true,
213
+ proxyUsername: 'testuser',
214
+ proxyPassword: 'testpass',
215
+ };
216
+
217
+ const url = ProxyUrlBuilder.build(config);
218
+
219
+ expect(url).toBe('https://testuser:testpass@proxy.example.com:8080');
220
+ });
221
+
222
+ it('should build URL with socks5 proxy type and auth', () => {
223
+ const config: NetworkProxySettings = {
224
+ ...baseConfig,
225
+ proxyType: 'socks5',
226
+ proxyRequireAuth: true,
227
+ proxyUsername: 'sockuser',
228
+ proxyPassword: 'sockpass',
229
+ };
230
+
231
+ const url = ProxyUrlBuilder.build(config);
232
+
233
+ expect(url).toBe('socks5://sockuser:sockpass@proxy.example.com:8080');
234
+ });
235
+ });
236
+
237
+ describe('edge cases', () => {
238
+ it('should not include auth when proxyRequireAuth is false but credentials are provided', () => {
239
+ const config: NetworkProxySettings = {
240
+ ...baseConfig,
241
+ proxyRequireAuth: false,
242
+ proxyUsername: 'testuser',
243
+ proxyPassword: 'testpass',
244
+ };
245
+
246
+ const url = ProxyUrlBuilder.build(config);
247
+
248
+ expect(url).toBe('http://proxy.example.com:8080');
249
+ expect(url).not.toContain('testuser');
250
+ expect(url).not.toContain('testpass');
251
+ });
252
+
253
+ it('should not include auth when username is empty', () => {
254
+ const config: NetworkProxySettings = {
255
+ ...baseConfig,
256
+ proxyRequireAuth: true,
257
+ proxyUsername: '',
258
+ proxyPassword: 'testpass',
259
+ };
260
+
261
+ const url = ProxyUrlBuilder.build(config);
262
+
263
+ expect(url).toBe('http://proxy.example.com:8080');
264
+ expect(url).not.toContain('@');
265
+ });
266
+
267
+ it('should not include auth when password is empty', () => {
268
+ const config: NetworkProxySettings = {
269
+ ...baseConfig,
270
+ proxyRequireAuth: true,
271
+ proxyUsername: 'testuser',
272
+ proxyPassword: '',
273
+ };
274
+
275
+ const url = ProxyUrlBuilder.build(config);
276
+
277
+ expect(url).toBe('http://proxy.example.com:8080');
278
+ expect(url).not.toContain('@');
279
+ });
280
+
281
+ it('should not include auth when username is undefined', () => {
282
+ const config: NetworkProxySettings = {
283
+ ...baseConfig,
284
+ proxyRequireAuth: true,
285
+ proxyUsername: undefined,
286
+ proxyPassword: 'testpass',
287
+ };
288
+
289
+ const url = ProxyUrlBuilder.build(config);
290
+
291
+ expect(url).toBe('http://proxy.example.com:8080');
292
+ expect(url).not.toContain('@');
293
+ });
294
+
295
+ it('should not include auth when password is undefined', () => {
296
+ const config: NetworkProxySettings = {
297
+ ...baseConfig,
298
+ proxyRequireAuth: true,
299
+ proxyUsername: 'testuser',
300
+ proxyPassword: undefined,
301
+ };
302
+
303
+ const url = ProxyUrlBuilder.build(config);
304
+
305
+ expect(url).toBe('http://proxy.example.com:8080');
306
+ expect(url).not.toContain('@');
307
+ });
308
+
309
+ it('should handle minimum port number', () => {
310
+ const config: NetworkProxySettings = {
311
+ ...baseConfig,
312
+ proxyPort: '1',
313
+ };
314
+
315
+ const url = ProxyUrlBuilder.build(config);
316
+
317
+ expect(url).toBe('http://proxy.example.com:1');
318
+ });
319
+
320
+ it('should handle maximum port number', () => {
321
+ const config: NetworkProxySettings = {
322
+ ...baseConfig,
323
+ proxyPort: '65535',
324
+ };
325
+
326
+ const url = ProxyUrlBuilder.build(config);
327
+
328
+ expect(url).toBe('http://proxy.example.com:65535');
329
+ });
330
+
331
+ it('should handle complex URL encoding scenario', () => {
332
+ const config: NetworkProxySettings = {
333
+ ...baseConfig,
334
+ proxyRequireAuth: true,
335
+ proxyUsername: 'user@example.com:admin',
336
+ proxyPassword: 'p@ss:w0rd#123',
337
+ };
338
+
339
+ const url = ProxyUrlBuilder.build(config);
340
+
341
+ // Verify all special characters are encoded
342
+ const expectedUsername = encodeURIComponent('user@example.com:admin');
343
+ const expectedPassword = encodeURIComponent('p@ss:w0rd#123');
344
+
345
+ expect(url).toBe(`http://${expectedUsername}:${expectedPassword}@proxy.example.com:8080`);
346
+ });
347
+ });
348
+ });
349
+ });