Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

book: add (filters & client messages) JavaScript examples #613

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions book/snippets/nostr/js/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
const keys = require("./src/keys");
const eventJson = require("./src/event/json");
const eventBuilder = require("./src/event/builder");
const filters = require("./src/messages/filters");
const clientMessages = require("./src/messages/client");
const relayMessages = require("./src/messages/relay");
const nip01 = require("./src/nip01");
const nip05 = require("./src/nip05");
Expand All @@ -20,6 +22,8 @@ async function main() {
eventJson.eventJson();
eventBuilder.eventBuilder();

filters.run();
await clientMessages.run();
await relayMessages.run();

nip01.run();
Expand Down
63 changes: 63 additions & 0 deletions book/snippets/nostr/js/src/messages/client.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
const { ClientMessage, EventBuilder, Filter, Keys, loadWasmAsync } = require('@rust-nostr/nostr-sdk');

async function run() {
await loadWasmAsync();

const keys = Keys.generate();
const event = EventBuilder.textNote("TestTextNoTe", []).signWithKeys(keys);

console.log()
console.log("Client Messages:");

// ANCHOR: event-message
// Create Event client message
console.log(" Event Client Message:");
let clientMessage = ClientMessage.event(event);
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: event-message

console.log();
// ANCHOR: req-message
// Create Request client message
console.log(" Request Client Message:");
let f = new Filter().id(event.id);
clientMessage = ClientMessage.req("ABC123", [f]);
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: req-message

console.log();
// ANCHOR: close-message
// Create Close client message
console.log(" Close Client Message:");
clientMessage = ClientMessage.close("ABC123");
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: close-message

console.log();
// ANCHOR: parse-message
// Parse Messages from JSON
console.log(" Parse Client Messages:");
clientMessage = ClientMessage.fromJson('["REQ","ABC123",{"#p":["421a4dd67be773903f805bcb7975b4d3377893e0e09d7563b8972ee41031f551"]}]');
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: parse-message

console.log();
// ANCHOR: auth-message
// Create Auth client message (NIP42)
console.log(" Auth Client Message:");
clientMessage = ClientMessage.auth(event);
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: auth-message

console.log();
// ANCHOR: count-message
// Create Count client message (NIP45)
console.log(" Count Client Message:");
f = new Filter().pubkey(keys.publicKey);
clientMessage = ClientMessage.count("ABC123", [f]);
console.log(` - JSON: ${clientMessage.asJson()}`);
// ANCHOR_END: count-message

}

module.exports.run = run;
157 changes: 157 additions & 0 deletions book/snippets/nostr/js/src/messages/filters.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
const { Filter, Keys, Kind, EventBuilder, Timestamp, Tag, loadWasmSync } = require('@rust-nostr/nostr-sdk');

async function run() {
loadWasmSync();

// Generate keys and Events
const keys = Keys.generate();
const keys2 = Keys.generate();

const kind0 = new Kind(0);
const kind1 = new Kind(1);
const kind4 = new Kind(4);

const event = EventBuilder.textNote("Hello World!", []).signWithKeys(keys);
const event2 = new EventBuilder(kind0, "Goodbye World!", [Tag.identifier("Identification D Tag")]).signWithKeys(keys2);

console.log();
console.log("Creating Filters:");

// ANCHOR: create-filter-id
// Filter for specific ID
console.log(" Filter for specific Event ID:");
let f = new Filter().id(event.id);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-id

console.log();
// ANCHOR: create-filter-author
// Filter for specific Author
console.log(" Filter for specific Author:");
f = new Filter().author(keys.publicKey);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-author

console.log();
// ANCHOR: create-filter-kind-pk
// Filter by PK and Kinds
console.log(" Filter with PK and Kinds:");
f = new Filter()
.pubkey(keys.publicKey)
.kind(kind1);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-kind-pk

console.log();
// ANCHOR: create-filter-search
// Filter for specific string
console.log(" Filter for specific search string:");
f = new Filter().search("Ask Nostr Anything");
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-search

console.log();
// ANCHOR: create-filter-timeframe
console.log(" Filter for events from specific public key within given timeframe:");
// Create timestamps
const date = new Date(2009, 1, 3, 0, 0);
const timestamp = Math.floor(date.getTime() / 1000);
const sinceTs = Timestamp.fromSecs(timestamp);
const untilTs = Timestamp.now();

// Filter with timeframe
f = new Filter()
.pubkey(keys.publicKey)
.since(sinceTs)
.until(untilTs);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-timeframe

console.log();
// ANCHOR: create-filter-limit
// Filter for specific PK with limit
console.log(" Filter for specific Author, limited to 10 Events:");
f = new Filter()
.author(keys.publicKey)
.limit(10);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-limit

console.log();
// ANCHOR: create-filter-hashtag
// Filter for Hashtags
console.log(" Filter for a list of Hashtags:");
f = new Filter().hashtags(["#Bitcoin", "#AskNostr", "#Meme"]);
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-hashtag

console.log();
// ANCHOR: create-filter-reference
// Filter for Reference
console.log(" Filter for a Reference:");
f = new Filter().reference("This is my NIP-12 Reference");
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-reference

console.log();
// ANCHOR: create-filter-identifier
// Filter for Identifier
console.log(" Filter for a Identifier:");
f = new Filter().identifier("This is my NIP-12 Identifier");
console.log(` ${f.asJson()}`);
// ANCHOR_END: create-filter-identifier

console.log();
console.log("Modifying Filters:");
// ANCHOR: modify-filter
// Modifying Filters (adding/removing)
f = new Filter()
.pubkeys([keys.publicKey, keys2.publicKey])
.ids([event.id, event2.id])
.kinds([kind0, kind1])
.author(keys.publicKey);

// Add an additional Kind to existing filter
f = f.kinds([kind4]);

// Print Results
console.log(" Before:");
console.log(` ${f.asJson()}`);
console.log();

// Remove PKs, Kinds and IDs from filter
f = f.removePubkeys([keys2.publicKey]);
console.log(" After (remove pubkeys):");
console.log(` ${f.asJson()}`);
kind_rem0 = new Kind(0);
kind_rem4 = new Kind(4);
f = f.removeKinds([kind_rem0, kind_rem4]);
console.log(" After (remove kinds):");
console.log(` ${f.asJson()}`);

f = f.removeIds([event2.id]);
console.log(" After (remove IDs):");
console.log(` ${f.asJson()}`);
// ANCHOR_END: modify-filter

console.log();
console.log("Other Filter Operations:");
// ANCHOR: other-parse
// Parse filter
console.log(" Parse Filter from Json:");
const fJson = f.asJson();
f = Filter.fromJson(fJson);
console.log(` ${f.asJson()}`);
// ANCHOR_END: other-parse

console.log();
// ANCHOR: other-match
console.log(" Logical tests:");
kind_match = new Kind(1);
f = new Filter().author(keys.publicKey).kind(kind_match);
console.log(` Event match for filter: ${f.matchEvent(event)}`);
console.log(` Event2 match for filter: ${f.matchEvent(event2)}`);
// ANCHOR_END: other-match
}

module.exports.run = run;
49 changes: 44 additions & 5 deletions book/src/nostr/05_01-client-message.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,31 @@ When presented with a client message object as either a JSON or an instance of t
<div slot="title">JavaScript</div>
<section>

TODO
The `ClientMessage` class easily handles the construction of the 3 main message types `EVENT`, `REQ`, and `CLOSE`.
In the examples below we can utilize the relevant class methods `event()`, `req()` and `close()`, respectively, to create the client message objects.

Once we have the `ClientMessage` objects we can use the `asJson()` method to present their content.


```javascript,ignore
{{#include ../../snippets/nostr/js/src/messages/client.js:event-message}}
```

Note that when constructing a `REQ` we want to pass through a `Filter` object which will allow the relay to return data meeting a given set of criteria.
Please jump to the [Filter](05_01_01-filter.md) section for more details on how to construct these objects.

```javascript,ignore
{{#include ../../snippets/nostr/js/src/messages/client.js:req-message}}
```

```javascript,ignore
{{#include ../../snippets/nostr/js/src/messages/client.js:close-message}}
```

When presented with a client message object as either a JSON using the `fromJson()` method.

```javascript,ignore
{{#include ../../snippets/nostr/js/src/messages/client.js:parse-message}}

</section>

Expand Down Expand Up @@ -112,7 +136,21 @@ Note that `COUNT` is effectively a specific type of `REQ` message therefore it u
<div slot="title">JavaScript</div>
<section>

TODO
As an extension of the client messaging section of the protocol [NIP-42](https://github.com/nostr-protocol/nips/blob/master/42.md) and [NIP-45](https://github.com/nostr-protocol/nips/blob/master/45.md) introduce two new messaging types `AUTH` and `COUNT`.

The `AUTH` type is designed to facilitate a method by which clients can authenticate with a given relay.
Whereas the `COUNT` type offers a method for clients can request simple counts of events from relays.
These are constructed in much the same way as the earlier message examples, by using the `ClientMessage` class in conjunction with the relevant methods `auth()` and `count()`.

```python,ignore
{{#include ../../snippets/nostr/python/src/messages/client.py:auth-message}}
```

Note that `COUNT` is effectively a specific type of `REQ` message therefore it utilizes the `Filter` object in constructing the criteria which should be used by the relay to return the count value.

```python,ignore
{{#include ../../snippets/nostr/python/src/messages/client.py:count-message}}
```

</section>

Expand All @@ -132,7 +170,7 @@ TODO

</custom-tabs>

## Error Messages
## Negentropy Messages

<custom-tabs category="lang">

Expand All @@ -147,7 +185,8 @@ TODO
<section>

Finally, the `ClientMessageEnum` class also opens up three additional message types `NEG_OPEN()`, `NEG_CLOSE()` and `NEG_MSG()`.
These do not form part of the standard protocol specification but do have specific uses when it comes to providing methods by which error messaging can be handled by clients.
These do not form part of the standard protocol specification but instead form part of an additional protocol [Negentropy](https://github.com/hoytech/negentropy) for handling set-reconciliation.

To construct these we need to first create them as instance of the `ClientMessageEnum` class and then pass these into a `ClientMessage` object using the `from_enum()` method.

```python,ignore
Expand All @@ -167,7 +206,7 @@ To construct these we need to first create them as instance of the `ClientMessag
<div slot="title">JavaScript</div>
<section>

TODO
Not currently available in the Javascript Bindings.

</section>

Expand Down
Loading
Loading