@uploadista/expo 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 uploadista
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,567 @@
1
+ # @uploadista/expo
2
+
3
+ Expo client for Uploadista - file uploads from mobile devices with Expo.
4
+
5
+ Provides Expo-specific implementations for file uploads, including:
6
+ - Direct file system access (async storage)
7
+ - Image picker and camera integration
8
+ - Optimized chunked uploads for mobile networks
9
+ - Resumable uploads with automatic retry
10
+
11
+ ## Features
12
+
13
+ - **Expo Native APIs** - Uses Expo's DocumentPicker, ImagePicker, MediaLibrary
14
+ - **Automatic Resumption** - Resume failed uploads without re-uploading
15
+ - **Chunked Uploads** - Configurable chunk sizes for reliable transfers
16
+ - **Mobile-Optimized** - Handles network interruptions gracefully
17
+ - **TypeScript Support** - Full type safety for all APIs
18
+ - **Storage Integration** - AsyncStorage for upload state persistence
19
+ - **Camera Support** - Direct camera capture and upload
20
+ - **Image Library** - Pick and upload images from device library
21
+
22
+ ## Installation
23
+
24
+ ```bash
25
+ pnpm add @uploadista/expo expo expo-document-picker expo-image-picker
26
+ # or
27
+ npm install @uploadista/expo expo expo-document-picker expo-image-picker
28
+ # or
29
+ yarn add @uploadista/expo expo expo-document-picker expo-image-picker
30
+ ```
31
+
32
+ ## Requirements
33
+
34
+ - React Native 0.60+
35
+ - Expo 46+
36
+ - iOS 11+ or Android 6+
37
+ - TypeScript 5.0+ (optional but recommended)
38
+
39
+ ## Quick Start
40
+
41
+ ### 1. Create Uploadista Client
42
+
43
+ ```typescript
44
+ import { createUploadistaClient } from '@uploadista/expo'
45
+
46
+ const client = createUploadistaClient({
47
+ baseUrl: 'https://api.example.com',
48
+ storageId: 'my-storage',
49
+ chunkSize: 1024 * 1024, // 1MB chunks
50
+ })
51
+ ```
52
+
53
+ ### 2. Pick and Upload File from Device
54
+
55
+ ```typescript
56
+ import { useUpload } from '@uploadista/expo'
57
+ import * as DocumentPicker from 'expo-document-picker'
58
+
59
+ export function FileUploadScreen() {
60
+ const { state, upload } = useUpload()
61
+
62
+ const handlePickFile = async () => {
63
+ const result = await DocumentPicker.getDocumentAsync()
64
+ if (result.type === 'success') {
65
+ await upload(result)
66
+ }
67
+ }
68
+
69
+ return (
70
+ <View>
71
+ <TouchableOpacity onPress={handlePickFile}>
72
+ <Text>Pick File</Text>
73
+ </TouchableOpacity>
74
+
75
+ {state.status === 'uploading' && (
76
+ <Text>Progress: {Math.round(state.progress)}%</Text>
77
+ )}
78
+ {state.status === 'success' && <Text>Upload Complete!</Text>}
79
+ {state.status === 'error' && <Text>Error: {state.error?.message}</Text>}
80
+ </View>
81
+ )
82
+ }
83
+ ```
84
+
85
+ ### 3. Upload from Camera
86
+
87
+ ```typescript
88
+ import { useUpload } from '@uploadista/expo'
89
+ import * as ImagePicker from 'expo-image-picker'
90
+
91
+ export function CameraUploadScreen() {
92
+ const { state, upload } = useUpload()
93
+
94
+ const handleTakePhoto = async () => {
95
+ const result = await ImagePicker.launchCameraAsync({
96
+ mediaTypes: 'Images',
97
+ quality: 0.8,
98
+ })
99
+
100
+ if (!result.canceled) {
101
+ await upload(result.assets[0])
102
+ }
103
+ }
104
+
105
+ return (
106
+ <View>
107
+ <TouchableOpacity onPress={handleTakePhoto}>
108
+ <Text>Take Photo</Text>
109
+ </TouchableOpacity>
110
+
111
+ {state.status === 'uploading' && (
112
+ <ProgressBar value={state.progress} max={100} />
113
+ )}
114
+ {state.status === 'success' && (
115
+ <Text>Photo uploaded: {state.result?.filename}</Text>
116
+ )}
117
+ </View>
118
+ )
119
+ }
120
+ ```
121
+
122
+ ### 4. Upload from Image Library
123
+
124
+ ```typescript
125
+ import { useUpload } from '@uploadista/expo'
126
+ import * as ImagePicker from 'expo-image-picker'
127
+
128
+ export function ImageLibraryUploadScreen() {
129
+ const { state, upload } = useUpload()
130
+
131
+ const handlePickImage = async () => {
132
+ const result = await ImagePicker.launchImageLibraryAsync({
133
+ mediaTypes: 'Images',
134
+ multiple: false,
135
+ })
136
+
137
+ if (!result.canceled) {
138
+ await upload(result.assets[0])
139
+ }
140
+ }
141
+
142
+ return (
143
+ <View>
144
+ <TouchableOpacity onPress={handlePickImage}>
145
+ <Text>Pick from Library</Text>
146
+ </TouchableOpacity>
147
+
148
+ {state.status === 'uploading' && (
149
+ <Text>Uploading: {state.bytesUploaded} / {state.totalBytes} bytes</Text>
150
+ )}
151
+ {state.status === 'success' && (
152
+ <Image source={{ uri: state.result?.filename }} />
153
+ )}
154
+ </View>
155
+ )
156
+ }
157
+ ```
158
+
159
+ ## API Reference
160
+
161
+ ### Client
162
+
163
+ #### `createUploadistaClient(options)`
164
+
165
+ Creates the Expo Uploadista client.
166
+
167
+ **Options:**
168
+ - `baseUrl` (string) - API base URL
169
+ - `storageId` (string) - Storage backend identifier
170
+ - `chunkSize` (number, optional) - Chunk size in bytes (default: 1MB)
171
+ - `concurrency` (number, optional) - Concurrent chunk uploads (default: 3)
172
+ - `maxRetries` (number, optional) - Max retries per chunk (default: 3)
173
+ - `timeout` (number, optional) - Request timeout in ms
174
+
175
+ **Returns:** UploadistaClient instance
176
+
177
+ ```typescript
178
+ const client = createUploadistaClient({
179
+ baseUrl: 'https://api.example.com',
180
+ storageId: 'my-storage',
181
+ chunkSize: 2 * 1024 * 1024, // 2MB chunks
182
+ concurrency: 4,
183
+ maxRetries: 5,
184
+ timeout: 30000,
185
+ })
186
+ ```
187
+
188
+ ### Composables
189
+
190
+ #### `useUpload(options?)`
191
+
192
+ Single file upload composable.
193
+
194
+ **Returns:**
195
+ - `state` - Upload state (readonly)
196
+ - `status` - 'idle' | 'uploading' | 'success' | 'error' | 'aborted'
197
+ - `progress` - Progress 0-100
198
+ - `bytesUploaded` - Bytes uploaded
199
+ - `totalBytes` - Total file size
200
+ - `result` - Upload result
201
+ - `error` - Error object
202
+ - `upload(file, options?)` - Upload file
203
+ - `abort()` - Cancel upload
204
+ - `reset()` - Reset to idle
205
+ - `retry()` - Retry failed upload
206
+
207
+ **Options:**
208
+ - `onProgress(event)` - Progress callback
209
+ - `onComplete(result)` - Success callback
210
+ - `onError(error)` - Error callback
211
+
212
+ ```typescript
213
+ const { state, upload, abort } = useUpload({
214
+ onProgress: (event) => console.log(event.progress + '%'),
215
+ onComplete: (result) => console.log('Uploaded:', result.filename),
216
+ onError: (error) => console.error('Upload failed:', error),
217
+ })
218
+
219
+ // Upload file
220
+ await upload(file)
221
+
222
+ // Cancel
223
+ abort()
224
+ ```
225
+
226
+ #### `useMultiUpload(options?)`
227
+
228
+ Multiple concurrent file uploads.
229
+
230
+ **Returns:**
231
+ - `uploads` - Array of upload items
232
+ - `stats` - Aggregate statistics
233
+ - `totalFiles` - Total files
234
+ - `completedFiles` - Successfully uploaded
235
+ - `failedFiles` - Failed uploads
236
+ - `totalBytes` - Total size
237
+ - `uploadedBytes` - Bytes uploaded
238
+ - `totalProgress` - Overall progress 0-100
239
+ - `allComplete` - All finished
240
+ - `hasErrors` - Any failures
241
+ - `add(files)` - Add files to queue
242
+ - `remove(uploadId)` - Remove upload
243
+ - `clear()` - Clear all
244
+ - `retryFailed()` - Retry failures
245
+
246
+ ```typescript
247
+ const { uploads, stats, add, retryFailed } = useMultiUpload()
248
+
249
+ // Add files
250
+ await add([file1, file2, file3])
251
+
252
+ // Monitor progress
253
+ console.log(`${stats.value.uploadedBytes} / ${stats.value.totalBytes}`)
254
+
255
+ // Retry on failure
256
+ if (stats.value.hasErrors) {
257
+ await retryFailed()
258
+ }
259
+ ```
260
+
261
+ ### Services
262
+
263
+ #### `createExpoServices(options?)`
264
+
265
+ Creates all Expo-specific services for the client.
266
+
267
+ **Returns:** Service container with implementations for:
268
+ - `fileReaderService` - Read file chunks
269
+ - `httpClient` - HTTP requests
270
+ - `storageService` - AsyncStorage persistence
271
+ - `base64Service` - Base64 encoding
272
+ - `idGenerationService` - ID generation
273
+ - `checksumService` - File hashing
274
+ - `websocketFactory` - WebSocket creation
275
+
276
+ ```typescript
277
+ import { createExpoServices } from '@uploadista/expo'
278
+ import { createUploadistaClientCore } from '@uploadista/client-core'
279
+
280
+ const services = createExpoServices({
281
+ asyncStorageKey: '@uploadista/uploads',
282
+ })
283
+
284
+ const client = createUploadistaClientCore({
285
+ endpoint: 'https://api.example.com',
286
+ services,
287
+ })
288
+ ```
289
+
290
+ #### File System Provider (Legacy)
291
+
292
+ ```typescript
293
+ import { ExpoFileSystemProvider } from '@uploadista/expo'
294
+
295
+ const provider = new ExpoFileSystemProvider()
296
+
297
+ // Pick image from camera
298
+ const photoResult = await provider.pickImage({ camera: true })
299
+
300
+ // Pick from library
301
+ const libraryResult = await provider.pickImage({ camera: false })
302
+
303
+ // Pick document
304
+ const documentResult = await provider.pickDocument()
305
+ ```
306
+
307
+ ## Configuration
308
+
309
+ ### Permissions
310
+
311
+ Add required permissions to `app.json`:
312
+
313
+ ```json
314
+ {
315
+ "expo": {
316
+ "plugins": [
317
+ [
318
+ "expo-image-picker",
319
+ {
320
+ "photosPermission": "Allow $(PRODUCT_NAME) to access photos.",
321
+ "cameraPermission": "Allow $(PRODUCT_NAME) to access camera."
322
+ }
323
+ ],
324
+ [
325
+ "expo-document-picker",
326
+ {
327
+ "iCloudPermission": "Allow $(PRODUCT_NAME) to access iCloud."
328
+ }
329
+ ]
330
+ ]
331
+ }
332
+ }
333
+ ```
334
+
335
+ ### Chunk Size Configuration
336
+
337
+ Choose chunk sizes based on network conditions:
338
+
339
+ **Fast Networks (WiFi):**
340
+ ```typescript
341
+ const client = createUploadistaClient({
342
+ chunkSize: 5 * 1024 * 1024, // 5MB chunks
343
+ concurrency: 6,
344
+ })
345
+ ```
346
+
347
+ **Mobile Networks (LTE/4G):**
348
+ ```typescript
349
+ const client = createUploadistaClient({
350
+ chunkSize: 2 * 1024 * 1024, // 2MB chunks
351
+ concurrency: 3,
352
+ })
353
+ ```
354
+
355
+ **Slow Networks (3G/Edge):**
356
+ ```typescript
357
+ const client = createUploadistaClient({
358
+ chunkSize: 512 * 1024, // 512KB chunks
359
+ concurrency: 2,
360
+ })
361
+ ```
362
+
363
+ ## Examples
364
+
365
+ ### Complete Upload Screen
366
+
367
+ ```typescript
368
+ import { useUpload } from '@uploadista/expo'
369
+ import * as ImagePicker from 'expo-image-picker'
370
+ import {
371
+ View,
372
+ TouchableOpacity,
373
+ Text,
374
+ Image,
375
+ ProgressBarAndroidBase,
376
+ } from 'react-native'
377
+
378
+ export function UploadPhotoScreen() {
379
+ const { state, upload, abort } = useUpload()
380
+
381
+ const pickAndUpload = async () => {
382
+ // Request permissions
383
+ const { granted } = await ImagePicker.requestMediaLibraryPermissionsAsync()
384
+ if (!granted) return
385
+
386
+ // Pick image
387
+ const result = await ImagePicker.launchImageLibraryAsync({
388
+ mediaTypes: 'Images',
389
+ quality: 0.8,
390
+ })
391
+
392
+ if (!result.canceled) {
393
+ // Upload
394
+ await upload(result.assets[0])
395
+ }
396
+ }
397
+
398
+ return (
399
+ <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
400
+ {state.status === 'idle' && (
401
+ <TouchableOpacity onPress={pickAndUpload}>
402
+ <Text style={{ fontSize: 18 }}>Pick and Upload Photo</Text>
403
+ </TouchableOpacity>
404
+ )}
405
+
406
+ {state.status === 'uploading' && (
407
+ <View style={{ width: '80%' }}>
408
+ <ProgressBarAndroidBase
409
+ styleAttr="Horizontal"
410
+ indeterminate={false}
411
+ progress={state.progress / 100}
412
+ />
413
+ <Text>
414
+ {Math.round(state.progress)}% - {Math.round(state.bytesUploaded / 1024 / 1024)}MB /
415
+ {Math.round(state.totalBytes! / 1024 / 1024)}MB
416
+ </Text>
417
+ <TouchableOpacity onPress={abort}>
418
+ <Text style={{ color: 'red' }}>Cancel</Text>
419
+ </TouchableOpacity>
420
+ </View>
421
+ )}
422
+
423
+ {state.status === 'success' && (
424
+ <View>
425
+ <Image source={{ uri: state.result?.filename }} style={{ width: 200, height: 200 }} />
426
+ <Text>Upload successful!</Text>
427
+ <Text>File: {state.result?.filename}</Text>
428
+ </View>
429
+ )}
430
+
431
+ {state.status === 'error' && (
432
+ <View>
433
+ <Text style={{ color: 'red' }}>Upload failed</Text>
434
+ <Text>{state.error?.message}</Text>
435
+ <TouchableOpacity onPress={() => upload(/* file */)}>
436
+ <Text>Retry</Text>
437
+ </TouchableOpacity>
438
+ </View>
439
+ )}
440
+ </View>
441
+ )
442
+ }
443
+ ```
444
+
445
+ ### Multiple Files Upload
446
+
447
+ ```typescript
448
+ import { useMultiUpload } from '@uploadista/expo'
449
+ import * as ImagePicker from 'expo-image-picker'
450
+ import { FlatList, View } from 'react-native'
451
+
452
+ export function MultiUploadScreen() {
453
+ const { uploads, stats, add } = useMultiUpload()
454
+
455
+ const pickMultiple = async () => {
456
+ const result = await ImagePicker.launchImageLibraryAsync({
457
+ mediaTypes: 'Images',
458
+ multiple: true,
459
+ })
460
+
461
+ if (!result.canceled) {
462
+ await add(result.assets)
463
+ }
464
+ }
465
+
466
+ return (
467
+ <View>
468
+ <Button title="Add Photos" onPress={pickMultiple} />
469
+
470
+ <Text>
471
+ {stats.value.completedFiles} / {stats.value.totalFiles} uploaded
472
+ </Text>
473
+
474
+ <FlatList
475
+ data={uploads}
476
+ keyExtractor={(item) => item.id}
477
+ renderItem={({ item }) => (
478
+ <View>
479
+ <Text>{item.filename}</Text>
480
+ <Text>{Math.round(item.progress)}%</Text>
481
+ <Text>{item.state.status}</Text>
482
+ </View>
483
+ )}
484
+ />
485
+ </View>
486
+ )
487
+ }
488
+ ```
489
+
490
+ ## Troubleshooting
491
+
492
+ ### Permission Denied Errors
493
+
494
+ Ensure permissions are requested before accessing files:
495
+
496
+ ```typescript
497
+ const { granted } = await ImagePicker.requestMediaLibraryPermissionsAsync()
498
+ if (!granted) {
499
+ alert('Permission to access media library is required')
500
+ }
501
+ ```
502
+
503
+ ### Network Interruptions
504
+
505
+ Uploads automatically resume from the last successful chunk. To manually retry:
506
+
507
+ ```typescript
508
+ const { state, retry } = useUpload()
509
+
510
+ if (state.value.status === 'error') {
511
+ await retry()
512
+ }
513
+ ```
514
+
515
+ ### Memory Issues with Large Files
516
+
517
+ Use smaller chunk sizes for large files:
518
+
519
+ ```typescript
520
+ const client = createUploadistaClient({
521
+ chunkSize: 512 * 1024, // Smaller chunks use less memory
522
+ concurrency: 1,
523
+ })
524
+ ```
525
+
526
+ ### Slow Uploads
527
+
528
+ Increase chunk size and concurrency for faster networks:
529
+
530
+ ```typescript
531
+ const client = createUploadistaClient({
532
+ chunkSize: 5 * 1024 * 1024,
533
+ concurrency: 5,
534
+ })
535
+ ```
536
+
537
+ ## Related Packages
538
+
539
+ - **[@uploadista/client-core](../core/)** - Core client and types
540
+ - **[@uploadista/react-native-core](../react-native-core/)** - React Native composables
541
+ - **[@uploadista/client-browser](../browser/)** - Browser client implementation
542
+
543
+ ## TypeScript Support
544
+
545
+ Full TypeScript support included. Type definitions for all APIs:
546
+
547
+ ```typescript
548
+ import type {
549
+ UploadistaClientOptions,
550
+ UploadState,
551
+ UseUploadOptions,
552
+ UseMultiUploadOptions,
553
+ ExpoServiceOptions,
554
+ } from '@uploadista/expo'
555
+ ```
556
+
557
+ ## Performance Tips
558
+
559
+ 1. **Chunk Size** - Larger chunks (2-5MB) for fast networks, smaller (512KB) for slow
560
+ 2. **Concurrency** - Balance between 2-6 concurrent chunks based on network
561
+ 3. **Compression** - Pre-compress large files before upload (images, videos)
562
+ 4. **Resumption** - Automatically handled; failed chunks restart without re-uploading
563
+ 5. **Background Upload** - Consider using Background Tasks for long uploads
564
+
565
+ ## License
566
+
567
+ MIT
package/expo-env.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ /// <reference types="expo/types" />
2
+
3
+ // NOTE: This file should not be edited and should be in your git ignore
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@uploadista/expo",
3
+ "version": "0.0.3",
4
+ "type": "module",
5
+ "description": "Expo client for Uploadista with managed workflow support",
6
+ "license": "MIT",
7
+ "author": "Uploadista",
8
+ "exports": {
9
+ ".": "./src/index.ts",
10
+ "./services": "./src/services/index.ts"
11
+ },
12
+ "dependencies": {
13
+ "uuid": "^10.0.0",
14
+ "js-base64": "^3.7.7",
15
+ "@uploadista/core": "0.0.3",
16
+ "@uploadista/client-core": "0.0.3",
17
+ "@uploadista/react-native-core": "0.0.3"
18
+ },
19
+ "peerDependencies": {
20
+ "@react-native-async-storage/async-storage": ">=1.17.0",
21
+ "expo-camera": ">=15.0.0",
22
+ "expo-document-picker": ">=12.0.0",
23
+ "expo-file-system": ">=16.0.0",
24
+ "expo-image-picker": ">=14.0.0",
25
+ "expo-crypto": "15.0.7",
26
+ "react": ">=16.8.0",
27
+ "react-native": ">=0.71.0"
28
+ },
29
+ "peerDependenciesMeta": {
30
+ "@react-native-async-storage/async-storage": {
31
+ "optional": true
32
+ }
33
+ },
34
+ "devDependencies": {
35
+ "@types/react": ">=18.0.0",
36
+ "@types/react-native": ">=0.71.0",
37
+ "@types/uuid": "^10.0.0",
38
+ "@uploadista/typescript-config": "0.0.3"
39
+ },
40
+ "scripts": {
41
+ "format": "biome format --write ./src",
42
+ "lint": "biome lint --write ./src",
43
+ "check": "biome check --write ./src"
44
+ }
45
+ }
@@ -0,0 +1,67 @@
1
+ import {
2
+ type ConnectionPoolConfig,
3
+ createClientStorage,
4
+ createLogger,
5
+ createUploadistaClient as createUploadistaClientCore,
6
+ type UploadistaClientOptions as UploadistaClientOptionsCore,
7
+ } from "@uploadista/client-core";
8
+ import { createExpoServices } from "../services/create-expo-services";
9
+ import type { ExpoUploadInput } from "../types/upload-input";
10
+
11
+ export interface UploadistaClientOptions
12
+ extends Omit<
13
+ UploadistaClientOptionsCore<ExpoUploadInput>,
14
+ | "webSocketFactory"
15
+ | "abortControllerFactory"
16
+ | "generateId"
17
+ | "clientStorage"
18
+ | "logger"
19
+ | "httpClient"
20
+ | "fileReader"
21
+ | "base64"
22
+ > {
23
+ connectionPooling?: ConnectionPoolConfig;
24
+
25
+ /**
26
+ * Whether to use AsyncStorage for persistence
27
+ * If false, uses in-memory storage
28
+ * @default true
29
+ */
30
+ useAsyncStorage?: boolean;
31
+ }
32
+
33
+ /**
34
+ * Creates an upload client instance with Expo-specific service implementations
35
+ *
36
+ * @param options - Client configuration options
37
+ * @returns Configured UploadistaClient instance
38
+ *
39
+ * @example
40
+ * ```typescript
41
+ * import { createUploadistaClient } from '@uploadista/expo'
42
+ *
43
+ * const client = createUploadistaClient({
44
+ * baseUrl: 'https://api.example.com',
45
+ * storageId: 'my-storage',
46
+ * chunkSize: 1024 * 1024, // 1MB
47
+ * useAsyncStorage: true,
48
+ * });
49
+ * ```
50
+ */
51
+ export function createUploadistaClient(options: UploadistaClientOptions) {
52
+ const services = createExpoServices({
53
+ connectionPooling: options.connectionPooling,
54
+ useAsyncStorage: options.useAsyncStorage,
55
+ });
56
+
57
+ return createUploadistaClientCore<ExpoUploadInput>({
58
+ ...options,
59
+ webSocketFactory: services.websocket,
60
+ abortControllerFactory: services.abortController,
61
+ httpClient: services.httpClient,
62
+ fileReader: services.fileReader,
63
+ generateId: services.idGeneration,
64
+ logger: createLogger(false, () => {}),
65
+ clientStorage: createClientStorage(services.storage),
66
+ });
67
+ }
@@ -0,0 +1,4 @@
1
+ export {
2
+ createUploadistaClient,
3
+ type UploadistaClientOptions,
4
+ } from "./create-uploadista-client";