nostr package: vastly simplify the API #412

Merged
sistemd merged 27 commits from nostr-package-use-methods-for-events into main 2023-03-27 09:09:48 +00:00
sistemd commented 2023-03-08 20:53:37 +00:00 (Migrated from github.com)

I've decided to simplify the API.

  • Instead of classes, use type aliases for types which are really only strings (e.g. event ID, event signature, public/private key, hex strings). I'm only going to validate these when they enter the library functions. In the context of application development, having strong types is better, but for the purpose of keeping the API as simple as possible I decided it's best for the library to expose as few interfaces as possible, and leave the strong typing to the application.
  • Don't separate the RawEvent and Event concepts. I had an important realization that the RawEvent and Event both carry the same data: Event represents a particular interpretation of that data. So instead of changing the fields of Event based on kind, the fields (i.e. the data) are always the same: those of RawEvent. Instead, depending on the Event's kind field, the event will have additional methods which allow the data to be interpreted in different ways. E.g. when kind === EventKind.SetMetadata, the event will have a method called getUserMetadata which parses the content as user metadata JSON. Similar for EventKind.DirectMessage, there will be a method getMessage which decrypts the message, etc. The TS type system is powerful enough to elegantly express this.
  • Instead of separating the SignedEvent and Event, there is now a generic type Unsigned<Event> which just represents the event with the sig, id, and pubkey fields optionally omitted. Similar to the point above, the goal of this design is to help with unifying the event data. There's a signEvent method which fills in the missing fields. This also fits perfectly with NIP-07.
  • Finally, I don't think that strong typing like this (i.e. "newtypes") are very idiomatic in the TS/JS ecosystem to begin with. I think that the ecosystem prefers simplicity.

Altogether I think this is way better than what I had before. I believe this is very close to what the final API will look like and hopefully there won't be any more big API refactors in the future, just implementing functionality from all remaining NIPs.

I've decided to simplify the API. - Instead of classes, use type aliases for types which are really only strings (e.g. event ID, event signature, public/private key, hex strings). I'm only going to validate these when they enter the library functions. In the context of application development, having strong types is better, but for the purpose of keeping the API as simple as possible I decided it's best for the library to expose as few interfaces as possible, and leave the strong typing to the application. - Don't separate the `RawEvent` and `Event` concepts. I had an important realization that the `RawEvent` and `Event` both carry the same data: `Event` represents a particular interpretation of that data. So instead of changing the fields of `Event` based on `kind`, the fields (i.e. the data) are always the same: those of `RawEvent`. Instead, depending on the `Event`'s `kind` field, the event will have additional _methods_ which allow the data to be interpreted in different ways. E.g. when `kind === EventKind.SetMetadata`, the event will have a method called `getUserMetadata` which parses the `content` as user metadata JSON. Similar for `EventKind.DirectMessage`, there will be a method `getMessage` which decrypts the message, etc. The TS type system is powerful enough to elegantly express this. - Instead of separating the `SignedEvent` and `Event`, there is now a generic type `Unsigned<Event>` which just represents the event with the `sig`, `id`, and `pubkey` fields optionally omitted. Similar to the point above, the goal of this design is to help with unifying the event data. There's a `signEvent` method which fills in the missing fields. This also fits perfectly with NIP-07. - Finally, I don't think that strong typing like this (i.e. "newtypes") are very idiomatic in the TS/JS ecosystem to begin with. I think that the ecosystem prefers simplicity. Altogether I think this is way better than what I had before. I believe this is very close to what the final API will look like and hopefully there won't be any more big API refactors in the future, just implementing functionality from all remaining NIPs.
v0l (Migrated from github.com) reviewed 2023-03-08 21:35:27 +00:00
v0l (Migrated from github.com) left a comment

I was happy enough with the strong types, but maybe it was a bit overkill

One thing that we should try to accomodate is allowing people to do unsupported NIP's dont want a lib that needs to be constantly updated

One place this is obviously a problem in its current form is the REQ filters, those have a bunch of other values which are not implemented in this lib

I was happy enough with the strong types, but maybe it was a bit overkill One thing that we should try to accomodate is allowing people to do unsupported NIP's dont want a lib that needs to be constantly updated One place this is obviously a problem in its current form is the REQ filters, those have a bunch of other values which are not implemented in this lib
sistemd commented 2023-03-17 14:23:05 +00:00 (Migrated from github.com)

was happy enough with the strong types, but maybe it was a bit overkill

This still has strong types! The only difference is that instead of having different fields on the types, the fields are always the same (those of RawEvent), while the methods change. (E.g. there's a getUserMetadata() method on a set metadata event, when kind == EventKind.SetMetadata, while that method doesn't exist on kind == EventKind.DirectMessage. The direct message has async getMessage() and getRecipient() methods instead. And everything is still strongly typed due to how type narrowing works.)

One thing that we should try to accomodate is allowing people to do unsupported NIP's dont want a lib that needs to be constantly updated

Noted.

One place this is obviously a problem in its current form is the REQ filters, those have a bunch of other values which are not implemented in this lib

Noted, I'm going to look for a way to improve that.

> was happy enough with the strong types, but maybe it was a bit overkill This still has strong types! The only difference is that instead of having different fields on the types, the fields are always the same (those of `RawEvent`), while the methods change. (E.g. there's a `getUserMetadata()` method on a set metadata event, when `kind == EventKind.SetMetadata`, while that method doesn't exist on `kind == EventKind.DirectMessage`. The direct message has `async getMessage()` and `getRecipient()` methods instead. And everything is still strongly typed due to how type narrowing works.) > One thing that we should try to accomodate is allowing people to do unsupported NIP's dont want a lib that needs to be constantly updated Noted. > One place this is obviously a problem in its current form is the REQ filters, those have a bunch of other values which are not implemented in this lib Noted, I'm going to look for a way to improve that.
cloudflare-pages[bot] commented 2023-03-17 14:34:32 +00:00 (Migrated from github.com)

Deploying with  Cloudflare Pages  Cloudflare Pages

Latest commit: 589243c
Status:️  Build in progress...

View logs

## Deploying with &nbsp;<a href="https://pages.dev"><img alt="Cloudflare Pages" src="https://user-images.githubusercontent.com/23264/106598434-9e719e00-654f-11eb-9e59-6167043cfa01.png" width="16"></a> &nbsp;Cloudflare Pages <table><tr><td><strong>Latest commit:</strong> </td><td> <code>589243c</code> </td></tr> <tr><td><strong>Status:</strong></td><td>⚡️&nbsp; Build in progress...</td></tr> </table> [View logs](https://dash.cloudflare.com/?to=/:account/pages/view/snort-social/5eb6edf4-bfcc-4096-86dd-e46b1dafffa8)
v0l (Migrated from github.com) approved these changes 2023-03-18 06:45:09 +00:00
Sign in to join this conversation.
No description provided.