Loading...
Loading...
General file/object storage, such as for images, videos, files, documents and other bulk data. Perfect fit for image galleries, video galleries, and other file or object management. Supports large files beyond IC limit, with browser-cached HTTP URL access.
npx skill4agent add caffeinelabs/skills extension-object-storageMixinObjectStorageStorage.ExternalBlob403 Forbidden: Invalid payloadcaffeineai-object-storagemops.toml[dependencies]include MixinObjectStorage()main.mo"mo:caffeineai-object-storage/Mixin"Storage.ExternalBlobText@caffeineai/object-storageExternalBlob.fromBytes()@caffeineai/object-storagecaffeineai-object-storageStorage.ExternalBlobmo:caffeineai-object-storage/StorageStorage.ExternalBlobTextTextStorage.ExternalBlobTextblob : Storage.ExternalBlobblobId : Text
imageUrl : Text
fileRef : Textmo:caffeineai-object-storage/StorageExternalBlobBlobStorage.moMixinObjectStorageinclude MixinObjectStorage()main.moimport MixinObjectStorage "mo:caffeineai-object-storage/Mixin";
import Storage "mo:caffeineai-object-storage/Storage";
actor {
include MixinObjectStorage();
// Track file references
type Data = {
id: Text;
blob: Storage.ExternalBlob;
name: Text;
// other metadata
};
};_immutableObjectStorageCreateCertificate_immutableObjectStorage*MixinObjectStorage403 Forbidden: Invalid payload// WRONG: Do not write this yourself
public shared func _immutableObjectStorageCreateCertificate(fileHash : Text) : async Blob {
CertifiedData.set(Blob.fromArray(hashBytes));
Blob.fromArray([])
};// WRONG: Do not create src/backend/mixins/object-storage-api.mo
import ObjectStorageMixin "mixins/object-storage-api";
include ObjectStorageMixin();"mo:caffeineai-object-storage/Mixin""mixins/object-storage-api""./ObjectStorage"_immutableObjectStorageCreateCertificate : (blobHash : Text) -> async record { method : Text; blob_hash : Text }Blob()TextBlobExternalBlobimport { ExternalBlob } from "@caffeineai/object-storage";
import type { FileRecord } from "@caffeineai/object-storage";class ExternalBlob {
getBytes(): Promise<Uint8Array<ArrayBuffer>>;
getDirectURL(): string;
static fromURL(url: string): ExternalBlob;
static fromBytes(blob: Uint8Array<ArrayBuffer>): ExternalBlob;
withUploadProgress(onProgress: (percentage: number) => void): ExternalBlob;
}FileExternalBlobconst handleUpload = async (file: File) => {
const bytes = new Uint8Array(await file.arrayBuffer());
const blob = ExternalBlob.fromBytes(bytes).withUploadProgress((pct) => {
setProgress(pct);
});
await actor.uploadFile(file.name, blob);
};file.namegetDirectURL()<img src={record.blob.getDirectURL()} alt={record.filename} />getDirectURL()filenameconst isImage = (filename: string) =>
/\.(jpg|jpeg|png|gif|webp|svg|bmp|ico)$/i.test(filename);
// Conditional rendering
{isImage(record.filename) ? (
<img src={record.blob.getDirectURL()} alt={record.filename} />
) : (
<div>{record.filename}</div>
)}mimeTypeconst isImage = (mimeType?: string) => mimeType?.startsWith("image/");getBytes()const handleDownload = async (record: FileRecord) => {
const bytes = await record.blob.getBytes();
const blob = new Blob([bytes]);
const url = URL.createObjectURL(blob);
const a = document.createElement("a");
a.href = url;
a.download = record.filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
};getDirectURL()getBytes()| Use case | Method | Notes |
|---|---|---|
| Display image/video | | Streaming, cached |
| Download with filename | | Wrap in Blob + anchor |
| Upload from browser | | Pair with |
| Detect file type | | NEVER inspect the URL |
src/backend/mops.toml[dependencies]
caffeineai-object-storage = "0.1.2"caffeineai-object-storage[dependencies]mops install| Error | Cause | Fix |
|---|---|---|
| Backend canister missing | Install |
| | Add the mops dependency and rebuild backend |
| Method exists but still 403 | Hand-written stub returns wrong type (e.g. | Remove the custom implementation, use the platform mixin instead |
| Cashier registration issue (unrelated to this skill) | Redeploy the backend canister to trigger self-healing registration |