@ew-did-registry/did-s3-store
Version:
S3-based implementation of IDidStore
84 lines (75 loc) • 2.21 kB
text/typescript
import {
S3Client,
PutObjectCommand,
GetObjectCommand,
DeleteObjectCommand,
S3ClientConfig,
} from "@aws-sdk/client-s3";
import { IDidStore } from "@ew-did-registry/did-store-interface";
import { CID } from "multiformats";
import { sha256 } from "multiformats/hashes/sha2";
/**
* Implements decentralized storage in S3 Bucket
*/
export class DidStore implements IDidStore {
private s3: S3Client;
private bucket: string;
constructor(bucket: string, s3Config: S3ClientConfig) {
this.s3 = new S3Client(s3Config);
this.bucket = bucket;
}
private async computeCid(claim: string): Promise<CID> {
const bytes = new TextEncoder().encode(claim);
const hash = await sha256.digest(bytes);
return CID.create(1, 0x55, hash); // raw codec
}
/**
* @param claim stringified content
*/
async save(claim: string): Promise<string> {
const cid = await this.computeCid(claim);
const key = cid.toString();
await this.s3.send(
new PutObjectCommand({
Bucket: this.bucket,
Key: key,
Body: claim,
ContentType: "text/plain",
})
);
return key;
}
/**
* Looks up content identified by `cid`. If no content found during `timeout`, then `ContentNotFound` error is thrown.
* @param cid CID of the content
* @param timeout time limit for getting response, milliseconds
* @returns stringified content
*/
async get(uri: string): Promise<string> {
const res = await this.s3.send(
new GetObjectCommand({
Bucket: this.bucket,
Key: uri,
})
);
const chunks: Uint8Array[] = [];
for await (const chunk of res.Body as AsyncIterable<Uint8Array>) {
chunks.push(chunk instanceof Uint8Array ? chunk : Uint8Array.from(chunk as ArrayLike<number>));
}
return new TextDecoder().decode(Uint8Array.from(chunks.flatMap(arr => Array.from(arr))));
}
async delete(uri: string): Promise<boolean> {
try {
await this.s3.send(
new DeleteObjectCommand({
Bucket: this.bucket,
Key: uri,
})
);
return true;
} catch (err: any) {
if (err.name === "NoSuchKey") return false;
throw err;
}
}
}