Allows a client or server to access the file system in the current codebase or a different one.
You need to access the file system where the environment is unknown. This could be the client or server.
A lightweight fully type-safe package for handling this in the simplest and most secure solution in prod.
universal-fs provides some core Node fs functions in related to the file system module including:
- mkdir
- readdir
- readFile
- rmdir
- unlink
- writeFile
Comparison | universal-fs | Node fs | vite-plugin-fs |
---|---|---|---|
Works outside of Node | ✅ | ❌ | ✅ |
Works outside of Vite | ✅ | ✅ | ❌ |
Works in prod | ✅ | ✅ | ❌ |
Password protected | ✅ | ❌ | ❌ |
Multi-language support | ✅ 1 | ❌ | ❌ |
Full Node fs backwards compatibility | ✅ 2 | ✅ | ❌ |
Edge support | ✅ | ❌ | ❌ |
Access to other codebases file system | ✅ | ❌ | ❌ |
Additional functionality outside of standard Node fs | ✅ | ❌ | ❌ |
Custom API generation | ✅ | ❌ | ❌ |
Supports all Node fs methods | ❌ | ✅ | ❌ |
Server.init()
must be called in a Node environment, everything else can be called anywhere. However, this requirement may be removed in a new release.
- Run
npm install universal-fs
. - Create a .env file.
- Enter any value for
UNIVERSAL_FS_PASSWORD
this will be hashed and used to protect your filesystem. - Signup for you Ngrok token
- Copy the token as an environment variable named
NGROK_AUTHTOKEN
Simply call init()
with Server.init()
as a prop.
import {init, Server, readFile} from "universal-fs";
const server = new Server();
await init(await server.init());
await readFile("index.ts");
The browser is a little more difficult due to an inability to access .env
or any server side functionality. Luckily this is what this library is made to solve.
Below is the recommended approach there are other ways to due this. Just make sure you don't leak your password 🥶:
- Create a route called
/api/fs-init
with following content. Note this example server uses Express you can use the framework of your choosing:
import {Server} from "universal-fs";
app.get("/api/fs-init", async (req, res) => {
// Your custom auth code
const server = new Server();
const url = await server.init();
return res.json({
url,
token: encrypt(proccess.env.UNIVERSAL_FS_TOKEN as string) // use the encryption library of your choosing
});
});
Note this endpoint should not be public!
- Call the init function in the browser
import {init, readFile} from "universal-fs";
const res = await fetch("/api/fs-init");
const data = await res.json();
await init(data.url, decrypt(data.token));
await readFile("index.html");
- mkdir
- readdir
- readFile
- rmdir
- unlink
- writeFile
- exists
All of these are fully backwards compatible with Node fs promise api.
As of universal-fs v1.1.0 your own server with your own custom url for universal-fs with all the same benefits.
First create a function with the following shape:
(app: Express, server?: http.Server) => Promise<string> | string;
You won't actually end up calling this function but universal-fs will. Here is an example of what this function could look like:
const startServer = (app: Express): string => {
app.listen(3001, () => {
console.log("listening on port 3001");
});
This will tell universal-fs to listen on port 3001.
Now pass this function into the server.init()
call:
const server = new Server({startServer});
await server.init();
Overall your total code should be:
const startServer = (app: Express): string => {
app.listen(3001, () => {
console.log("listening on port 3001");
});
return "http://localhost:3001";
};
const server = new Server({startServer});
await server.init();
Please note that your function MUST return the url the server is on whether that be remote or local.
In order to use universal-fs without a password add the following option to the Server
constructor:
const server = new Server({isProtected: false});
You can now use universal-fs read methods like normal on files not in .gitignore
.
Get two cookies one named universal-fs-url
, and the other universal-fs-token
.
Read two files .fs/url.txt
and .fs/token.txt
Tip: to get the url and the token you can use the internal helpers getToken()
and getUrl()
. You can find them in src/helpers.`
Send an a fetch request to the following the url fetched.
await fetch(`${await getUrl()}/path/to/the/file?method=readFile`, {
method: "GET",
headers: {
Authorization: `Bearer ${getToken}`
}
});
The method param correspondents to the type of operation. For example mkdir is a POST.
- All operations can be aborted by passing an Abort signal
Contributions are welcome! Please contributing.md for how to contribute.
- Multi-language support is only possible via the relay file server api. Additionally you project still needs to obtain an access token and the server's url.
- The whole library is not backwards compatible however, each method works in the exact same way as the Node fs method.