@e280/quay
Version:
File-browser and outliner UI for the web
55 lines (44 loc) • 1.55 kB
text/typescript
import {Cask} from "./cask.js"
import {Forklift} from "./forklift.js"
import {OpfsForklift} from "./opfs-forklift.js"
import {MemoryForklift} from "./memory-forklift.js"
/**
* Cellar is an immutable content-addressable file store
* - files are identified by their hashes (duplicates are impossible)
* - files cannot be modified (delete it and save another)
* - no filenames or metadata (store those somewhere else)
* - pass in a forklift, which is the backend that actually stores the data
* - MemoryForklift is the default
* - OpfsForklift is probably what you really want in the browser
*/
export class Cellar {
static async opfs(dirname = "cellar") {
return new this(await OpfsForklift.setup(dirname))
}
constructor(private forklift: Forklift = new MemoryForklift()) {}
async *list(): AsyncIterable<string> {
yield* this.forklift.list()
}
async has(hash: string): Promise<boolean> {
return this.forklift.has(hash)
}
async save(file: Blob) {
const cask = await Cask.make(file)
if (!await this.forklift.has(cask.hash))
await this.forklift.save(cask.hash, cask.file)
return cask
}
async load(hash: string): Promise<Cask> {
const bytes = await this.forklift.load(hash)
const cask = await Cask.make(bytes)
if (cask.hash !== hash) throw new Error(`corruption error, hash mismatch (requested ${hash}) (got ${cask.hash})`)
return cask
}
async delete(hash: string) {
await this.forklift.delete(hash)
}
async clear() {
for await (const hash of this.list())
await this.delete(hash)
}
}