@symbiote-native/file-system 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +262 -0
  3. package/build/angular/index.d.ts +1 -0
  4. package/build/angular/index.js +1 -0
  5. package/build/core/file-system.d.ts +169 -0
  6. package/build/core/file-system.js +404 -0
  7. package/build/core/index.d.ts +2 -0
  8. package/build/core/index.js +2 -0
  9. package/build/core/native-module.d.ts +32 -0
  10. package/build/core/native-module.js +2 -0
  11. package/build/core/types.d.ts +104 -0
  12. package/build/core/types.js +15 -0
  13. package/build/next/directory.d.ts +36 -0
  14. package/build/next/directory.js +59 -0
  15. package/build/next/file.d.ts +71 -0
  16. package/build/next/file.js +207 -0
  17. package/build/next/index.d.ts +5 -0
  18. package/build/next/index.js +5 -0
  19. package/build/next/native-module.d.ts +109 -0
  20. package/build/next/native-module.js +2 -0
  21. package/build/next/network-tasks.d.ts +118 -0
  22. package/build/next/network-tasks.js +333 -0
  23. package/build/next/node-path.d.ts +16 -0
  24. package/build/next/node-path.js +353 -0
  25. package/build/next/path-utilities.d.ts +42 -0
  26. package/build/next/path-utilities.js +110 -0
  27. package/build/next/paths.d.ts +22 -0
  28. package/build/next/paths.js +43 -0
  29. package/build/next/streams.d.ts +25 -0
  30. package/build/next/streams.js +55 -0
  31. package/build/next/types.d.ts +152 -0
  32. package/build/next/types.js +19 -0
  33. package/build/next/url-utilities.d.ts +3 -0
  34. package/build/next/url-utilities.js +62 -0
  35. package/build/next/watcher.d.ts +19 -0
  36. package/build/next/watcher.js +64 -0
  37. package/build-ngc/angular/index.d.ts +1 -0
  38. package/build-ngc/angular/index.js +2 -0
  39. package/build-ngc/angular/index.js.map +1 -0
  40. package/build-ngc/next/directory.d.ts +36 -0
  41. package/build-ngc/next/directory.js +60 -0
  42. package/build-ngc/next/directory.js.map +1 -0
  43. package/build-ngc/next/file.d.ts +71 -0
  44. package/build-ngc/next/file.js +208 -0
  45. package/build-ngc/next/file.js.map +1 -0
  46. package/build-ngc/next/index.d.ts +5 -0
  47. package/build-ngc/next/index.js +6 -0
  48. package/build-ngc/next/index.js.map +1 -0
  49. package/build-ngc/next/native-module.d.ts +109 -0
  50. package/build-ngc/next/native-module.js +3 -0
  51. package/build-ngc/next/native-module.js.map +1 -0
  52. package/build-ngc/next/network-tasks.d.ts +118 -0
  53. package/build-ngc/next/network-tasks.js +334 -0
  54. package/build-ngc/next/network-tasks.js.map +1 -0
  55. package/build-ngc/next/node-path.d.ts +16 -0
  56. package/build-ngc/next/node-path.js +354 -0
  57. package/build-ngc/next/node-path.js.map +1 -0
  58. package/build-ngc/next/path-utilities.d.ts +42 -0
  59. package/build-ngc/next/path-utilities.js +111 -0
  60. package/build-ngc/next/path-utilities.js.map +1 -0
  61. package/build-ngc/next/paths.d.ts +22 -0
  62. package/build-ngc/next/paths.js +44 -0
  63. package/build-ngc/next/paths.js.map +1 -0
  64. package/build-ngc/next/streams.d.ts +25 -0
  65. package/build-ngc/next/streams.js +56 -0
  66. package/build-ngc/next/streams.js.map +1 -0
  67. package/build-ngc/next/types.d.ts +152 -0
  68. package/build-ngc/next/types.js +20 -0
  69. package/build-ngc/next/types.js.map +1 -0
  70. package/build-ngc/next/url-utilities.d.ts +3 -0
  71. package/build-ngc/next/url-utilities.js +63 -0
  72. package/build-ngc/next/url-utilities.js.map +1 -0
  73. package/build-ngc/next/watcher.d.ts +19 -0
  74. package/build-ngc/next/watcher.js +65 -0
  75. package/build-ngc/next/watcher.js.map +1 -0
  76. package/native-link.json +17 -0
  77. package/package.json +154 -0
  78. package/src/angular/index.ts +1 -0
  79. package/src/core/file-system.ts +634 -0
  80. package/src/core/index.ts +2 -0
  81. package/src/core/native-module.ts +99 -0
  82. package/src/core/types.ts +135 -0
  83. package/src/next/directory.ts +83 -0
  84. package/src/next/file.ts +318 -0
  85. package/src/next/index.ts +5 -0
  86. package/src/next/native-module.ts +188 -0
  87. package/src/next/network-tasks.ts +456 -0
  88. package/src/next/node-path.ts +362 -0
  89. package/src/next/path-utilities.ts +144 -0
  90. package/src/next/paths.ts +52 -0
  91. package/src/next/streams-ambient.d.ts +34 -0
  92. package/src/next/streams.ts +81 -0
  93. package/src/next/types.ts +194 -0
  94. package/src/next/url-utilities.ts +70 -0
  95. package/src/next/watcher.ts +106 -0
@@ -0,0 +1,194 @@
1
+ import type { File } from './file';
2
+ import type { Directory } from './directory';
3
+
4
+ export type IFileCreateOptions = {
5
+ intermediates?: boolean;
6
+ overwrite?: boolean;
7
+ };
8
+
9
+ export type IRelocationOptions = {
10
+ overwrite?: boolean;
11
+ };
12
+
13
+ export enum FileSystemEncodingType {
14
+ UTF8 = 'utf8',
15
+ Base64 = 'base64',
16
+ }
17
+
18
+ export type IFileWriteOptions = {
19
+ encoding?: FileSystemEncodingType | 'utf8' | 'base64';
20
+ append?: boolean;
21
+ };
22
+
23
+ export enum FileMode {
24
+ ReadWrite = 'rw',
25
+ ReadOnly = 'r',
26
+ WriteOnly = 'w',
27
+ Append = 'wa',
28
+ Truncate = 'wt',
29
+ }
30
+
31
+ export type IFileSystemHandle = {
32
+ close(): void;
33
+ readBytes(length: number): Uint8Array<ArrayBuffer>;
34
+ writeBytes(bytes: Uint8Array): void;
35
+ offset: number | null;
36
+ size: number | null;
37
+ };
38
+
39
+ export type IFileInfo = {
40
+ exists: boolean;
41
+ uri?: string;
42
+ size?: number;
43
+ modificationTime?: number;
44
+ creationTime?: number;
45
+ md5?: string;
46
+ };
47
+
48
+ export type IFileSystemInfoOptions = {
49
+ md5?: boolean;
50
+ };
51
+
52
+ export type IPickFileGeneralOptions = {
53
+ initialUri?: string;
54
+ mimeTypes?: string | string[];
55
+ multipleFiles?: boolean;
56
+ };
57
+
58
+ export type IPickSingleFileOptions = IPickFileGeneralOptions & {
59
+ multipleFiles?: false;
60
+ };
61
+
62
+ export type IPickMultipleFilesOptions = IPickFileGeneralOptions & {
63
+ multipleFiles: true;
64
+ };
65
+
66
+ export type IPickFileOptions =
67
+ IPickSingleFileOptions | IPickMultipleFilesOptions;
68
+
69
+ export type IPickSingleFileSuccessResult = {
70
+ result: File;
71
+ canceled: false;
72
+ };
73
+
74
+ export type IPickMultipleFilesSuccessResult = {
75
+ result: File[];
76
+ canceled: false;
77
+ };
78
+
79
+ export type IPickFileCanceledResult = {
80
+ result: null;
81
+ canceled: true;
82
+ };
83
+
84
+ export type IPickSingleFileResult =
85
+ IPickSingleFileSuccessResult | IPickFileCanceledResult;
86
+ export type IPickMultipleFilesResult =
87
+ IPickMultipleFilesSuccessResult | IPickFileCanceledResult;
88
+
89
+ export type IDirectoryCreateOptions = {
90
+ intermediates?: boolean;
91
+ overwrite?: boolean;
92
+ idempotent?: boolean;
93
+ };
94
+
95
+ export type IDirectoryInfo = {
96
+ exists: boolean;
97
+ uri?: string;
98
+ size?: number;
99
+ modificationTime?: number;
100
+ creationTime?: number;
101
+ files?: string[];
102
+ };
103
+
104
+ export type IPathInfo = {
105
+ exists: boolean;
106
+ isDirectory: boolean | null;
107
+ };
108
+
109
+ export type IFileSystemDownloadProgress = {
110
+ bytesWritten: number;
111
+ totalBytes: number;
112
+ };
113
+
114
+ export type IFileSystemDownloadOptions = {
115
+ headers?: Record<string, string>;
116
+ idempotent?: boolean;
117
+ onProgress?: (data: IFileSystemDownloadProgress) => void;
118
+ signal?: AbortSignal;
119
+ };
120
+
121
+ export enum FileSystemUploadType {
122
+ BINARY_CONTENT = 0,
123
+ MULTIPART = 1,
124
+ }
125
+
126
+ export type IFileSystemUploadProgress = {
127
+ bytesSent: number;
128
+ totalBytes: number;
129
+ };
130
+
131
+ export type IFileSystemUploadResult = {
132
+ body: string;
133
+ status: number;
134
+ headers: Record<string, string>;
135
+ };
136
+
137
+ export type IFileSystemNetworkTaskSessionType = 'background' | 'foreground';
138
+
139
+ export type IFileSystemUploadOptions = {
140
+ httpMethod?: 'POST' | 'PUT' | 'PATCH';
141
+ uploadType?: FileSystemUploadType;
142
+ headers?: Record<string, string>;
143
+ fieldName?: string;
144
+ mimeType?: string;
145
+ parameters?: Record<string, string>;
146
+ onProgress?: (data: IFileSystemUploadProgress) => void;
147
+ sessionType?: IFileSystemNetworkTaskSessionType;
148
+ signal?: AbortSignal;
149
+ };
150
+
151
+ export type IFileSystemDownloadTaskOptions = {
152
+ headers?: Record<string, string>;
153
+ sessionType?: IFileSystemNetworkTaskSessionType;
154
+ onProgress?: (data: IFileSystemDownloadProgress) => void;
155
+ signal?: AbortSignal;
156
+ };
157
+
158
+ export type IFileSystemDownloadPauseState = {
159
+ url: string;
160
+ fileUri: string;
161
+ isDirectory: boolean;
162
+ headers?: Record<string, string>;
163
+ resumeData?: string;
164
+ };
165
+
166
+ type IFileSystemTaskState =
167
+ 'idle' | 'active' | 'paused' | 'completed' | 'cancelled' | 'error';
168
+
169
+ export type IFileSystemUploadTaskState = Exclude<
170
+ IFileSystemTaskState,
171
+ 'paused'
172
+ >;
173
+ export type IFileSystemDownloadTaskState = IFileSystemTaskState;
174
+
175
+ export const DEFAULT_WATCH_DEBOUNCE_MS = 100;
176
+
177
+ export type IFileSystemWatchEventType =
178
+ 'created' | 'modified' | 'deleted' | 'renamed';
179
+
180
+ export type IFileSystemWatchEvent<T extends File | Directory> = {
181
+ type: IFileSystemWatchEventType;
182
+ target: T;
183
+ nativeEventFlags?: number;
184
+ newTarget?: T;
185
+ };
186
+
187
+ export type IFileSystemWatchOptions = {
188
+ debounce?: number;
189
+ events?: IFileSystemWatchEventType[];
190
+ };
191
+
192
+ export type IFileSystemWatchSubscription = {
193
+ remove(): void;
194
+ };
@@ -0,0 +1,70 @@
1
+ // Ported verbatim from expo-file-system's own vendored copy (Copyright Joyent, Inc. and other
2
+ // Node contributors, MIT licensed) — url-encoding helpers used when a path is a `file://`/URL
3
+ // rather than a bare posix path.
4
+
5
+ import { resolve, sep } from './node-path';
6
+
7
+ const percentRegEx = /%/g;
8
+ const backslashRegEx = /\\/g;
9
+ const newlineRegEx = /\n/g;
10
+ const carriageReturnRegEx = /\r/g;
11
+ const tabRegEx = /\t/g;
12
+ const questionRegex = /\?/g;
13
+ const hashRegex = /#/g;
14
+ const spaceRegEx = / /g;
15
+
16
+ function encodePathChars(filepath: string) {
17
+ if (filepath.indexOf('%') !== -1)
18
+ filepath = filepath.replace(percentRegEx, '%25');
19
+ if (filepath.indexOf('\\') !== -1)
20
+ filepath = filepath.replace(backslashRegEx, '%5C');
21
+ if (filepath.indexOf('\n') !== -1)
22
+ filepath = filepath.replace(newlineRegEx, '%0A');
23
+ if (filepath.indexOf('\r') !== -1)
24
+ filepath = filepath.replace(carriageReturnRegEx, '%0D');
25
+ if (filepath.indexOf('\t') !== -1)
26
+ filepath = filepath.replace(tabRegEx, '%09');
27
+ if (filepath.indexOf(' ') !== -1)
28
+ filepath = filepath.replace(spaceRegEx, '%20');
29
+ return filepath;
30
+ }
31
+
32
+ export function encodeURLChars(path: string) {
33
+ let resolved = resolve(path);
34
+ const filePathLast = path.charAt(path.length - 1);
35
+ if (filePathLast === '/' && resolved[resolved.length - 1] !== sep)
36
+ resolved += '/';
37
+
38
+ resolved = encodePathChars(resolved);
39
+
40
+ if (resolved.indexOf('?') !== -1)
41
+ resolved = resolved.replace(questionRegex, '%3F');
42
+ if (resolved.indexOf('#') !== -1)
43
+ resolved = resolved.replace(hashRegex, '%23');
44
+ return resolved;
45
+ }
46
+
47
+ export function isUrl(url: string) {
48
+ try {
49
+ return !!new URL(url);
50
+ } catch {
51
+ return false;
52
+ }
53
+ }
54
+
55
+ export function asUrl(url: string | URL) {
56
+ try {
57
+ const parsed = new URL(url);
58
+ if (parsed.hash === '') {
59
+ return parsed;
60
+ }
61
+ // Strip the hash by reconstructing rather than assigning `.hash = ''` — this project's
62
+ // resolved `URL` type declares its setters read-only (see path-utilities.ts's own note).
63
+ const hashIndex = parsed.href.indexOf('#');
64
+ return new URL(
65
+ hashIndex === -1 ? parsed.href : parsed.href.slice(0, hashIndex),
66
+ );
67
+ } catch {
68
+ return null;
69
+ }
70
+ }
@@ -0,0 +1,106 @@
1
+ import type { EventSubscription } from 'expo-modules-core';
2
+
3
+ import type { Directory } from './directory';
4
+ import type { File } from './file';
5
+ import {
6
+ expoFileSystemNext,
7
+ type INativeFileSystemWatcherEvent,
8
+ } from './native-module';
9
+ import { DEFAULT_WATCH_DEBOUNCE_MS } from './types';
10
+ import type {
11
+ IFileSystemWatchEvent,
12
+ IFileSystemWatchOptions,
13
+ IFileSystemWatchSubscription,
14
+ } from './types';
15
+
16
+ type ITargetFactory<T> = (uri: string, isDirectory: boolean) => T;
17
+
18
+ function normalizePath(path: string): string {
19
+ return path.replace(/\/+$/, '');
20
+ }
21
+
22
+ /**
23
+ * @hidden
24
+ * Internal implementation of file system watching. Use `File.watch()` or `Directory.watch()` instead.
25
+ */
26
+ export class FileSystemWatcher<
27
+ T extends File | Directory,
28
+ > implements IFileSystemWatchSubscription {
29
+ private nativeWatcher: InstanceType<
30
+ typeof expoFileSystemNext.FileSystemWatcher
31
+ > | null;
32
+ private subscription: EventSubscription | null = null;
33
+ private removed = false;
34
+ private readonly normalizedWatchedPath: string;
35
+
36
+ constructor(
37
+ path: string,
38
+ callback: (event: IFileSystemWatchEvent<T>) => void,
39
+ options: IFileSystemWatchOptions = {},
40
+ private readonly targetFactory: ITargetFactory<T>,
41
+ ) {
42
+ this.normalizedWatchedPath = normalizePath(path);
43
+ this.nativeWatcher = new expoFileSystemNext.FileSystemWatcher(path, {
44
+ debounce: options.debounce ?? DEFAULT_WATCH_DEBOUNCE_MS,
45
+ events: options.events,
46
+ });
47
+
48
+ this.subscription = this.nativeWatcher.addListener(
49
+ 'change',
50
+ (raw: INativeFileSystemWatcherEvent) => {
51
+ const event = this.mapEvent(raw);
52
+ const isWatchedTarget =
53
+ normalizePath(raw.path) === this.normalizedWatchedPath;
54
+
55
+ if (!options.events || options.events.includes(event.type)) {
56
+ callback(event);
57
+ }
58
+
59
+ if (
60
+ (event.type === 'deleted' || event.type === 'renamed') &&
61
+ isWatchedTarget
62
+ ) {
63
+ this.remove();
64
+ }
65
+ },
66
+ );
67
+
68
+ try {
69
+ this.nativeWatcher.start();
70
+ } catch (error) {
71
+ this.subscription.remove();
72
+ this.subscription = null;
73
+ this.nativeWatcher = null;
74
+ throw error;
75
+ }
76
+ }
77
+
78
+ private mapEvent(
79
+ raw: INativeFileSystemWatcherEvent,
80
+ ): IFileSystemWatchEvent<T> {
81
+ return {
82
+ type: raw.type,
83
+ target: this.targetFactory(raw.path, raw.isDirectory),
84
+ newTarget: raw.newPath
85
+ ? this.targetFactory(
86
+ raw.newPath,
87
+ raw.newPathIsDirectory ?? raw.isDirectory,
88
+ )
89
+ : undefined,
90
+ nativeEventFlags: raw.nativeEventFlags,
91
+ };
92
+ }
93
+
94
+ remove(): void {
95
+ if (this.removed) {
96
+ return;
97
+ }
98
+ this.removed = true;
99
+
100
+ this.subscription?.remove();
101
+ this.subscription = null;
102
+
103
+ this.nativeWatcher?.stop();
104
+ this.nativeWatcher = null;
105
+ }
106
+ }