nostr 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. checksums.yaml +4 -4
  2. data/.editorconfig +1 -1
  3. data/.rubocop.yml +26 -0
  4. data/.tool-versions +2 -1
  5. data/CHANGELOG.md +65 -1
  6. data/README.md +96 -183
  7. data/Steepfile +2 -0
  8. data/docs/.gitignore +4 -0
  9. data/docs/.vitepress/config.mjs +112 -0
  10. data/docs/README.md +44 -0
  11. data/docs/api-examples.md +49 -0
  12. data/docs/bun.lockb +0 -0
  13. data/docs/common-use-cases/bech32-encoding-and-decoding-(NIP-19).md +190 -0
  14. data/docs/core/client.md +108 -0
  15. data/docs/core/keys.md +136 -0
  16. data/docs/core/user.md +43 -0
  17. data/docs/events/contact-list.md +29 -0
  18. data/docs/events/encrypted-direct-message.md +28 -0
  19. data/docs/events/recommend-server.md +32 -0
  20. data/docs/events/set-metadata.md +20 -0
  21. data/docs/events/text-note.md +15 -0
  22. data/docs/events.md +11 -0
  23. data/docs/getting-started/installation.md +21 -0
  24. data/docs/getting-started/overview.md +170 -0
  25. data/docs/implemented-nips.md +9 -0
  26. data/docs/index.md +44 -0
  27. data/docs/markdown-examples.md +85 -0
  28. data/docs/package.json +12 -0
  29. data/docs/relays/connecting-to-a-relay.md +21 -0
  30. data/docs/relays/publishing-events.md +29 -0
  31. data/docs/relays/receiving-events.md +6 -0
  32. data/docs/subscriptions/creating-a-subscription.md +49 -0
  33. data/docs/subscriptions/deleting-a-subscription.md +10 -0
  34. data/docs/subscriptions/filtering-subscription-events.md +115 -0
  35. data/docs/subscriptions/updating-a-subscription.md +4 -0
  36. data/lib/nostr/bech32.rb +203 -0
  37. data/lib/nostr/client.rb +2 -1
  38. data/lib/nostr/crypto.rb +147 -0
  39. data/lib/nostr/errors/error.rb +7 -0
  40. data/lib/nostr/errors/invalid_hrp_error.rb +21 -0
  41. data/lib/nostr/errors/invalid_key_format_error.rb +20 -0
  42. data/lib/nostr/errors/invalid_key_length_error.rb +20 -0
  43. data/lib/nostr/errors/invalid_key_type_error.rb +18 -0
  44. data/lib/nostr/errors/key_validation_error.rb +6 -0
  45. data/lib/nostr/errors.rb +8 -0
  46. data/lib/nostr/event.rb +157 -12
  47. data/lib/nostr/event_kind.rb +8 -0
  48. data/lib/nostr/events/encrypted_direct_message.rb +54 -0
  49. data/lib/nostr/filter.rb +4 -4
  50. data/lib/nostr/key.rb +100 -0
  51. data/lib/nostr/key_pair.rb +30 -6
  52. data/lib/nostr/keygen.rb +43 -4
  53. data/lib/nostr/private_key.rb +36 -0
  54. data/lib/nostr/public_key.rb +36 -0
  55. data/lib/nostr/relay_message_type.rb +18 -0
  56. data/lib/nostr/subscription.rb +2 -2
  57. data/lib/nostr/user.rb +17 -36
  58. data/lib/nostr/version.rb +1 -1
  59. data/lib/nostr.rb +8 -1
  60. data/nostr.gemspec +9 -9
  61. data/sig/nostr/bech32.rbs +14 -0
  62. data/sig/nostr/client.rbs +5 -5
  63. data/sig/nostr/crypto.rbs +16 -0
  64. data/sig/nostr/errors/error.rbs +4 -0
  65. data/sig/nostr/errors/invalid_hrb_error.rbs +6 -0
  66. data/sig/nostr/errors/invalid_key_format_error.rbs +5 -0
  67. data/sig/nostr/errors/invalid_key_length_error.rbs +5 -0
  68. data/sig/nostr/errors/invalid_key_type_error.rbs +5 -0
  69. data/sig/nostr/errors/key_validation_error.rbs +4 -0
  70. data/sig/nostr/event.rbs +24 -9
  71. data/sig/nostr/event_kind.rbs +1 -0
  72. data/sig/nostr/events/encrypted_direct_message.rbs +12 -0
  73. data/sig/nostr/filter.rbs +3 -12
  74. data/sig/nostr/key.rbs +16 -0
  75. data/sig/nostr/key_pair.rbs +7 -3
  76. data/sig/nostr/keygen.rbs +5 -2
  77. data/sig/nostr/private_key.rbs +4 -0
  78. data/sig/nostr/public_key.rbs +4 -0
  79. data/sig/nostr/relay_message_type.rbs +8 -0
  80. data/sig/nostr/user.rbs +4 -10
  81. data/sig/vendor/bech32/nostr/entity.rbs +41 -0
  82. data/sig/vendor/bech32/nostr/nip19.rbs +20 -0
  83. data/sig/vendor/bech32/segwit_addr.rbs +21 -0
  84. data/sig/vendor/bech32.rbs +25 -0
  85. data/sig/vendor/event_emitter.rbs +10 -3
  86. data/sig/vendor/event_machine/channel.rbs +1 -1
  87. data/sig/vendor/faye/websocket/api.rbs +45 -0
  88. data/sig/vendor/faye/websocket/client.rbs +43 -0
  89. data/sig/vendor/faye/websocket.rbs +30 -0
  90. metadata +83 -23
  91. data/lib/nostr/event_fragment.rb +0 -111
  92. data/sig/nostr/event_fragment.rbs +0 -12
data/sig/nostr/event.rbs CHANGED
@@ -1,24 +1,39 @@
1
1
  module Nostr
2
- class Event < EventFragment
3
- attr_reader id: String
4
- attr_reader sig: String
2
+ class Event
3
+ attr_reader pubkey: PublicKey
4
+ attr_reader created_at: Integer
5
+ attr_reader kind: Integer
6
+ attr_reader tags: Array[Array[String]]
7
+ attr_reader content: String
8
+ attr_accessor id: String?|nil
9
+ attr_accessor sig: String?|nil
5
10
 
6
- def initialize: (id: String, sig: String,
7
- created_at: Integer,
11
+ def initialize: (
12
+ pubkey: PublicKey,
8
13
  kind: Integer,
9
- tags: Array[String],
10
14
  content: String,
15
+ ?created_at: Integer,
16
+ ?tags: Array[Array[String]],
17
+ ?id: String|nil,
18
+ ?sig: String|nil
11
19
  ) -> void
12
20
 
21
+ def serialize: -> [Integer, String, Integer, Integer, Array[Array[String]], String]
22
+
13
23
  def to_h: -> {
14
- id: String,
24
+ id: String?|nil,
15
25
  pubkey: String,
16
26
  created_at: Integer,
17
27
  kind: Integer,
18
- tags: Array[String],
28
+ tags: Array[Array[String]],
19
29
  content: String,
20
- sig: String
30
+ sig: String?|nil
21
31
  }
22
32
  def ==: (Event other) -> bool
33
+
34
+ def sign:(PrivateKey) -> Event
35
+
36
+ def add_event_reference: (String) -> Array[Array[String]]
37
+ def add_pubkey_reference: (PublicKey) -> Array[Array[String]]
23
38
  end
24
39
  end
@@ -4,5 +4,6 @@ module Nostr
4
4
  TEXT_NOTE: Integer
5
5
  RECOMMEND_SERVER: Integer
6
6
  CONTACT_LIST: Integer
7
+ ENCRYPTED_DIRECT_MESSAGE: Integer
7
8
  end
8
9
  end
@@ -0,0 +1,12 @@
1
+ module Nostr
2
+ module Events
3
+ class EncryptedDirectMessage < Event
4
+ def initialize: (
5
+ plain_text: String,
6
+ sender_private_key: PrivateKey,
7
+ recipient_public_key: PublicKey,
8
+ ?previous_direct_message: String|nil
9
+ ) -> void
10
+ end
11
+ end
12
+ end
data/sig/nostr/filter.rbs CHANGED
@@ -3,23 +3,14 @@ module Nostr
3
3
  attr_reader ids: Array[String]
4
4
  attr_reader authors: Array[String]
5
5
  attr_reader kinds: Array[Integer]
6
- attr_reader e: String
7
- attr_reader p: String
6
+ attr_reader e: Array[String]
7
+ attr_reader p: Array[String]
8
8
  attr_reader since: Integer
9
9
  attr_reader until: Integer
10
10
  attr_reader limit: Integer
11
11
 
12
12
  def initialize: (**untyped) -> void
13
- def to_h: -> {
14
- ids: Array[String],
15
- authors: Array[String],
16
- kinds: Array[Integer],
17
- e: String,
18
- p: String,
19
- since: Integer,
20
- until: Integer,
21
- limit: Integer
22
- }
13
+ def to_h: -> Hash[::Symbol, (::Array[::String] | ::Array[::Integer] | ::Integer)]
23
14
  def ==: (Filter other) -> bool
24
15
  end
25
16
  end
data/sig/nostr/key.rbs ADDED
@@ -0,0 +1,16 @@
1
+ module Nostr
2
+ class Key < String
3
+ FORMAT: Regexp
4
+ LENGTH: int
5
+
6
+ def self.from_bech32: (String) -> Key
7
+ def self.hrp: -> String
8
+
9
+ def initialize: (String) -> void
10
+ def to_bech32: -> String
11
+
12
+ private
13
+
14
+ def validate_hex_value: (String) -> nil
15
+ end
16
+ end
@@ -1,9 +1,13 @@
1
1
  # Classes
2
2
  module Nostr
3
3
  class KeyPair
4
- attr_reader private_key: String
5
- attr_reader public_key: String
4
+ attr_reader private_key: PrivateKey
5
+ attr_reader public_key: PublicKey
6
6
 
7
- def initialize: (private_key: String, public_key: String) -> void
7
+ def initialize: (private_key: PrivateKey, public_key: PublicKey) -> void
8
+
9
+ private
10
+
11
+ def validate_keys: (PrivateKey, PublicKey) -> void
8
12
  end
9
13
  end
data/sig/nostr/keygen.rbs CHANGED
@@ -3,11 +3,14 @@ module Nostr
3
3
  class Keygen
4
4
  def initialize: -> void
5
5
  def generate_key_pair: -> KeyPair
6
- def generate_private_key: -> String
7
- def extract_public_key: (String private_key) -> String
6
+ def generate_private_key: -> PrivateKey
7
+ def extract_public_key: (PrivateKey private_key) -> PublicKey
8
+ def get_key_pair_from_private_key: (PrivateKey private_key) -> KeyPair
8
9
 
9
10
  private
10
11
 
11
12
  attr_reader group: untyped
13
+
14
+ def validate_private_key: (PrivateKey private_key) -> void
12
15
  end
13
16
  end
@@ -0,0 +1,4 @@
1
+ module Nostr
2
+ class PrivateKey < Key
3
+ end
4
+ end
@@ -0,0 +1,4 @@
1
+ module Nostr
2
+ class PublicKey < Key
3
+ end
4
+ end
@@ -0,0 +1,8 @@
1
+ module Nostr
2
+ module RelayMessageType
3
+ EOSE: String
4
+ EVENT: String
5
+ NOTICE: String
6
+ OK: String
7
+ end
8
+ end
data/sig/nostr/user.rbs CHANGED
@@ -5,16 +5,10 @@ module Nostr
5
5
 
6
6
  def initialize: (?keypair: KeyPair | nil, ?keygen: Keygen) -> void
7
7
  def create_event: (
8
- {
9
- id: String,
10
- pubkey: String,
11
- created_at: Integer,
12
- kind: Integer,
13
- tags: Array[String],
14
- content: String,
15
- created_at: Integer,
16
- sig: String
17
- }
8
+ kind: Integer,
9
+ content: String,
10
+ ?created_at: Integer,
11
+ ?tags: Array[Array[String]],
18
12
  ) -> Event
19
13
 
20
14
  private
@@ -0,0 +1,41 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Bech32
3
+ module Nostr
4
+ class BareEntity
5
+ attr_reader hrp: untyped
6
+ attr_reader data: untyped
7
+
8
+ def initialize: (untyped hrp, untyped data) -> void
9
+ def encode: -> untyped
10
+ end
11
+
12
+ class TLVEntry
13
+ attr_reader type: (Float | Integer | String)?
14
+ attr_reader label: String?
15
+ attr_reader value: (Float | Integer | String)?
16
+
17
+ def initialize: ((Float | Integer | String)? `type`, (Float | Integer | String)? value, ?String? label) -> void
18
+ def to_payload: -> String
19
+ def to_s: -> String
20
+
21
+ private
22
+
23
+ def hex_string?: ((Float | Integer | String)? str) -> bool
24
+ end
25
+
26
+ class TLVEntity
27
+ TYPE_SPECIAL: Integer
28
+ TYPE_RELAY: Integer
29
+ TYPE_AUTHOR: Integer
30
+ TYPE_KIND: Integer
31
+ TYPES: [Integer, Integer, Integer, Integer]
32
+
33
+ attr_reader hrp: untyped
34
+ attr_reader entries: Array[TLVEntry]
35
+
36
+ def initialize: (untyped hrp, Array[TLVEntry] entries) -> void
37
+ def self.parse: (untyped hrp, untyped data) -> TLVEntity
38
+ def encode: -> untyped
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,20 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Bech32
3
+ module Nostr
4
+ module NIP19
5
+ HRP_PUBKEY: String
6
+ HRP_PRIVATE_KEY: String
7
+ HRP_NOTE_ID: String
8
+ HRP_PROFILE: String
9
+ HRP_EVENT: String
10
+ HRP_RELAY: String
11
+ HRP_EVENT_COORDINATE: String
12
+ BARE_PREFIXES: [String, String, String]
13
+ TLV_PREFIXES: [String, String, String, String]
14
+ ALL_PREFIXES: Array[String]
15
+
16
+ def decode: (untyped string) -> untyped
17
+ def self.decode: (untyped string) -> untyped
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,21 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Bech32
3
+ class SegwitAddr
4
+ HRP_MAINNET: String
5
+ HRP_TESTNET: String
6
+ HRP_REGTEST: String
7
+
8
+ attr_accessor hrp: String
9
+ attr_accessor ver: (Float | Integer | String)?
10
+ attr_accessor prog: Array[(Float | Integer | String)?]
11
+
12
+ def initialize: (?nil addr) -> void
13
+ def to_script_pubkey: -> ((Float | Integer | String)?)
14
+ def script_pubkey=: (untyped script_pubkey) -> (Array[(Float | Integer | String)?])
15
+ def addr: -> untyped
16
+
17
+ private
18
+
19
+ def parse_addr: (untyped addr) -> nil
20
+ end
21
+ end
@@ -0,0 +1,25 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Bech32
3
+ SEPARATOR: String
4
+ BECH32M_CONST: Integer
5
+
6
+ def encode: (untyped hrp, untyped data, untyped spec) -> untyped
7
+ def self.encode: (untyped hrp, untyped data, untyped spec) -> untyped
8
+ def decode: (untyped bech, ?Integer max_length) -> [untyped, untyped, Integer]?
9
+ def self.decode: (untyped bech, ?Integer max_length) -> [untyped, untyped, Integer]?
10
+ def create_checksum: (untyped hrp, untyped data, untyped spec) -> Array[Integer]
11
+ def self.create_checksum: (untyped hrp, untyped data, untyped spec) -> Array[Integer]
12
+ def verify_checksum: (untyped hrp, untyped data) -> Integer?
13
+ def self.verify_checksum: (untyped hrp, untyped data) -> Integer?
14
+ def expand_hrp: (untyped hrp) -> untyped
15
+ def self.expand_hrp: (untyped hrp) -> untyped
16
+ def convert_bits: (untyped data, untyped from, untyped to, ?true padding) -> Array[Integer]?
17
+ def self.convert_bits: (untyped data, untyped from, untyped to, ?true padding) -> Array[Integer]?
18
+ def polymod: (untyped values) -> Integer
19
+ def self.polymod: (untyped values) -> Integer
20
+
21
+ module Encoding
22
+ BECH32: Integer
23
+ BECH32M: Integer
24
+ end
25
+ end
@@ -1,9 +1,16 @@
1
1
  # Added only to satisfy the Steep requirements. Not 100% reliable.
2
2
  module EventEmitter
3
- def add_listener: (untyped `type`, ?{once: true} params) -> Integer
3
+ interface _Event
4
+ def data: -> String
5
+ def message: -> String
6
+ def code: -> Integer
7
+ def reason: -> String
8
+ end
9
+
10
+ def add_listener: (Symbol event_name) { (_Event event) -> void } -> void
4
11
  alias on add_listener
5
12
 
6
13
  def remove_listener: (untyped id_or_type) -> Array[untyped]?
7
- def emit: (untyped `type`, *untyped data) -> Array[untyped]
8
- def once: (untyped `type`) -> Integer
14
+ def emit: (Symbol `type`, *untyped data) -> Array[untyped]
15
+ def once: (Symbol `type`) -> Integer
9
16
  end
@@ -6,7 +6,7 @@ module EventMachine
6
6
 
7
7
  def initialize: -> void
8
8
  def num_subscribers: -> Integer
9
- def subscribe: (*untyped a) ?{ -> untyped } -> Integer
9
+ def subscribe: (*untyped a) ?{ (untyped) -> untyped } -> Integer
10
10
  def unsubscribe: (untyped name) -> untyped
11
11
  def push: (*untyped items) -> untyped
12
12
  alias << push
@@ -0,0 +1,45 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Faye
3
+ class WebSocket
4
+ module API
5
+ CONNECTING: Integer
6
+ OPEN: Integer
7
+ CLOSING: Integer
8
+ CLOSED: Integer
9
+ CLOSE_TIMEOUT: Integer
10
+
11
+ @driver: untyped
12
+ @ping: nil
13
+ @ping_id: Integer
14
+ @stream: nil
15
+ @proxy: nil
16
+ @ping_timer: nil
17
+ @close_timer: nil
18
+ @close_params: [String, Integer]?
19
+ @onerror: nil
20
+ @onclose: nil
21
+ @onmessage: nil
22
+ @onopen: nil
23
+
24
+ attr_reader url: untyped
25
+ attr_reader ready_state: Integer
26
+ attr_reader buffered_amount: Integer
27
+
28
+ def initialize: (?Hash[untyped, untyped] options) -> void
29
+ def write: (untyped data) -> untyped
30
+ def send: (untyped message) -> false
31
+ def ping: (?String message) -> false
32
+ def close: (?nil code, ?nil reason) -> untyped
33
+ def protocol: -> String
34
+
35
+ private
36
+
37
+ def open: -> nil
38
+ def receive_message: (untyped data) -> nil
39
+ def emit_error: (untyped message) -> nil
40
+ def begin_close: (String reason, Integer code, ?Hash[untyped, untyped] options) -> nil
41
+ def finalize_close: -> nil
42
+ def parse: (untyped data) -> untyped
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Faye
3
+ class WebSocket
4
+ class Client
5
+ DEFAULT_PORTS: Hash[String, Integer]
6
+ SECURE_PROTOCOLS: [String, String]
7
+
8
+ include EventEmitter
9
+ include API
10
+
11
+ @url: untyped
12
+ @endpoint: untyped
13
+ @origin_tls: Hash[untyped, untyped]
14
+ @socket_tls: Hash[untyped, untyped]
15
+ @driver: bot
16
+ @proxy: nil
17
+ @ssl_verifier: untyped
18
+ @stream: untyped
19
+
20
+ def initialize: (untyped url, ?Array[String] protocols, ?Hash[untyped, untyped] options) -> void
21
+
22
+ private
23
+
24
+ def configure_proxy: (Hash[untyped, untyped] proxy) -> nil
25
+ def start_tls: (untyped uri, Hash[untyped, untyped] options) -> nil
26
+ def on_connect: (untyped stream) -> untyped
27
+ def on_network_error: (nil error) -> untyped
28
+ def ssl_verify_peer: (untyped cert) -> untyped
29
+ def ssl_handshake_completed: -> untyped
30
+
31
+ module Connection
32
+ attr_accessor parent: bot
33
+
34
+ def connection_completed: -> untyped
35
+ def ssl_verify_peer: (untyped cert) -> untyped
36
+ def ssl_handshake_completed: -> untyped
37
+ def receive_data: (untyped data) -> untyped
38
+ def unbind: (?nil error) -> untyped
39
+ def write: (untyped data) -> nil
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,30 @@
1
+ # Added only to satisfy the Steep requirements. Not 100% reliable.
2
+ module Faye
3
+ class WebSocket
4
+ ADAPTERS: Hash[String, :Goliath | :Rainbows | :Thin]
5
+
6
+ @url: String
7
+ @driver_started: false
8
+ @stream: Stream
9
+ @driver: bot
10
+
11
+ def self.determine_url: (untyped env, ?[String, String] schemes) -> String
12
+ def self.ensure_reactor_running: -> nil
13
+ def self.load_adapter: (untyped backend) -> bool?
14
+ def self.secure_request?: (untyped env) -> bool
15
+ def self.websocket?: (untyped env) -> untyped
16
+
17
+ attr_reader env: untyped
18
+
19
+ def initialize: (untyped env, ?nil protocols, ?Hash[untyped, untyped] options) -> void
20
+ def start_driver: -> nil
21
+ def rack_response: -> [Integer, Hash[untyped, untyped], Array[untyped]]
22
+
23
+ class Stream
24
+ @socket_object: bot
25
+
26
+ def fail: -> untyped
27
+ def receive: (untyped data) -> untyped
28
+ end
29
+ end
30
+ end