@lobehub/lobehub 2.0.0-next.186 → 2.0.0-next.188

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 (140) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/locales/ar/models.json +89 -5
  4. package/locales/ar/plugin.json +5 -0
  5. package/locales/ar/providers.json +1 -0
  6. package/locales/bg-BG/models.json +68 -0
  7. package/locales/bg-BG/plugin.json +5 -0
  8. package/locales/bg-BG/providers.json +1 -0
  9. package/locales/de-DE/models.json +85 -0
  10. package/locales/de-DE/plugin.json +5 -0
  11. package/locales/de-DE/providers.json +1 -0
  12. package/locales/en-US/models.json +11 -10
  13. package/locales/en-US/plugin.json +5 -0
  14. package/locales/en-US/providers.json +1 -0
  15. package/locales/es-ES/models.json +72 -0
  16. package/locales/es-ES/plugin.json +5 -0
  17. package/locales/es-ES/providers.json +1 -0
  18. package/locales/fa-IR/models.json +86 -0
  19. package/locales/fa-IR/plugin.json +5 -0
  20. package/locales/fa-IR/providers.json +1 -0
  21. package/locales/fr-FR/models.json +49 -0
  22. package/locales/fr-FR/plugin.json +5 -0
  23. package/locales/fr-FR/providers.json +1 -0
  24. package/locales/it-IT/models.json +82 -0
  25. package/locales/it-IT/plugin.json +5 -0
  26. package/locales/it-IT/providers.json +1 -0
  27. package/locales/ja-JP/models.json +42 -5
  28. package/locales/ja-JP/plugin.json +5 -0
  29. package/locales/ja-JP/providers.json +1 -0
  30. package/locales/ko-KR/models.json +54 -0
  31. package/locales/ko-KR/plugin.json +5 -0
  32. package/locales/ko-KR/providers.json +1 -0
  33. package/locales/nl-NL/models.json +12 -1
  34. package/locales/nl-NL/plugin.json +5 -0
  35. package/locales/nl-NL/providers.json +1 -0
  36. package/locales/pl-PL/models.json +46 -0
  37. package/locales/pl-PL/plugin.json +5 -0
  38. package/locales/pl-PL/providers.json +1 -0
  39. package/locales/pt-BR/models.json +59 -0
  40. package/locales/pt-BR/plugin.json +5 -0
  41. package/locales/pt-BR/providers.json +1 -0
  42. package/locales/ru-RU/models.json +85 -0
  43. package/locales/ru-RU/plugin.json +5 -0
  44. package/locales/ru-RU/providers.json +1 -0
  45. package/locales/tr-TR/models.json +81 -0
  46. package/locales/tr-TR/plugin.json +5 -0
  47. package/locales/tr-TR/providers.json +1 -0
  48. package/locales/vi-VN/models.json +54 -0
  49. package/locales/vi-VN/plugin.json +5 -0
  50. package/locales/vi-VN/providers.json +1 -0
  51. package/locales/zh-CN/models.json +42 -5
  52. package/locales/zh-CN/plugin.json +5 -0
  53. package/locales/zh-CN/providers.json +1 -0
  54. package/locales/zh-TW/models.json +85 -0
  55. package/locales/zh-TW/plugin.json +5 -0
  56. package/locales/zh-TW/providers.json +1 -0
  57. package/package.json +1 -1
  58. package/packages/builtin-tool-gtd/src/manifest.ts +13 -8
  59. package/packages/builtin-tool-gtd/src/systemRole.ts +54 -19
  60. package/packages/builtin-tool-knowledge-base/package.json +1 -0
  61. package/packages/builtin-tool-knowledge-base/src/client/Inspector/ReadKnowledge/index.tsx +97 -0
  62. package/packages/builtin-tool-knowledge-base/src/client/Inspector/SearchKnowledgeBase/index.tsx +75 -0
  63. package/packages/builtin-tool-knowledge-base/src/client/Inspector/index.ts +11 -0
  64. package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/FileCard.tsx +12 -12
  65. package/packages/builtin-tool-knowledge-base/src/client/Render/ReadKnowledge/index.tsx +16 -25
  66. package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/Item/index.tsx +21 -47
  67. package/packages/builtin-tool-knowledge-base/src/client/Render/SearchKnowledgeBase/index.tsx +19 -31
  68. package/packages/builtin-tool-knowledge-base/src/client/Render/index.ts +0 -5
  69. package/packages/builtin-tool-knowledge-base/src/client/index.ts +5 -1
  70. package/packages/builtin-tool-knowledge-base/src/executor/index.ts +119 -0
  71. package/packages/builtin-tool-local-system/package.json +1 -0
  72. package/packages/builtin-tool-local-system/src/client/Inspector/EditLocalFile/index.tsx +44 -29
  73. package/packages/builtin-tool-local-system/src/client/Inspector/GrepContent/index.tsx +20 -18
  74. package/packages/builtin-tool-local-system/src/client/Inspector/ListLocalFiles/index.tsx +76 -0
  75. package/packages/builtin-tool-local-system/src/client/Inspector/ReadLocalFile/index.tsx +8 -32
  76. package/packages/builtin-tool-local-system/src/client/Inspector/RenameLocalFile/index.tsx +62 -0
  77. package/packages/builtin-tool-local-system/src/client/Inspector/SearchLocalFiles/index.tsx +17 -11
  78. package/packages/builtin-tool-local-system/src/client/Inspector/WriteLocalFile/index.tsx +61 -0
  79. package/packages/builtin-tool-local-system/src/client/Inspector/index.ts +6 -0
  80. package/packages/builtin-tool-local-system/src/client/Render/EditLocalFile/index.tsx +6 -1
  81. package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/SearchView.tsx +19 -31
  82. package/packages/builtin-tool-local-system/src/client/Render/SearchFiles/SearchQuery/index.tsx +2 -42
  83. package/packages/builtin-tool-local-system/src/client/Render/index.ts +0 -2
  84. package/packages/builtin-tool-local-system/src/client/components/FilePathDisplay.tsx +56 -0
  85. package/packages/builtin-tool-local-system/src/client/components/index.ts +2 -0
  86. package/packages/builtin-tool-local-system/src/executor/index.ts +435 -0
  87. package/packages/builtin-tool-web-browsing/src/client/Inspector/Search/index.tsx +32 -5
  88. package/packages/fetch-sse/src/__tests__/request.test.ts +608 -0
  89. package/packages/model-bank/src/aiModels/aihubmix.ts +44 -8
  90. package/packages/model-bank/src/aiModels/google.ts +49 -17
  91. package/packages/model-bank/src/aiModels/hunyuan.ts +20 -0
  92. package/packages/model-bank/src/aiModels/infiniai.ts +48 -7
  93. package/packages/model-bank/src/aiModels/lobehub.ts +13 -11
  94. package/packages/model-bank/src/aiModels/minimax.ts +46 -2
  95. package/packages/model-bank/src/aiModels/ollamacloud.ts +40 -5
  96. package/packages/model-bank/src/aiModels/openai.ts +6 -3
  97. package/packages/model-bank/src/aiModels/qwen.ts +1 -1
  98. package/packages/model-bank/src/aiModels/siliconcloud.ts +60 -0
  99. package/packages/model-bank/src/aiModels/vertexai.ts +77 -44
  100. package/packages/model-bank/src/aiModels/volcengine.ts +111 -2
  101. package/packages/model-bank/src/aiModels/zenmux.ts +19 -13
  102. package/packages/model-bank/src/aiModels/zhipu.ts +64 -2
  103. package/packages/model-bank/src/types/aiModel.ts +3 -0
  104. package/packages/model-runtime/src/core/contextBuilders/google.test.ts +84 -0
  105. package/packages/model-runtime/src/core/contextBuilders/google.ts +37 -1
  106. package/packages/model-runtime/src/providers/volcengine/index.ts +2 -1
  107. package/packages/model-runtime/src/providers/zhipu/index.test.ts +0 -27
  108. package/packages/model-runtime/src/providers/zhipu/index.ts +1 -1
  109. package/packages/model-runtime/src/utils/modelParse.ts +26 -21
  110. package/packages/types/src/agent/chatConfig.ts +6 -2
  111. package/src/features/ChatInput/ActionBar/Model/ControlsForm.tsx +40 -1
  112. package/src/features/ChatInput/ActionBar/Model/GPT52ProReasoningEffortSlider.tsx +59 -0
  113. package/src/features/ChatInput/ActionBar/Model/GPT52ReasoningEffortSlider.tsx +61 -0
  114. package/src/features/ChatInput/ActionBar/Model/TextVerbositySlider.tsx +1 -1
  115. package/src/features/ChatInput/ActionBar/Model/ThinkingLevel2Slider.tsx +58 -0
  116. package/src/features/ChatInput/ActionBar/Model/ThinkingLevelSlider.tsx +10 -8
  117. package/src/helpers/toolEngineering/index.ts +1 -1
  118. package/src/locales/default/plugin.ts +6 -0
  119. package/src/server/modules/Mecha/AgentToolsEngine/__tests__/index.test.ts +1 -1
  120. package/src/server/modules/Mecha/AgentToolsEngine/index.ts +1 -1
  121. package/src/services/chat/mecha/modelParamsResolver.ts +11 -0
  122. package/src/store/chat/slices/builtinTool/actions/index.ts +1 -11
  123. package/src/store/tool/slices/builtin/executors/index.ts +4 -0
  124. package/src/styles/text.ts +1 -1
  125. package/src/tools/executionRuntimes.ts +3 -8
  126. package/src/tools/identifiers.ts +1 -1
  127. package/src/tools/index.ts +1 -1
  128. package/src/tools/inspectors.ts +5 -0
  129. package/src/tools/renders.ts +6 -12
  130. package/packages/builtin-tool-local-system/src/client/Render/RenameLocalFile/index.tsx +0 -37
  131. package/src/store/chat/slices/builtinTool/actions/__tests__/localSystem.test.ts +0 -201
  132. package/src/store/chat/slices/builtinTool/actions/knowledgeBase.ts +0 -163
  133. package/src/store/chat/slices/builtinTool/actions/localSystem.ts +0 -241
  134. package/src/tools/knowledge-base/ExecutionRuntime/index.ts +0 -25
  135. package/src/tools/knowledge-base/Render/ReadKnowledge/index.tsx +0 -29
  136. package/src/tools/knowledge-base/Render/SearchKnowledgeBase/index.tsx +0 -29
  137. package/src/tools/knowledge-base/Render/index.ts +0 -7
  138. package/src/tools/knowledge-base/index.ts +0 -12
  139. package/src/tools/local-system/ExecutionRuntime/index.ts +0 -9
  140. package/src/tools/local-system/systemRole.ts +0 -1
@@ -0,0 +1,608 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+
3
+ import { getRequestBody } from '../request';
4
+
5
+ describe('getRequestBody', () => {
6
+ describe('undefined or null input', () => {
7
+ it('should return undefined when body is undefined', async () => {
8
+ // Arrange & Act
9
+ const result = await getRequestBody(undefined);
10
+
11
+ // Assert
12
+ expect(result).toBeUndefined();
13
+ });
14
+
15
+ it('should return undefined when body is null', async () => {
16
+ // Arrange & Act
17
+ const result = await getRequestBody(null);
18
+
19
+ // Assert
20
+ expect(result).toBeUndefined();
21
+ });
22
+
23
+ it('should return undefined when body is not provided', async () => {
24
+ // Arrange & Act
25
+ const result = await getRequestBody();
26
+
27
+ // Assert
28
+ expect(result).toBeUndefined();
29
+ });
30
+ });
31
+
32
+ describe('string input', () => {
33
+ it('should return string body as-is', async () => {
34
+ // Arrange
35
+ const body = 'test string body';
36
+
37
+ // Act
38
+ const result = await getRequestBody(body);
39
+
40
+ // Assert
41
+ expect(result).toBe('test string body');
42
+ expect(typeof result).toBe('string');
43
+ });
44
+
45
+ it('should return undefined for empty string (falsy check)', async () => {
46
+ // Arrange
47
+ const body = '';
48
+
49
+ // Act
50
+ const result = await getRequestBody(body);
51
+
52
+ // Assert
53
+ // Empty string is falsy, so the function returns undefined
54
+ expect(result).toBeUndefined();
55
+ });
56
+
57
+ it('should handle JSON string', async () => {
58
+ // Arrange
59
+ const body = JSON.stringify({ key: 'value', number: 123 });
60
+
61
+ // Act
62
+ const result = await getRequestBody(body);
63
+
64
+ // Assert
65
+ expect(result).toBe('{"key":"value","number":123}');
66
+ expect(typeof result).toBe('string');
67
+ });
68
+
69
+ it('should handle string with special characters', async () => {
70
+ // Arrange
71
+ const body = 'test\nstring\twith\rspecial\u0000chars';
72
+
73
+ // Act
74
+ const result = await getRequestBody(body);
75
+
76
+ // Assert
77
+ expect(result).toBe('test\nstring\twith\rspecial\u0000chars');
78
+ });
79
+
80
+ it('should handle very long string', async () => {
81
+ // Arrange
82
+ const body = 'a'.repeat(10000);
83
+
84
+ // Act
85
+ const result = await getRequestBody(body);
86
+
87
+ // Assert
88
+ expect(result).toBe(body);
89
+ expect(typeof result).toBe('string');
90
+ });
91
+ });
92
+
93
+ describe('ArrayBuffer input', () => {
94
+ it('should return ArrayBuffer as-is', async () => {
95
+ // Arrange
96
+ const buffer = new ArrayBuffer(8);
97
+ const view = new Uint8Array(buffer);
98
+ view[0] = 65; // 'A'
99
+ view[1] = 66; // 'B'
100
+
101
+ // Act
102
+ const result = await getRequestBody(buffer);
103
+
104
+ // Assert
105
+ expect(result).toBe(buffer);
106
+ expect(result).toBeInstanceOf(ArrayBuffer);
107
+ expect((result as ArrayBuffer).byteLength).toBe(8);
108
+ });
109
+
110
+ it('should handle empty ArrayBuffer', async () => {
111
+ // Arrange
112
+ const buffer = new ArrayBuffer(0);
113
+
114
+ // Act
115
+ const result = await getRequestBody(buffer);
116
+
117
+ // Assert
118
+ expect(result).toBe(buffer);
119
+ expect(result).toBeInstanceOf(ArrayBuffer);
120
+ expect((result as ArrayBuffer).byteLength).toBe(0);
121
+ });
122
+
123
+ it('should handle large ArrayBuffer', async () => {
124
+ // Arrange
125
+ const buffer = new ArrayBuffer(1024 * 1024); // 1MB
126
+
127
+ // Act
128
+ const result = await getRequestBody(buffer);
129
+
130
+ // Assert
131
+ expect(result).toBe(buffer);
132
+ expect((result as ArrayBuffer).byteLength).toBe(1024 * 1024);
133
+ });
134
+ });
135
+
136
+ describe('ArrayBufferView input (TypedArrays)', () => {
137
+ it('should convert Uint8Array to sliced ArrayBuffer', async () => {
138
+ // Arrange
139
+ const buffer = new ArrayBuffer(16);
140
+ const uint8View = new Uint8Array(buffer, 4, 8); // offset: 4, length: 8
141
+ uint8View[0] = 65;
142
+ uint8View[1] = 66;
143
+
144
+ // Act
145
+ const result = await getRequestBody(uint8View);
146
+
147
+ // Assert
148
+ expect(result).toBeInstanceOf(ArrayBuffer);
149
+ expect((result as ArrayBuffer).byteLength).toBe(8);
150
+ expect(result).not.toBe(buffer); // Should be a new sliced buffer
151
+
152
+ // Verify the sliced data
153
+ const resultView = new Uint8Array(result as ArrayBuffer);
154
+ expect(resultView[0]).toBe(65);
155
+ expect(resultView[1]).toBe(66);
156
+ });
157
+
158
+ it('should convert Uint16Array to sliced ArrayBuffer', async () => {
159
+ // Arrange
160
+ const buffer = new ArrayBuffer(32);
161
+ const uint16View = new Uint16Array(buffer, 8, 4); // offset: 8 bytes, length: 4 elements
162
+ uint16View[0] = 256;
163
+ uint16View[1] = 512;
164
+
165
+ // Act
166
+ const result = await getRequestBody(uint16View);
167
+
168
+ // Assert
169
+ expect(result).toBeInstanceOf(ArrayBuffer);
170
+ expect((result as ArrayBuffer).byteLength).toBe(8); // 4 elements * 2 bytes
171
+ expect(result).not.toBe(buffer);
172
+
173
+ // Verify data
174
+ const resultView = new Uint16Array(result as ArrayBuffer);
175
+ expect(resultView[0]).toBe(256);
176
+ expect(resultView[1]).toBe(512);
177
+ });
178
+
179
+ it('should convert Int32Array to sliced ArrayBuffer', async () => {
180
+ // Arrange
181
+ const buffer = new ArrayBuffer(64);
182
+ const int32View = new Int32Array(buffer, 16, 8); // offset: 16 bytes, length: 8 elements
183
+ int32View[0] = -12345;
184
+ int32View[7] = 67890;
185
+
186
+ // Act
187
+ const result = await getRequestBody(int32View);
188
+
189
+ // Assert
190
+ expect(result).toBeInstanceOf(ArrayBuffer);
191
+ expect((result as ArrayBuffer).byteLength).toBe(32); // 8 elements * 4 bytes
192
+ expect(result).not.toBe(buffer);
193
+
194
+ // Verify data
195
+ const resultView = new Int32Array(result as ArrayBuffer);
196
+ expect(resultView[0]).toBe(-12345);
197
+ expect(resultView[7]).toBe(67890);
198
+ });
199
+
200
+ it('should convert Float32Array to sliced ArrayBuffer', async () => {
201
+ // Arrange
202
+ const buffer = new ArrayBuffer(40);
203
+ const float32View = new Float32Array(buffer, 4, 5);
204
+ float32View[0] = 3.14159;
205
+ float32View[4] = 2.71828;
206
+
207
+ // Act
208
+ const result = await getRequestBody(float32View);
209
+
210
+ // Assert
211
+ expect(result).toBeInstanceOf(ArrayBuffer);
212
+ expect((result as ArrayBuffer).byteLength).toBe(20); // 5 elements * 4 bytes
213
+
214
+ const resultView = new Float32Array(result as ArrayBuffer);
215
+ expect(resultView[0]).toBeCloseTo(3.14159);
216
+ expect(resultView[4]).toBeCloseTo(2.71828);
217
+ });
218
+
219
+ it('should convert DataView to sliced ArrayBuffer', async () => {
220
+ // Arrange
221
+ const buffer = new ArrayBuffer(24);
222
+ const dataView = new DataView(buffer, 8, 8); // offset: 8, length: 8
223
+ dataView.setUint8(0, 65);
224
+ dataView.setUint8(1, 66);
225
+
226
+ // Act
227
+ const result = await getRequestBody(dataView);
228
+
229
+ // Assert
230
+ expect(result).toBeInstanceOf(ArrayBuffer);
231
+ expect((result as ArrayBuffer).byteLength).toBe(8);
232
+
233
+ const resultView = new Uint8Array(result as ArrayBuffer);
234
+ expect(resultView[0]).toBe(65);
235
+ expect(resultView[1]).toBe(66);
236
+ });
237
+
238
+ it('should handle TypedArray with zero offset', async () => {
239
+ // Arrange
240
+ const buffer = new ArrayBuffer(16);
241
+ const uint8View = new Uint8Array(buffer, 0, 16);
242
+ uint8View[0] = 100;
243
+
244
+ // Act
245
+ const result = await getRequestBody(uint8View);
246
+
247
+ // Assert
248
+ expect(result).toBeInstanceOf(ArrayBuffer);
249
+ expect((result as ArrayBuffer).byteLength).toBe(16);
250
+
251
+ const resultView = new Uint8Array(result as ArrayBuffer);
252
+ expect(resultView[0]).toBe(100);
253
+ });
254
+
255
+ it('should handle empty TypedArray', async () => {
256
+ // Arrange
257
+ const buffer = new ArrayBuffer(16);
258
+ const uint8View = new Uint8Array(buffer, 8, 0); // zero length
259
+
260
+ // Act
261
+ const result = await getRequestBody(uint8View);
262
+
263
+ // Assert
264
+ expect(result).toBeInstanceOf(ArrayBuffer);
265
+ expect((result as ArrayBuffer).byteLength).toBe(0);
266
+ });
267
+ });
268
+
269
+ describe('Blob input', () => {
270
+ it('should convert Blob to ArrayBuffer', async () => {
271
+ // Arrange
272
+ const blobData = 'test blob content';
273
+ const blob = new Blob([blobData], { type: 'text/plain' });
274
+
275
+ // Act
276
+ const result = await getRequestBody(blob);
277
+
278
+ // Assert
279
+ expect(result).toBeInstanceOf(ArrayBuffer);
280
+
281
+ // Verify content
282
+ const decoder = new TextDecoder();
283
+ const text = decoder.decode(result as ArrayBuffer);
284
+ expect(text).toBe('test blob content');
285
+ });
286
+
287
+ it('should convert Blob with binary data', async () => {
288
+ // Arrange
289
+ const uint8Array = new Uint8Array([72, 101, 108, 108, 111]); // "Hello"
290
+ const blob = new Blob([uint8Array], { type: 'application/octet-stream' });
291
+
292
+ // Act
293
+ const result = await getRequestBody(blob);
294
+
295
+ // Assert
296
+ expect(result).toBeInstanceOf(ArrayBuffer);
297
+
298
+ const decoder = new TextDecoder();
299
+ const text = decoder.decode(result as ArrayBuffer);
300
+ expect(text).toBe('Hello');
301
+ });
302
+
303
+ it('should handle empty Blob', async () => {
304
+ // Arrange
305
+ const blob = new Blob([], { type: 'text/plain' });
306
+
307
+ // Act
308
+ const result = await getRequestBody(blob);
309
+
310
+ // Assert
311
+ expect(result).toBeInstanceOf(ArrayBuffer);
312
+ expect((result as ArrayBuffer).byteLength).toBe(0);
313
+ });
314
+
315
+ it('should convert File (subclass of Blob)', async () => {
316
+ // Arrange
317
+ const fileContent = 'file content';
318
+ const file = new File([fileContent], 'test.txt', { type: 'text/plain' });
319
+
320
+ // Act
321
+ const result = await getRequestBody(file);
322
+
323
+ // Assert
324
+ expect(result).toBeInstanceOf(ArrayBuffer);
325
+
326
+ const decoder = new TextDecoder();
327
+ const text = decoder.decode(result as ArrayBuffer);
328
+ expect(text).toBe('file content');
329
+ });
330
+
331
+ it('should handle Blob with multiple chunks', async () => {
332
+ // Arrange
333
+ const blob = new Blob(['chunk1', 'chunk2', 'chunk3'], { type: 'text/plain' });
334
+
335
+ // Act
336
+ const result = await getRequestBody(blob);
337
+
338
+ // Assert
339
+ expect(result).toBeInstanceOf(ArrayBuffer);
340
+
341
+ const decoder = new TextDecoder();
342
+ const text = decoder.decode(result as ArrayBuffer);
343
+ expect(text).toBe('chunk1chunk2chunk3');
344
+ });
345
+
346
+ it('should handle large Blob', async () => {
347
+ // Arrange
348
+ const largeData = 'x'.repeat(100000);
349
+ const blob = new Blob([largeData], { type: 'text/plain' });
350
+
351
+ // Act
352
+ const result = await getRequestBody(blob);
353
+
354
+ // Assert
355
+ expect(result).toBeInstanceOf(ArrayBuffer);
356
+ expect((result as ArrayBuffer).byteLength).toBe(100000);
357
+ });
358
+ });
359
+
360
+ describe('Unsupported types', () => {
361
+ it('should throw error for FormData', async () => {
362
+ // Arrange
363
+ const formData = new FormData();
364
+ formData.append('key', 'value');
365
+
366
+ // Spy on console.warn
367
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
368
+
369
+ // Act & Assert
370
+ await expect(getRequestBody(formData as any)).rejects.toThrow(
371
+ 'Unsupported IPC proxy request body type',
372
+ );
373
+
374
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'object');
375
+
376
+ // Cleanup
377
+ warnSpy.mockRestore();
378
+ });
379
+
380
+ it('should throw error for URLSearchParams', async () => {
381
+ // Arrange
382
+ const params = new URLSearchParams({ key: 'value' });
383
+
384
+ // Spy on console.warn
385
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
386
+
387
+ // Act & Assert
388
+ await expect(getRequestBody(params as any)).rejects.toThrow(
389
+ 'Unsupported IPC proxy request body type',
390
+ );
391
+
392
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'object');
393
+
394
+ // Cleanup
395
+ warnSpy.mockRestore();
396
+ });
397
+
398
+ it('should throw error for ReadableStream', async () => {
399
+ // Arrange
400
+ const stream = new ReadableStream({
401
+ start(controller) {
402
+ controller.enqueue('test');
403
+ controller.close();
404
+ },
405
+ });
406
+
407
+ // Spy on console.warn
408
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
409
+
410
+ // Act & Assert
411
+ await expect(getRequestBody(stream as any)).rejects.toThrow(
412
+ 'Unsupported IPC proxy request body type',
413
+ );
414
+
415
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'object');
416
+
417
+ // Cleanup
418
+ warnSpy.mockRestore();
419
+ });
420
+
421
+ it('should throw error for plain object', async () => {
422
+ // Arrange
423
+ const obj = { key: 'value' };
424
+
425
+ // Spy on console.warn
426
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
427
+
428
+ // Act & Assert
429
+ await expect(getRequestBody(obj as any)).rejects.toThrow(
430
+ 'Unsupported IPC proxy request body type',
431
+ );
432
+
433
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'object');
434
+
435
+ // Cleanup
436
+ warnSpy.mockRestore();
437
+ });
438
+
439
+ it('should throw error for number', async () => {
440
+ // Arrange
441
+ const num = 123;
442
+
443
+ // Spy on console.warn
444
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
445
+
446
+ // Act & Assert
447
+ await expect(getRequestBody(num as any)).rejects.toThrow(
448
+ 'Unsupported IPC proxy request body type',
449
+ );
450
+
451
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'number');
452
+
453
+ // Cleanup
454
+ warnSpy.mockRestore();
455
+ });
456
+
457
+ it('should throw error for boolean', async () => {
458
+ // Arrange
459
+ const bool = true;
460
+
461
+ // Spy on console.warn
462
+ const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
463
+
464
+ // Act & Assert
465
+ await expect(getRequestBody(bool as any)).rejects.toThrow(
466
+ 'Unsupported IPC proxy request body type',
467
+ );
468
+
469
+ expect(warnSpy).toHaveBeenCalledWith('Unsupported IPC proxy request body type:', 'boolean');
470
+
471
+ // Cleanup
472
+ warnSpy.mockRestore();
473
+ });
474
+ });
475
+
476
+ describe('Edge cases', () => {
477
+ it('should handle Uint8Array from actual buffer slice', async () => {
478
+ // Arrange - simulate real-world scenario where buffer is sliced
479
+ const originalBuffer = new ArrayBuffer(100);
480
+ const originalView = new Uint8Array(originalBuffer);
481
+ originalView.fill(42);
482
+
483
+ const slicedView = new Uint8Array(originalBuffer, 20, 30);
484
+
485
+ // Act
486
+ const result = await getRequestBody(slicedView);
487
+
488
+ // Assert
489
+ expect(result).toBeInstanceOf(ArrayBuffer);
490
+ expect((result as ArrayBuffer).byteLength).toBe(30);
491
+
492
+ const resultView = new Uint8Array(result as ArrayBuffer);
493
+ expect(resultView.every((byte) => byte === 42)).toBe(true);
494
+ });
495
+
496
+ it('should preserve binary data integrity through TypedArray conversion', async () => {
497
+ // Arrange
498
+ const buffer = new ArrayBuffer(8);
499
+ const view = new Uint8Array(buffer);
500
+ // Set specific binary pattern
501
+ view[0] = 0xff;
502
+ view[1] = 0x00;
503
+ view[2] = 0xaa;
504
+ view[3] = 0x55;
505
+ view[4] = 0x12;
506
+ view[5] = 0x34;
507
+ view[6] = 0x56;
508
+ view[7] = 0x78;
509
+
510
+ // Act
511
+ const result = await getRequestBody(view);
512
+
513
+ // Assert
514
+ const resultView = new Uint8Array(result as ArrayBuffer);
515
+ expect(resultView[0]).toBe(0xff);
516
+ expect(resultView[1]).toBe(0x00);
517
+ expect(resultView[2]).toBe(0xaa);
518
+ expect(resultView[3]).toBe(0x55);
519
+ expect(resultView[4]).toBe(0x12);
520
+ expect(resultView[5]).toBe(0x34);
521
+ expect(resultView[6]).toBe(0x56);
522
+ expect(resultView[7]).toBe(0x78);
523
+ });
524
+
525
+ it('should handle Blob with non-ASCII characters', async () => {
526
+ // Arrange
527
+ const unicodeText = 'Hello 世界 🌍 مرحبا';
528
+ const blob = new Blob([unicodeText], { type: 'text/plain;charset=utf-8' });
529
+
530
+ // Act
531
+ const result = await getRequestBody(blob);
532
+
533
+ // Assert
534
+ expect(result).toBeInstanceOf(ArrayBuffer);
535
+
536
+ const decoder = new TextDecoder('utf-8');
537
+ const text = decoder.decode(result as ArrayBuffer);
538
+ expect(text).toBe('Hello 世界 🌍 مرحبا');
539
+ });
540
+ });
541
+
542
+ describe('Real-world scenarios', () => {
543
+ it('should handle JSON API request body', async () => {
544
+ // Arrange
545
+ const apiPayload = JSON.stringify({
546
+ model: 'gpt-4',
547
+ messages: [{ role: 'user', content: 'Hello' }],
548
+ stream: true,
549
+ });
550
+
551
+ // Act
552
+ const result = await getRequestBody(apiPayload);
553
+
554
+ // Assert
555
+ expect(typeof result).toBe('string');
556
+ expect(result).toBe(apiPayload);
557
+ });
558
+
559
+ it('should handle file upload as Blob', async () => {
560
+ // Arrange
561
+ const imageData = new Uint8Array([
562
+ 0x89,
563
+ 0x50,
564
+ 0x4e,
565
+ 0x47,
566
+ 0x0d,
567
+ 0x0a,
568
+ 0x1a,
569
+ 0x0a, // PNG header
570
+ ]);
571
+ const imageBlob = new Blob([imageData], { type: 'image/png' });
572
+
573
+ // Act
574
+ const result = await getRequestBody(imageBlob);
575
+
576
+ // Assert
577
+ expect(result).toBeInstanceOf(ArrayBuffer);
578
+ const resultView = new Uint8Array(result as ArrayBuffer);
579
+ expect(resultView[0]).toBe(0x89);
580
+ expect(resultView[1]).toBe(0x50);
581
+ expect(resultView[2]).toBe(0x4e);
582
+ expect(resultView[3]).toBe(0x47);
583
+ });
584
+
585
+ it('should handle binary protocol buffer data', async () => {
586
+ // Arrange
587
+ const protobufData = new Uint8Array([
588
+ 0x08, 0x96, 0x01, 0x12, 0x05, 0x48, 0x65, 0x6c, 0x6c, 0x6f,
589
+ ]);
590
+ const buffer = protobufData.buffer;
591
+
592
+ // Act
593
+ const result = await getRequestBody(buffer);
594
+
595
+ // Assert
596
+ expect(result).toBe(buffer);
597
+ expect(result).toBeInstanceOf(ArrayBuffer);
598
+ });
599
+
600
+ it('should handle empty request (no body)', async () => {
601
+ // Arrange & Act
602
+ const result = await getRequestBody();
603
+
604
+ // Assert
605
+ expect(result).toBeUndefined();
606
+ });
607
+ });
608
+ });