stream-chat-react-native-core 9.0.2-beta.2 → 9.1.0-beta.1

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 (212) hide show
  1. package/lib/commonjs/components/Attachment/Attachment.js +38 -10
  2. package/lib/commonjs/components/Attachment/Attachment.js.map +1 -1
  3. package/lib/commonjs/components/Attachment/AttachmentFileUploadProgressIndicator.js +97 -0
  4. package/lib/commonjs/components/Attachment/AttachmentFileUploadProgressIndicator.js.map +1 -0
  5. package/lib/commonjs/components/Attachment/AttachmentUploadIndicator.js +97 -0
  6. package/lib/commonjs/components/Attachment/AttachmentUploadIndicator.js.map +1 -0
  7. package/lib/commonjs/components/Attachment/CircularProgressIndicator.js +141 -0
  8. package/lib/commonjs/components/Attachment/CircularProgressIndicator.js.map +1 -0
  9. package/lib/commonjs/components/Attachment/FileAttachment.js +18 -4
  10. package/lib/commonjs/components/Attachment/FileAttachment.js.map +1 -1
  11. package/lib/commonjs/components/Attachment/Gallery.js +7 -1
  12. package/lib/commonjs/components/Attachment/Gallery.js.map +1 -1
  13. package/lib/commonjs/components/Attachment/MediaUploadProgressOverlay.js +59 -0
  14. package/lib/commonjs/components/Attachment/MediaUploadProgressOverlay.js.map +1 -0
  15. package/lib/commonjs/components/Attachment/VideoThumbnail.js +18 -8
  16. package/lib/commonjs/components/Attachment/VideoThumbnail.js.map +1 -1
  17. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js +2 -0
  18. package/lib/commonjs/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  19. package/lib/commonjs/components/Channel/Channel.js +94 -92
  20. package/lib/commonjs/components/Channel/Channel.js.map +1 -1
  21. package/lib/commonjs/components/Chat/Chat.js +10 -1
  22. package/lib/commonjs/components/Chat/Chat.js.map +1 -1
  23. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.js +42 -54
  24. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.js.map +1 -1
  25. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js +10 -6
  26. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js.map +1 -1
  27. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.js +12 -6
  28. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.js.map +1 -1
  29. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js +13 -7
  30. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js.map +1 -1
  31. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js +6 -2
  32. package/lib/commonjs/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js.map +1 -1
  33. package/lib/commonjs/components/index.js +33 -0
  34. package/lib/commonjs/components/index.js.map +1 -1
  35. package/lib/commonjs/contexts/componentsContext/defaultComponents.js +6 -0
  36. package/lib/commonjs/contexts/componentsContext/defaultComponents.js.map +1 -1
  37. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +3 -1
  38. package/lib/commonjs/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  39. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.js +4 -1
  40. package/lib/commonjs/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.js.map +1 -1
  41. package/lib/commonjs/contexts/themeContext/utils/theme.js +5 -0
  42. package/lib/commonjs/contexts/themeContext/utils/theme.js.map +1 -1
  43. package/lib/commonjs/hooks/index.js +11 -0
  44. package/lib/commonjs/hooks/index.js.map +1 -1
  45. package/lib/commonjs/hooks/usePendingAttachmentUpload.js +106 -0
  46. package/lib/commonjs/hooks/usePendingAttachmentUpload.js.map +1 -0
  47. package/lib/commonjs/index.js +12 -0
  48. package/lib/commonjs/index.js.map +1 -1
  49. package/lib/commonjs/middlewares/attachments.js +2 -0
  50. package/lib/commonjs/middlewares/attachments.js.map +1 -1
  51. package/lib/commonjs/native.js +8 -1
  52. package/lib/commonjs/native.js.map +1 -1
  53. package/lib/commonjs/nativeMultipartUpload.js +237 -0
  54. package/lib/commonjs/nativeMultipartUpload.js.map +1 -0
  55. package/lib/commonjs/types/types.js.map +1 -1
  56. package/lib/commonjs/utils/installNativeMultipartAdapter.js +223 -0
  57. package/lib/commonjs/utils/installNativeMultipartAdapter.js.map +1 -0
  58. package/lib/commonjs/utils/utils.js +2 -2
  59. package/lib/commonjs/utils/utils.js.map +1 -1
  60. package/lib/commonjs/version.json +1 -1
  61. package/lib/module/components/Attachment/Attachment.js +38 -10
  62. package/lib/module/components/Attachment/Attachment.js.map +1 -1
  63. package/lib/module/components/Attachment/AttachmentFileUploadProgressIndicator.js +97 -0
  64. package/lib/module/components/Attachment/AttachmentFileUploadProgressIndicator.js.map +1 -0
  65. package/lib/module/components/Attachment/AttachmentUploadIndicator.js +97 -0
  66. package/lib/module/components/Attachment/AttachmentUploadIndicator.js.map +1 -0
  67. package/lib/module/components/Attachment/CircularProgressIndicator.js +141 -0
  68. package/lib/module/components/Attachment/CircularProgressIndicator.js.map +1 -0
  69. package/lib/module/components/Attachment/FileAttachment.js +18 -4
  70. package/lib/module/components/Attachment/FileAttachment.js.map +1 -1
  71. package/lib/module/components/Attachment/Gallery.js +7 -1
  72. package/lib/module/components/Attachment/Gallery.js.map +1 -1
  73. package/lib/module/components/Attachment/MediaUploadProgressOverlay.js +59 -0
  74. package/lib/module/components/Attachment/MediaUploadProgressOverlay.js.map +1 -0
  75. package/lib/module/components/Attachment/VideoThumbnail.js +18 -8
  76. package/lib/module/components/Attachment/VideoThumbnail.js.map +1 -1
  77. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js +2 -0
  78. package/lib/module/components/Attachment/utils/buildGallery/buildThumbnail.js.map +1 -1
  79. package/lib/module/components/Channel/Channel.js +94 -92
  80. package/lib/module/components/Channel/Channel.js.map +1 -1
  81. package/lib/module/components/Chat/Chat.js +10 -1
  82. package/lib/module/components/Chat/Chat.js.map +1 -1
  83. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.js +42 -54
  84. package/lib/module/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.js.map +1 -1
  85. package/lib/module/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js +10 -6
  86. package/lib/module/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.js.map +1 -1
  87. package/lib/module/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.js +12 -6
  88. package/lib/module/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.js.map +1 -1
  89. package/lib/module/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js +13 -7
  90. package/lib/module/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.js.map +1 -1
  91. package/lib/module/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js +6 -2
  92. package/lib/module/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.js.map +1 -1
  93. package/lib/module/components/index.js +33 -0
  94. package/lib/module/components/index.js.map +1 -1
  95. package/lib/module/contexts/componentsContext/defaultComponents.js +6 -0
  96. package/lib/module/contexts/componentsContext/defaultComponents.js.map +1 -1
  97. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js +3 -1
  98. package/lib/module/contexts/messageInputContext/hooks/useCreateMessageInputContext.js.map +1 -1
  99. package/lib/module/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.js +4 -1
  100. package/lib/module/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.js.map +1 -1
  101. package/lib/module/contexts/themeContext/utils/theme.js +5 -0
  102. package/lib/module/contexts/themeContext/utils/theme.js.map +1 -1
  103. package/lib/module/hooks/index.js +11 -0
  104. package/lib/module/hooks/index.js.map +1 -1
  105. package/lib/module/hooks/usePendingAttachmentUpload.js +106 -0
  106. package/lib/module/hooks/usePendingAttachmentUpload.js.map +1 -0
  107. package/lib/module/index.js +12 -0
  108. package/lib/module/index.js.map +1 -1
  109. package/lib/module/middlewares/attachments.js +2 -0
  110. package/lib/module/middlewares/attachments.js.map +1 -1
  111. package/lib/module/native.js +8 -1
  112. package/lib/module/native.js.map +1 -1
  113. package/lib/module/nativeMultipartUpload.js +237 -0
  114. package/lib/module/nativeMultipartUpload.js.map +1 -0
  115. package/lib/module/types/types.js.map +1 -1
  116. package/lib/module/utils/installNativeMultipartAdapter.js +223 -0
  117. package/lib/module/utils/installNativeMultipartAdapter.js.map +1 -0
  118. package/lib/module/utils/utils.js +2 -2
  119. package/lib/module/utils/utils.js.map +1 -1
  120. package/lib/module/version.json +1 -1
  121. package/lib/typescript/components/Attachment/Attachment.d.ts.map +1 -1
  122. package/lib/typescript/components/Attachment/AttachmentFileUploadProgressIndicator.d.ts +14 -0
  123. package/lib/typescript/components/Attachment/AttachmentFileUploadProgressIndicator.d.ts.map +1 -0
  124. package/lib/typescript/components/Attachment/AttachmentUploadIndicator.d.ts +18 -0
  125. package/lib/typescript/components/Attachment/AttachmentUploadIndicator.d.ts.map +1 -0
  126. package/lib/typescript/components/Attachment/CircularProgressIndicator.d.ts +18 -0
  127. package/lib/typescript/components/Attachment/CircularProgressIndicator.d.ts.map +1 -0
  128. package/lib/typescript/components/Attachment/FileAttachment.d.ts.map +1 -1
  129. package/lib/typescript/components/Attachment/Gallery.d.ts.map +1 -1
  130. package/lib/typescript/components/Attachment/MediaUploadProgressOverlay.d.ts +12 -0
  131. package/lib/typescript/components/Attachment/MediaUploadProgressOverlay.d.ts.map +1 -0
  132. package/lib/typescript/components/Attachment/VideoThumbnail.d.ts +4 -0
  133. package/lib/typescript/components/Attachment/VideoThumbnail.d.ts.map +1 -1
  134. package/lib/typescript/components/Attachment/utils/buildGallery/buildThumbnail.d.ts.map +1 -1
  135. package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts +2 -0
  136. package/lib/typescript/components/Attachment/utils/buildGallery/types.d.ts.map +1 -1
  137. package/lib/typescript/components/Channel/Channel.d.ts.map +1 -1
  138. package/lib/typescript/components/Chat/Chat.d.ts +10 -0
  139. package/lib/typescript/components/Chat/Chat.d.ts.map +1 -1
  140. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.d.ts +7 -2
  141. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.d.ts.map +1 -1
  142. package/lib/typescript/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.d.ts.map +1 -1
  143. package/lib/typescript/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.d.ts.map +1 -1
  144. package/lib/typescript/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.d.ts.map +1 -1
  145. package/lib/typescript/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.d.ts.map +1 -1
  146. package/lib/typescript/components/index.d.ts +3 -0
  147. package/lib/typescript/components/index.d.ts.map +1 -1
  148. package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts +5 -2
  149. package/lib/typescript/contexts/componentsContext/defaultComponents.d.ts.map +1 -1
  150. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts +1 -1
  151. package/lib/typescript/contexts/messageInputContext/hooks/useCreateMessageInputContext.d.ts.map +1 -1
  152. package/lib/typescript/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.d.ts.map +1 -1
  153. package/lib/typescript/contexts/themeContext/ThemeContext.d.ts +5 -0
  154. package/lib/typescript/contexts/themeContext/ThemeContext.d.ts.map +1 -1
  155. package/lib/typescript/contexts/themeContext/utils/theme.d.ts +5 -0
  156. package/lib/typescript/contexts/themeContext/utils/theme.d.ts.map +1 -1
  157. package/lib/typescript/hooks/index.d.ts +1 -0
  158. package/lib/typescript/hooks/index.d.ts.map +1 -1
  159. package/lib/typescript/hooks/usePendingAttachmentUpload.d.ts +14 -0
  160. package/lib/typescript/hooks/usePendingAttachmentUpload.d.ts.map +1 -0
  161. package/lib/typescript/index.d.ts +1 -0
  162. package/lib/typescript/index.d.ts.map +1 -1
  163. package/lib/typescript/middlewares/attachments.d.ts.map +1 -1
  164. package/lib/typescript/native.d.ts +5 -2
  165. package/lib/typescript/native.d.ts.map +1 -1
  166. package/lib/typescript/nativeMultipartUpload.d.ts +98 -0
  167. package/lib/typescript/nativeMultipartUpload.d.ts.map +1 -0
  168. package/lib/typescript/types/types.d.ts +2 -0
  169. package/lib/typescript/types/types.d.ts.map +1 -1
  170. package/lib/typescript/utils/installNativeMultipartAdapter.d.ts +8 -0
  171. package/lib/typescript/utils/installNativeMultipartAdapter.d.ts.map +1 -0
  172. package/lib/typescript/utils/utils.d.ts +1 -1
  173. package/lib/typescript/utils/utils.d.ts.map +1 -1
  174. package/package.json +2 -2
  175. package/src/__tests__/nativeMultipartUpload.test.ts +267 -0
  176. package/src/components/Attachment/Attachment.tsx +54 -5
  177. package/src/components/Attachment/AttachmentFileUploadProgressIndicator.tsx +108 -0
  178. package/src/components/Attachment/AttachmentUploadIndicator.tsx +112 -0
  179. package/src/components/Attachment/CircularProgressIndicator.tsx +161 -0
  180. package/src/components/Attachment/FileAttachment.tsx +22 -6
  181. package/src/components/Attachment/Gallery.tsx +9 -1
  182. package/src/components/Attachment/MediaUploadProgressOverlay.tsx +77 -0
  183. package/src/components/Attachment/VideoThumbnail.tsx +17 -9
  184. package/src/components/Attachment/__tests__/Attachment.test.tsx +63 -16
  185. package/src/components/Attachment/utils/buildGallery/buildThumbnail.ts +3 -0
  186. package/src/components/Attachment/utils/buildGallery/types.ts +2 -0
  187. package/src/components/Channel/Channel.tsx +65 -61
  188. package/src/components/Chat/Chat.tsx +20 -0
  189. package/src/components/MessageInput/__tests__/AttachmentUploadPreviewList.test.tsx +51 -6
  190. package/src/components/MessageInput/__tests__/AudioAttachmentUploadPreview.test.tsx +31 -1
  191. package/src/components/MessageInput/components/AttachmentPreview/AttachmentUploadProgressIndicator.tsx +30 -44
  192. package/src/components/MessageInput/components/AttachmentPreview/AudioAttachmentUploadPreview.tsx +11 -5
  193. package/src/components/MessageInput/components/AttachmentPreview/FileAttachmentUploadPreview.tsx +20 -5
  194. package/src/components/MessageInput/components/AttachmentPreview/ImageAttachmentUploadPreview.tsx +20 -9
  195. package/src/components/MessageInput/components/AttachmentPreview/VideoAttachmentUploadPreview.tsx +7 -1
  196. package/src/components/index.ts +3 -0
  197. package/src/contexts/componentsContext/defaultComponents.ts +6 -0
  198. package/src/contexts/messageInputContext/hooks/useCreateMessageInputContext.ts +3 -1
  199. package/src/contexts/messageInputContext/hooks/useMessageComposerHasSendableData.ts +5 -1
  200. package/src/contexts/themeContext/utils/theme.ts +10 -0
  201. package/src/hooks/__tests__/usePendingAttachmentUpload.test.tsx +106 -0
  202. package/src/hooks/index.ts +1 -0
  203. package/src/hooks/usePendingAttachmentUpload.ts +131 -0
  204. package/src/index.ts +1 -0
  205. package/src/middlewares/attachments.ts +2 -0
  206. package/src/native.ts +28 -0
  207. package/src/nativeMultipartUpload.ts +384 -0
  208. package/src/types/types.ts +2 -0
  209. package/src/utils/__tests__/installNativeMultipartAdapter.test.ts +437 -0
  210. package/src/utils/installNativeMultipartAdapter.ts +302 -0
  211. package/src/utils/utils.ts +3 -3
  212. package/src/version.json +1 -1
@@ -0,0 +1,437 @@
1
+ import type { AxiosProgressEvent, AxiosRequestConfig } from 'axios';
2
+
3
+ import { getTestClient } from '../../mock-builders/mock';
4
+ import { NativeHandlers, NativeMultipartUploadProgressConfig } from '../../native';
5
+ import {
6
+ installNativeMultipartAdapter,
7
+ wrapAxiosAdapterWithNativeMultipart,
8
+ } from '../installNativeMultipartAdapter';
9
+
10
+ type NativeMultipartTestAxiosConfig = AxiosRequestConfig & {
11
+ uploadProgress?: (event: AxiosProgressEvent) => void;
12
+ uploadProgressOptions?: NativeMultipartUploadProgressConfig;
13
+ };
14
+
15
+ const nativeMultipartConfig = (config: NativeMultipartTestAxiosConfig) => config;
16
+
17
+ describe('installNativeMultipartAdapter', () => {
18
+ const originalMultipartUpload = NativeHandlers.multipartUpload;
19
+
20
+ beforeEach(() => {
21
+ NativeHandlers.multipartUpload = jest.fn().mockResolvedValue({
22
+ body: JSON.stringify({ file: 'https://example.com/file.jpg' }),
23
+ headers: { 'content-type': 'application/json' },
24
+ status: 200,
25
+ statusText: 'OK',
26
+ });
27
+ });
28
+
29
+ const preserveRequestData = (client: ReturnType<typeof getTestClient>) => {
30
+ client.axiosInstance.defaults.transformRequest = [(data) => data];
31
+ };
32
+
33
+ afterEach(() => {
34
+ NativeHandlers.multipartUpload = originalMultipartUpload;
35
+ jest.clearAllMocks();
36
+ });
37
+
38
+ it('routes multipart requests through the native handler', async () => {
39
+ const client = getTestClient();
40
+ preserveRequestData(client);
41
+ const defaultAdapter = jest.fn().mockResolvedValue({
42
+ config: {},
43
+ data: 'default',
44
+ headers: {},
45
+ status: 200,
46
+ statusText: 'OK',
47
+ });
48
+
49
+ client.axiosInstance.defaults.adapter = defaultAdapter;
50
+
51
+ installNativeMultipartAdapter(client);
52
+ const formData = {
53
+ _parts: [
54
+ [
55
+ 'file',
56
+ {
57
+ name: 'test.jpg',
58
+ type: 'image/jpeg',
59
+ uri: 'file:///tmp/test.jpg',
60
+ },
61
+ ],
62
+ ['user', JSON.stringify({ id: 'john' })],
63
+ ],
64
+ };
65
+
66
+ const response = await client.axiosInstance.post('/uploads/image', formData, {
67
+ headers: {
68
+ Authorization: 'token',
69
+ 'Content-Type': 'multipart/form-data',
70
+ 'X-Stream-Client': 'stream-test',
71
+ },
72
+ params: {
73
+ api_key: 'test-key',
74
+ },
75
+ timeout: 1234,
76
+ });
77
+
78
+ expect(defaultAdapter).not.toHaveBeenCalled();
79
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalledWith(
80
+ expect.objectContaining({
81
+ headers: expect.objectContaining({
82
+ Authorization: 'token',
83
+ 'Content-Type': 'multipart/form-data',
84
+ 'X-Stream-Client': 'stream-test',
85
+ }),
86
+ timeoutMs: 1234,
87
+ parts: [
88
+ {
89
+ fieldName: 'file',
90
+ fileName: 'test.jpg',
91
+ kind: 'file',
92
+ mimeType: 'image/jpeg',
93
+ uri: 'file:///tmp/test.jpg',
94
+ },
95
+ {
96
+ fieldName: 'user',
97
+ kind: 'text',
98
+ value: JSON.stringify({ id: 'john' }),
99
+ },
100
+ ],
101
+ }),
102
+ );
103
+ expect(response.status).toBe(200);
104
+ });
105
+
106
+ it('leaves non-multipart requests on the fallback adapter', async () => {
107
+ const client = getTestClient();
108
+ preserveRequestData(client);
109
+ const defaultAdapter = jest.fn().mockResolvedValue({
110
+ config: {},
111
+ data: 'default',
112
+ headers: {},
113
+ status: 200,
114
+ statusText: 'OK',
115
+ });
116
+
117
+ client.axiosInstance.defaults.adapter = defaultAdapter;
118
+
119
+ installNativeMultipartAdapter(client);
120
+
121
+ await client.axiosInstance.post('/messages', { text: 'hello' });
122
+
123
+ expect(defaultAdapter).toHaveBeenCalled();
124
+ expect(NativeHandlers.multipartUpload).not.toHaveBeenCalled();
125
+ });
126
+
127
+ it('forwards native upload progress to axios upload progress callbacks', async () => {
128
+ NativeHandlers.multipartUpload = jest.fn().mockImplementation(({ onProgress }) => {
129
+ onProgress?.({
130
+ loaded: '50' as unknown as number,
131
+ total: '100' as unknown as number,
132
+ });
133
+
134
+ return {
135
+ body: JSON.stringify({ file: 'https://example.com/file.jpg' }),
136
+ headers: { 'content-type': 'application/json' },
137
+ status: 200,
138
+ statusText: 'OK',
139
+ };
140
+ });
141
+
142
+ const client = getTestClient();
143
+ preserveRequestData(client);
144
+ installNativeMultipartAdapter(client);
145
+ const onUploadProgress = jest.fn();
146
+ const uploadProgress = jest.fn();
147
+ const formData = {
148
+ _parts: [
149
+ [
150
+ 'file',
151
+ {
152
+ name: 'test.jpg',
153
+ type: 'image/jpeg',
154
+ uri: 'file:///tmp/test.jpg',
155
+ },
156
+ ],
157
+ ],
158
+ };
159
+
160
+ await client.axiosInstance.post(
161
+ '/uploads/image',
162
+ formData,
163
+ nativeMultipartConfig({
164
+ onUploadProgress,
165
+ uploadProgressOptions: {
166
+ count: 10,
167
+ intervalMs: 25,
168
+ },
169
+ uploadProgress,
170
+ }),
171
+ );
172
+
173
+ expect(onUploadProgress).toHaveBeenCalledWith(
174
+ expect.objectContaining({
175
+ lengthComputable: true,
176
+ loaded: 50,
177
+ progress: 0.5,
178
+ total: 100,
179
+ }),
180
+ );
181
+ expect(uploadProgress).toHaveBeenCalledWith(
182
+ expect.objectContaining({
183
+ lengthComputable: true,
184
+ loaded: 50,
185
+ progress: 0.5,
186
+ total: 100,
187
+ }),
188
+ );
189
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalledWith(
190
+ expect.objectContaining({
191
+ progress: {
192
+ count: 10,
193
+ intervalMs: 25,
194
+ },
195
+ }),
196
+ );
197
+ });
198
+
199
+ it('caps native multipart body progress to 90 percent while waiting for the response', async () => {
200
+ NativeHandlers.multipartUpload = jest.fn().mockImplementation(({ onProgress }) => {
201
+ onProgress?.({
202
+ loaded: 100,
203
+ total: 100,
204
+ });
205
+
206
+ return {
207
+ body: JSON.stringify({ file: 'https://example.com/file.jpg' }),
208
+ headers: { 'content-type': 'application/json' },
209
+ status: 200,
210
+ statusText: 'OK',
211
+ };
212
+ });
213
+
214
+ const client = getTestClient();
215
+ preserveRequestData(client);
216
+ installNativeMultipartAdapter(client);
217
+ const onUploadProgress = jest.fn();
218
+ const formData = {
219
+ _parts: [
220
+ [
221
+ 'file',
222
+ {
223
+ name: 'test.jpg',
224
+ type: 'image/jpeg',
225
+ uri: 'file:///tmp/test.jpg',
226
+ },
227
+ ],
228
+ ],
229
+ };
230
+
231
+ await client.axiosInstance.post('/uploads/image', formData, { onUploadProgress });
232
+
233
+ expect(onUploadProgress).toHaveBeenCalledTimes(1);
234
+ expect(onUploadProgress).toHaveBeenCalledWith(
235
+ expect.objectContaining({
236
+ bytes: 90,
237
+ lengthComputable: true,
238
+ loaded: 90,
239
+ progress: 0.9,
240
+ total: 100,
241
+ }),
242
+ );
243
+ });
244
+
245
+ it('allows overriding the native multipart completion progress cap', async () => {
246
+ NativeHandlers.multipartUpload = jest.fn().mockImplementation(({ onProgress }) => {
247
+ onProgress?.({
248
+ loaded: 100,
249
+ total: 100,
250
+ });
251
+
252
+ return {
253
+ body: JSON.stringify({ file: 'https://example.com/file.jpg' }),
254
+ headers: { 'content-type': 'application/json' },
255
+ status: 200,
256
+ statusText: 'OK',
257
+ };
258
+ });
259
+
260
+ const client = getTestClient();
261
+ preserveRequestData(client);
262
+ installNativeMultipartAdapter(client);
263
+ const onUploadProgress = jest.fn();
264
+ const formData = {
265
+ _parts: [
266
+ [
267
+ 'file',
268
+ {
269
+ name: 'test.jpg',
270
+ type: 'image/jpeg',
271
+ uri: 'file:///tmp/test.jpg',
272
+ },
273
+ ],
274
+ ],
275
+ };
276
+
277
+ await client.axiosInstance.post(
278
+ '/uploads/image',
279
+ formData,
280
+ nativeMultipartConfig({
281
+ onUploadProgress,
282
+ uploadProgressOptions: {
283
+ completionProgressCap: 75,
284
+ count: 10,
285
+ intervalMs: 25,
286
+ },
287
+ }),
288
+ );
289
+
290
+ expect(onUploadProgress).toHaveBeenCalledTimes(1);
291
+ expect(onUploadProgress).toHaveBeenCalledWith(
292
+ expect.objectContaining({
293
+ bytes: 75,
294
+ loaded: 75,
295
+ progress: 0.75,
296
+ total: 100,
297
+ }),
298
+ );
299
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalledWith(
300
+ expect.objectContaining({
301
+ progress: {
302
+ count: 10,
303
+ intervalMs: 25,
304
+ },
305
+ }),
306
+ );
307
+ });
308
+
309
+ it('uses the final config after user request interceptors run', async () => {
310
+ const client = getTestClient();
311
+ preserveRequestData(client);
312
+ const defaultAdapter = jest.fn().mockResolvedValue({
313
+ config: {},
314
+ data: 'default',
315
+ headers: {},
316
+ status: 200,
317
+ statusText: 'OK',
318
+ });
319
+
320
+ client.axiosInstance.defaults.adapter = defaultAdapter;
321
+
322
+ const interceptorId = client.axiosInstance.interceptors.request.use((config) => {
323
+ config.headers.set('X-CDN-Route', 'custom-cdn');
324
+ config.url = '/uploads/file';
325
+ return config;
326
+ });
327
+
328
+ installNativeMultipartAdapter(client);
329
+ const formData = {
330
+ _parts: [
331
+ [
332
+ 'file',
333
+ {
334
+ name: 'test.jpg',
335
+ type: 'image/jpeg',
336
+ uri: 'file:///tmp/test.jpg',
337
+ },
338
+ ],
339
+ ],
340
+ };
341
+
342
+ await client.axiosInstance.post('/uploads/image', formData, {
343
+ headers: {
344
+ Authorization: 'token',
345
+ },
346
+ });
347
+
348
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalledWith(
349
+ expect.objectContaining({
350
+ headers: expect.objectContaining({
351
+ Authorization: 'token',
352
+ 'X-CDN-Route': 'custom-cdn',
353
+ }),
354
+ url: expect.stringContaining('/uploads/file'),
355
+ }),
356
+ );
357
+ expect(defaultAdapter).not.toHaveBeenCalled();
358
+
359
+ client.axiosInstance.interceptors.request.eject(interceptorId);
360
+ });
361
+
362
+ it('installs only once per client', async () => {
363
+ const client = getTestClient();
364
+ preserveRequestData(client);
365
+ const defaultAdapter = jest.fn().mockResolvedValue({
366
+ config: {},
367
+ data: 'default',
368
+ headers: {},
369
+ status: 200,
370
+ statusText: 'OK',
371
+ });
372
+
373
+ client.axiosInstance.defaults.adapter = defaultAdapter;
374
+
375
+ installNativeMultipartAdapter(client);
376
+ const installedAdapter = client.axiosInstance.defaults.adapter;
377
+ installNativeMultipartAdapter(client);
378
+
379
+ const formData = {
380
+ _parts: [
381
+ [
382
+ 'file',
383
+ {
384
+ name: 'test.jpg',
385
+ type: 'image/jpeg',
386
+ uri: 'file:///tmp/test.jpg',
387
+ },
388
+ ],
389
+ ],
390
+ };
391
+
392
+ await client.axiosInstance.post('/uploads/image', formData);
393
+
394
+ expect(client.axiosInstance.defaults.adapter).toBe(installedAdapter);
395
+ expect(defaultAdapter).not.toHaveBeenCalled();
396
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalled();
397
+ });
398
+
399
+ it('composes explicitly with a custom adapter', async () => {
400
+ const client = getTestClient();
401
+ preserveRequestData(client);
402
+ const customAdapter = jest.fn().mockResolvedValue({
403
+ config: {},
404
+ data: 'custom',
405
+ headers: {},
406
+ status: 200,
407
+ statusText: 'OK',
408
+ });
409
+
410
+ client.axiosInstance.defaults.adapter = wrapAxiosAdapterWithNativeMultipart(
411
+ client,
412
+ customAdapter,
413
+ );
414
+
415
+ const multipartFormData = {
416
+ _parts: [
417
+ [
418
+ 'file',
419
+ {
420
+ name: 'test.jpg',
421
+ type: 'image/jpeg',
422
+ uri: 'file:///tmp/test.jpg',
423
+ },
424
+ ],
425
+ ],
426
+ };
427
+
428
+ await client.axiosInstance.post('/uploads/image', multipartFormData);
429
+
430
+ expect(NativeHandlers.multipartUpload).toHaveBeenCalled();
431
+ expect(customAdapter).not.toHaveBeenCalled();
432
+
433
+ await client.axiosInstance.post('/messages', { text: 'hello' });
434
+
435
+ expect(customAdapter).toHaveBeenCalled();
436
+ });
437
+ });