@opendatalabs/vana-sdk
Version:
A TypeScript library for interacting with Vana Network smart contracts.
227 lines • 7.28 kB
JavaScript
import {
StorageError
} from "../../types/storage.js";
class CallbackStorage {
/**
* Creates a new callback-based storage provider.
*
* @param callbacks - User-provided storage operation callbacks.
* Must include at minimum `upload` and `download` functions.
* @throws {Error} If required callbacks are missing
*/
constructor(callbacks) {
this.callbacks = callbacks;
if (!callbacks.upload || !callbacks.download) {
throw new Error(
"CallbackStorage requires both upload and download callbacks"
);
}
}
callbacks;
/**
* Uploads a file using the user-provided callback.
*
* @param file - The blob to upload.
* Can be any Blob-compatible object including File.
* @param filename - Optional filename for the upload.
* If not provided, callback may generate a name.
* @returns Upload result containing URL and metadata
*
* @throws {StorageError} With code 'INVALID_UPLOAD_RESULT' if callback returns invalid data
* @throws {StorageError} With code 'UPLOAD_ERROR' if upload fails
*
* @example
* ```typescript
* const file = new File(['content'], 'data.json');
* const result = await storage.upload(file);
* console.log('Uploaded to:', result.url);
* ```
*/
async upload(file, filename) {
try {
const result = await this.callbacks.upload(file, filename);
if (!result.url || result.url.trim() === "") {
throw new StorageError(
"Upload callback returned invalid result: missing or empty url",
"INVALID_UPLOAD_RESULT",
"callback-storage"
);
}
return result;
} catch (error) {
if (error instanceof StorageError) {
throw error;
}
throw new StorageError(
`Upload failed: ${error instanceof Error ? error.message : String(error)}`,
"UPLOAD_ERROR",
"callback-storage",
{ cause: error instanceof Error ? error : void 0 }
);
}
}
/**
* Downloads a file using the user-provided callback.
*
* @param url - The URL or identifier to download.
* If `extractIdentifier` callback is provided, it will be used to extract the identifier.
* @returns The downloaded file as a Blob
*
* @throws {StorageError} With code 'INVALID_DOWNLOAD_RESULT' if callback returns non-Blob
* @throws {StorageError} With code 'DOWNLOAD_ERROR' if download fails
*
* @example
* ```typescript
* const blob = await storage.download('https://storage.example.com/file123');
* const text = await blob.text();
* ```
*/
async download(url) {
try {
const identifier = this.callbacks.extractIdentifier ? this.callbacks.extractIdentifier(url) : url;
const blob = await this.callbacks.download(identifier);
if (!(blob instanceof Blob)) {
throw new StorageError(
"Download callback returned invalid result: expected Blob",
"INVALID_DOWNLOAD_RESULT",
"callback-storage"
);
}
return blob;
} catch (error) {
if (error instanceof StorageError) {
throw error;
}
throw new StorageError(
`Download failed: ${error instanceof Error ? error.message : String(error)}`,
"DOWNLOAD_ERROR",
"callback-storage",
{ cause: error instanceof Error ? error : void 0 }
);
}
}
/**
* Lists files using the user-provided callback.
*
* @param options - Optional list options.
* @param options.namePattern - Pattern to filter files by name.
* Implementation depends on callback.
* @param options.limit - Maximum number of files to return.
* Implementation depends on callback.
* @returns Array of storage file metadata
*
* @throws {StorageError} With code 'NOT_SUPPORTED' if list callback not provided
* @throws {StorageError} With code 'LIST_ERROR' if listing fails
*
* @remarks
* This operation is optional and only available if a `list` callback
* is provided during construction.
*
* @example
* ```typescript
* const files = await storage.list({ namePattern: '*.json' });
* files.forEach(file => console.log(file.name, file.size));
* ```
*/
async list(options) {
if (!this.callbacks.list) {
throw new StorageError(
"List operation not supported - no list callback provided",
"NOT_SUPPORTED",
"callback-storage"
);
}
try {
const result = await this.callbacks.list(options?.namePattern, options);
return result.items.map((item, index) => ({
id: item.identifier,
name: item.identifier.split("/").pop() ?? `file-${index}`,
url: item.identifier,
size: item.size ?? 0,
contentType: "application/octet-stream",
createdAt: item.lastModified ?? /* @__PURE__ */ new Date(),
metadata: item.metadata
}));
} catch (error) {
throw new StorageError(
`List failed: ${error instanceof Error ? error.message : String(error)}`,
"LIST_ERROR",
"callback-storage",
{ cause: error instanceof Error ? error : void 0 }
);
}
}
/**
* Deletes a file using the user-provided callback.
*
* @param url - The URL or identifier to delete.
* If `extractIdentifier` callback is provided, it will be used to extract the identifier.
* @returns True if deletion succeeded, false otherwise
*
* @throws {StorageError} With code 'NOT_SUPPORTED' if delete callback not provided
* @throws {StorageError} With code 'DELETE_ERROR' if deletion fails
*
* @remarks
* This operation is optional and only available if a `delete` callback
* is provided during construction.
*
* @example
* ```typescript
* const deleted = await storage.delete('https://storage.example.com/file123');
* if (deleted) {
* console.log('File deleted successfully');
* }
* ```
*/
async delete(url) {
if (!this.callbacks.delete) {
throw new StorageError(
"Delete operation not supported - no delete callback provided",
"NOT_SUPPORTED",
"callback-storage"
);
}
try {
const identifier = this.callbacks.extractIdentifier ? this.callbacks.extractIdentifier(url) : url;
return await this.callbacks.delete(identifier);
} catch (error) {
throw new StorageError(
`Delete failed: ${error instanceof Error ? error.message : String(error)}`,
"DELETE_ERROR",
"callback-storage",
{ cause: error instanceof Error ? error : void 0 }
);
}
}
/**
* Returns the provider's configuration and capabilities.
*
* @returns Configuration object indicating supported features
*
* @example
* ```typescript
* const config = storage.getConfig();
* if (config.features.list) {
* // List operation is supported
* const files = await storage.list();
* }
* ```
*/
getConfig() {
return {
name: "callback-storage",
type: "callback",
requiresAuth: false,
features: {
upload: true,
download: true,
list: !!this.callbacks.list,
delete: !!this.callbacks.delete
}
};
}
}
export {
CallbackStorage
};
//# sourceMappingURL=callback-storage.js.map