Blossom

low level

CLI — ndk blossom upload|download|delete|list|mirror|check|servers

Example

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

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);

Server authentication (BUD-01)

Some servers only serve a private blob, or only accept an upload, from a client that signed a kind 24242 event. The auth parameter says which identity a server may learn, as on requests and broadcasts:

final response = await ndk.blossom.getBlob(
  sha256: hash,
  serverUrls: ['https://cdn.example.com'],
  auth: AuthPolicy.allow(account),
);
policy what goes out what a server learns
AuthPolicy.never() no authorization, ever nothing. A server that refuses without one simply does not serve the request
AuthPolicy.allow(a) nothing at first, then the signed event once a server answered 401 who you are, but only after that server asked
AuthPolicy.require(a) the signed event on the first request who you are, as soon as you ask it for anything

The account does not have to be one NDK knows. allow costs a refused HTTP round trip, and for an upload a body sent twice, so prefer require when the server is known to ask. If require names an account that cannot sign, nothing is sent and the call throws BlossomAuthUnavailableException.

Without auth, reads stay anonymous and everything else authorises as the logged-in account, or as a throwaway key when none is. This default is expected to change.

useAuth and customSigner were removed in favour of auth:

removed replace with
useAuth: true auth: AuthPolicy.require(account), with the logged-in account, or the one holding the customSigner passed alongside
customSigner: s alone the same with the account holding s, except on a download or a check, where it never signed: drop it
useAuth: false auth: const AuthPolicy.never() on listBlobs, nothing elsewhere

methods - Blossom

uploadBlob

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

Future<List<BlobUploadResult>> uploadBlob({
  required Uint8List data,
  List<String>? serverUrls,
  String? contentType,
  UploadStrategy strategy = UploadStrategy.mirrorAfterSuccess,
  bool serverMediaOptimisation = false,
  AuthPolicy? auth,
  String? pubkeyToFetchUserServerList,
  String? precomputedSha256,
})

uploadBlobFromFile

Reads the file in chunks, so a large file is never held whole in memory.

Stream<BlobUploadProgress> uploadBlobFromFile({
  required String filePath,
  List<String>? serverUrls,
  String? contentType,
  UploadStrategy strategy = UploadStrategy.mirrorAfterSuccess,
  bool serverMediaOptimisation = false,
  AuthPolicy? auth,
  String? pubkeyToFetchUserServerList,
  String? precomputedSha256,
})

getBlob

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

Future<BlobResponse> getBlob({
  required String sha256,
  AuthPolicy? auth,
  List<String>? serverUrls,
  String? pubkeyToFetchUserServerList,
})

checkBlob

Future<String> checkBlob({
  required String sha256,
  AuthPolicy? auth,
  List<String>? serverUrls,
  String? pubkeyToFetchUserServerList,
})

getBlobStream

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

Future<Stream<BlobResponse>> getBlobStream({
  required String sha256,
  AuthPolicy? auth,
  List<String>? serverUrls,
  String? pubkeyToFetchUserServerList,
  int chunkSize = 1024 * 1024,
})

listBlobs

Future<List<BlobDescriptor>> listBlobs({
  required String pubkey,
  List<String>? serverUrls,
  AuthPolicy? auth,
  DateTime? since,
  DateTime? until,
})

deleteBlob

Future<List<BlobDeleteResult>> deleteBlob({
  required String sha256,
  List<String>? serverUrls,
  AuthPolicy? auth,
  String? pubkeyToFetchUserServerList,
})

mirrorToServers

Copies a blob that already lives somewhere else onto other servers, without downloading it first.

Future<List<BlobUploadResult>> mirrorToServers({
  required Uri blossomUrl,
  required List<String> targetServerUrls,
  AuthPolicy? auth,
})

directDownload

Future<BlobResponse> directDownload({required Uri url})

report

The report is a signed event in the request body, so never() signs it with a throwaway key rather than sending nothing.

Future<int> report({
  required String sha256,
  required String eventId,
  required String reportType,
  required String reportMsg,
  required String serverUrl,
  AuthPolicy? auth,
})

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 {