Skip to content
/ nostr Public

Develop Scalable Dart/Flutter Nostr clients quickly and easily

License

Notifications You must be signed in to change notification settings

anasfik/nostr

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

208 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

dart_nostr

A Dart/Flutter library for building Nostr clients. Built with simplicity in mind, dart_nostr handles the complexity of the Nostr protocol so you can focus on creating great user experiences.

What is Nostr?

Nostr (Notes and Other Stuff Transmitted by Relays) is a simple, open protocol for global, decentralized, and censorship-resistant social media. This library gives you everything you need to build Nostr clients in Dart or Flutter.

Features

  • Complete key management (generation, derivation, encoding/decoding)
  • Event creation, signing, and verification
  • WebSocket relay connections with automatic reconnection
  • Event subscriptions with stream and future-based APIs
  • Support for 40+ NIPs out of the box
  • NIP-05 verification
  • NIP-19 entity encoding (nevent, nprofile, etc.)
  • Proof of work support (NIP-13)
  • And much more

Supported NIPs

Currently implements: 01, 02, 03, 04, 05, 06, 08, 09, 10, 11, 13, 14, 15, 18, 19, 21, 23, 24, 25, 27, 28, 30, 31, 32, 36, 38, 39, 40, 45, 47, 48, 50, 51, 52, 53, 56, 57, 58, 72, 75, 78, 84, 89, 94, 98, 99.

Note: NIP-42 and NIP-44 are planned for future releases. Platform-specific NIPs like NIP-07 (web browser extensions) aren't directly applicable to this library.

Getting Started

Add dart_nostr to your pubspec.yaml:

dependencies:
  dart_nostr: ^9.2.4

Or use the command line:

flutter pub add dart_nostr  # Flutter
dart pub add dart_nostr     # Dart

Quick Example

Here's a simple example to get you started:

import 'package:dart_nostr/dart_nostr.dart';

void main() async {
  // Initialize
  final nostr = Nostr.instance;

  // Generate keys
  final keyPair = nostr.keysService.generateKeyPair();
  print('Public key: ${keyPair.public}');

  // Connect to relays
  await nostr.relaysService.init(
    relaysUrl: ['wss://relay.damus.io', 'wss://nos.lol'],
  );

  // Create and publish an event
  final event = NostrEvent.fromPartialData(
    kind: 1,
    content: 'Hello Nostr!',
    keyPairs: keyPair,
  );

  nostr.relaysService.sendEventToRelays(event);

  // Subscribe to events
  final stream = nostr.relaysService.startEventsSubscription(
    request: NostrRequest(filters: [
      NostrFilter(kinds: [1], limit: 10),
    ]),
  );

  stream.stream.listen((event) {
    print('Received: ${event.content}');
  });
}

Usage Guide

Working with Instances

You can use dart_nostr in two ways depending on your needs:

// Singleton - shared state across your app
final nostr = Nostr.instance;
// Multiple instances - isolated state
final nostr1 = Nostr();
final nostr2 = Nostr(); // Completely independent

Most apps work well with the singleton. Use multiple instances if you need to connect to different relay sets simultaneously or want to isolate different parts of your app.

Keys

Generate New Keys

final keyPair = nostr.keysService.generateKeyPair();
print(keyPair.public);  // Your public key
print(keyPair.private); // Keep this secret!

Work with Existing Keys

// If you already have a private key
final keyPair = nostr.keysService
    .generateKeyPairFromExistingPrivateKey(myPrivateKey);

Sign and Verify Messages

final signature = nostr.keysService.sign(
  privateKey: keyPair.private,
  message: "GM",
);

final isValid = nostr.keysService.verify(
  publicKey: keyPair.public,
  message: "GM",
  signature: signature,
);

Bech32 Encoding (nsec/npub)

// Encode to human-friendly formats
final nsec = nostr.keysService.encodePrivateKeyToNsec(privateKey);
final npub = nostr.keysService.encodePublicKeyToNpub(publicKey);

// Decode back
final privateKey = nostr.keysService.decodeNsecKeyToPrivateKey(nsec);
final publicKey = nostr.keysService.decodeNpubKeyToPublicKey(npub);

Events

Create and Sign Events

The easiest way:

final event = NostrEvent.fromPartialData(
  kind: 1,  // Text note
  content: 'Hello Nostr!',
  keyPairs: keyPair,
  tags: [
    ['p', 'pubkey_to_mention'],
    ['e', 'event_id_to_reference'],
  ],
);

// Event is already signed and has an ID
print(event.id);
print(event.sig);

Relays

Connect to Relays

await nostr.relaysService.init(
  relaysUrl: [
    'wss://relay.damus.io',
    'wss://nos.lol',
    'wss://relay.nostr.band',
  ],
);

Subscribe to Events

Real-time streaming:

final stream = nostr.relaysService.startEventsSubscription(
  request: NostrRequest(filters: [
    NostrFilter(
      kinds: [1],
      authors: [keyPair.public],
      limit: 50,
    ),
  ]),
);

stream.stream.listen((event) {
  print(event.content);
});

// Don't forget to close when done
stream.close();

One-time fetch (waits for EOSE):

final events = await nostr.relaysService.startEventsSubscriptionAsync(
  request: NostrRequest(filters: [
    NostrFilter(kinds: [1], limit: 20),
  ]),
);

print('Got ${events.length} events');

Publish Events

nostr.relaysService.sendEventToRelays(event);

// Or wait for confirmation
final ok = await nostr.relaysService.sendEventToRelaysAsync(event);
print(ok.message);

More Features

NIP-05 Verification

final verified = await nostr.utilsService.verifyNip05(
  internetIdentifier: "user@domain.com",
  pubKey: publicKey,
);

NIP-19 Entities

// Create shareable event links
final nevent = nostr.utilsService.encodeNevent(
  eventId: event.id,
  pubkey: keyPair.public,
  userRelays: ['wss://relay.damus.io'],
);

// Create profile links
final nprofile = nostr.utilsService.encodeNProfile(
  pubkey: keyPair.public,
  userRelays: ['wss://relay.damus.io'],
);

Event Counting

final countEvent = NostrCountEvent.fromPartialData(
  eventsFilter: NostrFilter(kinds: [1], authors: [keyPair.public]),
);

final count = await nostr.relaysService.sendCountEventToRelaysAsync(countEvent);
print('User has ${count.count} text notes');

Relay Information

final info = await nostr.relaysService.relayInformationsDocumentNip11(
  relayUrl: "wss://relay.damus.io",
);

print(info?.name);
print(info?.supportedNips);

Examples

The example directory contains runnable examples showing:

  • Basic key management
  • Creating and publishing events
  • Subscribing to event streams
  • Working with different event kinds
  • NIP-05 verification flows
  • And more real-world scenarios

API Documentation

Full API documentation is available at pub.dev.

Contributing

Found a bug? Have a feature idea? Contributions are welcome!

  1. Check existing issues or create a new one
  2. Fork the repository
  3. Create your feature branch
  4. Make your changes
  5. Submit a pull request

Please ensure your code follows the existing style and includes tests where appropriate.

License

MIT License - see LICENSE for details.

Links

Questions?

About

Develop Scalable Dart/Flutter Nostr clients quickly and easily

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Contributors 5

Languages