@uploadista/expo 0.0.3 → 0.0.4
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/dist/index.d.ts +333 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/package.json +8 -8
- package/tsdown.config.ts +12 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import * as _uploadista_client_core0 from "@uploadista/client-core";
|
|
2
|
+
import { Base64Service, Base64Service as Base64Service$1, ConnectionPoolConfig, ConnectionPoolConfig as ConnectionPoolConfig$1, FileReaderService, FileReaderService as FileReaderService$1, FileSource, HttpClient, HttpClient as HttpClient$1, HttpRequestOptions, HttpResponse, IdGenerationService, IdGenerationService as IdGenerationService$1, ServiceContainer, ServiceContainer as ServiceContainer$1, SliceResult, StorageService, StorageService as StorageService$1, UploadistaClientOptions as UploadistaClientOptions$1 } from "@uploadista/client-core";
|
|
3
|
+
import * as _uploadista_core0 from "@uploadista/core";
|
|
4
|
+
import { ReactNativeUploadInput } from "@uploadista/react-native-core";
|
|
5
|
+
|
|
6
|
+
//#region src/types/upload-input.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* Expo file input types
|
|
9
|
+
* Can be a Blob, File, URI string, or URI object from Expo APIs
|
|
10
|
+
*/
|
|
11
|
+
type ExpoUploadInput = Blob | File | string | {
|
|
12
|
+
uri: string;
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
//#region src/client/create-uploadista-client.d.ts
|
|
16
|
+
interface UploadistaClientOptions extends Omit<UploadistaClientOptions$1<ExpoUploadInput>, "webSocketFactory" | "abortControllerFactory" | "generateId" | "clientStorage" | "logger" | "httpClient" | "fileReader" | "base64"> {
|
|
17
|
+
connectionPooling?: ConnectionPoolConfig$1;
|
|
18
|
+
/**
|
|
19
|
+
* Whether to use AsyncStorage for persistence
|
|
20
|
+
* If false, uses in-memory storage
|
|
21
|
+
* @default true
|
|
22
|
+
*/
|
|
23
|
+
useAsyncStorage?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Creates an upload client instance with Expo-specific service implementations
|
|
27
|
+
*
|
|
28
|
+
* @param options - Client configuration options
|
|
29
|
+
* @returns Configured UploadistaClient instance
|
|
30
|
+
*
|
|
31
|
+
* @example
|
|
32
|
+
* ```typescript
|
|
33
|
+
* import { createUploadistaClient } from '@uploadista/expo'
|
|
34
|
+
*
|
|
35
|
+
* const client = createUploadistaClient({
|
|
36
|
+
* baseUrl: 'https://api.example.com',
|
|
37
|
+
* storageId: 'my-storage',
|
|
38
|
+
* chunkSize: 1024 * 1024, // 1MB
|
|
39
|
+
* useAsyncStorage: true,
|
|
40
|
+
* });
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
declare function createUploadistaClient(options: UploadistaClientOptions): {
|
|
44
|
+
upload: (file: ExpoUploadInput, {
|
|
45
|
+
uploadLengthDeferred,
|
|
46
|
+
uploadSize,
|
|
47
|
+
onProgress,
|
|
48
|
+
onChunkComplete,
|
|
49
|
+
onSuccess,
|
|
50
|
+
onShouldRetry,
|
|
51
|
+
onError
|
|
52
|
+
}?: _uploadista_client_core0.UploadistaUploadOptions) => Promise<{
|
|
53
|
+
abort: () => void;
|
|
54
|
+
}>;
|
|
55
|
+
uploadWithFlow: (file: ExpoUploadInput, flowConfig: _uploadista_client_core0.FlowUploadConfig, {
|
|
56
|
+
onProgress,
|
|
57
|
+
onChunkComplete,
|
|
58
|
+
onSuccess,
|
|
59
|
+
onShouldRetry,
|
|
60
|
+
onJobStart,
|
|
61
|
+
onError
|
|
62
|
+
}?: Omit<_uploadista_client_core0.UploadistaUploadOptions, "uploadLengthDeferred" | "uploadSize" | "metadata">) => Promise<{
|
|
63
|
+
abort: () => void;
|
|
64
|
+
jobId: string;
|
|
65
|
+
}>;
|
|
66
|
+
abort: (params: Parameters<typeof void 0>[0]) => Promise<void>;
|
|
67
|
+
getFlow: (flowId: string) => Promise<{
|
|
68
|
+
status: number;
|
|
69
|
+
flow: _uploadista_core0.FlowData;
|
|
70
|
+
}>;
|
|
71
|
+
runFlow: ({
|
|
72
|
+
flowId,
|
|
73
|
+
inputs,
|
|
74
|
+
storageId: flowStorageId
|
|
75
|
+
}: {
|
|
76
|
+
flowId: string;
|
|
77
|
+
inputs: Record<string, unknown>;
|
|
78
|
+
storageId?: string;
|
|
79
|
+
}) => Promise<{
|
|
80
|
+
status: number;
|
|
81
|
+
job: _uploadista_core0.FlowJob;
|
|
82
|
+
}>;
|
|
83
|
+
continueFlow: ({
|
|
84
|
+
jobId,
|
|
85
|
+
nodeId,
|
|
86
|
+
newData,
|
|
87
|
+
contentType
|
|
88
|
+
}: {
|
|
89
|
+
jobId: string;
|
|
90
|
+
nodeId: string;
|
|
91
|
+
newData: unknown;
|
|
92
|
+
contentType?: "application/json" | "application/octet-stream";
|
|
93
|
+
}) => Promise<_uploadista_core0.FlowJob>;
|
|
94
|
+
getJobStatus: (jobId: string) => Promise<_uploadista_core0.FlowJob>;
|
|
95
|
+
openUploadWebSocket: (uploadId: string) => Promise<_uploadista_client_core0.WebSocketLike>;
|
|
96
|
+
openFlowWebSocket: (jobId: string) => Promise<_uploadista_client_core0.WebSocketLike>;
|
|
97
|
+
openWebSocket: (id: string) => Promise<_uploadista_client_core0.WebSocketLike>;
|
|
98
|
+
closeWebSocket: (id: string) => void;
|
|
99
|
+
closeAllWebSockets: () => void;
|
|
100
|
+
sendPing: (jobId: string) => boolean;
|
|
101
|
+
isWebSocketConnected: (id: string) => boolean;
|
|
102
|
+
getWebSocketConnectionCount: () => number;
|
|
103
|
+
getWebSocketConnectionCountByType: () => {
|
|
104
|
+
upload: number;
|
|
105
|
+
flow: number;
|
|
106
|
+
total: number;
|
|
107
|
+
};
|
|
108
|
+
getNetworkMetrics: () => _uploadista_client_core0.NetworkMetrics;
|
|
109
|
+
getNetworkCondition: () => _uploadista_client_core0.NetworkCondition;
|
|
110
|
+
getChunkingInsights: () => _uploadista_client_core0.PerformanceInsights;
|
|
111
|
+
exportMetrics: () => {
|
|
112
|
+
session: Partial<_uploadista_client_core0.UploadSessionMetrics>;
|
|
113
|
+
chunks: _uploadista_client_core0.ChunkMetrics[];
|
|
114
|
+
insights: _uploadista_client_core0.PerformanceInsights;
|
|
115
|
+
};
|
|
116
|
+
getConnectionMetrics: () => _uploadista_client_core0.ConnectionMetrics;
|
|
117
|
+
getDetailedConnectionMetrics: () => _uploadista_client_core0.DetailedConnectionMetrics;
|
|
118
|
+
warmupConnections: (urls: string[]) => Promise<void>;
|
|
119
|
+
getConnectionPoolingInsights: () => Promise<{
|
|
120
|
+
isOptimized: boolean;
|
|
121
|
+
reuseRate: number;
|
|
122
|
+
recommendedMinChunkSize: number;
|
|
123
|
+
connectionOverhead: number;
|
|
124
|
+
}>;
|
|
125
|
+
resetMetrics: () => Promise<void>;
|
|
126
|
+
validateConfiguration: (options: UploadistaClientOptions$1<ExpoUploadInput>) => {
|
|
127
|
+
valid: boolean;
|
|
128
|
+
errors: string[];
|
|
129
|
+
warnings: string[];
|
|
130
|
+
};
|
|
131
|
+
validateConfigurationAsync: (options: UploadistaClientOptions$1<ExpoUploadInput>) => Promise<{
|
|
132
|
+
valid: boolean;
|
|
133
|
+
errors: string[];
|
|
134
|
+
warnings: string[];
|
|
135
|
+
capabilities: _uploadista_core0.DataStoreCapabilities;
|
|
136
|
+
}>;
|
|
137
|
+
getCapabilities: () => Promise<_uploadista_core0.DataStoreCapabilities>;
|
|
138
|
+
};
|
|
139
|
+
//#endregion
|
|
140
|
+
//#region src/services/base64-service.d.ts
|
|
141
|
+
/**
|
|
142
|
+
* Expo-specific implementation of Base64Service using js-base64 library
|
|
143
|
+
* Expo/React Native doesn't have native btoa/atob functions, so we use js-base64
|
|
144
|
+
*/
|
|
145
|
+
declare function createExpoBase64Service(): Base64Service$1;
|
|
146
|
+
//#endregion
|
|
147
|
+
//#region src/services/create-expo-services.d.ts
|
|
148
|
+
interface ExpoServiceOptions {
|
|
149
|
+
/**
|
|
150
|
+
* HTTP client configuration for connection pooling
|
|
151
|
+
*/
|
|
152
|
+
connectionPooling?: ConnectionPoolConfig$1;
|
|
153
|
+
/**
|
|
154
|
+
* Whether to use AsyncStorage for persistence
|
|
155
|
+
* If false, uses in-memory storage
|
|
156
|
+
* @default true
|
|
157
|
+
*/
|
|
158
|
+
useAsyncStorage?: boolean;
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Creates a service container with Expo-specific implementations
|
|
162
|
+
* of all required services for the upload client
|
|
163
|
+
*
|
|
164
|
+
* @param options - Configuration options for Expo services
|
|
165
|
+
* @returns ServiceContainer with Expo implementations
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* ```typescript
|
|
169
|
+
* import { createExpoServices } from '@uploadista/expo/services';
|
|
170
|
+
*
|
|
171
|
+
* const services = createExpoServices({
|
|
172
|
+
* useAsyncStorage: true,
|
|
173
|
+
* connectionPooling: {
|
|
174
|
+
* maxConnectionsPerHost: 6,
|
|
175
|
+
* connectionTimeout: 30000,
|
|
176
|
+
* }
|
|
177
|
+
* });
|
|
178
|
+
* ```
|
|
179
|
+
*/
|
|
180
|
+
declare function createExpoServices(options?: ExpoServiceOptions): ServiceContainer$1<ReactNativeUploadInput>;
|
|
181
|
+
//#endregion
|
|
182
|
+
//#region src/services/file-reader-service.d.ts
|
|
183
|
+
/**
|
|
184
|
+
* Expo-specific implementation of FileReaderService
|
|
185
|
+
* Handles Blob, File, and URI-based file inputs using Expo FileSystem APIs
|
|
186
|
+
*/
|
|
187
|
+
declare function createExpoFileReaderService(): FileReaderService$1<ExpoUploadInput>;
|
|
188
|
+
//#endregion
|
|
189
|
+
//#region src/services/http-client.d.ts
|
|
190
|
+
/**
|
|
191
|
+
* Expo-specific implementation of HttpClient using fetch API
|
|
192
|
+
* Expo's fetch is similar to browser fetch but optimized for React Native
|
|
193
|
+
*/
|
|
194
|
+
declare function createExpoHttpClient(config?: ConnectionPoolConfig$1): HttpClient$1;
|
|
195
|
+
//#endregion
|
|
196
|
+
//#region src/services/id-generation-service.d.ts
|
|
197
|
+
/**
|
|
198
|
+
* Expo-specific implementation of IdGenerationService using uuid library
|
|
199
|
+
* crypto.randomUUID() is not available in Expo/React Native, so we use the uuid library
|
|
200
|
+
*/
|
|
201
|
+
declare function createExpoIdGenerationService(): IdGenerationService$1;
|
|
202
|
+
//#endregion
|
|
203
|
+
//#region src/services/storage-service.d.ts
|
|
204
|
+
/**
|
|
205
|
+
* Expo-specific implementation of StorageService using AsyncStorage
|
|
206
|
+
* AsyncStorage is provided as an optional peer dependency and must be installed separately
|
|
207
|
+
*/
|
|
208
|
+
declare function createAsyncStorageService(): StorageService$1;
|
|
209
|
+
//#endregion
|
|
210
|
+
//#region src/types.d.ts
|
|
211
|
+
/**
|
|
212
|
+
* Core types for Expo Uploadista client
|
|
213
|
+
*/
|
|
214
|
+
/**
|
|
215
|
+
* Options for file picker operations
|
|
216
|
+
*/
|
|
217
|
+
interface PickerOptions {
|
|
218
|
+
/** Allowed file types/MIME types */
|
|
219
|
+
allowedTypes?: string[];
|
|
220
|
+
/** Allow multiple selection */
|
|
221
|
+
allowMultiple?: boolean;
|
|
222
|
+
/** Maximum file size in bytes */
|
|
223
|
+
maxSize?: number;
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Options for camera operations
|
|
227
|
+
*/
|
|
228
|
+
interface CameraOptions {
|
|
229
|
+
/** Camera to use: 'front' or 'back' */
|
|
230
|
+
cameraType?: "front" | "back";
|
|
231
|
+
/** Image quality (0-1) */
|
|
232
|
+
quality?: number;
|
|
233
|
+
/** Maximum width for captured image */
|
|
234
|
+
maxWidth?: number;
|
|
235
|
+
/** Maximum height for captured image */
|
|
236
|
+
maxHeight?: number;
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Result from a file pick operation
|
|
240
|
+
*/
|
|
241
|
+
interface FilePickResult {
|
|
242
|
+
/** URI to the file (platform-specific format) */
|
|
243
|
+
uri: string;
|
|
244
|
+
/** File name with extension */
|
|
245
|
+
name: string;
|
|
246
|
+
/** File size in bytes */
|
|
247
|
+
size: number;
|
|
248
|
+
/** MIME type of the file (if available) */
|
|
249
|
+
mimeType?: string;
|
|
250
|
+
/** Local file path (if available) */
|
|
251
|
+
localPath?: string;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Information about a file
|
|
255
|
+
*/
|
|
256
|
+
interface FileInfo {
|
|
257
|
+
/** URI to the file */
|
|
258
|
+
uri: string;
|
|
259
|
+
/** File name */
|
|
260
|
+
name: string;
|
|
261
|
+
/** File size in bytes */
|
|
262
|
+
size: number;
|
|
263
|
+
/** MIME type (if available) */
|
|
264
|
+
mimeType?: string;
|
|
265
|
+
/** Last modified timestamp */
|
|
266
|
+
modificationTime?: number;
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Interface for file system abstraction layer
|
|
270
|
+
* Provides pluggable access to file system APIs across different Expo environments
|
|
271
|
+
*/
|
|
272
|
+
interface FileSystemProvider {
|
|
273
|
+
/**
|
|
274
|
+
* Opens a document picker for selecting files
|
|
275
|
+
* @param options - Configuration for the picker
|
|
276
|
+
* @returns Promise resolving to picked file information
|
|
277
|
+
*/
|
|
278
|
+
pickDocument(options?: PickerOptions): Promise<FilePickResult>;
|
|
279
|
+
/**
|
|
280
|
+
* Opens an image picker for selecting images from gallery
|
|
281
|
+
* @param options - Configuration for the picker
|
|
282
|
+
* @returns Promise resolving to picked image information
|
|
283
|
+
*/
|
|
284
|
+
pickImage(options?: PickerOptions): Promise<FilePickResult>;
|
|
285
|
+
/**
|
|
286
|
+
* Opens a video picker for selecting videos from gallery
|
|
287
|
+
* @param options - Configuration for the picker
|
|
288
|
+
* @returns Promise resolving to picked video information
|
|
289
|
+
*/
|
|
290
|
+
pickVideo(options?: PickerOptions): Promise<FilePickResult>;
|
|
291
|
+
/**
|
|
292
|
+
* Captures a photo using the device camera
|
|
293
|
+
* @param options - Configuration for camera
|
|
294
|
+
* @returns Promise resolving to captured photo information
|
|
295
|
+
*/
|
|
296
|
+
pickCamera(options?: CameraOptions): Promise<FilePickResult>;
|
|
297
|
+
/**
|
|
298
|
+
* Gets a URI for a document that can be read
|
|
299
|
+
* @param filePath - Path to the document
|
|
300
|
+
* @returns Promise resolving to accessible URI
|
|
301
|
+
*/
|
|
302
|
+
getDocumentUri(filePath: string): Promise<string>;
|
|
303
|
+
/**
|
|
304
|
+
* Reads file contents as ArrayBuffer
|
|
305
|
+
* @param uri - URI to read from
|
|
306
|
+
* @returns Promise resolving to file contents as ArrayBuffer
|
|
307
|
+
*/
|
|
308
|
+
readFile(uri: string): Promise<ArrayBuffer>;
|
|
309
|
+
/**
|
|
310
|
+
* Gets information about a file
|
|
311
|
+
* @param uri - URI of the file
|
|
312
|
+
* @returns Promise resolving to file information
|
|
313
|
+
*/
|
|
314
|
+
getFileInfo(uri: string): Promise<FileInfo>;
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/services/expo-file-system-provider.d.ts
|
|
318
|
+
/**
|
|
319
|
+
* File system provider implementation for Expo managed environment
|
|
320
|
+
* Uses Expo DocumentPicker, ImagePicker, Camera, and FileSystem APIs
|
|
321
|
+
*/
|
|
322
|
+
declare class ExpoFileSystemProvider implements FileSystemProvider {
|
|
323
|
+
pickDocument(options?: PickerOptions): Promise<FilePickResult>;
|
|
324
|
+
pickImage(options?: PickerOptions): Promise<FilePickResult>;
|
|
325
|
+
pickVideo(options?: PickerOptions): Promise<FilePickResult>;
|
|
326
|
+
pickCamera(options?: CameraOptions): Promise<FilePickResult>;
|
|
327
|
+
readFile(uri: string): Promise<ArrayBuffer>;
|
|
328
|
+
getDocumentUri(filePath: string): Promise<string>;
|
|
329
|
+
getFileInfo(uri: string): Promise<FileInfo>;
|
|
330
|
+
}
|
|
331
|
+
//#endregion
|
|
332
|
+
export { type Base64Service, type CameraOptions, type ConnectionPoolConfig, ExpoFileSystemProvider, type ExpoServiceOptions, type FileInfo, type FilePickResult, type FileReaderService, type FileSource, type FileSystemProvider, type HttpClient, type HttpRequestOptions, type HttpResponse, type IdGenerationService, type PickerOptions, type ServiceContainer, type SliceResult, type StorageService, type UploadistaClientOptions, createAsyncStorageService, createExpoBase64Service, createExpoFileReaderService, createExpoHttpClient, createExpoIdGenerationService, createExpoServices, createUploadistaClient };
|
|
333
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types/upload-input.ts","../src/client/create-uploadista-client.ts","../src/services/base64-service.ts","../src/services/create-expo-services.ts","../src/services/file-reader-service.ts","../src/services/http-client.ts","../src/services/id-generation-service.ts","../src/services/storage-service.ts","../src/types.ts","../src/services/expo-file-system-provider.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;KAIY,eAAA,GAAkB,OAAO;;AAArC,CAAA;;;UCMiB,uBAAA,SACP,KACN,0BAA4B;sBAUV;;;ADlBtB;;;;ACMA;;;;;;AAwCA;;;;;;;;;;;;;iBAAgB,sBAAA,UAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EC3ChC,qBAAA,EAAA,CAAA,OAAuB,2BAAiB,gBAAA,CAAA,EAAA,GAAA;;;;ECUvC,CAAA;EAkCD,0BAAkB,EAAA,CAAA,OAAA,2BAAA,gBAAA,CAAA,EAAA,UAAA,CAAA;IACvB,KAAA,EAAA,OAAA;IACS,MAAA,EAAA,MAAA,EAAA;IAAjB,QAAA,EAAA,MAAA,EAAA;IAAgB,YAAA,yCAAA;;;;;;;;;;iBD9CH,uBAAA,CAAA,GAA2B;;;UCU1B,kBAAA;;;;EHbL,iBAAA,CAAe,EGiBL,sBHjBe;;;;ACMrC;;EAEI,eAAA,CAAA,EAAA,OAAA;;;;AAsCJ;;;;;;;;;;;;;;;;;;iBECgB,kBAAA,WACL,qBACR,mBAAiB;;;;;;;AHjDR,iBIOI,2BAAA,CAAA,CJPyB,EIOM,mBJPN,CIOwB,eJPxB,CAAA;;;;;;;iBKYzB,oBAAA,UACL,yBACR;;;;;;;iBCXa,6BAAA,CAAA,GAAiC;;;;;;;iBCDjC,yBAAA,CAAA,GAA6B;;;;;;;;;APFjC,UQGK,aAAA,CRHU;;;;ECMV,aAAA,CAAA,EAAA,OAAA;EAEe;EAA5B,OAAA,CAAA,EAAA,MAAA;;;;AAsCJ;AAAgD,UO/B/B,aAAA,CP+B+B;;;;;;;;;;;;;UOjB/B,cAAA;;;;;;;;;;;;;;;UAgBA,QAAA;;;;;;;;;;;;;;;;UAiBA,kBAAA;;;;;;yBAMQ,gBAAgB,QAAQ;;;;;;sBAO3B,gBAAgB,QAAQ;;;;;;sBAOxB,gBAAgB,QAAQ;;;;;;uBAOvB,gBAAgB,QAAQ;;;ANtF/C;;;oCM6FoC;ELnFnB;AAkCjB;;;;EAEmB,QAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EKsDM,OLtDN,CKsDc,WLtDd,CAAA;;;;AC1CnB;;4BIuG4B,QAAQ;;;;;;;;cCnGvB,sBAAA,YAAkC;ETXnC,YAAA,CAAA,OAAyB,CAAV,ESYI,aTZM,CAAA,ESYU,OTZN,CSYc,cTZd,CAAA;sBSoDb,gBAAgB,QAAQ;sBAyCxB,gBAAgB,QAAQ;uBAwCvB,gBAAgB,QAAQ;ER/HpC,QAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EQsKc,ORrK7B,CQqKqC,WRrKrC,CAAA;EAC8B,cAAA,CAAA,QAAA,EAAA,MAAA,CAAA,EQ2LU,OR3LV,CAAA,MAAA,CAAA;EAA5B,WAAA,CAAA,GAAA,EAAA,MAAA,CAAA,EQgM8B,ORhM9B,CQgMsC,QRhMtC,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{createRequire as e}from"node:module";import{createClientStorage as t,createInMemoryStorageService as n,createLogger as r,createUploadistaClient as i}from"@uploadista/client-core";import{fromBase64 as a,toBase64 as o}from"js-base64";import*as s from"expo-file-system";import{v4 as c}from"uuid";import l from"@react-native-async-storage/async-storage";import*as u from"expo-crypto";import*as d from"expo-document-picker";import*as f from"expo-image-picker";var p=e(import.meta.url),m=class{native;constructor(){this.native=new AbortController}get signal(){return this.native.signal}abort(e){this.native.abort()}};const h=()=>({create:()=>new m});function g(){return{toBase64(e){let t=new Uint8Array(e);return o(Array.from(t).map(e=>String.fromCharCode(e)).join(``))},fromBase64(e){let t=a(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n.buffer}}}function _(){return{async openFile(e,t){if(e instanceof Blob)return v(e);if(typeof e==`string`||e&&typeof e==`object`&&`uri`in e)return b(typeof e==`string`?e:e.uri);throw Error(`Unsupported file input type for Expo. Expected Blob, File, URI string, or {uri: string}`)}}}function v(e){return{input:e,size:e.size,async slice(t,n){let r=e.slice(t,n),i=await y(r);return{done:n>=e.size,value:new Uint8Array(i),size:r.size}},close(){},name:null,lastModified:null,type:null}}function y(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{r.result instanceof ArrayBuffer?t(r.result):n(Error(`FileReader result is not an ArrayBuffer`))},r.onerror=()=>n(r.error),r.readAsArrayBuffer(e)})}function b(e){let t=null,n=null;return{input:e,size:n,async slice(r,i){if(!t)try{let r=await x(),i=await r.getInfoAsync(e);if(!i.exists)throw Error(`File does not exist at URI: ${e}`);n=i.size??0;let a=S(await r.readAsStringAsync(e,{encoding:r.EncodingType.Base64}));n=a.length,t=new Blob([a.buffer])}catch(t){throw Error(`Failed to read file from URI ${e}: ${t}`)}let a=t.slice(r,i),o=await y(a);return{done:i>=t.size,value:new Uint8Array(o),size:a.size}},close(){t=null,n=null},name:e,lastModified:null,type:null}}async function x(){try{return p(`expo-file-system`)}catch{throw Error(`expo-file-system is required but not installed. Please install it with: npx expo install expo-file-system`)}}function S(e){let{fromBase64:t}=p(`js-base64`),n=t(e),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}function C(e){return new w(e)}var w=class{metrics;connectionTimes=[];requestCount=0;errorCount=0;timeoutCount=0;retryCount=0;startTime=Date.now();constructor(e={}){this.metrics={activeConnections:0,totalConnections:0,reuseRate:0,averageConnectionTime:0}}async request(e,t={}){this.requestCount++;let n={method:t.method||`GET`,headers:t.headers,body:t.body,signal:t.signal};t.credentials&&(n.credentials=t.credentials);let r=Date.now();try{let i=t.timeout?new Promise((e,n)=>{setTimeout(()=>{this.timeoutCount++,n(Error(`Request timeout after ${t.timeout}ms`))},t.timeout)}):null,a=fetch(e,n),o=i?await Promise.race([a,i]):await a,s=Date.now()-r;return this.connectionTimes.push(s),this.metrics.totalConnections++,this.updateMetrics(),this.adaptResponse(o)}catch(e){throw this.errorCount++,e}}adaptResponse(e){return{status:e.status,statusText:e.statusText,headers:{get:t=>e.headers.get(t),has:t=>e.headers.has(t),forEach:t=>{e.headers.forEach(t)}},ok:e.ok,json:()=>e.json(),text:()=>e.text(),arrayBuffer:()=>e.arrayBuffer()}}updateMetrics(){if(this.connectionTimes.length>0){let e=this.connectionTimes.reduce((e,t)=>e+t,0);this.metrics.averageConnectionTime=e/this.connectionTimes.length}let e=this.connectionTimes.filter(e=>e<100).length;this.metrics.reuseRate=this.connectionTimes.length>0?e/this.connectionTimes.length:0}getMetrics(){return{...this.metrics}}getDetailedMetrics(){let e=Date.now()-this.startTime,t=e>0?this.requestCount/(e/1e3):0,n=this.requestCount>0?this.errorCount/this.requestCount:0,r=this.connectionTimes.filter(e=>e<100).length,i=this.connectionTimes.length-r,a=this.calculateHealth(n),o={supported:!1,detected:!1,version:`h1.1`,multiplexingActive:!1};return{...this.metrics,health:a,requestsPerSecond:t,errorRate:n,timeouts:this.timeoutCount,retries:this.retryCount,fastConnections:r,slowConnections:i,http2Info:o}}calculateHealth(e){let t,n,r=[],i=[];return e>.1?(t=`poor`,n=30,r.push(`High error rate: ${(e*100).toFixed(1)}%`),i.push(`Check network connectivity`)):e>.05?(t=`degraded`,n=60,r.push(`Moderate error rate: ${(e*100).toFixed(1)}%`),i.push(`Monitor connection stability`)):(t=`healthy`,n=100),this.metrics.averageConnectionTime>1e3&&(r.push(`Slow connections: ${this.metrics.averageConnectionTime.toFixed(0)}ms avg`),i.push(`Check network conditions`),n=Math.min(n,70)),{status:t,score:n,issues:r,recommendations:i}}reset(){this.metrics={activeConnections:0,totalConnections:0,reuseRate:0,averageConnectionTime:0},this.connectionTimes=[],this.requestCount=0,this.errorCount=0,this.timeoutCount=0,this.retryCount=0,this.startTime=Date.now()}async close(){this.reset()}async warmupConnections(e){let t=e.map(e=>this.request(e,{method:`HEAD`}).catch(()=>{}));await Promise.all(t)}};function T(){return{generate(){return c()}}}function E(){return{setTimeout:(e,t)=>globalThis.setTimeout(e,t),clearTimeout:e=>{globalThis.clearTimeout(e)},isBrowser:()=>!1,isOnline:()=>!0,isFileLike:e=>typeof e==`object`&&!!e&&(`uri`in e||`name`in e),getFileName:e=>{if(typeof e==`object`&&e&&`name`in e)return e.name;if(typeof e==`object`&&e&&`uri`in e){let t=e.uri;if(t)return t.split(`/`).pop()}},getFileType:e=>{if(typeof e==`object`&&e&&`type`in e)return e.type},getFileSize:e=>{if(typeof e==`object`&&e&&`size`in e)return e.size},getFileLastModified:e=>{if(typeof e==`object`&&e&&`lastModified`in e)return e.lastModified}}}function D(){let e=async e=>{let t={},n=await l.getAllKeys();for(let r in n)if(r.startsWith(e)){let e=await l.getItem(r);e&&(t[r]=e)}return t};return{async getItem(e){try{return await l.getItem(e)}catch(t){return console.error(`AsyncStorage getItem error for key ${e}:`,t),null}},async setItem(e,t){try{await l.setItem(e,t)}catch(t){throw console.error(`AsyncStorage setItem error for key ${e}:`,t),t}},async removeItem(e){try{await l.removeItem(e)}catch(t){throw console.error(`AsyncStorage removeItem error for key ${e}:`,t),t}},async findAll(){return e(``)},async find(t){return e(t)}}}var O=class{CONNECTING=0;OPEN=1;CLOSING=2;CLOSED=3;readyState;onopen=null;onclose=null;onerror=null;onmessage=null;native;constructor(e){this.native=new WebSocket(e),this.readyState=this.native.readyState,this.native.onopen=()=>{this.readyState=this.native.readyState,this.onopen?.()},this.native.onclose=e=>{this.readyState=this.native.readyState,this.onclose?.({code:e.code??1e3,reason:e.reason??`undefined reason`})},this.native.onerror=e=>{this.onerror?.(e)},this.native.onmessage=e=>{this.onmessage?.({data:e.data})}}send(e){this.native.send(e)}close(e,t){this.native.close(e,t)}};const k=()=>({create:e=>new O(e)});async function A(e){try{let t=await u.digest(u.CryptoDigestAlgorithm.SHA256,e);return Array.from(new Uint8Array(t)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}catch(e){throw Error(`Failed to compute checksum: ${e instanceof Error?e.message:`Unknown error`}`)}}async function j(e){try{return A(await M(e))}catch(e){throw Error(`Failed to compute file checksum: ${e instanceof Error?e.message:`Unknown error`}`)}}async function M(e){return new Promise((t,n)=>{let r=new FileReader;r.onload=()=>{r.result instanceof ArrayBuffer?t(new Uint8Array(r.result)):n(Error(`FileReader result is not an ArrayBuffer`))},r.onerror=()=>n(r.error),r.readAsArrayBuffer(e)})}function N(){return{computeChecksum:async e=>A(e)}}function P(){return{computeFingerprint:async(e,t)=>{if(e instanceof Blob)return j(e);if(typeof e==`string`||e&&typeof e==`object`&&`uri`in e)return F(typeof e==`string`?e:e.uri);throw Error(`Unsupported file input type for fingerprinting. Expected Blob, File, URI string, or {uri: string}`)}}}async function F(e){try{let t=await I();if(!(await t.getInfoAsync(e)).exists)throw Error(`File does not exist at URI: ${e}`);let n=L(await t.readAsStringAsync(e,{encoding:t.EncodingType.Base64})),r=await u.digest(u.CryptoDigestAlgorithm.SHA256,n);return Array.from(new Uint8Array(r)).map(e=>e.toString(16).padStart(2,`0`)).join(``)}catch(t){throw Error(`Failed to compute fingerprint from URI ${e}: ${t instanceof Error?t.message:`Unknown error`}`)}}async function I(){try{return p(`expo-file-system`)}catch{throw Error(`expo-file-system is required for URI-based fingerprinting. Please install it with: npx expo install expo-file-system`)}}function L(e){let{fromBase64:t}=p(`js-base64`),n=t(e),r=new Uint8Array(n.length);for(let e=0;e<n.length;e++)r[e]=n.charCodeAt(e);return r}function R(e={}){let{connectionPooling:t,useAsyncStorage:r=!0}=e;return{storage:r?D():n(),idGeneration:T(),httpClient:C(t),fileReader:_(),base64:g(),websocket:k(),abortController:h(),platform:E(),checksumService:N(),fingerprintService:P()}}function z(e){let n=R({connectionPooling:e.connectionPooling,useAsyncStorage:e.useAsyncStorage});return i({...e,webSocketFactory:n.websocket,abortControllerFactory:n.abortController,httpClient:n.httpClient,fileReader:n.fileReader,generateId:n.idGeneration,logger:r(!1,()=>{}),clientStorage:t(n.storage)})}var B=class{async pickDocument(e){try{let t=await d.getDocumentAsync({type:e?.allowedTypes||[`*/*`],copyToCacheDirectory:!0});if(t.canceled)throw Error(`Document picker was cancelled`);let n=t.assets?.[0];if(!n)throw Error(`No document selected`);return{uri:n.uri,name:n.name,size:n.size||0,mimeType:n.mimeType}}catch(e){throw e instanceof Error&&e.message.includes(`cancelled`)?e:Error(`Failed to pick document: ${e instanceof Error?e.message:String(e)}`)}}async pickImage(e){try{let{status:t}=await f.requestMediaLibraryPermissionsAsync();if(t!==`granted`)throw Error(`Camera roll permission not granted`);let n=await f.launchImageLibraryAsync({mediaTypes:`Images`,selectionLimit:e?.allowMultiple?0:1,quality:1});if(n.canceled)throw Error(`Image picker was cancelled`);let r=n.assets?.[0];if(!r)throw Error(`No image selected`);return{uri:r.uri,name:r.fileName||`image-${Date.now()}.jpg`,size:r.fileSize||0,mimeType:`image/jpeg`}}catch(e){throw e instanceof Error&&e.message.includes(`cancelled`)?e:Error(`Failed to pick image: ${e instanceof Error?e.message:String(e)}`)}}async pickVideo(e){try{let{status:t}=await f.requestMediaLibraryPermissionsAsync();if(t!==`granted`)throw Error(`Camera roll permission not granted`);let n=await f.launchImageLibraryAsync({mediaTypes:`Videos`,selectionLimit:e?.allowMultiple?0:1});if(n.canceled)throw Error(`Video picker was cancelled`);let r=n.assets?.[0];if(!r)throw Error(`No video selected`);return{uri:r.uri,name:r.fileName||`video-${Date.now()}.mp4`,size:r.fileSize||0,mimeType:`video/mp4`}}catch(e){throw e instanceof Error&&e.message.includes(`cancelled`)?e:Error(`Failed to pick video: ${e instanceof Error?e.message:String(e)}`)}}async pickCamera(e){try{let{status:t}=await f.requestCameraPermissionsAsync();if(t!==`granted`)throw Error(`Camera permission not granted`);let n=await f.launchCameraAsync({allowsEditing:!1,aspect:[4,3],quality:e?.quality??1});if(n.canceled)throw Error(`Camera capture was cancelled`);let r=n.assets?.[0];if(!r)throw Error(`No photo captured`);return{uri:r.uri,name:r.fileName||`photo-${Date.now()}.jpg`,size:r.fileSize||0,mimeType:`image/jpeg`}}catch(e){throw e instanceof Error&&e.message.includes(`cancelled`)?e:Error(`Failed to capture photo: ${e instanceof Error?e.message:String(e)}`)}}async readFile(e){try{let t=await s.readAsStringAsync(e,{encoding:s.EncodingType.Base64}),{fromBase64:n}=await import(`js-base64`),r=n(t),i=new Uint8Array(r.length);for(let e=0;e<r.length;e++)i[e]=r.charCodeAt(e);return i.buffer}catch(e){throw Error(`Failed to read file: ${e instanceof Error?e.message:String(e)}`)}}async getDocumentUri(e){return e}async getFileInfo(e){try{let t=await s.getInfoAsync(e);if(!t.exists)throw Error(`File does not exist`);return{uri:e,name:e.split(`/`).pop()||`unknown`,size:t.size??0,modificationTime:t.modificationTime?t.modificationTime*1e3:void 0}}catch(e){throw Error(`Failed to get file info: ${e instanceof Error?e.message:String(e)}`)}}};export{B as ExpoFileSystemProvider,D as createAsyncStorageService,g as createExpoBase64Service,_ as createExpoFileReaderService,C as createExpoHttpClient,T as createExpoIdGenerationService,R as createExpoServices,z as createUploadistaClient};
|
|
2
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["encode","decode","cachedBlob: Blob | null","cachedSize: number | null","FileSystem","getExpoFileSystem","base64ToUint8Array","fromBase64","fetchOptions: RequestInit","http2Info: Http2Info","status: \"healthy\" | \"degraded\" | \"poor\"","score: number","issues: string[]","recommendations: string[]","uuidv4","results: Record<string, string>","FileSystem","fromBase64","createUploadistaClientCore","fromBase64"],"sources":["../src/services/abort-controller-factory.ts","../src/services/base64-service.ts","../src/services/file-reader-service.ts","../src/services/http-client.ts","../src/services/id-generation-service.ts","../src/services/platform-service.ts","../src/services/storage-service.ts","../src/services/websocket-factory.ts","../src/utils/hash-util.ts","../src/services/checksum-service.ts","../src/services/fingerprint-service.ts","../src/services/create-expo-services.ts","../src/client/create-uploadista-client.ts","../src/services/expo-file-system-provider.ts"],"sourcesContent":["import type {\n AbortControllerFactory,\n AbortControllerLike,\n AbortSignalLike,\n} from \"@uploadista/client-core\";\n\n/**\n * Expo AbortController implementation that wraps native AbortController\n * Expo provides an AbortController API that is compatible with the browser AbortController API\n */\nclass ExpoAbortController implements AbortControllerLike {\n private native: AbortController;\n\n constructor() {\n this.native = new AbortController();\n }\n\n get signal(): AbortSignalLike {\n return this.native.signal;\n }\n\n abort(_reason?: unknown): void {\n this.native.abort();\n }\n}\n\n/**\n * Factory for creating Expo AbortController instances\n */\nexport const createExpoAbortControllerFactory = (): AbortControllerFactory => ({\n create: (): AbortControllerLike => new ExpoAbortController(),\n});\n","import type { Base64Service } from \"@uploadista/client-core\";\nimport { fromBase64 as decode, toBase64 as encode } from \"js-base64\";\n\n/**\n * Expo-specific implementation of Base64Service using js-base64 library\n * Expo/React Native doesn't have native btoa/atob functions, so we use js-base64\n */\nexport function createExpoBase64Service(): Base64Service {\n return {\n toBase64(data: ArrayBuffer): string {\n // Convert ArrayBuffer to Uint8Array\n const uint8Array = new Uint8Array(data);\n // Convert Uint8Array to string\n const binary = Array.from(uint8Array)\n .map((byte) => String.fromCharCode(byte))\n .join(\"\");\n return encode(binary);\n },\n\n fromBase64(data: string): ArrayBuffer {\n const binary = decode(data);\n const uint8Array = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n uint8Array[i] = binary.charCodeAt(i);\n }\n return uint8Array.buffer;\n },\n };\n}\n","import type {\n FileReaderService,\n FileSource,\n SliceResult,\n} from \"@uploadista/client-core\";\nimport type { ExpoUploadInput } from \"@/types/upload-input\";\n\n/**\n * Expo-specific implementation of FileReaderService\n * Handles Blob, File, and URI-based file inputs using Expo FileSystem APIs\n */\nexport function createExpoFileReaderService(): FileReaderService<ExpoUploadInput> {\n return {\n async openFile(input: unknown, _chunkSize: number): Promise<FileSource> {\n // Handle Blob/File objects\n if (input instanceof Blob) {\n return createBlobFileSource(input);\n }\n\n // Handle URI strings or URI objects from Expo APIs\n if (\n typeof input === \"string\" ||\n (input && typeof input === \"object\" && \"uri\" in input)\n ) {\n const uri =\n typeof input === \"string\" ? input : (input as { uri: string }).uri;\n return createExpoUriFileSource(uri);\n }\n\n throw new Error(\n \"Unsupported file input type for Expo. Expected Blob, File, URI string, or {uri: string}\",\n );\n },\n };\n}\n\n/**\n * Create a FileSource from a Blob object\n */\nfunction createBlobFileSource(blob: Blob): FileSource {\n return {\n input: blob,\n size: blob.size,\n async slice(start: number, end: number): Promise<SliceResult> {\n const chunk = blob.slice(start, end);\n\n // React Native/Expo Blob may not have arrayBuffer() method\n // Always use FileReader fallback for compatibility\n const arrayBuffer = await blobToArrayBuffer(chunk);\n\n const done = end >= blob.size;\n\n return {\n done,\n value: new Uint8Array(arrayBuffer),\n size: chunk.size,\n };\n },\n close() {\n // No cleanup needed for Blob\n },\n name: null,\n lastModified: null,\n type: null,\n };\n}\n\n/**\n * Convert Blob to ArrayBuffer using FileReader (fallback for React Native/Expo)\n */\nfunction blobToArrayBuffer(blob: Blob): Promise<ArrayBuffer> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n if (reader.result instanceof ArrayBuffer) {\n resolve(reader.result);\n } else {\n reject(new Error(\"FileReader result is not an ArrayBuffer\"));\n }\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(blob);\n });\n}\n\n/**\n * Create a FileSource from a URI using Expo FileSystem\n * This implementation uses expo-file-system for native file access\n */\nfunction createExpoUriFileSource(uri: string): FileSource {\n // For Expo URIs, we use FileSystem to read the file\n let cachedBlob: Blob | null = null;\n let cachedSize: number | null = null;\n\n return {\n input: uri,\n size: cachedSize,\n async slice(start: number, end: number): Promise<SliceResult> {\n // Fetch the blob if not cached\n if (!cachedBlob) {\n try {\n // Use Expo FileSystem to read the file as base64\n const FileSystem = await getExpoFileSystem();\n const fileInfo = await FileSystem.getInfoAsync(uri);\n\n if (!fileInfo.exists) {\n throw new Error(`File does not exist at URI: ${uri}`);\n }\n\n cachedSize = fileInfo.size ?? 0;\n\n // Read the entire file as base64\n const base64String = await FileSystem.readAsStringAsync(uri, {\n encoding: FileSystem.EncodingType.Base64,\n });\n\n // Convert base64 to Uint8Array and cache size\n const uint8Array = base64ToUint8Array(base64String);\n cachedSize = uint8Array.length;\n\n // Create a Blob from the Uint8Array buffer\n // React Native Blob constructor accepts array-like objects\n // biome-ignore lint/suspicious/noExplicitAny: React Native Blob constructor type compatibility\n cachedBlob = new Blob([uint8Array.buffer] as any);\n } catch (error) {\n throw new Error(`Failed to read file from URI ${uri}: ${error}`);\n }\n }\n\n const chunk = cachedBlob.slice(start, end);\n\n // React Native/Expo Blob may not have arrayBuffer() method\n // Always use FileReader fallback for compatibility\n const arrayBuffer = await blobToArrayBuffer(chunk);\n\n const done = end >= cachedBlob.size;\n\n return {\n done,\n value: new Uint8Array(arrayBuffer),\n size: chunk.size,\n };\n },\n close() {\n // Clear cached blob\n cachedBlob = null;\n cachedSize = null;\n },\n name: uri,\n lastModified: null,\n type: null,\n };\n}\n\n/**\n * Dynamically import Expo FileSystem\n * This allows the service to work even if expo-file-system is not installed\n */\nasync function getExpoFileSystem() {\n try {\n return require(\"expo-file-system\");\n } catch (_error) {\n throw new Error(\n \"expo-file-system is required but not installed. \" +\n \"Please install it with: npx expo install expo-file-system\",\n );\n }\n}\n\n/**\n * Convert base64 string to Uint8Array\n * Uses js-base64 library for cross-platform compatibility\n */\nfunction base64ToUint8Array(base64: string): Uint8Array {\n // Use js-base64 for decoding (works in all environments)\n const { fromBase64 } = require(\"js-base64\");\n const binaryString = fromBase64(base64);\n\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","import type {\n ConnectionHealth,\n ConnectionMetrics,\n ConnectionPoolConfig,\n DetailedConnectionMetrics,\n HeadersLike,\n Http2Info,\n HttpClient,\n HttpRequestOptions,\n HttpResponse,\n} from \"@uploadista/client-core\";\n\n/**\n * Expo-specific implementation of HttpClient using fetch API\n * Expo's fetch is similar to browser fetch but optimized for React Native\n */\nexport function createExpoHttpClient(\n config?: ConnectionPoolConfig,\n): HttpClient {\n return new ExpoHttpClient(config);\n}\n\n/**\n * Expo HTTP client implementation\n */\nclass ExpoHttpClient implements HttpClient {\n private metrics: ConnectionMetrics;\n private connectionTimes: number[] = [];\n private requestCount = 0;\n private errorCount = 0;\n private timeoutCount = 0;\n private retryCount = 0;\n private startTime = Date.now();\n\n constructor(_config: ConnectionPoolConfig = {}) {\n // Configuration is stored for potential future use\n // Currently Expo doesn't expose connection pool configuration\n\n this.metrics = {\n activeConnections: 0,\n totalConnections: 0,\n reuseRate: 0,\n averageConnectionTime: 0,\n };\n }\n\n async request(\n url: string,\n options: HttpRequestOptions = {},\n ): Promise<HttpResponse> {\n this.requestCount++;\n\n const fetchOptions: RequestInit = {\n method: options.method || \"GET\",\n headers: options.headers,\n // biome-ignore lint/suspicious/noExplicitAny: Expo's BodyInit type compatibility\n body: options.body as any,\n signal: options.signal as AbortSignal | undefined,\n };\n\n // Add credentials if specified\n if (options.credentials) {\n // biome-ignore lint/suspicious/noExplicitAny: Expo's RequestCredentials type compatibility\n fetchOptions.credentials = options.credentials as any;\n }\n\n const startTime = Date.now();\n\n try {\n // Handle timeout\n const timeoutPromise = options.timeout\n ? new Promise<never>((_, reject) => {\n setTimeout(() => {\n this.timeoutCount++;\n reject(new Error(`Request timeout after ${options.timeout}ms`));\n }, options.timeout);\n })\n : null;\n\n const fetchPromise = fetch(url, fetchOptions);\n\n const response = timeoutPromise\n ? await Promise.race([fetchPromise, timeoutPromise])\n : await fetchPromise;\n\n const connectionTime = Date.now() - startTime;\n this.connectionTimes.push(connectionTime);\n this.metrics.totalConnections++;\n this.updateMetrics();\n\n // Convert fetch Response to HttpResponse\n return this.adaptResponse(response);\n } catch (error) {\n this.errorCount++;\n throw error;\n }\n }\n\n private adaptResponse(response: Response): HttpResponse {\n const headers: HeadersLike = {\n get: (name: string) => response.headers.get(name),\n has: (name: string) => response.headers.has(name),\n forEach: (callback: (value: string, name: string) => void) => {\n response.headers.forEach(callback);\n },\n };\n\n return {\n status: response.status,\n statusText: response.statusText,\n headers,\n ok: response.ok,\n json: () => response.json(),\n text: () => response.text(),\n arrayBuffer: () => response.arrayBuffer(),\n };\n }\n\n private updateMetrics(): void {\n if (this.connectionTimes.length > 0) {\n const sum = this.connectionTimes.reduce((a, b) => a + b, 0);\n this.metrics.averageConnectionTime = sum / this.connectionTimes.length;\n }\n\n // Estimate reuse rate based on connection times\n // Faster connections are likely reused\n const fastConnections = this.connectionTimes.filter(\n (time) => time < 100,\n ).length;\n this.metrics.reuseRate =\n this.connectionTimes.length > 0\n ? fastConnections / this.connectionTimes.length\n : 0;\n }\n\n getMetrics(): ConnectionMetrics {\n return { ...this.metrics };\n }\n\n getDetailedMetrics(): DetailedConnectionMetrics {\n const uptime = Date.now() - this.startTime;\n const requestsPerSecond =\n uptime > 0 ? this.requestCount / (uptime / 1000) : 0;\n const errorRate =\n this.requestCount > 0 ? this.errorCount / this.requestCount : 0;\n\n const fastConnections = this.connectionTimes.filter(\n (time) => time < 100,\n ).length;\n const slowConnections = this.connectionTimes.length - fastConnections;\n\n const health = this.calculateHealth(errorRate);\n\n const http2Info: Http2Info = {\n supported: false, // Expo doesn't support HTTP/2\n detected: false,\n version: \"h1.1\",\n multiplexingActive: false,\n };\n\n return {\n ...this.metrics,\n health,\n requestsPerSecond,\n errorRate,\n timeouts: this.timeoutCount,\n retries: this.retryCount,\n fastConnections,\n slowConnections,\n http2Info,\n };\n }\n\n private calculateHealth(errorRate: number): ConnectionHealth {\n let status: \"healthy\" | \"degraded\" | \"poor\";\n let score: number;\n const issues: string[] = [];\n const recommendations: string[] = [];\n\n if (errorRate > 0.1) {\n status = \"poor\";\n score = 30;\n issues.push(`High error rate: ${(errorRate * 100).toFixed(1)}%`);\n recommendations.push(\"Check network connectivity\");\n } else if (errorRate > 0.05) {\n status = \"degraded\";\n score = 60;\n issues.push(`Moderate error rate: ${(errorRate * 100).toFixed(1)}%`);\n recommendations.push(\"Monitor connection stability\");\n } else {\n status = \"healthy\";\n score = 100;\n }\n\n if (this.metrics.averageConnectionTime > 1000) {\n issues.push(\n `Slow connections: ${this.metrics.averageConnectionTime.toFixed(0)}ms avg`,\n );\n recommendations.push(\"Check network conditions\");\n score = Math.min(score, 70);\n }\n\n return { status, score, issues, recommendations };\n }\n\n reset(): void {\n this.metrics = {\n activeConnections: 0,\n totalConnections: 0,\n reuseRate: 0,\n averageConnectionTime: 0,\n };\n this.connectionTimes = [];\n this.requestCount = 0;\n this.errorCount = 0;\n this.timeoutCount = 0;\n this.retryCount = 0;\n this.startTime = Date.now();\n }\n\n async close(): Promise<void> {\n // Expo fetch doesn't require explicit connection closing\n this.reset();\n }\n\n async warmupConnections(urls: string[]): Promise<void> {\n // Warmup by making HEAD requests to the URLs\n const promises = urls.map((url) =>\n this.request(url, { method: \"HEAD\" }).catch(() => {\n // Ignore warmup errors\n }),\n );\n await Promise.all(promises);\n }\n}\n","import type { IdGenerationService } from \"@uploadista/client-core\";\nimport { v4 as uuidv4 } from \"uuid\";\n\n/**\n * Expo-specific implementation of IdGenerationService using uuid library\n * crypto.randomUUID() is not available in Expo/React Native, so we use the uuid library\n */\nexport function createExpoIdGenerationService(): IdGenerationService {\n return {\n generate(): string {\n return uuidv4();\n },\n };\n}\n","import type { PlatformService, Timeout } from \"@uploadista/client-core\";\n\n/**\n * Expo implementation of PlatformService\n */\nexport function createExpoPlatformService(): PlatformService {\n return {\n setTimeout: (callback: () => void, ms: number | undefined) => {\n return globalThis.setTimeout(callback, ms);\n },\n\n clearTimeout: (id: Timeout) => {\n globalThis.clearTimeout(id as number);\n },\n\n isBrowser: () => {\n return false;\n },\n\n isOnline: () => {\n // Expo's NetInfo would need to be imported separately\n // For now, assume online\n return true;\n },\n\n isFileLike: (value: unknown) => {\n // Check for blob-like interface or File-like object\n return (\n value !== null &&\n typeof value === \"object\" &&\n (\"uri\" in value || \"name\" in value)\n );\n },\n\n getFileName: (file: unknown) => {\n if (file !== null && typeof file === \"object\" && \"name\" in file) {\n return (file as Record<string, unknown>).name as string | undefined;\n }\n if (file !== null && typeof file === \"object\" && \"uri\" in file) {\n const uri = (file as Record<string, unknown>).uri as string | undefined;\n if (uri) {\n return uri.split(\"/\").pop();\n }\n }\n return undefined;\n },\n\n getFileType: (file: unknown) => {\n if (file !== null && typeof file === \"object\" && \"type\" in file) {\n return (file as Record<string, unknown>).type as string | undefined;\n }\n return undefined;\n },\n\n getFileSize: (file: unknown) => {\n if (file !== null && typeof file === \"object\" && \"size\" in file) {\n return (file as Record<string, unknown>).size as number | undefined;\n }\n return undefined;\n },\n\n getFileLastModified: (file: unknown) => {\n if (file !== null && typeof file === \"object\" && \"lastModified\" in file) {\n return (file as Record<string, unknown>).lastModified as\n | number\n | undefined;\n }\n return undefined;\n },\n };\n}\n","import AsyncStorage from \"@react-native-async-storage/async-storage\";\nimport type { StorageService } from \"@uploadista/client-core\";\n/**\n * Expo-specific implementation of StorageService using AsyncStorage\n * AsyncStorage is provided as an optional peer dependency and must be installed separately\n */\nexport function createAsyncStorageService(): StorageService {\n const findEntries = async (\n prefix: string,\n ): Promise<Record<string, string>> => {\n const results: Record<string, string> = {};\n\n const keys = await AsyncStorage.getAllKeys();\n for (const key in keys) {\n if (key.startsWith(prefix)) {\n const item = await AsyncStorage.getItem(key);\n if (item) {\n results[key] = item;\n }\n }\n }\n\n return results;\n };\n\n return {\n async getItem(key: string): Promise<string | null> {\n try {\n return await AsyncStorage.getItem(key);\n } catch (error) {\n console.error(`AsyncStorage getItem error for key ${key}:`, error);\n return null;\n }\n },\n\n async setItem(key: string, value: string): Promise<void> {\n try {\n await AsyncStorage.setItem(key, value);\n } catch (error) {\n console.error(`AsyncStorage setItem error for key ${key}:`, error);\n throw error;\n }\n },\n\n async removeItem(key: string): Promise<void> {\n try {\n await AsyncStorage.removeItem(key);\n } catch (error) {\n console.error(`AsyncStorage removeItem error for key ${key}:`, error);\n throw error;\n }\n },\n\n async findAll(): Promise<Record<string, string>> {\n return findEntries(\"\");\n },\n\n async find(prefix: string): Promise<Record<string, string>> {\n return findEntries(prefix);\n },\n };\n}\n","import type { WebSocketFactory, WebSocketLike } from \"@uploadista/client-core\";\n\n/**\n * Expo WebSocket implementation that wraps native WebSocket\n * Expo provides a WebSocket API that is compatible with the browser WebSocket API\n */\nclass ExpoWebSocket implements WebSocketLike {\n readonly CONNECTING = 0;\n readonly OPEN = 1;\n readonly CLOSING = 2;\n readonly CLOSED = 3;\n\n readyState: number;\n onopen: (() => void) | null = null;\n onclose: ((event: { code: number; reason: string }) => void) | null = null;\n onerror: ((event: { message: string }) => void) | null = null;\n onmessage: ((event: { data: string }) => void) | null = null;\n\n private native: WebSocket;\n\n constructor(url: string) {\n this.native = new WebSocket(url);\n this.readyState = this.native.readyState;\n\n // Proxy event handlers\n this.native.onopen = () => {\n this.readyState = this.native.readyState;\n this.onopen?.();\n };\n\n this.native.onclose = (event) => {\n this.readyState = this.native.readyState;\n this.onclose?.({\n code: event.code ?? 1000,\n reason: event.reason ?? \"undefined reason\",\n });\n };\n\n this.native.onerror = (event) => {\n this.onerror?.(event);\n };\n\n this.native.onmessage = (event) => {\n this.onmessage?.({ data: event.data });\n };\n }\n\n send(data: string | Uint8Array): void {\n this.native.send(data);\n }\n\n close(code?: number, reason?: string): void {\n this.native.close(code, reason);\n }\n}\n\n/**\n * Factory for creating Expo WebSocket connections\n */\nexport const createExpoWebSocketFactory = (): WebSocketFactory => ({\n create: (url: string): WebSocketLike => new ExpoWebSocket(url),\n});\n","import * as Crypto from \"expo-crypto\";\n\n/**\n * Compute SHA-256 checksum using Web Crypto API\n * Compatible with React Native and Expo environments\n *\n * @param data - Uint8Array to hash\n * @returns Promise that resolves to hex-encoded SHA-256 checksum\n */\nexport async function computeUint8ArraySha256(\n data: Uint8Array,\n): Promise<string> {\n try {\n // Compute SHA-256 hash using Web Crypto API\n const hashBuffer = await Crypto.digest(\n Crypto.CryptoDigestAlgorithm.SHA256,\n data,\n );\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return hashHex;\n } catch (error) {\n throw new Error(\n `Failed to compute checksum: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n}\n\n/**\n * Compute SHA-256 checksum of a Blob using Web Crypto API\n * Compatible with React Native and Expo Blob objects\n *\n * @param blob - Blob to hash\n * @returns Promise that resolves to hex-encoded SHA-256 checksum\n */\nexport async function computeblobSha256(blob: Blob): Promise<string> {\n try {\n // Convert Blob to Uint8Array using FileReader for compatibility\n const uint8Array = await blobToUint8Array(blob);\n return computeUint8ArraySha256(uint8Array);\n } catch (error) {\n throw new Error(\n `Failed to compute file checksum: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n}\n\n/**\n * Convert Blob to Uint8Array using FileReader\n * Works in React Native and Expo environments\n */\nasync function blobToUint8Array(blob: Blob): Promise<Uint8Array> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = () => {\n if (reader.result instanceof ArrayBuffer) {\n resolve(new Uint8Array(reader.result));\n } else {\n reject(new Error(\"FileReader result is not an ArrayBuffer\"));\n }\n };\n reader.onerror = () => reject(reader.error);\n reader.readAsArrayBuffer(blob);\n });\n}\n","import type { ChecksumService } from \"@uploadista/client-core\";\nimport { computeUint8ArraySha256 } from \"../utils/hash-util\";\n\n/**\n * Creates a ChecksumService for Expo environments\n * Computes SHA-256 checksums of file data using Web Crypto API\n */\nexport function createExpoChecksumService(): ChecksumService {\n return {\n computeChecksum: async (data: Uint8Array<ArrayBuffer>) => {\n return computeUint8ArraySha256(data);\n },\n };\n}\n","import type { FingerprintService } from \"@uploadista/client-core\";\nimport * as Crypto from \"expo-crypto\";\nimport type { ExpoUploadInput } from \"../types/upload-input\";\nimport { computeblobSha256 } from \"../utils/hash-util\";\n\n/**\n * Creates a FingerprintService for Expo environments\n * Computes file fingerprints using SHA-256 hashing\n * Supports Blob, File, and URI-based inputs\n */\nexport function createExpoFingerprintService(): FingerprintService<ExpoUploadInput> {\n return {\n computeFingerprint: async (input, _endpoint) => {\n // Handle Blob/File objects directly\n if (input instanceof Blob) {\n return computeblobSha256(input);\n }\n\n // For URI inputs (string or {uri: string}), we need to convert to Blob first\n if (\n typeof input === \"string\" ||\n (input && typeof input === \"object\" && \"uri\" in input)\n ) {\n const uri =\n typeof input === \"string\" ? input : (input as { uri: string }).uri;\n return computeFingerprintFromUri(uri);\n }\n\n throw new Error(\n \"Unsupported file input type for fingerprinting. Expected Blob, File, URI string, or {uri: string}\",\n );\n },\n };\n}\n\n/**\n * Compute fingerprint from a Expo file URI\n * Uses Expo FileSystem to read the file and compute its SHA-256 hash\n */\nasync function computeFingerprintFromUri(uri: string): Promise<string> {\n try {\n // Use Expo FileSystem to read the file as base64\n const FileSystem = await getExpoFileSystem();\n const fileInfo = await FileSystem.getInfoAsync(uri);\n\n if (!fileInfo.exists) {\n throw new Error(`File does not exist at URI: ${uri}`);\n }\n\n // Read the entire file as base64\n const base64String = await FileSystem.readAsStringAsync(uri, {\n encoding: FileSystem.EncodingType.Base64,\n });\n\n // Convert base64 to Uint8Array\n const uint8Array = base64ToUint8Array(base64String);\n\n // Compute SHA-256 hash directly on the Uint8Array\n const hashBuffer = await Crypto.digest(\n Crypto.CryptoDigestAlgorithm.SHA256,\n uint8Array,\n );\n\n // Convert hash to hex string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray\n .map((byte) => byte.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return hashHex;\n } catch (error) {\n throw new Error(\n `Failed to compute fingerprint from URI ${uri}: ${error instanceof Error ? error.message : \"Unknown error\"}`,\n );\n }\n}\n\n/**\n * Dynamically import Expo FileSystem\n * This allows the service to work even if expo-file-system is not installed\n */\nasync function getExpoFileSystem() {\n try {\n return require(\"expo-file-system\");\n } catch (_error) {\n throw new Error(\n \"expo-file-system is required for URI-based fingerprinting. \" +\n \"Please install it with: npx expo install expo-file-system\",\n );\n }\n}\n\n/**\n * Convert base64 string to Uint8Array\n * Uses js-base64 library for cross-platform compatibility\n */\nfunction base64ToUint8Array(base64: string): Uint8Array {\n // Use js-base64 for decoding (works in all environments)\n const { fromBase64 } = require(\"js-base64\");\n const binaryString = fromBase64(base64);\n\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes;\n}\n","import {\n type ConnectionPoolConfig,\n createInMemoryStorageService,\n type ServiceContainer,\n} from \"@uploadista/client-core\";\nimport type { ReactNativeUploadInput } from \"@uploadista/react-native-core\";\nimport { createExpoAbortControllerFactory } from \"./abort-controller-factory\";\nimport { createExpoBase64Service } from \"./base64-service\";\nimport { createExpoFileReaderService } from \"./file-reader-service\";\nimport { createExpoHttpClient } from \"./http-client\";\nimport { createExpoIdGenerationService } from \"./id-generation-service\";\nimport { createExpoPlatformService } from \"./platform-service\";\nimport { createAsyncStorageService } from \"./storage-service\";\nimport { createExpoWebSocketFactory } from \"./websocket-factory\";\nimport { createExpoChecksumService } from \"./checksum-service\";\nimport { createExpoFingerprintService } from \"./fingerprint-service\";\n\nexport interface ExpoServiceOptions {\n /**\n * HTTP client configuration for connection pooling\n */\n connectionPooling?: ConnectionPoolConfig;\n\n /**\n * Whether to use AsyncStorage for persistence\n * If false, uses in-memory storage\n * @default true\n */\n useAsyncStorage?: boolean;\n}\n\n/**\n * Creates a service container with Expo-specific implementations\n * of all required services for the upload client\n *\n * @param options - Configuration options for Expo services\n * @returns ServiceContainer with Expo implementations\n *\n * @example\n * ```typescript\n * import { createExpoServices } from '@uploadista/expo/services';\n *\n * const services = createExpoServices({\n * useAsyncStorage: true,\n * connectionPooling: {\n * maxConnectionsPerHost: 6,\n * connectionTimeout: 30000,\n * }\n * });\n * ```\n */\nexport function createExpoServices(\n options: ExpoServiceOptions = {},\n): ServiceContainer<ReactNativeUploadInput> {\n const { connectionPooling, useAsyncStorage = true } = options;\n\n // Create storage service (AsyncStorage or in-memory fallback)\n const storage = useAsyncStorage\n ? createAsyncStorageService()\n : createInMemoryStorageService();\n\n // Create other services\n const idGeneration = createExpoIdGenerationService();\n const httpClient = createExpoHttpClient(connectionPooling);\n const fileReader = createExpoFileReaderService();\n const base64 = createExpoBase64Service();\n const websocket = createExpoWebSocketFactory();\n const abortController = createExpoAbortControllerFactory();\n const platform = createExpoPlatformService();\n const checksumService = createExpoChecksumService();\n const fingerprintService = createExpoFingerprintService();\n\n return {\n storage,\n idGeneration,\n httpClient,\n fileReader,\n base64,\n websocket,\n abortController,\n platform,\n checksumService,\n fingerprintService,\n };\n}\n","import {\n type ConnectionPoolConfig,\n createClientStorage,\n createLogger,\n createUploadistaClient as createUploadistaClientCore,\n type UploadistaClientOptions as UploadistaClientOptionsCore,\n} from \"@uploadista/client-core\";\nimport { createExpoServices } from \"../services/create-expo-services\";\nimport type { ExpoUploadInput } from \"../types/upload-input\";\n\nexport interface UploadistaClientOptions\n extends Omit<\n UploadistaClientOptionsCore<ExpoUploadInput>,\n | \"webSocketFactory\"\n | \"abortControllerFactory\"\n | \"generateId\"\n | \"clientStorage\"\n | \"logger\"\n | \"httpClient\"\n | \"fileReader\"\n | \"base64\"\n > {\n connectionPooling?: ConnectionPoolConfig;\n\n /**\n * Whether to use AsyncStorage for persistence\n * If false, uses in-memory storage\n * @default true\n */\n useAsyncStorage?: boolean;\n}\n\n/**\n * Creates an upload client instance with Expo-specific service implementations\n *\n * @param options - Client configuration options\n * @returns Configured UploadistaClient instance\n *\n * @example\n * ```typescript\n * import { createUploadistaClient } from '@uploadista/expo'\n *\n * const client = createUploadistaClient({\n * baseUrl: 'https://api.example.com',\n * storageId: 'my-storage',\n * chunkSize: 1024 * 1024, // 1MB\n * useAsyncStorage: true,\n * });\n * ```\n */\nexport function createUploadistaClient(options: UploadistaClientOptions) {\n const services = createExpoServices({\n connectionPooling: options.connectionPooling,\n useAsyncStorage: options.useAsyncStorage,\n });\n\n return createUploadistaClientCore<ExpoUploadInput>({\n ...options,\n webSocketFactory: services.websocket,\n abortControllerFactory: services.abortController,\n httpClient: services.httpClient,\n fileReader: services.fileReader,\n generateId: services.idGeneration,\n logger: createLogger(false, () => {}),\n clientStorage: createClientStorage(services.storage),\n });\n}\n","import * as DocumentPicker from \"expo-document-picker\";\nimport * as FileSystem from \"expo-file-system\";\nimport * as ImagePicker from \"expo-image-picker\";\nimport type {\n CameraOptions,\n FileInfo,\n FilePickResult,\n FileSystemProvider,\n PickerOptions,\n} from \"../types\";\n\n/**\n * File system provider implementation for Expo managed environment\n * Uses Expo DocumentPicker, ImagePicker, Camera, and FileSystem APIs\n */\nexport class ExpoFileSystemProvider implements FileSystemProvider {\n async pickDocument(options?: PickerOptions): Promise<FilePickResult> {\n try {\n const result = (await DocumentPicker.getDocumentAsync({\n type: options?.allowedTypes || [\"*/*\"],\n copyToCacheDirectory: true,\n })) as {\n canceled: boolean;\n assets?: Array<{\n uri: string;\n name: string;\n size?: number;\n mimeType?: string;\n }>;\n };\n\n if (result.canceled) {\n throw new Error(\"Document picker was cancelled\");\n }\n\n const asset = result.assets?.[0];\n if (!asset) {\n throw new Error(\"No document selected\");\n }\n\n return {\n uri: asset.uri,\n name: asset.name,\n size: asset.size || 0,\n mimeType: asset.mimeType,\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"cancelled\")) {\n throw error;\n }\n throw new Error(\n `Failed to pick document: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async pickImage(options?: PickerOptions): Promise<FilePickResult> {\n try {\n // Request permissions\n const { status } =\n await ImagePicker.requestMediaLibraryPermissionsAsync();\n if (status !== \"granted\") {\n throw new Error(\"Camera roll permission not granted\");\n }\n\n const result = await ImagePicker.launchImageLibraryAsync({\n // biome-ignore lint/suspicious/noExplicitAny: Expo ImagePicker mediaTypes type compatibility\n mediaTypes: \"Images\" as any,\n selectionLimit: options?.allowMultiple ? 0 : 1,\n quality: 1,\n });\n\n if (result.canceled) {\n throw new Error(\"Image picker was cancelled\");\n }\n\n const asset = result.assets?.[0];\n if (!asset) {\n throw new Error(\"No image selected\");\n }\n\n return {\n uri: asset.uri,\n name: asset.fileName || `image-${Date.now()}.jpg`,\n size: asset.fileSize || 0,\n mimeType: \"image/jpeg\",\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"cancelled\")) {\n throw error;\n }\n throw new Error(\n `Failed to pick image: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async pickVideo(options?: PickerOptions): Promise<FilePickResult> {\n try {\n // Request permissions\n const { status } =\n await ImagePicker.requestMediaLibraryPermissionsAsync();\n if (status !== \"granted\") {\n throw new Error(\"Camera roll permission not granted\");\n }\n\n const result = await ImagePicker.launchImageLibraryAsync({\n // biome-ignore lint/suspicious/noExplicitAny: Expo ImagePicker mediaTypes type compatibility\n mediaTypes: \"Videos\" as any,\n selectionLimit: options?.allowMultiple ? 0 : 1,\n });\n\n if (result.canceled) {\n throw new Error(\"Video picker was cancelled\");\n }\n\n const asset = result.assets?.[0];\n if (!asset) {\n throw new Error(\"No video selected\");\n }\n\n return {\n uri: asset.uri,\n name: asset.fileName || `video-${Date.now()}.mp4`,\n size: asset.fileSize || 0,\n mimeType: \"video/mp4\",\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"cancelled\")) {\n throw error;\n }\n throw new Error(\n `Failed to pick video: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async pickCamera(options?: CameraOptions): Promise<FilePickResult> {\n try {\n // Request camera permissions\n const { status } = await ImagePicker.requestCameraPermissionsAsync();\n if (status !== \"granted\") {\n throw new Error(\"Camera permission not granted\");\n }\n\n const result = await ImagePicker.launchCameraAsync({\n allowsEditing: false,\n aspect: [4, 3],\n quality: options?.quality ?? 1,\n });\n\n if (result.canceled) {\n throw new Error(\"Camera capture was cancelled\");\n }\n\n const asset = result.assets?.[0];\n if (!asset) {\n throw new Error(\"No photo captured\");\n }\n\n return {\n uri: asset.uri,\n name: asset.fileName || `photo-${Date.now()}.jpg`,\n size: asset.fileSize || 0,\n mimeType: \"image/jpeg\",\n };\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"cancelled\")) {\n throw error;\n }\n throw new Error(\n `Failed to capture photo: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async readFile(uri: string): Promise<ArrayBuffer> {\n try {\n // Read file as base64\n const base64String = await FileSystem.readAsStringAsync(uri, {\n encoding: FileSystem.EncodingType.Base64,\n });\n\n // Convert base64 to ArrayBuffer\n // Use js-base64 for decoding since atob is not available in all RN environments\n const { fromBase64 } = await import(\"js-base64\");\n const binaryString = fromBase64(base64String);\n const bytes = new Uint8Array(binaryString.length);\n for (let i = 0; i < binaryString.length; i++) {\n bytes[i] = binaryString.charCodeAt(i);\n }\n return bytes.buffer;\n } catch (error) {\n throw new Error(\n `Failed to read file: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n\n async getDocumentUri(filePath: string): Promise<string> {\n // In Expo, the file path is typically already a URI\n return filePath;\n }\n\n async getFileInfo(uri: string): Promise<FileInfo> {\n try {\n const fileInfo = await FileSystem.getInfoAsync(uri);\n\n if (!fileInfo.exists) {\n throw new Error(\"File does not exist\");\n }\n\n return {\n uri,\n name: uri.split(\"/\").pop() || \"unknown\",\n size: fileInfo.size ?? 0,\n modificationTime: fileInfo.modificationTime\n ? fileInfo.modificationTime * 1000\n : undefined,\n };\n } catch (error) {\n throw new Error(\n `Failed to get file info: ${error instanceof Error ? error.message : String(error)}`,\n );\n }\n }\n}\n"],"mappings":"ueAUM,EAAN,KAAyD,CACvD,OAEA,aAAc,CACZ,KAAK,OAAS,IAAI,gBAGpB,IAAI,QAA0B,CAC5B,OAAO,KAAK,OAAO,OAGrB,MAAM,EAAyB,CAC7B,KAAK,OAAO,OAAO,GAOvB,MAAa,OAAkE,CAC7E,WAAmC,IAAI,EACxC,ECxBD,SAAgB,GAAyC,CACvD,MAAO,CACL,SAAS,EAA2B,CAElC,IAAM,EAAa,IAAI,WAAW,EAAK,CAKvC,OAAOA,EAHQ,MAAM,KAAK,EAAW,CAClC,IAAK,GAAS,OAAO,aAAa,EAAK,CAAC,CACxC,KAAK,GAAG,CACU,EAGvB,WAAW,EAA2B,CACpC,IAAM,EAASC,EAAO,EAAK,CACrB,EAAa,IAAI,WAAW,EAAO,OAAO,CAChD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAO,OAAQ,IACjC,EAAW,GAAK,EAAO,WAAW,EAAE,CAEtC,OAAO,EAAW,QAErB,CChBH,SAAgB,GAAkE,CAChF,MAAO,CACL,MAAM,SAAS,EAAgB,EAAyC,CAEtE,GAAI,aAAiB,KACnB,OAAO,EAAqB,EAAM,CAIpC,GACE,OAAO,GAAU,UAChB,GAAS,OAAO,GAAU,UAAY,QAAS,EAIhD,OAAO,EADL,OAAO,GAAU,SAAW,EAAS,EAA0B,IAC9B,CAGrC,MAAU,MACR,0FACD,EAEJ,CAMH,SAAS,EAAqB,EAAwB,CACpD,MAAO,CACL,MAAO,EACP,KAAM,EAAK,KACX,MAAM,MAAM,EAAe,EAAmC,CAC5D,IAAM,EAAQ,EAAK,MAAM,EAAO,EAAI,CAI9B,EAAc,MAAM,EAAkB,EAAM,CAIlD,MAAO,CACL,KAHW,GAAO,EAAK,KAIvB,MAAO,IAAI,WAAW,EAAY,CAClC,KAAM,EAAM,KACb,EAEH,OAAQ,GAGR,KAAM,KACN,aAAc,KACd,KAAM,KACP,CAMH,SAAS,EAAkB,EAAkC,CAC3D,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAS,IAAI,WACnB,EAAO,WAAe,CAChB,EAAO,kBAAkB,YAC3B,EAAQ,EAAO,OAAO,CAEtB,EAAW,MAAM,0CAA0C,CAAC,EAGhE,EAAO,YAAgB,EAAO,EAAO,MAAM,CAC3C,EAAO,kBAAkB,EAAK,EAC9B,CAOJ,SAAS,EAAwB,EAAyB,CAExD,IAAIC,EAA0B,KAC1BC,EAA4B,KAEhC,MAAO,CACL,MAAO,EACP,KAAM,EACN,MAAM,MAAM,EAAe,EAAmC,CAE5D,GAAI,CAAC,EACH,GAAI,CAEF,IAAMC,EAAa,MAAMC,GAAmB,CACtC,EAAW,MAAMD,EAAW,aAAa,EAAI,CAEnD,GAAI,CAAC,EAAS,OACZ,MAAU,MAAM,+BAA+B,IAAM,CAGvD,EAAa,EAAS,MAAQ,EAQ9B,IAAM,EAAaE,EALE,MAAMF,EAAW,kBAAkB,EAAK,CAC3D,SAAUA,EAAW,aAAa,OACnC,CAAC,CAGiD,CACnD,EAAa,EAAW,OAKxB,EAAa,IAAI,KAAK,CAAC,EAAW,OAAO,CAAQ,OAC1C,EAAO,CACd,MAAU,MAAM,gCAAgC,EAAI,IAAI,IAAQ,CAIpE,IAAM,EAAQ,EAAW,MAAM,EAAO,EAAI,CAIpC,EAAc,MAAM,EAAkB,EAAM,CAIlD,MAAO,CACL,KAHW,GAAO,EAAW,KAI7B,MAAO,IAAI,WAAW,EAAY,CAClC,KAAM,EAAM,KACb,EAEH,OAAQ,CAEN,EAAa,KACb,EAAa,MAEf,KAAM,EACN,aAAc,KACd,KAAM,KACP,CAOH,eAAeC,GAAoB,CACjC,GAAI,CACF,OAAA,EAAe,mBAAmB,MACnB,CACf,MAAU,MACR,4GAED,EAQL,SAASC,EAAmB,EAA4B,CAEtD,GAAM,CAAE,WAAA,GAAA,EAAuB,YAAY,CACrC,EAAeC,EAAW,EAAO,CAEjC,EAAQ,IAAI,WAAW,EAAa,OAAO,CACjD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,EAAM,GAAK,EAAa,WAAW,EAAE,CAEvC,OAAO,ECtKT,SAAgB,EACd,EACY,CACZ,OAAO,IAAI,EAAe,EAAO,CAMnC,IAAM,EAAN,KAA2C,CACzC,QACA,gBAAoC,EAAE,CACtC,aAAuB,EACvB,WAAqB,EACrB,aAAuB,EACvB,WAAqB,EACrB,UAAoB,KAAK,KAAK,CAE9B,YAAY,EAAgC,EAAE,CAAE,CAI9C,KAAK,QAAU,CACb,kBAAmB,EACnB,iBAAkB,EAClB,UAAW,EACX,sBAAuB,EACxB,CAGH,MAAM,QACJ,EACA,EAA8B,EAAE,CACT,CACvB,KAAK,eAEL,IAAMC,EAA4B,CAChC,OAAQ,EAAQ,QAAU,MAC1B,QAAS,EAAQ,QAEjB,KAAM,EAAQ,KACd,OAAQ,EAAQ,OACjB,CAGG,EAAQ,cAEV,EAAa,YAAc,EAAQ,aAGrC,IAAM,EAAY,KAAK,KAAK,CAE5B,GAAI,CAEF,IAAM,EAAiB,EAAQ,QAC3B,IAAI,SAAgB,EAAG,IAAW,CAChC,eAAiB,CACf,KAAK,eACL,EAAW,MAAM,yBAAyB,EAAQ,QAAQ,IAAI,CAAC,EAC9D,EAAQ,QAAQ,EACnB,CACF,KAEE,EAAe,MAAM,EAAK,EAAa,CAEvC,EAAW,EACb,MAAM,QAAQ,KAAK,CAAC,EAAc,EAAe,CAAC,CAClD,MAAM,EAEJ,EAAiB,KAAK,KAAK,CAAG,EAMpC,OALA,KAAK,gBAAgB,KAAK,EAAe,CACzC,KAAK,QAAQ,mBACb,KAAK,eAAe,CAGb,KAAK,cAAc,EAAS,OAC5B,EAAO,CAEd,KADA,MAAK,aACC,GAIV,cAAsB,EAAkC,CAStD,MAAO,CACL,OAAQ,EAAS,OACjB,WAAY,EAAS,WACrB,QAX2B,CAC3B,IAAM,GAAiB,EAAS,QAAQ,IAAI,EAAK,CACjD,IAAM,GAAiB,EAAS,QAAQ,IAAI,EAAK,CACjD,QAAU,GAAoD,CAC5D,EAAS,QAAQ,QAAQ,EAAS,EAErC,CAMC,GAAI,EAAS,GACb,SAAY,EAAS,MAAM,CAC3B,SAAY,EAAS,MAAM,CAC3B,gBAAmB,EAAS,aAAa,CAC1C,CAGH,eAA8B,CAC5B,GAAI,KAAK,gBAAgB,OAAS,EAAG,CACnC,IAAM,EAAM,KAAK,gBAAgB,QAAQ,EAAG,IAAM,EAAI,EAAG,EAAE,CAC3D,KAAK,QAAQ,sBAAwB,EAAM,KAAK,gBAAgB,OAKlE,IAAM,EAAkB,KAAK,gBAAgB,OAC1C,GAAS,EAAO,IAClB,CAAC,OACF,KAAK,QAAQ,UACX,KAAK,gBAAgB,OAAS,EAC1B,EAAkB,KAAK,gBAAgB,OACvC,EAGR,YAAgC,CAC9B,MAAO,CAAE,GAAG,KAAK,QAAS,CAG5B,oBAAgD,CAC9C,IAAM,EAAS,KAAK,KAAK,CAAG,KAAK,UAC3B,EACJ,EAAS,EAAI,KAAK,cAAgB,EAAS,KAAQ,EAC/C,EACJ,KAAK,aAAe,EAAI,KAAK,WAAa,KAAK,aAAe,EAE1D,EAAkB,KAAK,gBAAgB,OAC1C,GAAS,EAAO,IAClB,CAAC,OACI,EAAkB,KAAK,gBAAgB,OAAS,EAEhD,EAAS,KAAK,gBAAgB,EAAU,CAExCC,EAAuB,CAC3B,UAAW,GACX,SAAU,GACV,QAAS,OACT,mBAAoB,GACrB,CAED,MAAO,CACL,GAAG,KAAK,QACR,SACA,oBACA,YACA,SAAU,KAAK,aACf,QAAS,KAAK,WACd,kBACA,kBACA,YACD,CAGH,gBAAwB,EAAqC,CAC3D,IAAIC,EACAC,EACEC,EAAmB,EAAE,CACrBC,EAA4B,EAAE,CAyBpC,OAvBI,EAAY,IACd,EAAS,OACT,EAAQ,GACR,EAAO,KAAK,qBAAqB,EAAY,KAAK,QAAQ,EAAE,CAAC,GAAG,CAChE,EAAgB,KAAK,6BAA6B,EACzC,EAAY,KACrB,EAAS,WACT,EAAQ,GACR,EAAO,KAAK,yBAAyB,EAAY,KAAK,QAAQ,EAAE,CAAC,GAAG,CACpE,EAAgB,KAAK,+BAA+B,GAEpD,EAAS,UACT,EAAQ,KAGN,KAAK,QAAQ,sBAAwB,MACvC,EAAO,KACL,qBAAqB,KAAK,QAAQ,sBAAsB,QAAQ,EAAE,CAAC,QACpE,CACD,EAAgB,KAAK,2BAA2B,CAChD,EAAQ,KAAK,IAAI,EAAO,GAAG,EAGtB,CAAE,SAAQ,QAAO,SAAQ,kBAAiB,CAGnD,OAAc,CACZ,KAAK,QAAU,CACb,kBAAmB,EACnB,iBAAkB,EAClB,UAAW,EACX,sBAAuB,EACxB,CACD,KAAK,gBAAkB,EAAE,CACzB,KAAK,aAAe,EACpB,KAAK,WAAa,EAClB,KAAK,aAAe,EACpB,KAAK,WAAa,EAClB,KAAK,UAAY,KAAK,KAAK,CAG7B,MAAM,OAAuB,CAE3B,KAAK,OAAO,CAGd,MAAM,kBAAkB,EAA+B,CAErD,IAAM,EAAW,EAAK,IAAK,GACzB,KAAK,QAAQ,EAAK,CAAE,OAAQ,OAAQ,CAAC,CAAC,UAAY,GAEhD,CACH,CACD,MAAM,QAAQ,IAAI,EAAS,GCjO/B,SAAgB,GAAqD,CACnE,MAAO,CACL,UAAmB,CACjB,OAAOC,GAAQ,EAElB,CCPH,SAAgB,GAA6C,CAC3D,MAAO,CACL,YAAa,EAAsB,IAC1B,WAAW,WAAW,EAAU,EAAG,CAG5C,aAAe,GAAgB,CAC7B,WAAW,aAAa,EAAa,EAGvC,cACS,GAGT,aAGS,GAGT,WAAa,GAIT,OAAO,GAAU,YADjB,IAEC,QAAS,GAAS,SAAU,GAIjC,YAAc,GAAkB,CAC9B,GAAqB,OAAO,GAAS,UAAjC,GAA6C,SAAU,EACzD,OAAQ,EAAiC,KAE3C,GAAqB,OAAO,GAAS,UAAjC,GAA6C,QAAS,EAAM,CAC9D,IAAM,EAAO,EAAiC,IAC9C,GAAI,EACF,OAAO,EAAI,MAAM,IAAI,CAAC,KAAK,GAMjC,YAAc,GAAkB,CAC9B,GAAqB,OAAO,GAAS,UAAjC,GAA6C,SAAU,EACzD,OAAQ,EAAiC,MAK7C,YAAc,GAAkB,CAC9B,GAAqB,OAAO,GAAS,UAAjC,GAA6C,SAAU,EACzD,OAAQ,EAAiC,MAK7C,oBAAsB,GAAkB,CACtC,GAAqB,OAAO,GAAS,UAAjC,GAA6C,iBAAkB,EACjE,OAAQ,EAAiC,cAM9C,CC/DH,SAAgB,GAA4C,CAC1D,IAAM,EAAc,KAClB,IACoC,CACpC,IAAMC,EAAkC,EAAE,CAEpC,EAAO,MAAM,EAAa,YAAY,CAC5C,IAAK,IAAM,KAAO,EAChB,GAAI,EAAI,WAAW,EAAO,CAAE,CAC1B,IAAM,EAAO,MAAM,EAAa,QAAQ,EAAI,CACxC,IACF,EAAQ,GAAO,GAKrB,OAAO,GAGT,MAAO,CACL,MAAM,QAAQ,EAAqC,CACjD,GAAI,CACF,OAAO,MAAM,EAAa,QAAQ,EAAI,OAC/B,EAAO,CAEd,OADA,QAAQ,MAAM,sCAAsC,EAAI,GAAI,EAAM,CAC3D,OAIX,MAAM,QAAQ,EAAa,EAA8B,CACvD,GAAI,CACF,MAAM,EAAa,QAAQ,EAAK,EAAM,OAC/B,EAAO,CAEd,MADA,QAAQ,MAAM,sCAAsC,EAAI,GAAI,EAAM,CAC5D,IAIV,MAAM,WAAW,EAA4B,CAC3C,GAAI,CACF,MAAM,EAAa,WAAW,EAAI,OAC3B,EAAO,CAEd,MADA,QAAQ,MAAM,yCAAyC,EAAI,GAAI,EAAM,CAC/D,IAIV,MAAM,SAA2C,CAC/C,OAAO,EAAY,GAAG,EAGxB,MAAM,KAAK,EAAiD,CAC1D,OAAO,EAAY,EAAO,EAE7B,CCtDH,IAAM,EAAN,KAA6C,CAC3C,WAAsB,EACtB,KAAgB,EAChB,QAAmB,EACnB,OAAkB,EAElB,WACA,OAA8B,KAC9B,QAAsE,KACtE,QAAyD,KACzD,UAAwD,KAExD,OAEA,YAAY,EAAa,CACvB,KAAK,OAAS,IAAI,UAAU,EAAI,CAChC,KAAK,WAAa,KAAK,OAAO,WAG9B,KAAK,OAAO,WAAe,CACzB,KAAK,WAAa,KAAK,OAAO,WAC9B,KAAK,UAAU,EAGjB,KAAK,OAAO,QAAW,GAAU,CAC/B,KAAK,WAAa,KAAK,OAAO,WAC9B,KAAK,UAAU,CACb,KAAM,EAAM,MAAQ,IACpB,OAAQ,EAAM,QAAU,mBACzB,CAAC,EAGJ,KAAK,OAAO,QAAW,GAAU,CAC/B,KAAK,UAAU,EAAM,EAGvB,KAAK,OAAO,UAAa,GAAU,CACjC,KAAK,YAAY,CAAE,KAAM,EAAM,KAAM,CAAC,EAI1C,KAAK,EAAiC,CACpC,KAAK,OAAO,KAAK,EAAK,CAGxB,MAAM,EAAe,EAAuB,CAC1C,KAAK,OAAO,MAAM,EAAM,EAAO,GAOnC,MAAa,OAAsD,CACjE,OAAS,GAA+B,IAAI,EAAc,EAAI,CAC/D,ECpDD,eAAsB,EACpB,EACiB,CACjB,GAAI,CAEF,IAAM,EAAa,MAAM,EAAO,OAC9B,EAAO,sBAAsB,OAC7B,EACD,CAQD,OALkB,MAAM,KAAK,IAAI,WAAW,EAAW,CAAC,CAErD,IAAK,GAAS,EAAK,SAAS,GAAG,CAAC,SAAS,EAAG,IAAI,CAAC,CACjD,KAAK,GAAG,OAGJ,EAAO,CACd,MAAU,MACR,+BAA+B,aAAiB,MAAQ,EAAM,QAAU,kBACzE,EAWL,eAAsB,EAAkB,EAA6B,CACnE,GAAI,CAGF,OAAO,EADY,MAAM,EAAiB,EAAK,CACL,OACnC,EAAO,CACd,MAAU,MACR,oCAAoC,aAAiB,MAAQ,EAAM,QAAU,kBAC9E,EAQL,eAAe,EAAiB,EAAiC,CAC/D,OAAO,IAAI,SAAS,EAAS,IAAW,CACtC,IAAM,EAAS,IAAI,WACnB,EAAO,WAAe,CAChB,EAAO,kBAAkB,YAC3B,EAAQ,IAAI,WAAW,EAAO,OAAO,CAAC,CAEtC,EAAW,MAAM,0CAA0C,CAAC,EAGhE,EAAO,YAAgB,EAAO,EAAO,MAAM,CAC3C,EAAO,kBAAkB,EAAK,EAC9B,CC7DJ,SAAgB,GAA6C,CAC3D,MAAO,CACL,gBAAiB,KAAO,IACf,EAAwB,EAAK,CAEvC,CCFH,SAAgB,GAAoE,CAClF,MAAO,CACL,mBAAoB,MAAO,EAAO,IAAc,CAE9C,GAAI,aAAiB,KACnB,OAAO,EAAkB,EAAM,CAIjC,GACE,OAAO,GAAU,UAChB,GAAS,OAAO,GAAU,UAAY,QAAS,EAIhD,OAAO,EADL,OAAO,GAAU,SAAW,EAAS,EAA0B,IAC5B,CAGvC,MAAU,MACR,oGACD,EAEJ,CAOH,eAAe,EAA0B,EAA8B,CACrE,GAAI,CAEF,IAAMC,EAAa,MAAM,GAAmB,CAG5C,GAAI,EAFa,MAAMA,EAAW,aAAa,EAAI,EAErC,OACZ,MAAU,MAAM,+BAA+B,IAAM,CASvD,IAAM,EAAa,EALE,MAAMA,EAAW,kBAAkB,EAAK,CAC3D,SAAUA,EAAW,aAAa,OACnC,CAAC,CAGiD,CAG7C,EAAa,MAAM,EAAO,OAC9B,EAAO,sBAAsB,OAC7B,EACD,CAQD,OALkB,MAAM,KAAK,IAAI,WAAW,EAAW,CAAC,CAErD,IAAK,GAAS,EAAK,SAAS,GAAG,CAAC,SAAS,EAAG,IAAI,CAAC,CACjD,KAAK,GAAG,OAGJ,EAAO,CACd,MAAU,MACR,0CAA0C,EAAI,IAAI,aAAiB,MAAQ,EAAM,QAAU,kBAC5F,EAQL,eAAe,GAAoB,CACjC,GAAI,CACF,OAAA,EAAe,mBAAmB,MACnB,CACf,MAAU,MACR,uHAED,EAQL,SAAS,EAAmB,EAA4B,CAEtD,GAAM,CAAE,WAAA,GAAA,EAAuB,YAAY,CACrC,EAAeC,EAAW,EAAO,CAEjC,EAAQ,IAAI,WAAW,EAAa,OAAO,CACjD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,EAAM,GAAK,EAAa,WAAW,EAAE,CAEvC,OAAO,ECtDT,SAAgB,EACd,EAA8B,EAAE,CACU,CAC1C,GAAM,CAAE,oBAAmB,kBAAkB,IAAS,EAkBtD,MAAO,CACL,QAhBc,EACZ,GAA2B,CAC3B,GAA8B,CAehC,aAZmB,GAA+B,CAalD,WAZiB,EAAqB,EAAkB,CAaxD,WAZiB,GAA6B,CAa9C,OAZa,GAAyB,CAatC,UAZgB,GAA4B,CAa5C,gBAZsB,GAAkC,CAaxD,SAZe,GAA2B,CAa1C,gBAZsB,GAA2B,CAajD,mBAZyB,GAA8B,CAaxD,CCjCH,SAAgB,EAAuB,EAAkC,CACvE,IAAM,EAAW,EAAmB,CAClC,kBAAmB,EAAQ,kBAC3B,gBAAiB,EAAQ,gBAC1B,CAAC,CAEF,OAAOC,EAA4C,CACjD,GAAG,EACH,iBAAkB,EAAS,UAC3B,uBAAwB,EAAS,gBACjC,WAAY,EAAS,WACrB,WAAY,EAAS,WACrB,WAAY,EAAS,aACrB,OAAQ,EAAa,OAAa,GAAG,CACrC,cAAe,EAAoB,EAAS,QAAQ,CACrD,CAAC,CClDJ,IAAa,EAAb,KAAkE,CAChE,MAAM,aAAa,EAAkD,CACnE,GAAI,CACF,IAAM,EAAU,MAAM,EAAe,iBAAiB,CACpD,KAAM,GAAS,cAAgB,CAAC,MAAM,CACtC,qBAAsB,GACvB,CAAC,CAUF,GAAI,EAAO,SACT,MAAU,MAAM,gCAAgC,CAGlD,IAAM,EAAQ,EAAO,SAAS,GAC9B,GAAI,CAAC,EACH,MAAU,MAAM,uBAAuB,CAGzC,MAAO,CACL,IAAK,EAAM,IACX,KAAM,EAAM,KACZ,KAAM,EAAM,MAAQ,EACpB,SAAU,EAAM,SACjB,OACM,EAAO,CAId,MAHI,aAAiB,OAAS,EAAM,QAAQ,SAAS,YAAY,CACzD,EAEE,MACR,4BAA4B,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GACnF,EAIL,MAAM,UAAU,EAAkD,CAChE,GAAI,CAEF,GAAM,CAAE,UACN,MAAM,EAAY,qCAAqC,CACzD,GAAI,IAAW,UACb,MAAU,MAAM,qCAAqC,CAGvD,IAAM,EAAS,MAAM,EAAY,wBAAwB,CAEvD,WAAY,SACZ,eAAgB,GAAS,cAAgB,EAAI,EAC7C,QAAS,EACV,CAAC,CAEF,GAAI,EAAO,SACT,MAAU,MAAM,6BAA6B,CAG/C,IAAM,EAAQ,EAAO,SAAS,GAC9B,GAAI,CAAC,EACH,MAAU,MAAM,oBAAoB,CAGtC,MAAO,CACL,IAAK,EAAM,IACX,KAAM,EAAM,UAAY,SAAS,KAAK,KAAK,CAAC,MAC5C,KAAM,EAAM,UAAY,EACxB,SAAU,aACX,OACM,EAAO,CAId,MAHI,aAAiB,OAAS,EAAM,QAAQ,SAAS,YAAY,CACzD,EAEE,MACR,yBAAyB,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAChF,EAIL,MAAM,UAAU,EAAkD,CAChE,GAAI,CAEF,GAAM,CAAE,UACN,MAAM,EAAY,qCAAqC,CACzD,GAAI,IAAW,UACb,MAAU,MAAM,qCAAqC,CAGvD,IAAM,EAAS,MAAM,EAAY,wBAAwB,CAEvD,WAAY,SACZ,eAAgB,GAAS,cAAgB,EAAI,EAC9C,CAAC,CAEF,GAAI,EAAO,SACT,MAAU,MAAM,6BAA6B,CAG/C,IAAM,EAAQ,EAAO,SAAS,GAC9B,GAAI,CAAC,EACH,MAAU,MAAM,oBAAoB,CAGtC,MAAO,CACL,IAAK,EAAM,IACX,KAAM,EAAM,UAAY,SAAS,KAAK,KAAK,CAAC,MAC5C,KAAM,EAAM,UAAY,EACxB,SAAU,YACX,OACM,EAAO,CAId,MAHI,aAAiB,OAAS,EAAM,QAAQ,SAAS,YAAY,CACzD,EAEE,MACR,yBAAyB,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAChF,EAIL,MAAM,WAAW,EAAkD,CACjE,GAAI,CAEF,GAAM,CAAE,UAAW,MAAM,EAAY,+BAA+B,CACpE,GAAI,IAAW,UACb,MAAU,MAAM,gCAAgC,CAGlD,IAAM,EAAS,MAAM,EAAY,kBAAkB,CACjD,cAAe,GACf,OAAQ,CAAC,EAAG,EAAE,CACd,QAAS,GAAS,SAAW,EAC9B,CAAC,CAEF,GAAI,EAAO,SACT,MAAU,MAAM,+BAA+B,CAGjD,IAAM,EAAQ,EAAO,SAAS,GAC9B,GAAI,CAAC,EACH,MAAU,MAAM,oBAAoB,CAGtC,MAAO,CACL,IAAK,EAAM,IACX,KAAM,EAAM,UAAY,SAAS,KAAK,KAAK,CAAC,MAC5C,KAAM,EAAM,UAAY,EACxB,SAAU,aACX,OACM,EAAO,CAId,MAHI,aAAiB,OAAS,EAAM,QAAQ,SAAS,YAAY,CACzD,EAEE,MACR,4BAA4B,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GACnF,EAIL,MAAM,SAAS,EAAmC,CAChD,GAAI,CAEF,IAAM,EAAe,MAAM,EAAW,kBAAkB,EAAK,CAC3D,SAAU,EAAW,aAAa,OACnC,CAAC,CAII,CAAE,WAAA,GAAe,MAAM,OAAO,aAC9B,EAAeC,EAAW,EAAa,CACvC,EAAQ,IAAI,WAAW,EAAa,OAAO,CACjD,IAAK,IAAI,EAAI,EAAG,EAAI,EAAa,OAAQ,IACvC,EAAM,GAAK,EAAa,WAAW,EAAE,CAEvC,OAAO,EAAM,aACN,EAAO,CACd,MAAU,MACR,wBAAwB,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GAC/E,EAIL,MAAM,eAAe,EAAmC,CAEtD,OAAO,EAGT,MAAM,YAAY,EAAgC,CAChD,GAAI,CACF,IAAM,EAAW,MAAM,EAAW,aAAa,EAAI,CAEnD,GAAI,CAAC,EAAS,OACZ,MAAU,MAAM,sBAAsB,CAGxC,MAAO,CACL,MACA,KAAM,EAAI,MAAM,IAAI,CAAC,KAAK,EAAI,UAC9B,KAAM,EAAS,MAAQ,EACvB,iBAAkB,EAAS,iBACvB,EAAS,iBAAmB,IAC5B,IAAA,GACL,OACM,EAAO,CACd,MAAU,MACR,4BAA4B,aAAiB,MAAQ,EAAM,QAAU,OAAO,EAAM,GACnF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uploadista/expo",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Expo client for Uploadista with managed workflow support",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,11 +10,11 @@
|
|
|
10
10
|
"./services": "./src/services/index.ts"
|
|
11
11
|
},
|
|
12
12
|
"dependencies": {
|
|
13
|
-
"uuid": "^
|
|
13
|
+
"uuid": "^13.0.0",
|
|
14
14
|
"js-base64": "^3.7.7",
|
|
15
|
-
"@uploadista/core": "0.0.
|
|
16
|
-
"@uploadista/client-core": "0.0.
|
|
17
|
-
"@uploadista/react-native-core": "0.0.
|
|
15
|
+
"@uploadista/core": "0.0.4",
|
|
16
|
+
"@uploadista/client-core": "0.0.4",
|
|
17
|
+
"@uploadista/react-native-core": "0.0.4"
|
|
18
18
|
},
|
|
19
19
|
"peerDependencies": {
|
|
20
20
|
"@react-native-async-storage/async-storage": ">=1.17.0",
|
|
@@ -33,11 +33,11 @@
|
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/react": ">=18.0.0",
|
|
36
|
-
"
|
|
37
|
-
"@
|
|
38
|
-
"@uploadista/typescript-config": "0.0.3"
|
|
36
|
+
"tsdown": "0.15.9",
|
|
37
|
+
"@uploadista/typescript-config": "0.0.4"
|
|
39
38
|
},
|
|
40
39
|
"scripts": {
|
|
40
|
+
"build": "tsdown",
|
|
41
41
|
"format": "biome format --write ./src",
|
|
42
42
|
"lint": "biome lint --write ./src",
|
|
43
43
|
"check": "biome check --write ./src"
|
package/tsdown.config.ts
ADDED