rn-file-toolkit 1.0.1 → 1.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/README.md CHANGED
@@ -1,522 +1,242 @@
1
- # rn-file-toolkit
2
-
3
- [![npm version](https://img.shields.io/npm/v/rn-file-toolkit.svg?style=flat-square)](https://www.npmjs.com/package/rn-file-toolkit)
4
- [![npm downloads](https://img.shields.io/npm/dm/rn-file-toolkit.svg?style=flat-square)](https://www.npmjs.com/package/rn-file-toolkit)
5
- [![license](https://img.shields.io/npm/l/rn-file-toolkit.svg?style=flat-square)](https://github.com/chavan-labs/rn-file-toolkit/blob/main/LICENSE)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg?style=flat-square)](https://www.typescriptlang.org/)
7
- [![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20Android-lightgrey.svg?style=flat-square)](https://github.com/chavan-labs/rn-file-toolkit)
8
-
9
- The easiest way to download **and manage files** in React Native — with background support, pause/resume, upload, queueing, and built-in filesystem APIs.
10
-
11
- > 100% pure native code (Kotlin + Swift). Zero third-party dependencies.
12
-
13
- **Keywords:** react native download, react native file download, react native background download, react native download manager, react native file upload, react native download progress, react native pause resume download, react native cache manager, react native turbo module, expo download, iOS URLSession, Android DownloadManager, react native checksum validation, base64 converter, url to base64, data uri, share file, open file, file sharing, native share, document viewer, download queue, concurrent downloads, queue concurrency, priority queue, batch download, max concurrent downloads, react native filesystem, read file, write file, copy file, move file, stat file, file exists, useDownload hook, download speed, download eta, download progress bytes
14
-
15
- ⭐ **Star this repo if you found it useful** — it helps others discover the project!
16
-
17
- ## Problems?
18
-
19
- Most React Native file download solutions have one or more of these problems:
20
-
21
- - **Complexity** — require configuring native modules, background tasks, and notification channels separately
22
- - **Dependencies** — rely on heavy third-party libraries that bloat your app size
23
- - **Limited features** — lack pause/resume, checksum validation, or proper background support
24
- - **No queue** — spawn 20 downloads and you'll crash or saturate the network; libraries like `react-native-blob-util` have no queue at all
25
- - **Split libraries** — downloading is in one package, filesystem operations in another (read/write/copy/stat/exists), adding extra dependency and complexity
26
- - **Poor DX** — complicated APIs that require managing multiple IDs, listeners, and cleanup logic
27
-
28
- **rn-file-toolkit** was built to solve these issues. It provides a simple, unified API while leveraging platform-native download managers (URLSession on iOS, DownloadManager on Android) for reliable, battery-efficient downloads. Everything works out of the box — background downloads, progress tracking, pause/resume — without wrestling with native configuration.
29
-
30
- ## ✨ Features
31
-
32
- - **`useDownload()` hook** — drop-in React hook with built-in state: `status`, `progress`, `result`, `pause`, `resume`, `cancel` — no competitors have this
33
- - **Rich progress info** — `onProgress` gives you `percent`, `bytesDownloaded`, `totalBytes`, `speedBps`, and `etaSeconds` — not just a plain number
34
- - **Zip & Unzip** — compress files/directories and extract ZIP archives natively with **zero third-party dependencies** (`java.util.zip` on Android, system `zlib` on iOS)
35
- - **Download with progress** — clean `0 → 100` progress natively, no UI freezing
36
- - **Background downloads** — survive app suspension (iOS background URLSession + Android DownloadManager)
37
- - **Download Queue** — built-in concurrency-limited queue with `maxConcurrent` control and `high`/`normal` priority
38
- - **Pause & Resume** — resume mid-download using HTTP Range requests
39
- - **Auto-Retry** — automatic retry on network errors with exponential backoff
40
- - **Cancel** — cancel any active download, partial files are cleaned up automatically
41
- - **Re-attach** — reconnect to background downloads after app restart
42
- - **Custom Headers** — support for Authorization tokens and custom metadata
43
- - **Custom Destinations** — save to `downloads`, `cache`, or `documents` folders
44
- - **Multipart Upload** — simple, native file uploading
45
- - **Checksum Validation** — verify file integrity (MD5, SHA1, SHA256) after download
46
- - **Base64 & Data URI Support** — convert base64 strings and data URIs to files natively
47
- - **URL to Base64** — convert remote URLs (images, videos, gifs) to base64 strings
48
- - **Share Files** — share files with other apps using native share dialog
49
- - **Open Files** — open files with default apps or app chooser
50
- - **Filesystem API (`fs`)** — `exists`, `stat`, `readFile`, `writeFile`, `copyFile`, `moveFile`, `mkdir`, `ls`, `deleteFile`
51
- - **Expo Support** — includes a config plugin for zero-config integration
52
- - **TurboModules** — built on the React Native New Architecture
53
- - **File management** — list, delete individual files, or clear all downloads
1
+ <div align="center">
2
+ <h1>rn-file-toolkit 🗂️</h1>
3
+ <p><b>The ultimate, unified native file management toolkit for React Native & Expo</b></p>
4
+
5
+ [![npm version](https://img.shields.io/npm/v/rn-file-toolkit.svg?style=for-the-badge&color=success)](https://www.npmjs.com/package/rn-file-toolkit)
6
+ [![npm downloads](https://img.shields.io/npm/dt/rn-file-toolkit.svg?style=for-the-badge)](https://www.npmjs.com/package/rn-file-toolkit)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg?style=for-the-badge&logo=typescript)](https://www.typescriptlang.org/)
8
+ [![platforms](https://img.shields.io/badge/Platforms-iOS%20%7C%20Android-lightgrey.svg?style=for-the-badge&logo=apple&logoColor=white)](https://github.com/chavan-labs/rn-file-toolkit)
9
+ [![license](https://img.shields.io/npm/l/rn-file-toolkit.svg?style=for-the-badge)](https://github.com/chavan-labs/rn-file-toolkit/blob/main/LICENSE)
10
+ </div>
54
11
 
55
12
  ---
56
13
 
57
- ## Installation
14
+ **rn-file-toolkit** is the modern replacement for legacy file libraries. Download, upload, manage queues, extract archives, and interact with the filesystem—all powered by pure native implementations (Kotlin + Swift) with **zero third-party dependencies**.
58
15
 
59
- ```sh
60
- npm install rn-file-toolkit
61
- ```
62
-
63
- ---
64
-
65
- ## API
66
-
67
- ### `download(options)`
68
-
69
- ```javascript
70
- import { download } from 'rn-file-toolkit';
71
-
72
- const result = await download({
73
- url: 'https://example.com/file.pdf',
74
- fileName: 'my_file.pdf',
75
- headers: { Authorization: 'Bearer <token>' },
76
- destination: 'documents', // 'downloads' | 'cache' | 'documents'
77
- checksum: {
78
- hash: 'd41d8cd98f00b204e9800998ecf8427e',
79
- algorithm: 'md5',
80
- },
81
- onProgress: ({
82
- percent,
83
- bytesDownloaded,
84
- totalBytes,
85
- speedBps,
86
- etaSeconds,
87
- }) => {
88
- console.log(
89
- `${percent.toFixed(1)}% — ${(speedBps / 1024).toFixed(
90
- 1
91
- )} KB/s — ETA ${etaSeconds.toFixed(0)}s`
92
- );
93
- },
94
- // Auto-retry on network failure (optional)
95
- retry: {
96
- attempts: 3, // max retry attempts
97
- delay: 1000, // base delay in ms; doubles each attempt: 1s → 2s → 4s (capped at 30s)
98
- onRetry: (attempt, error) => console.log(`Retry #${attempt}: ${error}`),
99
- },
100
- });
101
- ```
16
+ ⭐ **Star this repo if you find it useful to help others discover it!**
102
17
 
103
- > **Retry behaviour:**
104
- >
105
- > - Only retries on **network errors** (timeouts, connection drops, socket errors).
106
- > - Server errors (`4xx`/`5xx`) and checksum mismatches are **not** retried.
107
- > - Delay doubles each attempt (exponential backoff), capped at 30 seconds.
108
- > - Works on both iOS and Android for foreground downloads.
18
+ ## 📖 Table of Contents
19
+ - [Why rn-file-toolkit?](#-why-rn-file-toolkit)
20
+ - [Installation](#-installation)
21
+ - [Quick Start: `useDownload`](#-quick-start-usedownload)
22
+ - [Core APIs](#-core-apis)
23
+ - [Background Downloads](#background-downloads)
24
+ - [Multipart Uploads](#multipart-uploads)
25
+ - [File System (FS)](#file-system-fs)
26
+ - [Zip & Unzip Archives](#zip--unzip-archives)
27
+ - [Media & Utilities](#media--utilities)
28
+ - [API Reference](#-api-reference)
29
+ - [Expo Support](#-expo-support)
30
+ - [Contributing](#-contributing)
109
31
 
110
32
  ---
111
33
 
112
- ### `setQueueOptions(options)` · `getQueueStatus()` · Queue-aware `download()`
34
+ ## 🚀 Why rn-file-toolkit?
113
35
 
114
- Avoid crashing your app (or saturating the network) when kicking off many simultaneous downloads. The built-in queue lets you cap concurrency and prioritise individual items all in pure JavaScript, with zero native changes required.
36
+ Most React Native file solutions (`rn-fetch-blob`, `react-native-fs`) are fragmented, lightly maintained, or lack modern features. **rn-file-toolkit** gives you a unified, **TurboModule-ready** API utilizing OS-native managers (`URLSession` on iOS, `DownloadManager` on Android) for reliable, battery-efficient operations.
115
37
 
116
- ```javascript
117
- import { download, setQueueOptions, getQueueStatus } from 'rn-file-toolkit';
38
+ ### ✨ Highlights
39
+ - 🪝 **Drop-in React Hooks:** Built-in state management (`useDownload`) for progress and controls.
40
+ - 📥 **Background Ready:** Downloads and uploads survive app suspension with automatic re-attachment.
41
+ - 🚦 **Smart Queueing:** Cap concurrency and set priorities without touching native code.
42
+ - 🛡️ **Resilient:** Auto-retries on network errors with exponential backoff and HTTP resume.
43
+ - 🗜️ **Zero-Dependency Zip:** Uses native `java.util.zip` and iOS `zlib`.
44
+ - 🗄️ **Rich File System API:** Comprehensive FS methods (`readFile`, `writeFile`, `copyFile`, `mkdir`, `stat`, etc.).
45
+ - 🛠️ **Expo Compatible:** Seamless integration with Expo custom dev clients.
118
46
 
119
- // 1. Configure the global queue (call once, e.g. at app startup)
120
- setQueueOptions({ maxConcurrent: 3 }); // default is 3
47
+ ---
121
48
 
122
- // 2. Enqueue downloads — at most 3 will run at the same time
123
- const promises = urls.map((url) =>
124
- download({
125
- url,
126
- destination: 'documents',
127
- queue: true, // join the managed queue
128
- priority: 'normal', // 'high' | 'normal' (default)
129
- onProgress: (p) => console.log(`${url}: ${p.percent}%`),
130
- })
131
- );
49
+ ## 📦 Installation
132
50
 
133
- const results = await Promise.all(promises);
51
+ ```bash
52
+ # npm
53
+ npm install rn-file-toolkit
134
54
 
135
- // High-priority item jumps ahead of all 'normal' pending items
136
- download({
137
- url: 'https://example.com/urgent.pdf',
138
- queue: true,
139
- priority: 'high',
140
- });
55
+ # yarn
56
+ yarn add rn-file-toolkit
141
57
 
142
- // 3. Inspect queue state at any time
143
- const { active, pending, maxConcurrent } = getQueueStatus();
144
- console.log(`Running: ${active} Waiting: ${pending} Limit: ${maxConcurrent}`);
58
+ # pnpm
59
+ pnpm add rn-file-toolkit
145
60
  ```
146
61
 
147
- > **Queue behaviour:**
148
- >
149
- > - `queue: false` (default) — download starts immediately, bypassing the queue entirely. All existing behaviour is unchanged.
150
- > - `queue: true` — the download is placed in the JS queue. It starts as soon as an active slot is free.
151
- > - `priority: 'high'` — item is inserted at the **front** of the pending list, so it runs before any `'normal'` items.
152
- > - `priority: 'normal'` (default) — item is appended to the **back**.
153
- > - `setQueueOptions` can be called at any time; if `maxConcurrent` is increased, idle slots are filled immediately.
154
- > - All other `DownloadOptions` (`onProgress`, `retry`, `checksum`, `headers`, etc.) work exactly the same inside the queue.
62
+ *(Optional) If you are not using Expo or an auto-linking setup, run `pod install` in your `ios` directory.*
155
63
 
156
64
  ---
157
65
 
158
- ### `useDownload()` hook
66
+ ## ⚡ Quick Start: `useDownload`
159
67
 
160
- The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls — all with zero boilerplate.
68
+ The easiest way to manage a download inside a React component. Get status, rich progress (with speed & ETA), and full controls instantly.
161
69
 
162
70
  ```tsx
71
+ import React from 'react';
72
+ import { View, Text, Button } from 'react-native';
163
73
  import { useDownload } from 'rn-file-toolkit';
164
74
 
165
- function DownloadScreen() {
166
- const { start, pause, resume, cancel, status, progress, result } =
167
- useDownload();
75
+ export default function DownloadScreen() {
76
+ const { start, pause, resume, cancel, status, progress, result } = useDownload();
168
77
 
169
78
  return (
170
- <View>
171
- <Button
172
- title="Download"
173
- onPress={() =>
174
- start({
175
- url: 'https://example.com/video.mp4',
176
- destination: 'documents',
177
- })
178
- }
79
+ <View style={{ padding: 20 }}>
80
+ <Button
81
+ title="Start Download"
82
+ onPress={() => start({
83
+ url: 'https://example.com/large-video.mp4',
84
+ destination: 'documents'
85
+ })}
179
86
  />
180
87
 
181
88
  {status === 'downloading' && progress && (
182
- <View>
183
- <Text>{progress.percent.toFixed(1)}%</Text>
184
- <Text>Speed: {(progress.speedBps / 1024).toFixed(1)} KB/s</Text>
185
- <Text>ETA: {progress.etaSeconds.toFixed(0)}s</Text>
186
- <Text>
187
- {(progress.bytesDownloaded / 1024 / 1024).toFixed(1)} MB
188
- {' / '}
189
- {(progress.totalBytes / 1024 / 1024).toFixed(1)} MB
190
- </Text>
191
- <Button title="Pause" onPress={pause} />
192
- <Button title="Cancel" onPress={cancel} />
89
+ <View style={{ marginTop: 20 }}>
90
+ <Text>Progress: {progress.percent.toFixed(1)}%</Text>
91
+ <Text>Speed: {(progress.speedBps / 1024 / 1024).toFixed(2)} MB/s</Text>
92
+ <Text>ETA: {progress.etaSeconds.toFixed(0)} seconds</Text>
93
+ <View style={{ flexDirection: 'row', gap: 10, marginTop: 10 }}>
94
+ <Button title="Pause" onPress={pause} />
95
+ <Button title="Cancel" onPress={cancel} color="red" />
96
+ </View>
193
97
  </View>
194
98
  )}
195
99
 
196
100
  {status === 'paused' && <Button title="Resume" onPress={resume} />}
197
-
198
- {status === 'done' && result?.success && (
199
- <Text>✅ Saved to: {result.filePath}</Text>
200
- )}
201
-
202
- {status === 'error' && <Text>❌ {result?.error}</Text>}
101
+ {status === 'done' && <Text style={{ color: 'green' }}>✅ Saved: {result?.filePath}</Text>}
102
+ {status === 'error' && <Text style={{ color: 'red' }}>❌ Error: {result?.error}</Text>}
203
103
  </View>
204
104
  );
205
105
  }
206
106
  ```
207
107
 
208
- | Property | Type | Description |
209
- | ---------------- | ---------------------------------------------------------- | ------------------------------- |
210
- | `start(options)` | `(options: DownloadOptions) => Promise<DownloadResult>` | Start a download |
211
- | `pause()` | `() => Promise<void>` | Pause the active download |
212
- | `resume()` | `() => Promise<void>` | Resume a paused download |
213
- | `cancel()` | `() => Promise<void>` | Cancel and discard the download |
214
- | `status` | `'idle' \| 'downloading' \| 'paused' \| 'done' \| 'error'` | Current state |
215
- | `progress` | `ProgressInfo \| null` | Live progress info (see below) |
216
- | `result` | `DownloadResult \| null` | Final result once complete |
217
- | `downloadId` | `string \| null` | Active download ID |
218
-
219
108
  ---
220
109
 
221
- ### `upload(options)`
222
-
223
- ```javascript
224
- import { upload } from 'rn-file-toolkit';
225
-
226
- const result = await upload({
227
- url: 'https://example.com/api/upload',
228
- filePath: '/path/to/my_image.jpg',
229
- fieldName: 'avatar', // default: 'file'
230
- parameters: {
231
- userId: '123',
232
- },
233
- headers: { 'X-Custom-Header': 'value' },
234
- onProgress: (p) => console.log(`Uploading: ${p}%`),
235
- });
236
-
237
- if (result.success) {
238
- console.log('Response:', result.data);
239
- }
240
- ```
110
+ ## 🛠️ Core APIs
241
111
 
242
- ---
112
+ ### Background Downloads
113
+ For programmatic, queue-aware background downloads outside of React components.
243
114
 
244
- ### `saveBase64AsFile(options)`
115
+ ```typescript
116
+ import { download, setQueueOptions } from 'rn-file-toolkit';
245
117
 
246
- Save a base64 string or data URI as a file. Perfect for handling base64 images, documents, or any binary data.
118
+ // Optimize global concurrency
119
+ setQueueOptions({ maxConcurrent: 3 });
247
120
 
248
- ```javascript
249
- import { saveBase64AsFile } from 'rn-file-toolkit';
250
-
251
- // From data URI (auto-detects file extension)
252
- const result = await saveBase64AsFile({
253
- base64Data: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUg...',
254
- fileName: 'photo.png',
121
+ const result = await download({
122
+ url: 'https://example.com/file.pdf',
255
123
  destination: 'documents', // 'downloads' | 'cache' | 'documents'
124
+ queue: true, // Join the managed queue
125
+ priority: 'high', // 'high' | 'normal'
126
+ retry: { attempts: 3, delay: 1000 },
127
+ onProgress: (p) => console.log(`${p.percent.toFixed(1)}% downloaded`),
256
128
  });
257
-
258
- // From plain base64 string
259
- const result = await saveBase64AsFile({
260
- base64Data: 'SGVsbG8gV29ybGQ=',
261
- fileName: 'hello.txt',
262
- destination: 'cache',
263
- });
264
-
265
- if (result.success) {
266
- console.log('File saved at:', result.filePath);
267
- }
268
129
  ```
269
130
 
270
- ---
271
-
272
- ### `urlToBase64(options)`
131
+ ### Multipart Uploads
132
+ Robust, memory-efficient multipart file uploading for large media or documents.
273
133
 
274
- Convert a web URL (image, video, gif, etc.) to base64 string. Perfect for converting remote media to base64 for local processing.
275
-
276
- ```javascript
277
- import { urlToBase64 } from 'rn-file-toolkit';
134
+ ```typescript
135
+ import { upload } from 'rn-file-toolkit';
278
136
 
279
- const result = await urlToBase64({
280
- url: 'https://example.com/photo.jpg',
281
- headers: { Authorization: 'Bearer <token>' }, // optional
137
+ const result = await upload({
138
+ url: 'https://api.example.com/v1/upload',
139
+ filePath: '/path/to/local/image.jpg',
140
+ fieldName: 'file',
141
+ parameters: { userId: '123', folder: 'avatars' },
142
+ onProgress: (percent) => console.log(`Uploading: ${percent}%`),
282
143
  });
283
-
284
- if (result.success) {
285
- console.log('Base64:', result.base64);
286
- console.log('Data URI:', result.dataUri);
287
- console.log('MIME Type:', result.mimeType); // e.g., 'image/jpeg'
288
-
289
- // Use in Image component
290
- // <Image source={{ uri: result.dataUri }} />
291
- }
292
144
  ```
293
145
 
294
- ---
295
-
296
- ### `shareFile(options)`
146
+ ### File System (FS)
147
+ Perform native filesystem operations securely.
297
148
 
298
- Share a file with other apps using the native share dialog.
149
+ ```typescript
150
+ import { fs } from 'rn-file-toolkit';
299
151
 
300
- ```javascript
301
- import { shareFile } from 'rn-file-toolkit';
152
+ // Check & Inspect
153
+ const exists = await fs.exists('/path/to/data.json');
154
+ const stats = await fs.stat('/path/to/data.json'); // { size, modified, isDir }
302
155
 
303
- const result = await shareFile({
304
- filePath: '/path/to/document.pdf',
305
- title: 'Share Document', // Android only
306
- subject: 'Check this out', // Android only
307
- });
156
+ // Read & Write
157
+ await fs.writeFile('/path/to/data.txt', 'Hello World', 'utf8'); // Also supports 'base64'
158
+ const content = await fs.readFile('/path/to/data.txt', 'utf8');
308
159
 
309
- if (result.success) {
310
- console.log('File shared successfully');
311
- }
160
+ // Manage Folders & Files
161
+ await fs.mkdir('/path/to/new_folder');
162
+ const files = await fs.ls('/path/to/new_folder');
163
+ await fs.copyFile('/path/src.txt', '/path/dest.txt');
164
+ await fs.moveFile('/path/old.txt', '/path/new.txt');
165
+ await fs.deleteFile('/path/unwanted.txt');
312
166
  ```
313
167
 
314
- ---
168
+ ### Zip & Unzip Archives
169
+ Compress and extract archives directly on the device.
315
170
 
316
- ### `openFile(options)`
171
+ ```typescript
172
+ import { unzip, zip } from 'rn-file-toolkit';
317
173
 
318
- Open a file with the default app or app chooser.
174
+ // Extract a downloaded zip
175
+ await unzip('/path/to/bundle.zip', '/path/to/extract-folder');
319
176
 
320
- ```javascript
321
- import { openFile } from 'rn-file-toolkit';
322
-
323
- const result = await openFile({
324
- filePath: '/path/to/document.pdf',
325
- mimeType: 'application/pdf', // optional, auto-detected if not provided
326
- });
327
-
328
- if (result.success) {
329
- console.log('File opened');
330
- }
177
+ // Compress user data before uploading
178
+ await zip('/path/to/user-data-folder', '/path/to/backup.zip');
331
179
  ```
332
180
 
333
- ---
334
-
335
- ### `unzip(sourcePath, destDir)` · `zip(sourcePath, destPath)`
336
-
337
- Compress and extract ZIP archives natively — **no third-party library required**.
181
+ ### Media & Utilities
182
+ Helpful tools for sharing, opening, and encoding files.
338
183
 
339
- - **Android** uses `java.util.zip` (built into the Android SDK, every API level).
340
- - **iOS** uses `zlib` (system framework, linked via `s.libraries = 'z'` in the podspec — ships on every iPhone/iPad).
184
+ ```typescript
185
+ import { saveBase64AsFile, urlToBase64, shareFile, openFile } from 'rn-file-toolkit';
341
186
 
342
- ```javascript
343
- import { download, unzip, zip } from 'rn-file-toolkit';
344
-
345
- // ── Unzip a downloaded archive ──────────────────────────────────────────────
346
- const dl = await download({
347
- url: 'https://example.com/assets.zip',
348
- destination: 'cache',
187
+ // Base64 to File
188
+ await saveBase64AsFile({
189
+ base64Data: 'data:image/png;base64,...',
190
+ destination: 'documents',
191
+ fileName: 'image.png'
349
192
  });
350
193
 
351
- if (dl.success) {
352
- const result = await unzip(
353
- dl.filePath, // absolute path to the .zip file
354
- '/path/to/output-folder' // destination directory (created if it doesn't exist)
355
- );
356
-
357
- if (result.success) {
358
- console.log('Destination:', result.destDir);
359
- console.log('Extracted files:', result.files);
360
- // result.files → ['/path/to/output-folder/image.png', ...]
361
- } else {
362
- console.log('Error:', result.error);
363
- }
364
- }
365
-
366
- // ── Zip a single file ───────────────────────────────────────────────────────
367
- const zipResult = await zip(
368
- '/path/to/document.pdf', // source file
369
- '/path/to/document.zip' // output archive path
370
- );
194
+ // URL to Base64 (Great for caching small images)
195
+ const b64 = await urlToBase64({ url: 'https://example.com/icon.png' });
371
196
 
372
- if (zipResult.success) {
373
- console.log('Archive created at:', zipResult.zipPath);
374
- }
197
+ // Native Share Sheet
198
+ await shareFile({ filePath: '/path/to/report.pdf' });
375
199
 
376
- // ── Zip an entire directory ─────────────────────────────────────────────────
377
- const dirResult = await zip(
378
- '/path/to/my-folder', // source directory
379
- '/path/to/my-folder.zip' // output archive path
380
- );
200
+ // Open with default system app
201
+ await openFile({ filePath: '/path/to/report.pdf', mimeType: 'application/pdf' });
381
202
  ```
382
203
 
383
- > **Notes:**
384
- >
385
- > - `unzip` auto-creates the destination directory including any intermediate folders.
386
- > - `unzip` on Android protects against [zip-slip attacks](https://snyk.io/research/zip-slip-vulnerability) by validating each entry path.
387
- > - `zip` supports both single files and entire directory trees (recursive).
388
- > - Both functions run on a background thread and never block the JS thread.
389
- > - Supported compression methods: **Deflate** (method 8) and **Store** (method 0) — the two methods used by virtually every ZIP file.
390
-
391
204
  ---
392
205
 
393
- ### Pause / Resume / Cancel
206
+ ## 📚 API Reference
394
207
 
395
- ```javascript
396
- import { pauseDownload, resumeDownload, cancelDownload } from 'rn-file-toolkit';
208
+ | Interface | Key Properties | Description |
209
+ | :--- | :--- | :--- |
210
+ | `DownloadOptions` | `url`, `destination`, `queue`, `retry`, `onProgress` | Configuration for downloading a file. |
211
+ | `UploadOptions` | `url`, `filePath`, `fieldName`, `parameters`, `onProgress` | Configuration for multipart uploads. |
212
+ | `ProgressInfo` | `percent`, `bytesDownloaded`, `speedBps`, `etaSeconds` | Rich real-time progress payload. |
213
+ | `UseDownloadReturn` | `start`, `pause`, `resume`, `cancel`, `status`, `progress` | Hook state and control methods. |
214
+ | `FsStat` | `size`, `modified`, `isDir` | Output of the filesystem `stat` method. |
397
215
 
398
- await pauseDownload(downloadId);
399
- await resumeDownload(downloadId);
400
- await cancelDownload(downloadId);
401
- ```
216
+ *For advanced types and detailed parameter documentation, please refer to the source TypeScript definitions.*
402
217
 
403
218
  ---
404
219
 
405
- ### Cache Management
406
-
407
- ```javascript
408
- import { getCachedFiles, deleteFile, clearCache } from 'rn-file-toolkit';
220
+ ## 🎪 Expo Support
409
221
 
410
- // List all files in the cache/documents folders
411
- const { files } = await getCachedFiles();
222
+ **rn-file-toolkit** works seamlessly with Expo custom development clients (EAS Build / `npx expo run:android` / `npx expo run:ios`). Since it contains native code, it is not compatible with Expo Go.
412
223
 
413
- // Delete a specific file
414
- await deleteFile('/path/to/file.pdf');
415
-
416
- // Clear all managed files
417
- await clearCache();
418
- ```
224
+ An Expo config plugin is included automatically. No extra configuration is needed in your `app.json` unless you want to customize permissions.
419
225
 
420
226
  ---
421
227
 
422
- ### `fs` (filesystem namespace)
423
-
424
- Use built-in file system helpers without adding another dependency.
425
-
426
- ```javascript
427
- import { fs } from 'rn-file-toolkit';
428
-
429
- await fs.exists('/path/to/file.pdf'); // → true/false
430
-
431
- await fs.stat('/path/to/file.pdf');
432
- // → { path, name, size, modified, isDir }
433
-
434
- await fs.readFile('/path/to/file.txt'); // utf8 by default
435
- await fs.readFile('/path/to/file.bin', 'base64');
436
-
437
- await fs.writeFile('/path/to/file.txt', 'hello');
438
- await fs.writeFile('/path/to/file.bin', 'SGVsbG8=', 'base64');
439
-
440
- await fs.copyFile('/src/file.pdf', '/dst/file.pdf');
441
- await fs.moveFile('/src/file.pdf', '/dst/file.pdf');
442
- await fs.deleteFile('/path/to/file.pdf');
443
-
444
- await fs.mkdir('/path/to/folder');
445
- await fs.ls('/path/to/folder'); // → string[]
446
- ```
447
-
448
- > `readFile` / `writeFile` support encodings: `'utf8'` (default) and `'base64'`.
449
-
450
- ---
451
-
452
- ## Use Cases
453
-
454
- ### Download from URLs
455
-
456
- Perfect for downloading files from remote servers with progress tracking, background support, and resume capability.
457
-
458
- ### Convert URLs to Base64
459
-
460
- Convert remote media (images, videos, gifs) to base64 strings for:
461
-
462
- - Display in Image components without downloading to disk
463
- - Inline embedding in HTML/emails
464
- - Upload to APIs requiring base64 format
465
- - Cross-platform data transfer
466
-
467
- ### Save Base64/Data URIs
468
-
469
- Convert base64-encoded data (like images from canvas, camera, or API responses) directly to files:
470
-
471
- - Canvas-generated images (`canvas.toDataURL()`)
472
- - Camera/photo library base64 outputs
473
- - API responses with base64-encoded files
474
- - Email attachments in base64 format
475
-
476
- ---
477
-
478
- ## Type Reference
479
-
480
- | Type | Fields |
481
- | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
482
- | `DownloadOptions` | `url`, `fileName?`, `background?`, `headers?`, `destination?`, `notificationTitle?`, `notificationDescription?`, `checksum?`, `onProgress?`, `retry?`, `queue?`, `priority?` |
483
- | `ProgressInfo` | `percent`, `bytesDownloaded`, `totalBytes`, `speedBps`, `etaSeconds` |
484
- | `RetryOptions` | `attempts`, `delay?`, `onRetry?` |
485
- | `QueueOptions` | `maxConcurrent?` |
486
- | `QueueStatus` | `active`, `pending`, `maxConcurrent` |
487
- | `DownloadStatus` | `'idle' \| 'downloading' \| 'paused' \| 'done' \| 'error'` |
488
- | `UseDownloadReturn` | `start`, `pause`, `resume`, `cancel`, `status`, `progress`, `result`, `downloadId` |
489
- | `FsEncoding` | `'utf8' \| 'base64'` |
490
- | `FsStat` | `path`, `name`, `size`, `modified`, `isDir` |
491
- | `FsApi` | `exists`, `stat`, `readFile`, `writeFile`, `copyFile`, `moveFile`, `deleteFile`, `mkdir`, `ls` |
492
- | `UploadOptions` | `url`, `filePath`, `fieldName?`, `headers?`, `parameters?`, `onProgress?` |
493
- | `SaveBase64Options` | `base64Data`, `fileName?`, `destination?` |
494
- | `UrlToBase64Options` | `url`, `headers?` |
495
- | `ShareFileOptions` | `filePath`, `title?`, `subject?` |
496
- | `OpenFileOptions` | `filePath`, `mimeType?` |
497
- | `DownloadResult` | `success`, `filePath?`, `downloadId?`, `error?` |
498
- | `UploadResult` | `success`, `status?`, `data?`, `error?` |
499
- | `UnzipResult` | `success`, `destDir?`, `files?`, `error?` |
500
- | `ZipResult` | `success`, `zipPath?`, `error?` |
501
- | `SaveBase64Result` | `success`, `filePath?`, `error?` |
502
- | `UrlToBase64Result` | `success`, `base64?`, `mimeType?`, `dataUri?`, `error?` |
503
- | `ShareFileResult` | `success`, `completed?`, `error?` |
504
- | `OpenFileResult` | `success`, `error?` |
505
- | `Checksum` | `hash`, `algorithm: 'md5' \| 'sha1' \| 'sha256'` |
506
-
507
- ---
508
-
509
- ## Articles & Resources
510
-
511
- - [**I Got Tired of React Native File Downloads Being a Mess — So I Built rn-file-toolkit**](https://medium.com/@chavanrohit413/i-got-tired-of-react-native-file-downloads-being-a-mess-so-i-built-rn-file-toolkit-29b7a8b5c743) — Deep dive into the problems with existing solutions and how rn-file-toolkit solves them
512
-
513
- ---
228
+ ## 🤝 Contributing
514
229
 
515
- ## Links
230
+ Contributions are welcome! If you find a bug or want to request a feature, please [open an issue](https://github.com/chavan-labs/rn-file-toolkit/issues).
516
231
 
517
- - [GitHub](https://github.com/chavan-labs/rn-file-toolkit)
518
- - [npm](https://www.npmjs.com/package/rn-file-toolkit)
232
+ 1. Fork the repository
233
+ 2. Create your feature branch (`git checkout -b feature/AmazingFeature`)
234
+ 3. Commit your changes (`git commit -m 'Add some AmazingFeature'`)
235
+ 4. Push to the branch (`git push origin feature/AmazingFeature`)
236
+ 5. Open a Pull Request
519
237
 
520
238
  ---
521
239
 
522
- _Made natively for the community 🤝 by Rohit Chavan_
240
+ <div align="center">
241
+ <i>Built with ❤️ for the React Native community by <a href="https://github.com/chavan-labs">Rohit Chavan</a></i>
242
+ </div>