useUpload
Upload bytes to Bulletin-backed cloud storage and get a CID receipt
useUpload stores raw bytes in Bulletin-backed cloud storage. Call
upload(data, options?) with a Uint8Array; it resolves with a
StoreResult receipt whose cid you later pass to
useCid to read the content back. The receipt also
carries size and, when known, the blockNumber and extrinsicIndex of the
storing extrinsic. Mutation state (data, error, isPending, reset)
tracks the last upload.
Uploads are signed: the storage client is created lazily on first use and
signs with the connected account, so the user must connect before the first
upload (it rejects with a clear error otherwise). The app config must include
cloudStorage: { environment }, or every storage hook rejects with a config
error.
Usage
Uploading a JSON document: encode it to bytes with TextEncoder, keep the
returned CID to read it back.
import { useCid, useUpload } from "@use-truapi/react";
import { useState } from "react";
interface Note { title: string; body: string }
function NoteUploader() {
const [cid, setCid] = useState<string | undefined>(undefined);
const upload = useUpload({
mutation: { onSuccess: (result) => setCid(result.cid?.toString()) },
});
const stored = useCid<Note>(cid, { json: true });
function onSave(note: Note) {
const data = new TextEncoder().encode(JSON.stringify(note));
void upload.upload(data).catch(() => {}); // failures land in upload.error
}
return (
<>
<button
type="button"
disabled={upload.isPending}
onClick={() => onSave({ title: "hello", body: "stored on Bulletin" })}
>
{upload.isPending ? "Uploading…" : "Save note"}
</button>
{upload.error && <p role="alert">{upload.error.message}</p>}
{cid && <p>Stored as {cid}, reads back: {stored.data?.title ?? "fetching…"}</p>}
</>
);
}<script setup lang="ts">
import { useCid, useUpload } from "@use-truapi/vue";
import { ref } from "vue";
interface Note { title: string; body: string }
const cid = ref<string | undefined>(undefined);
const upload = useUpload({
mutation: { onSuccess: (result) => (cid.value = result.cid?.toString()) },
});
const stored = useCid<Note>(() => cid.value, { json: true });
function onSave(note: Note) {
const data = new TextEncoder().encode(JSON.stringify(note));
void upload.upload(data).catch(() => {}); // failures land in upload.error
}
</script>
<template>
<button
type="button"
:disabled="upload.isPending"
@click="onSave({ title: 'hello', body: 'stored on Bulletin' })"
>
{{ upload.isPending ? "Uploading…" : "Save note" }}
</button>
<p v-if="upload.error" role="alert">{{ upload.error.message }}</p>
<p v-if="cid">Stored as {{ cid }}, reads back: {{ stored.data?.title ?? "fetching…" }}</p>
</template>Large payloads can be chunked, with per-chunk progress reported through
onProgress; both are per-upload options:
const result = await upload.upload(fileBytes, {
chunkSize: 256 * 1024,
onProgress: (event) => console.log("upload progress", event),
});See also
useCidfetches the stored content back by CID.useStorageAuthorizationchecks the account's remaining quota before uploading.
API reference
React
function useUpload(options?): NamedMutation<StoreResult, UploadVariables> & object;Upload bytes to Bulletin-backed cloud storage: upload(data) → CID receipt.
Parameters
| Parameter | Type |
|---|---|
options? | { mutation?: MutationOptions<StoreResult, UploadVariables>; } |
options.mutation? | MutationOptions<StoreResult, UploadVariables> |
Returns
NamedMutation<StoreResult, UploadVariables> & object
Vue
function useUpload(options?): NamedMutation<StoreResult, UploadVariables> & object;Upload bytes to Bulletin-backed cloud storage: upload(data) → CID receipt.
Parameters
| Parameter | Type |
|---|---|
options? | { mutation?: MutationOptions<StoreResult, UploadVariables>; } |
options.mutation? | MutationOptions<StoreResult, UploadVariables> |
Returns
NamedMutation<StoreResult, UploadVariables> & object