applesauce-relay 0.0.0-next-20250404075518 → 0.0.0-next-20250404092229
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.
- package/dist/group.js +12 -5
- package/dist/relay.d.ts +3 -1
- package/dist/relay.js +14 -10
- package/package.json +2 -2
package/dist/group.js
CHANGED
|
@@ -1,13 +1,18 @@
|
|
|
1
|
-
import { combineLatest, filter, map, merge } from "rxjs";
|
|
2
|
-
import { onlyEvents } from "./operators/only-events.js";
|
|
1
|
+
import { catchError, combineLatest, EMPTY, filter, map, merge, of } from "rxjs";
|
|
3
2
|
import { nanoid } from "nanoid";
|
|
3
|
+
import { onlyEvents } from "./operators/only-events.js";
|
|
4
4
|
export class RelayGroup {
|
|
5
5
|
relays;
|
|
6
6
|
constructor(relays) {
|
|
7
7
|
this.relays = relays;
|
|
8
8
|
}
|
|
9
|
-
req(filters, id = nanoid()) {
|
|
10
|
-
const requests = this.relays.reduce((acc,
|
|
9
|
+
req(filters, id = nanoid(8)) {
|
|
10
|
+
const requests = this.relays.reduce((acc, relay) => ({
|
|
11
|
+
...acc,
|
|
12
|
+
[relay.url]: relay.req(filters, id).pipe(
|
|
13
|
+
// Ignore connection errors
|
|
14
|
+
catchError(() => EMPTY)),
|
|
15
|
+
}), {});
|
|
11
16
|
// Create stream of events only
|
|
12
17
|
const events = merge(...Object.values(requests)).pipe(onlyEvents());
|
|
13
18
|
// Create stream that emits EOSE when all relays have sent EOSE
|
|
@@ -18,6 +23,8 @@ export class RelayGroup {
|
|
|
18
23
|
return merge(events, eose);
|
|
19
24
|
}
|
|
20
25
|
event(event) {
|
|
21
|
-
return merge(...this.relays.map((
|
|
26
|
+
return merge(...this.relays.map((relay) => relay.event(event).pipe(
|
|
27
|
+
// Catch error and return as PublishResponse
|
|
28
|
+
catchError((err) => of({ ok: false, from: relay.url, message: err?.message || "Unknown error" })))));
|
|
22
29
|
}
|
|
23
30
|
}
|
package/dist/relay.d.ts
CHANGED
|
@@ -30,9 +30,11 @@ export declare class Relay implements IRelay {
|
|
|
30
30
|
constructor(url: string, opts?: RelayOptions);
|
|
31
31
|
protected waitForAuth<T extends unknown = unknown>(requireAuth: BehaviorSubject<boolean>, observable: Observable<T>): Observable<T>;
|
|
32
32
|
multiplex<T>(open: () => any, close: () => any, filter: (message: any) => boolean): Observable<T>;
|
|
33
|
+
/** Send a message to the relay */
|
|
33
34
|
next(message: any): void;
|
|
35
|
+
/** Create a REQ observable that emits events | "EOSE" or errors */
|
|
34
36
|
req(filters: Filter | Filter[], id?: string): Observable<SubscriptionResponse>;
|
|
35
|
-
/** send an Event message */
|
|
37
|
+
/** send an Event message and always return an observable of PublishResponse that completes or errors */
|
|
36
38
|
event(event: NostrEvent, verb?: "EVENT" | "AUTH"): Observable<PublishResponse>;
|
|
37
39
|
/** send and AUTH message */
|
|
38
40
|
auth(event: NostrEvent): Observable<{
|
package/dist/relay.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BehaviorSubject, combineLatest, filter, ignoreElements, map, merge, NEVER, of, scan, share, switchMap, take, takeWhile, tap, timeout, } from "rxjs";
|
|
1
|
+
import { BehaviorSubject, combineLatest, defer, filter, ignoreElements, map, merge, NEVER, of, scan, share, switchMap, take, takeWhile, tap, timeout, } from "rxjs";
|
|
2
2
|
import { webSocket } from "rxjs/webSocket";
|
|
3
3
|
import { nanoid } from "nanoid";
|
|
4
4
|
import { logger } from "applesauce-core";
|
|
@@ -97,7 +97,7 @@ export class Relay {
|
|
|
97
97
|
share());
|
|
98
98
|
}
|
|
99
99
|
waitForAuth(
|
|
100
|
-
// require BehaviorSubject so it always has a value
|
|
100
|
+
// NOTE: require BehaviorSubject so it always has a value
|
|
101
101
|
requireAuth, observable) {
|
|
102
102
|
return combineLatest([requireAuth, this.authenticated$]).pipe(
|
|
103
103
|
// wait for auth not required or authenticated
|
|
@@ -110,9 +110,11 @@ export class Relay {
|
|
|
110
110
|
multiplex(open, close, filter) {
|
|
111
111
|
return this.socket.multiplex(open, close, filter);
|
|
112
112
|
}
|
|
113
|
+
/** Send a message to the relay */
|
|
113
114
|
next(message) {
|
|
114
115
|
this.socket.next(message);
|
|
115
116
|
}
|
|
117
|
+
/** Create a REQ observable that emits events | "EOSE" or errors */
|
|
116
118
|
req(filters, id = nanoid()) {
|
|
117
119
|
const request = this.socket
|
|
118
120
|
.multiplex(() => (Array.isArray(filters) ? ["REQ", id, ...filters] : ["REQ", id, filters]), () => ["CLOSE", id], (message) => (message[0] === "EVENT" || message[0] === "CLOSE" || message[0] === "EOSE") && message[1] === id)
|
|
@@ -144,22 +146,24 @@ export class Relay {
|
|
|
144
146
|
// Wait for auth if required and make sure to start the watch tower
|
|
145
147
|
return this.waitForAuth(this.authRequiredForReq, merge(this.watchTower, request));
|
|
146
148
|
}
|
|
147
|
-
/** send an Event message */
|
|
149
|
+
/** send an Event message and always return an observable of PublishResponse that completes or errors */
|
|
148
150
|
event(event, verb = "EVENT") {
|
|
149
|
-
const base =
|
|
150
|
-
|
|
151
|
-
.
|
|
152
|
-
|
|
153
|
-
|
|
151
|
+
const base = defer(() => {
|
|
152
|
+
// Send event when subscription starts
|
|
153
|
+
this.socket.next([verb, event]);
|
|
154
|
+
return this.socket.pipe(filter((m) => m[0] === "OK" && m[1] === event.id),
|
|
155
|
+
// format OK message
|
|
156
|
+
map((m) => ({ ok: m[2], message: m[3], from: this.url })));
|
|
157
|
+
});
|
|
154
158
|
// Start the watch tower with the observable
|
|
155
159
|
const withWatchTower = merge(this.watchTower, base);
|
|
156
|
-
//
|
|
160
|
+
// Add complete operators
|
|
157
161
|
const observable = withWatchTower.pipe(
|
|
158
162
|
// complete on first value
|
|
159
163
|
take(1),
|
|
160
164
|
// listen for OK auth-required
|
|
161
165
|
tap(({ ok, message }) => {
|
|
162
|
-
if (ok === false && message
|
|
166
|
+
if (ok === false && message?.startsWith("auth-required") && !this.authRequiredForPublish.value) {
|
|
163
167
|
this.log("Auth required for publish");
|
|
164
168
|
this.authRequiredForPublish.next(true);
|
|
165
169
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "applesauce-relay",
|
|
3
|
-
"version": "0.0.0-next-
|
|
3
|
+
"version": "0.0.0-next-20250404092229",
|
|
4
4
|
"description": "nostr relay communication framework built on rxjs",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
56
|
"@noble/hashes": "^1.7.1",
|
|
57
|
-
"applesauce-core": "0.0.0-next-
|
|
57
|
+
"applesauce-core": "0.0.0-next-20250404092229",
|
|
58
58
|
"nanoid": "^5.0.9",
|
|
59
59
|
"nostr-tools": "^2.10.4",
|
|
60
60
|
"rxjs": "^7.8.1"
|