@symbiote-native/file-system 0.1.2 → 0.1.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/README.md +52 -32
- package/package.json +15 -15
package/README.md
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
# @symbiote-native/file-system
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
[
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
[Legacy API (`/legacy`)](#legacy-api-legacy) below.
|
|
3
|
+
Read, write, copy, move and download files on the device. One API for every
|
|
4
|
+
[SymbioteNative](../../README.md) adapter (React, Vue, Svelte, Solid and Angular).
|
|
5
|
+
|
|
6
|
+
It wraps [`expo-file-system`](https://github.com/expo/expo/tree/main/packages/expo-file-system) and
|
|
7
|
+
ports both of upstream's surfaces, matching upstream's own layout:
|
|
8
|
+
|
|
9
|
+
- **Default export:** the modern `File` / `Directory` / `Paths` classes, built on JSI shared objects
|
|
10
|
+
(`expo-modules-core`'s `SharedObject`). Upstream's default entry since SDK 54.
|
|
11
|
+
- **`./legacy` subpath:** the function-based API (read/write/copy/move/delete, directory listing,
|
|
12
|
+
disk-space queries, resumable download/upload, Android Storage Access Framework), reachable
|
|
13
|
+
upstream as `expo-file-system/legacy`. See [Legacy API (`/legacy`)](#legacy-api-legacy) below.
|
|
14
|
+
|
|
15
|
+
Which directory? `Paths.document` is for data the user expects to keep; `Paths.cache` is for
|
|
16
|
+
anything you can re-create, and the OS may clear it when storage runs low.
|
|
14
17
|
|
|
15
18
|
## Install
|
|
16
19
|
|
|
@@ -26,33 +29,33 @@ npx @symbiote-native/cli new my-app --file-system
|
|
|
26
29
|
npx @symbiote-native/cli add --file-system
|
|
27
30
|
```
|
|
28
31
|
|
|
29
|
-
Either way: installs `@symbiote-native/file-system` and wires the native autolinking automatically
|
|
32
|
+
Either way: installs `@symbiote-native/file-system` and wires the native autolinking automatically - see
|
|
30
33
|
[`@symbiote-native/cli`](../cli).
|
|
31
34
|
|
|
32
35
|
<details>
|
|
33
|
-
<summary>Manual install (no CLI
|
|
36
|
+
<summary>Manual install (no CLI - installing and wiring native autolinking by hand)</summary>
|
|
34
37
|
|
|
35
38
|
```bash
|
|
36
39
|
npm install @symbiote-native/file-system
|
|
37
40
|
```
|
|
38
41
|
|
|
39
42
|
`expo-file-system` and `expo-modules-core` come along as regular dependencies, pinned to exact
|
|
40
|
-
versions
|
|
43
|
+
versions - never install them yourself, and never add the `expo` meta-package to your project.
|
|
41
44
|
|
|
42
45
|
## Required one-time step: native autolinking wiring
|
|
43
46
|
|
|
44
|
-
Same one-time step as every other `expo-modules-core` package this project ships
|
|
47
|
+
Same one-time step as every other `expo-modules-core` package this project ships - see
|
|
45
48
|
[`@symbiote-native/local-auth`'s README](../local-auth/README.md#required-one-time-step-native-autolinking-wiring)
|
|
46
49
|
and the `symbiote-expo-native-module` project skill.
|
|
47
50
|
|
|
48
|
-
`native-link.json` carries no `Info.plist` keys or `<application>` attributes
|
|
51
|
+
`native-link.json` carries no `Info.plist` keys or `<application>` attributes - upstream's own
|
|
49
52
|
config plugin only sets two OPT-IN keys (`LSSupportsOpeningDocumentsInPlace`,
|
|
50
53
|
`UIFileSharingEnabled`), which an app adds itself only if it wants its Documents directory exposed
|
|
51
54
|
to the Files app; nothing here needs either by default.
|
|
52
55
|
|
|
53
56
|
</details>
|
|
54
57
|
|
|
55
|
-
**Android runtime permissions are NOT added automatically, by the CLI or otherwise**
|
|
58
|
+
**Android runtime permissions are NOT added automatically, by the CLI or otherwise** - add
|
|
56
59
|
whichever of these your app actually needs to your own `AndroidManifest.xml`, the same opt-in
|
|
57
60
|
shape [`@symbiote-native/media-library`](../media-library) uses:
|
|
58
61
|
|
|
@@ -65,25 +68,25 @@ shape [`@symbiote-native/media-library`](../media-library) uses:
|
|
|
65
68
|
|
|
66
69
|
`Paths.document`/`Paths.cache` operations and `StorageAccessFramework` (which asks the user to pick
|
|
67
70
|
a directory at runtime, and never touches the two `EXTERNAL_STORAGE` permissions) both work without
|
|
68
|
-
any of these on modern Android
|
|
71
|
+
any of these on modern Android - they matter only for direct legacy-path access outside the app
|
|
69
72
|
sandbox.
|
|
70
73
|
|
|
71
74
|
## Shape
|
|
72
75
|
|
|
73
76
|
```
|
|
74
77
|
src/next/ File.ts / Directory.ts / Paths.ts / network-tasks.ts (UploadTask/DownloadTask) /
|
|
75
|
-
watcher.ts (FileSystemWatcher) / path-utilities.ts / streams.ts / types.ts
|
|
78
|
+
watcher.ts (FileSystemWatcher) / path-utilities.ts / streams.ts / types.ts -
|
|
76
79
|
the default, shared-object surface. See "API" below.
|
|
77
80
|
src/core/ file-system.ts (every legacy function + DownloadResumable/UploadTask +
|
|
78
81
|
StorageAccessFramework), native-module.ts, types.ts. See "Legacy API" below.
|
|
79
|
-
src/angular/ @symbiote-native/file-system/angular
|
|
82
|
+
src/angular/ @symbiote-native/file-system/angular - export * from '../next'
|
|
80
83
|
```
|
|
81
84
|
|
|
82
|
-
`./react`, `./vue`, `./svelte`, and `./solid` are `exports`-map aliases straight onto `src/next
|
|
83
|
-
|
|
85
|
+
`./react`, `./vue`, `./svelte`, and `./solid` are `exports`-map aliases straight onto `src/next/`:
|
|
86
|
+
every class here carries no children/ref/render fields, so there is nothing to split per
|
|
84
87
|
framework. `./angular` stays a physical file/subpath since Angular ships through a separate
|
|
85
88
|
`ngc`/AOT build (`build-ngc/`). `./legacy` is one subpath shared by every adapter, for the same
|
|
86
|
-
reason
|
|
89
|
+
reason - plain async functions have no framework-specific shape either.
|
|
87
90
|
|
|
88
91
|
## Use it
|
|
89
92
|
|
|
@@ -108,7 +111,7 @@ const downloaded = await File.downloadFileAsync(
|
|
|
108
111
|
);
|
|
109
112
|
```
|
|
110
113
|
|
|
111
|
-
Identical import surface on every adapter
|
|
114
|
+
Identical import surface on every adapter - `@symbiote-native/file-system/react`, `/vue`,
|
|
112
115
|
`/svelte`, `/solid`, `/angular` all re-export the same classes.
|
|
113
116
|
|
|
114
117
|
## API
|
|
@@ -176,7 +179,7 @@ static fromSavable(savable): DownloadTask
|
|
|
176
179
|
|
|
177
180
|
### Errors
|
|
178
181
|
|
|
179
|
-
No custom JS error-class hierarchy
|
|
182
|
+
No custom JS error-class hierarchy - every native exception surfaces as an ordinary thrown `Error`
|
|
180
183
|
or rejected `Promise`, same as every other native module wrapper in this repo.
|
|
181
184
|
|
|
182
185
|
| Trigger | When |
|
|
@@ -185,15 +188,32 @@ or rejected `Promise`, same as every other native module wrapper in this repo.
|
|
|
185
188
|
| Reading/writing through a stale or already-closed handle | `IFileSystemHandle` methods throw |
|
|
186
189
|
| `pickFileAsync`/`pickDirectoryAsync` cancelled by the user | Rejects with an `AbortError` (old-API overload) or resolves `{ canceled: true }` (options-object overload) |
|
|
187
190
|
| `upload()`/`createUploadTask()`/`createDownloadTask()` aborted via `options.signal` | Rejects with an `AbortError` |
|
|
188
|
-
| `.copy()`/`.move()` onto an existing destination without `overwrite: true` | Native `Exception`
|
|
189
|
-
| Any operation on a path outside the app sandbox without permission | Native `Exception`
|
|
191
|
+
| `.copy()`/`.move()` onto an existing destination without `overwrite: true` | Native `Exception` - destination already exists |
|
|
192
|
+
| Any operation on a path outside the app sandbox without permission | Native `Exception` - permission/sandbox violation |
|
|
193
|
+
|
|
194
|
+
## Common questions
|
|
195
|
+
|
|
196
|
+
- **Where does a download go, and why can't the user see it?** The app's private sandbox. For the
|
|
197
|
+
Gallery use [`@symbiote-native/media-library`](../media-library); to let the user keep or send it,
|
|
198
|
+
[`@symbiote-native/sharing`](../sharing); on Android, the legacy `StorageAccessFramework` lets the
|
|
199
|
+
user pick a folder.
|
|
200
|
+
- **Permission denied outside the app's folders.** The classes work inside `Paths.document` and
|
|
201
|
+
`Paths.cache`. Anything else needs the Storage Access Framework (Android).
|
|
202
|
+
- **Document or cache?** `Paths.document` for data to keep; `Paths.cache` for what you can
|
|
203
|
+
re-create. The OS may clear the cache, and you should delete what you no longer need.
|
|
204
|
+
- **`file.create()` throws.** It throws if the file exists or you cannot create it; use
|
|
205
|
+
`file.write()` to replace contents.
|
|
206
|
+
|
|
207
|
+
Sources: [Expo forums thread](https://forums.expo.dev/t/unable-to-download-file-in-expected-location/19632),
|
|
208
|
+
[expo/expo#20298](https://github.com/expo/expo/issues/20298),
|
|
209
|
+
[Expo docs: FileSystem (legacy)](https://docs.expo.dev/versions/latest/sdk/filesystem-legacy/).
|
|
190
210
|
|
|
191
211
|
## Legacy API (`/legacy`)
|
|
192
212
|
|
|
193
|
-
Upstream's original function-based surface
|
|
213
|
+
Upstream's original function-based surface - plain async functions over `expo-modules-core`
|
|
194
214
|
instead of JSI shared objects. Same install, same autolinking step as above; the native module
|
|
195
215
|
behind it is a **separate** registration (`ExponentFileSystem`, vs. the modern API's
|
|
196
|
-
`FileSystem`) inside the same `expo-file-system` npm dependency
|
|
216
|
+
`FileSystem`) inside the same `expo-file-system` npm dependency - nothing extra to install.
|
|
197
217
|
|
|
198
218
|
```ts
|
|
199
219
|
import {
|
|
@@ -251,12 +271,12 @@ repo's `I`-prefix convention for exported types (`ts-js-best-practices`).
|
|
|
251
271
|
|
|
252
272
|
### Legacy notes
|
|
253
273
|
|
|
254
|
-
- **`StorageAccessFramework` is Android-only**
|
|
274
|
+
- **`StorageAccessFramework` is Android-only** - every function throws `UnavailabilityError` on iOS,
|
|
255
275
|
matching upstream (there is no SAF equivalent on iOS; use the ordinary `document`/`cacheDirectory`
|
|
256
276
|
functions there instead).
|
|
257
|
-
- **`getContentUriAsync` is Android-only**
|
|
277
|
+
- **`getContentUriAsync` is Android-only** - on iOS it resolves to the input `fileUri` unchanged,
|
|
258
278
|
matching upstream's own platform branch, rather than throwing.
|
|
259
|
-
- **Progress callbacks fire only while a task is subscribed**
|
|
279
|
+
- **Progress callbacks fire only while a task is subscribed** - `DownloadResumable`/`UploadTask`
|
|
260
280
|
add their native event listener only for the duration of the in-flight call
|
|
261
281
|
(`downloadAsync`/`uploadAsync`/`resumeAsync`), removing it as soon as the promise settles, exactly
|
|
262
282
|
as upstream does.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@symbiote-native/file-system",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "expo-file-system wrapped for SymbioteNative — one framework-agnostic core, built once and reachable from the React, Vue, Svelte, Solid, and Angular adapters. Matches upstream's own layout: the modern JSI shared-object File/Directory/Paths API (including upload/download tasks and filesystem watching) at the package root, and the legacy function-based API (read/write/copy/move/delete, directory listing, disk-space queries, resumable download/upload, Android Storage Access Framework) at the ./legacy subpath. See the module's own README.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
},
|
|
75
75
|
"dependencies": {
|
|
76
76
|
"expo-file-system": "57.0.6",
|
|
77
|
-
"expo-modules-core": "57.0.
|
|
77
|
+
"expo-modules-core": "57.0.20"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
80
80
|
"@angular/core": ">=20",
|
|
@@ -84,12 +84,12 @@
|
|
|
84
84
|
"solid-js": ">=1.9.0",
|
|
85
85
|
"svelte": ">=5.56.0",
|
|
86
86
|
"vue": ">=3.5.0",
|
|
87
|
-
"@symbiote-native/angular": "^3.
|
|
88
|
-
"@symbiote-native/engine": "^1.
|
|
89
|
-
"@symbiote-native/react": "^3.0
|
|
90
|
-
"@symbiote-native/solid": "^3.0
|
|
91
|
-
"@symbiote-native/svelte": "^3.0
|
|
92
|
-
"@symbiote-native/vue": "^3.0
|
|
87
|
+
"@symbiote-native/angular": "^3.3.0",
|
|
88
|
+
"@symbiote-native/engine": "^1.6.0",
|
|
89
|
+
"@symbiote-native/react": "^3.3.0",
|
|
90
|
+
"@symbiote-native/solid": "^3.2.0",
|
|
91
|
+
"@symbiote-native/svelte": "^3.2.0",
|
|
92
|
+
"@symbiote-native/vue": "^3.3.0"
|
|
93
93
|
},
|
|
94
94
|
"peerDependenciesMeta": {
|
|
95
95
|
"@symbiote-native/angular": {
|
|
@@ -137,13 +137,13 @@
|
|
|
137
137
|
"solid-js": "^1.9.14",
|
|
138
138
|
"svelte": "^5.56.0",
|
|
139
139
|
"typescript": "~6.0.0",
|
|
140
|
-
"@symbiote-native/angular": "3.
|
|
141
|
-
"@symbiote-native/engine": "1.
|
|
142
|
-
"@symbiote-native/react": "3.0
|
|
143
|
-
"@symbiote-native/solid": "3.0
|
|
144
|
-
"@symbiote-native/svelte": "3.0
|
|
145
|
-
"@symbiote-native/test-utils": "0.4.
|
|
146
|
-
"@symbiote-native/vue": "3.0
|
|
140
|
+
"@symbiote-native/angular": "3.3.0",
|
|
141
|
+
"@symbiote-native/engine": "1.6.0",
|
|
142
|
+
"@symbiote-native/react": "3.3.0",
|
|
143
|
+
"@symbiote-native/solid": "3.2.0",
|
|
144
|
+
"@symbiote-native/svelte": "3.2.0",
|
|
145
|
+
"@symbiote-native/test-utils": "0.4.7",
|
|
146
|
+
"@symbiote-native/vue": "3.3.0"
|
|
147
147
|
},
|
|
148
148
|
"scripts": {
|
|
149
149
|
"typecheck": "tsc --build",
|