applesauce-relay 0.0.0-next-20250430170741 → 0.0.0-next-20250430173639
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/__tests__/relay.test.js +50 -0
- package/dist/relay.d.ts +9 -9
- package/dist/relay.js +25 -18
- package/package.json +1 -1
|
@@ -332,9 +332,59 @@ describe("notices$", () => {
|
|
|
332
332
|
expect(relay.notices$.value).toEqual(["Important notice"]);
|
|
333
333
|
});
|
|
334
334
|
});
|
|
335
|
+
describe("notice$", () => {
|
|
336
|
+
it("should not trigger connection to relay", async () => {
|
|
337
|
+
subscribeSpyTo(relay.notice$);
|
|
338
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
339
|
+
expect(relay.connected).toBe(false);
|
|
340
|
+
});
|
|
341
|
+
it("should emit NOTICE messages when they are received", async () => {
|
|
342
|
+
const spy = subscribeSpyTo(relay.notice$);
|
|
343
|
+
// Start connection
|
|
344
|
+
subscribeSpyTo(relay.req({ kinds: [1] }));
|
|
345
|
+
// Send multiple NOTICE messages
|
|
346
|
+
server.send(["NOTICE", "Notice 1"]);
|
|
347
|
+
server.send(["NOTICE", "Notice 2"]);
|
|
348
|
+
server.send(["NOTICE", "Notice 3"]);
|
|
349
|
+
// Verify the notices state contains all messages
|
|
350
|
+
expect(spy.getValues()).toEqual(["Notice 1", "Notice 2", "Notice 3"]);
|
|
351
|
+
});
|
|
352
|
+
it("should ignore non-NOTICE messages", async () => {
|
|
353
|
+
const spy = subscribeSpyTo(relay.notice$);
|
|
354
|
+
// Start connection
|
|
355
|
+
subscribeSpyTo(relay.req({ kinds: [1] }));
|
|
356
|
+
server.send(["NOTICE", "Important notice"]);
|
|
357
|
+
server.send(["OTHER", "other message"]);
|
|
358
|
+
// Verify only NOTICE messages are in the state
|
|
359
|
+
expect(spy.getValues()).toEqual(["Important notice"]);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
describe("message$", () => {
|
|
363
|
+
it("should not trigger connection to relay", async () => {
|
|
364
|
+
subscribeSpyTo(relay.message$);
|
|
365
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
366
|
+
expect(relay.connected).toBe(false);
|
|
367
|
+
});
|
|
368
|
+
it("should emit all messages when they are received", async () => {
|
|
369
|
+
const spy = subscribeSpyTo(relay.message$);
|
|
370
|
+
// Start connection
|
|
371
|
+
subscribeSpyTo(relay.req({ kinds: [1] }));
|
|
372
|
+
// Send multiple NOTICE messages
|
|
373
|
+
server.send(["NOTICE", "Notice 1"]);
|
|
374
|
+
server.send(["EVENT", "sub1", mockEvent]);
|
|
375
|
+
server.send(["EOSE", "sub1"]);
|
|
376
|
+
// Verify the notices state contains all messages
|
|
377
|
+
expect(spy.getValues()).toEqual([
|
|
378
|
+
["NOTICE", "Notice 1"],
|
|
379
|
+
["EVENT", "sub1", mockEvent],
|
|
380
|
+
["EOSE", "sub1"],
|
|
381
|
+
]);
|
|
382
|
+
});
|
|
383
|
+
});
|
|
335
384
|
describe("challenge$", () => {
|
|
336
385
|
it("should not trigger connection to relay", async () => {
|
|
337
386
|
subscribeSpyTo(relay.challenge$);
|
|
387
|
+
await new Promise((resolve) => setTimeout(resolve, 10));
|
|
338
388
|
expect(relay.connected).toBe(false);
|
|
339
389
|
});
|
|
340
390
|
it("should set challenge$ when AUTH message received", async () => {
|
package/dist/relay.d.ts
CHANGED
|
@@ -30,21 +30,21 @@ export declare class Relay implements IRelay {
|
|
|
30
30
|
notices$: BehaviorSubject<string[]>;
|
|
31
31
|
/** The last connection error */
|
|
32
32
|
error$: BehaviorSubject<Error | null>;
|
|
33
|
-
/** An observable that emits the NIP-11 information document for the relay */
|
|
34
|
-
information$: Observable<RelayInformation | null>;
|
|
35
|
-
protected _nip11: RelayInformation | null;
|
|
36
|
-
/** An observable that emits the limitations for the relay */
|
|
37
|
-
limitations$: Observable<RelayInformation["limitation"] | null>;
|
|
38
33
|
/**
|
|
39
|
-
*
|
|
40
|
-
* @note Subscribing to this will
|
|
34
|
+
* A passive observable of all messages from the relay
|
|
35
|
+
* @note Subscribing to this will not connect to the relay
|
|
41
36
|
*/
|
|
42
37
|
message$: Observable<any>;
|
|
43
38
|
/**
|
|
44
|
-
*
|
|
45
|
-
* @note Subscribing to this will
|
|
39
|
+
* A passive observable of NOTICE messages from the relay
|
|
40
|
+
* @note Subscribing to this will not connect to the relay
|
|
46
41
|
*/
|
|
47
42
|
notice$: Observable<string>;
|
|
43
|
+
/** An observable that emits the NIP-11 information document for the relay */
|
|
44
|
+
information$: Observable<RelayInformation | null>;
|
|
45
|
+
protected _nip11: RelayInformation | null;
|
|
46
|
+
/** An observable that emits the limitations for the relay */
|
|
47
|
+
limitations$: Observable<RelayInformation["limitation"] | null>;
|
|
48
48
|
get connected(): boolean;
|
|
49
49
|
get challenge(): string | null;
|
|
50
50
|
get notices(): string[];
|
package/dist/relay.js
CHANGED
|
@@ -2,7 +2,7 @@ import { logger } from "applesauce-core";
|
|
|
2
2
|
import { simpleTimeout } from "applesauce-core/observable";
|
|
3
3
|
import { nanoid } from "nanoid";
|
|
4
4
|
import { nip42 } from "nostr-tools";
|
|
5
|
-
import { BehaviorSubject, catchError, combineLatest, defer, filter, from, ignoreElements, map, merge, mergeMap, NEVER, of, retry, scan, share, shareReplay, switchMap, take, tap, throwError, timeout, timer, } from "rxjs";
|
|
5
|
+
import { BehaviorSubject, catchError, combineLatest, defer, filter, from, ignoreElements, map, merge, mergeMap, NEVER, of, retry, scan, share, shareReplay, Subject, switchMap, take, tap, throwError, timeout, timer, } from "rxjs";
|
|
6
6
|
import { webSocket } from "rxjs/webSocket";
|
|
7
7
|
import { completeOnEose } from "./operators/complete-on-eose.js";
|
|
8
8
|
import { markFromRelay } from "./operators/mark-from-relay.js";
|
|
@@ -29,21 +29,21 @@ export class Relay {
|
|
|
29
29
|
notices$ = new BehaviorSubject([]);
|
|
30
30
|
/** The last connection error */
|
|
31
31
|
error$ = new BehaviorSubject(null);
|
|
32
|
-
/** An observable that emits the NIP-11 information document for the relay */
|
|
33
|
-
information$;
|
|
34
|
-
_nip11 = null;
|
|
35
|
-
/** An observable that emits the limitations for the relay */
|
|
36
|
-
limitations$;
|
|
37
32
|
/**
|
|
38
|
-
*
|
|
39
|
-
* @note Subscribing to this will
|
|
33
|
+
* A passive observable of all messages from the relay
|
|
34
|
+
* @note Subscribing to this will not connect to the relay
|
|
40
35
|
*/
|
|
41
36
|
message$;
|
|
42
37
|
/**
|
|
43
|
-
*
|
|
44
|
-
* @note Subscribing to this will
|
|
38
|
+
* A passive observable of NOTICE messages from the relay
|
|
39
|
+
* @note Subscribing to this will not connect to the relay
|
|
45
40
|
*/
|
|
46
41
|
notice$;
|
|
42
|
+
/** An observable that emits the NIP-11 information document for the relay */
|
|
43
|
+
information$;
|
|
44
|
+
_nip11 = null;
|
|
45
|
+
/** An observable that emits the limitations for the relay */
|
|
46
|
+
limitations$;
|
|
47
47
|
// sync state
|
|
48
48
|
get connected() {
|
|
49
49
|
return this.connected$.value;
|
|
@@ -116,7 +116,6 @@ export class Relay {
|
|
|
116
116
|
},
|
|
117
117
|
WebSocketCtor: opts?.WebSocket,
|
|
118
118
|
});
|
|
119
|
-
this.message$ = this.socket.asObservable();
|
|
120
119
|
// Create an observable to fetch the NIP-11 information document
|
|
121
120
|
this.information$ = defer(() => {
|
|
122
121
|
this.log("Fetching NIP-11 information document");
|
|
@@ -132,19 +131,18 @@ export class Relay {
|
|
|
132
131
|
// Create observables that track if auth is required for REQ or EVENT
|
|
133
132
|
this.authRequiredForReq = combineLatest([this.receivedAuthRequiredForReq, this.limitations$]).pipe(map(([received, limitations]) => received || limitations?.auth_required === true), tap((required) => required && this.log("Auth required for REQ")), shareReplay(1));
|
|
134
133
|
this.authRequiredForEvent = combineLatest([this.receivedAuthRequiredForEvent, this.limitations$]).pipe(map(([received, limitations]) => received || limitations?.auth_required === true), tap((required) => required && this.log("Auth required for EVENT")), shareReplay(1));
|
|
135
|
-
|
|
134
|
+
// Update the notices state
|
|
135
|
+
const listenForNotice = this.socket.pipe(
|
|
136
136
|
// listen for NOTICE messages
|
|
137
|
-
filter((m) => m[0] === "NOTICE"),
|
|
137
|
+
filter((m) => Array.isArray(m) && m[0] === "NOTICE"),
|
|
138
138
|
// pick the string out of the message
|
|
139
|
-
map((m) => m[1])
|
|
140
|
-
// Update the notices state
|
|
141
|
-
const notice = this.notice$.pipe(
|
|
139
|
+
map((m) => m[1]),
|
|
142
140
|
// Track all notices
|
|
143
141
|
scan((acc, notice) => [...acc, notice], []),
|
|
144
142
|
// Update the notices state
|
|
145
143
|
tap((notices) => this.notices$.next(notices)));
|
|
146
144
|
// Update the challenge state
|
|
147
|
-
const
|
|
145
|
+
const ListenForChallenge = this.socket.pipe(
|
|
148
146
|
// listen for AUTH messages
|
|
149
147
|
filter((message) => message[0] === "AUTH"),
|
|
150
148
|
// pick the challenge string out
|
|
@@ -154,12 +152,21 @@ export class Relay {
|
|
|
154
152
|
this.log("Received AUTH challenge", challenge);
|
|
155
153
|
this.challenge$.next(challenge);
|
|
156
154
|
}));
|
|
155
|
+
const allMessagesSubject = new Subject();
|
|
156
|
+
const listenForAllMessages = this.socket.pipe(tap((message) => allMessagesSubject.next(message)));
|
|
157
|
+
// Create passive observables for messages and notices
|
|
158
|
+
this.message$ = allMessagesSubject.asObservable();
|
|
159
|
+
this.notice$ = this.message$.pipe(
|
|
160
|
+
// listen for NOTICE messages
|
|
161
|
+
filter((m) => Array.isArray(m) && m[0] === "NOTICE"),
|
|
162
|
+
// pick the string out of the message
|
|
163
|
+
map((m) => m[1]));
|
|
157
164
|
// Merge all watchers
|
|
158
165
|
this.watchTower = this.ready$.pipe(switchMap((ready) => {
|
|
159
166
|
if (!ready)
|
|
160
167
|
return NEVER;
|
|
161
168
|
// Only start the watch tower if the relay is ready
|
|
162
|
-
return merge(
|
|
169
|
+
return merge(listenForAllMessages, listenForNotice, ListenForChallenge, this.information$).pipe(
|
|
163
170
|
// Never emit any values
|
|
164
171
|
ignoreElements(),
|
|
165
172
|
// Start the reconnect timer if the connection has an error
|