Skip to content

Commit bf57f44

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

File tree

1 file changed

+69
-0
lines changed

1 file changed

+69
-0
lines changed

packages/storage/src/web-fs.ts

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

0 commit comments

Comments
 (0)