@umituz/react-native-filesystem 2.1.19 → 2.1.21

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umituz/react-native-filesystem",
3
- "version": "2.1.19",
3
+ "version": "2.1.21",
4
4
  "description": "File operations and import/export functionality for React Native apps",
5
5
  "main": "./src/index.ts",
6
6
  "types": "./src/index.ts",
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Download Service Constants
3
+ */
4
+
5
+ export const SUPPORTED_DOWNLOAD_EXTENSIONS = ["mp4", "mov", "m4v", "webm", "jpg", "png", "pdf"] as const;
6
+ export const DEFAULT_DOWNLOAD_EXTENSION = "mp4" as const;
@@ -1,72 +1,48 @@
1
1
  /**
2
2
  * Download Service
3
- * Single Responsibility: Handle file download operations
4
3
  */
5
4
 
6
5
  import { File, Paths, Directory } from "expo-file-system";
7
6
  import type { FileOperationResult } from "../../domain/entities/File";
8
7
  import { FileUtils } from "../../domain/entities/File";
8
+ import { SUPPORTED_DOWNLOAD_EXTENSIONS, DEFAULT_DOWNLOAD_EXTENSION } from "./download.constants";
9
9
  import type { DownloadProgressCallback, DownloadWithProgressResult } from "./download.types";
10
10
 
11
- const hashUrl = (url: string): string => {
11
+ const hashUrl = (url: string) => {
12
12
  let hash = 0;
13
13
  for (let i = 0; i < url.length; i++) hash = ((hash << 5) - hash + url.charCodeAt(i)) | 0;
14
14
  return Math.abs(hash).toString(36);
15
15
  };
16
16
 
17
- const getExt = (url: string): string => {
18
- const ext = url.split("?")[0].split(".").pop()?.toLowerCase() || "mp4";
19
- return ["mp4", "mov", "m4v", "webm", "jpg", "png", "pdf"].includes(ext) ? ext : "mp4";
17
+ const getExt = (url: string) => {
18
+ const parts = url.split("?")[0]?.split(".") || [];
19
+ const ext = parts.length > 1 ? parts.pop()?.toLowerCase() || DEFAULT_DOWNLOAD_EXTENSION : DEFAULT_DOWNLOAD_EXTENSION;
20
+ return (SUPPORTED_DOWNLOAD_EXTENSIONS as readonly string[]).includes(ext) ? ext : DEFAULT_DOWNLOAD_EXTENSION;
20
21
  };
21
22
 
22
- const getCacheUri = (url: string, dir: string): string => {
23
- return FileUtils.joinPaths(dir, `cached_${hashUrl(url)}.${getExt(url)}`);
24
- };
25
-
26
- interface DownloadError extends Error {
27
- message: string;
28
- }
23
+ const getCacheUri = (url: string, dir: string) => FileUtils.joinPaths(dir, `cached_${hashUrl(url)}.${getExt(url)}`);
29
24
 
30
25
  export async function downloadFile(url: string, dest?: string): Promise<FileOperationResult> {
31
26
  try {
32
- const destination = dest
33
- ? new File(dest)
34
- : new File(Paths.document, FileUtils.generateUniqueFilename("download"));
27
+ const destination = dest ? new File(dest) : new File(Paths.document, FileUtils.generateUniqueFilename("download"));
35
28
  const res = await File.downloadFileAsync(url, destination, { idempotent: true });
36
29
  return { success: true, uri: res.uri };
37
- } catch (error) {
38
- const downloadError = error as DownloadError;
39
- return { success: false, error: downloadError.message || "Unknown error" };
40
- }
30
+ } catch (e: any) { return { success: false, error: e.message }; }
41
31
  }
42
32
 
43
- export async function downloadFileWithProgress(
44
- url: string,
45
- cacheDir: string,
46
- onProgress?: DownloadProgressCallback,
47
- ): Promise<DownloadWithProgressResult> {
33
+ export async function downloadFileWithProgress(url: string, cacheDir: string, onProgress?: DownloadProgressCallback): Promise<DownloadWithProgressResult> {
48
34
  try {
49
35
  const dir = new Directory(cacheDir);
50
- if (!dir.exists) {
51
- dir.create({ intermediates: true, idempotent: true });
52
- }
36
+ if (!dir.exists) dir.create({ intermediates: true, idempotent: true });
53
37
 
54
38
  const destUri = getCacheUri(url, cacheDir);
55
- const cachedFile = new File(destUri);
56
- if (cachedFile.exists) {
57
- return { success: true, uri: destUri, fromCache: true };
58
- }
39
+ if (new File(destUri).exists) return { success: true, uri: destUri, fromCache: true };
59
40
 
60
41
  const response = await fetch(url);
61
- if (!response.ok) {
62
- throw new Error(`HTTP ${response.status}`);
63
- }
64
-
42
+ if (!response.ok) throw new Error(`HTTP ${response.status}`);
43
+
65
44
  const totalBytes = parseInt(response.headers.get("content-length") || "0", 10);
66
- if (!response.body) {
67
- const downloadResult = await downloadFile(url, destUri);
68
- return { ...downloadResult, fromCache: false };
69
- }
45
+ if (!response.body) return { ...(await downloadFile(url, destUri)), fromCache: false };
70
46
 
71
47
  const reader = response.body.getReader();
72
48
  const chunks: Uint8Array[] = [];
@@ -77,39 +53,22 @@ export async function downloadFileWithProgress(
77
53
  if (done) break;
78
54
  chunks.push(value);
79
55
  received += value.length;
80
- onProgress?.({
81
- totalBytesWritten: received,
82
- totalBytesExpectedToWrite: totalBytes || received,
83
- });
56
+ onProgress?.({ totalBytesWritten: received, totalBytesExpectedToWrite: totalBytes || received });
84
57
  }
85
58
 
86
59
  const all = new Uint8Array(received);
87
60
  let pos = 0;
88
- for (const chunk of chunks) {
89
- all.set(chunk, pos);
90
- pos += chunk.length;
91
- }
61
+ for (const c of chunks) { all.set(c, pos); pos += c.length; }
92
62
  new File(destUri).write(all);
93
63
 
94
64
  return { success: true, uri: destUri, fromCache: false };
95
- } catch (error) {
96
- const downloadError = error as DownloadError;
97
- return { success: false, error: downloadError.message || "Unknown error" };
98
- }
65
+ } catch (e: any) { return { success: false, error: e.message }; }
99
66
  }
100
67
 
101
- export const isUrlCached = (url: string, dir: string): boolean => {
102
- return new File(getCacheUri(url, dir)).exists;
103
- };
104
-
105
- export const getCachedFileUri = (url: string, dir: string): string | null => {
106
- return isUrlCached(url, dir) ? getCacheUri(url, dir) : null;
107
- };
108
-
109
- export const deleteCachedFile = (url: string, dir: string): boolean => {
110
- const file = new File(getCacheUri(url, dir));
111
- if (file.exists) {
112
- file.delete();
113
- }
68
+ export const isUrlCached = (url: string, dir: string) => new File(getCacheUri(url, dir)).exists;
69
+ export const getCachedFileUri = (url: string, dir: string) => isUrlCached(url, dir) ? getCacheUri(url, dir) : null;
70
+ export const deleteCachedFile = (url: string, dir: string) => {
71
+ const f = new File(getCacheUri(url, dir));
72
+ if (f.exists) f.delete();
114
73
  return true;
115
74
  };
@@ -11,8 +11,7 @@ export function blobToBase64(blob: Blob): Promise<string> {
11
11
  const reader = new FileReader();
12
12
  reader.onloadend = () => {
13
13
  const result = reader.result as string;
14
- // Remove data URL prefix if present
15
- const base64 = result.includes(",") ? result.split(",")[1] : result;
14
+ const base64 = result.includes(",") ? result.split(",")[1] ?? result : result;
16
15
  resolve(base64);
17
16
  };
18
17
  reader.onerror = reject;