1(()=>{2 let g = globalThis, d = g.document, CT = "content-type"3 if (g.mercury) return4 let send = (el, type, detail)=>(el ?? d ?? g).dispatchEvent(new CustomEvent(type, {detail, cancelable:1, bubbles:1, composed:1}))5 let hex = (b)=>[...new Uint8Array(b)].map((x)=>x.toString(16).padStart(2, "0")).join("")6 let sha = async(b)=>hex(await crypto.subtle.digest("SHA-256", b))7 let fail = (r)=>{8 if (!r.ok) throw Object.assign(Error(`${r.status} ${r.headers.get("x-reason") ?? r.statusText}`), {status:r.status, response:r})9 return r10 }11 let sign = async(event, elt)=>{12 let cfg = {elt, event:{created_at:Date.now() / 1e3 | 0, content:"", ...event}, sign:(e)=>(g.nostr ?? g.helium.signer).signEvent(e)}13 send(elt, "nhy:config", {cfg})14 if (!send(elt, "nhg:sign", {cfg})) throw new DOMException("nhg:sign cancelled", "AbortError")15 return "Nostr " + btoa(String.fromCharCode(...new TextEncoder().encode(JSON.stringify(await cfg.sign(cfg.event)))))16 }17 let guard = async(elt, f)=>{18 try { return await f() } catch(error) {19 send(elt, "nhg:error", {error})20 throw error21 }22 }23 let hfetch = async(url, o = {}, f = fetch)=>{24 url = new URL(url, g.location?.href).href25 let m = (o.method ?? "GET").toUpperCase(), h = new Headers(o.headers), tags = [["u", url], ["method", m]], r, t26 if (o.body != null){27 r = new Response(o.body)28 o = {...o, body:await r.arrayBuffer()}29 if ((t = r.headers.get(CT)) && !h.has(CT)) h.set(CT, t)30 tags.push(["payload", await sha(o.body)])31 }32 if (!h.has("authorization")) h.set("authorization", await sign({kind:27235, tags}, o.elt))33 return f(url, {...o, method:m, headers:h})34 }35 let verb = (m)=>(url, body, o = {})=>{36 let q = /GET|HEAD|DEL/.test(m)37 if (body != null){38 if (q) url += (/\?/.test(url) ? "&" : "?") + new URLSearchParams(body), body = null39 else if (body.constructor == Object || Array.isArray(body)) body = JSON.stringify(body), o = {...o, headers:{"content-type":"application/json", ...o.headers}}40 else if (body.tagName == "FORM") body = new FormData(body)41 }42 let p = guard(o.elt, ()=>hfetch(url, {...o, method:m, body}).then(fail))43 p.json = ()=>p.then((r)=>r.json())44 p.text = ()=>p.then((r)=>r.text())45 return p46 }47 let blossom = (server, path, t, x, o = {})=>guard(o.elt, async()=>{48 let u = new URL(path, server.replace(/\/?$/, "/")), tags = [["t", t], ["expiration", "" + ((Date.now() / 1e3 | 0) + (g.nhgCfg?.ttl ?? 300))], ["server", o.server ?? u.hostname]]49 if (x) tags.push(["x", x])50 let a = await sign({kind:24242, content:`${t} ${x || "blobs"}`, tags}, o.elt)51 return fail(await fetch(u, {...o, headers:{...o.headers, authorization:a}}))52 })53 let upload = async(server, blob, o = {})=>{54 let body = await blob.arrayBuffer(), x = await sha(body), t = o.media ? "media" : "upload"55 return (await blossom(server, t, t, x, {...o, method:"PUT", body, headers:{"content-type":blob.type || "application/octet-stream", "x-sha-256":x}})).json()56 }57 let remove = (server, x, o)=>blossom(server, x, "delete", x, {...o, method:"DELETE"}).then(()=>true)58 let list = (server, pubkey, o)=>blossom(server, "list/" + pubkey, "list", 0, o).then((r)=>r.json())59 g.mercury = {fetch:(url, o)=>guard(o?.elt, ()=>hfetch(url, o)), sign, upload, remove, list, get:verb("GET"), head:verb("HEAD"), post:verb("POST"), put:verb("PUT"), patch:verb("PATCH"), del:verb("DELETE")}60 d?.addEventListener("fx:config", (e)=>{61 let el = e.target, c = e.detail.cfg, f = c.fetch62 if (el.closest?.("[nhg-sign]")) c.fetch = (url, o)=>guard(el, ()=>hfetch(url, {...o, elt:el}, f))63 })64})()