All files / src/crud-to-cas CrudCasBase.ts

100% Statements 34/34
100% Branches 11/11
100% Functions 9/9
100% Lines 33/33

Press n or j to go to the next uncovered block, b, p or k for the previous block.

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        2x 38x 38x   16x 16x     13x     3x       2x   32x 32x 32x 32x     32x 32x 32x 32x 32x     32x 14x 14x 14x 11x 8x 8x   8x       32x 10x 10x 10x       32x 14x 14x 14x        
import type { CasApi, CasGetOptions } from '../cas/types';
import type { CrudApi, CrudResourceInfo } from '../crud/types';
import type { FsLocation } from '../fsa-to-node/types';
 
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 CrudCasBase<Hash> implements CasApi<Hash> {
  constructor(
    protected readonly crud: CrudApi,
    protected readonly hash: (blob: Uint8Array) => Promise<Hash>,
    protected readonly hash2Loc: (hash: Hash) => FsLocation,
    protected readonly hashEqual: (h1: Hash, h2: Hash) => boolean,
  ) {}
 
  public readonly put = async (blob: Uint8Array): Promise<Hash> => {
    const digest = await this.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.hash(blob);
        if (!this.hashEqual(digest, hash)) 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);
    });
  };
}