agentstr 0.1.10__py3-none-any.whl → 0.1.12__py3-none-any.whl

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.
agentstr/nostr.py CHANGED
@@ -1,5 +1,11 @@
1
+ import json
1
2
  import logging
2
- from typing import Optional
3
+ import traceback
4
+ from datetime import timedelta
5
+ from pathlib import Path
6
+ from typing import Dict, List, Optional, Tuple
7
+
8
+ from agentstr.models import MerchantProduct, MerchantStall, NostrProfile
3
9
 
4
10
  try:
5
11
  import asyncio
@@ -10,11 +16,13 @@ except ImportError:
10
16
 
11
17
  try:
12
18
  from nostr_sdk import (
19
+ Alphabet,
13
20
  Client,
14
21
  Coordinate,
15
- Event,
16
22
  EventBuilder,
17
23
  EventId,
24
+ Events,
25
+ Filter,
18
26
  Keys,
19
27
  Kind,
20
28
  Metadata,
@@ -23,8 +31,11 @@ try:
23
31
  PublicKey,
24
32
  ShippingCost,
25
33
  ShippingMethod,
34
+ SingleLetterTag,
26
35
  StallData,
27
36
  Tag,
37
+ TagKind,
38
+ TagStandard,
28
39
  Timestamp,
29
40
  )
30
41
 
@@ -44,8 +55,6 @@ class NostrClient:
44
55
  """
45
56
 
46
57
  logger = logging.getLogger("NostrClient")
47
- ERROR: str = "ERROR"
48
- SUCCESS: str = "SUCCESS"
49
58
 
50
59
  def __init__(
51
60
  self,
@@ -74,6 +83,7 @@ class NostrClient:
74
83
  self.keys = Keys.parse(nsec)
75
84
  self.nostr_signer = NostrSigner.keys(self.keys)
76
85
  self.client = Client(self.nostr_signer)
86
+ self.connected = False
77
87
 
78
88
  def delete_event(self, event_id: EventId, reason: Optional[str] = None) -> EventId:
79
89
  """
@@ -98,7 +108,7 @@ class NostrClient:
98
108
  Publish generic Nostr event to the relay
99
109
 
100
110
  Returns:
101
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
111
+ EventId: event id published
102
112
 
103
113
  Raises:
104
114
  RuntimeError: if the product can't be published
@@ -113,7 +123,7 @@ class NostrClient:
113
123
  text: text to be published as kind 1 event
114
124
 
115
125
  Returns:
116
- EventId: EventId if successful or NostrClient.ERROR if unsuccesful
126
+ EventId: EventId if successful
117
127
 
118
128
  Raises:
119
129
  RuntimeError: if the product can't be published
@@ -121,7 +131,7 @@ class NostrClient:
121
131
  # Run the async publishing function synchronously
122
132
  return asyncio.run(self._async_publish_note(text))
123
133
 
124
- def publish_product(self, product: ProductData) -> EventId:
134
+ def publish_product(self, product: MerchantProduct) -> EventId:
125
135
  """
126
136
  Create or update a NIP-15 Marketplace product with event kind 30018
127
137
 
@@ -129,13 +139,16 @@ class NostrClient:
129
139
  product: product to be published
130
140
 
131
141
  Returns:
132
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
142
+ EventId: event id of the publication event
133
143
 
134
144
  Raises:
135
145
  RuntimeError: if the product can't be published
136
146
  """
137
147
  # Run the async publishing function synchronously
138
- return asyncio.run(self._async_publish_product(product))
148
+ try:
149
+ return asyncio.run(self._async_publish_product(product))
150
+ except Exception as e:
151
+ raise RuntimeError(f"Failed to publish product: {e}")
139
152
 
140
153
  def publish_profile(self, name: str, about: str, picture: str) -> EventId:
141
154
  """
@@ -147,7 +160,7 @@ class NostrClient:
147
160
  picture: url to a png file with a picture for the profile
148
161
 
149
162
  Returns:
150
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
163
+ EventId: event id if successful
151
164
 
152
165
  Raises:
153
166
  RuntimeError: if the profile can't be published
@@ -155,20 +168,166 @@ class NostrClient:
155
168
  # Run the async publishing function synchronously
156
169
  return asyncio.run(self._async_publish_profile(name, about, picture))
157
170
 
158
- def publish_stall(self, stall: StallData) -> EventId:
171
+ def publish_stall(self, stall: MerchantStall) -> EventId:
159
172
  """Publish a stall to nostr
160
173
 
161
174
  Args:
162
175
  stall: stall to be published
163
176
 
164
177
  Returns:
165
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
178
+ EventId: Id of the publication event
179
+
180
+ Raises:
181
+ RuntimeError: if the stall can't be published
166
182
  """
167
183
  try:
168
184
  return asyncio.run(self._async_publish_stall(stall))
169
185
  except Exception as e:
170
- self.logger.error(f"Failed to publish stall: {e}")
171
- return NostrClient.ERROR
186
+ raise RuntimeError(f"Failed to publish stall: {e}")
187
+
188
+ def retrieve_products_from_seller(self, seller: PublicKey) -> List[MerchantProduct]:
189
+ """
190
+ Retrieve all products from a given seller.
191
+
192
+ Args:
193
+ seller: PublicKey of the seller
194
+
195
+ Returns:
196
+ List[MerchantProduct]: list of products from the seller
197
+ """
198
+ products = []
199
+ try:
200
+ events = asyncio.run(self._async_retrieve_products_from_seller(seller))
201
+ events_list = events.to_vec()
202
+ for event in events_list:
203
+ content = json.loads(event.content())
204
+ product_data = ProductData(
205
+ id=content.get("id"),
206
+ stall_id=content.get("stall_id"),
207
+ name=content.get("name"),
208
+ description=content.get("description"),
209
+ images=content.get("images", []),
210
+ currency=content.get("currency"),
211
+ price=content.get("price"),
212
+ quantity=content.get("quantity"),
213
+ specs=content.get("specs", {}),
214
+ shipping=content.get("shipping", []),
215
+ categories=content.get("categories", []),
216
+ )
217
+ products.append(MerchantProduct.from_product_data(product_data))
218
+ return products
219
+ except Exception as e:
220
+ raise RuntimeError(f"Failed to retrieve products: {e}")
221
+
222
+ def retrieve_profile(self, public_key: PublicKey) -> NostrProfile:
223
+ """
224
+ Retrieve a Nostr profile from the relay.
225
+
226
+ Args:
227
+ public_key: bech32 encoded public key of the profile to retrieve
228
+
229
+ Returns:
230
+ NostrProfile: profile of the author
231
+
232
+ Raises:
233
+ RuntimeError: if the profile can't be retrieved
234
+ """
235
+ try:
236
+ return asyncio.run(self._async_retrieve_profile(public_key))
237
+ except Exception as e:
238
+ raise RuntimeError(f"Failed to retrieve profile: {e}")
239
+
240
+ def retrieve_sellers(self) -> set[NostrProfile]:
241
+ """
242
+ Retrieve all sellers from the relay.
243
+ Sellers are npubs who have published a stall.
244
+ Return set may be empty if metadata can't be retrieved for any author.
245
+
246
+ Returns:
247
+ set[NostrProfile]: set of seller profiles (skips authors with missing metadata)
248
+ """
249
+
250
+ sellers: set[NostrProfile] = set()
251
+
252
+ # First we retrieve all stalls from the relay
253
+
254
+ try:
255
+ events = asyncio.run(self._async_retrieve_all_stalls())
256
+ except Exception as e:
257
+ raise RuntimeError(f"Failed to retrieve stalls: {e}")
258
+
259
+ # Now we search for unique npubs from the list of stalls
260
+
261
+ events_list = events.to_vec()
262
+ authors: Dict[PublicKey, NostrProfile] = {}
263
+
264
+ for event in events_list:
265
+ if event.kind() == Kind(30017):
266
+ # Is this event the first time we see this author?
267
+ if event.author() not in authors:
268
+ # First time we see this author. Let's add the profile to the dictionary
269
+ try:
270
+ profile = asyncio.run(
271
+ self._async_retrieve_profile(event.author())
272
+ )
273
+ # Add the profile to the dictionary, associating it with the author's PublicKey
274
+ authors[event.author()] = profile
275
+ except Exception as e:
276
+ # print(
277
+ # f"Failed to retrieve profile for {event.author().to_bech32()}: {e}"
278
+ # )
279
+ continue
280
+
281
+ # Now we add locations from the event locations to the profile
282
+
283
+ for tag in event.tags().to_vec():
284
+ standardized_tag = tag.as_standardized()
285
+ if isinstance(standardized_tag, TagStandard.GEOHASH):
286
+ string_repr = str(standardized_tag)
287
+ extracted_geohash = string_repr.split("=")[1].rstrip(
288
+ ")"
289
+ ) # Splitting and removing the closing parenthesis
290
+ # print(
291
+ # f"Adding location {extracted_geohash} to profile {authors[event.author()].get_name()}"
292
+ # )
293
+ profile = authors[event.author()]
294
+ profile.add_location(extracted_geohash)
295
+ authors[event.author()] = profile
296
+ # print(
297
+ # f"New locations for {authors[event.author()].get_name()}: {authors[event.author()].get_locations()}"
298
+ # )
299
+ # else:
300
+ # print(f"Unknown tag: {standardized_tag}")
301
+
302
+ # once we're done iterating over the events, we return the set of profiles
303
+ return set(authors.values())
304
+
305
+ def retrieve_stalls_from_seller(self, seller: PublicKey) -> List[StallData]:
306
+ """
307
+ Retrieve all stalls from a given seller.
308
+
309
+ Args:
310
+ seller: PublicKey of the seller
311
+
312
+ Returns:
313
+ List[StallData]: list of stalls from the seller
314
+ """
315
+ stalls = []
316
+ try:
317
+ events = asyncio.run(self._async_retrieve_stalls_from_seller(seller))
318
+ events_list = events.to_vec()
319
+ for event in events_list:
320
+ try:
321
+ # Parse the content field instead of the whole event
322
+ content = event.content()
323
+ stall = StallData.from_json(content)
324
+ stalls.append(stall)
325
+ except Exception as e:
326
+ self.logger.warning(f"Failed to parse stall data: {e}")
327
+ continue
328
+ return stalls
329
+ except Exception as e:
330
+ raise RuntimeError(f"Failed to retrieve stalls: {e}")
172
331
 
173
332
  @classmethod
174
333
  def set_logging_level(cls, logging_level: int) -> None:
@@ -186,23 +345,26 @@ class NostrClient:
186
345
  # --*-- async functions for internal use only. Developers should use synchronous functions above
187
346
  # ----------------------------------------------------------------------------------------------
188
347
 
189
- async def _async_connect(self) -> str:
348
+ async def _async_connect(self) -> None:
190
349
  """Asynchronous function to add relay to the NostrClient instance and connect to it.
350
+ TBD: refactor to not return anything if successful and raise an exception if not
191
351
 
192
- Returns:
193
- str: NostrClient.SUCCESS or NostrClient.ERROR
352
+ Raises:
353
+ RuntimeError: if the relay can't be connected to
194
354
  """
195
- try:
196
- await self.client.add_relay(self.relay)
197
- NostrClient.logger.info(f"Relay {self.relay} succesfully added.")
198
- await self.client.connect()
199
- NostrClient.logger.info("Connected to relay.")
200
- return NostrClient.SUCCESS
201
- except Exception as e:
202
- NostrClient.logger.error(
203
- f"Unable to connect to relay {self.relay}. Exception: {e}."
204
- )
205
- return NostrClient.ERROR
355
+
356
+ if not self.connected:
357
+ try:
358
+ await self.client.add_relay(self.relay)
359
+ NostrClient.logger.info(f"Relay {self.relay} succesfully added.")
360
+ await self.client.connect()
361
+ await asyncio.sleep(2) # give time for slower connections
362
+ NostrClient.logger.info("Connected to relay.")
363
+ self.connected = True
364
+ except Exception as e:
365
+ raise RuntimeError(
366
+ f"Unable to connect to relay {self.relay}. Exception: {e}."
367
+ )
206
368
 
207
369
  async def _async_publish_event(self, event_builder: EventBuilder) -> EventId:
208
370
  """
@@ -214,27 +376,35 @@ class NostrClient:
214
376
  Raises:
215
377
  RuntimeError: if the event can't be published
216
378
  """
217
- connected = await self._async_connect()
379
+ try:
380
+ await self._async_connect()
218
381
 
219
- if connected == NostrClient.ERROR:
220
- raise RuntimeError("Unable to connect to the relay")
382
+ # Add debug logging
383
+ NostrClient.logger.debug(f"Attempting to publish event: {event_builder}")
384
+ NostrClient.logger.debug(
385
+ f"Using keys: {self.keys.public_key().to_bech32()}"
386
+ )
221
387
 
222
- try:
388
+ # Wait for connection and try to publish
223
389
  output = await self.client.send_event_builder(event_builder)
224
- if len(output.success) > 0:
225
- NostrClient.logger.info(
226
- f"Event published with event id: {output.id.to_bech32()}"
390
+
391
+ # More detailed error handling
392
+ if not output:
393
+ raise RuntimeError("No output received from send_event_builder")
394
+ if len(output.success) == 0:
395
+ raise RuntimeError(
396
+ f"Event rejected by relay. Reason: {output.message if hasattr(output, 'message') else 'unknown'}"
227
397
  )
228
- return output.id
229
- else:
230
- raise RuntimeError("Unable to publish event")
231
- except Exception as e:
232
- NostrClient.logger.error(
233
- f"NostrClient instance not properly initialized. Exception: {e}."
234
- )
235
- raise RuntimeError(
236
- f"NostrClient instance not properly initialized. Exception: {e}."
398
+
399
+ NostrClient.logger.info(
400
+ f"Event published with event id: {output.id.to_bech32()}"
237
401
  )
402
+ return output.id
403
+
404
+ except Exception as e:
405
+ NostrClient.logger.error(f"Failed to publish event: {str(e)}")
406
+ NostrClient.logger.debug("Event details:", exc_info=True)
407
+ raise RuntimeError(f"Unable to publish event: {str(e)}")
238
408
 
239
409
  async def _async_publish_note(self, text: str) -> EventId:
240
410
  """
@@ -244,7 +414,7 @@ class NostrClient:
244
414
  text: text to be published as kind 1 event
245
415
 
246
416
  Returns:
247
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
417
+ EventId: event id if successful
248
418
 
249
419
  Raises:
250
420
  RuntimeError: if the event can't be published
@@ -252,7 +422,7 @@ class NostrClient:
252
422
  event_builder = EventBuilder.text_note(text)
253
423
  return await self._async_publish_event(event_builder)
254
424
 
255
- async def _async_publish_product(self, product: ProductData) -> EventId:
425
+ async def _async_publish_product(self, product: MerchantProduct) -> EventId:
256
426
  """
257
427
  Asynchronous function to create or update a NIP-15 Marketplace product with event kind 30018
258
428
 
@@ -260,7 +430,7 @@ class NostrClient:
260
430
  product: product to publish
261
431
 
262
432
  Returns:
263
- EventId: event id if successful or NostrClient.ERROR if unsuccesfull
433
+ EventId: event id if successful
264
434
 
265
435
  Raises:
266
436
  RuntimeError: if the product can't be published
@@ -271,7 +441,7 @@ class NostrClient:
271
441
 
272
442
  # EventBuilder.product_data() has a bug with tag handling.
273
443
  # We use the function to create the content field and discard the eventbuilder
274
- bad_event_builder = EventBuilder.product_data(product)
444
+ bad_event_builder = EventBuilder.product_data(product.to_product_data())
275
445
 
276
446
  # create an event from bad_event_builder to extract the content - not broadcasted
277
447
  bad_event = await self.client.sign_event_builder(bad_event_builder)
@@ -296,7 +466,7 @@ class NostrClient:
296
466
  picture: url to a png file with a picture for the profile
297
467
 
298
468
  Returns:
299
- EventId: event id if successful or NostrClient.ERROR if unsuccesful
469
+ EventId: event id if successful
300
470
 
301
471
  Raises:
302
472
  RuntimeError: if the profile can't be published
@@ -308,7 +478,7 @@ class NostrClient:
308
478
  event_builder = EventBuilder.metadata(metadata_content)
309
479
  return await self._async_publish_event(event_builder)
310
480
 
311
- async def _async_publish_stall(self, stall: StallData) -> EventId:
481
+ async def _async_publish_stall(self, stall: MerchantStall) -> EventId:
312
482
  """
313
483
  Asynchronous function to create or update a NIP-15 Marketplace stall with event kind 30017
314
484
 
@@ -316,12 +486,178 @@ class NostrClient:
316
486
  stall: stall to be published
317
487
 
318
488
  Returns:
319
- EventId: event id if successful or NostrClient.ERROR if unsuccesfull
489
+ EventId: Id of the publication event
320
490
 
321
491
  Raises:
322
492
  RuntimeError: if the profile can't be published
323
493
  """
324
494
 
325
- self.logger.info(f"Stall: {stall}")
326
- event_builder = EventBuilder.stall_data(stall)
495
+ # good_event_builder = EventBuilder(Kind(30018), content).tags(
496
+ # [Tag.identifier(product.id), Tag.coordinate(coordinate_tag)]
497
+ # )
498
+
499
+ self.logger.info(f" Merchant Stall: {stall}")
500
+ event_builder = EventBuilder.stall_data(stall.to_stall_data()).tags(
501
+ [
502
+ Tag.custom(
503
+ TagKind.SINGLE_LETTER(SingleLetterTag.lowercase(Alphabet.G)),
504
+ [stall.geohash],
505
+ ),
506
+ ]
507
+ )
327
508
  return await self._async_publish_event(event_builder)
509
+
510
+ async def _async_retrieve_all_stalls(self) -> Events:
511
+ """
512
+ Asynchronous function to retreive all stalls from a relay
513
+ This function is used internally to find Merchants.
514
+
515
+ Returns:
516
+ Events: events containing all stalls.
517
+
518
+ Raises:
519
+ RuntimeError: if the stalls can't be retrieved
520
+ """
521
+ try:
522
+ await self._async_connect()
523
+ except Exception as e:
524
+ raise RuntimeError("Unable to connect to the relay")
525
+
526
+ try:
527
+ filter = Filter().kind(Kind(30017))
528
+ events = await self.client.fetch_events_from(
529
+ urls=[self.relay], filter=filter, timeout=timedelta(seconds=2)
530
+ )
531
+ return events
532
+ except Exception as e:
533
+ raise RuntimeError(f"Unable to retrieve stalls: {e}")
534
+
535
+ async def _async_retrieve_products_from_seller(self, seller: PublicKey) -> Events:
536
+ """
537
+ Asynchronous function to retrieve the products for a given author
538
+
539
+ Args:
540
+ seller: PublicKey of the seller to retrieve the products for
541
+
542
+ Returns:
543
+ Events: list of events containing the products of the seller
544
+
545
+ Raises:
546
+ RuntimeError: if the products can't be retrieved
547
+ """
548
+ try:
549
+ await self._async_connect()
550
+ except Exception as e:
551
+ raise RuntimeError("Unable to connect to the relay")
552
+
553
+ try:
554
+ # print(f"Retrieving products from seller: {seller}")
555
+ filter = Filter().kind(Kind(30018)).authors([seller])
556
+ events = await self.client.fetch_events_from(
557
+ urls=[self.relay], filter=filter, timeout=timedelta(seconds=2)
558
+ )
559
+ return events
560
+ except Exception as e:
561
+ raise RuntimeError(f"Unable to retrieve stalls: {e}")
562
+
563
+ async def _async_retrieve_profile(self, author: PublicKey) -> NostrProfile:
564
+ """
565
+ Asynchronous function to retrieve the profile for a given author
566
+
567
+ Args:
568
+ author: PublicKey of the author to retrieve the profile for
569
+
570
+ Returns:
571
+ NostrProfile: profile of the author
572
+
573
+ Raises:
574
+ RuntimeError: if the profile can't be retrieved
575
+ """
576
+ try:
577
+ await self._async_connect()
578
+ except Exception as e:
579
+ raise RuntimeError("Unable to connect to the relay")
580
+
581
+ try:
582
+ metadata = await self.client.fetch_metadata(
583
+ public_key=author, timeout=timedelta(seconds=2)
584
+ )
585
+ return NostrProfile.from_metadata(metadata, author)
586
+ except Exception as e:
587
+ raise RuntimeError(f"Unable to retrieve metadata: {e}")
588
+
589
+ async def _async_retrieve_stalls_from_seller(self, seller: PublicKey) -> Events:
590
+ """
591
+ Asynchronous function to retrieve the stall for a given author
592
+
593
+ Args:
594
+ seller: PublicKey of the seller to retrieve the stall for
595
+
596
+ Returns:
597
+ Events: list of events containing the stalls of the seller
598
+
599
+ Raises:
600
+ RuntimeError: if the stall can't be retrieved
601
+ """
602
+ try:
603
+ await self._async_connect()
604
+ except Exception as e:
605
+ raise RuntimeError("Unable to connect to the relay")
606
+
607
+ try:
608
+ filter = Filter().kind(Kind(30017)).authors([seller])
609
+ events = await self.client.fetch_events_from(
610
+ urls=[self.relay], filter=filter, timeout=timedelta(seconds=2)
611
+ )
612
+ return events
613
+ except Exception as e:
614
+ raise RuntimeError(f"Unable to retrieve stalls: {e}")
615
+
616
+
617
+ def generate_and_save_keys(env_var: str, env_path: Path) -> Keys:
618
+ """Generate new nostr keys and save the private key to .env file.
619
+
620
+ Args:
621
+ env_var: Name of the environment variable to store the key
622
+ env_path: Path to the .env file. If None, looks for .env in current directory
623
+
624
+ Returns:
625
+ The generated Keys object
626
+ """
627
+ # Generate new keys
628
+ keys = Keys.generate()
629
+ nsec = keys.secret_key().to_bech32()
630
+
631
+ # Determine .env path
632
+ if env_path is None:
633
+ env_path = Path.cwd() / ".env"
634
+
635
+ # Read existing .env content
636
+ env_content = ""
637
+ if env_path.exists():
638
+ with open(env_path, "r") as f:
639
+ env_content = f.read()
640
+
641
+ # Check if the env var already exists
642
+ lines = env_content.splitlines()
643
+ new_lines = []
644
+ var_found = False
645
+
646
+ for line in lines:
647
+ if line.startswith(f"{env_var}="):
648
+ new_lines.append(f"{env_var}={nsec}")
649
+ var_found = True
650
+ else:
651
+ new_lines.append(line)
652
+
653
+ # If var wasn't found, add it
654
+ if not var_found:
655
+ new_lines.append(f"{env_var}={nsec}")
656
+
657
+ # Write back to .env
658
+ with open(env_path, "w") as f:
659
+ f.write("\n".join(new_lines))
660
+ if new_lines: # Add final newline if there's content
661
+ f.write("\n")
662
+
663
+ return keys
agentstr/nostr.pyi ADDED
@@ -0,0 +1,82 @@
1
+ from logging import Logger
2
+ from pathlib import Path
3
+ from typing import ClassVar, List, Optional
4
+
5
+ from nostr_sdk import ( # type: ignore
6
+ Client,
7
+ Event,
8
+ EventBuilder,
9
+ EventId,
10
+ Events,
11
+ Keys,
12
+ Kind,
13
+ Metadata,
14
+ NostrSigner,
15
+ ProductData,
16
+ PublicKey,
17
+ ShippingCost,
18
+ ShippingMethod,
19
+ StallData,
20
+ Tag,
21
+ Timestamp,
22
+ )
23
+
24
+ from agentstr.models import MerchantProduct, MerchantStall, NostrProfile
25
+
26
+ # Re-export all needed types
27
+ __all__ = [
28
+ "Event",
29
+ "EventBuilder",
30
+ "Events",
31
+ "EventId",
32
+ "Keys",
33
+ "Kind",
34
+ "Metadata",
35
+ "ProductData",
36
+ "PublicKey",
37
+ "ShippingCost",
38
+ "ShippingMethod",
39
+ "StallData",
40
+ "Timestamp",
41
+ ]
42
+
43
+ class NostrClient:
44
+ logger: ClassVar[Logger]
45
+ relay: str
46
+ keys: Keys
47
+ nostr_signer: NostrSigner
48
+ client: Client
49
+
50
+ def __init__(self, relay: str, nsec: str) -> None: ...
51
+ def delete_event(
52
+ self, event_id: EventId, reason: Optional[str] = None
53
+ ) -> EventId: ...
54
+ def publish_event(self, event_builder: EventBuilder) -> EventId: ...
55
+ def publish_note(self, text: str) -> EventId: ...
56
+ def publish_product(self, product: MerchantProduct) -> EventId: ...
57
+ def publish_profile(self, name: str, about: str, picture: str) -> EventId: ...
58
+ def publish_stall(self, stall: MerchantStall) -> EventId: ...
59
+ def retrieve_products_from_seller(
60
+ self, seller: PublicKey
61
+ ) -> List[MerchantProduct]: ...
62
+ def retrieve_profile(self, public_key: PublicKey) -> NostrProfile: ...
63
+ def retrieve_stalls_from_seller(self, seller: PublicKey) -> List[StallData]: ...
64
+ def retrieve_sellers(self) -> set[NostrProfile]: ...
65
+ @classmethod
66
+ def set_logging_level(cls, logging_level: int) -> None: ...
67
+ async def _async_connect(self) -> None: ...
68
+ async def _async_publish_event(self, event_builder: EventBuilder) -> EventId: ...
69
+ async def _async_publish_note(self, text: str) -> EventId: ...
70
+ async def _async_publish_product(self, product: MerchantProduct) -> EventId: ...
71
+ async def _async_publish_profile(
72
+ self, name: str, about: str, picture: str
73
+ ) -> EventId: ...
74
+ async def _async_publish_stall(self, stall: MerchantStall) -> EventId: ...
75
+ async def _async_retrieve_all_stalls(self) -> Events: ...
76
+ async def _async_retrieve_products_from_seller(
77
+ self, seller: PublicKey
78
+ ) -> Events: ...
79
+ async def _async_retrieve_profile(self, author: PublicKey) -> NostrProfile: ...
80
+ async def _async_retrieve_stalls_from_seller(self, seller: PublicKey) -> Events: ...
81
+
82
+ def generate_and_save_keys(env_var: str, env_path: Optional[Path] = None) -> Keys: ...
agentstr/py.typed ADDED
File without changes