Skip to content

Commit 531d6de

Browse files
committed
feat(storage): Add WebFileSystemStore
1 parent b90f16b commit 531d6de

File tree

1 file changed

+64
-0
lines changed

1 file changed

+64
-0
lines changed

packages/storage/src/web-fs.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import type { AbsolutePath, AsyncReadable } from "./types.js";
2+
3+
/**
4+
* Get a file handle to a file in a directory.
5+
*
6+
* @param root - A root directory from the Web File System API.
7+
* @param path - A key to a file in the root directory.
8+
* @returns A file handle to the file.
9+
*/
10+
async function resolveFileHandleForPath(root: FileSystemDirectoryHandle, path: string): Promise<FileSystemFileHandle> {
11+
const dirs = path.split("/");
12+
const fname = dirs.pop();
13+
if (!fname) {
14+
throw new Error("Invalid path");
15+
}
16+
for (const dir of dirs) {
17+
root = await root.getDirectoryHandle(dir);
18+
}
19+
return root.getFileHandle(fname);
20+
}
21+
22+
/**
23+
* A store for zarrita based on the Web File System API.
24+
*
25+
* Note: usage requires prompting the user to select a directory to grant
26+
* access to the Web File System API.
27+
*
28+
* @see {@link https://developer.mozilla.org/en-US/docs/Web/API/File_System_API}
29+
*
30+
* @example
31+
* ```js
32+
* import * as zarr from "zarrita";
33+
* import WebFileSystemStore from "@zarrita/storage/web-fs";
34+
*
35+
* let directoryHandle = await globalThis.showDirectoryPicker();
36+
* let store = new WebFileSystemStore(directoryHandle);
37+
* let root = await zarr.root(store);
38+
* let arr = await zarr.open(root.resolve("/foo"), { kind: "array" });
39+
* ```
40+
*/
41+
class WebFileSystemStore implements AsyncReadable {
42+
#root: FileSystemDirectoryHandle;
43+
44+
constructor(root: FileSystemDirectoryHandle) {
45+
this.#root = root;
46+
}
47+
48+
async get(key: AbsolutePath): Promise<Uint8Array | undefined> {
49+
let fh = await resolveFileHandleForPath(this.#root, key.slice(1)).catch(() => {
50+
// TODO: better error handling
51+
// I believe a missing file will trigger an error here, which we should explicitly
52+
// catch and return `undefined`
53+
return undefined;
54+
});
55+
if (!fh) {
56+
return undefined;
57+
};
58+
let file = await fh.getFile();
59+
let buffer = await file.arrayBuffer();
60+
return new Uint8Array(buffer);
61+
}
62+
}
63+
64+
export default WebFileSystemStore;

0 commit comments

Comments
 (0)