Skip to content
This repository was archived by the owner on Dec 22, 2024. It is now read-only.

Commit d7f7e2c

Browse files
committed
feat: implement storage adapter
1 parent 385edff commit d7f7e2c

File tree

4 files changed

+86
-11
lines changed

4 files changed

+86
-11
lines changed

.vscode/settings.json

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"typescript.tsdk": "node_modules/typescript/lib"
3+
}

src/index.ts

Lines changed: 73 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,83 @@
11
import { Chunk, StorageAdapter, StorageKey } from '@automerge/automerge-repo';
22

33
export class OPFSStorageAdapter extends StorageAdapter {
4-
private baseDirectory: string
4+
private baseDirectory: string;
5+
private baseDirectoryHandle: FileSystemDirectoryHandle;
6+
private root: FileSystemDirectoryHandle;
57

6-
load(key: StorageKey): Promise<Uint8Array | undefined> {
7-
throw new Error('Method not implemented.');
8+
constructor(baseDirectory: string = "automerge-repo-data") {
9+
super();
10+
this.baseDirectory = baseDirectory;
11+
this.initialize();
812
}
9-
save(key: StorageKey, data: Uint8Array): Promise<void> {
10-
throw new Error('Method not implemented.');
13+
14+
async load(key: StorageKey): Promise<Uint8Array | undefined> {
15+
const fileName = getKey(key);
16+
17+
try {
18+
const fileHandle = await this.baseDirectoryHandle.getFileHandle(fileName);
19+
const file = await fileHandle.getFile();
20+
const arrayBuffer = await file.arrayBuffer();
21+
return new Uint8Array(arrayBuffer);
22+
} catch (error) {
23+
// don't throw if file not found
24+
if (error.code === "NotFoundError") return undefined
25+
throw error;
26+
}
27+
}
28+
29+
async save(key: StorageKey, data: Uint8Array): Promise<void> {
30+
const fileName = getKey(key);
31+
32+
const fileHandle = await this.baseDirectoryHandle.getFileHandle(fileName, { create: true });
33+
const fileWritable = await fileHandle.createWritable();
34+
await fileWritable.write(data);
35+
return fileWritable.close();
36+
}
37+
38+
async remove(key: StorageKey): Promise<void> {
39+
const fileName = getKey(key);
40+
41+
try {
42+
return this.baseDirectoryHandle.removeEntry(fileName);
43+
} catch (error) {
44+
// don't throw if file not found
45+
if (error.code === "NotFoundError") return undefined
46+
throw error;
47+
}
1148
}
12-
remove(key: StorageKey): Promise<void> {
13-
throw new Error('Method not implemented.');
49+
50+
async loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {
51+
const chunks: Chunk[] = [];
52+
const prefix = getKey(keyPrefix);
53+
54+
for await (const [name] of this.baseDirectoryHandle) {
55+
if (name.startsWith(prefix)) {
56+
const fileHandle = await this.baseDirectoryHandle.getFileHandle(name);
57+
const file = await fileHandle.getFile();
58+
const arrayBuffer = await file.arrayBuffer();
59+
chunks.push({key: name.split("_"), data: new Uint8Array(arrayBuffer)});
60+
}
61+
}
62+
63+
return chunks;
1464
}
15-
loadRange(keyPrefix: StorageKey): Promise<Chunk[]> {
16-
throw new Error('Method not implemented.');
65+
66+
async removeRange(keyPrefix: StorageKey): Promise<void> {
67+
const prefix = getKey(keyPrefix);
68+
69+
for await (const [name] of this.baseDirectoryHandle) {
70+
if (name.startsWith(prefix)) {
71+
await this.baseDirectoryHandle.removeEntry(name);
72+
}
73+
}
1774
}
18-
removeRange(keyPrefix: StorageKey): Promise<void> {
19-
throw new Error('Method not implemented.');
75+
76+
private async initialize() {
77+
this.root = await navigator.storage.getDirectory();
78+
this.baseDirectoryHandle = await this.root.getDirectoryHandle(this.baseDirectory, { create: true });
2079
}
80+
2181
}
82+
83+
const getKey = (key: StorageKey): string => key.join("_");

src/types.d.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
// dom.asynciterable haven't been released yet
2+
// see https://github.com/microsoft/TypeScript/pull/56723
3+
4+
interface FileSystemDirectoryHandle {
5+
[Symbol.asyncIterator](): AsyncIterableIterator<[string, FileSystemHandle]>;
6+
entries(): AsyncIterableIterator<[string, FileSystemHandle]>;
7+
keys(): AsyncIterableIterator<string>;
8+
values(): AsyncIterableIterator<FileSystemHandle>;
9+
}

tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
{
22
"compilerOptions": {
33
"target": "ESNext",
4+
"lib": ["DOM"],
45
"jsx": "react",
56
"module": "NodeNext",
67
"moduleResolution": "Node16",

0 commit comments

Comments
 (0)