# Blossom

low level

# Example

final downloadResult = await ndk.blossom.getBlob(
  sha256:
      "b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f553",
  serverUrls: ["https://cdn.hzrd149.com"],
);

print(
  "file of type: ${downloadResult.mimeType}, size: ${downloadResult.data.length}",
);

# When to use

For a simpler, more generic API, check out

Files
../files/

If no servers are specified the default user server list (kind 10063) is used for upload and delete.

The auth events get automatically signed and are valid for:

const Duration BLOSSOM_AUTH_EXPIRATION = Duration(minutes: 5);

# methods - Blossom

# uploadBlob

upload a blob, if serverMediaOptimisation is set to true the /media endpoint is used.

EventSigner _getSigner(EventSigner? customSigner) {
  if (customSigner != null) return customSigner;

  if (_accounts.canSign) {
    return _accounts.getLoggedAccount()!.signer;
  }

  // Create a temporary signer if no account is logged in
  final keyPair = Bip340.generatePrivateKey();
  return Bip340EventSigner(
    privateKey: keyPair.privateKey,
    publicKey: keyPair.publicKey,
  );

# getBlob

Download the blob and use fallback if the blob is not found or the server is offline.

serverUrls ??= await _userServerList
    .getUserServerList(pubkeys: [signer.getPublicKey()]);

if (serverUrls == null) {
  throw Exception("User has no server list");
}

final stream = _blossomImpl.uploadBlob(
  dataStreamFactory: () => Stream.value(data),

# checkBlob

    completedUploads: const [],
    phase: UploadPhase.hashing,
    progressPhase: hashProgress.progress,
  );

  if (hashProgress.isComplete && hashProgress.hash != null) {
    fileHash = hashProgress.hash;
  }
}

if (fileHash == null) {
  throw Exception('Failed to compute file hash');

# getBlobStream

Similar to getBlob, it streams the data, which is helpful for video files.

/// Throws an [Exception] if no SHA256 hash is detected in the URL
Future<List<BlobUploadResult>> mirrorToServers({
  required Uri blossomUrl,
  required List<String> targetServerUrls,
  EventSigner? customSigner,
}) async {
  final signer = _getSigner(customSigner);

  // Extract sha256 from the URL
  final sha256Match = sha256Regex.firstMatch(blossomUrl.toString());

# listBlobs

Future<BlobResponse> getBlob({
  required String sha256,
  bool useAuth = false,
  List<String>? serverUrls,
  String? pubkeyToFetchUserServerList,
  EventSigner? customSigner,
}) async {
  Nip01Event? myAuthorization;
  Nip01Event? signedAuthorization;

  if (useAuth) {

# deleteBlob

  );
}

/// Downloads a blob directly to a file path (without loading into memory)
/// For native platforms (Windows, macOS, Linux, Android, iOS): uses actual file system paths
/// For web: triggers browser download dialog to save the file
///
/// if [serverUrls] is null, the userServerList is fetched from nostr. \

# directDownload

if (pubkeyToFetchUserServerList == null) {
  throw Exception(
      "pubkeyToFetchUserServerList is null and serverUrls is null");
}

# report

  }

  if (serverUrls == null) {
    throw Exception("User has no server list");
  }

  return _blossomImpl.downloadBlobToFile(
    sha256: sha256,
    outputPath: outputPath,
    authorization: signedAuthorization,
    serverUrls: serverUrls,
  );
}

/// checks if the blob exists on the server without downloading, useful to check before streaming a video via url \

# methods - BlossomUserServerList

To get and set the user server list e.g. on settings page, you can use BlossomUserServerList

# getUserServerList

/// Get user server list \
/// returns list of server urls \
/// returns null if the user has no server list
Future<List<String>?> getUserServerList({
  required List<String> pubkeys,
}) async {

# publishUserServerList

/// Publish user server list \
/// order of [serverUrlsOrdered] is important, the first server is the most trusted server
Future<List<RelayBroadcastResponse>> publishUserServerList({
  required List<String> serverUrlsOrdered,
}) async {