import { html, LitElement } from "./lib/lit.min.js"; import { unixNow, newExpirationValue, getFileSha256, formatBytes } from "./utils.js"; import "./open-blob-form.js"; export class UploadForm extends LitElement { static properties = { selected: { state: true }, status: { state: true, type: String }, }; createRenderRoot() { return this; } async upload(e) { e.preventDefault(); try { if (!this.selected) throw new Error("Select file first"); let file = this.selected; // handle an edge case where some browsers set the mime type of .m3u8 files to audio/x-mpegurl if (file.type === "audio/x-mpegurl" && file.name.endsWith(".m3u8")) { file = new File([file], file.name, { type: "application/vnd.apple.mpegurl", }); } this.status = "Compute SHA256 hash..."; const hash = await getFileSha256(file); this.status = "Signing..."; // create auth event const auth = await window.nostr.signEvent({ kind: 24242, content: "Authorize Upload", created_at: unixNow(), tags: [ ["t", "upload"], ["x", hash], ["expiration", newExpirationValue()], ], }); const authorization = "Nostr " + btoa(JSON.stringify(auth)); // BUD-06 check upload this.status = "Checking Upload..."; const check = await fetch("/upload", { method: "HEAD", headers: { authorization, "X-Content-Type": file.type, "X-Content-Length": file.size, "X-Sha-256": hash, }, }); if (!check.ok) { throw new Error(check.headers.get("x-upload-message") || "Upload Rejected"); } // Upload blob this.status = "Uploading..."; const res = await fetch("/upload", { method: "PUT", body: file, // attach Authorization: Nostr header to request headers: { authorization }, }); if (res.ok) { const body = await res.json(); this.selected = undefined; window.open(body.url, "_blank"); } else { throw new Error(await res.text()); } } catch (error) { if (error instanceof Error) { alert(error.message); } } this.status = "Upload"; } inputChange(e) { this.selected = e.target.files[0]; } render() { const preview = !this.selected ? html`

Drag and drop files here
or select a file from your computer

` : html`

${this.selected.name}

${formatBytes(this.selected.size)}

`; return html`

🌸 Blossom Server

Blobs stored simply on mediaservers

Github
List Blobs ${window.nostr && html`Mirror Blobs`}
🌸 Blossom Spec
`; } } customElements.define("upload-form", UploadForm);