/
CrudCas.ts
65 lines (57 loc) · 2.28 KB
/
CrudCas.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import { hashToLocation as defaultHashToLocation } from './util';
import type { CasApi, CasGetOptions } from '../cas/types';
import type { CrudApi, CrudResourceInfo } from '../crud/types';
import type { FsLocation } from '../fsa-to-node/types';
export interface CrudCasOptions<Hash = string> {
hash: (blob: Uint8Array) => Promise<Hash>;
hash2Loc?: (hash: Hash) => FsLocation;
}
const normalizeErrors = async <T>(code: () => Promise<T>): Promise<T> => {
try {
return await code();
} catch (error) {
if (error && typeof error === 'object') {
switch (error.name) {
case 'ResourceNotFound':
case 'CollectionNotFound':
throw new DOMException(error.message, 'BlobNotFound');
}
}
throw error;
}
};
export class CrudCas<Hash = string> implements CasApi<Hash> {
protected readonly hash2Loc: (hash: Hash) => FsLocation;
constructor(protected readonly crud: CrudApi, protected readonly options: CrudCasOptions<Hash>) {
this.hash2Loc = options.hash2Loc || <(hash: Hash) => FsLocation>defaultHashToLocation;
}
public readonly put = async (blob: Uint8Array): Promise<Hash> => {
const digest = await this.options.hash(blob);
const [collection, resource] = this.hash2Loc(digest);
await this.crud.put(collection, resource, blob);
return digest;
};
public readonly get = async (hash: Hash, options?: CasGetOptions): Promise<Uint8Array> => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
const blob = await this.crud.get(collection, resource);
if (!options?.skipVerification) {
const digest = await this.options.hash(blob);
if (hash !== digest) throw new DOMException('Blob contents does not match hash', 'Integrity');
}
return blob;
});
};
public readonly del = async (hash: Hash, silent?: boolean): Promise<void> => {
const [collection, resource] = this.hash2Loc(hash);
await normalizeErrors(async () => {
return await this.crud.del(collection, resource, silent);
});
};
public readonly info = async (hash: Hash): Promise<CrudResourceInfo> => {
const [collection, resource] = this.hash2Loc(hash);
return await normalizeErrors(async () => {
return await this.crud.info(collection, resource);
});
};
}