"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // nipb7.ts var nipb7_exports = {}; __export(nipb7_exports, { BlossomClient: () => BlossomClient }); module.exports = __toCommonJS(nipb7_exports); var import_sha256 = require("@noble/hashes/sha256"); // utils.ts var import_utils = require("@noble/hashes/utils"); var utf8Decoder = new TextDecoder("utf-8"); var utf8Encoder = new TextEncoder(); // nipb7.ts var BlossomClient = class { mediaserver; signer; constructor(mediaserver, signer) { if (!mediaserver.startsWith("http")) { mediaserver = "https://" + mediaserver; } this.mediaserver = mediaserver.replace(/\/$/, "") + "/"; this.signer = signer; } async httpCall(method, url, contentType, addAuthorization, body, result) { const headers = {}; if (contentType) { headers["Content-Type"] = contentType; } if (addAuthorization) { const auth = await addAuthorization(); if (auth) { headers["Authorization"] = auth; } } const response = await fetch(this.mediaserver + url, { method, headers, body }); if (response.status >= 300) { const reason = response.headers.get("X-Reason") || response.statusText; throw new Error(`${url} returned an error (${response.status}): ${reason}`); } if (result !== null && response.headers.get("content-type")?.includes("application/json")) { return await response.json(); } return response; } async authorizationHeader(modify) { const now = Math.floor(Date.now() / 1e3); const event = { created_at: now, kind: 24242, content: "blossom stuff", tags: [["expiration", String(now + 60)]] }; if (modify) { modify(event); } try { const signedEvent = await this.signer.signEvent(event); const eventJson = JSON.stringify(signedEvent); return "Nostr " + btoa(eventJson); } catch (error) { return ""; } } isValid32ByteHex(hash) { return /^[a-f0-9]{64}$/i.test(hash); } async check(hash) { if (!this.isValid32ByteHex(hash)) { throw new Error(`${hash} is not a valid 32-byte hex string`); } try { await this.httpCall("HEAD", hash); } catch (error) { throw new Error(`failed to check for ${hash}: ${error}`); } } async uploadBlob(file, contentType) { const hash = (0, import_utils.bytesToHex)((0, import_sha256.sha256)(new Uint8Array(await file.arrayBuffer()))); const actualContentType = contentType || file.type || "application/octet-stream"; const bd = await this.httpCall( "PUT", "upload", actualContentType, () => this.authorizationHeader((evt) => { evt.tags.push(["t", "upload"]); evt.tags.push(["x", hash]); }), file, {} ); return bd; } async uploadFile(file) { return this.uploadBlob(file, file.type); } async download(hash) { if (!this.isValid32ByteHex(hash)) { throw new Error(`${hash} is not a valid 32-byte hex string`); } const authHeader = await this.authorizationHeader((evt) => { evt.tags.push(["t", "get"]); evt.tags.push(["x", hash]); }); const response = await fetch(this.mediaserver + hash, { method: "GET", headers: { Authorization: authHeader } }); if (response.status >= 300) { throw new Error(`${hash} is not present in ${this.mediaserver}: ${response.status}`); } return await response.arrayBuffer(); } async downloadAsBlob(hash) { const arrayBuffer = await this.download(hash); return new Blob([arrayBuffer]); } async list() { const pubkey = await this.signer.getPublicKey(); if (!this.isValid32ByteHex(pubkey)) { throw new Error(`pubkey ${pubkey} is not valid`); } try { const bds = await this.httpCall( "GET", `list/${pubkey}`, void 0, () => this.authorizationHeader((evt) => { evt.tags.push(["t", "list"]); }), void 0, [] ); return bds; } catch (error) { throw new Error(`failed to list blobs: ${error}`); } } async delete(hash) { if (!this.isValid32ByteHex(hash)) { throw new Error(`${hash} is not a valid 32-byte hex string`); } try { await this.httpCall( "DELETE", hash, void 0, () => this.authorizationHeader((evt) => { evt.tags.push(["t", "delete"]); evt.tags.push(["x", hash]); }), void 0, null ); } catch (error) { throw new Error(`failed to delete ${hash}: ${error}`); } } };