@monkdb/monkdb
Version:
🚀 Official TypeScript SDK for MonkDB — a unified, AI-native database for diverse data workloads
84 lines • 3.23 kB
JavaScript
// --- src/blobstore/MonkBlobstoreContainer.ts ---
import crypto from 'crypto';
import { MonkDigestNotFoundException, MonkBlobLocationNotFoundException, } from '../errors/MonkErrors.js';
import { Readable } from 'stream';
export class MonkBlobstoreContainer {
constructor(containerName, connection) {
this.containerName = containerName;
this.connection = connection;
}
async computeDigest(stream) {
const hash = crypto.createHash('sha1');
for await (const chunk of stream) {
hash.update(chunk);
}
return hash.digest('hex');
}
async put(file, digest) {
let stream;
let buffer;
if (file instanceof Blob || file instanceof File) {
buffer = Buffer.from(await file.arrayBuffer());
stream = Readable.from(buffer);
}
else if (Buffer.isBuffer(file)) {
buffer = file;
stream = Readable.from(buffer);
}
else if (file instanceof Readable) {
// If digest is not provided, we need to buffer the stream to compute it
if (!digest) {
const chunks = [];
for await (const chunk of file) {
chunks.push(chunk);
}
buffer = Buffer.concat(chunks);
stream = Readable.from(buffer);
}
else {
stream = file;
}
}
else {
throw new Error('Unsupported file type');
}
const actualDigest = digest || (await this.computeDigest(Readable.from(buffer)));
const headers = { 'Content-Type': 'application/octet-stream' };
const path = `/_blobs/${this.containerName}/${actualDigest}`;
const response = await this.connection.client.request('PUT', path, stream, headers);
if (!response)
throw new Error('Blob upload failed: No response');
return digest ? response.status === 201 : actualDigest;
}
async get(digest) {
const path = `/_blobs/${this.containerName}/${digest}`;
const response = await this.connection.client.request('GET', path);
if (!response || response.status === 404) {
throw new MonkDigestNotFoundException(this.containerName, digest);
}
if (!response.body) {
throw new Error('Blob response missing stream');
}
return response.body;
}
async delete(digest) {
const path = `/_blobs/${this.containerName}/${digest}`;
const response = await this.connection.client.request('DELETE', path);
if (!response)
return false;
if (response.status === 204)
return true;
if (response.status === 404)
return false;
throw new MonkBlobLocationNotFoundException(this.containerName, digest);
}
async exists(digest) {
const path = `/_blobs/${this.containerName}/${digest}`;
const response = await this.connection.client.request('HEAD', path);
return response?.status === 200;
}
toString() {
return `<BlobContainer '${this.containerName}'>`;
}
}
//# sourceMappingURL=MonkBlobstoreContainer.js.map